diff options
Diffstat (limited to 'doc/man/libpq.3')
-rw-r--r-- | doc/man/libpq.3 | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/doc/man/libpq.3 b/doc/man/libpq.3 new file mode 100644 index 00000000000..01d731a1541 --- /dev/null +++ b/doc/man/libpq.3 @@ -0,0 +1,962 @@ +.\" This is -*-nroff-*- +.\" XXX standard disclaimer belongs here.... +.\" $Header: /cvsroot/pgsql/doc/man/Attic/libpq.3,v 1.1.1.1 1996/08/18 22:14:25 scrappy Exp $ +.TH LIBPQ INTRO 03/12/94 Postgres95 Postgres95 +.SH DESCRIPTION +Libpq is the programmer's interface to Postgres. Libpq is a set of +library routines that allows queries to pass to the Postgres backend and +instances to return through an IPC channel. +.PP +This version of the documentation describes the C interface library. +Three short programs are included at the end of this section to show how +to write programs that use Libpq. +.PP +There are several examples of Libpq applications in the following +directories: +.nf +\&../src/test/regress +\&../src/test/examples +\&../src/bin/psql +.fi +.PP +Frontend programs which use Libpq must include the header file +.B "libpq-fe.h" +and must link with the +.B libpq +library. +.SH "Control and Initialization" +.PP +The following environment variables can be used to set up default +environment values to avoid hard-coding database names into +an application program: +.sp +\(bu +.B PGHOST +sets the default server name. +.sp +\(bu +.B PGOPTIONS +sets additional runtime options for the Postgres backend. +.sp +\(bu +.B PGPORT +sets the default port for communicating with the Postgres backend. +.sp +\(bu +.B PGTTY +sets the file or tty on which debugging messages from the backend server +are displayed. +.sp +\(bu +.B PGDATABASE +sets the default Postgres database name. +.sp +\(bu +.B PGREALM +sets the +.I Kerberos +realm to use with Postgres, if it is different from the local realm. If +.B PGREALM +is set, Postgres applications will attempt authentication with servers +for this realm and use separate ticket files to avoid conflicts with +local ticket files. This environment variable is only used if +.I Kerberos +authentication is enabled. +.SH "Database Connection Functions" +.PP +The following routines deal with making a connection to a backend +from a C program. +.PP +.B PQsetdb +.IP +Makes a new connection to a backend. +.nf +PGconn *PQsetdb(char *pghost, + char *pgport, + char *pgoptions, + char *pgtty, + char *dbName); +.fi +If any argument is NULL, then the corresponding environment variable +is checked. If the environment variable is also not set, then hardwired +defaults are used. +.IP +.I PQsetdb +always returns a valid PGconn pointer. The +.I PQstatus +(see below) command should be called to ensure that a connection was +properly made before queries are sent via the connection. Libpq +programmers should be careful to maintain the PGconn abstraction. Use +the accessor functions below to get at the contents of PGconn. Avoid +directly referencing the fields of the PGconn structure as they are +subject to change in the future. +.IP +.B PQdb +returns the database name of the connection. +.nf +char *PQdb(PGconn *conn) +.fi +.B PQhost +returns the host name of the connection. +.nf +char *PQhost(PGconn *conn) +.fi +.B PQoptions +returns the pgoptions used in the connection. +.nf +char *PQoptions(PGconn *conn) +.fi +.B PQport +returns the pgport of the connection. +.nf +char *PQport(PGconn *conn) +.fi +.B PQtty +returns the pgtty of the connection. +.nf +char *PQtty(PGconn *conn) +.fi +.B PQstatus +Returns the status of the connection. The status can be CONNECTION_OK or +CONNECTION_BAD. +.nf +ConnStatusType *PQstatus(PGconn *conn) +.fi +.B PQerrorMessage +returns the error message associated with the connection +.nf +char *PQerrorMessage(PGconn* conn); +.fi +.PP +.B PQfinish +.IP +Close the connection to the backend. Also frees memory used by the +PGconn structure. The PGconn pointer should not be used after PQfinish +has been called. +.nf +void PQfinish(PGconn *conn) +.fi +.PP +.B PQreset +.IP +Reset the communication port with the backend. This function will close +the IPC socket connection to the backend and attempt to reestablish a +new connection to the same backend. +.nf +void PQreset(PGconn *conn) +.fi +.PP +.B PQtrace +.IP +Enables tracing of messages passed between the frontend and the backend. +The messages are echoed to the debug_port file stream. +.nf +void PQtrace(PGconn *conn, + FILE* debug_port); +.fi +.PP +.B PQuntrace +.IP +Disables tracing of messages passed between the frontend and the backend. +.nf +void PQuntrace(PGconn *conn); +.fi +.PP +.SH "Query Execution Functions" +.PP +.B PQexec +.IP +Submit a query to Postgres. Returns a PGresult pointer if the query was +successful or a NULL otherwise. If a NULL is returned, +.I PQerrorMessage +can be used to get more information about the error. +.nf +PGresult *PQexec(PGconn *conn, + char *query); +.fi +The PGresult structure encapsulates the query result returned by the +backend. Libpq programmers should be careful to maintain the PGresult +abstraction. Use the accessor functions described below to retrieve the +results of the query. Avoid directly referencing the fields of the PGresult +structure as they are subject to change in the future. +.PP +.B PQresultStatus +.IP +Returns the result status of the query. +.I PQresultStatus +can return one of the following values: +.nf +PGRES_EMPTY_QUERY, +PGRES_COMMAND_OK, /* the query was a command */ +PGRES_TUPLES_OK, /* the query successfully returned tuples */ +PGRES_COPY_OUT, +PGRES_COPY_IN, +PGRES_BAD_RESPONSE, /* an unexpected response was received */ +PGRES_NONFATAL_ERROR, +PGRES_FATAL_ERROR +.fi +.IP +If the result status is PGRES_TUPLES_OK, then the following routines can +be used to retrieve the tuples returned by the query. +.IP + +.B PQntuples +returns the number of tuples (instances) in the query result. +.nf +int PQntuples(PGresult *res); +.fi + +.B PQnfields +returns the number of fields (attributes) in the query result. +.nf +int PQnfields(PGresult *res); +.fi + +.B PQfname +returns the field (attribute) name associated with the given field index. +Field indices start at 0. +.nf +char *PQfname(PGresult *res, + int field_index); +.fi + +.B PQfnumber +returns the field (attribute) index associated with the given field name. +.nf +int PQfnumber(PGresult *res, + char* field_name); +.fi + +.B PQftype +returns the field type associated with the given field index. The +integer returned is an internal coding of the type. Field indices start +at 0. +.nf +Oid PQftype(PGresult *res, + int field_num); +.fi + +.B PQfsize +returns the size in bytes of the field associated with the given field +index. If the size returned is -1, the field is a variable length field. +Field indices start at 0. +.nf +int2 PQfsize(PGresult *res, + int field_index); +.fi + +.B PQgetvalue +returns the field (attribute) value. For most queries, the value +returned by +.I PQgetvalue +is a null-terminated ASCII string representation +of the attribute value. If the query was a result of a +.B BINARY +cursor, then the value returned by +.I PQgetvalue +is the binary representation of the type in the internal format of the +backend server. It is the programmer's responsibility to cast and +convert the data to the correct C type. The value returned by +.I PQgetvalue +points to storage that is part of the PGresult structure. One must +explicitly copy the value into other storage if it is to be used past +the lifetime of the PGresult structure itself. +.nf +char* PQgetvalue(PGresult *res, + int tup_num, + int field_num); +.fi + +.B PQgetlength +returns the length of a field (attribute) in bytes. If the field +is a +.I "struct varlena" , +the length returned here does +.B not +include the size field of the varlena, i.e., it is 4 bytes less. +.nf +int PQgetlength(PGresult *res, + int tup_num, + int field_num); +.fi + +.B PQgetisnull +returns the NULL status of a field. +.nf +int PQgetisnull(PGresult *res, + int tup_num, + int field_num); +.fi + +.PP +.B PQcmdStatus +.IP +Returns the command status associated with the last query command. +.nf +char *PQcmdStatus(PGresult *res); +.fi +.PP +.B PQoidStatus +.IP +Returns a string with the object id of the tuple inserted if the last +query is an INSERT command. Otherwise, returns an empty string. +.nf +char* PQoidStatus(PGresult *res); +.fi +.PP +.B PQprint +.IP ++ Prints out all the tuples in an intelligent manner. The +.B psql ++ program uses this function for its output. +.nf +void PQprint( + FILE* fout, /* output stream */ + PGresult* res, /* query results */ + PQprintOpt *ps /* option structure */ + ); + +.fi +.I PQprintOpt +is a typedef'ed structure as defined below. +.(C +typedef struct _PQprintOpt { + bool header; /* print table headings and row count */ + bool align; /* fill align the fields */ + bool standard; /* old brain dead format (needs align) */ + bool html3; /* output html3+ tables */ + bool expanded; /* expand tables */ + bool pager; /* use pager if needed */ + char *fieldSep; /* field separator */ + char *caption; /* html table caption (or NULL) */ + char **fieldName; /* null terminated array of field names (or NULL) */ +} PQprintOpt; +.fi +.LP +.B PQclear +.IP +Frees the storage associated with the PGresult. Every query result +should be properly freed when it is no longer used. Failure to do this +will result in memory leaks in the frontend application. The PQresult* +passed in should be a value which is returned from PQexec(). Calling +PQclear() on an uninitialized PQresult pointer will very likely result +in a core dump. +.nf +void PQclear(PQresult *res); +.fi +.PP +.SH "Fast Path" +.PP +Postgres provides a +.B "fast path" +interface to send function calls to the backend. This is a trapdoor +into system internals and can be a potential security hole. Most users +will not need this feature. +.nf +PGresult* PQfn(PGconn* conn, + int fnid, + int *result_buf, + int *result_len, + int result_is_int, + PQArgBlock *args, + int nargs); +.fi +.PP +The +.I fnid +argument is the object identifier of the function to be executed. +.I result_buf +is the buffer in which to load the return value. The caller must have +allocated sufficient space to store the return value. +The result length will be returned in the storage pointed to by +.I result_len. +If the result is to be an integer value, than +.I result_is_int +should be set to 1; otherwise it should be set to 0. +.I args +and +.I nargs +specify the arguments to the function. +.nf +typedef struct { + int len; + int isint; + union { + int *ptr; + int integer; + } u; +} PQArgBlock; +.fi +.PP +.I PQfn +always returns a valid PGresult*. The resultStatus should be checked +before the result is used. The caller is responsible for freeing the +PGresult with +.I PQclear +when it is not longer needed. +.PP +.SH "Asynchronous Notification" +.PP +Postgres supports asynchronous notification via the +.I LISTEN +and +.I NOTIFY +commands. A backend registers its interest in a particular relation +with the LISTEN command. All backends listening on a particular +relation will be notified asynchronously when a NOTIFY of that relation +name is executed by another backend. No additional information is +passed from the notifier to the listener. Thus, typically, any actual +data that needs to be communicated is transferred through the relation. +.PP +Libpq applications are notified whenever a connected backend has +received an asynchronous notification. However, the communication from +the backend to the frontend is not asynchronous. Notification comes +piggy-backed on other query results. Thus, an application must submit +queries, even empty ones, in order to receive notice of backend +notification. In effect, the Libpq application must poll the backend to +see if there is any pending notification information. After the +execution of a query, a frontend may call +.I PQNotifies +to see if any notification data is available from the backend. +.PP +.B PQNotifies +.IP +returns the notification from a list of unhandled notifications from the +backend. Returns NULL if there are no pending notifications from the +backend. +.I PQNotifies +behaves like the popping of a stack. Once a notification is returned +from +.I PQnotifies, +it is considered handled and will be removed from the list of +notifications. +.nf +PGnotify* PQNotifies(PGconn *conn); +.fi +.PP +The second sample program gives an example of the use of asynchronous +notification. +.PP +.SH "Functions Associated with the COPY Command" +.PP +The +.I copy +command in Postgres has options to read from or write to the network +connection used by Libpq. Therefore, functions are necessary to +access this network connection directly so applications may take full +advantage of this capability. +.PP +.B PQgetline +.IP +Reads a newline-terminated line of characters (transmitted by the +backend server) into a buffer +.I string +of size +.I length . +Like +.I fgets (3), +this routine copies up to +.I length "-1" +characters into +.I string . +It is like +.I gets (3), +however, in that it converts the terminating newline into a null +character. +.IP +.I PQgetline +returns EOF at EOF, 0 if the entire line has been read, and 1 if the +buffer is full but the terminating newline has not yet been read. +.IP +Notice that the application must check to see if a new line consists +of the single character \*(lq.\*(rq, which indicates that the backend +server has finished sending the results of the +.I copy +command. Therefore, if the application ever expects to receive lines +that are more than +.I length "-1" +characters long, the application must be sure to check the return +value of +.I PQgetline +very carefully. +.IP +The code in +.nf +\&../src/bin/psql/psql.c +.fi +contains routines that correctly handle the copy protocol. +.nf +int PQgetline(PGconn *conn, + char *string, + int length) +.fi +.PP +.B PQputline +.IP +Sends a null-terminated +.I string +to the backend server. +.IP +The application must explicitly send the single character \*(lq.\*(rq +to indicate to the backend that it has finished sending its data. +.nf +void PQputline(PGconn *conn, + char *string); +.fi +.PP +.B PQendcopy +.IP +Syncs with the backend. This function waits until the backend has +finished the copy. It should either be issued when the +last string has been sent to the backend using +.I PQputline +or when the last string has been received from the backend using +.I PGgetline . +It must be issued or the backend may get \*(lqout of sync\*(rq with +the frontend. Upon return from this function, the backend is ready to +receive the next query. +.IP +The return value is 0 on successful completion, nonzero otherwise. +.nf +int PQendcopy(PGconn *conn); +.fi +As an example: +.nf +PQexec(conn, "create table foo (a int4, b char16, d float8)"); +PQexec(conn, "copy foo from stdin"); +PQputline(conn, "3<TAB>hello world<TAB>4.5\en"); +PQputline(conn,"4<TAB>goodbye world<TAB>7.11\en"); +\&... +PQputline(conn,".\en"); +PQendcopy(conn); +.fi +.PP +.SH "LIBPQ Tracing Functions" +.PP +.B PQtrace +.IP +Enable tracing of the frontend/backend communication to a debugging file +stream. +.nf +void PQtrace(PGconn *conn + FILE *debug_port) +.fi +.PP +.B PQuntrace +.IP +Disable tracing started by +.I PQtrace +.nf +void PQuntrace(PGconn *conn) +.fi +.PP +.SH "User Authentication Functions" +.PP +If the user has generated the appropriate authentication credentials +(e.g., obtaining +.I Kerberos +tickets), the frontend/backend authentication process is handled by +.I PQexec +without any further intervention. The following routines may be +called by Libpq programs to tailor the behavior of the authentication +process. +.PP +.B fe_getauthname +.IP +Returns a pointer to static space containing whatever name the user +has authenticated. Use of this routine in place of calls to +.I getenv (3) +or +.I getpwuid (3) +by applications is highly recommended, as it is entirely possible that +the authenticated user name is +.B not +the same as value of the +.B USER +environment variable or the user's entry in +.I /etc/passwd . +.nf +char *fe_getauthname(char* errorMessage) +.fi +.PP +.B fe_setauthsvc +.IP +Specifies that Libpq should use authentication service +.I name +rather than its compiled-in default. This value is typically taken +from a command-line switch. +.nf +void fe_setauthsvc(char *name, + char* errorMessage) +.fi +Any error messages from the authentication attempts are returned in the +errorMessage argument. +.PP +.SH "BUGS" +.PP +The query buffer is 8192 bytes long, and queries over that length will +be silently truncated. +.PP +.SH "Sample Programs" +.bp +.SH "Sample Program 1" +.PP +.nf M +/* + * testlibpq.c + * Test the C version of Libpq, the Postgres frontend library. + * + * + */ +#include <stdio.h> +#include "libpq-fe.h" + +void +exit_nicely(PGconn* conn) +{ + PQfinish(conn); + exit(1); +} + +main() +{ + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; + +/* FILE *debug; */ + + PGconn* conn; + PGresult* res; + + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ + dbName = "template1"; + + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); + + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.\n", dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } + +/* debug = fopen("/tmp/trace.out","w"); */ +/* PQtrace(conn, debug); */ + + /* start a transaction block */ + res = PQexec(conn,"BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); + + /* fetch instances from the 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 command failed\n"); + PQclear(res); + exit_nicely(conn); + } + PQclear(res); + + res = PQexec(conn,"FETCH ALL in myportal"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"FETCH ALL command didn't return tuples properly\n"); + 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 instances */ + for (i=0; i < PQntuples(res); i++) { + for (j=0 ; j < nFields; j++) { + printf("%-15s", PQgetvalue(res,i,j)); + } + printf("\n"); + } + + PQclear(res); + + /* close the portal */ + 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); + +/* fclose(debug); */ +} +.fi +.bp +.SH "Sample Program 2" +.PP +.nf M +/* + * testlibpq2.c + * Test of the asynchronous notification interface + * + populate a database with the following: + +CREATE TABLE TBL1 (i int4); + +CREATE TABLE TBL2 (i int4); + +CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2]; + + * Then start up this program + * After the program has begun, do + +INSERT INTO TBL1 values (10); + + * + * + */ +#include <stdio.h> +#include "libpq-fe.h" + +void exit_nicely(PGconn* conn) +{ + PQfinish(conn); + exit(1); +} + +main() +{ + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; + + PGconn* conn; + PGresult* res; + PGnotify* notify; + + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ + dbName = getenv("USER"); /* change this to the name of your test database*/ + + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); + + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.\n", dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } + + res = PQexec(conn, "LISTEN TBL2"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"LISTEN command failed\n"); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); + + while (1) { + /* async notification only come back as a result of a query*/ + /* we can send empty queries */ + res = PQexec(conn, " "); +/* printf("res->status = %s\n", pgresStatus[PQresultStatus(res)]); */ + /* check for asynchronous returns */ + notify = PQnotifies(conn); + if (notify) { + fprintf(stderr, + "ASYNC NOTIFY of '%s' from backend pid '%d' received\n", + notify->relname, notify->be_pid); + free(notify); + break; + } + PQclear(res); + } + + /* close the connection to the database and cleanup */ + PQfinish(conn); + +} +.fi +.bp +.SH "Sample Program 3" +.PP +.nf M +/* + * testlibpq3.c + * Test the C version of Libpq, the Postgres frontend library. + * tests the binary cursor interface + * + * + * + populate a database by doing the following: + +CREATE TABLE test1 (i int4, d float4, p polygon); + +INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon); + +INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon); + + the expected output is: + +tuple 0: got + i = (4 bytes) 1, + d = (4 bytes) 3.567000, + p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000) +tuple 1: got + i = (4 bytes) 2, + d = (4 bytes) 89.050003, + p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000) + + * + */ +#include <stdio.h> +#include "libpq-fe.h" +#include "utils/geo-decls.h" /* for the POLYGON type */ + +void exit_nicely(PGconn* conn) +{ + PQfinish(conn); + exit(1); +} + +main() +{ + char *pghost, *pgport, *pgoptions, *pgtty; + char* dbName; + int nFields; + int i,j; + int i_fnum, d_fnum, p_fnum; + + PGconn* conn; + PGresult* res; + + /* begin, by setting the parameters for a backend connection + if the parameters are null, then the system will try to use + reasonable defaults by looking up environment variables + or, failing that, using hardwired constants */ + pghost = NULL; /* host name of the backend server */ + pgport = NULL; /* port of the backend server */ + pgoptions = NULL; /* special options to start up the backend server */ + pgtty = NULL; /* debugging tty for the backend server */ + + dbName = getenv("USER"); /* change this to the name of your test database*/ + + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); + + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.\n", dbName); + fprintf(stderr,"%s",PQerrorMessage(conn)); + exit_nicely(conn); + } + + /* start a transaction block */ + res = PQexec(conn,"BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + PQclear(res); + exit_nicely(conn); + } + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear(res); + + /* fetch instances from the pg_database, the system catalog of databases*/ + res = PQexec(conn,"DECLARE mycursor BINARY CURSOR FOR select * from test1"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"DECLARE CURSOR command failed\n"); + PQclear(res); + exit_nicely(conn); + } + PQclear(res); + + res = PQexec(conn,"FETCH ALL in mycursor"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"FETCH ALL command didn't return tuples properly\n"); + PQclear(res); + exit_nicely(conn); + } + + i_fnum = PQfnumber(res,"i"); + d_fnum = PQfnumber(res,"d"); + p_fnum = PQfnumber(res,"p"); + + for (i=0;i<3;i++) { + printf("type[%d] = %d, size[%d] = %d\n", + i, PQftype(res,i), + i, PQfsize(res,i)); + } + for (i=0; i < PQntuples(res); i++) { + int *ival; + float *dval; + int plen; + POLYGON* pval; + /* we hard-wire this to the 3 fields we know about */ + ival = (int*)PQgetvalue(res,i,i_fnum); + dval = (float*)PQgetvalue(res,i,d_fnum); + plen = PQgetlength(res,i,p_fnum); + + /* plen doesn't include the length field so need to increment by VARHDSZ*/ + pval = (POLYGON*) malloc(plen + VARHDRSZ); + pval->size = plen; + memmove((char*)&pval->npts, PQgetvalue(res,i,p_fnum), plen); + printf("tuple %d: got\n", i); + printf(" i = (%d bytes) %d,\n", + PQgetlength(res,i,i_fnum), *ival); + printf(" d = (%d bytes) %f,\n", + PQgetlength(res,i,d_fnum), *dval); + printf(" p = (%d bytes) %d points \tboundbox = (hi=%f/%f, lo = %f,%f)\n", + PQgetlength(res,i,d_fnum), + pval->npts, + pval->boundbox.xh, + pval->boundbox.yh, + pval->boundbox.xl, + pval->boundbox.yl); + } + + PQclear(res); + + /* close the portal */ + res = PQexec(conn, "CLOSE mycursor"); + PQclear(res); + + /* end the transaction */ + res = PQexec(conn, "END"); + PQclear(res); + + /* close the connection to the database and cleanup */ + PQfinish(conn); + +} +.fi |