BUG #8524: PQsendQueryParams with RETURNING clause on a INSERT

From: peter(dot)reijnders(at)verpeteren(dot)nl
To: pgsql-bugs(at)postgresql(dot)org
Subject: BUG #8524: PQsendQueryParams with RETURNING clause on a INSERT
Date: 2013-10-13 09:30:10
Message-ID: E1VVI02-0007ky-OM@wrigleys.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 8524
Logged by: Peter Reijnders
Email address: peter(dot)reijnders(at)verpeteren(dot)nl
PostgreSQL version: 9.1.9
Operating system: Debian Wheezy
Description:

Hai

I am implementing a postgresql database interface with mozilla's
spidermonkey.
So that users can use Postgresql querys in serverside javascript. It goes
rather well!
I prefer to give the users flexibility:
- they should be able to use multiple statements in one request.
- they should be able to send parameterised querys.
- the result of the query should be accessible.
I thougth that the following code was providing a good balance:

if (queue->nParams == 0) {
rc = PQsendQuery(myhandle->conn, queue->statement);
} else {
//only Version 2 protocoll, and only one command per statement
rc = PQsendQueryParams(myhandle->conn, queue->statement, queue->nParams,
NULL, queue->paramValues, queue->paramLengths, NULL, 1);
}

I am having troubles with a the RETURNING clause on a INSERT when using
PQsendQueryParams.
PQsendQuery is returning the record as it has been written to to database.
PQsendQueryParams appears just to be returning the records, before these
have been written.
That means that defaults and serial fields are ('') empty.
Am I doing something wrong, or is PQsendQueryParams indeed behaving
differently then PQsendQuery.
I looked on the TODO list for libpq, the faq, the documentation, and
google-fu. but I have not found any reference.
Any pointers, tips, comments, workarounds etc are greatly appreciated.

I am using:
debian wheezy`s postgresql-server: 9.1.9-1 and libpq-dev 9.1.9-1.
select version();: PostgreSQL 9.1.9 on i686-pc-linux-gnu, compiled by gcc
(Debian 4.7.2-5) 4.7.2, 32-bit
uname -a: Linux P2201 3.2.0-4-686-pae #1 SMP Debian 3.2.46-1+deb7u1 i686
GNU/Linux
installed via apt-get
changes to the configuration are basically involving more logging, so I can
see the results of my development
log_connections = on
log_disconnections = on
log_statements = 'all'
listen_address = '10.0.0.25'
I could reproduce this also on another machine using
debian sid`s postgresql-server 9.3.1-1 and libpq-dev 9.3.1-1.
select version();: PostgreSQL 9.3.1 on i686-pc-linux-gnu, compiled by gcc
(Debian 4.8.1-10) 4.8.1, 32-bit
uname -a: Linux L1866 2.6.32-5-686 #1 SMP Sun May 6 04:01:19 UTC 2012 i686
GNU/Linux
installed via apt-get
changes to the configuration are basically involving more logging, so I can
see the results of my development
log_connections = on
log_disconnections = on
log_statements = 'all'
listen_address = '10.0.0.34'

Steps to reproduce are possible via the snippets here below.

---%<---------- create a simple table with default and primary key -----
CREATE TABLE IF NOT EXISTS foo (
id SERIAL PRIMARY KEY,
ed INTEGER,
t TIMESTAMP DEFAULT now(),
bar VARCHAR(32),
listint integer[]
) WITH OIDS ;
NOTICE: CREATE TABLE will create implicit sequence "foo_id_seq" for serial
column "foo.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey"
for table "foo"
--->%---------------

---%<---------- create a simple Makefile (Makefile)-----
all: sendQuery sendQueryParams

sendQuery: test.c
gcc -o sendQuery test.c -I /usr/include/postgresql -L /usr/lib -lpq

sendQueryParams: test.c
gcc -o sendQueryParams test.c -I /usr/include/postgresql -L /usr/lib -lpq
-D PARAMS=2

.PHONEY: clean

clean:
rm -rf sendQuery sendQueryParams

