3232
3333static bool DescribeQuery (const char * query , double * elapsed_msec );
3434static bool ExecQueryUsingCursor (const char * query , double * elapsed_msec );
35+ static bool ExecQueryAndProcessResult (const char * query , double * elapsed_msec , bool * svpt_gone_p );
3536static bool command_no_begin (const char * query );
3637static bool is_select_command (const char * query );
3738
@@ -1195,12 +1196,12 @@ bool
11951196SendQuery (const char * query )
11961197{
11971198 bool timing = pset .timing ;
1198- PGresult * result ;
11991199 PGTransactionStatusType transaction_status ;
12001200 double elapsed_msec = 0 ;
12011201 bool OK = false;
12021202 int i ;
12031203 bool on_error_rollback_savepoint = false;
1204+ bool svpt_gone = false;
12041205
12051206 if (!pset .db )
12061207 {
@@ -1247,6 +1248,8 @@ SendQuery(const char *query)
12471248 !pset .autocommit &&
12481249 !command_no_begin (query ))
12491250 {
1251+ PGresult * result ;
1252+
12501253 result = PQexec (pset .db , "BEGIN" );
12511254 if (PQresultStatus (result ) != PGRES_COMMAND_OK )
12521255 {
@@ -1264,6 +1267,8 @@ SendQuery(const char *query)
12641267 (pset .cur_cmd_interactive ||
12651268 pset .on_error_rollback == PSQL_ERROR_ROLLBACK_ON ))
12661269 {
1270+ PGresult * result ;
1271+
12671272 result = PQexec (pset .db , "SAVEPOINT pg_psql_temporary_savepoint" );
12681273 if (PQresultStatus (result ) != PGRES_COMMAND_OK )
12691274 {
@@ -1281,41 +1286,18 @@ SendQuery(const char *query)
12811286 /* Describe query's result columns, without executing it */
12821287 OK = DescribeQuery (query , & elapsed_msec );
12831288 ResetCancelConn ();
1284- result = NULL ; /* PQclear(NULL) does nothing */
12851289 }
12861290 else if (pset .fetch_count <= 0 || pset .gexec_flag ||
12871291 pset .crosstab_flag || !is_select_command (query ))
12881292 {
12891293 /* Default fetch-it-all-and-print mode */
1290- instr_time before ,
1291- after ;
1292-
1293- if (timing )
1294- INSTR_TIME_SET_CURRENT (before );
1295-
1296- result = PQexec (pset .db , query );
1297-
1298- /* these operations are included in the timing result: */
1299- ResetCancelConn ();
1300- OK = ProcessResult (& result );
1301-
1302- if (timing )
1303- {
1304- INSTR_TIME_SET_CURRENT (after );
1305- INSTR_TIME_SUBTRACT (after , before );
1306- elapsed_msec = INSTR_TIME_GET_MILLISEC (after );
1307- }
1308-
1309- /* but printing result isn't: */
1310- if (OK && result )
1311- OK = PrintQueryResult (result );
1294+ OK = ExecQueryAndProcessResult (query , & elapsed_msec , & svpt_gone );
13121295 }
13131296 else
13141297 {
13151298 /* Fetch-in-segments mode */
13161299 OK = ExecQueryUsingCursor (query , & elapsed_msec );
13171300 ResetCancelConn ();
1318- result = NULL ; /* PQclear(NULL) does nothing */
13191301 }
13201302
13211303 if (!OK && pset .echo == PSQL_ECHO_ERRORS )
@@ -1340,20 +1322,11 @@ SendQuery(const char *query)
13401322 break ;
13411323
13421324 case PQTRANS_INTRANS :
1343-
13441325 /*
1345- * Do nothing if they are messing with savepoints themselves:
1346- * If the user did COMMIT AND CHAIN, RELEASE or ROLLBACK, our
1347- * savepoint is gone. If they issued a SAVEPOINT, releasing
1348- * ours would remove theirs.
1326+ * Release our savepoint, but do nothing if they are messing
1327+ * with savepoints themselves
13491328 */
1350- if (result &&
1351- (strcmp (PQcmdStatus (result ), "COMMIT" ) == 0 ||
1352- strcmp (PQcmdStatus (result ), "SAVEPOINT" ) == 0 ||
1353- strcmp (PQcmdStatus (result ), "RELEASE" ) == 0 ||
1354- strcmp (PQcmdStatus (result ), "ROLLBACK" ) == 0 ))
1355- svptcmd = NULL ;
1356- else
1329+ if (!svpt_gone )
13571330 svptcmd = "RELEASE pg_psql_temporary_savepoint" ;
13581331 break ;
13591332
@@ -1379,16 +1352,13 @@ SendQuery(const char *query)
13791352 ClearOrSaveResult (svptres );
13801353 OK = false;
13811354
1382- PQclear (result );
13831355 ResetCancelConn ();
13841356 goto sendquery_cleanup ;
13851357 }
13861358 PQclear (svptres );
13871359 }
13881360 }
13891361
1390- ClearOrSaveResult (result );
1391-
13921362 /* Possible microtiming output */
13931363 if (timing )
13941364 PrintTiming (elapsed_msec );
@@ -1565,6 +1535,60 @@ DescribeQuery(const char *query, double *elapsed_msec)
15651535}
15661536
15671537
1538+ /*
1539+ * ExecQueryAndProcessResults: SendQuery() subroutine for the normal way to
1540+ * send a query
1541+ */
1542+ static bool
1543+ ExecQueryAndProcessResult (const char * query , double * elapsed_msec , bool * svpt_gone_p )
1544+ {
1545+ bool timing = pset .timing ;
1546+ bool OK ;
1547+ instr_time before ,
1548+ after ;
1549+ PGresult * result ;
1550+
1551+ if (timing )
1552+ INSTR_TIME_SET_CURRENT (before );
1553+
1554+ result = PQexec (pset .db , query );
1555+
1556+ /* these operations are included in the timing result: */
1557+ ResetCancelConn ();
1558+ OK = ProcessResult (& result );
1559+
1560+ if (timing )
1561+ {
1562+ INSTR_TIME_SET_CURRENT (after );
1563+ INSTR_TIME_SUBTRACT (after , before );
1564+ * elapsed_msec = INSTR_TIME_GET_MILLISEC (after );
1565+ }
1566+
1567+ /* but printing result isn't: */
1568+ if (OK && result )
1569+ OK = PrintQueryResult (result );
1570+
1571+ /*
1572+ * Check if the user ran any command that would destroy our internal
1573+ * savepoint: If the user did COMMIT AND CHAIN, RELEASE or ROLLBACK, our
1574+ * savepoint is gone. If they issued a SAVEPOINT, releasing ours would
1575+ * remove theirs.
1576+ */
1577+ if (result && svpt_gone_p )
1578+ {
1579+ const char * cmd = PQcmdStatus (result );
1580+ * svpt_gone_p = (strcmp (cmd , "COMMIT" ) == 0 ||
1581+ strcmp (cmd , "SAVEPOINT" ) == 0 ||
1582+ strcmp (cmd , "RELEASE" ) == 0 ||
1583+ strcmp (cmd , "ROLLBACK" ) == 0 );
1584+ }
1585+
1586+ ClearOrSaveResult (result );
1587+
1588+ return OK ;
1589+ }
1590+
1591+
15681592/*
15691593 * ExecQueryUsingCursor: run a SELECT-like query using a cursor
15701594 *
0 commit comments