diff options
Diffstat (limited to 'src/interfaces')
| -rw-r--r-- | src/interfaces/libpq/exports.txt | 4 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-exec.c | 124 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-protocol3.c | 19 | ||||
| -rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 6 | ||||
| -rw-r--r-- | src/interfaces/libpq/libpq-int.h | 2 |
5 files changed, 132 insertions, 23 deletions
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 7ded77aff37..850734ac96c 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -187,3 +187,7 @@ PQsetTraceFlags 184 PQmblenBounded 185 PQsendFlushRequest 186 PQconnectionUsedGSSAPI 187 +PQclosePrepared 188 +PQclosePortal 189 +PQsendClosePrepared 190 +PQsendClosePortal 191 diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 14d706efd57..01f8efabbef 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -77,8 +77,8 @@ static void parseInput(PGconn *conn); static PGresult *getCopyResult(PGconn *conn, ExecStatusType copytype); static bool PQexecStart(PGconn *conn); static PGresult *PQexecFinish(PGconn *conn); -static int PQsendDescribe(PGconn *conn, char desc_type, - const char *desc_target); +static int PQsendTypedCommand(PGconn *conn, char command, char type, + const char *target); static int check_field_number(const PGresult *res, int field_num); static void pqPipelineProcessQueue(PGconn *conn); static int pqPipelineFlush(PGconn *conn); @@ -2422,7 +2422,7 @@ PQdescribePrepared(PGconn *conn, const char *stmt) { if (!PQexecStart(conn)) return NULL; - if (!PQsendDescribe(conn, 'S', stmt)) + if (!PQsendTypedCommand(conn, 'D', 'S', stmt)) return NULL; return PQexecFinish(conn); } @@ -2441,7 +2441,7 @@ PQdescribePortal(PGconn *conn, const char *portal) { if (!PQexecStart(conn)) return NULL; - if (!PQsendDescribe(conn, 'P', portal)) + if (!PQsendTypedCommand(conn, 'D', 'P', portal)) return NULL; return PQexecFinish(conn); } @@ -2456,7 +2456,7 @@ PQdescribePortal(PGconn *conn, const char *portal) int PQsendDescribePrepared(PGconn *conn, const char *stmt) { - return PQsendDescribe(conn, 'S', stmt); + return PQsendTypedCommand(conn, 'D', 'S', stmt); } /* @@ -2469,26 +2469,96 @@ PQsendDescribePrepared(PGconn *conn, const char *stmt) int PQsendDescribePortal(PGconn *conn, const char *portal) { - return PQsendDescribe(conn, 'P', portal); + return PQsendTypedCommand(conn, 'D', 'P', portal); } /* - * PQsendDescribe - * Common code to send a Describe command + * PQclosePrepared + * Close a previously prepared statement + * + * If the query was not even sent, return NULL; conn->errorMessage is set to + * a relevant message. + * If the query was sent, a new PGresult is returned (which could indicate + * either success or failure). On success, the PGresult contains status + * PGRES_COMMAND_OK. The user is responsible for freeing the PGresult via + * PQclear() when done with it. + */ +PGresult * +PQclosePrepared(PGconn *conn, const char *stmt) +{ + if (!PQexecStart(conn)) + return NULL; + if (!PQsendTypedCommand(conn, 'C', 'S', stmt)) + return NULL; + return PQexecFinish(conn); +} + +/* + * PQclosePortal + * Close a previously created portal + * + * This is exactly like PQclosePrepared, but for portals. Note that at the + * moment, libpq doesn't really expose portals to the client; but this can be + * used with a portal created by a SQL DECLARE CURSOR command. + */ +PGresult * +PQclosePortal(PGconn *conn, const char *portal) +{ + if (!PQexecStart(conn)) + return NULL; + if (!PQsendTypedCommand(conn, 'C', 'P', portal)) + return NULL; + return PQexecFinish(conn); +} + +/* + * PQsendClosePrepared + * Submit a Close Statement command, but don't wait for it to finish + * + * Returns: 1 if successfully submitted + * 0 if error (conn->errorMessage is set) + */ +int +PQsendClosePrepared(PGconn *conn, const char *stmt) +{ + return PQsendTypedCommand(conn, 'C', 'S', stmt); +} + +/* + * PQsendClosePortal + * Submit a Close Portal command, but don't wait for it to finish + * + * Returns: 1 if successfully submitted + * 0 if error (conn->errorMessage is set) + */ +int +PQsendClosePortal(PGconn *conn, const char *portal) +{ + return PQsendTypedCommand(conn, 'C', 'P', portal); +} + +/* + * PQsendTypedCommand + * Common code to send a Describe or Close command + * + * Available options for "command" are + * 'C' for Close; or + * 'D' for Describe. + * + * Available options for "type" are + * 'S' to run a command on a prepared statement; or + * 'P' to run a command on a portal. * - * Available options for desc_type are - * 'S' to describe a prepared statement; or - * 'P' to describe a portal. * Returns 1 on success and 0 on failure. */ static int -PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) +PQsendTypedCommand(PGconn *conn, char command, char type, const char *target) { PGcmdQueueEntry *entry = NULL; - /* Treat null desc_target as empty string */ - if (!desc_target) - desc_target = ""; + /* Treat null target as empty string */ + if (!target) + target = ""; if (!PQsendQueryStart(conn, true)) return 0; @@ -2497,10 +2567,10 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) if (entry == NULL) return 0; /* error msg already set */ - /* construct the Describe message */ - if (pqPutMsgStart('D', conn) < 0 || - pqPutc(desc_type, conn) < 0 || - pqPuts(desc_target, conn) < 0 || + /* construct the Close message */ + if (pqPutMsgStart(command, conn) < 0 || + pqPutc(type, conn) < 0 || + pqPuts(target, conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; @@ -2512,8 +2582,20 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) goto sendFailed; } - /* remember we are doing a Describe */ - entry->queryclass = PGQUERY_DESCRIBE; + /* remember if we are doing a Close or a Describe */ + if (command == 'C') + { + entry->queryclass = PGQUERY_CLOSE; + } + else if (command == 'D') + { + entry->queryclass = PGQUERY_DESCRIBE; + } + else + { + libpq_append_conn_error(conn, "unknown command type provided"); + goto sendFailed; + } /* * Give the data a push (in pipeline mode, only if we're past the size diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 32b66d561cb..7bc6355d17f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -278,8 +278,25 @@ pqParseInput3(PGconn *conn) } break; case '2': /* Bind Complete */ + /* Nothing to do for this message type */ + break; case '3': /* Close Complete */ - /* Nothing to do for these message types */ + /* If we're doing PQsendClose, we're done; else ignore */ + if (conn->cmd_queue_head && + conn->cmd_queue_head->queryclass == PGQUERY_CLOSE) + { + if (!pgHavePendingResult(conn)) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_COMMAND_OK); + if (!conn->result) + { + libpq_append_conn_error(conn, "out of memory"); + pqSaveErrorResult(conn); + } + } + conn->asyncStatus = PGASYNC_READY; + } break; case 'S': /* parameter status */ if (getParameterStatus(conn)) diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 7476dbe0e90..97762d56f5d 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -548,6 +548,12 @@ extern PGresult *PQdescribePortal(PGconn *conn, const char *portal); extern int PQsendDescribePrepared(PGconn *conn, const char *stmt); extern int PQsendDescribePortal(PGconn *conn, const char *portal); +/* Close prepared statements and portals */ +extern PGresult *PQclosePrepared(PGconn *conn, const char *stmt); +extern PGresult *PQclosePortal(PGconn *conn, const char *portal); +extern int PQsendClosePrepared(PGconn *conn, const char *stmt); +extern int PQsendClosePortal(PGconn *conn, const char *portal); + /* Delete a PGresult */ extern void PQclear(PGresult *res); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index b70d4aee6a1..9d63472c35b 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -324,7 +324,7 @@ typedef enum PGQUERY_PREPARE, /* Parse only (PQprepare) */ PGQUERY_DESCRIBE, /* Describe Statement or Portal */ PGQUERY_SYNC, /* Sync (at end of a pipeline) */ - PGQUERY_CLOSE + PGQUERY_CLOSE /* Close Statement or Portal */ } PGQueryClass; /* |
