[This message refers to my previous post '[GENERAL] return value of a version-1 C function'] Ooops, I didn't read the docs very carefully! I solved the problem, by declaring cod as a proper structure and then returning it with PG_RETURN_BPCHAR_P(cod): BpChar *cod = (BpChar *)SPI_palloc(VARHDRSZ + 8); char c[9]; ... /* c = generated code (8 chars) + '\0' */ ... cod->vl_len = VARHDRSZ + 8; memmove(VARDATA(cod), c, 8); PG_RETURN_BPCHAR_P(cod); } Now I have three more questions! 1) SPI_connect() and SPI_finish() mark a new memory context; since I must return cod I need to SPI_palloc() it in the upper Executor context. The problem is: how can I free the SPI_palloc()'ed memory? I can't SPI_pfree() it before PG_RETURN_BPCHAR_P(cod), conversely nothing after PG_RETURN_BPCHAR_P(cod) would be executed. As stated in section 22.3 of the PostgreSQL Programmer's Guide 'SPI has no ability to automatically free allocations in the upper Executor context!', hence the question: how do I cope with this situation? 2) If I use the VARSIZE(__PTR) macro (defined in postgres.h) to set the size of cod, the compiler will complain about an invalid lvalue. This is not valid: VARSIZE(cod) = VARHDRSZ + 8; Can I safely use: cod->vl_len = VARHDRSZ + 8; or is this incorrect? 3) The following variable is an identifier (Name): Name tablename = PG_GETARG_NAME(0); If I want to retrieve the string contained in the union pointed to by tablename I should use the macro NameStr(name) defined in c.h: (void)strlcat(query, NameStr(fieldname), sizeof(query)); but again the compiler will complain with the error "request for member `data' in something not a structure or union". Name is a pointer to NameData union: typedef union nameData { char data[NAMEDATALEN]; int alignmentDummy; } NameData; typedef NameData *Name; NameStr is defined as: #define NameStr(name) ((name).data) but name is a pointer, so shouldn't NameStr be defined as: #define NameStr(name) ((name)->data) ? Is it correct to use: tablename->data? I attached the C code of the function. I'm not a C/PostgreSQL guru, so ANY suggestion is welcome. Thanks in advance for your help. Francesco Casadei
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sysexits.h> #include "postgres.h" #include "fmgr.h" #include "executor/spi.h" char cod[8]; /* codice di otto lettere */ PG_FUNCTION_INFO_V1(genera_codice); Datum genera_codice(PG_FUNCTION_ARGS) { int i; char n; /* numero pseudo-casuale */ char c[9]; /* codice di otto lettere + NULL */ char query[1024]; /* testo della query per selezionare il codice */ Name tablename = PG_GETARG_NAME(0); Name fieldname = PG_GETARG_NAME(1); elog(DEBUG, "tablename: %s", tablename->data); elog(DEBUG, "fieldname: %s", fieldname->data); /* Connette la procedura all'SPI manager */ if (SPI_connect() != SPI_OK_CONNECT) PG_RETURN_NULL(); do { /* Genera il codice di otto lettere */ for (i = 0; i < 8; i++) { srandomdev(); n = (char)(random() % 62); /* Numero pseudo-casuale compreso tra 0 e 61 */ if (n <= 25) { /* 0 <= n <= 25: lettera tra 'A' e 'Z' (alfabeto inglese) */ cod[i] = n + 'A'; c[i] = cod[i]; } else if (n <= 51) { /* 26 <= n <= 51: lettera tra 'a' e 'z' (alfabeto inglese) */ cod[i] = (n - 26) + 'a'; c[i] = cod[i]; } else { /* 52 <= n <= 61: cifra tra '0' e '9' */ cod[i] = (n - 52) + '0'; c[i] = cod[i]; } } c[i] = '\0'; elog(DEBUG, "Generated code: %s", c); /* * Prepara il testo della query che verifica se nella base di dati * e' gia' presente il codice appena generato */ bzero(query, sizeof(query)); (void)strlcat(query, "SELECT ", sizeof(query)); (void)strlcat(query, fieldname->data, sizeof(query)); (void)strlcat(query, " FROM ", sizeof(query)); (void)strlcat(query, tablename->data, sizeof(query)); (void)strlcat(query, " WHERE ", sizeof(query)); (void)strlcat(query, fieldname->data, sizeof(query)); (void)strlcat(query, " = '", sizeof(query)); (void)strlcat(query, c, sizeof(query)); (void)strlcat(query, "';", sizeof(query)); elog(DEBUG, "Query text: %s", query); /* Esegue la query per cercare il codice generato */ if (SPI_exec(query, 1) != SPI_OK_SELECT) { SPI_finish(); PG_RETURN_NULL(); } /* * Se la query ritorna 0 tuple allora il codice non e' presente nella base * di dati e il ciclo puo' terminare. * In caso contrario (la query ritorna una tupla) e' necessario eseguire un * altro ciclo per generare un nuovo codice. */ } while (SPI_processed > 0); /* Disconnette la procedura dall'SPI manager */ SPI_finish(); PG_RETURN_BPCHAR_P(cod); }
---------------------------(end of broadcast)--------------------------- TIP 6: Have you searched our list archives? http://www.postgresql.org/search.mpl