Thread: return value of a version-1 C function (Solved)

return value of a version-1 C function (Solved)

From
Francesco Casadei
Date:
[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

Attachment

Re: return value of a version-1 C function (Solved)

From
Tom Lane
Date:
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

Re: return value of a version-1 C function (Solved)

From
Francesco Casadei
Date:
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.