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">
|
||||
|
@ -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.
|
||||
</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>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
|
@ -4226,7 +4246,7 @@ testlibpq.o(.text+0xa4): undefined reference to `PQerrorMessage'
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
@ -4235,112 +4255,111 @@ testlibpq.o(.text+0xa4): undefined reference to `PQerrorMessage'
|
|||
static void
|
||||
exit_nicely(PGconn *conn)
|
||||
{
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
int nFields;
|
||||
int i,
|
||||
j;
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
int nFields;
|
||||
int i,
|
||||
j;
|
||||
|
||||
/*
|
||||
* 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";
|
||||
/*
|
||||
* 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);
|
||||
/* 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);
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Our test case here involves using a cursor, for which we must be
|
||||
* inside a transaction block. We could do the whole thing with a
|
||||
* single PQexec() of "select * from pg_database", but that's too
|
||||
* trivial to make a good example.
|
||||
*/
|
||||
/*
|
||||
* Our test case here involves using a cursor, for which we must be inside
|
||||
* a transaction block. We could do the whole thing with a single
|
||||
* PQexec() of "select * from pg_database", but that's too trivial to make
|
||||
* a good example.
|
||||
*/
|
||||
|
||||
/* Start a transaction block */
|
||||
res = PQexec(conn, "BEGIN");
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
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
|
||||
*/
|
||||
/* Start a transaction block */
|
||||
res = PQexec(conn, "BEGIN");
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch rows from pg_database, the system catalog of databases
|
||||
*/
|
||||
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);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
/*
|
||||
* Should PQclear PGresult whenever it is no longer needed to avoid memory
|
||||
* leaks
|
||||
*/
|
||||
PQclear(res);
|
||||
|
||||
/*
|
||||
* Fetch rows from pg_database, the system catalog of databases
|
||||
*/
|
||||
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);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
PQclear(res);
|
||||
|
||||
res = PQexec(conn, "FETCH ALL in myportal");
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
res = PQexec(conn, "FETCH ALL in myportal");
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
/* close the portal ... we don't bother to check for errors ... */
|
||||
res = PQexec(conn, "CLOSE myportal");
|
||||
PQclear(res);
|
||||
/* first, print out the attribute names */
|
||||
nFields = PQnfields(res);
|
||||
for (i = 0; i < nFields; i++)
|
||||
printf("%-15s", PQfname(res, i));
|
||||
printf("\n\n");
|
||||
|
||||
/* end the transaction */
|
||||
res = PQexec(conn, "END");
|
||||
PQclear(res);
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/* close the connection to the database and cleanup */
|
||||
PQfinish(conn);
|
||||
PQclear(res);
|
||||
|
||||
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>
|
||||
</example>
|
||||
|
@ -4351,7 +4370,7 @@ main(int argc, char **argv)
|
|||
<programlisting>
|
||||
/*
|
||||
* testlibpq2.c
|
||||
* Test of the asynchronous notification interface
|
||||
* Test of the asynchronous notification interface
|
||||
*
|
||||
* Start this program, then from psql in another window do
|
||||
* NOTIFY TBL2;
|
||||
|
@ -4382,102 +4401,101 @@ main(int argc, char **argv)
|
|||
static void
|
||||
exit_nicely(PGconn *conn)
|
||||
{
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
PGnotify *notify;
|
||||
int nnotifies;
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
PGnotify *notify;
|
||||
int nnotifies;
|
||||
|
||||
/*
|
||||
* 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";
|
||||
/*
|
||||
* 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);
|
||||
/* 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);
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
|
||||
*/
|
||||
res = PQexec(conn, "LISTEN TBL2");
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
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
|
||||
*/
|
||||
/*
|
||||
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
|
||||
*/
|
||||
res = PQexec(conn, "LISTEN TBL2");
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
/* Quit after four notifies are received. */
|
||||
nnotifies = 0;
|
||||
while (nnotifies < 4)
|
||||
/*
|
||||
* should PQclear PGresult whenever it is no longer needed to avoid memory
|
||||
* 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)
|
||||
{
|
||||
/*
|
||||
* 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));
|
||||
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, "select() failed: %s\n", strerror(errno));
|
||||
exit_nicely(conn);
|
||||
}
|
||||
|
||||
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 */
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, "Done.\n");
|
||||
|
||||
return 0;
|
||||
/* close the connection to the database and cleanup */
|
||||
PQfinish(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
@ -4488,7 +4506,7 @@ main(int argc, char **argv)
|
|||
<programlisting>
|
||||
/*
|
||||
* 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
|
||||
* (provided in src/test/examples/testlibpq3.sql):
|
||||
|
@ -4505,6 +4523,10 @@ main(int argc, char **argv)
|
|||
* t = (11 bytes) 'joe's place'
|
||||
* 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 <stdlib.h>
|
||||
|
@ -4520,125 +4542,178 @@ main(int argc, char **argv)
|
|||
static void
|
||||
exit_nicely(PGconn *conn)
|
||||
{
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
PQfinish(conn);
|
||||
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
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const char *conninfo;
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
const char *paramValues[1];
|
||||
int i,
|
||||
j;
|
||||
int i_fnum,
|
||||
t_fnum,
|
||||
b_fnum;
|
||||
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";
|
||||
/*
|
||||
* 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);
|
||||
/* 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);
|
||||
}
|
||||
/* 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.
|
||||
*/
|
||||
/*
|
||||
* 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";
|
||||
/* 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 */
|
||||
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");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* close the connection to the database and cleanup */
|
||||
PQfinish(conn);
|
||||
show_binary_results(res);
|
||||
|
||||
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>
|
||||
</example>
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
* t = (11 bytes) 'joe's place'
|
||||
* 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 <stdlib.h>
|
||||
|
@ -36,67 +40,20 @@ exit_nicely(PGconn *conn)
|
|||
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,
|
||||
j;
|
||||
int i_fnum,
|
||||
t_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 */
|
||||
i_fnum = PQfnumber(res, "i");
|
||||
t_fnum = PQfnumber(res, "t");
|
||||
|
@ -141,6 +98,109 @@ main(int argc, char **argv)
|
|||
printf("\\%03o", bptr[j]);
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue