Thread: 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 > >