Обсуждение: URL Managment - C Function help
Hi,
I'm writing two functions "parse_url_key" and "parse_url_record" which
will have one text argument and will return a record or a specific
column of it. Theses functions are calling "parse_url_exec" which parse
the URL. When theses function will works, i'll purpose them to
PostgreSQL community.
The problem is that they don't work fine... :/
Prototypes of function/struct used by them:
----------------------------------------------------
typedef struct url {char *scheme;char *user;char *pass;char *host;unsigned short port;char *path;char *query;char
*fragment;
} url;
url *parse_url_exec (char* str);
----------------------------------------------------
The parse_url_key function:
----------------------------------------------------
PG_FUNCTION_INFO_V1(parse_url_key);
Datum parse_url_key (PG_FUNCTION_ARGS)
{char str[] = "http://www.ovh.com/intenal.html";//text *my_url = PG_GETARG_TEXT_P(0);//char *char_url =
DatumGetCString(my_url);
url *ret = parse_url_exec(str);
PG_RETURN_TEXT_P(ret->host);
}
----------------------------------------------------
Note: I'm using built-in strings to be sure that the recuperation
doesn't change anything..
This function works well:
----------------------------------------------------
postgres=# CREATE OR REPLACE FUNCTION parse_url_key(text) RETURNS text
AS '/home/samuel/parse_url.so', 'parse_url_key' LANGUAGE C;
CREATE FUNCTION
postgres=# SELECT parse_url_key('') as scheme; scheme
------------ww.ovh.com
(1 row)
----------------------------------------------------
Note: there's a little problem here but not important. :-)
The problem is that the other function, "parse_url_record" doesn't
return values ! The code is:
----------------------------------------------------
PG_FUNCTION_INFO_V1(parse_url_record);
Datum parse_url_record (PG_FUNCTION_ARGS)
{// Vars about the params//text *str2 = PG_GETARG_TEXT_P(0);char str[] = "http://www.ovh.com/intenal.html";
// Some vars which will used to create the composite output typeTupleDesc tupdesc;Datum values[2]; // 8
valuesHeapTuple tuple;bool nulls[2];int tuplen;
// Check NULLs valuesif(PG_ARGISNULL(0) || PG_ARGISNULL(1)) { PG_RETURN_NULL();}
url *ret = parse_url_exec(str);
// Add datas into the values Datumvalues[0] = PointerGetDatum(ret->scheme);values[1] = PointerGetDatum(ret->host);
// Convert values into a composite type/*tuplen = tupdesc->natts;nulls = palloc(tuplen * sizeof(bool));*/memset(nulls,
0,sizeof(nulls));
// build tuple from datum arraytuple = heap_form_tuple(tupdesc, values, nulls);// Free null values/*pfree(nulls);*/
// Return the composite typePG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
----------------------------------------------------
Note: I'm just returning scheme and host fields for test, but others are
too completed by parse_url_exec.
It doesn't works fine:
----------------------------------------------------
postgres=# CREATE OR REPLACE FUNCTION parse_url_record(text) RETURNS
record AS '/home/samuel/parse_url.so', 'parse_url_record' LANGUAGE C;
CREATE FUNCTION
postgres=# SELECT * FROM parse_url_record('') as ("scheme" text, "host"
text);scheme | host
--------+------ |
(1 row)
----------------------------------------------------
Is there anybody here who can help me ?
Thanks you very much !
Samuel ROZE.
http://www.d-sites.com
Samuel ROZE <samuel.roze@gmail.com> writes:
> The problem is that they don't work fine... :/
I think the problem is that you are passing C strings to code that
expects pointers to text datums --- which are not the same thing
at all. (text has a length word, not a null terminator byte.)
It's pure accident that your first example works, and entirely
unsurprising that the second one doesn't. Some CStringGetTextDatum
calls might help.
regards, tom lane
Samuel ROZE wrote:
> PG_FUNCTION_INFO_V1(parse_url_record);
> Datum parse_url_record (PG_FUNCTION_ARGS)
> {
> // Vars about the params
> //text *str2 = PG_GETARG_TEXT_P(0);
> char str[] = "http://www.ovh.com/intenal.html";
>
> // Some vars which will used to create the composite output type
> TupleDesc tupdesc;
> Datum values[2]; // 8 values
> HeapTuple tuple;
> bool nulls[2];
> int tuplen;
>
> // Check NULLs values
> if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
> PG_RETURN_NULL();
> }
>
> url *ret = parse_url_exec(str);
>
> // Add datas into the values Datum
> values[0] = PointerGetDatum(ret->scheme);
> values[1] = PointerGetDatum(ret->host);
>
> // Convert values into a composite type
> /*tuplen = tupdesc->natts;
> nulls = palloc(tuplen * sizeof(bool));*/
> memset(nulls, 0, sizeof(nulls));
>
> // build tuple from datum array
> tuple = heap_form_tuple(tupdesc, values, nulls);
> // Free null values
> /*pfree(nulls);*/
>
> // Return the composite type
> PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
> }
You haven't initialized tupdesc.
BTW, there's a fine example in the manual:
http://www.postgresql.org/docs/8.4/interactive/xfunc-c.html#AEN44968
-- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com
Thanks for your reply.
--------------------------------------------------------
PG_FUNCTION_INFO_V1(parse_url_record);
Datum parse_url_record (PG_FUNCTION_ARGS)
{// Vars about the params//text *str2 = PG_GETARG_TEXT_P(0);char str[] = "http://www.ovh.com/intenal.html";
// Some vars which will used to create the composite output typeTupleDesc tupdesc;char **values;HeapTuple
tuple;AttInMetadata*attinmeta;bool nulls[2];int tuplen;
// Check NULLs valuesif(PG_ARGISNULL(0) || PG_ARGISNULL(1)) { PG_RETURN_NULL();}
url *ret = parse_url_exec(str);
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
{ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record
calledin context " "that cannot accept type record")));}attinmeta = TupleDescGetAttInMetadata(tupdesc);
// ...values = (char **) palloc(2 * sizeof(char *));
// Add datas into the values Datumvalues[0] = (char *) ret->scheme;values[1] = (char *) ret->host;
// Convert values into a composite typememset(nulls, 0, sizeof(nulls));
// build tuple from datum arraytuple = BuildTupleFromCStrings(attinmeta, values);
// Return the composite typePG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
-------------------------------------------------------
This code doesn't works better... :/
Le mercredi 21 octobre 2009 à 18:42 +0300, Heikki Linnakangas a écrit :
> Samuel ROZE wrote:
> > PG_FUNCTION_INFO_V1(parse_url_record);
> > Datum parse_url_record (PG_FUNCTION_ARGS)
> > {
> > // Vars about the params
> > //text *str2 = PG_GETARG_TEXT_P(0);
> > char str[] = "http://www.ovh.com/intenal.html";
> >
> > // Some vars which will used to create the composite output type
> > TupleDesc tupdesc;
> > Datum values[2]; // 8 values
> > HeapTuple tuple;
> > bool nulls[2];
> > int tuplen;
> >
> > // Check NULLs values
> > if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
> > PG_RETURN_NULL();
> > }
> >
> > url *ret = parse_url_exec(str);
> >
> > // Add datas into the values Datum
> > values[0] = PointerGetDatum(ret->scheme);
> > values[1] = PointerGetDatum(ret->host);
> >
> > // Convert values into a composite type
> > /*tuplen = tupdesc->natts;
> > nulls = palloc(tuplen * sizeof(bool));*/
> > memset(nulls, 0, sizeof(nulls));
> >
> > // build tuple from datum array
> > tuple = heap_form_tuple(tupdesc, values, nulls);
> > // Free null values
> > /*pfree(nulls);*/
> >
> > // Return the composite type
> > PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
> > }
>
> You haven't initialized tupdesc.
>
> BTW, there's a fine example in the manual:
> http://www.postgresql.org/docs/8.4/interactive/xfunc-c.html#AEN44968
>
Le mercredi 21 octobre 2009 à 11:42 -0400, Tom Lane a écrit : > CStringGetTextDatum Can you give me more precisions ? I'm creating a "user C function", with shared library and CStringGetTextDatum is in "varlena.h" file which is not in the "src/include" dir... How can I include it ? Thanks. Samuel.
Samuel ROZE wrote: > Le mercredi 21 octobre 2009 à 11:42 -0400, Tom Lane a écrit : > >> CStringGetTextDatum >> > > Can you give me more precisions ? > > I'm creating a "user C function", with shared library and > CStringGetTextDatum is in "varlena.h" file which is not in the > "src/include" dir... How can I include it ? > > > It's in utils/builtins.h, as a simple grep search should have told you. cheers andrew
I've done it but I had no results... strange. I've a 8.3 version and this lines are NOT in the file: 00668 /* varlena.c */ 00669 extern text *cstring_to_text(const char *s); 00670 extern text *cstring_to_text_with_len(const char *s, int len); 00671 extern char *text_to_cstring(const text *t); 00672 extern void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len); 00673 00674 #define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s)) 00675 #define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d)) Le mercredi 21 octobre 2009 à 12:28 -0400, Andrew Dunstan a écrit : > > Samuel ROZE wrote: > > Le mercredi 21 octobre 2009 à 11:42 -0400, Tom Lane a écrit : > > > >> CStringGetTextDatum > >> > > > > Can you give me more precisions ? > > > > I'm creating a "user C function", with shared library and > > CStringGetTextDatum is in "varlena.h" file which is not in the > > "src/include" dir... How can I include it ? > > > > > > > > It's in utils/builtins.h, as a simple grep search should have told you. > > cheers > > andrew
I'm now using C strings. I don't need to use CStringGetTextDatum, but it
still don't works. There's the code:
---------------------------------------------------------------
PG_FUNCTION_INFO_V1(parse_url_record);
Datum parse_url_record (PG_FUNCTION_ARGS)
{// Vars about the params//text *str2 = PG_GETARG_TEXT_P(0);char str[] = "http://www.ovh.com/intenal.html";
// Some vars which will used to create the composite output typeTupleDesc tupdesc;char **values;HeapTuple
tuple;AttInMetadata*attinmeta;bool nulls[2];url *ret;
// Check NULLs valuesif(PG_ARGISNULL(0) || PG_ARGISNULL(1)) { PG_RETURN_NULL();}
ret = parse_url_exec(str);
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
{ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record
calledin context that
cannot accept type record")));}attinmeta = TupleDescGetAttInMetadata(tupdesc);
// ...values = (char **) palloc(2 * sizeof(char *));
// Add datas into the values Datumvalues[0] = (char *) ret->scheme;values[1] = (char *) ret->host;
// Convert values into a composite typememset(nulls, 0, sizeof(nulls));
// build tuple from datum arraytuple = BuildTupleFromCStrings(attinmeta, values);
// Return the composite typePG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
---------------------------------------------------------------
Thanks a lot !
Samuel ROZE.
Le mercredi 21 octobre 2009 à 11:42 -0400, Tom Lane a écrit :
> Samuel ROZE <samuel.roze@gmail.com> writes:
> > The problem is that they don't work fine... :/
>
> I think the problem is that you are passing C strings to code that
> expects pointers to text datums --- which are not the same thing
> at all. (text has a length word, not a null terminator byte.)
> It's pure accident that your first example works, and entirely
> unsurprising that the second one doesn't. Some CStringGetTextDatum
> calls might help.
>
> regards, tom lane
Samuel ROZE <samuel.roze@gmail.com> writes:
> I've done it but I had no results... strange.
> I've a 8.3 version and this lines are NOT in the file:
Oh, it was changed in 8.4 IIRC. If you are thinking of submitting
code to the project you should not be developing against a back
release anyway ...
regards, tom lane
Samuel ROZE wrote: > I've done it but I had no results... strange. > > I've a 8.3 version and this lines are NOT in the file: > You neglected to tell us you were in 8.3 before, I think. On 8.3 you might need to put a #define for it directly in your C file. cheers andrew
Le mercredi 21 octobre 2009 à 12:59 -0400, Andrew Dunstan a écrit : > On 8.3 you might need to put a #define for it directly in your C file. I can't: cstring_to_text isn't defined. I'll develop on 8.4.
Samuel ROZE wrote: > Le mercredi 21 octobre 2009 à 12:59 -0400, Andrew Dunstan a écrit : > >> On 8.3 you might need to put a #define for it directly in your C file. >> > > I can't: cstring_to_text isn't defined. > > I'll develop on 8.4. > or try: #define CStringGetTextP(c) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(c))) cheers andrew
It is solved. I'll propose my work the next weeks. :-)
Regards,
Samuel.
Le mercredi 21 octobre 2009 à 17:31 +0200, Samuel ROZE a écrit :
> Hi,
>
> I'm writing two functions "parse_url_key" and "parse_url_record" which
> will have one text argument and will return a record or a specific
> column of it. Theses functions are calling "parse_url_exec" which parse
> the URL. When theses function will works, i'll purpose them to
> PostgreSQL community.
>
> The problem is that they don't work fine... :/
>
> Prototypes of function/struct used by them:
> ----------------------------------------------------
> typedef struct url {
> char *scheme;
> char *user;
> char *pass;
> char *host;
> unsigned short port;
> char *path;
> char *query;
> char *fragment;
> } url;
>
> url *parse_url_exec (char* str);
> ----------------------------------------------------
>
> The parse_url_key function:
> ----------------------------------------------------
> PG_FUNCTION_INFO_V1(parse_url_key);
> Datum parse_url_key (PG_FUNCTION_ARGS)
> {
> char str[] = "http://www.ovh.com/intenal.html";
> //text *my_url = PG_GETARG_TEXT_P(0);
> //char *char_url = DatumGetCString(my_url);
>
> url *ret = parse_url_exec(str);
>
> PG_RETURN_TEXT_P(ret->host);
> }
> ----------------------------------------------------
> Note: I'm using built-in strings to be sure that the recuperation
> doesn't change anything..
>
> This function works well:
> ----------------------------------------------------
> postgres=# CREATE OR REPLACE FUNCTION parse_url_key(text) RETURNS text
> AS '/home/samuel/parse_url.so', 'parse_url_key' LANGUAGE C;
> CREATE FUNCTION
> postgres=# SELECT parse_url_key('') as scheme;
> scheme
> ------------
> ww.ovh.com
> (1 row)
> ----------------------------------------------------
> Note: there's a little problem here but not important. :-)
>
> The problem is that the other function, "parse_url_record" doesn't
> return values ! The code is:
> ----------------------------------------------------
> PG_FUNCTION_INFO_V1(parse_url_record);
> Datum parse_url_record (PG_FUNCTION_ARGS)
> {
> // Vars about the params
> //text *str2 = PG_GETARG_TEXT_P(0);
> char str[] = "http://www.ovh.com/intenal.html";
>
> // Some vars which will used to create the composite output type
> TupleDesc tupdesc;
> Datum values[2]; // 8 values
> HeapTuple tuple;
> bool nulls[2];
> int tuplen;
>
> // Check NULLs values
> if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
> PG_RETURN_NULL();
> }
>
> url *ret = parse_url_exec(str);
>
> // Add datas into the values Datum
> values[0] = PointerGetDatum(ret->scheme);
> values[1] = PointerGetDatum(ret->host);
>
> // Convert values into a composite type
> /*tuplen = tupdesc->natts;
> nulls = palloc(tuplen * sizeof(bool));*/
> memset(nulls, 0, sizeof(nulls));
>
> // build tuple from datum array
> tuple = heap_form_tuple(tupdesc, values, nulls);
> // Free null values
> /*pfree(nulls);*/
>
> // Return the composite type
> PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
> }
> ----------------------------------------------------
> Note: I'm just returning scheme and host fields for test, but others are
> too completed by parse_url_exec.
>
> It doesn't works fine:
> ----------------------------------------------------
> postgres=# CREATE OR REPLACE FUNCTION parse_url_record(text) RETURNS
> record AS '/home/samuel/parse_url.so', 'parse_url_record' LANGUAGE C;
> CREATE FUNCTION
> postgres=# SELECT * FROM parse_url_record('') as ("scheme" text, "host"
> text);
> scheme | host
> --------+------
> |
> (1 row)
> ----------------------------------------------------
>
> Is there anybody here who can help me ?
>
> Thanks you very much !
> Samuel ROZE.
> http://www.d-sites.com
>
>