? 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);