diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index c1bf7fb..fc951ad 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -4295,10 +4295,30 @@ static PGresult * exec_query(const char *query) { PGresult *result; + bool rollback_to_tab_completion_savepoint = false; if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK) return NULL; + /* If the server supports it, create a savepoint before running the tab completion query + * in case it fails. */ + if (pset.sversion >= 80000) + { + PGTransactionStatusType transaction_status = PQtransactionStatus(pset.db); + + if (transaction_status == PQTRANS_INTRANS) + { + PGresult *savepoint_result = PQexec(pset.db, "SAVEPOINT pg_psql_tab_completion_savepoint"); + if (PQresultStatus(savepoint_result) == PGRES_COMMAND_OK) + rollback_to_tab_completion_savepoint = true; +#ifdef NOT_USED + else + psql_error("could not create savepoint for tab completion: %s", PQerrorMessage(pset.db)); +#endif + PQclear(savepoint_result); + } + } + result = PQexec(pset.db, query); if (PQresultStatus(result) != PGRES_TUPLES_OK) @@ -4311,6 +4331,18 @@ exec_query(const char *query) result = NULL; } + /* If a savepoint was created above, roll back to it. We do this regardless of whether the + above query was successful, because all tab completion queries should have no effect. */ + if (rollback_to_tab_completion_savepoint) + { + PGresult *rollback_result = PQexec(pset.db, "ROLLBACK TO pg_psql_tab_completion_savepoint"); +#ifdef NOT_USED + if (PQresultStatus(rollback_result) != PGRES_COMMAND_OK) + psql_error("could not roll back to tab completion savepoint: %s", PQerrorMessage(pset.db)); +#endif + PQclear(rollback_result); + } + return result; }