Thread: C Programming with postgres.h - my function crashes the database backend

C Programming with postgres.h - my function crashes the database backend

From
Alex Page
Date:
I've been trying to extend Postgres and create an enumerated type to
represent gender, as a precursor to more complex enumerated types. I've
created the C functions for input and output with the following code:

- ---- gender.c -----
  #include "server/postgres.h"
  #include <string.h>
  #include "server/fmgr.h"

  PG_FUNCTION_INFO_V1(enum_gender_in);

  Datum enum_gender_in(PG_FUNCTION_ARGS) {
      text    *invalue = PG_GETARG_TEXT_P(0);

      if ( strcmp ( VARDATA(invalue), "Male" ) ) {        /* VARDATA gets the data portion of a "varlena" struct, which
istypedef'd to "text" */ 
          PG_RETURN_INT32( 0 );
      }
      PG_RETURN_INT32( 1 );
  }

  PG_FUNCTION_INFO_V1(enum_gender_out);

  Datum enum_gender_out(PG_FUNCTION_ARGS) {
      int32    internal = PG_GETARG_INT32(0);
      text    *outvalue;

      if ( internal == 0 ) {
          int32 male_struct_size = 5 * sizeof(char) + VARHDRSZ;    /* Five characters ('Male\0') plus int32 */
          outvalue = (text *) palloc ( male_struct_size );
          VARATT_SIZEP(outvalue) = male_struct_size;
          memcpy(VARDATA(outvalue), "Male\0", 5);
      } else {
          int32 female_struct_size = 7 * sizeof(char) + VARHDRSZ;    /* Five characters ('Female\0') plus int32 */
          outvalue = (text *) palloc ( female_struct_size );
          VARATT_SIZEP(outvalue) = female_struct_size;
          memcpy(VARDATA(outvalue), "Female\0", 5);
      }
      PG_RETURN_TEXT_P (outvalue);
  }
- ---- end of gender.c -----

Once I've compiled this to a shared library file with no errors or
warnings (even with -Wall), I can load these functions in psql
without error, and create a table with the appropriate type:

  test=# CREATE FUNCTION enum_gender_in (cstring) RETURNS enum_gender IMMUTABLE STRICT AS '/home/alex/epic/gender.so'
LANGUAGEC; 
  NOTICE:  ProcedureCreate: type enum_gender is not yet defined
  CREATE FUNCTION

  test=# CREATE FUNCTION enum_gender_out (enum_gender) RETURNS cstring IMMUTABLE STRICT AS '/home/alex/epic/gender.so'
