Thread: SPI example does not work for 7.1beta4

SPI example does not work for 7.1beta4

From
Limin Liu
Date:
Folks,

I am learning and using SPI. In PostgreSQL documentation chapter "Server
Programming Interface," there is a small example name "execq(text,
int)".

This example works as the document says on 7.0.3 and earlier version,
but this example DOES NOT work on my 7.1 beta4.

This is the error message I got.  I wonder does anyone test your SPI
functions on 7.1 beta?  Does anyone notice the problem I got here?
I know I should test this under beta6 before I post this message, but my
co-worker's anti-virus s/w gave him a virus warning message after him
finished the download of 7.1beta6 .gz!  :-)

------------
db1=# select execq('create table a (x int4)', 0);
pqReadData() -- backend closed the channel unexpectedly.
        This probably means the backend terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
!#
------------

Thanks for your help

--
LM Liu



Re: SPI example does not work for 7.1beta4

From
Tom Lane
Date:
Limin Liu <limin@pumpkinnet.com> writes:
> I am learning and using SPI. In PostgreSQL documentation chapter "Server
> Programming Interface," there is a small example name "execq(text,
> int)".
> This example works as the document says on 7.0.3 and earlier version,
> but this example DOES NOT work on my 7.1 beta4.

Hm.  textout() can't be called that way anymore --- as indeed your compiler
should have told you, if it's any good at all.  I get

execq.c: In function `execq':
execq.c:13: warning: passing arg 1 of `textout' from incompatible pointer type
execq.c:13: warning: passing arg 1 of `SPI_exec' makes pointer from integer without a cast

Looks like the example is in need of update.  Thanks for the report.

            regards, tom lane

Re: SPI example does not work for 7.1beta4

From
Limin Liu
Date:
Thanks Tom,

By the way, did you change the whole archetecture of SPI invocation?

I put
---
   SPI_connect();
   SPI_exec("create temp table tbl_tmp (n int);",0);
   SPI_exec("insert into tbl_tmp values (1);",0);
   SPI_finish();
---
after InitPostgres and before setsigjmp().
This works perfectly in my 7.03 and earlier version.  That means, after authentication, we
will have a temp table per each db connection.  User can use the client program to "select"
or "insert" upon this temp table.

However, the same code does not work in 7.1.  Actually, I got some messages contradicting to
each other:
---
db1=> select * from tbl_tmp;
ERROR:  Relation 'tbl_tmp' does not exist
db1=> create temp table tbl_tmp (n int);
ERROR:  Relation 'tbl_tmp' already exists
db1=>
---

Can you please give us some hints on what's going on here?

Thanks

Tom Lane wrote:

> Limin Liu <limin@pumpkinnet.com> writes:
> > I am learning and using SPI. In PostgreSQL documentation chapter "Server
> > Programming Interface," there is a small example name "execq(text,
> > int)".
> > This example works as the document says on 7.0.3 and earlier version,
> > but this example DOES NOT work on my 7.1 beta4.
>
> Hm.  textout() can't be called that way anymore --- as indeed your compiler
> should have told you, if it's any good at all.  I get
>
> execq.c: In function `execq':
> execq.c:13: warning: passing arg 1 of `textout' from incompatible pointer type
> execq.c:13: warning: passing arg 1 of `SPI_exec' makes pointer from integer without a cast
>
> Looks like the example is in need of update.  Thanks for the report.
>
>                         regards, tom lane

--
LM Liu

Re: SPI example does not work for 7.1beta4

From
Tom Lane
Date:
Limin Liu <limin@pumpkinnet.com> writes:
> By the way, did you change the whole archetecture of SPI invocation?

No, I told you: what's broken here is the textout() call.  Attached
is the updated example.

> I put
> ---
>    SPI_connect();
>    SPI_exec("create temp table tbl_tmp (n int);",0);
>    SPI_exec("insert into tbl_tmp values (1);",0);
>    SPI_finish();
> ---
> after InitPostgres and before setsigjmp().

I doubt this will work correctly without a transaction around it ...

            regards, tom lane


#include "executor/spi.h"   /* this is what you need to work with SPI */

int execq(text *sql, int cnt);

int
execq(text *sql, int cnt)
{
    char *query;
    int ret;
    int proc;

    /* Convert given TEXT object to a C string */
    query = DatumGetCString(DirectFunctionCall1(textout,
                                                PointerGetDatum(sql)));

    SPI_connect();

    ret = SPI_exec(query, cnt);

    proc = SPI_processed;
    /*
     * If this is SELECT and some tuple(s) fetched -
     * returns tuples to the caller via elog (NOTICE).
     */
    if ( ret == SPI_OK_SELECT && SPI_processed > 0 )
    {
        TupleDesc tupdesc = SPI_tuptable->tupdesc;
        SPITupleTable *tuptable = SPI_tuptable;
        char buf[8192];
        int i,j;

        for (j = 0; j < proc; j++)
        {
            HeapTuple tuple = tuptable->vals[j];

            for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
                sprintf(buf + strlen (buf), " %s%s",
                        SPI_getvalue(tuple, tupdesc, i),
                        (i == tupdesc->natts) ? " " : " |");
            elog (NOTICE, "EXECQ: %s", buf);
        }
    }

    SPI_finish();

    pfree(query);

    return (proc);
}