Обсуждение: return value of a version-1 C function (Solved)
[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
Вложения
Francesco Casadei <f_casadei@libero.it> writes: > 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 don't believe you need to. AFAICT, SPI_palloc will allocate in the context that was current when SPI_connect was called. Assuming that that was the active context when your function was entered, that is the right context to palloc your result value in. It's the executor's responsibility to clean up the result value, not yours. > 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; Right. As of 7.1 this should be VARATT_SIZEP(cod) = VARHDRSZ + 8; Did we miss any places in the documentation where this needs to be updated? > 3) The following variable is an identifier (Name): > Name tablename = PG_GETARG_NAME(0); > (void)strlcat(query, NameStr(fieldname), sizeof(query)); Should be NameStr(*tablename). Not too consistent maybe, but I didn't invent that macro ;-) regards, tom lane
On Tue, Jun 05, 2001 at 10:35:17AM -0400, Tom Lane wrote: > Francesco Casadei <f_casadei@libero.it> writes: > > 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 don't believe you need to. AFAICT, SPI_palloc will allocate in the > context that was current when SPI_connect was called. Assuming that > that was the active context when your function was entered, that is the > right context to palloc your result value in. It's the executor's > responsibility to clean up the result value, not yours. > > > 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; > > Right. As of 7.1 this should be > > VARATT_SIZEP(cod) = VARHDRSZ + 8; > > Did we miss any places in the documentation where this needs to be > updated? > > > 3) The following variable is an identifier (Name): > > > Name tablename = PG_GETARG_NAME(0); > > > (void)strlcat(query, NameStr(fieldname), sizeof(query)); > > Should be NameStr(*tablename). Not too consistent maybe, but I didn't > invent that macro ;-) > > regards, tom lane > > ---------------------------(end of broadcast)--------------------------- > TIP 2: you can get off all lists at once with the unregister command > (send "unregister YourEmailAddressHere" to majordomo@postgresql.org) > > end of the original message The example with Text in section 13.4 of the PostgreSQL 7.1.2 Programmer's Guide is quite self-explanatory. I was looking for BpChar and didn't pay attention to it. The docs talk about "variable-length types", bringing as example the text data type and I didn't know that fixed-length data type (CHAR(n), i.e. BpChar) are actually the same as TEXT, VARCHAR and bytea. The only difference is semantic. typedef struct varlena bytea; typedef struct varlena text; typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */ typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */ Next time I will read ALL the docs before doing anything, sorry. Francesco Casadei P.S. I attached the wrong file to my previous post: that was the old (wrong) version.