psql: Set variables from query result on failure when printing tuples
authorMichael Paquier <michael@paquier.xyz>
Mon, 2 Oct 2023 02:05:05 +0000 (11:05 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 2 Oct 2023 02:05:05 +0000 (11:05 +0900)
SetResultVariables() was not getting called when "printing" a result
that failed (see around PrintQueryResult), which would cause some
variables to not be set, like ROW_COUNT, SQLSTATE or ERROR.  This can be
confusing as a previous result would be retained.

This state could be reached when failing to process tuples in a few
commands, like \gset when it returns no tuples, or \crosstabview.  A
test is added, based on \gset.

This is arguably a bug fix, but no backpatch is done as there is a risk
of breaking scripts that rely on the previous behavior, even if they do
so accidentally.

Reported-by: amutu
Author: Japin Li
Reviewed-by: Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/18134-87126d90cb4dd049@postgresql.org

src/bin/psql/common.c
src/test/regress/expected/psql.out
src/test/regress/sql/psql.sql

index ede197bebebe5396dad212dc4548d5faaf33c0c7..daabf6f12b73d49c3dca99f2ace42ce82ae072e6 100644 (file)
@@ -1659,9 +1659,9 @@ ExecQueryAndProcessResults(const char *query,
                                            tuples_fout, printQueryFout);
        }
 
-       /* set variables on last result if all went well */
-       if (!is_watch && last && success)
-           SetResultVariables(result, true);
+       /* set variables from last result */
+       if (!is_watch && last)
+           SetResultVariables(result, success);
 
        ClearOrSaveResult(result);
        result = next_result;
index 7cd0c27cca8b9d29021050cb71ab0cf345910382..c70205b98a42e611c9dd8ba24066ce35bfde845d 100644 (file)
@@ -171,6 +171,11 @@ select 10 as test01, 20 as test02 from generate_series(1,3) \gset
 more than one row returned for \gset
 select 10 as test01, 20 as test02 from generate_series(1,0) \gset
 no rows returned for \gset
+-- \gset returns no tuples
+select a from generate_series(1, 10) as a where a = 11 \gset
+no rows returned for \gset
+\echo :ROW_COUNT
+0
 -- \gset should work in FETCH_COUNT mode too
 \set FETCH_COUNT 1
 select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
index f3bc6cd07e8d505f256e8d923663ceb7d0950d41..66ff64a160fd504aa35378e1f9142fa24c3c9c90 100644 (file)
@@ -87,6 +87,10 @@ select 1 as var1, NULL as var2, 3 as var3 \gset
 select 10 as test01, 20 as test02 from generate_series(1,3) \gset
 select 10 as test01, 20 as test02 from generate_series(1,0) \gset
 
+-- \gset returns no tuples
+select a from generate_series(1, 10) as a where a = 11 \gset
+\echo :ROW_COUNT
+
 -- \gset should work in FETCH_COUNT mode too
 \set FETCH_COUNT 1