LANGUAGEC;  
  NOTICE:  Argument type "enum_gender" is only a shell
  CREATE FUNCTION

  test=# CREATE TYPE enum_gender (
  test(#         INPUT = enum_gender_in,
  test(#         OUTPUT = enum_gender_out,
  test(#         INTERNALLENGTH = 2,
  test(#         PASSEDBYVALUE
  test(# );
  CREATE TYPE

  test=# CREATE TABLE people (
  test(#         id      serial,
  test(#         name    text,
  test(#         gender  enum_gender
  test(# );
  NOTICE:  CREATE TABLE will create implicit sequence 'people_id_seq' for SERIAL column 'people.id'
  CREATE TABLE

So far so good. However, the real problem comes when I try to insert
something into the table I've just created:

  test=# INSERT INTO people (name, gender) VALUES ('Alex', 'Male');
  server closed the connection unexpectedly
          This probably means the server terminated abnormally
      before or while processing the request.
  The connection to the server was lost. Attempting reset: Failed.
  !#

I'm fairly sure there's a bug in my C code somewhere, but I can't spot
it. Admittedly, my C is pretty rusty, and I've not been able to find any
useful documentation for the internal C structures in postgres, other
than the source code itself. Any links to HOWTOs or similar would also
be appreciated.

Can I request a feature enhancement of built-in enumerated types for Postgres? ;)

Alex
--
Mail: Alex Page <alex.page@cancer.org.uk>
Real: Systems/Network Assistant, Epidemiology Unit, Oxford
Tel:  01865 302 223 (external) / 223 (internal)
PGP:  8868 21D7 3D35 DD77 9D06  BF0A 0746 2DE6 55EA 367E

Attachment

Re: C Programming with postgres.h - my function crashes the database backend

From
Alvaro Herrera
Date:
On Tue, Dec 02, 2003 at 05:56:45PM +0000, Alex Page wrote:

>   Datum enum_gender_in(PG_FUNCTION_ARGS) {
>       text    *invalue = PG_GETARG_TEXT_P(0);
>
>       if ( strcmp ( VARDATA(invalue), "Male" ) ) {        /* VARDATA gets the data portion of a "varlena" struct,
whichis typedef'd to "text" */ 
>           PG_RETURN_INT32( 0 );
>       }
>       PG_RETURN_INT32( 1 );
>   }

VARDATA is not 0-terminated, so you can't use strcmp on it.  Maybe you
should use memcmp instead.

--
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"Nunca se desea ardientemente lo que solo se desea por razón" (F. Alexandre)

Re: C Programming with postgres.h - my function crashes

From
Teodor Sigaev
Date:
>
>   Datum enum_gender_in(PG_FUNCTION_ARGS) {
>       text    *invalue = PG_GETARG_TEXT_P(0);




>
>   PG_FUNCTION_INFO_V1(enum_gender_out);
>
>   Datum enum_gender_out(PG_FUNCTION_ARGS) {
>       PG_RETURN_TEXT_P (outvalue);
>   }

IN function takes a C-string, not a text and
OUT functions should return C-string, not a text.


--
Teodor Sigaev                                  E-mail: teodor@sigaev.ru


Re: C Programming with postgres.h - my function crashes

From
Jan Wieck
Date:
Alvaro Herrera wrote:

> On Tue, Dec 02, 2003 at 05:56:45PM +0000, Alex Page wrote:
>
>>   Datum enum_gender_in(PG_FUNCTION_ARGS) {
>>       text    *invalue = PG_GETARG_TEXT_P(0);
>>
>>       if ( strcmp ( VARDATA(invalue), "Male" ) ) {        /* VARDATA gets the data portion of a "varlena" struct,
whichis typedef'd to "text" */ 
>>           PG_RETURN_INT32( 0 );
>>       }
>>       PG_RETURN_INT32( 1 );
>>   }
>
> VARDATA is not 0-terminated, so you can't use strcmp on it.  Maybe you
> should use memcmp instead.
>

First of all, the argument to a type input procedure is a nul terminated
CString, not text.

Alex, why don't you look at an existing datatype in backend/utils/adt?


Jan

--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #


Re: C Programming with postgres.h - my function crashes

From
Alex Page
Date:
On Tue, Dec 02, 2003 at 01:54:06PM -0500, Jan Wieck wrote:

> First of all, the argument to a type input procedure is a nul terminated
> CString, not text.

Oops! Thanks for that, I'll see if I can get this working now.

> Alex, why don't you look at an existing datatype in backend/utils/adt?

I don't seem to have this file in my Postgres installation. Is it
available somewhere?

Alex
--
Mail: Alex Page <alex.page@cancer.org.uk>
Real: Systems/Network Assistant, Epidemiology Unit, Oxford
Tel:  01865 302 223 (external) / 223 (internal)
PGP:  8868 21D7 3D35 DD77 9D06  BF0A 0746 2DE6 55EA 367E

Attachment

Re: C Programming with postgres.h - my function crashes

From
Jan Wieck
Date:
Alex Page wrote:

> On Tue, Dec 02, 2003 at 01:54:06PM -0500, Jan Wieck wrote:
>
>> First of all, the argument to a type input procedure is a nul terminated
>> CString, not text.
>
> Oops! Thanks for that, I'll see if I can get this working now.
>
>> Alex, why don't you look at an existing datatype in backend/utils/adt?
>
> I don't seem to have this file in my Postgres installation. Is it
> available somewhere?

It is the directory of the PostgreSQL source tree where all the builtin
data types live and you can find it here:

http://developer.postgresql.org/cvsweb.cgi/pgsql-server/src/backend/utils/adt/


Jan

--
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #