Thread: creating a new type in C
Hello, I've been playing with a new type I want to create, but I got stuck, therefore I ask for your assistance. I don't know if this is the right list for this, if not please tell me where to post my questions. This is the source: #include "postgres.h" #include "fmgr.h" typedef struct movie_property { int4 id; char name[31]; } movie_property; Datum movie_property_in(PG_FUNCTION_ARGS); Datum movie_property_out(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(movie_property_in) Datum movie_property_in(PG_FUNCTION_ARGS) { int4 id = PG_GETARG_INT32(0); char *name = PG_GETARG_CSTRING(1); movie_property *result; result = (movie_property *) palloc(sizeof(movie_property)); result->id = id; strncpy(result->name, name, 30); result->name[30] = 0; PG_RETURN_POINTER(result); } PG_FUNCTION_INFO_V1(movie_property_out) Datum movie_property_out(PG_FUNCTION_ARGS) { movie_property *property = (movie_property *) PG_GETARG_POINTER(0); char *result; if (property == NULL) PG_RETURN_POINTER(NULL); if ((result = (char *) palloc(40)) != NULL) { sprintf(result, "(%d,%s)", property->id, property->name); } PG_RETURN_CSTRING(result); } Creating functions and type: create function movie_property_in(opaque) returns opaque as '$libdir/movie_property' language 'c'; create function movie_property_out(opaque) returns opaque as '$libdir/movie_property' language 'c'; create type movie_property ( internallength = 35, input = movie_property_in, output = movie_property_out ); CREATE TABLE pp (p movie_property); INSERT INTO pp values('(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")'); The problem is with movie_property_in function. When I try to obtain the id with PG_GETARG_INT32(0), I don't get 1, but 138944104. I tried and logged the result of PG_GETARG_CSTRING(0), and it seems it returns the whole string (1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"). Please, tell me, how do I do this the right way ? If you have any other comments regarding my code (I'm a C begginer), they are welcomed. Postgresql version is 7.2.3 on a Gentoo Linux 1.2 gcc version 2.95.3 20010315
Hello, I think you gave the answer for your question by yourself. In the XXX_in function you have only one args. You have to parse it and covert it into the proper format by yourself. The sample code (complex type) very good in the Postgres docs http://www.postgresql.org/idocs/index.php?xtypes.html Complex * complex_in(char *str) { double x, y; Complex *result; if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) { elog(ERROR, "complex_in: error in parsing %s", str); return NULL; } result = (Complex *)palloc(sizeof(Complex)); result->x = x; result->y = y; return (result); } It uses version 0 calling conversion in the sample, but the rest is the same. As you see the sscanf "C" library function is used to convert the argument string. In your case it is not going to work, becasue the sscanf in not good enough to make to conversion. The best way if you write a small function to make it for you. Best Regards, Yuri ----- Original Message ----- From: "Andrei Ivanov" <andrei.ivanov@ines.ro> To: <pgsql-general@postgresql.org> Sent: Friday, October 18, 2002 12:29 PM Subject: [GENERAL] creating a new type in C > > Hello, > I've been playing with a new type I want to create, but I got stuck, > therefore I ask for your assistance. > I don't know if this is the right list for this, if not please tell me > where to post my questions. > This is the source: > > #include "postgres.h" > #include "fmgr.h" > > typedef struct movie_property > { > int4 id; > char name[31]; > } movie_property; > > Datum movie_property_in(PG_FUNCTION_ARGS); > Datum movie_property_out(PG_FUNCTION_ARGS); > > PG_FUNCTION_INFO_V1(movie_property_in) > Datum movie_property_in(PG_FUNCTION_ARGS) > { > int4 id = PG_GETARG_INT32(0); > char *name = PG_GETARG_CSTRING(1); > movie_property *result; > result = (movie_property *) palloc(sizeof(movie_property)); > result->id = id; > strncpy(result->name, name, 30); > result->name[30] = 0; > PG_RETURN_POINTER(result); > } > > PG_FUNCTION_INFO_V1(movie_property_out) > Datum movie_property_out(PG_FUNCTION_ARGS) > { > movie_property *property = (movie_property *) PG_GETARG_POINTER(0); > char *result; > > if (property == NULL) > PG_RETURN_POINTER(NULL); > if ((result = (char *) palloc(40)) != NULL) > { > sprintf(result, "(%d,%s)", property->id, property->name); > } > PG_RETURN_CSTRING(result); > } > > Creating functions and type: > create function movie_property_in(opaque) > returns opaque > as '$libdir/movie_property' > language 'c'; > create function movie_property_out(opaque) > returns opaque > as '$libdir/movie_property' > language 'c'; > create type movie_property ( > internallength = 35, > input = movie_property_in, > output = movie_property_out > ); > CREATE TABLE pp (p movie_property); > INSERT INTO pp values('(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")'); > > The problem is with movie_property_in function. > When I try to obtain the id with PG_GETARG_INT32(0), > I don't get 1, but 138944104. > I tried and logged the result of PG_GETARG_CSTRING(0), and it seems it > returns the whole string (1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"). > Please, tell me, how do I do this the right way ? > If you have any other comments regarding my code (I'm a C begginer), > they are welcomed. > > Postgresql version is 7.2.3 on a Gentoo Linux 1.2 > gcc version 2.95.3 20010315 > > > > ---------------------------(end of broadcast)--------------------------- > TIP 5: Have you checked our extensive FAQ? > > http://www.postgresql.org/users-lounge/docs/faq.html
I see, but aren't all those PG_GETARG_XXX functions supposed to do the parsing and casting ? I though that's why they existed, to make the manual parsing unnecessary and maybe eliminate bugs. And another thought, is this the right query to insert data into this type ? INSERT INTO pp values('(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")'); PS: this is a second reply, because the first time I forgot to CC to the list, sorry. On Fri, 18 Oct 2002, Gyorgy Molnar wrote: > Hello, > I think you gave the answer for your question by yourself. In the XXX_in > function you have only one args. You have to parse it and covert it into the > proper format by yourself. > > The sample code (complex type) very good in the Postgres docs > http://www.postgresql.org/idocs/index.php?xtypes.html > > Complex * > complex_in(char *str) > { > double x, y; > Complex *result; > if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) { > elog(ERROR, "complex_in: error in parsing %s", str); > return NULL; > } > result = (Complex *)palloc(sizeof(Complex)); > result->x = x; > result->y = y; > return (result); > } > > It uses version 0 calling conversion in the sample, but the rest is the > same. > > As you see the sscanf "C" library function is used to convert the argument > string. > In your case it is not going to work, becasue the sscanf in not good enough > to make to conversion. The best way if you write a small function to make it > for you. > > Best Regards, > Yuri > > > > ----- Original Message ----- > From: "Andrei Ivanov" <andrei.ivanov@ines.ro> > To: <pgsql-general@postgresql.org> > Sent: Friday, October 18, 2002 12:29 PM > Subject: [GENERAL] creating a new type in C > > > > > > Hello, > > I've been playing with a new type I want to create, but I got stuck, > > therefore I ask for your assistance. > > I don't know if this is the right list for this, if not please tell me > > where to post my questions. > > This is the source: > > > > #include "postgres.h" > > #include "fmgr.h" > > > > typedef struct movie_property > > { > > int4 id; > > char name[31]; > > } movie_property; > > > > Datum movie_property_in(PG_FUNCTION_ARGS); > > Datum movie_property_out(PG_FUNCTION_ARGS); > > > > PG_FUNCTION_INFO_V1(movie_property_in) > > Datum movie_property_in(PG_FUNCTION_ARGS) > > { > > int4 id = PG_GETARG_INT32(0); > > char *name = PG_GETARG_CSTRING(1); > > movie_property *result; > > result = (movie_property *) palloc(sizeof(movie_property)); > > result->id = id; > > strncpy(result->name, name, 30); > > result->name[30] = 0; > > PG_RETURN_POINTER(result); > > } > > > > PG_FUNCTION_INFO_V1(movie_property_out) > > Datum movie_property_out(PG_FUNCTION_ARGS) > > { > > movie_property *property = (movie_property *) PG_GETARG_POINTER(0); > > char *result; > > > > if (property == NULL) > > PG_RETURN_POINTER(NULL); > > if ((result = (char *) palloc(40)) != NULL) > > { > > sprintf(result, "(%d,%s)", property->id, property->name); > > } > > PG_RETURN_CSTRING(result); > > } > > > > Creating functions and type: > > create function movie_property_in(opaque) > > returns opaque > > as '$libdir/movie_property' > > language 'c'; > > create function movie_property_out(opaque) > > returns opaque > > as '$libdir/movie_property' > > language 'c'; > > create type movie_property ( > > internallength = 35, > > input = movie_property_in, > > output = movie_property_out > > ); > > CREATE TABLE pp (p movie_property); > > INSERT INTO pp values('(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")'); > > > > The problem is with movie_property_in function. > > When I try to obtain the id with PG_GETARG_INT32(0), > > I don't get 1, but 138944104. > > I tried and logged the result of PG_GETARG_CSTRING(0), and it seems it > > returns the whole string (1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"). > > Please, tell me, how do I do this the right way ? > > If you have any other comments regarding my code (I'm a C begginer), > > they are welcomed. > > > > Postgresql version is 7.2.3 on a Gentoo Linux 1.2 > > gcc version 2.95.3 20010315 > > > > > > > > ---------------------------(end of broadcast)--------------------------- > > TIP 5: Have you checked our extensive FAQ? > > > > http://www.postgresql.org/users-lounge/docs/faq.html > >