mirror of
https://github.com/postgres/postgres.git
synced 2025-05-08 07:21:33 +03:00
The buildfarm members using debug_parallel_query = regress are mostly unhappy with this test. I guess what is happening is that rows generated by a parallel worker are buffered, and might or might not get to the leader before the expected error occurs. We did not see any variability in the old version of this test because each FETCH would succeed or fail atomically, leading to a predictable number of rows emitted before failure. I don't find this to be a bug, just unspecified behavior, so let's disable parallel query for this one test case to make the results stable.
1892 lines
42 KiB
PL/PgSQL
1892 lines
42 KiB
PL/PgSQL
--
|
|
-- 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
|
|
|
|
-- \g/\gx with pset options
|
|
|
|
SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t')
|
|
\g
|
|
SELECT 1 as one, 2 as two \gx (title='foo bar')
|
|
\g
|
|
|
|
-- \bind (extended query protocol)
|
|
|
|
SELECT 1 \bind \g
|
|
SELECT $1 \bind 'foo' \g
|
|
SELECT $1, $2 \bind 'foo' 'bar' \g
|
|
|
|
-- errors
|
|
-- parse error
|
|
SELECT foo \bind \g
|
|
-- tcop error
|
|
SELECT 1 \; SELECT 2 \bind \g
|
|
-- bind error
|
|
SELECT $1, $2 \bind 'foo' \g
|
|
|
|
-- \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 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
|
|
|
|
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
|
|
|
|
-- \gdesc
|
|
|
|
SELECT
|
|
NULL AS zero,
|
|
1 AS one,
|
|
2.0 AS two,
|
|
'three' AS three,
|
|
$1 AS four,
|
|
sin($2) as five,
|
|
'foo'::varchar(4) as six,
|
|
CURRENT_DATE AS now
|
|
\gdesc
|
|
|
|
-- should work with tuple-returning utilities, such as EXECUTE
|
|
PREPARE test AS SELECT 1 AS first, 2 AS second;
|
|
EXECUTE test \gdesc
|
|
EXPLAIN EXECUTE test \gdesc
|
|
|
|
-- should fail cleanly - syntax error
|
|
SELECT 1 + \gdesc
|
|
|
|
-- check behavior with empty results
|
|
SELECT \gdesc
|
|
CREATE TABLE bububu(a int) \gdesc
|
|
|
|
-- subject command should not have executed
|
|
TABLE bububu; -- fail
|
|
|
|
-- query buffer should remain unchanged
|
|
SELECT 1 AS x, 'Hello', 2 AS y, true AS "dirty\name"
|
|
\gdesc
|
|
\g
|
|
|
|
-- all on one line
|
|
SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g
|
|
|
|
-- test for server bug #17983 with empty statement in aborted transaction
|
|
set search_path = default;
|
|
begin;
|
|
bogus;
|
|
;
|
|
\gdesc
|
|
rollback;
|
|
|
|
-- \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
|
|
|
|
-- \setenv, \getenv
|
|
|
|
-- ensure MYVAR isn't set
|
|
\setenv MYVAR
|
|
-- in which case, reading it doesn't change the target
|
|
\getenv res MYVAR
|
|
\echo :res
|
|
-- now set it
|
|
\setenv MYVAR 'environment value'
|
|
\getenv res MYVAR
|
|
\echo :res
|
|
|
|
-- show all pset options
|
|
\pset
|
|
|
|
-- test multi-line headers, wrapping, and newline indicators
|
|
-- in aligned, unaligned, and wrapped formats
|
|
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
|
|
\pset border 1
|
|
|
|
-- support table for output-format tests (useful to create a footer)
|
|
|
|
create table psql_serial_tab (id serial);
|
|
|
|
-- test header/footer/tuples_only behavior in aligned/unaligned/wrapped cases
|
|
|
|
\pset format aligned
|
|
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
-- empty table is a special case for this format
|
|
select 1 where false;
|
|
|
|
\pset format unaligned
|
|
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
\pset format wrapped
|
|
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
-- check conditional am display
|
|
\pset expanded off
|
|
|
|
CREATE SCHEMA tableam_display;
|
|
CREATE ROLE regress_display_role;
|
|
ALTER SCHEMA tableam_display OWNER TO regress_display_role;
|
|
SET search_path TO tableam_display;
|
|
CREATE ACCESS METHOD heap_psql TYPE TABLE HANDLER heap_tableam_handler;
|
|
SET ROLE TO regress_display_role;
|
|
-- Use only relations with a physical size of zero.
|
|
CREATE TABLE tbl_heap_psql(f1 int, f2 char(100)) using heap_psql;
|
|
CREATE TABLE tbl_heap(f1 int, f2 char(100)) using heap;
|
|
CREATE VIEW view_heap_psql AS SELECT f1 from tbl_heap_psql;
|
|
CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tbl_heap_psql;
|
|
\d+ tbl_heap_psql
|
|
\d+ tbl_heap
|
|
\set HIDE_TABLEAM off
|
|
\d+ tbl_heap_psql
|
|
\d+ tbl_heap
|
|
-- AM is displayed for tables, indexes and materialized views.
|
|
\d+
|
|
\dt+
|
|
\dm+
|
|
-- But not for views and sequences.
|
|
\dv+
|
|
\set HIDE_TABLEAM on
|
|
\d+
|
|
RESET ROLE;
|
|
RESET search_path;
|
|
DROP SCHEMA tableam_display CASCADE;
|
|
DROP ACCESS METHOD heap_psql;
|
|
DROP ROLE regress_display_role;
|
|
|
|
-- test numericlocale (as best we can without control of psql's locale)
|
|
|
|
\pset format aligned
|
|
\pset expanded off
|
|
\pset numericlocale true
|
|
|
|
select n, -n as m, n * 111 as x, '1e90'::float8 as f
|
|
from generate_series(0,3) n;
|
|
|
|
\pset numericlocale false
|
|
|
|
-- test asciidoc output format
|
|
|
|
\pset format asciidoc
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some|text' as "a|title", ' ' as "empty ", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\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;
|
|
|
|
-- test csv output format
|
|
|
|
\pset format csv
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some"text' as "a""title", E' <foo>\n<bar>' as "junk",
|
|
' ' as "empty", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\pset expanded off
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
execute q;
|
|
|
|
deallocate q;
|
|
|
|
-- special cases
|
|
\pset expanded off
|
|
select 'comma,comma' as comma, 'semi;semi' as semi;
|
|
\pset csv_fieldsep ';'
|
|
select 'comma,comma' as comma, 'semi;semi' as semi;
|
|
select '\.' as data;
|
|
\pset csv_fieldsep '.'
|
|
select '\' as d1, '' as d2;
|
|
|
|
-- illegal csv separators
|
|
\pset csv_fieldsep ''
|
|
\pset csv_fieldsep '\0'
|
|
\pset csv_fieldsep '\n'
|
|
\pset csv_fieldsep '\r'
|
|
\pset csv_fieldsep '"'
|
|
\pset csv_fieldsep ',,'
|
|
|
|
\pset csv_fieldsep ','
|
|
|
|
-- test html output format
|
|
|
|
\pset format html
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some"text' as "a&title", E' <foo>\n<bar>' as "junk",
|
|
' ' as "empty", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\pset expanded off
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset tableattr foobar
|
|
execute q;
|
|
\pset tableattr
|
|
|
|
\pset expanded on
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset tableattr foobar
|
|
execute q;
|
|
\pset tableattr
|
|
|
|
deallocate q;
|
|
|
|
-- test latex output format
|
|
|
|
\pset format latex
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some\more_text' as "a$title", E' #<foo>%&^~|\n{bar}' as "junk",
|
|
' ' as "empty", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\pset expanded off
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
\pset border 3
|
|
execute q;
|
|
|
|
\pset expanded on
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
\pset border 3
|
|
execute q;
|
|
|
|
deallocate q;
|
|
|
|
-- test latex-longtable output format
|
|
|
|
\pset format latex-longtable
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some\more_text' as "a$title", E' #<foo>%&^~|\n{bar}' as "junk",
|
|
' ' as "empty", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\pset expanded off
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
\pset border 3
|
|
execute q;
|
|
|
|
\pset tableattr lr
|
|
execute q;
|
|
\pset tableattr
|
|
|
|
\pset expanded on
|
|
\pset border 0
|
|
execute q;
|
|
|
|
\pset border 1
|
|
execute q;
|
|
|
|
\pset border 2
|
|
execute q;
|
|
|
|
\pset border 3
|
|
execute q;
|
|
|
|
\pset tableattr lr
|
|
execute q;
|
|
\pset tableattr
|
|
|
|
deallocate q;
|
|
|
|
-- test troff-ms output format
|
|
|
|
\pset format troff-ms
|
|
|
|
\pset border 1
|
|
\pset expanded off
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
\pset expanded on
|
|
\d psql_serial_tab_id_seq
|
|
\pset tuples_only true
|
|
\df exp
|
|
\pset tuples_only false
|
|
|
|
prepare q as
|
|
select 'some\text' as "a\title", E' <foo>\n<bar>' as "junk",
|
|
' ' as "empty", n as int
|
|
from generate_series(1,2) as n;
|
|
|
|
\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;
|
|
|
|
-- check ambiguous format requests
|
|
|
|
\pset format a
|
|
\pset format l
|
|
|
|
-- clean up after output format tests
|
|
|
|
drop table psql_serial_tab;
|
|
|
|
\pset format aligned
|
|
\pset expanded off
|
|
\pset border 1
|
|
|
|
-- \echo and allied features
|
|
|
|
\echo this is a test
|
|
\echo -n without newline
|
|
\echo with -n newline
|
|
\echo '-n' with newline
|
|
|
|
\set foo bar
|
|
\echo foo = :foo
|
|
|
|
\qecho this is a test
|
|
\qecho foo = :foo
|
|
|
|
\warn this is a test
|
|
\warn foo = :foo
|
|
|
|
-- 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 true-false elif after initial true branch
|
|
\if true
|
|
\echo 'should print #2-5'
|
|
\elif true
|
|
\echo 'should not print #2-6'
|
|
\elif false
|
|
\echo 'should not print #2-7'
|
|
\else
|
|
\echo 'should not print #2-8'
|
|
\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
|
|
SELECT $1 \bind 1 \g
|
|
\C arg1
|
|
\c arg1 arg2 arg3 arg4
|
|
\cd arg1
|
|
\conninfo
|
|
\copy arg1 arg2 arg3 arg4 arg5 arg6
|
|
\copyright
|
|
SELECT 1 as one, 2, 3 \crosstabview
|
|
\dt arg1
|
|
\e arg1 arg2
|
|
\ef whole_line
|
|
\ev whole_line
|
|
\echo arg1 arg2 arg3 arg4 arg5
|
|
\echo arg1
|
|
\encoding arg1
|
|
\errverbose
|
|
\f arg1
|
|
\g arg1
|
|
\gx arg1
|
|
\gexec
|
|
SELECT 1 AS one \gset
|
|
\h
|
|
\?
|
|
\html
|
|
\i arg1
|
|
\ir arg1
|
|
\l arg1
|
|
\lo arg1 arg2
|
|
\lo_list
|
|
\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 arg2
|
|
\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
|
|
\z
|
|
\else
|
|
\echo 'should print #8-1'
|
|
\endif
|
|
|
|
-- :{?...} defined variable test
|
|
\set i 1
|
|
\if :{?i}
|
|
\echo '#9-1 ok, variable i is defined'
|
|
\else
|
|
\echo 'should not print #9-2'
|
|
\endif
|
|
|
|
\if :{?no_such_variable}
|
|
\echo 'should not print #10-1'
|
|
\else
|
|
\echo '#10-2 ok, variable no_such_variable is not defined'
|
|
\endif
|
|
|
|
SELECT :{?i} AS i_is_defined;
|
|
|
|
SELECT NOT :{?no_such_var} AS no_such_var_is_not_defined;
|
|
|
|
-- 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
|
|
|
|
-- tests for special result variables
|
|
|
|
-- working query, 2 rows selected
|
|
SELECT 1 AS stuff UNION SELECT 2;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
|
|
-- syntax error
|
|
SELECT 1 UNION;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
|
|
|
-- empty query
|
|
;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
-- must have kept previous values
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
|
|
|
-- other query error
|
|
DROP TABLE this_table_does_not_exist;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
|
|
|
-- nondefault verbosity error settings (except verbose, which is too unstable)
|
|
\set VERBOSITY terse
|
|
SELECT 1 UNION;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
|
|
\set VERBOSITY sqlstate
|
|
SELECT 1/0;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
|
|
\set VERBOSITY default
|
|
|
|
-- working \gdesc
|
|
SELECT 3 AS three, 4 AS four \gdesc
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
|
|
-- \gdesc with an error
|
|
SELECT 4 AS \gdesc
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
|
|
|
-- check row count for a query with chunked results
|
|
\set FETCH_COUNT 10
|
|
select unique2 from tenk1 order by unique2 limit 19;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
|
|
-- chunked results with an error after the first chunk
|
|
-- (we must disable parallel query here, else the behavior is timing-dependent)
|
|
set debug_parallel_query = off;
|
|
select 1/(15-unique2) from tenk1 order by unique2 limit 19;
|
|
\echo 'error:' :ERROR
|
|
\echo 'error code:' :SQLSTATE
|
|
\echo 'number of rows:' :ROW_COUNT
|
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
|
reset debug_parallel_query;
|
|
|
|
\unset FETCH_COUNT
|
|
|
|
create schema testpart;
|
|
create role regress_partitioning_role;
|
|
|
|
alter schema testpart owner to regress_partitioning_role;
|
|
|
|
set role to regress_partitioning_role;
|
|
|
|
-- run test inside own schema and hide other partitions
|
|
set search_path to testpart;
|
|
|
|
create table testtable_apple(logdate date);
|
|
create table testtable_orange(logdate date);
|
|
create index testtable_apple_index on testtable_apple(logdate);
|
|
create index testtable_orange_index on testtable_orange(logdate);
|
|
|
|
create table testpart_apple(logdate date) partition by range(logdate);
|
|
create table testpart_orange(logdate date) partition by range(logdate);
|
|
|
|
create index testpart_apple_index on testpart_apple(logdate);
|
|
create index testpart_orange_index on testpart_orange(logdate);
|
|
|
|
-- only partition related object should be displayed
|
|
\dP test*apple*
|
|
\dPt test*apple*
|
|
\dPi test*apple*
|
|
|
|
drop table testtable_apple;
|
|
drop table testtable_orange;
|
|
drop table testpart_apple;
|
|
drop table testpart_orange;
|
|
|
|
create table parent_tab (id int) partition by range (id);
|
|
create index parent_index on parent_tab (id);
|
|
create table child_0_10 partition of parent_tab
|
|
for values from (0) to (10);
|
|
create table child_10_20 partition of parent_tab
|
|
for values from (10) to (20);
|
|
create table child_20_30 partition of parent_tab
|
|
for values from (20) to (30);
|
|
insert into parent_tab values (generate_series(0,29));
|
|
create table child_30_40 partition of parent_tab
|
|
for values from (30) to (40)
|
|
partition by range(id);
|
|
create table child_30_35 partition of child_30_40
|
|
for values from (30) to (35);
|
|
create table child_35_40 partition of child_30_40
|
|
for values from (35) to (40);
|
|
insert into parent_tab values (generate_series(30,39));
|
|
|
|
\dPt
|
|
\dPi
|
|
|
|
\dP testpart.*
|
|
\dP
|
|
|
|
\dPtn
|
|
\dPin
|
|
\dPn
|
|
\dPn testpart.*
|
|
|
|
drop table parent_tab cascade;
|
|
|
|
drop schema testpart;
|
|
|
|
set search_path to default;
|
|
|
|
set role to default;
|
|
drop role regress_partitioning_role;
|
|
|
|
-- \d on toast table (use pg_statistic's toast table, which has a known name)
|
|
\d pg_toast.pg_toast_2619
|
|
|
|
-- check printing info about access methods
|
|
\dA
|
|
\dA *
|
|
\dA h*
|
|
\dA foo
|
|
\dA foo bar
|
|
\dA+
|
|
\dA+ *
|
|
\dA+ h*
|
|
\dA+ foo
|
|
\dAc brin pg*.oid*
|
|
\dAf spgist
|
|
\dAf btree int4
|
|
\dAo+ btree float_ops
|
|
\dAo * pg_catalog.jsonb_path_ops
|
|
\dAp+ btree float_ops
|
|
\dAp * pg_catalog.uuid_ops
|
|
|
|
-- check \dconfig
|
|
set work_mem = 10240;
|
|
\dconfig work_mem
|
|
\dconfig+ work*
|
|
reset work_mem;
|
|
|
|
-- check \df, \do with argument specifications
|
|
\df *sqrt
|
|
\df *sqrt num*
|
|
\df int*pl
|
|
\df int*pl int4
|
|
\df int*pl * pg_catalog.int8
|
|
\df acl* aclitem[]
|
|
\df has_database_privilege oid text
|
|
\df has_database_privilege oid text -
|
|
\dfa bit* small*
|
|
\df *._pg_expandarray
|
|
\do - pg_catalog.int4
|
|
\do && anyarray *
|
|
|
|
-- check \df+
|
|
-- we have to use functions with a predictable owner name, so make a role
|
|
create role regress_psql_user superuser;
|
|
begin;
|
|
set session authorization regress_psql_user;
|
|
|
|
create function psql_df_internal (float8)
|
|
returns float8
|
|
language internal immutable parallel safe strict
|
|
as 'dsin';
|
|
create function psql_df_sql (x integer)
|
|
returns integer
|
|
security definer
|
|
begin atomic select x + 1; end;
|
|
create function psql_df_plpgsql ()
|
|
returns void
|
|
language plpgsql
|
|
as $$ begin return; end; $$;
|
|
comment on function psql_df_plpgsql () is 'some comment';
|
|
|
|
\df+ psql_df_*
|
|
rollback;
|
|
drop role regress_psql_user;
|
|
|
|
-- check \sf
|
|
\sf information_schema._pg_index_position
|
|
\sf+ information_schema._pg_index_position
|
|
\sf+ interval_pl_time
|
|
\sf ts_debug(text);
|
|
\sf+ ts_debug(text)
|
|
|
|
-- AUTOCOMMIT
|
|
|
|
CREATE TABLE ac_test (a int);
|
|
\set AUTOCOMMIT off
|
|
|
|
INSERT INTO ac_test VALUES (1);
|
|
COMMIT;
|
|
SELECT * FROM ac_test;
|
|
COMMIT;
|
|
|
|
INSERT INTO ac_test VALUES (2);
|
|
ROLLBACK;
|
|
SELECT * FROM ac_test;
|
|
COMMIT;
|
|
|
|
BEGIN;
|
|
INSERT INTO ac_test VALUES (3);
|
|
COMMIT;
|
|
SELECT * FROM ac_test;
|
|
COMMIT;
|
|
|
|
BEGIN;
|
|
INSERT INTO ac_test VALUES (4);
|
|
ROLLBACK;
|
|
SELECT * FROM ac_test;
|
|
COMMIT;
|
|
|
|
\set AUTOCOMMIT on
|
|
DROP TABLE ac_test;
|
|
SELECT * FROM ac_test; -- should be gone now
|
|
|
|
-- ON_ERROR_ROLLBACK
|
|
|
|
\set ON_ERROR_ROLLBACK on
|
|
CREATE TABLE oer_test (a int);
|
|
|
|
BEGIN;
|
|
INSERT INTO oer_test VALUES (1);
|
|
INSERT INTO oer_test VALUES ('foo');
|
|
INSERT INTO oer_test VALUES (3);
|
|
COMMIT;
|
|
SELECT * FROM oer_test;
|
|
|
|
BEGIN;
|
|
INSERT INTO oer_test VALUES (4);
|
|
ROLLBACK;
|
|
SELECT * FROM oer_test;
|
|
|
|
BEGIN;
|
|
INSERT INTO oer_test VALUES (5);
|
|
COMMIT AND CHAIN;
|
|
INSERT INTO oer_test VALUES (6);
|
|
COMMIT;
|
|
SELECT * FROM oer_test;
|
|
|
|
DROP TABLE oer_test;
|
|
\set ON_ERROR_ROLLBACK off
|
|
|
|
-- ECHO errors
|
|
\set ECHO errors
|
|
SELECT * FROM notexists;
|
|
\set ECHO all
|
|
|
|
--
|
|
-- combined queries
|
|
--
|
|
CREATE FUNCTION warn(msg TEXT) RETURNS BOOLEAN LANGUAGE plpgsql
|
|
AS $$
|
|
BEGIN RAISE NOTICE 'warn %', msg ; RETURN TRUE ; END
|
|
$$;
|
|
|
|
-- show both
|
|
SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
|
|
-- \gset applies to last query only
|
|
SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset
|
|
\echo :three :four
|
|
-- syntax error stops all processing
|
|
SELECT 5 \; SELECT 6 + \; SELECT warn('6.5') \; SELECT 7 ;
|
|
-- with aborted transaction, stop on first error
|
|
BEGIN \; SELECT 8 AS eight \; SELECT 9/0 AS nine \; ROLLBACK \; SELECT 10 AS ten ;
|
|
-- close previously aborted transaction
|
|
ROLLBACK;
|
|
|
|
-- miscellaneous SQL commands
|
|
-- (non SELECT output is sent to stderr, thus is not shown in expected results)
|
|
SELECT 'ok' AS "begin" \;
|
|
CREATE TABLE psql_comics(s TEXT) \;
|
|
INSERT INTO psql_comics VALUES ('Calvin'), ('hobbes') \;
|
|
COPY psql_comics FROM STDIN \;
|
|
UPDATE psql_comics SET s = 'Hobbes' WHERE s = 'hobbes' \;
|
|
DELETE FROM psql_comics WHERE s = 'Moe' \;
|
|
COPY psql_comics TO STDOUT \;
|
|
TRUNCATE psql_comics \;
|
|
DROP TABLE psql_comics \;
|
|
SELECT 'ok' AS "done" ;
|
|
Moe
|
|
Susie
|
|
\.
|
|
|
|
\set SHOW_ALL_RESULTS off
|
|
SELECT 1 AS one \; SELECT warn('1.5') \; SELECT 2 AS two ;
|
|
|
|
\set SHOW_ALL_RESULTS on
|
|
DROP FUNCTION warn(TEXT);
|
|
|
|
--
|
|
-- \g with file
|
|
--
|
|
\getenv abs_builddir PG_ABS_BUILDDIR
|
|
\set g_out_file :abs_builddir '/results/psql-output1'
|
|
|
|
CREATE TEMPORARY TABLE reload_output(
|
|
lineno int NOT NULL GENERATED ALWAYS AS IDENTITY,
|
|
line text
|
|
);
|
|
|
|
SELECT 1 AS a \g :g_out_file
|
|
COPY reload_output(line) FROM :'g_out_file';
|
|
SELECT 2 AS b\; SELECT 3 AS c\; SELECT 4 AS d \g :g_out_file
|
|
COPY reload_output(line) FROM :'g_out_file';
|
|
COPY (SELECT 'foo') TO STDOUT \; COPY (SELECT 'bar') TO STDOUT \g :g_out_file
|
|
COPY reload_output(line) FROM :'g_out_file';
|
|
|
|
SELECT line FROM reload_output ORDER BY lineno;
|
|
TRUNCATE TABLE reload_output;
|
|
|
|
--
|
|
-- \o with file
|
|
--
|
|
\set o_out_file :abs_builddir '/results/psql-output2'
|
|
|
|
\o :o_out_file
|
|
SELECT max(unique1) FROM onek;
|
|
SELECT 1 AS a\; SELECT 2 AS b\; SELECT 3 AS c;
|
|
|
|
-- COPY TO file
|
|
-- The data goes to :g_out_file and the status to :o_out_file
|
|
\set QUIET false
|
|
COPY (SELECT unique1 FROM onek ORDER BY unique1 LIMIT 10) TO :'g_out_file';
|
|
-- DML command status
|
|
UPDATE onek SET unique1 = unique1 WHERE false;
|
|
\set QUIET true
|
|
\o
|
|
|
|
-- Check the contents of the files generated.
|
|
COPY reload_output(line) FROM :'g_out_file';
|
|
SELECT line FROM reload_output ORDER BY lineno;
|
|
TRUNCATE TABLE reload_output;
|
|
COPY reload_output(line) FROM :'o_out_file';
|
|
SELECT line FROM reload_output ORDER BY lineno;
|
|
TRUNCATE TABLE reload_output;
|
|
|
|
-- Multiple COPY TO STDOUT with output file
|
|
\o :o_out_file
|
|
-- The data goes to :o_out_file with no status generated.
|
|
COPY (SELECT 'foo1') TO STDOUT \; COPY (SELECT 'bar1') TO STDOUT;
|
|
-- Combination of \o and \g file with multiple COPY queries.
|
|
COPY (SELECT 'foo2') TO STDOUT \; COPY (SELECT 'bar2') TO STDOUT \g :g_out_file
|
|
\o
|
|
|
|
-- Check the contents of the files generated.
|
|
COPY reload_output(line) FROM :'g_out_file';
|
|
SELECT line FROM reload_output ORDER BY lineno;
|
|
TRUNCATE TABLE reload_output;
|
|
COPY reload_output(line) FROM :'o_out_file';
|
|
SELECT line FROM reload_output ORDER BY lineno;
|
|
|
|
DROP TABLE reload_output;
|
|
|
|
--
|
|
-- AUTOCOMMIT and combined queries
|
|
--
|
|
\set AUTOCOMMIT off
|
|
\echo '# AUTOCOMMIT:' :AUTOCOMMIT
|
|
-- BEGIN is now implicit
|
|
|
|
CREATE TABLE foo(s TEXT) \;
|
|
ROLLBACK;
|
|
|
|
CREATE TABLE foo(s TEXT) \;
|
|
INSERT INTO foo(s) VALUES ('hello'), ('world') \;
|
|
COMMIT;
|
|
|
|
DROP TABLE foo \;
|
|
ROLLBACK;
|
|
|
|
-- table foo is still there
|
|
SELECT * FROM foo ORDER BY 1 \;
|
|
DROP TABLE foo \;
|
|
COMMIT;
|
|
|
|
\set AUTOCOMMIT on
|
|
\echo '# AUTOCOMMIT:' :AUTOCOMMIT
|
|
-- BEGIN now explicit for multi-statement transactions
|
|
|
|
BEGIN \;
|
|
CREATE TABLE foo(s TEXT) \;
|
|
INSERT INTO foo(s) VALUES ('hello'), ('world') \;
|
|
COMMIT;
|
|
|
|
BEGIN \;
|
|
DROP TABLE foo \;
|
|
ROLLBACK \;
|
|
|
|
-- implicit transactions
|
|
SELECT * FROM foo ORDER BY 1 \;
|
|
DROP TABLE foo;
|
|
|
|
--
|
|
-- test ON_ERROR_ROLLBACK and combined queries
|
|
--
|
|
CREATE FUNCTION psql_error(msg TEXT) RETURNS BOOLEAN AS $$
|
|
BEGIN
|
|
RAISE EXCEPTION 'error %', msg;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
\set ON_ERROR_ROLLBACK on
|
|
\echo '# ON_ERROR_ROLLBACK:' :ON_ERROR_ROLLBACK
|
|
\echo '# AUTOCOMMIT:' :AUTOCOMMIT
|
|
|
|
BEGIN;
|
|
CREATE TABLE bla(s NO_SUCH_TYPE); -- fails
|
|
CREATE TABLE bla(s TEXT); -- succeeds
|
|
SELECT psql_error('oops!'); -- fails
|
|
INSERT INTO bla VALUES ('Calvin'), ('Hobbes');
|
|
COMMIT;
|
|
|
|
SELECT * FROM bla ORDER BY 1;
|
|
|
|
BEGIN;
|
|
INSERT INTO bla VALUES ('Susie'); -- succeeds
|
|
-- now with combined queries
|
|
INSERT INTO bla VALUES ('Rosalyn') \; -- will rollback
|
|
SELECT 'before error' AS show \; -- will show nevertheless!
|
|
SELECT psql_error('boum!') \; -- failure
|
|
SELECT 'after error' AS noshow; -- hidden by preceding error
|
|
INSERT INTO bla(s) VALUES ('Moe') \; -- will rollback
|
|
SELECT psql_error('bam!');
|
|
INSERT INTO bla VALUES ('Miss Wormwood'); -- succeeds
|
|
COMMIT;
|
|
SELECT * FROM bla ORDER BY 1;
|
|
|
|
-- some with autocommit off
|
|
\set AUTOCOMMIT off
|
|
\echo '# AUTOCOMMIT:' :AUTOCOMMIT
|
|
|
|
-- implicit BEGIN
|
|
INSERT INTO bla VALUES ('Dad'); -- succeeds
|
|
SELECT psql_error('bad!'); -- implicit partial rollback
|
|
|
|
INSERT INTO bla VALUES ('Mum') \; -- will rollback
|
|
SELECT COUNT(*) AS "#mum"
|
|
FROM bla WHERE s = 'Mum' \; -- but be counted here
|
|
SELECT psql_error('bad!'); -- implicit partial rollback
|
|
COMMIT;
|
|
|
|
SELECT COUNT(*) AS "#mum"
|
|
FROM bla WHERE s = 'Mum' \; -- no mum here
|
|
SELECT * FROM bla ORDER BY 1;
|
|
COMMIT;
|
|
|
|
-- reset all
|
|
\set AUTOCOMMIT on
|
|
\set ON_ERROR_ROLLBACK off
|
|
\echo '# final ON_ERROR_ROLLBACK:' :ON_ERROR_ROLLBACK
|
|
DROP TABLE bla;
|
|
DROP FUNCTION psql_error;
|
|
|
|
-- check describing invalid multipart names
|
|
\dA regression.heap
|
|
\dA nonesuch.heap
|
|
\dt host.regression.pg_catalog.pg_class
|
|
\dt |.pg_catalog.pg_class
|
|
\dt nonesuch.pg_catalog.pg_class
|
|
\da host.regression.pg_catalog.sum
|
|
\da +.pg_catalog.sum
|
|
\da nonesuch.pg_catalog.sum
|
|
\dAc nonesuch.brin
|
|
\dAc regression.brin
|
|
\dAf nonesuch.brin
|
|
\dAf regression.brin
|
|
\dAo nonesuch.brin
|
|
\dAo regression.brin
|
|
\dAp nonesuch.brin
|
|
\dAp regression.brin
|
|
\db nonesuch.pg_default
|
|
\db regression.pg_default
|
|
\dc host.regression.public.conversion
|
|
\dc (.public.conversion
|
|
\dc nonesuch.public.conversion
|
|
\dC host.regression.pg_catalog.int8
|
|
\dC ).pg_catalog.int8
|
|
\dC nonesuch.pg_catalog.int8
|
|
\dd host.regression.pg_catalog.pg_class
|
|
\dd [.pg_catalog.pg_class
|
|
\dd nonesuch.pg_catalog.pg_class
|
|
\dD host.regression.public.gtestdomain1
|
|
\dD ].public.gtestdomain1
|
|
\dD nonesuch.public.gtestdomain1
|
|
\ddp host.regression.pg_catalog.pg_class
|
|
\ddp {.pg_catalog.pg_class
|
|
\ddp nonesuch.pg_catalog.pg_class
|
|
\dE host.regression.public.ft
|
|
\dE }.public.ft
|
|
\dE nonesuch.public.ft
|
|
\di host.regression.public.tenk1_hundred
|
|
\di ..public.tenk1_hundred
|
|
\di nonesuch.public.tenk1_hundred
|
|
\dm host.regression.public.mvtest_bb
|
|
\dm ^.public.mvtest_bb
|
|
\dm nonesuch.public.mvtest_bb
|
|
\ds host.regression.public.check_seq
|
|
\ds regression|mydb.public.check_seq
|
|
\ds nonesuch.public.check_seq
|
|
\dt host.regression.public.b_star
|
|
\dt regres+ion.public.b_star
|
|
\dt nonesuch.public.b_star
|
|
\dv host.regression.public.shoe
|
|
\dv regress(ion).public.shoe
|
|
\dv nonesuch.public.shoe
|
|
\des nonesuch.server
|
|
\des regression.server
|
|
\des nonesuch.server
|
|
\des regression.server
|
|
\des nonesuch.username
|
|
\des regression.username
|
|
\dew nonesuch.fdw
|
|
\dew regression.fdw
|
|
\df host.regression.public.namelen
|
|
\df regres[qrstuv]ion.public.namelen
|
|
\df nonesuch.public.namelen
|
|
\dF host.regression.pg_catalog.arabic
|
|
\dF regres{1,2}ion.pg_catalog.arabic
|
|
\dF nonesuch.pg_catalog.arabic
|
|
\dFd host.regression.pg_catalog.arabic_stem
|
|
\dFd regres?ion.pg_catalog.arabic_stem
|
|
\dFd nonesuch.pg_catalog.arabic_stem
|
|
\dFp host.regression.pg_catalog.default
|
|
\dFp ^regression.pg_catalog.default
|
|
\dFp nonesuch.pg_catalog.default
|
|
\dFt host.regression.pg_catalog.ispell
|
|
\dFt regression$.pg_catalog.ispell
|
|
\dFt nonesuch.pg_catalog.ispell
|
|
\dg nonesuch.pg_database_owner
|
|
\dg regression.pg_database_owner
|
|
\dL host.regression.plpgsql
|
|
\dL *.plpgsql
|
|
\dL nonesuch.plpgsql
|
|
\dn host.regression.public
|
|
\dn """".public
|
|
\dn nonesuch.public
|
|
\do host.regression.public.!=-
|
|
\do "regression|mydb".public.!=-
|
|
\do nonesuch.public.!=-
|
|
\dO host.regression.pg_catalog.POSIX
|
|
\dO .pg_catalog.POSIX
|
|
\dO nonesuch.pg_catalog.POSIX
|
|
\dp host.regression.public.a_star
|
|
\dp "regres+ion".public.a_star
|
|
\dp nonesuch.public.a_star
|
|
\dP host.regression.public.mlparted
|
|
\dP "regres(sion)".public.mlparted
|
|
\dP nonesuch.public.mlparted
|
|
\drds nonesuch.lc_messages
|
|
\drds regression.lc_messages
|
|
\dRp public.mypub
|
|
\dRp regression.mypub
|
|
\dRs public.mysub
|
|
\dRs regression.mysub
|
|
\dT host.regression.public.widget
|
|
\dT "regression{1,2}".public.widget
|
|
\dT nonesuch.public.widget
|
|
\dx regression.plpgsql
|
|
\dx nonesuch.plpgsql
|
|
\dX host.regression.public.func_deps_stat
|
|
\dX "^regression$".public.func_deps_stat
|
|
\dX nonesuch.public.func_deps_stat
|
|
\dy regression.myevt
|
|
\dy nonesuch.myevt
|
|
|
|
-- check that dots within quoted name segments are not counted
|
|
\dA "no.such.access.method"
|
|
\dt "no.such.table.relation"
|
|
\da "no.such.aggregate.function"
|
|
\dAc "no.such.operator.class"
|
|
\dAf "no.such.operator.family"
|
|
\dAo "no.such.operator.of.operator.family"
|
|
\dAp "no.such.operator.support.function.of.operator.family"
|
|
\db "no.such.tablespace"
|
|
\dc "no.such.conversion"
|
|
\dC "no.such.cast"
|
|
\dd "no.such.object.description"
|
|
\dD "no.such.domain"
|
|
\ddp "no.such.default.access.privilege"
|
|
\di "no.such.index.relation"
|
|
\dm "no.such.materialized.view"
|
|
\ds "no.such.relation"
|
|
\dt "no.such.relation"
|
|
\dv "no.such.relation"
|
|
\des "no.such.foreign.server"
|
|
\dew "no.such.foreign.data.wrapper"
|
|
\df "no.such.function"
|
|
\dF "no.such.text.search.configuration"
|
|
\dFd "no.such.text.search.dictionary"
|
|
\dFp "no.such.text.search.parser"
|
|
\dFt "no.such.text.search.template"
|
|
\dg "no.such.role"
|
|
\dL "no.such.language"
|
|
\dn "no.such.schema"
|
|
\do "no.such.operator"
|
|
\dO "no.such.collation"
|
|
\dp "no.such.access.privilege"
|
|
\dP "no.such.partitioned.relation"
|
|
\drds "no.such.setting"
|
|
\dRp "no.such.publication"
|
|
\dRs "no.such.subscription"
|
|
\dT "no.such.data.type"
|
|
\dx "no.such.installed.extension"
|
|
\dX "no.such.extended.statistics"
|
|
\dy "no.such.event.trigger"
|
|
|
|
-- again, but with dotted schema qualifications.
|
|
\dA "no.such.schema"."no.such.access.method"
|
|
\dt "no.such.schema"."no.such.table.relation"
|
|
\da "no.such.schema"."no.such.aggregate.function"
|
|
\dAc "no.such.schema"."no.such.operator.class"
|
|
\dAf "no.such.schema"."no.such.operator.family"
|
|
\dAo "no.such.schema"."no.such.operator.of.operator.family"
|
|
\dAp "no.such.schema"."no.such.operator.support.function.of.operator.family"
|
|
\db "no.such.schema"."no.such.tablespace"
|
|
\dc "no.such.schema"."no.such.conversion"
|
|
\dC "no.such.schema"."no.such.cast"
|
|
\dd "no.such.schema"."no.such.object.description"
|
|
\dD "no.such.schema"."no.such.domain"
|
|
\ddp "no.such.schema"."no.such.default.access.privilege"
|
|
\di "no.such.schema"."no.such.index.relation"
|
|
\dm "no.such.schema"."no.such.materialized.view"
|
|
\ds "no.such.schema"."no.such.relation"
|
|
\dt "no.such.schema"."no.such.relation"
|
|
\dv "no.such.schema"."no.such.relation"
|
|
\des "no.such.schema"."no.such.foreign.server"
|
|
\dew "no.such.schema"."no.such.foreign.data.wrapper"
|
|
\df "no.such.schema"."no.such.function"
|
|
\dF "no.such.schema"."no.such.text.search.configuration"
|
|
\dFd "no.such.schema"."no.such.text.search.dictionary"
|
|
\dFp "no.such.schema"."no.such.text.search.parser"
|
|
\dFt "no.such.schema"."no.such.text.search.template"
|
|
\dg "no.such.schema"."no.such.role"
|
|
\dL "no.such.schema"."no.such.language"
|
|
\do "no.such.schema"."no.such.operator"
|
|
\dO "no.such.schema"."no.such.collation"
|
|
\dp "no.such.schema"."no.such.access.privilege"
|
|
\dP "no.such.schema"."no.such.partitioned.relation"
|
|
\drds "no.such.schema"."no.such.setting"
|
|
\dRp "no.such.schema"."no.such.publication"
|
|
\dRs "no.such.schema"."no.such.subscription"
|
|
\dT "no.such.schema"."no.such.data.type"
|
|
\dx "no.such.schema"."no.such.installed.extension"
|
|
\dX "no.such.schema"."no.such.extended.statistics"
|
|
\dy "no.such.schema"."no.such.event.trigger"
|
|
|
|
-- again, but with current database and dotted schema qualifications.
|
|
\dt regression."no.such.schema"."no.such.table.relation"
|
|
\da regression."no.such.schema"."no.such.aggregate.function"
|
|
\dc regression."no.such.schema"."no.such.conversion"
|
|
\dC regression."no.such.schema"."no.such.cast"
|
|
\dd regression."no.such.schema"."no.such.object.description"
|
|
\dD regression."no.such.schema"."no.such.domain"
|
|
\di regression."no.such.schema"."no.such.index.relation"
|
|
\dm regression."no.such.schema"."no.such.materialized.view"
|
|
\ds regression."no.such.schema"."no.such.relation"
|
|
\dt regression."no.such.schema"."no.such.relation"
|
|
\dv regression."no.such.schema"."no.such.relation"
|
|
\df regression."no.such.schema"."no.such.function"
|
|
\dF regression."no.such.schema"."no.such.text.search.configuration"
|
|
\dFd regression."no.such.schema"."no.such.text.search.dictionary"
|
|
\dFp regression."no.such.schema"."no.such.text.search.parser"
|
|
\dFt regression."no.such.schema"."no.such.text.search.template"
|
|
\do regression."no.such.schema"."no.such.operator"
|
|
\dO regression."no.such.schema"."no.such.collation"
|
|
\dp regression."no.such.schema"."no.such.access.privilege"
|
|
\dP regression."no.such.schema"."no.such.partitioned.relation"
|
|
\dT regression."no.such.schema"."no.such.data.type"
|
|
\dX regression."no.such.schema"."no.such.extended.statistics"
|
|
|
|
-- again, but with dotted database and dotted schema qualifications.
|
|
\dt "no.such.database"."no.such.schema"."no.such.table.relation"
|
|
\da "no.such.database"."no.such.schema"."no.such.aggregate.function"
|
|
\dc "no.such.database"."no.such.schema"."no.such.conversion"
|
|
\dC "no.such.database"."no.such.schema"."no.such.cast"
|
|
\dd "no.such.database"."no.such.schema"."no.such.object.description"
|
|
\dD "no.such.database"."no.such.schema"."no.such.domain"
|
|
\ddp "no.such.database"."no.such.schema"."no.such.default.access.privilege"
|
|
\di "no.such.database"."no.such.schema"."no.such.index.relation"
|
|
\dm "no.such.database"."no.such.schema"."no.such.materialized.view"
|
|
\ds "no.such.database"."no.such.schema"."no.such.relation"
|
|
\dt "no.such.database"."no.such.schema"."no.such.relation"
|
|
\dv "no.such.database"."no.such.schema"."no.such.relation"
|
|
\df "no.such.database"."no.such.schema"."no.such.function"
|
|
\dF "no.such.database"."no.such.schema"."no.such.text.search.configuration"
|
|
\dFd "no.such.database"."no.such.schema"."no.such.text.search.dictionary"
|
|
\dFp "no.such.database"."no.such.schema"."no.such.text.search.parser"
|
|
\dFt "no.such.database"."no.such.schema"."no.such.text.search.template"
|
|
\do "no.such.database"."no.such.schema"."no.such.operator"
|
|
\dO "no.such.database"."no.such.schema"."no.such.collation"
|
|
\dp "no.such.database"."no.such.schema"."no.such.access.privilege"
|
|
\dP "no.such.database"."no.such.schema"."no.such.partitioned.relation"
|
|
\dT "no.such.database"."no.such.schema"."no.such.data.type"
|
|
\dX "no.such.database"."no.such.schema"."no.such.extended.statistics"
|
|
|
|
-- check \drg and \du
|
|
CREATE ROLE regress_du_role0;
|
|
CREATE ROLE regress_du_role1;
|
|
CREATE ROLE regress_du_role2;
|
|
CREATE ROLE regress_du_admin;
|
|
|
|
GRANT regress_du_role0 TO regress_du_admin WITH ADMIN TRUE;
|
|
GRANT regress_du_role1 TO regress_du_admin WITH ADMIN TRUE;
|
|
GRANT regress_du_role2 TO regress_du_admin WITH ADMIN TRUE;
|
|
|
|
GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN TRUE, INHERIT TRUE, SET TRUE GRANTED BY regress_du_admin;
|
|
GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN TRUE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_admin;
|
|
GRANT regress_du_role1 TO regress_du_role2 WITH ADMIN TRUE , INHERIT FALSE, SET TRUE GRANTED BY regress_du_admin;
|
|
GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT TRUE, SET FALSE GRANTED BY regress_du_role1;
|
|
GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT TRUE , SET TRUE GRANTED BY regress_du_role1;
|
|
GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT FALSE, SET TRUE GRANTED BY regress_du_role2;
|
|
GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_role2;
|
|
|
|
\drg regress_du_role*
|
|
\du regress_du_role*
|
|
|
|
DROP ROLE regress_du_role0;
|
|
DROP ROLE regress_du_role1;
|
|
DROP ROLE regress_du_role2;
|
|
DROP ROLE regress_du_admin;
|
|
|
|
-- Test display of empty privileges.
|
|
BEGIN;
|
|
-- Create an owner for tested objects because output contains owner name.
|
|
CREATE ROLE regress_zeropriv_owner;
|
|
SET LOCAL ROLE regress_zeropriv_owner;
|
|
|
|
CREATE DOMAIN regress_zeropriv_domain AS int;
|
|
REVOKE ALL ON DOMAIN regress_zeropriv_domain FROM CURRENT_USER, PUBLIC;
|
|
\dD+ regress_zeropriv_domain
|
|
|
|
CREATE PROCEDURE regress_zeropriv_proc() LANGUAGE sql AS '';
|
|
REVOKE ALL ON PROCEDURE regress_zeropriv_proc() FROM CURRENT_USER, PUBLIC;
|
|
\df+ regress_zeropriv_proc
|
|
|
|
CREATE TABLE regress_zeropriv_tbl (a int);
|
|
REVOKE ALL ON TABLE regress_zeropriv_tbl FROM CURRENT_USER;
|
|
\dp regress_zeropriv_tbl
|
|
|
|
CREATE TYPE regress_zeropriv_type AS (a int);
|
|
REVOKE ALL ON TYPE regress_zeropriv_type FROM CURRENT_USER, PUBLIC;
|
|
\dT+ regress_zeropriv_type
|
|
|
|
ROLLBACK;
|
|
|
|
-- Test display of default privileges with \pset null.
|
|
CREATE TABLE defprivs (a int);
|
|
\pset null '(default)'
|
|
\z defprivs
|
|
\pset null ''
|
|
DROP TABLE defprivs;
|