mirror of https://github.com/postgres/postgres
Improve testlibpq3.c's example of PQexecParams() usage to include sending
a parameter in binary format. Also, add a TIP explaining how to use casts in the query text to avoid needing to specify parameter types by OID. Also fix bogus spacing --- apparently somebody expanded the tabs in the example programs to 8 spaces instead of 4 when transposing them into SGML.
This commit is contained in:
parent
61abd9a3fb
commit
d1959f9ff6
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.195 2005/10/20 21:04:14 neilc Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.196 2005/10/20 23:57:51 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="libpq">
|
<chapter id="libpq">
|
||||||
|
@ -1187,6 +1187,26 @@ than one nonempty command.) This is a limitation of the underlying protocol,
|
||||||
but has some usefulness as an extra defense against SQL-injection attacks.
|
but has some usefulness as an extra defense against SQL-injection attacks.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<tip>
|
||||||
|
<para>
|
||||||
|
Specifying parameter types via OIDs is tedious, particularly if you prefer
|
||||||
|
not to hard-wire particular OID values into your program. However, you can
|
||||||
|
avoid doing so even in cases where the server by itself cannot determine the
|
||||||
|
type of the parameter, or chooses a different type than you want. In the
|
||||||
|
SQL command text, attach an explicit cast to the parameter symbol to show what
|
||||||
|
data type you will send. For example,
|
||||||
|
<programlisting>
|
||||||
|
select * from mytable where x = $1::bigint;
|
||||||
|
</programlisting>
|
||||||
|
This forces parameter <literal>$1</> to be treated as <type>bigint</>, whereas
|
||||||
|
by default it would be assigned the same type as <literal>x</>. Forcing the
|
||||||
|
parameter type decision, either this way or by specifying a numeric type OID,
|
||||||
|
is strongly recommended when sending parameter values in binary format, because
|
||||||
|
binary format has less redundancy than text format and so there is less chance
|
||||||
|
that the server will detect a type mismatch mistake for you.
|
||||||
|
</para>
|
||||||
|
</tip>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -4226,7 +4246,7 @@ testlibpq.o(.text+0xa4): undefined reference to `PQerrorMessage'
|
||||||
/*
|
/*
|
||||||
* testlibpq.c
|
* testlibpq.c
|
||||||
*
|
*
|
||||||
* Test the C version of LIBPQ, the POSTGRES frontend library.
|
* Test the C version of libpq, the PostgreSQL frontend library.
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -4235,112 +4255,111 @@ testlibpq.o(.text+0xa4): undefined reference to `PQerrorMessage'
|
||||||
static void
|
static void
|
||||||
exit_nicely(PGconn *conn)
|
exit_nicely(PGconn *conn)
|
||||||
{
|
{
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *conninfo;
|
const char *conninfo;
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
int nFields;
|
int nFields;
|
||||||
int i,
|
int i,
|
||||||
j;
|
j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user supplies a parameter on the command line, use it as
|
* If the user supplies a parameter on the command line, use it as the
|
||||||
* the conninfo string; otherwise default to setting dbname=postgres
|
* conninfo string; otherwise default to setting dbname=postgres and using
|
||||||
* and using environment variables or defaults for all other connection
|
* environment variables or defaults for all other connection parameters.
|
||||||
* parameters.
|
*/
|
||||||
*/
|
if (argc > 1)
|
||||||
if (argc > 1)
|
conninfo = argv[1];
|
||||||
conninfo = argv[1];
|
else
|
||||||
else
|
conninfo = "dbname = postgres";
|
||||||
conninfo = "dbname = postgres";
|
|
||||||
|
|
||||||
/* Make a connection to the database */
|
/* Make a connection to the database */
|
||||||
conn = PQconnectdb(conninfo);
|
conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
/* Check to see that the backend connection was successfully made */
|
/* Check to see that the backend connection was successfully made */
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Connection to database failed: %s",
|
fprintf(stderr, "Connection to database failed: %s",
|
||||||
PQerrorMessage(conn));
|
PQerrorMessage(conn));
|
||||||
exit_nicely(conn);
|
exit_nicely(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our test case here involves using a cursor, for which we must be
|
* Our test case here involves using a cursor, for which we must be inside
|
||||||
* inside a transaction block. We could do the whole thing with a
|
* a transaction block. We could do the whole thing with a single
|
||||||
* single PQexec() of "select * from pg_database", but that's too
|
* PQexec() of "select * from pg_database", but that's too trivial to make
|
||||||
* trivial to make a good example.
|
* a good example.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Start a transaction block */
|
/* Start a transaction block */
|
||||||
res = PQexec(conn, "BEGIN");
|
res = PQexec(conn, "BEGIN");
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
|
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Should PQclear PGresult whenever it is no longer needed to avoid
|
|
||||||
* memory leaks
|
|
||||||
*/
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch rows from pg_database, the system catalog of databases
|
* Should PQclear PGresult whenever it is no longer needed to avoid memory
|
||||||
*/
|
* leaks
|
||||||
res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
|
*/
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
PQclear(res);
|
||||||
{
|
|
||||||
fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
|
/*
|
||||||
PQclear(res);
|
* Fetch rows from pg_database, the system catalog of databases
|
||||||
exit_nicely(conn);
|
*/
|
||||||
}
|
res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
res = PQexec(conn, "FETCH ALL in myportal");
|
res = PQexec(conn, "FETCH ALL in myportal");
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
|
fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first, print out the attribute names */
|
|
||||||
nFields = PQnfields(res);
|
|
||||||
for (i = 0; i < nFields; i++)
|
|
||||||
printf("%-15s", PQfname(res, i));
|
|
||||||
printf("\n\n");
|
|
||||||
|
|
||||||
/* next, print out the rows */
|
|
||||||
for (i = 0; i < PQntuples(res); i++)
|
|
||||||
{
|
|
||||||
for (j = 0; j < nFields; j++)
|
|
||||||
printf("%-15s", PQgetvalue(res, i, j));
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/* close the portal ... we don't bother to check for errors ... */
|
/* first, print out the attribute names */
|
||||||
res = PQexec(conn, "CLOSE myportal");
|
nFields = PQnfields(res);
|
||||||
PQclear(res);
|
for (i = 0; i < nFields; i++)
|
||||||
|
printf("%-15s", PQfname(res, i));
|
||||||
|
printf("\n\n");
|
||||||
|
|
||||||
/* end the transaction */
|
/* next, print out the rows */
|
||||||
res = PQexec(conn, "END");
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
PQclear(res);
|
{
|
||||||
|
for (j = 0; j < nFields; j++)
|
||||||
|
printf("%-15s", PQgetvalue(res, i, j));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* close the connection to the database and cleanup */
|
PQclear(res);
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
return 0;
|
/* close the portal ... we don't bother to check for errors ... */
|
||||||
|
res = PQexec(conn, "CLOSE myportal");
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/* end the transaction */
|
||||||
|
res = PQexec(conn, "END");
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/* close the connection to the database and cleanup */
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
@ -4351,7 +4370,7 @@ main(int argc, char **argv)
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/*
|
/*
|
||||||
* testlibpq2.c
|
* testlibpq2.c
|
||||||
* Test of the asynchronous notification interface
|
* Test of the asynchronous notification interface
|
||||||
*
|
*
|
||||||
* Start this program, then from psql in another window do
|
* Start this program, then from psql in another window do
|
||||||
* NOTIFY TBL2;
|
* NOTIFY TBL2;
|
||||||
|
@ -4382,102 +4401,101 @@ main(int argc, char **argv)
|
||||||
static void
|
static void
|
||||||
exit_nicely(PGconn *conn)
|
exit_nicely(PGconn *conn)
|
||||||
{
|
{
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *conninfo;
|
const char *conninfo;
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
PGnotify *notify;
|
PGnotify *notify;
|
||||||
int nnotifies;
|
int nnotifies;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user supplies a parameter on the command line, use it as
|
* If the user supplies a parameter on the command line, use it as the
|
||||||
* the conninfo string; otherwise default to setting dbname=postgres
|
* conninfo string; otherwise default to setting dbname=postgres and using
|
||||||
* and using environment variables or defaults for all other connection
|
* environment variables or defaults for all other connection parameters.
|
||||||
* parameters.
|
*/
|
||||||
*/
|
if (argc > 1)
|
||||||
if (argc > 1)
|
conninfo = argv[1];
|
||||||
conninfo = argv[1];
|
else
|
||||||
else
|
conninfo = "dbname = postgres";
|
||||||
conninfo = "dbname = postgres";
|
|
||||||
|
|
||||||
/* Make a connection to the database */
|
/* Make a connection to the database */
|
||||||
conn = PQconnectdb(conninfo);
|
conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
/* Check to see that the backend connection was successfully made */
|
/* Check to see that the backend connection was successfully made */
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Connection to database failed: %s",
|
fprintf(stderr, "Connection to database failed: %s",
|
||||||
PQerrorMessage(conn));
|
PQerrorMessage(conn));
|
||||||
exit_nicely(conn);
|
exit_nicely(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
|
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
|
||||||
*/
|
*/
|
||||||
res = PQexec(conn, "LISTEN TBL2");
|
res = PQexec(conn, "LISTEN TBL2");
|
||||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
|
fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* should PQclear PGresult whenever it is no longer needed to avoid
|
|
||||||
* memory leaks
|
|
||||||
*/
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/* Quit after four notifies are received. */
|
/*
|
||||||
nnotifies = 0;
|
* should PQclear PGresult whenever it is no longer needed to avoid memory
|
||||||
while (nnotifies < 4)
|
* leaks
|
||||||
|
*/
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/* Quit after four notifies are received. */
|
||||||
|
nnotifies = 0;
|
||||||
|
while (nnotifies < 4)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Sleep until something happens on the connection. We use select(2)
|
||||||
|
* to wait for input, but you could also use poll() or similar
|
||||||
|
* facilities.
|
||||||
|
*/
|
||||||
|
int sock;
|
||||||
|
fd_set input_mask;
|
||||||
|
|
||||||
|
sock = PQsocket(conn);
|
||||||
|
|
||||||
|
if (sock < 0)
|
||||||
|
break; /* shouldn't happen */
|
||||||
|
|
||||||
|
FD_ZERO(&input_mask);
|
||||||
|
FD_SET(sock, &input_mask);
|
||||||
|
|
||||||
|
if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
|
||||||
{
|
{
|
||||||
/*
|
fprintf(stderr, "select() failed: %s\n", strerror(errno));
|
||||||
* Sleep until something happens on the connection. We use select(2)
|
exit_nicely(conn);
|
||||||
* to wait for input, but you could also use poll() or similar
|
|
||||||
* facilities.
|
|
||||||
*/
|
|
||||||
int sock;
|
|
||||||
fd_set input_mask;
|
|
||||||
|
|
||||||
sock = PQsocket(conn);
|
|
||||||
|
|
||||||
if (sock < 0)
|
|
||||||
break; /* shouldn't happen */
|
|
||||||
|
|
||||||
FD_ZERO(&input_mask);
|
|
||||||
FD_SET(sock, &input_mask);
|
|
||||||
|
|
||||||
if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "select() failed: %s\n", strerror(errno));
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now check for input */
|
|
||||||
PQconsumeInput(conn);
|
|
||||||
while ((notify = PQnotifies(conn)) != NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"ASYNC NOTIFY of '%s' received from backend pid %d\n",
|
|
||||||
notify->relname, notify->be_pid);
|
|
||||||
PQfreemem(notify);
|
|
||||||
nnotifies++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Done.\n");
|
/* Now check for input */
|
||||||
|
PQconsumeInput(conn);
|
||||||
|
while ((notify = PQnotifies(conn)) != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"ASYNC NOTIFY of '%s' received from backend pid %d\n",
|
||||||
|
notify->relname, notify->be_pid);
|
||||||
|
PQfreemem(notify);
|
||||||
|
nnotifies++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* close the connection to the database and cleanup */
|
fprintf(stderr, "Done.\n");
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
return 0;
|
/* close the connection to the database and cleanup */
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
@ -4488,7 +4506,7 @@ main(int argc, char **argv)
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/*
|
/*
|
||||||
* testlibpq3.c
|
* testlibpq3.c
|
||||||
* Test out-of-line parameters and binary I/O.
|
* Test out-of-line parameters and binary I/O.
|
||||||
*
|
*
|
||||||
* Before running this, populate a database with the following commands
|
* Before running this, populate a database with the following commands
|
||||||
* (provided in src/test/examples/testlibpq3.sql):
|
* (provided in src/test/examples/testlibpq3.sql):
|
||||||
|
@ -4505,6 +4523,10 @@ main(int argc, char **argv)
|
||||||
* t = (11 bytes) 'joe's place'
|
* t = (11 bytes) 'joe's place'
|
||||||
* b = (5 bytes) \000\001\002\003\004
|
* b = (5 bytes) \000\001\002\003\004
|
||||||
*
|
*
|
||||||
|
* tuple 0: got
|
||||||
|
* i = (4 bytes) 2
|
||||||
|
* t = (8 bytes) 'ho there'
|
||||||
|
* b = (5 bytes) \004\003\002\001\000
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -4520,125 +4542,178 @@ main(int argc, char **argv)
|
||||||
static void
|
static void
|
||||||
exit_nicely(PGconn *conn)
|
exit_nicely(PGconn *conn)
|
||||||
{
|
{
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function prints a query result that is a binary-format fetch from
|
||||||
|
* a table defined as in the comment above. We split it out because the
|
||||||
|
* main() function uses it twice.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_binary_results(PGresult *res)
|
||||||
|
{
|
||||||
|
int i,
|
||||||
|
j;
|
||||||
|
int i_fnum,
|
||||||
|
t_fnum,
|
||||||
|
b_fnum;
|
||||||
|
|
||||||
|
/* Use PQfnumber to avoid assumptions about field order in result */
|
||||||
|
i_fnum = PQfnumber(res, "i");
|
||||||
|
t_fnum = PQfnumber(res, "t");
|
||||||
|
b_fnum = PQfnumber(res, "b");
|
||||||
|
|
||||||
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
|
{
|
||||||
|
char *iptr;
|
||||||
|
char *tptr;
|
||||||
|
char *bptr;
|
||||||
|
int blen;
|
||||||
|
int ival;
|
||||||
|
|
||||||
|
/* Get the field values (we ignore possibility they are null!) */
|
||||||
|
iptr = PQgetvalue(res, i, i_fnum);
|
||||||
|
tptr = PQgetvalue(res, i, t_fnum);
|
||||||
|
bptr = PQgetvalue(res, i, b_fnum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The binary representation of INT4 is in network byte order, which
|
||||||
|
* we'd better coerce to the local byte order.
|
||||||
|
*/
|
||||||
|
ival = ntohl(*((uint32_t *) iptr));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The binary representation of TEXT is, well, text, and since libpq
|
||||||
|
* was nice enough to append a zero byte to it, it'll work just fine
|
||||||
|
* as a C string.
|
||||||
|
*
|
||||||
|
* The binary representation of BYTEA is a bunch of bytes, which could
|
||||||
|
* include embedded nulls so we have to pay attention to field length.
|
||||||
|
*/
|
||||||
|
blen = PQgetlength(res, i, b_fnum);
|
||||||
|
|
||||||
|
printf("tuple %d: got\n", i);
|
||||||
|
printf(" i = (%d bytes) %d\n",
|
||||||
|
PQgetlength(res, i, i_fnum), ival);
|
||||||
|
printf(" t = (%d bytes) '%s'\n",
|
||||||
|
PQgetlength(res, i, t_fnum), tptr);
|
||||||
|
printf(" b = (%d bytes) ", blen);
|
||||||
|
for (j = 0; j < blen; j++)
|
||||||
|
printf("\\%03o", bptr[j]);
|
||||||
|
printf("\n\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *conninfo;
|
const char *conninfo;
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
const char *paramValues[1];
|
const char *paramValues[1];
|
||||||
int i,
|
int paramLengths[1];
|
||||||
j;
|
int paramFormats[1];
|
||||||
int i_fnum,
|
uint32_t binaryIntVal;
|
||||||
t_fnum,
|
|
||||||
b_fnum;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user supplies a parameter on the command line, use it as
|
* If the user supplies a parameter on the command line, use it as the
|
||||||
* the conninfo string; otherwise default to setting dbname=postgres
|
* conninfo string; otherwise default to setting dbname=postgres and using
|
||||||
* and using environment variables or defaults for all other connection
|
* environment variables or defaults for all other connection parameters.
|
||||||
* parameters.
|
*/
|
||||||
*/
|
if (argc > 1)
|
||||||
if (argc > 1)
|
conninfo = argv[1];
|
||||||
conninfo = argv[1];
|
else
|
||||||
else
|
conninfo = "dbname = postgres";
|
||||||
conninfo = "dbname = postgres";
|
|
||||||
|
|
||||||
/* Make a connection to the database */
|
/* Make a connection to the database */
|
||||||
conn = PQconnectdb(conninfo);
|
conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
/* Check to see that the backend connection was successfully made */
|
/* Check to see that the backend connection was successfully made */
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Connection to database failed: %s",
|
fprintf(stderr, "Connection to database failed: %s",
|
||||||
PQerrorMessage(conn));
|
PQerrorMessage(conn));
|
||||||
exit_nicely(conn);
|
exit_nicely(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The point of this program is to illustrate use of PQexecParams()
|
* The point of this program is to illustrate use of PQexecParams() with
|
||||||
* with out-of-line parameters, as well as binary transmission of
|
* out-of-line parameters, as well as binary transmission of data.
|
||||||
* results. By using out-of-line parameters we can avoid a lot of
|
*
|
||||||
* tedious mucking about with quoting and escaping. Notice how we
|
* This first example transmits the parameters as text, but receives the
|
||||||
* don't have to do anything special with the quote mark in the
|
* results in binary format. By using out-of-line parameters we can
|
||||||
* parameter value.
|
* avoid a lot of tedious mucking about with quoting and escaping, even
|
||||||
*/
|
* though the data is text. Notice how we don't have to do anything
|
||||||
|
* special with the quote mark in the parameter value.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Here is our out-of-line parameter value */
|
/* Here is our out-of-line parameter value */
|
||||||
paramValues[0] = "joe's place";
|
paramValues[0] = "joe's place";
|
||||||
|
|
||||||
res = PQexecParams(conn,
|
res = PQexecParams(conn,
|
||||||
"SELECT * FROM test1 WHERE t = $1",
|
"SELECT * FROM test1 WHERE t = $1",
|
||||||
1, /* one param */
|
1, /* one param */
|
||||||
NULL, /* let the backend deduce param type */
|
NULL, /* let the backend deduce param type */
|
||||||
paramValues,
|
paramValues,
|
||||||
NULL, /* don't need param lengths since text */
|
NULL, /* don't need param lengths since text */
|
||||||
NULL, /* default to all text params */
|
NULL, /* default to all text params */
|
||||||
1); /* ask for binary results */
|
1); /* ask for binary results */
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
|
||||||
PQclear(res);
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use PQfnumber to avoid assumptions about field order in result */
|
|
||||||
i_fnum = PQfnumber(res, "i");
|
|
||||||
t_fnum = PQfnumber(res, "t");
|
|
||||||
b_fnum = PQfnumber(res, "b");
|
|
||||||
|
|
||||||
for (i = 0; i < PQntuples(res); i++)
|
|
||||||
{
|
|
||||||
char *iptr;
|
|
||||||
char *tptr;
|
|
||||||
char *bptr;
|
|
||||||
int blen;
|
|
||||||
int ival;
|
|
||||||
|
|
||||||
/* Get the field values (we ignore possibility they are null!) */
|
|
||||||
iptr = PQgetvalue(res, i, i_fnum);
|
|
||||||
tptr = PQgetvalue(res, i, t_fnum);
|
|
||||||
bptr = PQgetvalue(res, i, b_fnum);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The binary representation of INT4 is in network byte order,
|
|
||||||
* which we'd better coerce to the local byte order.
|
|
||||||
*/
|
|
||||||
ival = ntohl(*((uint32_t *) iptr));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The binary representation of TEXT is, well, text, and since
|
|
||||||
* libpq was nice enough to append a zero byte to it, it'll work
|
|
||||||
* just fine as a C string.
|
|
||||||
*
|
|
||||||
* The binary representation of BYTEA is a bunch of bytes, which
|
|
||||||
* could include embedded nulls so we have to pay attention to
|
|
||||||
* field length.
|
|
||||||
*/
|
|
||||||
blen = PQgetlength(res, i, b_fnum);
|
|
||||||
|
|
||||||
printf("tuple %d: got\n", i);
|
|
||||||
printf(" i = (%d bytes) %d\n",
|
|
||||||
PQgetlength(res, i, i_fnum), ival);
|
|
||||||
printf(" t = (%d bytes) '%s'\n",
|
|
||||||
PQgetlength(res, i, t_fnum), tptr);
|
|
||||||
printf(" b = (%d bytes) ", blen);
|
|
||||||
for (j = 0; j < blen; j++)
|
|
||||||
printf("\\%03o", bptr[j]);
|
|
||||||
printf("\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/* close the connection to the database and cleanup */
|
show_binary_results(res);
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
return 0;
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In this second example we transmit an integer parameter in binary
|
||||||
|
* form, and again retrieve the results in binary form.
|
||||||
|
*
|
||||||
|
* Although we tell PQexecParams we are letting the backend deduce
|
||||||
|
* parameter type, we really force the decision by casting the parameter
|
||||||
|
* symbol in the query text. This is a good safety measure when sending
|
||||||
|
* binary parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Convert integer value "2" to network byte order */
|
||||||
|
binaryIntVal = htonl((uint32_t) 2);
|
||||||
|
|
||||||
|
/* Set up parameter arrays for PQexecParams */
|
||||||
|
paramValues[0] = (char *) &binaryIntVal;
|
||||||
|
paramLengths[0] = sizeof(binaryIntVal);
|
||||||
|
paramFormats[0] = 1; /* binary */
|
||||||
|
|
||||||
|
res = PQexecParams(conn,
|
||||||
|
"SELECT * FROM test1 WHERE i = $1::int4",
|
||||||
|
1, /* one param */
|
||||||
|
NULL, /* let the backend deduce param type */
|
||||||
|
paramValues,
|
||||||
|
paramLengths,
|
||||||
|
paramFormats,
|
||||||
|
1); /* ask for binary results */
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_binary_results(res);
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/* close the connection to the database and cleanup */
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
* t = (11 bytes) 'joe's place'
|
* t = (11 bytes) 'joe's place'
|
||||||
* b = (5 bytes) \000\001\002\003\004
|
* b = (5 bytes) \000\001\002\003\004
|
||||||
*
|
*
|
||||||
|
* tuple 0: got
|
||||||
|
* i = (4 bytes) 2
|
||||||
|
* t = (8 bytes) 'ho there'
|
||||||
|
* b = (5 bytes) \004\003\002\001\000
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -36,67 +40,20 @@ exit_nicely(PGconn *conn)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/*
|
||||||
main(int argc, char **argv)
|
* This function prints a query result that is a binary-format fetch from
|
||||||
|
* a table defined as in the comment above. We split it out because the
|
||||||
|
* main() function uses it twice.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_binary_results(PGresult *res)
|
||||||
{
|
{
|
||||||
const char *conninfo;
|
|
||||||
PGconn *conn;
|
|
||||||
PGresult *res;
|
|
||||||
const char *paramValues[1];
|
|
||||||
int i,
|
int i,
|
||||||
j;
|
j;
|
||||||
int i_fnum,
|
int i_fnum,
|
||||||
t_fnum,
|
t_fnum,
|
||||||
b_fnum;
|
b_fnum;
|
||||||
|
|
||||||
/*
|
|
||||||
* If the user supplies a parameter on the command line, use it as the
|
|
||||||
* conninfo string; otherwise default to setting dbname=postgres and using
|
|
||||||
* environment variables or defaults for all other connection parameters.
|
|
||||||
*/
|
|
||||||
if (argc > 1)
|
|
||||||
conninfo = argv[1];
|
|
||||||
else
|
|
||||||
conninfo = "dbname = postgres";
|
|
||||||
|
|
||||||
/* Make a connection to the database */
|
|
||||||
conn = PQconnectdb(conninfo);
|
|
||||||
|
|
||||||
/* Check to see that the backend connection was successfully made */
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Connection to database failed: %s",
|
|
||||||
PQerrorMessage(conn));
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The point of this program is to illustrate use of PQexecParams() with
|
|
||||||
* out-of-line parameters, as well as binary transmission of results. By
|
|
||||||
* using out-of-line parameters we can avoid a lot of tedious mucking
|
|
||||||
* about with quoting and escaping. Notice how we don't have to do
|
|
||||||
* anything special with the quote mark in the parameter value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Here is our out-of-line parameter value */
|
|
||||||
paramValues[0] = "joe's place";
|
|
||||||
|
|
||||||
res = PQexecParams(conn,
|
|
||||||
"SELECT * FROM test1 WHERE t = $1",
|
|
||||||
1, /* one param */
|
|
||||||
NULL, /* let the backend deduce param type */
|
|
||||||
paramValues,
|
|
||||||
NULL, /* don't need param lengths since text */
|
|
||||||
NULL, /* default to all text params */
|
|
||||||
1); /* ask for binary results */
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
|
||||||
PQclear(res);
|
|
||||||
exit_nicely(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use PQfnumber to avoid assumptions about field order in result */
|
/* Use PQfnumber to avoid assumptions about field order in result */
|
||||||
i_fnum = PQfnumber(res, "i");
|
i_fnum = PQfnumber(res, "i");
|
||||||
t_fnum = PQfnumber(res, "t");
|
t_fnum = PQfnumber(res, "t");
|
||||||
|
@ -141,6 +98,109 @@ main(int argc, char **argv)
|
||||||
printf("\\%03o", bptr[j]);
|
printf("\\%03o", bptr[j]);
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *conninfo;
|
||||||
|
PGconn *conn;
|
||||||
|
PGresult *res;
|
||||||
|
const char *paramValues[1];
|
||||||
|
int paramLengths[1];
|
||||||
|
int paramFormats[1];
|
||||||
|
uint32_t binaryIntVal;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user supplies a parameter on the command line, use it as the
|
||||||
|
* conninfo string; otherwise default to setting dbname=postgres and using
|
||||||
|
* environment variables or defaults for all other connection parameters.
|
||||||
|
*/
|
||||||
|
if (argc > 1)
|
||||||
|
conninfo = argv[1];
|
||||||
|
else
|
||||||
|
conninfo = "dbname = postgres";
|
||||||
|
|
||||||
|
/* Make a connection to the database */
|
||||||
|
conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
|
/* Check to see that the backend connection was successfully made */
|
||||||
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Connection to database failed: %s",
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The point of this program is to illustrate use of PQexecParams() with
|
||||||
|
* out-of-line parameters, as well as binary transmission of data.
|
||||||
|
*
|
||||||
|
* This first example transmits the parameters as text, but receives the
|
||||||
|
* results in binary format. By using out-of-line parameters we can
|
||||||
|
* avoid a lot of tedious mucking about with quoting and escaping, even
|
||||||
|
* though the data is text. Notice how we don't have to do anything
|
||||||
|
* special with the quote mark in the parameter value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Here is our out-of-line parameter value */
|
||||||
|
paramValues[0] = "joe's place";
|
||||||
|
|
||||||
|
res = PQexecParams(conn,
|
||||||
|
"SELECT * FROM test1 WHERE t = $1",
|
||||||
|
1, /* one param */
|
||||||
|
NULL, /* let the backend deduce param type */
|
||||||
|
paramValues,
|
||||||
|
NULL, /* don't need param lengths since text */
|
||||||
|
NULL, /* default to all text params */
|
||||||
|
1); /* ask for binary results */
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_binary_results(res);
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In this second example we transmit an integer parameter in binary
|
||||||
|
* form, and again retrieve the results in binary form.
|
||||||
|
*
|
||||||
|
* Although we tell PQexecParams we are letting the backend deduce
|
||||||
|
* parameter type, we really force the decision by casting the parameter
|
||||||
|
* symbol in the query text. This is a good safety measure when sending
|
||||||
|
* binary parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Convert integer value "2" to network byte order */
|
||||||
|
binaryIntVal = htonl((uint32_t) 2);
|
||||||
|
|
||||||
|
/* Set up parameter arrays for PQexecParams */
|
||||||
|
paramValues[0] = (char *) &binaryIntVal;
|
||||||
|
paramLengths[0] = sizeof(binaryIntVal);
|
||||||
|
paramFormats[0] = 1; /* binary */
|
||||||
|
|
||||||
|
res = PQexecParams(conn,
|
||||||
|
"SELECT * FROM test1 WHERE i = $1::int4",
|
||||||
|
1, /* one param */
|
||||||
|
NULL, /* let the backend deduce param type */
|
||||||
|
paramValues,
|
||||||
|
paramLengths,
|
||||||
|
paramFormats,
|
||||||
|
1); /* ask for binary results */
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
exit_nicely(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_binary_results(res);
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue