Обсуждение: C Programming with postgres.h - my function crashes the database backend
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
Вложения
Re: C Programming with postgres.h - my function crashes the database backend
От
Alvaro Herrera
Дата:
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)
>
> 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
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 #
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
Вложения
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 #