? src/interfaces/libpq/.deps
? src/interfaces/libpq/cscope.out
? src/interfaces/libpq/libpq.so.4.2
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.206
diff -c -r1.206 libpq.sgml
*** doc/src/sgml/libpq.sgml 10 Mar 2006 19:10:48 -0000 1.206
--- doc/src/sgml/libpq.sgml 1 Apr 2006 18:27:41 -0000
***************
*** 2045,2053 ****
! PQprintPQprint>>
Prints out all the rows and, optionally, the
column names to the specified output stream.
--- 2045,2081 ----
! PQdescPreparedPQdescPrepared>>
! PQdescPortalPQdescPortal>>
+ Describe a prepared statement or portal.
+ int PQdescPrepared(PGconn *conn, const char *stmt);
+ int PQdescPortal(PGconn *conn, const char *portal);
+
+
+ These two functions are used to describe a prepared statement or portal.
+ Functions return 1 on success and 0 on failure. (An appropriate error
+ message will be placed in an error situation.) NULL> values in
+ the stmt> and portal> parameters will be treated
+ as an empty string.
+
+
+ After a PQdescPrepared> or PQdescPortal> function
+ call, issuing a PQgetResult> will place backend's response
+ into a PGresult structure - that'll be
+ extractable via PQftype>.
+
+
+ These functions are available within extended query protocol which is
+ available in version 3.0 and above.
+
+
+
+
+
+ PQprintPQprint>>
+
Prints out all the rows and, optionally, the
column names to the specified output stream.
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.482
diff -c -r1.482 postgres.c
*** src/backend/tcop/postgres.c 14 Mar 2006 22:48:21 -0000 1.482
--- src/backend/tcop/postgres.c 1 Apr 2006 18:28:08 -0000
***************
*** 3391,3396 ****
--- 3391,3398 ----
describe_type)));
break;
}
+
+ send_ready_for_query = true;
}
break;
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.182
diff -c -r1.182 fe-exec.c
*** src/interfaces/libpq/fe-exec.c 14 Mar 2006 22:48:23 -0000 1.182
--- src/interfaces/libpq/fe-exec.c 1 Apr 2006 18:28:15 -0000
***************
*** 55,60 ****
--- 55,62 ----
static void parseInput(PGconn *conn);
static bool PQexecStart(PGconn *conn);
static PGresult *PQexecFinish(PGconn *conn);
+ static int pqDescribe(PGconn *conn, const char desc_type,
+ const char *desc_target);
/* ----------------
***************
*** 2281,2286 ****
--- 2283,2400 ----
return 0;
}
+
+ /*
+ * pqDescribe - Describe given prepared statement or portal.
+ *
+ * Available options for target_type are
+ * 's' to describe a prepared statement; or
+ * 'p' to describe a portal.
+ * Returns 1 on success and 0 on failure.
+ *
+ * By issuing a PQgetResult(), response from the server will be placed
+ * in an empty PGresult that will be extractable via PQftype().
+ */
+ static int
+ pqDescribe(PGconn *conn, const char desc_type, const char *desc_target)
+ {
+ int ret;
+
+ /* This isn't gonna work on a 2.0 server. */
+ if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("function requires at least protocol version 3.0\n"));
+ return 0;
+ }
+
+ if (!conn)
+ return 0;
+
+ /* Clear the connection error message. */
+ resetPQExpBuffer(&conn->errorMessage);
+
+ /* Don't try to send if we know there's no live connection. */
+ if (conn->status != CONNECTION_OK)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("no connection to the server\n"));
+ return false;
+ }
+
+ /* Can't send while already busy, either. */
+ if (conn->asyncStatus != PGASYNC_IDLE)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("another command is already in progress\n"));
+ return false;
+ }
+
+ /* Initialize async result-accumulation state. */
+ conn->result = NULL;
+ conn->curTuple = NULL;
+
+ if (desc_target)
+ {
+ int len = strlen(desc_target) + 2;
+ char buf[len];
+
+ snprintf(buf, len, "%c%s", desc_type, desc_target);
+
+ /*
+ * Flushing stuff will be handled by pqPacketSend(). (Although
+ * this theoretically could block, it really shouldn't for
+ * these kind of small messages.)
+ */
+ ret = pqPacketSend(conn, 'D', buf, len);
+ }
+
+ /* NULL desc_target values will be treated as an empty string. */
+ else
+ {
+ int len = 2;
+ char buf[len];
+
+ buf[0] = desc_type;
+ buf[1] = '\0';
+ ret = pqPacketSend(conn, 'D', buf, len);
+ }
+
+ /* In case of a pqPacketSend() failure... */
+ if (ret != STATUS_OK)
+ {
+ pqHandleSendFailure(conn);
+ return 0;
+ }
+
+ /* Remember we are using extended query protocol. */
+ conn->queryclass = PGQUERY_EXTENDED;
+
+ /* Free last query string. */
+ if (conn->last_query)
+ {
+ free(conn->last_query);
+ conn->last_query = NULL;
+ }
+
+ /* Describe request is sent. */
+ conn->asyncStatus = PGASYNC_BUSY;
+ return 1;
+ }
+
+ int
+ PQdescPrepared(PGconn *conn, const char *stmt)
+ {
+ return pqDescribe(conn, 'S', stmt);
+ }
+
+ int
+ PQdescPortal(PGconn *conn, const char *portal)
+ {
+ return pqDescribe(conn, 'P', portal);
+ }
+
+
/* PQsetnonblocking:
* sets the PGconn's database connection non-blocking if the arg is TRUE
* or makes it non-blocking if the arg is FALSE, this will not protect
***************
*** 2346,2351 ****
--- 2460,2466 ----
free(ptr);
}
+
/*
* PQfreeNotify - free's the memory associated with a PGnotify
*
Index: src/interfaces/libpq/fe-protocol3.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v
retrieving revision 1.26
diff -c -r1.26 fe-protocol3.c
*** src/interfaces/libpq/fe-protocol3.c 14 Mar 2006 22:48:23 -0000 1.26
--- src/interfaces/libpq/fe-protocol3.c 1 Apr 2006 18:28:22 -0000
***************
*** 50,55 ****
--- 50,56 ----
static int getNotify(PGconn *conn);
static int getCopyStart(PGconn *conn, ExecStatusType copytype);
static int getReadyForQuery(PGconn *conn);
+ static int getParamDescriptions(PGconn *conn);
static void reportErrorPosition(PQExpBuffer msg, const char *query,
int loc, int encoding);
static int build_startup_packet(const PGconn *conn, char *packet,
***************
*** 350,355 ****
--- 351,375 ----
* the COPY command.
*/
break;
+ case 't': /* Parameter Description */
+ if (!conn->result)
+ {
+ if (!getParamDescriptions(conn)) /* Success. */
+ break;
+ else /* Not enough data or an error. */
+ return;
+ }
+ else
+ {
+ /*
+ * We'll use a new PGresult to place 't' input. Thus,
+ * we stop parsing until the application accepts the
+ * current result.
+ */
+ conn->asyncStatus = PGASYNC_READY;
+ return;
+ }
+ break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
***************
*** 1154,1159 ****
--- 1174,1249 ----
}
/*
+ * getParamDescriptions - process ParameterDescription message.
+ *
+ * We'll place parsed message information into a new PGresult. (Only
+ * parameter description attributes are going to be reliable.)
+ * Returns 0 if parsing is completed, 1 if there isn't enough data yet
+ * and -1 if there occurs an error.
+ */
+ static int
+ getParamDescriptions(PGconn *conn)
+ {
+ PGresult *res;
+ int nattr;
+ int i;
+ Oid typid;
+
+ res = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
+ if (!res)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory\n"));
+ goto Error;
+ }
+
+ /*
+ * parseInput() already read the 't' label and message length.
+ * The next byte is the number of parameters used by the
+ * statement (may be zero).
+ */
+ if (pqGetInt(&nattr, 2, conn) < 0)
+ goto NotEnoughData;
+ res->numAttributes = nattr;
+
+ /* Allocate space for the attribute descriptors. */
+ if (nattr > 0)
+ {
+ int sz = nattr * sizeof(PGresAttDesc);
+
+ res->attDescs = (PGresAttDesc *) pqResultAlloc(res, sz, TRUE);
+ if (!res->attDescs)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory\n"));
+ goto Error;
+ }
+
+ MemSet(res->attDescs, 0, sz);
+ }
+
+ /* Loop through attribute's type OIDs. */
+ for (i = 0; i < nattr; i++)
+ {
+ if (pqGetInt(&typid, 4, conn) < 0)
+ goto NotEnoughData;
+ res->attDescs[i].typid = typid;
+ }
+
+ /* Success. */
+ conn->result = res;
+ return 0;
+
+ NotEnoughData:
+ PQclear(res);
+ return 1;
+
+ Error:
+ PQclear(res);
+ return -1;
+ }
+
+ /*
* PQgetCopyData - read a row of data from the backend during COPY OUT
*
* If successful, sets *buffer to point to a malloc'd row of data, and
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.126
diff -c -r1.126 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h 20 Mar 2006 15:07:05 -0000 1.126
--- src/interfaces/libpq/libpq-fe.h 1 Apr 2006 18:28:25 -0000
***************
*** 414,419 ****
--- 414,423 ----
extern int PQgetlength(const PGresult *res, int tup_num, int field_num);
extern int PQgetisnull(const PGresult *res, int tup_num, int field_num);
+ /* Describe prepared statements or portals. */
+ extern int PQdescPrepared(PGconn *conn, const char *stmt);
+ extern int PQdescPortal(PGconn *conn, const char *portal);
+
/* Delete a PGresult */
extern void PQclear(PGresult *res);