Issue on C function that reads int2[] (using "int2vector")

Started by Rodrigo Hjortabout 10 years ago3 messages
#1Rodrigo Hjort
rodrigo.hjort@gmail.com

Hello PG Hackers,

I created a custom C function with this signature:

CREATE FUNCTION calculate_hash(numbers int2[])
RETURNS int8
AS 'MODULE_PATHNAME', 'pg_calculate_hash'
LANGUAGE C
IMMUTABLE STRICT;

And here is the function source code (inspired in codes I found in
src/backend/utils/adt/int.c):

PG_FUNCTION_INFO_V1(pg_calculate_hash);
Datum
pg_calculate_hash(PG_FUNCTION_ARGS)
{
int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);
const int qtd = int2Array->dim1;

elog(DEBUG1, "pg_calculate_hash(qtd=%d)", qtd);

elog(DEBUG2, " [ndim=%d, dataoffset=%d, elemtype=%d, dim1=%d,
lbound1=%d]",
int2Array->ndim, int2Array->dataoffset, int2Array->elemtype,
int2Array->dim1, int2Array->lbound1);

[...]
}

In order to test it against a table structure, I executed these
instructions on psql:

db=# create table ss (s int2[]);
CREATE TABLE

db=# \d+ ss
Table "public.ss"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------------+-----------+----------+--------------+-------------
s | smallint[] | | extended | |
Has OIDs: no

db=# insert into ss values ('[0:5]={58,17,15,36,59,54}');
INSERT 0 1

db=# select * from ss;
s
---------------------------
[0:5]={58,17,15,36,59,54}
(1 row)

Then, whenever calling the function passing the int2[] column directly,
strange values are read into the "int2vector" object:

db=# set client_min_messages to debug2;
SET

db=# select s, calculate_hash(s) from ss;
DEBUG: pg_calculate_hash(qtd=0)
DEBUG: [ndim=0, dataoffset=5376, elemtype=1536, dim1=0,
lbound1=285227520]
s | calculate_hash
---------------------------+---------------
[0:5]={58,17,15,36,59,54} | 0
(1 row)

On the other hand, when I double-cast the int2[] column value, it works as
expected (reading the proper "int2vector" structure):

db=# select s, calculate_hash(s::varchar::int2[]) from ss;
DEBUG: pg_calculate_hash(qtd=6)
DEBUG: [ndim=1, dataoffset=0, elemtype=21, dim1=6, lbound1=0]
s | calculate_hash
---------------------------+--------------------
[0:5]={58,17,15,36,59,54} | 441352797842128896
(1 row)

Please, what is wrong with that function code?

Thanks in advance.

The whole project is on GitHub:
https://github.com/hjort/mega-sena/tree/master/src

Best regards,

--
Rodrigo Hjort
www.hjort.co

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Rodrigo Hjort (#1)
Re: Issue on C function that reads int2[] (using "int2vector")

Rodrigo Hjort <rodrigo.hjort@gmail.com> writes:

I created a custom C function with this signature:

CREATE FUNCTION calculate_hash(numbers int2[])
RETURNS int8
AS 'MODULE_PATHNAME', 'pg_calculate_hash'
LANGUAGE C
IMMUTABLE STRICT;

And here is the function source code (inspired in codes I found in
src/backend/utils/adt/int.c):

PG_FUNCTION_INFO_V1(pg_calculate_hash);
Datum
pg_calculate_hash(PG_FUNCTION_ARGS)
{
int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);

Nope. int2vector is not the same as int2[]. It might occasionally seem
to work, but in general it's not the same type. And this particular
coding won't work at all on on-disk int2[] data, because it doesn't
account for toasting.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Rodrigo Hjort
rodrigo.hjort@gmail.com
In reply to: Tom Lane (#2)
Re: Issue on C function that reads int2[] (using "int2vector")

2015-11-30 0:39 GMT-02:00 Tom Lane:

Rodrigo Hjort writes:

I created a custom C function with this signature:

CREATE FUNCTION calculate_hash(numbers int2[])
RETURNS int8
AS 'MODULE_PATHNAME', 'pg_calculate_hash'
LANGUAGE C
IMMUTABLE STRICT;

And here is the function source code (inspired in codes I found in
src/backend/utils/adt/int.c):

PG_FUNCTION_INFO_V1(pg_calculate_hash);
Datum
pg_calculate_hash(PG_FUNCTION_ARGS)
{
int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);

Nope. int2vector is not the same as int2[]. It might occasionally seem
to work, but in general it's not the same type. And this particular
coding won't work at all on on-disk int2[] data, because it doesn't
account for toasting.

regards, tom lane

Thanks for the advice, Tom.

I ended up with the following code, which worked successfully:

#define ARRPTR16(x) ((uint16 *) ARR_DATA_PTR(x))
#define ARRNELEMS(x) ArrayGetNItems(ARR_NDIM(x), ARR_DIMS(x))
#define ARRISEMPTY(x) (ARRNELEMS(x) == 0)

PG_FUNCTION_INFO_V1(pg_calculate_hash);
Datum
pg_calculate_hash(PG_FUNCTION_ARGS)
{
ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
unsigned int i, qtd, tipo, nums[MAX_NUMEROS];
uint16 *da;

qtd = ARRNELEMS(a);
tipo = ARR_ELEMTYPE(a);
da = ARRPTR16(a);

elog(DEBUG1, "pg_calculate_hash(qtd=%d, tipo=%d)", qtd, tipo);

[...]

pfree(a);
PG_RETURN_INT64(hash);
}

Regards,

Rodrigo Hjort