--->%---------------

---%<---------- create a simple test case (test.c) -----
/*
* Test RETURNING CLAUSE WITH PQsendQueryParams and PQsendQuery
* Code based upon examples out "PostgreSQL: A Comprehensive Guide to
Building, Programming, and ..; By Korry Douglas, Susan Douglas*"
*
* I am having troubles with a the RETURNING clause on a INSERT when using
PQsendQueryParams.
* PQsendQuery is returning the record as it has been written to to
database. PQsendQueryParams appears just to be returning the records, before
these have been written.
* That means that defaults and serial fields are ('') empty.
*
*
* A simple insert, via PQSendQuery.
* This is returning the record with the data as it has been written to the
database.
* --> It is working as expected. YAY!
*
* $./sendQuery "hostaddr=10.0.0.25 dbname=apedevdb user=apedev
password=vedepa port=5432"
* INSERT INTO foo (ed, bar) VALUES (6, 'cool') RETURNING *; submit: 1
*
* Record: 0
* id: 40
* ed: 6
* t: 2013-10-13 11:09:37.069289
* bar: cool
* listint:
*
*
* A insert with parameters, via PQsendQueryParams.
* The id and the t colums are filled in the database, but these "written"
values are not in the returning record.
* --> It is NOT working as expected. :-(i
*
* $ ./sendQueryParams "hostaddr=10.0.0.25 dbname=apedevdb user=apedev
password=vedepa port=5432"
* INSERT INTO foo (ed, bar) VALUES ($1, $2) RETURNING *; submit: 1
*
* Record: 0
* id:
* ed:
* t:
* bar: Beatnuts`, no escapin' this!
* listint:
*
*
* The following table must be created, as this is used for the insert
statements.
CREATE TABLE IF NOT EXISTS foo (
id SERIAL PRIMARY KEY,
ed INTEGER,
t TIMESTAMP DEFAULT now(),
bar VARCHAR(32),
listint integer[]
) WITH OIDS ;'
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <libpq-fe.h>

void print_result_set(PGresult *result) {
int row, col, fields, records;

records = PQntuples(result);
for (row =0; row < records; row++) {
fields = PQnfields(result);
printf("Record: %d\n" , row);
for (col = 0; col < fields; col++ ) {
printf("\t%s:\t%s\n", PQfname(result, col), PQgetvalue(result, row,
col));
}
}
printf("\n");
}

int is_result_ready(PGconn * connection) {
int my_socket;
struct timeval timer;
fd_set read_mask;

if (PQisBusy(connection) == 0) {
return 1;
}
my_socket = PQsocket (connection);
timer.tv_sec = (time_t) 1;
timer.tv_usec =0;
FD_ZERO (&read_mask);
FD_SET(my_socket, &read_mask);
if (select(my_socket + 1, &read_mask, NULL, NULL, &timer) == 0 ) {
return 0;
} else if (FD_ISSET(my_socket, &read_mask)) {
PQconsumeInput(connection);
if (PQisBusy (connection) ==0 ) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
}

int process_query(PGconn * connection) {
int submitted;
PGresult * result;
#ifdef PARAMS
const char *query_text = "INSERT INTO foo (ed, bar) VALUES ($1, $2)
RETURNING *;";
const char *paramValues[PARAMS];
int paramLengths[PARAMS], i;

paramValues[0] = "6";
paramValues[1] = "Beatnuts`, no escapin' this!";
for (i = 0; i <PARAMS; i++) {
paramLengths[i] = strlen(paramValues[i]);
}
submitted = PQsendQueryParams( connection, query_text, PARAMS, NULL,
paramValues, paramLengths, NULL, 1);
#else
const char *query_text = "INSERT INTO foo (ed, bar) VALUES (6, \'cool\')
RETURNING *;";

submitted = PQsendQuery( connection, query_text);
#endif
printf("%s submit: %d\n", query_text, submitted);
if (submitted == 0 ) {
printf ("%d\n", PQerrorMessage(connection));
return;
}
do {
while (is_result_ready( connection) == 0 ) {
putchar ('.');
fflush (stdout);
}
printf("\n");
if (( result = PQgetResult(connection)) != NULL) {
if (PQresultStatus (result) == PGRES_TUPLES_OK) {
print_result_set(result);
} else if (PQresultStatus (result ) == PGRES_COMMAND_OK) {
printf ("%s", PQcmdStatus(result));
if (strlen(PQcmdTuples(result))) {
printf(" - %s rows\t", PQcmdTuples (result));
} else {
printf ("\n");
}
} else {
printf ("%s\n", PQresultErrorMessage(result));
}
PQclear(result);
}
} while (result != NULL);
}

void usage(char **argv) {
printf("Usage: %s \"connection string\n\"", argv[0]);
printf(" e.g.: %s \"hostaddr=10.0.0.25 dbname=apedevdb user=apedev
password=vedepa port=5432\"\n", argv[0]);
exit(1);
}

int main(int argc, char **argv) {
PGconn *connection;

if (argc != 2 ) {
usage(argv);
}
if (( connection = PQconnectdb(argv[1])) == NULL) {
printf("Unable to allocate connection\n");
exit(1);
}
if (PQstatus(connection) != CONNECTION_OK) {
printf("%s\n", PQerrorMessage(connection));
exit(1);
}
process_query(connection);
PQfinish(connection);

return 0;
}

--->%---------------

---%<---------- shell -----
peter(at)P2201:~/Development/src/libpq$ make
gcc -o sendQuery test.c -I /usr/include/postgresql -L /usr/lib -lpq
gcc -o sendQueryParams test.c -I /usr/include/postgresql -L /usr/lib -lpq -D
PARAMS=2
peter(at)P2201:~/Development/src/libpq$ ./sendQueryParams "hostaddr=10.0.0.25
dbname=apedevdb user=apedev password=vedepa port=5432"
INSERT INTO foo (ed, bar) VALUES ($1, $2) RETURNING *; submit: 1

Record: 0
id:
ed:
t:
bar: Beatnuts`, no escapin' this!
listint:

peter(at)P2201:~/Development/src/libpq$ ./sendQuery "hostaddr=10.0.0.25
dbname=apedevdb user=apedev password=vedepa port=5432"INSERT INTO foo (ed,
bar) VALUES (6, 'cool') RETURNING *; submit: 1

Record: 0
id: 45
ed: 6
t: 2013-10-13 11:14:54.029993
bar: cool
listint:

tail -f /var/log/postgresql/postgresql-9.1-main.log
2013-10-13 11:14:42 CEST LOG: connection received:
host=statusclick.bieosthoes.net port=58441
2013-10-13 11:14:42 CEST LOG: connection authorized: user=apedev
database=apedevdb
2013-10-13 11:14:42 CEST LOG: execute <unnamed>: INSERT INTO foo (ed, bar)
VALUES ($1, $2) RETURNING *;
2013-10-13 11:14:42 CEST DETAIL: parameters: $1 = '6', $2 = 'Beatnuts`, no
escapin'' this!'
2013-10-13 11:14:42 CEST LOG: disconnection: session time: 0:00:00.075
user=apedev database=apedevdb host=statusclick.bieosthoes.net port=58441

2013-10-13 11:14:53 CEST LOG: connection received:
host=statusclick.bieosthoes.net port=58442
2013-10-13 11:14:54 CEST LOG: connection authorized: user=apedev
database=apedevdb
2013-10-13 11:14:54 CEST LOG: statement: INSERT INTO foo (ed, bar) VALUES
(6, 'cool') RETURNING *;
2013-10-13 11:14:54 CEST LOG: disconnection: session time: 0:00:00.077
user=apedev database=apedevdb host=statusclick.bieosthoes.net port=58442

--->%---------------

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Greg Stark 2013-10-14 02:56:37 Re: BUG #8515: Random 'relation "..." does not exist'
Previous Message John R Pierce 2013-10-12 22:17:34 Re: BUG #8515: Random 'relation "..." does not exist'