Thread: create a new GIN index for my own type

create a new GIN index for my own type

From
"huangning290@yahoo.com"
Date:
Hi:
  I created a new data type, and then I wanted to create a GIN index for it, but when I created the index, the program would crash 。
 
 The version of postgresql is 9.6。

The following is part of the code, and I also refer to the code of intarray.

```sql
CREATE OR REPLACE FUNCTION geomgrid_in(cstring)
RETURNS geomgrid
AS '$libdir/module-1.0','geomgrid_in'
LANGUAGE 'c' NOT FENCED IMMUTABLE STRICT ;

CREATE OR REPLACE FUNCTION geomgrid_out(geomgrid)
RETURNS cstring
AS '$libdir/module-1.0','geomgrid_out'
LANGUAGE 'c' NOT FENCED IMMUTABLE STRICT ;

CREATE OR REPLACE FUNCTION geomgrid_recv(internal)
RETURNS geomgrid
AS '$libdir/module-1.0','geomgrid_recv'
LANGUAGE 'c' NOT FENCED IMMUTABLE STRICT ;

CREATE OR REPLACE FUNCTION geomgrid_send(geomgrid)
RETURNS bytea
AS '$libdir/module-1.0','geomgrid_send'
LANGUAGE 'c' NOT FENCED IMMUTABLE STRICT ;

CREATE TYPE geomgrid(
internallength = 8,
input = geomgrid_in,
output = geomgrid_out,
send = geomgrid_send,
receive = geomgrid_recv,
alignment = double,
PASSEDBYVALUE = true,
storage = plain
);

CREATE OPERATOR CLASS gin_grid_ops
DEFAULT FOR TYPE _geomgrid USING gin
AS
    OPERATOR 3 &&,
OPERATOR 6 = (anyarray, anyarray),
OPERATOR 7 @>,
OPERATOR 8 <@,
    FUNCTION    1   grid_cmp(geomgrid,geomgrid),
    FUNCTION 2 gridarray_extract (anyarray, internal, internal),
FUNCTION 3 gridarray_queryextract (geomgrid, internal, int2, internal, internal, internal, internal),
```

```c
Datum geomgrid_in(PG_FUNCTION_ARGS)
{
  char *input = PG_GETARG_CSTRING(0);
  int len = strlen(input);
  if (len != 16)
    PG_RETURN_NULL();

  char *data = palloc(len / 2 );
  for (int i = 0, j = 7; i < len; i += 2, j--)
  {
    data[j] = Char2Hex(input + i);
  }
  int64_t* return_data = (int64_t*)data;
  PG_RETURN_INT64(*return_data);
}

Datum geomgrid_out(PG_FUNCTION_ARGS)
{
  int64_t out_data = PG_GETARG_INT64(0);
  char* buf_data = (char*)(&out_data);

  unsigned char dst[2] = {0};

  char *result = palloc(16 + 1);
  memset(result, 0, 16 + 1);

  for (int i = 7, j = 0; i >= 0; i--, j++)
  {
    Hex2Char((unsigned char)buf_data[i], dst);
    result[j * 2 + 1] = dst[0];
    result[j * 2] = dst[1];
  }
  PG_RETURN_CSTRING(result);
}
```

```c
Datum gridarray_extract(PG_FUNCTION_ARGS)
{
  ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
  int size = VARSIZE(array);
  int32 *nkeys = (int32 *)PG_GETARG_POINTER(1);
  bool **nullFlags = (bool **)PG_GETARG_POINTER(2);

  if (array == NULL || nkeys == NULL || nullFlags == NULL)
    ereport(ERROR,
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid arguments for function gridarray_extract")));

  int16 elmlen;
  bool elmbyval = false;
  char elmalign;
  Datum *elems = NULL;
  bool *nulls = NULL;
  int nelems;

  get_typlenbyvalalign(ARR_ELEMTYPE(array), &elmlen, &elmbyval, &elmalign);

  deconstruct_array(array, ARR_ELEMTYPE(array), elmlen, elmbyval, elmalign, &elems, &nulls, &nelems);

  *nkeys = nelems;
  *nullFlags = nulls;
  PG_RETURN_POINTER(elems);
}
```

            Best Regards!

Re: create a new GIN index for my own type

From
Tomas Vondra
Date:
On 10/4/21 8:30 AM, huangning290@yahoo.com wrote:
> Hi:
> I created a new data type, and then I wanted to create a GIN index for 
> it, but when I created the index, the program would crash 。
> The version of postgresql is 9.6。
> 
> The following is part of the code, and I also refer to the code of intarray.
> 

I doubt anyone is going to investigate this unless you provide a more 
complete example - something like an extension where people can do "make 
install" without having to fill in various pieces of code.

To investigate the crash, you need to attach a debugger to the backend 
and run the CREATE INDEX (or whatever triggers the crash). The debugger 
should catch the segfault and you'll be able to identify where exactly 
it crashes and why (and investigate).

1) first get PID of the backend

   SELECT pg_backend_pid();

2) then attach a debugger to the backend

   gdb -p $PID
   (gdb) c

3) run the CREATE INDEX query

4) get backtrace from the debugger

   (gdb) bt


regards

-- 
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: create a new GIN index for my own type

From
Tomas Vondra
Date:
On 10/4/21 3:32 PM, huangning290@yahoo.com wrote:
> I have already debugged the program according to this step, but I found 
> that in the DataCopy function, the variable typlen should be 8, but it 
> is -1,
> 

Well, if you have debugged this, it'd be nice if you could share more 
information (e.g. backtraces, etc.) otherwise others can just guess what 
you saw. And that makes it much harder to help you.

I see you defined the data type as PASSEDBYVALUE, but you haven't 
specified INTERNALLENGTH, so it's -1 (i.e. variable length). Obviously, 
that can't be passed by value - not sure if this is intentional or just 
a case of CREATE TYPE not checking it.


BTW it's customary not to top post - inline replies are much easier to 
follow, as it makes clearer which parts you respond to. And please make 
sure that you're responding to the mailing list, not just directly to 
the other person.


regards

-- 
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: create a new GIN index for my own type

From
"huangning290@yahoo.com"
Date:

Thanks for you reply.This is my stack information.
Inline image

Another question is, I have already set INTERNALLENGTH in CREATE TYPE, do I need to set it elsewhere?
On Monday, October 4, 2021, 09:51:38 PM GMT+8, Tomas Vondra <tomas.vondra@enterprisedb.com> wrote:


On 10/4/21 3:32 PM, huangning290@yahoo.com wrote:
> I have already debugged the program according to this step, but I found
> that in the DataCopy function, the variable typlen should be 8, but it
> is -1,
>

Well, if you have debugged this, it'd be nice if you could share more
information (e.g. backtraces, etc.) otherwise others can just guess what
you saw. And that makes it much harder to help you.

I see you defined the data type as PASSEDBYVALUE, but you haven't
specified INTERNALLENGTH, so it's -1 (i.e. variable length). Obviously,
that can't be passed by value - not sure if this is intentional or just
a case of CREATE TYPE not checking it.


BTW it's customary not to top post - inline replies are much easier to
follow, as it makes clearer which parts you respond to. And please make
sure that you're responding to the mailing list, not just directly to
the other person.



regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachment