mirror of
https://github.com/postgres/postgres.git
synced 2025-05-28 05:21:27 +03:00
If an interactive psql session used \gset when querying a compromised server, the attacker could execute arbitrary code as the operating system account running psql. Using a prefix not found among specially treated variables, e.g. every lowercase string, precluded the attack. Fix by issuing a warning and setting no variable for the column in question. Users wanting the old behavior can use a prefix and then a meta-command like "\set HISTSIZE :prefix_HISTSIZE". Back-patch to 9.5 (all supported versions). Reviewed by Robert Haas. Reported by Nick Cleaton. Security: CVE-2020-25696
576 lines
10 KiB
SQL
576 lines
10 KiB
SQL
--
|
|
-- Tests for psql features that aren't closely connected to any
|
|
-- specific server features
|
|
--
|
|
|
|
-- \set
|
|
|
|
-- fail: invalid name
|
|
\set invalid/name foo
|
|
-- fail: invalid value for special variable
|
|
\set AUTOCOMMIT foo
|
|
\set FETCH_COUNT foo
|
|
-- check handling of built-in boolean variable
|
|
\echo :ON_ERROR_ROLLBACK
|
|
\set ON_ERROR_ROLLBACK
|
|
\echo :ON_ERROR_ROLLBACK
|
|
\set ON_ERROR_ROLLBACK foo
|
|
\echo :ON_ERROR_ROLLBACK
|
|
\set ON_ERROR_ROLLBACK on
|
|
\echo :ON_ERROR_ROLLBACK
|
|
\unset ON_ERROR_ROLLBACK
|
|
\echo :ON_ERROR_ROLLBACK
|
|
|
|
-- \g and \gx
|
|
|
|
SELECT 1 as one, 2 as two \g
|
|
\gx
|
|
SELECT 3 as three, 4 as four \gx
|
|
\g
|
|
|
|
-- \gx should work in FETCH_COUNT mode too
|
|
\set FETCH_COUNT 1
|
|
|
|
SELECT 1 as one, 2 as two \g
|
|
\gx
|
|
SELECT 3 as three, 4 as four \gx
|
|
\g
|
|
|
|
\unset FETCH_COUNT
|
|
|
|
-- \gset
|
|
|
|
select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
|
|
|
|
\echo :pref01_test01 :pref01_test02 :pref01_test03
|
|
|
|
-- should fail: bad variable name
|
|
select 10 as "bad name"
|
|
\gset
|
|
|
|
select 97 as "EOF", 'ok' as _foo \gset IGNORE
|
|
\echo :IGNORE_foo :IGNOREEOF
|
|
|
|
-- multiple backslash commands in one line
|
|
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
|
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y
|
|
select 5 as x, 6 as y \gset pref01_ \\ \g \echo :pref01_x :pref01_y
|
|
select 7 as x, 8 as y \g \gset pref01_ \echo :pref01_x :pref01_y
|
|
|
|
-- NULL should unset the variable
|
|
\set var2 xyz
|
|
select 1 as var1, NULL as var2, 3 as var3 \gset
|
|
\echo :var1 :var2 :var3
|
|
|
|
-- \gset requires just one tuple
|
|
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 should work in FETCH_COUNT mode too
|
|
\set FETCH_COUNT 1
|
|
|
|
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
|
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y
|
|
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
|
|
|
|
\unset FETCH_COUNT
|
|
|
|
-- \gexec
|
|
|
|
create temporary table gexec_test(a int, b text, c date, d float);
|
|
select format('create index on gexec_test(%I)', attname)
|
|
from pg_attribute
|
|
where attrelid = 'gexec_test'::regclass and attnum > 0
|
|
order by attnum
|
|
\gexec
|
|
|
|
-- \gexec should work in FETCH_COUNT mode too
|
|
-- (though the fetch limit applies to the executed queries not the meta query)
|
|
\set FETCH_COUNT 1
|
|
|
|
select 'select 1 as ones', 'select x.y, x.y*2 as double from generate_series(1,4) as x(y)'
|
|
union all
|
|
select 'drop table gexec_test', NULL
|
|
union all
|
|
select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over'
|
|
\gexec
|
|
|
|
\unset FETCH_COUNT
|
|
|
|
-- show all pset options
|
|
\pset
|
|
|
|
-- test multi-line headers, wrapping, and newline indicators
|
|
prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab
|
|
|
|
c", array_to_string(array_agg(repeat('y',20-2*n)),E'\n') as "a
|
|
bc" from generate_series(1,10) as n(n) group by n>1 order by n>1;
|
|
|
|
\pset linestyle ascii
|
|
|
|
\pset expanded off
|
|
\pset columns 40
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset columns 20
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset linestyle old-ascii
|
|
|
|
\pset expanded off
|
|
\pset columns 40
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset columns 20
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
deallocate q;
|
|
|
|
-- test single-line header and data
|
|
prepare q as select repeat('x',2*n) as "0123456789abcdef", repeat('y',20-2*n) as "0123456789" from generate_series(1,10) as n;
|
|
|
|
\pset linestyle ascii
|
|
|
|
\pset expanded off
|
|
\pset columns 40
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset columns 30
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset columns 20
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset linestyle old-ascii
|
|
|
|
\pset expanded off
|
|
\pset columns 40
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
|
|
\pset border 0
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 1
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
\pset border 2
|
|
\pset format unaligned
|
|
execute q;
|
|
\pset format aligned
|
|
execute q;
|
|
\pset format wrapped
|
|
execute q;
|
|
|
|
deallocate q;
|
|
|
|
\pset linestyle ascii
|
|
|
|
prepare q as select ' | = | lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (&' as " | -- | 012345678 9abc def!*@#&!@(*&*~~_+-=\ \", '11' as "0123456789", 11 as int from generate_series(1,10) as n;
|
|
|
|
\pset format asciidoc
|
|
\pset expanded off
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
deallocate q;
|
|
|
|
\pset format aligned
|
|
\pset expanded off
|
|
\pset border 1
|
|
|
|
-- tests for \if ... \endif
|
|
|
|
\if true
|
|
select 'okay';
|
|
select 'still okay';
|
|
\else
|
|
not okay;
|
|
still not okay
|
|
\endif
|
|
|
|
-- at this point query buffer should still have last valid line
|
|
\g
|
|
|
|
-- \if should work okay on part of a query
|
|
select
|
|
\if true
|
|
42
|
|
\else
|
|
(bogus
|
|
\endif
|
|
forty_two;
|
|
|
|
select \if false \\ (bogus \else \\ 42 \endif \\ forty_two;
|
|
|
|
-- test a large nested if using a variety of true-equivalents
|
|
\if true
|
|
\if 1
|
|
\if yes
|
|
\if on
|
|
\echo 'all true'
|
|
\else
|
|
\echo 'should not print #1-1'
|
|
\endif
|
|
\else
|
|
\echo 'should not print #1-2'
|
|
\endif
|
|
\else
|
|
\echo 'should not print #1-3'
|
|
\endif
|
|
\else
|
|
\echo 'should not print #1-4'
|
|
\endif
|
|
|
|
-- test a variety of false-equivalents in an if/elif/else structure
|
|
\if false
|
|
\echo 'should not print #2-1'
|
|
\elif 0
|
|
\echo 'should not print #2-2'
|
|
\elif no
|
|
\echo 'should not print #2-3'
|
|
\elif off
|
|
\echo 'should not print #2-4'
|
|
\else
|
|
\echo 'all false'
|
|
\endif
|
|
|
|
-- test simple true-then-else
|
|
\if true
|
|
\echo 'first thing true'
|
|
\else
|
|
\echo 'should not print #3-1'
|
|
\endif
|
|
|
|
-- test simple false-true-else
|
|
\if false
|
|
\echo 'should not print #4-1'
|
|
\elif true
|
|
\echo 'second thing true'
|
|
\else
|
|
\echo 'should not print #5-1'
|
|
\endif
|
|
|
|
-- invalid boolean expressions are false
|
|
\if invalid boolean expression
|
|
\echo 'will not print #6-1'
|
|
\else
|
|
\echo 'will print anyway #6-2'
|
|
\endif
|
|
|
|
-- test un-matched endif
|
|
\endif
|
|
|
|
-- test un-matched else
|
|
\else
|
|
|
|
-- test un-matched elif
|
|
\elif
|
|
|
|
-- test double-else error
|
|
\if true
|
|
\else
|
|
\else
|
|
\endif
|
|
|
|
-- test elif out-of-order
|
|
\if false
|
|
\else
|
|
\elif
|
|
\endif
|
|
|
|
-- test if-endif matching in a false branch
|
|
\if false
|
|
\if false
|
|
\echo 'should not print #7-1'
|
|
\else
|
|
\echo 'should not print #7-2'
|
|
\endif
|
|
\echo 'should not print #7-3'
|
|
\else
|
|
\echo 'should print #7-4'
|
|
\endif
|
|
|
|
-- show that vars and backticks are not expanded when ignoring extra args
|
|
\set foo bar
|
|
\echo :foo :'foo' :"foo"
|
|
\pset fieldsep | `nosuchcommand` :foo :'foo' :"foo"
|
|
|
|
-- show that vars and backticks are not expanded and commands are ignored
|
|
-- when in a false if-branch
|
|
\set try_to_quit '\\q'
|
|
\if false
|
|
:try_to_quit
|
|
\echo `nosuchcommand` :foo :'foo' :"foo"
|
|
\pset fieldsep | `nosuchcommand` :foo :'foo' :"foo"
|
|
\a \C arg1 \c arg1 arg2 arg3 arg4 \cd arg1 \conninfo
|
|
\copy arg1 arg2 arg3 arg4 arg5 arg6
|
|
\copyright \dt arg1 \e arg1 arg2
|
|
\ef whole_line
|
|
\ev whole_line
|
|
\echo arg1 arg2 arg3 arg4 arg5 \echo arg1 \encoding arg1 \errverbose
|
|
\g arg1 \gx arg1 \gexec \h \html \i arg1 \ir arg1 \l arg1 \lo arg1 arg2
|
|
\o arg1 \p \password arg1 \prompt arg1 arg2 \pset arg1 arg2 \q
|
|
\reset \s arg1 \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2
|
|
\sf whole_line
|
|
\sv whole_line
|
|
\t arg1 \T arg1 \timing arg1 \unset arg1 \w arg1 \watch arg1 \x arg1
|
|
-- \else here is eaten as part of OT_FILEPIPE argument
|
|
\w |/no/such/file \else
|
|
-- \endif here is eaten as part of whole-line argument
|
|
\! whole_line \endif
|
|
\else
|
|
\echo 'should print #8-1'
|
|
\endif
|
|
|
|
-- SHOW_CONTEXT
|
|
|
|
\set SHOW_CONTEXT never
|
|
do $$
|
|
begin
|
|
raise notice 'foo';
|
|
raise exception 'bar';
|
|
end $$;
|
|
|
|
\set SHOW_CONTEXT errors
|
|
do $$
|
|
begin
|
|
raise notice 'foo';
|
|
raise exception 'bar';
|
|
end $$;
|
|
|
|
\set SHOW_CONTEXT always
|
|
do $$
|
|
begin
|
|
raise notice 'foo';
|
|
raise exception 'bar';
|
|
end $$;
|
|
|
|
-- test printing and clearing the query buffer
|
|
SELECT 1;
|
|
\p
|
|
SELECT 2 \r
|
|
\p
|
|
SELECT 3 \p
|
|
UNION SELECT 4 \p
|
|
UNION SELECT 5
|
|
ORDER BY 1;
|
|
\r
|
|
\p
|