*** /Users/decibel/pgsql/HEAD/src/test/regress/expected/create_index.out Tue Oct 28 15:52:02 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/create_index.out Tue Oct 28 15:53:04 2014 *************** *** 2835,2867 **** CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab; REINDEX INDEX CONCURRENTLY concur_reindex_ind1; REINDEX TABLE CONCURRENTLY concur_reindex_tab; ! REINDEX TABLE CONCURRENTLY concur_reindex_matview; ! -- Check errors ! -- Cannot run inside a transaction block ! BEGIN; ! REINDEX TABLE CONCURRENTLY concur_reindex_tab; ! ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block ! COMMIT; ! REINDEX TABLE CONCURRENTLY pg_database; -- no shared relation ! ERROR: concurrent reindex is not supported for shared relations ! REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relations ! ERROR: concurrent reindex is not supported for catalog relations ! REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM ! ERROR: cannot reindex system concurrently ! -- Check the relation status, there should not be invalid indexes ! \d concur_reindex_tab ! Table "public.concur_reindex_tab" ! Column | Type | Modifiers ! --------+---------+----------- ! c1 | integer | not null ! c2 | text | ! Indexes: ! "concur_reindex_ind1" PRIMARY KEY, btree (c1) ! "concur_reindex_ind3" UNIQUE, btree (abs(c1)) ! "concur_reindex_ind2" btree (c2) ! "concur_reindex_ind4" btree (c1, c1, c2) ! Referenced by: ! TABLE "concur_reindex_tab2" CONSTRAINT "concur_reindex_tab2_c1_fkey" FOREIGN KEY (c1) REFERENCES concur_reindex_tab(c1) ! ! DROP MATERIALIZED VIEW concur_reindex_matview; ! DROP TABLE concur_reindex_tab, concur_reindex_tab2; --- 2835,2841 ---- CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab; REINDEX INDEX CONCURRENTLY concur_reindex_ind1; REINDEX TABLE CONCURRENTLY concur_reindex_tab; ! server closed the connection unexpectedly ! This probably means the server terminated abnormally ! before or while processing the request. ! connection to server was lost ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/create_aggregate.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/create_aggregate.out Tue Oct 28 15:53:05 2014 *************** *** 1,129 **** ! -- ! -- CREATE_AGGREGATE ! -- ! -- all functions CREATEd ! CREATE AGGREGATE newavg ( ! sfunc = int4_avg_accum, basetype = int4, stype = _int8, ! finalfunc = int8_avg, ! initcond1 = '{0,0}' ! ); ! -- test comments ! COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment'; ! ERROR: aggregate newavg_wrong(integer) does not exist ! COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment'; ! COMMENT ON AGGREGATE newavg (int4) IS NULL; ! -- without finalfunc; test obsolete spellings 'sfunc1' etc ! CREATE AGGREGATE newsum ( ! sfunc1 = int4pl, basetype = int4, stype1 = int4, ! initcond1 = '0' ! ); ! -- zero-argument aggregate ! CREATE AGGREGATE newcnt (*) ( ! sfunc = int8inc, stype = int8, ! initcond = '0' ! ); ! -- old-style spelling of same ! CREATE AGGREGATE oldcnt ( ! sfunc = int8inc, basetype = 'ANY', stype = int8, ! initcond = '0' ! ); ! -- aggregate that only cares about null/nonnull input ! CREATE AGGREGATE newcnt ("any") ( ! sfunc = int8inc_any, stype = int8, ! initcond = '0' ! ); ! COMMENT ON AGGREGATE nosuchagg (*) IS 'should fail'; ! ERROR: aggregate nosuchagg(*) does not exist ! COMMENT ON AGGREGATE newcnt (*) IS 'an agg(*) comment'; ! COMMENT ON AGGREGATE newcnt ("any") IS 'an agg(any) comment'; ! -- multi-argument aggregate ! create function sum3(int8,int8,int8) returns int8 as ! 'select $1 + $2 + $3' language sql strict immutable; ! create aggregate sum2(int8,int8) ( ! sfunc = sum3, stype = int8, ! initcond = '0' ! ); ! -- multi-argument aggregates sensitive to distinct/order, strict/nonstrict ! create type aggtype as (a integer, b integer, c text); ! create function aggf_trans(aggtype[],integer,integer,text) returns aggtype[] ! as 'select array_append($1,ROW($2,$3,$4)::aggtype)' ! language sql strict immutable; ! create function aggfns_trans(aggtype[],integer,integer,text) returns aggtype[] ! as 'select array_append($1,ROW($2,$3,$4)::aggtype)' ! language sql immutable; ! create aggregate aggfstr(integer,integer,text) ( ! sfunc = aggf_trans, stype = aggtype[], ! initcond = '{}' ! ); ! create aggregate aggfns(integer,integer,text) ( ! sfunc = aggfns_trans, stype = aggtype[], sspace = 10000, ! initcond = '{}' ! ); ! -- variadic aggregate ! create function least_accum(anyelement, variadic anyarray) ! returns anyelement language sql as ! 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)'; ! create aggregate least_agg(variadic items anyarray) ( ! stype = anyelement, sfunc = least_accum ! ); ! -- test ordered-set aggs using built-in support functions ! create aggregate my_percentile_disc(float8 ORDER BY anyelement) ( ! stype = internal, ! sfunc = ordered_set_transition, ! finalfunc = percentile_disc_final, ! finalfunc_extra = true ! ); ! create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( ! stype = internal, ! sfunc = ordered_set_transition_multi, ! finalfunc = rank_final, ! finalfunc_extra = true, ! hypothetical ! ); ! alter aggregate my_percentile_disc(float8 ORDER BY anyelement) ! rename to test_percentile_disc; ! alter aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ! rename to test_rank; ! \da test_* ! List of aggregate functions ! Schema | Name | Result data type | Argument data types | Description ! --------+----------------------+------------------+----------------------------------------+------------- ! public | test_percentile_disc | anyelement | double precision ORDER BY anyelement | ! public | test_rank | bigint | VARIADIC "any" ORDER BY VARIADIC "any" | ! (2 rows) ! ! -- moving-aggregate options ! CREATE AGGREGATE sumdouble (float8) ! ( ! stype = float8, ! sfunc = float8pl, ! mstype = float8, ! msfunc = float8pl, ! minvfunc = float8mi ! ); ! -- invalid: nonstrict inverse with strict forward function ! CREATE FUNCTION float8mi_n(float8, float8) RETURNS float8 AS ! $$ SELECT $1 - $2; $$ ! LANGUAGE SQL; ! CREATE AGGREGATE invalidsumdouble (float8) ! ( ! stype = float8, ! sfunc = float8pl, ! mstype = float8, ! msfunc = float8pl, ! minvfunc = float8mi_n ! ); ! ERROR: strictness of aggregate's forward and inverse transition functions must match ! -- invalid: non-matching result types ! CREATE FUNCTION float8mi_int(float8, float8) RETURNS int AS ! $$ SELECT CAST($1 - $2 AS INT); $$ ! LANGUAGE SQL; ! CREATE AGGREGATE wrongreturntype (float8) ! ( ! stype = float8, ! sfunc = float8pl, ! mstype = float8, ! msfunc = float8pl, ! minvfunc = float8mi_int ! ); ! ERROR: return type of inverse transition function float8mi_int is not double precision --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/create_function_3.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/create_function_3.out Tue Oct 28 15:53:05 2014 *************** *** 1,243 **** ! -- ! -- CREATE FUNCTION ! -- ! -- sanity check of pg_proc catalog to the given parameters ! -- ! CREATE USER regtest_unpriv_user; ! CREATE SCHEMA temp_func_test; ! GRANT ALL ON SCHEMA temp_func_test TO public; ! SET search_path TO temp_func_test, public; ! -- ! -- ARGUMENT and RETURN TYPES ! -- ! CREATE FUNCTION functest_A_1(text, date) RETURNS bool LANGUAGE 'sql' ! AS 'SELECT $1 = ''abcd'' AND $2 > ''2001-01-01'''; ! CREATE FUNCTION functest_A_2(text[]) RETURNS int LANGUAGE 'sql' ! AS 'SELECT $1[0]::int'; ! CREATE FUNCTION functest_A_3() RETURNS bool LANGUAGE 'sql' ! AS 'SELECT false'; ! SELECT proname, prorettype::regtype, proargtypes::regtype[] FROM pg_proc ! WHERE oid in ('functest_A_1'::regproc, ! 'functest_A_2'::regproc, ! 'functest_A_3'::regproc) ORDER BY proname; ! proname | prorettype | proargtypes ! --------------+------------+------------------- ! functest_a_1 | boolean | [0:1]={text,date} ! functest_a_2 | integer | [0:0]={text[]} ! functest_a_3 | boolean | {} ! (3 rows) ! ! -- ! -- IMMUTABLE | STABLE | VOLATILE ! -- ! CREATE FUNCTION functest_B_1(int) RETURNS bool LANGUAGE 'sql' ! AS 'SELECT $1 > 0'; ! CREATE FUNCTION functest_B_2(int) RETURNS bool LANGUAGE 'sql' ! IMMUTABLE AS 'SELECT $1 > 0'; ! CREATE FUNCTION functest_B_3(int) RETURNS bool LANGUAGE 'sql' ! STABLE AS 'SELECT $1 = 0'; ! CREATE FUNCTION functest_B_4(int) RETURNS bool LANGUAGE 'sql' ! VOLATILE AS 'SELECT $1 < 0'; ! SELECT proname, provolatile FROM pg_proc ! WHERE oid in ('functest_B_1'::regproc, ! 'functest_B_2'::regproc, ! 'functest_B_3'::regproc, ! 'functest_B_4'::regproc) ORDER BY proname; ! proname | provolatile ! --------------+------------- ! functest_b_1 | v ! functest_b_2 | i ! functest_b_3 | s ! functest_b_4 | v ! (4 rows) ! ! ALTER FUNCTION functest_B_2(int) VOLATILE; ! ALTER FUNCTION functest_B_3(int) COST 100; -- unrelated change, no effect ! SELECT proname, provolatile FROM pg_proc ! WHERE oid in ('functest_B_1'::regproc, ! 'functest_B_2'::regproc, ! 'functest_B_3'::regproc, ! 'functest_B_4'::regproc) ORDER BY proname; ! proname | provolatile ! --------------+------------- ! functest_b_1 | v ! functest_b_2 | v ! functest_b_3 | s ! functest_b_4 | v ! (4 rows) ! ! -- ! -- SECURITY DEFINER | INVOKER ! -- ! CREATE FUNCTION functext_C_1(int) RETURNS bool LANGUAGE 'sql' ! AS 'SELECT $1 > 0'; ! CREATE FUNCTION functext_C_2(int) RETURNS bool LANGUAGE 'sql' ! SECURITY DEFINER AS 'SELECT $1 = 0'; ! CREATE FUNCTION functext_C_3(int) RETURNS bool LANGUAGE 'sql' ! SECURITY INVOKER AS 'SELECT $1 < 0'; ! SELECT proname, prosecdef FROM pg_proc ! WHERE oid in ('functext_C_1'::regproc, ! 'functext_C_2'::regproc, ! 'functext_C_3'::regproc) ORDER BY proname; ! proname | prosecdef ! --------------+----------- ! functext_c_1 | f ! functext_c_2 | t ! functext_c_3 | f ! (3 rows) ! ! ALTER FUNCTION functext_C_1(int) IMMUTABLE; -- unrelated change, no effect ! ALTER FUNCTION functext_C_2(int) SECURITY INVOKER; ! ALTER FUNCTION functext_C_3(int) SECURITY DEFINER; ! SELECT proname, prosecdef FROM pg_proc ! WHERE oid in ('functext_C_1'::regproc, ! 'functext_C_2'::regproc, ! 'functext_C_3'::regproc) ORDER BY proname; ! proname | prosecdef ! --------------+----------- ! functext_c_1 | f ! functext_c_2 | f ! functext_c_3 | t ! (3 rows) ! ! -- ! -- LEAKPROOF ! -- ! CREATE FUNCTION functext_E_1(int) RETURNS bool LANGUAGE 'sql' ! AS 'SELECT $1 > 100'; ! CREATE FUNCTION functext_E_2(int) RETURNS bool LANGUAGE 'sql' ! LEAKPROOF AS 'SELECT $1 > 100'; ! SELECT proname, proleakproof FROM pg_proc ! WHERE oid in ('functext_E_1'::regproc, ! 'functext_E_2'::regproc) ORDER BY proname; ! proname | proleakproof ! --------------+-------------- ! functext_e_1 | f ! functext_e_2 | t ! (2 rows) ! ! ALTER FUNCTION functext_E_1(int) LEAKPROOF; ! ALTER FUNCTION functext_E_2(int) STABLE; -- unrelated change, no effect ! SELECT proname, proleakproof FROM pg_proc ! WHERE oid in ('functext_E_1'::regproc, ! 'functext_E_2'::regproc) ORDER BY proname; ! proname | proleakproof ! --------------+-------------- ! functext_e_1 | t ! functext_e_2 | t ! (2 rows) ! ! ALTER FUNCTION functext_E_2(int) NOT LEAKPROOF; -- remove leakproog attribute ! SELECT proname, proleakproof FROM pg_proc ! WHERE oid in ('functext_E_1'::regproc, ! 'functext_E_2'::regproc) ORDER BY proname; ! proname | proleakproof ! --------------+-------------- ! functext_e_1 | t ! functext_e_2 | f ! (2 rows) ! ! -- it takes superuser privilege to turn on leakproof, but not for turn off ! ALTER FUNCTION functext_E_1(int) OWNER TO regtest_unpriv_user; ! ALTER FUNCTION functext_E_2(int) OWNER TO regtest_unpriv_user; ! SET SESSION AUTHORIZATION regtest_unpriv_user; ! SET search_path TO temp_func_test, public; ! ALTER FUNCTION functext_E_1(int) NOT LEAKPROOF; ! ALTER FUNCTION functext_E_2(int) LEAKPROOF; ! ERROR: only superuser can define a leakproof function ! CREATE FUNCTION functext_E_3(int) RETURNS bool LANGUAGE 'sql' ! LEAKPROOF AS 'SELECT $1 < 200'; -- failed ! ERROR: only superuser can define a leakproof function ! RESET SESSION AUTHORIZATION; ! -- ! -- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT ! -- ! CREATE FUNCTION functext_F_1(int) RETURNS bool LANGUAGE 'sql' ! AS 'SELECT $1 > 50'; ! CREATE FUNCTION functext_F_2(int) RETURNS bool LANGUAGE 'sql' ! CALLED ON NULL INPUT AS 'SELECT $1 = 50'; ! CREATE FUNCTION functext_F_3(int) RETURNS bool LANGUAGE 'sql' ! RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50'; ! CREATE FUNCTION functext_F_4(int) RETURNS bool LANGUAGE 'sql' ! STRICT AS 'SELECT $1 = 50'; ! SELECT proname, proisstrict FROM pg_proc ! WHERE oid in ('functext_F_1'::regproc, ! 'functext_F_2'::regproc, ! 'functext_F_3'::regproc, ! 'functext_F_4'::regproc) ORDER BY proname; ! proname | proisstrict ! --------------+------------- ! functext_f_1 | f ! functext_f_2 | f ! functext_f_3 | t ! functext_f_4 | t ! (4 rows) ! ! ALTER FUNCTION functext_F_1(int) IMMUTABLE; -- unrelated change, no effect ! ALTER FUNCTION functext_F_2(int) STRICT; ! ALTER FUNCTION functext_F_3(int) CALLED ON NULL INPUT; ! SELECT proname, proisstrict FROM pg_proc ! WHERE oid in ('functext_F_1'::regproc, ! 'functext_F_2'::regproc, ! 'functext_F_3'::regproc, ! 'functext_F_4'::regproc) ORDER BY proname; ! proname | proisstrict ! --------------+------------- ! functext_f_1 | f ! functext_f_2 | t ! functext_f_3 | f ! functext_f_4 | t ! (4 rows) ! ! -- information_schema tests ! CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo') ! RETURNS int ! LANGUAGE SQL ! AS 'SELECT $1 + $2'; ! CREATE FUNCTION functest_IS_2(out a int, b int default 1) ! RETURNS int ! LANGUAGE SQL ! AS 'SELECT $1'; ! CREATE FUNCTION functest_IS_3(a int default 1, out b int) ! RETURNS int ! LANGUAGE SQL ! AS 'SELECT $1'; ! SELECT routine_name, ordinal_position, parameter_name, parameter_default ! FROM information_schema.parameters JOIN information_schema.routines USING (specific_schema, specific_name) ! WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_' ! ORDER BY 1, 2; ! routine_name | ordinal_position | parameter_name | parameter_default ! ---------------+------------------+----------------+------------------- ! functest_is_1 | 1 | a | ! functest_is_1 | 2 | b | 1 ! functest_is_1 | 3 | c | 'foo'::text ! functest_is_2 | 1 | a | ! functest_is_2 | 2 | b | 1 ! functest_is_3 | 1 | a | 1 ! functest_is_3 | 2 | b | ! (7 rows) ! ! -- Cleanups ! DROP SCHEMA temp_func_test CASCADE; ! NOTICE: drop cascades to 19 other objects ! DETAIL: drop cascades to function functest_a_1(text,date) ! drop cascades to function functest_a_2(text[]) ! drop cascades to function functest_a_3() ! drop cascades to function functest_b_1(integer) ! drop cascades to function functest_b_2(integer) ! drop cascades to function functest_b_3(integer) ! drop cascades to function functest_b_4(integer) ! drop cascades to function functext_c_1(integer) ! drop cascades to function functext_c_2(integer) ! drop cascades to function functext_c_3(integer) ! drop cascades to function functext_e_1(integer) ! drop cascades to function functext_e_2(integer) ! drop cascades to function functext_f_1(integer) ! drop cascades to function functext_f_2(integer) ! drop cascades to function functext_f_3(integer) ! drop cascades to function functext_f_4(integer) ! drop cascades to function functest_is_1(integer,integer,text) ! drop cascades to function functest_is_2(integer) ! drop cascades to function functest_is_3(integer) ! DROP USER regtest_unpriv_user; ! RESET search_path; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/create_cast.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/create_cast.out Tue Oct 28 15:53:05 2014 *************** *** 1,74 **** ! -- ! -- CREATE_CAST ! -- ! -- Create some types to test with ! CREATE TYPE casttesttype; ! CREATE FUNCTION casttesttype_in(cstring) ! RETURNS casttesttype ! AS 'textin' ! LANGUAGE internal STRICT; ! NOTICE: return type casttesttype is only a shell ! CREATE FUNCTION casttesttype_out(casttesttype) ! RETURNS cstring ! AS 'textout' ! LANGUAGE internal STRICT; ! NOTICE: argument type casttesttype is only a shell ! CREATE TYPE casttesttype ( ! internallength = variable, ! input = casttesttype_in, ! output = casttesttype_out, ! alignment = int4 ! ); ! -- a dummy function to test with ! CREATE FUNCTION casttestfunc(casttesttype) RETURNS int4 LANGUAGE SQL AS ! $$ SELECT 1; $$; ! SELECT casttestfunc('foo'::text); -- fails, as there's no cast ! ERROR: function casttestfunc(text) does not exist ! LINE 1: SELECT casttestfunc('foo'::text); ! ^ ! HINT: No function matches the given name and argument types. You might need to add explicit type casts. ! -- Try binary coercion cast ! CREATE CAST (text AS casttesttype) WITHOUT FUNCTION; ! SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit ! ERROR: function casttestfunc(text) does not exist ! LINE 1: SELECT casttestfunc('foo'::text); ! ^ ! HINT: No function matches the given name and argument types. You might need to add explicit type casts. ! SELECT casttestfunc('foo'::text::casttesttype); -- should work ! casttestfunc ! -------------- ! 1 ! (1 row) ! ! DROP CAST (text AS casttesttype); -- cleanup ! -- Try IMPLICIT binary coercion cast ! CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT; ! SELECT casttestfunc('foo'::text); -- Should work now ! casttestfunc ! -------------- ! 1 ! (1 row) ! ! -- Try I/O conversion cast. ! SELECT 1234::int4::casttesttype; -- No cast yet, should fail ! ERROR: cannot cast type integer to casttesttype ! LINE 1: SELECT 1234::int4::casttesttype; ! ^ ! CREATE CAST (int4 AS casttesttype) WITH INOUT; ! SELECT 1234::int4::casttesttype; -- Should work now ! casttesttype ! -------------- ! 1234 ! (1 row) ! ! DROP CAST (int4 AS casttesttype); ! -- Try cast with a function ! CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS ! $$ SELECT ('foo'::text || $1::text)::casttesttype; $$; ! CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT; ! SELECT 1234::int4::casttesttype; -- Should work now ! casttesttype ! -------------- ! foo1234 ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/constraints.out Tue Oct 28 15:52:48 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/constraints.out Tue Oct 28 15:53:05 2014 *************** *** 1,647 **** ! -- ! -- CONSTRAINTS ! -- Constraints can be specified with: ! -- - DEFAULT clause ! -- - CHECK clauses ! -- - PRIMARY KEY clauses ! -- - UNIQUE clauses ! -- - EXCLUDE clauses ! -- ! -- ! -- DEFAULT syntax ! -- ! CREATE TABLE DEFAULT_TBL (i int DEFAULT 100, ! x text DEFAULT 'vadim', f float8 DEFAULT 123.456); ! INSERT INTO DEFAULT_TBL VALUES (1, 'thomas', 57.0613); ! INSERT INTO DEFAULT_TBL VALUES (1, 'bruce'); ! INSERT INTO DEFAULT_TBL (i, f) VALUES (2, 987.654); ! INSERT INTO DEFAULT_TBL (x) VALUES ('marc'); ! INSERT INTO DEFAULT_TBL VALUES (3, null, 1.0); ! SELECT '' AS five, * FROM DEFAULT_TBL; ! five | i | x | f ! ------+-----+--------+--------- ! | 1 | thomas | 57.0613 ! | 1 | bruce | 123.456 ! | 2 | vadim | 987.654 ! | 100 | marc | 123.456 ! | 3 | | 1 ! (5 rows) ! ! CREATE SEQUENCE DEFAULT_SEQ; ! CREATE TABLE DEFAULTEXPR_TBL (i1 int DEFAULT 100 + (200-199) * 2, ! i2 int DEFAULT nextval('default_seq')); ! INSERT INTO DEFAULTEXPR_TBL VALUES (-1, -2); ! INSERT INTO DEFAULTEXPR_TBL (i1) VALUES (-3); ! INSERT INTO DEFAULTEXPR_TBL (i2) VALUES (-4); ! INSERT INTO DEFAULTEXPR_TBL (i2) VALUES (NULL); ! SELECT '' AS four, * FROM DEFAULTEXPR_TBL; ! four | i1 | i2 ! ------+-----+---- ! | -1 | -2 ! | -3 | 1 ! | 102 | -4 ! | 102 | ! (4 rows) ! ! -- syntax errors ! -- test for extraneous comma ! CREATE TABLE error_tbl (i int DEFAULT (100, )); ! ERROR: syntax error at or near ")" ! LINE 1: CREATE TABLE error_tbl (i int DEFAULT (100, )); ! ^ ! -- this will fail because gram.y uses b_expr not a_expr for defaults, ! -- to avoid a shift/reduce conflict that arises from NOT NULL being ! -- part of the column definition syntax: ! CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2)); ! ERROR: syntax error at or near "IN" ! LINE 1: CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2)); ! ^ ! -- this should work, however: ! CREATE TABLE error_tbl (b1 bool DEFAULT (1 IN (1, 2))); ! DROP TABLE error_tbl; ! -- ! -- CHECK syntax ! -- ! CREATE TABLE CHECK_TBL (x int, ! CONSTRAINT CHECK_CON CHECK (x > 3)); ! INSERT INTO CHECK_TBL VALUES (5); ! INSERT INTO CHECK_TBL VALUES (4); ! INSERT INTO CHECK_TBL VALUES (3); ! ERROR: new row for relation "check_tbl" violates check constraint "check_con" ! DETAIL: Failing row contains (3). ! INSERT INTO CHECK_TBL VALUES (2); ! ERROR: new row for relation "check_tbl" violates check constraint "check_con" ! DETAIL: Failing row contains (2). ! INSERT INTO CHECK_TBL VALUES (6); ! INSERT INTO CHECK_TBL VALUES (1); ! ERROR: new row for relation "check_tbl" violates check constraint "check_con" ! DETAIL: Failing row contains (1). ! SELECT '' AS three, * FROM CHECK_TBL; ! three | x ! -------+--- ! | 5 ! | 4 ! | 6 ! (3 rows) ! ! CREATE SEQUENCE CHECK_SEQ; ! CREATE TABLE CHECK2_TBL (x int, y text, z int, ! CONSTRAINT SEQUENCE_CON ! CHECK (x > 3 and y <> 'check failed' and z < 8)); ! INSERT INTO CHECK2_TBL VALUES (4, 'check ok', -2); ! INSERT INTO CHECK2_TBL VALUES (1, 'x check failed', -2); ! ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con" ! DETAIL: Failing row contains (1, x check failed, -2). ! INSERT INTO CHECK2_TBL VALUES (5, 'z check failed', 10); ! ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con" ! DETAIL: Failing row contains (5, z check failed, 10). ! INSERT INTO CHECK2_TBL VALUES (0, 'check failed', -2); ! ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con" ! DETAIL: Failing row contains (0, check failed, -2). ! INSERT INTO CHECK2_TBL VALUES (6, 'check failed', 11); ! ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con" ! DETAIL: Failing row contains (6, check failed, 11). ! INSERT INTO CHECK2_TBL VALUES (7, 'check ok', 7); ! SELECT '' AS two, * from CHECK2_TBL; ! two | x | y | z ! -----+---+----------+---- ! | 4 | check ok | -2 ! | 7 | check ok | 7 ! (2 rows) ! ! -- ! -- Check constraints on INSERT ! -- ! CREATE SEQUENCE INSERT_SEQ; ! CREATE TABLE INSERT_TBL (x INT DEFAULT nextval('insert_seq'), ! y TEXT DEFAULT '-NULL-', ! z INT DEFAULT -1 * currval('insert_seq'), ! CONSTRAINT INSERT_CON CHECK (x >= 3 AND y <> 'check failed' AND x < 8), ! CHECK (x + z = 0)); ! INSERT INTO INSERT_TBL(x,z) VALUES (2, -2); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (2, -NULL-, -2). ! SELECT '' AS zero, * FROM INSERT_TBL; ! zero | x | y | z ! ------+---+---+--- ! (0 rows) ! ! SELECT 'one' AS one, nextval('insert_seq'); ! one | nextval ! -----+--------- ! one | 1 ! (1 row) ! ! INSERT INTO INSERT_TBL(y) VALUES ('Y'); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (2, Y, -2). ! INSERT INTO INSERT_TBL(y) VALUES ('Y'); ! INSERT INTO INSERT_TBL(x,z) VALUES (1, -2); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check" ! DETAIL: Failing row contains (1, -NULL-, -2). ! INSERT INTO INSERT_TBL(z,x) VALUES (-7, 7); ! INSERT INTO INSERT_TBL VALUES (5, 'check failed', -5); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (5, check failed, -5). ! INSERT INTO INSERT_TBL VALUES (7, '!check failed', -7); ! INSERT INTO INSERT_TBL(y) VALUES ('-!NULL-'); ! SELECT '' AS four, * FROM INSERT_TBL; ! four | x | y | z ! ------+---+---------------+---- ! | 3 | Y | -3 ! | 7 | -NULL- | -7 ! | 7 | !check failed | -7 ! | 4 | -!NULL- | -4 ! (4 rows) ! ! INSERT INTO INSERT_TBL(y,z) VALUES ('check failed', 4); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check" ! DETAIL: Failing row contains (5, check failed, 4). ! INSERT INTO INSERT_TBL(x,y) VALUES (5, 'check failed'); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (5, check failed, -5). ! INSERT INTO INSERT_TBL(x,y) VALUES (5, '!check failed'); ! INSERT INTO INSERT_TBL(y) VALUES ('-!NULL-'); ! SELECT '' AS six, * FROM INSERT_TBL; ! six | x | y | z ! -----+---+---------------+---- ! | 3 | Y | -3 ! | 7 | -NULL- | -7 ! | 7 | !check failed | -7 ! | 4 | -!NULL- | -4 ! | 5 | !check failed | -5 ! | 6 | -!NULL- | -6 ! (6 rows) ! ! SELECT 'seven' AS one, nextval('insert_seq'); ! one | nextval ! -------+--------- ! seven | 7 ! (1 row) ! ! INSERT INTO INSERT_TBL(y) VALUES ('Y'); ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (8, Y, -8). ! SELECT 'eight' AS one, currval('insert_seq'); ! one | currval ! -------+--------- ! eight | 8 ! (1 row) ! ! -- According to SQL, it is OK to insert a record that gives rise to NULL ! -- constraint-condition results. Postgres used to reject this, but it ! -- was wrong: ! INSERT INTO INSERT_TBL VALUES (null, null, null); ! SELECT '' AS nine, * FROM INSERT_TBL; ! nine | x | y | z ! ------+---+---------------+---- ! | 3 | Y | -3 ! | 7 | -NULL- | -7 ! | 7 | !check failed | -7 ! | 4 | -!NULL- | -4 ! | 5 | !check failed | -5 ! | 6 | -!NULL- | -6 ! | | | ! (7 rows) ! ! -- ! -- Check constraints on system columns ! -- ! CREATE TABLE SYS_COL_CHECK_TBL (city text, state text, is_capital bool, ! altitude int, ! CHECK (NOT (is_capital AND tableoid::regclass::text = 'sys_col_check_tbl'))); ! INSERT INTO SYS_COL_CHECK_TBL VALUES ('Seattle', 'Washington', false, 100); ! INSERT INTO SYS_COL_CHECK_TBL VALUES ('Olympia', 'Washington', true, 100); ! ERROR: new row for relation "sys_col_check_tbl" violates check constraint "sys_col_check_tbl_check" ! DETAIL: Failing row contains (Olympia, Washington, t, 100). ! SELECT *, tableoid::regclass::text FROM SYS_COL_CHECK_TBL; ! city | state | is_capital | altitude | tableoid ! ---------+------------+------------+----------+------------------- ! Seattle | Washington | f | 100 | sys_col_check_tbl ! (1 row) ! ! DROP TABLE SYS_COL_CHECK_TBL; ! -- ! -- Check constraints on system columns other then TableOid should return error ! -- ! CREATE TABLE SYS_COL_CHECK_TBL (city text, state text, is_capital bool, ! altitude int, ! CHECK (NOT (is_capital AND ctid::text = 'sys_col_check_tbl'))); ! ERROR: system column "ctid" reference in check constraint is invalid ! -- ! -- Check inheritance of defaults and constraints ! -- ! CREATE TABLE INSERT_CHILD (cx INT default 42, ! cy INT CHECK (cy > x)) ! INHERITS (INSERT_TBL); ! INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,11); ! INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,6); ! ERROR: new row for relation "insert_child" violates check constraint "insert_child_check" ! DETAIL: Failing row contains (7, -NULL-, -7, 42, 6). ! INSERT INTO INSERT_CHILD(x,z,cy) VALUES (6,-7,7); ! ERROR: new row for relation "insert_child" violates check constraint "insert_tbl_check" ! DETAIL: Failing row contains (6, -NULL-, -7, 42, 7). ! INSERT INTO INSERT_CHILD(x,y,z,cy) VALUES (6,'check failed',-6,7); ! ERROR: new row for relation "insert_child" violates check constraint "insert_con" ! DETAIL: Failing row contains (6, check failed, -6, 42, 7). ! SELECT * FROM INSERT_CHILD; ! x | y | z | cx | cy ! ---+--------+----+----+---- ! 7 | -NULL- | -7 | 42 | 11 ! (1 row) ! ! DROP TABLE INSERT_CHILD; ! -- ! -- Check NO INHERIT type of constraints and inheritance ! -- ! CREATE TABLE ATACC1 (TEST INT ! CHECK (TEST > 0) NO INHERIT); ! CREATE TABLE ATACC2 (TEST2 INT) INHERITS (ATACC1); ! -- check constraint is not there on child ! INSERT INTO ATACC2 (TEST) VALUES (-3); ! -- check constraint is there on parent ! INSERT INTO ATACC1 (TEST) VALUES (-3); ! ERROR: new row for relation "atacc1" violates check constraint "atacc1_test_check" ! DETAIL: Failing row contains (-3). ! DROP TABLE ATACC1 CASCADE; ! NOTICE: drop cascades to table atacc2 ! CREATE TABLE ATACC1 (TEST INT, TEST2 INT ! CHECK (TEST > 0), CHECK (TEST2 > 10) NO INHERIT); ! CREATE TABLE ATACC2 () INHERITS (ATACC1); ! -- check constraint is there on child ! INSERT INTO ATACC2 (TEST) VALUES (-3); ! ERROR: new row for relation "atacc2" violates check constraint "atacc1_test_check" ! DETAIL: Failing row contains (-3, null). ! -- check constraint is there on parent ! INSERT INTO ATACC1 (TEST) VALUES (-3); ! ERROR: new row for relation "atacc1" violates check constraint "atacc1_test_check" ! DETAIL: Failing row contains (-3, null). ! -- check constraint is not there on child ! INSERT INTO ATACC2 (TEST2) VALUES (3); ! -- check constraint is there on parent ! INSERT INTO ATACC1 (TEST2) VALUES (3); ! ERROR: new row for relation "atacc1" violates check constraint "atacc1_test2_check" ! DETAIL: Failing row contains (null, 3). ! DROP TABLE ATACC1 CASCADE; ! NOTICE: drop cascades to table atacc2 ! -- ! -- Check constraints on INSERT INTO ! -- ! DELETE FROM INSERT_TBL; ! ALTER SEQUENCE INSERT_SEQ RESTART WITH 4; ! CREATE TABLE tmp (xd INT, yd TEXT, zd INT); ! INSERT INTO tmp VALUES (null, 'Y', null); ! INSERT INTO tmp VALUES (5, '!check failed', null); ! INSERT INTO tmp VALUES (null, 'try again', null); ! INSERT INTO INSERT_TBL(y) select yd from tmp; ! SELECT '' AS three, * FROM INSERT_TBL; ! three | x | y | z ! -------+---+---------------+---- ! | 4 | Y | -4 ! | 5 | !check failed | -5 ! | 6 | try again | -6 ! (3 rows) ! ! INSERT INTO INSERT_TBL SELECT * FROM tmp WHERE yd = 'try again'; ! INSERT INTO INSERT_TBL(y,z) SELECT yd, -7 FROM tmp WHERE yd = 'try again'; ! INSERT INTO INSERT_TBL(y,z) SELECT yd, -8 FROM tmp WHERE yd = 'try again'; ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (8, try again, -8). ! SELECT '' AS four, * FROM INSERT_TBL; ! four | x | y | z ! ------+---+---------------+---- ! | 4 | Y | -4 ! | 5 | !check failed | -5 ! | 6 | try again | -6 ! | | try again | ! | 7 | try again | -7 ! (5 rows) ! ! DROP TABLE tmp; ! -- ! -- Check constraints on UPDATE ! -- ! UPDATE INSERT_TBL SET x = NULL WHERE x = 5; ! UPDATE INSERT_TBL SET x = 6 WHERE x = 6; ! UPDATE INSERT_TBL SET x = -z, z = -x; ! UPDATE INSERT_TBL SET x = z, z = x; ! ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ! DETAIL: Failing row contains (-4, Y, 4). ! SELECT * FROM INSERT_TBL; ! x | y | z ! ---+---------------+---- ! 4 | Y | -4 ! | try again | ! 7 | try again | -7 ! 5 | !check failed | ! 6 | try again | -6 ! (5 rows) ! ! -- DROP TABLE INSERT_TBL; ! -- ! -- Check constraints on COPY FROM ! -- ! CREATE TABLE COPY_TBL (x INT, y TEXT, z INT, ! CONSTRAINT COPY_CON ! CHECK (x > 3 AND y <> 'check failed' AND x < 7 )); ! COPY COPY_TBL FROM '/Users/decibel/pgsql/HEAD/src/test/regress/data/constro.data'; ! SELECT '' AS two, * FROM COPY_TBL; ! two | x | y | z ! -----+---+---------------+--- ! | 4 | !check failed | 5 ! | 6 | OK | 4 ! (2 rows) ! ! COPY COPY_TBL FROM '/Users/decibel/pgsql/HEAD/src/test/regress/data/constrf.data'; ! ERROR: new row for relation "copy_tbl" violates check constraint "copy_con" ! DETAIL: Failing row contains (7, check failed, 6). ! CONTEXT: COPY copy_tbl, line 2: "7 check failed 6" ! SELECT * FROM COPY_TBL; ! x | y | z ! ---+---------------+--- ! 4 | !check failed | 5 ! 6 | OK | 4 ! (2 rows) ! ! -- ! -- Primary keys ! -- ! CREATE TABLE PRIMARY_TBL (i int PRIMARY KEY, t text); ! INSERT INTO PRIMARY_TBL VALUES (1, 'one'); ! INSERT INTO PRIMARY_TBL VALUES (2, 'two'); ! INSERT INTO PRIMARY_TBL VALUES (1, 'three'); ! ERROR: duplicate key value violates unique constraint "primary_tbl_pkey" ! DETAIL: Key (i)=(1) already exists. ! INSERT INTO PRIMARY_TBL VALUES (4, 'three'); ! INSERT INTO PRIMARY_TBL VALUES (5, 'one'); ! INSERT INTO PRIMARY_TBL (t) VALUES ('six'); ! ERROR: null value in column "i" violates not-null constraint ! DETAIL: Failing row contains (null, six). ! SELECT '' AS four, * FROM PRIMARY_TBL; ! four | i | t ! ------+---+------- ! | 1 | one ! | 2 | two ! | 4 | three ! | 5 | one ! (4 rows) ! ! DROP TABLE PRIMARY_TBL; ! CREATE TABLE PRIMARY_TBL (i int, t text, ! PRIMARY KEY(i,t)); ! INSERT INTO PRIMARY_TBL VALUES (1, 'one'); ! INSERT INTO PRIMARY_TBL VALUES (2, 'two'); ! INSERT INTO PRIMARY_TBL VALUES (1, 'three'); ! INSERT INTO PRIMARY_TBL VALUES (4, 'three'); ! INSERT INTO PRIMARY_TBL VALUES (5, 'one'); ! INSERT INTO PRIMARY_TBL (t) VALUES ('six'); ! ERROR: null value in column "i" violates not-null constraint ! DETAIL: Failing row contains (null, six). ! SELECT '' AS three, * FROM PRIMARY_TBL; ! three | i | t ! -------+---+------- ! | 1 | one ! | 2 | two ! | 1 | three ! | 4 | three ! | 5 | one ! (5 rows) ! ! DROP TABLE PRIMARY_TBL; ! -- ! -- Unique keys ! -- ! CREATE TABLE UNIQUE_TBL (i int UNIQUE, t text); ! INSERT INTO UNIQUE_TBL VALUES (1, 'one'); ! INSERT INTO UNIQUE_TBL VALUES (2, 'two'); ! INSERT INTO UNIQUE_TBL VALUES (1, 'three'); ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(1) already exists. ! INSERT INTO UNIQUE_TBL VALUES (4, 'four'); ! INSERT INTO UNIQUE_TBL VALUES (5, 'one'); ! INSERT INTO UNIQUE_TBL (t) VALUES ('six'); ! INSERT INTO UNIQUE_TBL (t) VALUES ('seven'); ! SELECT '' AS five, * FROM UNIQUE_TBL; ! five | i | t ! ------+---+------- ! | 1 | one ! | 2 | two ! | 4 | four ! | 5 | one ! | | six ! | | seven ! (6 rows) ! ! DROP TABLE UNIQUE_TBL; ! CREATE TABLE UNIQUE_TBL (i int, t text, ! UNIQUE(i,t)); ! INSERT INTO UNIQUE_TBL VALUES (1, 'one'); ! INSERT INTO UNIQUE_TBL VALUES (2, 'two'); ! INSERT INTO UNIQUE_TBL VALUES (1, 'three'); ! INSERT INTO UNIQUE_TBL VALUES (1, 'one'); ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_t_key" ! DETAIL: Key (i, t)=(1, one) already exists. ! INSERT INTO UNIQUE_TBL VALUES (5, 'one'); ! INSERT INTO UNIQUE_TBL (t) VALUES ('six'); ! SELECT '' AS five, * FROM UNIQUE_TBL; ! five | i | t ! ------+---+------- ! | 1 | one ! | 2 | two ! | 1 | three ! | 5 | one ! | | six ! (5 rows) ! ! DROP TABLE UNIQUE_TBL; ! -- ! -- Deferrable unique constraints ! -- ! CREATE TABLE unique_tbl (i int UNIQUE DEFERRABLE, t text); ! INSERT INTO unique_tbl VALUES (0, 'one'); ! INSERT INTO unique_tbl VALUES (1, 'two'); ! INSERT INTO unique_tbl VALUES (2, 'tree'); ! INSERT INTO unique_tbl VALUES (3, 'four'); ! INSERT INTO unique_tbl VALUES (4, 'five'); ! BEGIN; ! -- default is immediate so this should fail right away ! UPDATE unique_tbl SET i = 1 WHERE i = 0; ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(1) already exists. ! ROLLBACK; ! -- check is done at end of statement, so this should succeed ! UPDATE unique_tbl SET i = i+1; ! SELECT * FROM unique_tbl; ! i | t ! ---+------ ! 1 | one ! 2 | two ! 3 | tree ! 4 | four ! 5 | five ! (5 rows) ! ! -- explicitly defer the constraint ! BEGIN; ! SET CONSTRAINTS unique_tbl_i_key DEFERRED; ! INSERT INTO unique_tbl VALUES (3, 'three'); ! DELETE FROM unique_tbl WHERE t = 'tree'; -- makes constraint valid again ! COMMIT; -- should succeed ! SELECT * FROM unique_tbl; ! i | t ! ---+------- ! 1 | one ! 2 | two ! 4 | four ! 5 | five ! 3 | three ! (5 rows) ! ! -- try adding an initially deferred constraint ! ALTER TABLE unique_tbl DROP CONSTRAINT unique_tbl_i_key; ! ALTER TABLE unique_tbl ADD CONSTRAINT unique_tbl_i_key ! UNIQUE (i) DEFERRABLE INITIALLY DEFERRED; ! BEGIN; ! INSERT INTO unique_tbl VALUES (1, 'five'); ! INSERT INTO unique_tbl VALUES (5, 'one'); ! UPDATE unique_tbl SET i = 4 WHERE i = 2; ! UPDATE unique_tbl SET i = 2 WHERE i = 4 AND t = 'four'; ! DELETE FROM unique_tbl WHERE i = 1 AND t = 'one'; ! DELETE FROM unique_tbl WHERE i = 5 AND t = 'five'; ! COMMIT; ! SELECT * FROM unique_tbl; ! i | t ! ---+------- ! 3 | three ! 1 | five ! 5 | one ! 4 | two ! 2 | four ! (5 rows) ! ! -- should fail at commit-time ! BEGIN; ! INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now ! COMMIT; -- should fail ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(3) already exists. ! -- make constraint check immediate ! BEGIN; ! SET CONSTRAINTS ALL IMMEDIATE; ! INSERT INTO unique_tbl VALUES (3, 'Three'); -- should fail ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(3) already exists. ! COMMIT; ! -- forced check when SET CONSTRAINTS is called ! BEGIN; ! SET CONSTRAINTS ALL DEFERRED; ! INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now ! SET CONSTRAINTS ALL IMMEDIATE; -- should fail ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(3) already exists. ! COMMIT; ! -- test a HOT update that invalidates the conflicting tuple. ! -- the trigger should still fire and catch the violation ! BEGIN; ! INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now ! UPDATE unique_tbl SET t = 'THREE' WHERE i = 3 AND t = 'Three'; ! COMMIT; -- should fail ! ERROR: duplicate key value violates unique constraint "unique_tbl_i_key" ! DETAIL: Key (i)=(3) already exists. ! SELECT * FROM unique_tbl; ! i | t ! ---+------- ! 3 | three ! 1 | five ! 5 | one ! 4 | two ! 2 | four ! (5 rows) ! ! -- test a HOT update that modifies the newly inserted tuple, ! -- but should succeed because we then remove the other conflicting tuple. ! BEGIN; ! INSERT INTO unique_tbl VALUES(3, 'tree'); -- should succeed for now ! UPDATE unique_tbl SET t = 'threex' WHERE t = 'tree'; ! DELETE FROM unique_tbl WHERE t = 'three'; ! SELECT * FROM unique_tbl; ! i | t ! ---+-------- ! 1 | five ! 5 | one ! 4 | two ! 2 | four ! 3 | threex ! (5 rows) ! ! COMMIT; ! SELECT * FROM unique_tbl; ! i | t ! ---+-------- ! 1 | five ! 5 | one ! 4 | two ! 2 | four ! 3 | threex ! (5 rows) ! ! DROP TABLE unique_tbl; ! -- ! -- EXCLUDE constraints ! -- ! CREATE TABLE circles ( ! c1 CIRCLE, ! c2 TEXT, ! EXCLUDE USING gist ! (c1 WITH &&, (c2::circle) WITH &&) ! WHERE (circle_center(c1) <> '(0,0)') ! ); ! -- these should succeed because they don't match the index predicate ! INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>'); ! INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 4>'); ! -- succeed ! INSERT INTO circles VALUES('<(10,10), 10>', '<(0,0), 5>'); ! -- fail, overlaps ! INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 4>'); ! ERROR: conflicting key value violates exclusion constraint "circles_c1_c2_excl" ! DETAIL: Key (c1, (c2::circle))=(<(20,20),10>, <(0,0),4>) conflicts with existing key (c1, (c2::circle))=(<(10,10),10>, <(0,0),5>). ! -- succeed because c1 doesn't overlap ! INSERT INTO circles VALUES('<(20,20), 1>', '<(0,0), 5>'); ! -- succeed because c2 doesn't overlap ! INSERT INTO circles VALUES('<(20,20), 10>', '<(10,10), 5>'); ! -- should fail on existing data without the WHERE clause ! ALTER TABLE circles ADD EXCLUDE USING gist ! (c1 WITH &&, (c2::circle) WITH &&); ! ERROR: could not create exclusion constraint "circles_c1_c2_excl1" ! DETAIL: Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),4>). ! -- try reindexing an existing constraint ! REINDEX INDEX circles_c1_c2_excl; ! DROP TABLE circles; ! -- Check deferred exclusion constraint ! CREATE TABLE deferred_excl ( ! f1 int, ! CONSTRAINT deferred_excl_con EXCLUDE (f1 WITH =) INITIALLY DEFERRED ! ); ! INSERT INTO deferred_excl VALUES(1); ! INSERT INTO deferred_excl VALUES(2); ! INSERT INTO deferred_excl VALUES(1); -- fail ! ERROR: conflicting key value violates exclusion constraint "deferred_excl_con" ! DETAIL: Key (f1)=(1) conflicts with existing key (f1)=(1). ! BEGIN; ! INSERT INTO deferred_excl VALUES(2); -- no fail here ! COMMIT; -- should fail here ! ERROR: conflicting key value violates exclusion constraint "deferred_excl_con" ! DETAIL: Key (f1)=(2) conflicts with existing key (f1)=(2). ! BEGIN; ! INSERT INTO deferred_excl VALUES(3); ! INSERT INTO deferred_excl VALUES(3); -- no fail here ! COMMIT; -- should fail here ! ERROR: conflicting key value violates exclusion constraint "deferred_excl_con" ! DETAIL: Key (f1)=(3) conflicts with existing key (f1)=(3). ! ALTER TABLE deferred_excl DROP CONSTRAINT deferred_excl_con; ! -- This should fail, but worth testing because of HOT updates ! UPDATE deferred_excl SET f1 = 3; ! ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =); ! ERROR: could not create exclusion constraint "deferred_excl_f1_excl" ! DETAIL: Key (f1)=(3) conflicts with key (f1)=(3). ! DROP TABLE deferred_excl; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/triggers.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/triggers.out Tue Oct 28 15:53:05 2014 *************** *** 1,1733 **** ! -- ! -- TRIGGERS ! -- ! create table pkeys (pkey1 int4 not null, pkey2 text not null); ! create table fkeys (fkey1 int4, fkey2 text, fkey3 int); ! create table fkeys2 (fkey21 int4, fkey22 text, pkey23 int not null); ! create index fkeys_i on fkeys (fkey1, fkey2); ! create index fkeys2_i on fkeys2 (fkey21, fkey22); ! create index fkeys2p_i on fkeys2 (pkey23); ! insert into pkeys values (10, '1'); ! insert into pkeys values (20, '2'); ! insert into pkeys values (30, '3'); ! insert into pkeys values (40, '4'); ! insert into pkeys values (50, '5'); ! insert into pkeys values (60, '6'); ! create unique index pkeys_i on pkeys (pkey1, pkey2); ! -- ! -- For fkeys: ! -- (fkey1, fkey2) --> pkeys (pkey1, pkey2) ! -- (fkey3) --> fkeys2 (pkey23) ! -- ! create trigger check_fkeys_pkey_exist ! before insert or update on fkeys ! for each row ! execute procedure ! check_primary_key ('fkey1', 'fkey2', 'pkeys', 'pkey1', 'pkey2'); ! create trigger check_fkeys_pkey2_exist ! before insert or update on fkeys ! for each row ! execute procedure check_primary_key ('fkey3', 'fkeys2', 'pkey23'); ! -- ! -- For fkeys2: ! -- (fkey21, fkey22) --> pkeys (pkey1, pkey2) ! -- ! create trigger check_fkeys2_pkey_exist ! before insert or update on fkeys2 ! for each row ! execute procedure ! check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2'); ! -- Test comments ! COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong'; ! ERROR: trigger "check_fkeys2_pkey_bad" for table "fkeys2" does not exist ! COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS 'right'; ! COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS NULL; ! -- ! -- For pkeys: ! -- ON DELETE/UPDATE (pkey1, pkey2) CASCADE: ! -- fkeys (fkey1, fkey2) and fkeys2 (fkey21, fkey22) ! -- ! create trigger check_pkeys_fkey_cascade ! before delete or update on pkeys ! for each row ! execute procedure ! check_foreign_key (2, 'cascade', 'pkey1', 'pkey2', ! 'fkeys', 'fkey1', 'fkey2', 'fkeys2', 'fkey21', 'fkey22'); ! -- ! -- For fkeys2: ! -- ON DELETE/UPDATE (pkey23) RESTRICT: ! -- fkeys (fkey3) ! -- ! create trigger check_fkeys2_fkey_restrict ! before delete or update on fkeys2 ! for each row ! execute procedure check_foreign_key (1, 'restrict', 'pkey23', 'fkeys', 'fkey3'); ! insert into fkeys2 values (10, '1', 1); ! insert into fkeys2 values (30, '3', 2); ! insert into fkeys2 values (40, '4', 5); ! insert into fkeys2 values (50, '5', 3); ! -- no key in pkeys ! insert into fkeys2 values (70, '5', 3); ! ERROR: tuple references non-existent key ! DETAIL: Trigger "check_fkeys2_pkey_exist" found tuple referencing non-existent key in "pkeys". ! insert into fkeys values (10, '1', 2); ! insert into fkeys values (30, '3', 3); ! insert into fkeys values (40, '4', 2); ! insert into fkeys values (50, '5', 2); ! -- no key in pkeys ! insert into fkeys values (70, '5', 1); ! ERROR: tuple references non-existent key ! DETAIL: Trigger "check_fkeys_pkey_exist" found tuple referencing non-existent key in "pkeys". ! -- no key in fkeys2 ! insert into fkeys values (60, '6', 4); ! ERROR: tuple references non-existent key ! DETAIL: Trigger "check_fkeys_pkey2_exist" found tuple referencing non-existent key in "fkeys2". ! delete from pkeys where pkey1 = 30 and pkey2 = '3'; ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted ! ERROR: "check_fkeys2_fkey_restrict": tuple is referenced in "fkeys" ! CONTEXT: SQL statement "delete from fkeys2 where fkey21 = $1 and fkey22 = $2 " ! delete from pkeys where pkey1 = 40 and pkey2 = '4'; ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are deleted ! update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 50 and pkey2 = '5'; ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted ! ERROR: "check_fkeys2_fkey_restrict": tuple is referenced in "fkeys" ! CONTEXT: SQL statement "delete from fkeys2 where fkey21 = $1 and fkey22 = $2 " ! update pkeys set pkey1 = 7, pkey2 = '70' where pkey1 = 10 and pkey2 = '1'; ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys are deleted ! NOTICE: check_pkeys_fkey_cascade: 1 tuple(s) of fkeys2 are deleted ! DROP TABLE pkeys; ! DROP TABLE fkeys; ! DROP TABLE fkeys2; ! -- -- I've disabled the funny_dup17 test because the new semantics ! -- -- of AFTER ROW triggers, which get now fired at the end of a ! -- -- query always, cause funny_dup17 to enter an endless loop. ! -- -- ! -- -- Jan ! -- ! -- create table dup17 (x int4); ! -- ! -- create trigger dup17_before ! -- before insert on dup17 ! -- for each row ! -- execute procedure ! -- funny_dup17 () ! -- ; ! -- ! -- insert into dup17 values (17); ! -- select count(*) from dup17; ! -- insert into dup17 values (17); ! -- select count(*) from dup17; ! -- ! -- drop trigger dup17_before on dup17; ! -- ! -- create trigger dup17_after ! -- after insert on dup17 ! -- for each row ! -- execute procedure ! -- funny_dup17 () ! -- ; ! -- insert into dup17 values (13); ! -- select count(*) from dup17 where x = 13; ! -- insert into dup17 values (13); ! -- select count(*) from dup17 where x = 13; ! -- ! -- DROP TABLE dup17; ! create sequence ttdummy_seq increment 10 start 0 minvalue 0; ! create table tttest ( ! price_id int4, ! price_val int4, ! price_on int4, ! price_off int4 default 999999 ! ); ! create trigger ttdummy ! before delete or update on tttest ! for each row ! execute procedure ! ttdummy (price_on, price_off); ! create trigger ttserial ! before insert or update on tttest ! for each row ! execute procedure ! autoinc (price_on, ttdummy_seq); ! insert into tttest values (1, 1, null); ! insert into tttest values (2, 2, null); ! insert into tttest values (3, 3, 0); ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 2 | 2 | 20 | 999999 ! 3 | 3 | 30 | 999999 ! (3 rows) ! ! delete from tttest where price_id = 2; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 3 | 3 | 30 | 999999 ! 2 | 2 | 20 | 40 ! (3 rows) ! ! -- what do we see ? ! -- get current prices ! select * from tttest where price_off = 999999; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 3 | 3 | 30 | 999999 ! (2 rows) ! ! -- change price for price_id == 3 ! update tttest set price_val = 30 where price_id = 3; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 2 | 2 | 20 | 40 ! 3 | 30 | 50 | 999999 ! 3 | 3 | 30 | 50 ! (4 rows) ! ! -- now we want to change pric_id in ALL tuples ! -- this gets us not what we need ! update tttest set price_id = 5 where price_id = 3; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 2 | 2 | 20 | 40 ! 3 | 3 | 30 | 50 ! 5 | 30 | 60 | 999999 ! 3 | 30 | 50 | 60 ! (5 rows) ! ! -- restore data as before last update: ! select set_ttdummy(0); ! set_ttdummy ! ------------- ! 1 ! (1 row) ! ! delete from tttest where price_id = 5; ! update tttest set price_off = 999999 where price_val = 30; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 2 | 2 | 20 | 40 ! 3 | 3 | 30 | 50 ! 3 | 30 | 50 | 999999 ! (4 rows) ! ! -- and try change price_id now! ! update tttest set price_id = 5 where price_id = 3; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 1 | 1 | 10 | 999999 ! 2 | 2 | 20 | 40 ! 5 | 3 | 30 | 50 ! 5 | 30 | 50 | 999999 ! (4 rows) ! ! -- isn't it what we need ? ! select set_ttdummy(1); ! set_ttdummy ! ------------- ! 0 ! (1 row) ! ! -- we want to correct some "date" ! update tttest set price_on = -1 where price_id = 1; ! ERROR: ttdummy (tttest): you cannot change price_on and/or price_off columns (use set_ttdummy) ! -- but this doesn't work ! -- try in this way ! select set_ttdummy(0); ! set_ttdummy ! ------------- ! 1 ! (1 row) ! ! update tttest set price_on = -1 where price_id = 1; ! select * from tttest; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 2 | 2 | 20 | 40 ! 5 | 3 | 30 | 50 ! 5 | 30 | 50 | 999999 ! 1 | 1 | -1 | 999999 ! (4 rows) ! ! -- isn't it what we need ? ! -- get price for price_id == 5 as it was @ "date" 35 ! select * from tttest where price_on <= 35 and price_off > 35 and price_id = 5; ! price_id | price_val | price_on | price_off ! ----------+-----------+----------+----------- ! 5 | 3 | 30 | 50 ! (1 row) ! ! drop table tttest; ! drop sequence ttdummy_seq; ! -- ! -- tests for per-statement triggers ! -- ! CREATE TABLE log_table (tstamp timestamp default timeofday()::timestamp); ! CREATE TABLE main_table (a int, b int); ! COPY main_table (a,b) FROM stdin; ! CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS ' ! BEGIN ! RAISE NOTICE ''trigger_func(%) called: action = %, when = %, level = %'', TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL; ! RETURN NULL; ! END;'; ! CREATE TRIGGER before_ins_stmt_trig BEFORE INSERT ON main_table ! FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('before_ins_stmt'); ! CREATE TRIGGER after_ins_stmt_trig AFTER INSERT ON main_table ! FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('after_ins_stmt'); ! -- ! -- if neither 'FOR EACH ROW' nor 'FOR EACH STATEMENT' was specified, ! -- CREATE TRIGGER should default to 'FOR EACH STATEMENT' ! -- ! CREATE TRIGGER after_upd_stmt_trig AFTER UPDATE ON main_table ! EXECUTE PROCEDURE trigger_func('after_upd_stmt'); ! CREATE TRIGGER after_upd_row_trig AFTER UPDATE ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_row'); ! INSERT INTO main_table DEFAULT VALUES; ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! UPDATE main_table SET a = a + 1 WHERE b < 30; ! NOTICE: trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! -- UPDATE that effects zero rows should still call per-statement trigger ! UPDATE main_table SET a = a + 2 WHERE b > 100; ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! -- COPY should fire per-row and per-statement INSERT triggers ! COPY main_table (a, b) FROM stdin; ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! SELECT * FROM main_table ORDER BY a, b; ! a | b ! ----+---- ! 6 | 10 ! 21 | 20 ! 30 | 40 ! 31 | 10 ! 50 | 35 ! 50 | 60 ! 81 | 15 ! | ! (8 rows) ! ! -- ! -- test triggers with WHEN clause ! -- ! CREATE TRIGGER modified_a BEFORE UPDATE OF a ON main_table ! FOR EACH ROW WHEN (OLD.a <> NEW.a) EXECUTE PROCEDURE trigger_func('modified_a'); ! CREATE TRIGGER modified_any BEFORE UPDATE OF a ON main_table ! FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.*) EXECUTE PROCEDURE trigger_func('modified_any'); ! CREATE TRIGGER insert_a AFTER INSERT ON main_table ! FOR EACH ROW WHEN (NEW.a = 123) EXECUTE PROCEDURE trigger_func('insert_a'); ! CREATE TRIGGER delete_a AFTER DELETE ON main_table ! FOR EACH ROW WHEN (OLD.a = 123) EXECUTE PROCEDURE trigger_func('delete_a'); ! CREATE TRIGGER insert_when BEFORE INSERT ON main_table ! FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('insert_when'); ! CREATE TRIGGER delete_when AFTER DELETE ON main_table ! FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('delete_when'); ! INSERT INTO main_table (a) VALUES (123), (456); ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! COPY main_table FROM stdin; ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! DELETE FROM main_table WHERE a IN (123, 456); ! NOTICE: trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW ! NOTICE: trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW ! NOTICE: trigger_func(delete_when) called: action = DELETE, when = AFTER, level = STATEMENT ! UPDATE main_table SET a = 50, b = 60; ! NOTICE: trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! SELECT * FROM main_table ORDER BY a, b; ! a | b ! ----+---- ! 6 | 10 ! 21 | 20 ! 30 | 40 ! 31 | 10 ! 50 | 35 ! 50 | 60 ! 81 | 15 ! | ! (8 rows) ! ! SELECT pg_get_triggerdef(oid, true) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_a'; ! pg_get_triggerdef ! -------------------------------------------------------------------------------------------------------------------------------------------- ! CREATE TRIGGER modified_a BEFORE UPDATE OF a ON main_table FOR EACH ROW WHEN (old.a <> new.a) EXECUTE PROCEDURE trigger_func('modified_a') ! (1 row) ! ! SELECT pg_get_triggerdef(oid, false) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_a'; ! pg_get_triggerdef ! ---------------------------------------------------------------------------------------------------------------------------------------------- ! CREATE TRIGGER modified_a BEFORE UPDATE OF a ON main_table FOR EACH ROW WHEN ((old.a <> new.a)) EXECUTE PROCEDURE trigger_func('modified_a') ! (1 row) ! ! SELECT pg_get_triggerdef(oid, true) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'modified_any'; ! pg_get_triggerdef ! -------------------------------------------------------------------------------------------------------------------------------------------------------------- ! CREATE TRIGGER modified_any BEFORE UPDATE OF a ON main_table FOR EACH ROW WHEN (old.* IS DISTINCT FROM new.*) EXECUTE PROCEDURE trigger_func('modified_any') ! (1 row) ! ! DROP TRIGGER modified_a ON main_table; ! DROP TRIGGER modified_any ON main_table; ! DROP TRIGGER insert_a ON main_table; ! DROP TRIGGER delete_a ON main_table; ! DROP TRIGGER insert_when ON main_table; ! DROP TRIGGER delete_when ON main_table; ! -- Test column-level triggers ! DROP TRIGGER after_upd_row_trig ON main_table; ! CREATE TRIGGER before_upd_a_row_trig BEFORE UPDATE OF a ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_a_row'); ! CREATE TRIGGER after_upd_b_row_trig AFTER UPDATE OF b ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_b_row'); ! CREATE TRIGGER after_upd_a_b_row_trig AFTER UPDATE OF a, b ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_a_b_row'); ! CREATE TRIGGER before_upd_a_stmt_trig BEFORE UPDATE OF a ON main_table ! FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('before_upd_a_stmt'); ! CREATE TRIGGER after_upd_b_stmt_trig AFTER UPDATE OF b ON main_table ! FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func('after_upd_b_stmt'); ! SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regclass AND tgname = 'after_upd_a_b_row_trig'; ! pg_get_triggerdef ! ------------------------------------------------------------------------------------------------------------------------------------------- ! CREATE TRIGGER after_upd_a_b_row_trig AFTER UPDATE OF a, b ON main_table FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_a_b_row') ! (1 row) ! ! UPDATE main_table SET a = 50; ! NOTICE: trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! UPDATE main_table SET b = 10; ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! -- ! -- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN ! -- ! CREATE TABLE some_t (some_col boolean NOT NULL); ! CREATE FUNCTION dummy_update_func() RETURNS trigger AS $$ ! BEGIN ! RAISE NOTICE 'dummy_update_func(%) called: action = %, old = %, new = %', ! TG_ARGV[0], TG_OP, OLD, NEW; ! RETURN NEW; ! END; ! $$ LANGUAGE plpgsql; ! CREATE TRIGGER some_trig_before BEFORE UPDATE ON some_t FOR EACH ROW ! EXECUTE PROCEDURE dummy_update_func('before'); ! CREATE TRIGGER some_trig_aftera AFTER UPDATE ON some_t FOR EACH ROW ! WHEN (NOT OLD.some_col AND NEW.some_col) ! EXECUTE PROCEDURE dummy_update_func('aftera'); ! CREATE TRIGGER some_trig_afterb AFTER UPDATE ON some_t FOR EACH ROW ! WHEN (NOT NEW.some_col) ! EXECUTE PROCEDURE dummy_update_func('afterb'); ! INSERT INTO some_t VALUES (TRUE); ! UPDATE some_t SET some_col = TRUE; ! NOTICE: dummy_update_func(before) called: action = UPDATE, old = (t), new = (t) ! UPDATE some_t SET some_col = FALSE; ! NOTICE: dummy_update_func(before) called: action = UPDATE, old = (t), new = (f) ! NOTICE: dummy_update_func(afterb) called: action = UPDATE, old = (t), new = (f) ! UPDATE some_t SET some_col = TRUE; ! NOTICE: dummy_update_func(before) called: action = UPDATE, old = (f), new = (t) ! NOTICE: dummy_update_func(aftera) called: action = UPDATE, old = (f), new = (t) ! DROP TABLE some_t; ! -- bogus cases ! CREATE TRIGGER error_upd_and_col BEFORE UPDATE OR UPDATE OF a ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('error_upd_and_col'); ! ERROR: duplicate trigger events specified at or near "ON" ! LINE 1: ...ER error_upd_and_col BEFORE UPDATE OR UPDATE OF a ON main_ta... ! ^ ! CREATE TRIGGER error_upd_a_a BEFORE UPDATE OF a, a ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('error_upd_a_a'); ! ERROR: column "a" specified more than once ! CREATE TRIGGER error_ins_a BEFORE INSERT OF a ON main_table ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('error_ins_a'); ! ERROR: syntax error at or near "OF" ! LINE 1: CREATE TRIGGER error_ins_a BEFORE INSERT OF a ON main_table ! ^ ! CREATE TRIGGER error_ins_when BEFORE INSERT OR UPDATE ON main_table ! FOR EACH ROW WHEN (OLD.a <> NEW.a) ! EXECUTE PROCEDURE trigger_func('error_ins_old'); ! ERROR: INSERT trigger's WHEN condition cannot reference OLD values ! LINE 2: FOR EACH ROW WHEN (OLD.a <> NEW.a) ! ^ ! CREATE TRIGGER error_del_when BEFORE DELETE OR UPDATE ON main_table ! FOR EACH ROW WHEN (OLD.a <> NEW.a) ! EXECUTE PROCEDURE trigger_func('error_del_new'); ! ERROR: DELETE trigger's WHEN condition cannot reference NEW values ! LINE 2: FOR EACH ROW WHEN (OLD.a <> NEW.a) ! ^ ! CREATE TRIGGER error_del_when BEFORE INSERT OR UPDATE ON main_table ! FOR EACH ROW WHEN (NEW.tableoid <> 0) ! EXECUTE PROCEDURE trigger_func('error_when_sys_column'); ! ERROR: BEFORE trigger's WHEN condition cannot reference NEW system columns ! LINE 2: FOR EACH ROW WHEN (NEW.tableoid <> 0) ! ^ ! CREATE TRIGGER error_stmt_when BEFORE UPDATE OF a ON main_table ! FOR EACH STATEMENT WHEN (OLD.* IS DISTINCT FROM NEW.*) ! EXECUTE PROCEDURE trigger_func('error_stmt_when'); ! ERROR: statement trigger's WHEN condition cannot reference column values ! LINE 2: FOR EACH STATEMENT WHEN (OLD.* IS DISTINCT FROM NEW.*) ! ^ ! -- check dependency restrictions ! ALTER TABLE main_table DROP COLUMN b; ! ERROR: cannot drop table main_table column b because other objects depend on it ! DETAIL: trigger after_upd_b_row_trig on table main_table depends on table main_table column b ! trigger after_upd_a_b_row_trig on table main_table depends on table main_table column b ! trigger after_upd_b_stmt_trig on table main_table depends on table main_table column b ! HINT: Use DROP ... CASCADE to drop the dependent objects too. ! -- this should succeed, but we'll roll it back to keep the triggers around ! begin; ! DROP TRIGGER after_upd_a_b_row_trig ON main_table; ! DROP TRIGGER after_upd_b_row_trig ON main_table; ! DROP TRIGGER after_upd_b_stmt_trig ON main_table; ! ALTER TABLE main_table DROP COLUMN b; ! rollback; ! -- Test enable/disable triggers ! create table trigtest (i serial primary key); ! -- test that disabling RI triggers works ! create table trigtest2 (i int references trigtest(i) on delete cascade); ! create function trigtest() returns trigger as $$ ! begin ! raise notice '% % % %', TG_RELNAME, TG_OP, TG_WHEN, TG_LEVEL; ! return new; ! end;$$ language plpgsql; ! create trigger trigtest_b_row_tg before insert or update or delete on trigtest ! for each row execute procedure trigtest(); ! create trigger trigtest_a_row_tg after insert or update or delete on trigtest ! for each row execute procedure trigtest(); ! create trigger trigtest_b_stmt_tg before insert or update or delete on trigtest ! for each statement execute procedure trigtest(); ! create trigger trigtest_a_stmt_tg after insert or update or delete on trigtest ! for each statement execute procedure trigtest(); ! insert into trigtest default values; ! NOTICE: trigtest INSERT BEFORE STATEMENT ! NOTICE: trigtest INSERT BEFORE ROW ! NOTICE: trigtest INSERT AFTER ROW ! NOTICE: trigtest INSERT AFTER STATEMENT ! alter table trigtest disable trigger trigtest_b_row_tg; ! insert into trigtest default values; ! NOTICE: trigtest INSERT BEFORE STATEMENT ! NOTICE: trigtest INSERT AFTER ROW ! NOTICE: trigtest INSERT AFTER STATEMENT ! alter table trigtest disable trigger user; ! insert into trigtest default values; ! alter table trigtest enable trigger trigtest_a_stmt_tg; ! insert into trigtest default values; ! NOTICE: trigtest INSERT AFTER STATEMENT ! insert into trigtest2 values(1); ! insert into trigtest2 values(2); ! delete from trigtest where i=2; ! NOTICE: trigtest DELETE AFTER STATEMENT ! select * from trigtest2; ! i ! --- ! 1 ! (1 row) ! ! alter table trigtest disable trigger all; ! delete from trigtest where i=1; ! select * from trigtest2; ! i ! --- ! 1 ! (1 row) ! ! -- ensure we still insert, even when all triggers are disabled ! insert into trigtest default values; ! select * from trigtest; ! i ! --- ! 3 ! 4 ! 5 ! (3 rows) ! ! drop table trigtest2; ! drop table trigtest; ! -- dump trigger data ! CREATE TABLE trigger_test ( ! i int, ! v varchar ! ); ! CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger ! LANGUAGE plpgsql AS $$ ! ! declare ! ! argstr text; ! relid text; ! ! begin ! ! relid := TG_relid::regclass; ! ! -- plpgsql can't discover its trigger data in a hash like perl and python ! -- can, or by a sort of reflection like tcl can, ! -- so we have to hard code the names. ! raise NOTICE 'TG_NAME: %', TG_name; ! raise NOTICE 'TG_WHEN: %', TG_when; ! raise NOTICE 'TG_LEVEL: %', TG_level; ! raise NOTICE 'TG_OP: %', TG_op; ! raise NOTICE 'TG_RELID::regclass: %', relid; ! raise NOTICE 'TG_RELNAME: %', TG_relname; ! raise NOTICE 'TG_TABLE_NAME: %', TG_table_name; ! raise NOTICE 'TG_TABLE_SCHEMA: %', TG_table_schema; ! raise NOTICE 'TG_NARGS: %', TG_nargs; ! ! argstr := '['; ! for i in 0 .. TG_nargs - 1 loop ! if i > 0 then ! argstr := argstr || ', '; ! end if; ! argstr := argstr || TG_argv[i]; ! end loop; ! argstr := argstr || ']'; ! raise NOTICE 'TG_ARGV: %', argstr; ! ! if TG_OP != 'INSERT' then ! raise NOTICE 'OLD: %', OLD; ! end if; ! ! if TG_OP != 'DELETE' then ! raise NOTICE 'NEW: %', NEW; ! end if; ! ! if TG_OP = 'DELETE' then ! return OLD; ! else ! return NEW; ! end if; ! ! end; ! $$; ! CREATE TRIGGER show_trigger_data_trig ! BEFORE INSERT OR UPDATE OR DELETE ON trigger_test ! FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo'); ! insert into trigger_test values(1,'insert'); ! NOTICE: TG_NAME: show_trigger_data_trig ! NOTICE: TG_WHEN: BEFORE ! NOTICE: TG_LEVEL: ROW ! NOTICE: TG_OP: INSERT ! NOTICE: TG_RELID::regclass: trigger_test ! NOTICE: TG_RELNAME: trigger_test ! NOTICE: TG_TABLE_NAME: trigger_test ! NOTICE: TG_TABLE_SCHEMA: public ! NOTICE: TG_NARGS: 2 ! NOTICE: TG_ARGV: [23, skidoo] ! NOTICE: NEW: (1,insert) ! update trigger_test set v = 'update' where i = 1; ! NOTICE: TG_NAME: show_trigger_data_trig ! NOTICE: TG_WHEN: BEFORE ! NOTICE: TG_LEVEL: ROW ! NOTICE: TG_OP: UPDATE ! NOTICE: TG_RELID::regclass: trigger_test ! NOTICE: TG_RELNAME: trigger_test ! NOTICE: TG_TABLE_NAME: trigger_test ! NOTICE: TG_TABLE_SCHEMA: public ! NOTICE: TG_NARGS: 2 ! NOTICE: TG_ARGV: [23, skidoo] ! NOTICE: OLD: (1,insert) ! NOTICE: NEW: (1,update) ! delete from trigger_test; ! NOTICE: TG_NAME: show_trigger_data_trig ! NOTICE: TG_WHEN: BEFORE ! NOTICE: TG_LEVEL: ROW ! NOTICE: TG_OP: DELETE ! NOTICE: TG_RELID::regclass: trigger_test ! NOTICE: TG_RELNAME: trigger_test ! NOTICE: TG_TABLE_NAME: trigger_test ! NOTICE: TG_TABLE_SCHEMA: public ! NOTICE: TG_NARGS: 2 ! NOTICE: TG_ARGV: [23, skidoo] ! NOTICE: OLD: (1,update) ! DROP TRIGGER show_trigger_data_trig on trigger_test; ! DROP FUNCTION trigger_data(); ! DROP TABLE trigger_test; ! -- ! -- Test use of row comparisons on OLD/NEW ! -- ! CREATE TABLE trigger_test (f1 int, f2 text, f3 text); ! -- this is the obvious (and wrong...) way to compare rows ! CREATE FUNCTION mytrigger() RETURNS trigger LANGUAGE plpgsql as $$ ! begin ! if row(old.*) = row(new.*) then ! raise notice 'row % not changed', new.f1; ! else ! raise notice 'row % changed', new.f1; ! end if; ! return new; ! end$$; ! CREATE TRIGGER t ! BEFORE UPDATE ON trigger_test ! FOR EACH ROW EXECUTE PROCEDURE mytrigger(); ! INSERT INTO trigger_test VALUES(1, 'foo', 'bar'); ! INSERT INTO trigger_test VALUES(2, 'baz', 'quux'); ! UPDATE trigger_test SET f3 = 'bar'; ! NOTICE: row 1 not changed ! NOTICE: row 2 changed ! UPDATE trigger_test SET f3 = NULL; ! NOTICE: row 1 changed ! NOTICE: row 2 changed ! -- this demonstrates that the above isn't really working as desired: ! UPDATE trigger_test SET f3 = NULL; ! NOTICE: row 1 changed ! NOTICE: row 2 changed ! -- the right way when considering nulls is ! CREATE OR REPLACE FUNCTION mytrigger() RETURNS trigger LANGUAGE plpgsql as $$ ! begin ! if row(old.*) is distinct from row(new.*) then ! raise notice 'row % changed', new.f1; ! else ! raise notice 'row % not changed', new.f1; ! end if; ! return new; ! end$$; ! UPDATE trigger_test SET f3 = 'bar'; ! NOTICE: row 1 changed ! NOTICE: row 2 changed ! UPDATE trigger_test SET f3 = NULL; ! NOTICE: row 1 changed ! NOTICE: row 2 changed ! UPDATE trigger_test SET f3 = NULL; ! NOTICE: row 1 not changed ! NOTICE: row 2 not changed ! DROP TABLE trigger_test; ! DROP FUNCTION mytrigger(); ! -- Test snapshot management in serializable transactions involving triggers ! -- per bug report in 6bc73d4c0910042358k3d1adff3qa36f8df75198ecea@mail.gmail.com ! CREATE FUNCTION serializable_update_trig() RETURNS trigger LANGUAGE plpgsql AS ! $$ ! declare ! rec record; ! begin ! new.description = 'updated in trigger'; ! return new; ! end; ! $$; ! CREATE TABLE serializable_update_tab ( ! id int, ! filler text, ! description text ! ); ! CREATE TRIGGER serializable_update_trig BEFORE UPDATE ON serializable_update_tab ! FOR EACH ROW EXECUTE PROCEDURE serializable_update_trig(); ! INSERT INTO serializable_update_tab SELECT a, repeat('xyzxz', 100), 'new' ! FROM generate_series(1, 50) a; ! BEGIN; ! SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! UPDATE serializable_update_tab SET description = 'no no', id = 1 WHERE id = 1; ! COMMIT; ! SELECT description FROM serializable_update_tab WHERE id = 1; ! description ! -------------------- ! updated in trigger ! (1 row) ! ! DROP TABLE serializable_update_tab; ! -- minimal update trigger ! CREATE TABLE min_updates_test ( ! f1 text, ! f2 int, ! f3 int); ! CREATE TABLE min_updates_test_oids ( ! f1 text, ! f2 int, ! f3 int) WITH OIDS; ! INSERT INTO min_updates_test VALUES ('a',1,2),('b','2',null); ! INSERT INTO min_updates_test_oids VALUES ('a',1,2),('b','2',null); ! CREATE TRIGGER z_min_update ! BEFORE UPDATE ON min_updates_test ! FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); ! CREATE TRIGGER z_min_update ! BEFORE UPDATE ON min_updates_test_oids ! FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); ! \set QUIET false ! UPDATE min_updates_test SET f1 = f1; ! UPDATE 0 ! UPDATE min_updates_test SET f2 = f2 + 1; ! UPDATE 2 ! UPDATE min_updates_test SET f3 = 2 WHERE f3 is null; ! UPDATE 1 ! UPDATE min_updates_test_oids SET f1 = f1; ! UPDATE 0 ! UPDATE min_updates_test_oids SET f2 = f2 + 1; ! UPDATE 2 ! UPDATE min_updates_test_oids SET f3 = 2 WHERE f3 is null; ! UPDATE 1 ! \set QUIET true ! SELECT * FROM min_updates_test; ! f1 | f2 | f3 ! ----+----+---- ! a | 2 | 2 ! b | 3 | 2 ! (2 rows) ! ! SELECT * FROM min_updates_test_oids; ! f1 | f2 | f3 ! ----+----+---- ! a | 2 | 2 ! b | 3 | 2 ! (2 rows) ! ! DROP TABLE min_updates_test; ! DROP TABLE min_updates_test_oids; ! -- ! -- Test triggers on views ! -- ! CREATE VIEW main_view AS SELECT a, b FROM main_table; ! -- VIEW trigger function ! CREATE OR REPLACE FUNCTION view_trigger() RETURNS trigger ! LANGUAGE plpgsql AS $$ ! declare ! argstr text := ''; ! begin ! for i in 0 .. TG_nargs - 1 loop ! if i > 0 then ! argstr := argstr || ', '; ! end if; ! argstr := argstr || TG_argv[i]; ! end loop; ! ! raise notice '% % % % (%)', TG_RELNAME, TG_WHEN, TG_OP, TG_LEVEL, argstr; ! ! if TG_LEVEL = 'ROW' then ! if TG_OP = 'INSERT' then ! raise NOTICE 'NEW: %', NEW; ! INSERT INTO main_table VALUES (NEW.a, NEW.b); ! RETURN NEW; ! end if; ! ! if TG_OP = 'UPDATE' then ! raise NOTICE 'OLD: %, NEW: %', OLD, NEW; ! UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b; ! if NOT FOUND then RETURN NULL; end if; ! RETURN NEW; ! end if; ! ! if TG_OP = 'DELETE' then ! raise NOTICE 'OLD: %', OLD; ! DELETE FROM main_table WHERE a = OLD.a AND b = OLD.b; ! if NOT FOUND then RETURN NULL; end if; ! RETURN OLD; ! end if; ! end if; ! ! RETURN NULL; ! end; ! $$; ! -- Before row triggers aren't allowed on views ! CREATE TRIGGER invalid_trig BEFORE INSERT ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_ins_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! CREATE TRIGGER invalid_trig BEFORE UPDATE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! CREATE TRIGGER invalid_trig BEFORE DELETE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_del_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! -- After row triggers aren't allowed on views ! CREATE TRIGGER invalid_trig AFTER INSERT ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_ins_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! CREATE TRIGGER invalid_trig AFTER UPDATE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_upd_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! CREATE TRIGGER invalid_trig AFTER DELETE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE trigger_func('before_del_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have row-level BEFORE or AFTER triggers. ! -- Truncate triggers aren't allowed on views ! CREATE TRIGGER invalid_trig BEFORE TRUNCATE ON main_view ! EXECUTE PROCEDURE trigger_func('before_tru_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have TRUNCATE triggers. ! CREATE TRIGGER invalid_trig AFTER TRUNCATE ON main_view ! EXECUTE PROCEDURE trigger_func('before_tru_row'); ! ERROR: "main_view" is a view ! DETAIL: Views cannot have TRUNCATE triggers. ! -- INSTEAD OF triggers aren't allowed on tables ! CREATE TRIGGER invalid_trig INSTEAD OF INSERT ON main_table ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_ins'); ! ERROR: "main_table" is a table ! DETAIL: Tables cannot have INSTEAD OF triggers. ! CREATE TRIGGER invalid_trig INSTEAD OF UPDATE ON main_table ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd'); ! ERROR: "main_table" is a table ! DETAIL: Tables cannot have INSTEAD OF triggers. ! CREATE TRIGGER invalid_trig INSTEAD OF DELETE ON main_table ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_del'); ! ERROR: "main_table" is a table ! DETAIL: Tables cannot have INSTEAD OF triggers. ! -- Don't support WHEN clauses with INSTEAD OF triggers ! CREATE TRIGGER invalid_trig INSTEAD OF UPDATE ON main_view ! FOR EACH ROW WHEN (OLD.a <> NEW.a) EXECUTE PROCEDURE view_trigger('instead_of_upd'); ! ERROR: INSTEAD OF triggers cannot have WHEN conditions ! -- Don't support column-level INSTEAD OF triggers ! CREATE TRIGGER invalid_trig INSTEAD OF UPDATE OF a ON main_view ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd'); ! ERROR: INSTEAD OF triggers cannot have column lists ! -- Don't support statement-level INSTEAD OF triggers ! CREATE TRIGGER invalid_trig INSTEAD OF UPDATE ON main_view ! EXECUTE PROCEDURE view_trigger('instead_of_upd'); ! ERROR: INSTEAD OF triggers must be FOR EACH ROW ! -- Valid INSTEAD OF triggers ! CREATE TRIGGER instead_of_insert_trig INSTEAD OF INSERT ON main_view ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_ins'); ! CREATE TRIGGER instead_of_update_trig INSTEAD OF UPDATE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd'); ! CREATE TRIGGER instead_of_delete_trig INSTEAD OF DELETE ON main_view ! FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_del'); ! -- Valid BEFORE statement VIEW triggers ! CREATE TRIGGER before_ins_stmt_trig BEFORE INSERT ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt'); ! CREATE TRIGGER before_upd_stmt_trig BEFORE UPDATE ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt'); ! CREATE TRIGGER before_del_stmt_trig BEFORE DELETE ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt'); ! -- Valid AFTER statement VIEW triggers ! CREATE TRIGGER after_ins_stmt_trig AFTER INSERT ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt'); ! CREATE TRIGGER after_upd_stmt_trig AFTER UPDATE ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt'); ! CREATE TRIGGER after_del_stmt_trig AFTER DELETE ON main_view ! FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt'); ! \set QUIET false ! -- Insert into view using trigger ! INSERT INTO main_view VALUES (20, 30); ! NOTICE: main_view BEFORE INSERT STATEMENT (before_view_ins_stmt) ! NOTICE: main_view INSTEAD OF INSERT ROW (instead_of_ins) ! NOTICE: NEW: (20,30) ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)" ! PL/pgSQL function view_trigger() line 17 at SQL statement ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)" ! PL/pgSQL function view_trigger() line 17 at SQL statement ! NOTICE: main_view AFTER INSERT STATEMENT (after_view_ins_stmt) ! INSERT 0 1 ! INSERT INTO main_view VALUES (21, 31) RETURNING a, b; ! NOTICE: main_view BEFORE INSERT STATEMENT (before_view_ins_stmt) ! NOTICE: main_view INSTEAD OF INSERT ROW (instead_of_ins) ! NOTICE: NEW: (21,31) ! NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)" ! PL/pgSQL function view_trigger() line 17 at SQL statement ! NOTICE: trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)" ! PL/pgSQL function view_trigger() line 17 at SQL statement ! NOTICE: main_view AFTER INSERT STATEMENT (after_view_ins_stmt) ! a | b ! ----+---- ! 21 | 31 ! (1 row) ! ! INSERT 0 1 ! -- Table trigger will prevent updates ! UPDATE main_view SET b = 31 WHERE a = 20; ! NOTICE: main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt) ! NOTICE: main_view INSTEAD OF UPDATE ROW (instead_of_upd) ! NOTICE: OLD: (20,30), NEW: (20,31) ! NOTICE: trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: main_view AFTER UPDATE STATEMENT (after_view_upd_stmt) ! UPDATE 0 ! UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b; ! NOTICE: main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt) ! NOTICE: main_view INSTEAD OF UPDATE ROW (instead_of_upd) ! NOTICE: OLD: (21,31), NEW: (21,32) ! NOTICE: trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: main_view AFTER UPDATE STATEMENT (after_view_upd_stmt) ! a | b ! ---+--- ! (0 rows) ! ! UPDATE 0 ! -- Remove table trigger to allow updates ! DROP TRIGGER before_upd_a_row_trig ON main_table; ! DROP TRIGGER ! UPDATE main_view SET b = 31 WHERE a = 20; ! NOTICE: main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt) ! NOTICE: main_view INSTEAD OF UPDATE ROW (instead_of_upd) ! NOTICE: OLD: (20,30), NEW: (20,31) ! NOTICE: trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: main_view AFTER UPDATE STATEMENT (after_view_upd_stmt) ! UPDATE 1 ! UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b; ! NOTICE: main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt) ! NOTICE: main_view INSTEAD OF UPDATE ROW (instead_of_upd) ! NOTICE: OLD: (21,31), NEW: (21,32) ! NOTICE: trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT ! CONTEXT: SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b" ! PL/pgSQL function view_trigger() line 23 at SQL statement ! NOTICE: main_view AFTER UPDATE STATEMENT (after_view_upd_stmt) ! a | b ! ----+---- ! 21 | 32 ! (1 row) ! ! UPDATE 1 ! -- Before and after stmt triggers should fire even when no rows are affected ! UPDATE main_view SET b = 0 WHERE false; ! NOTICE: main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt) ! NOTICE: main_view AFTER UPDATE STATEMENT (after_view_upd_stmt) ! UPDATE 0 ! -- Delete from view using trigger ! DELETE FROM main_view WHERE a IN (20,21); ! NOTICE: main_view BEFORE DELETE STATEMENT (before_view_del_stmt) ! NOTICE: main_view INSTEAD OF DELETE ROW (instead_of_del) ! NOTICE: OLD: (21,10) ! NOTICE: main_view INSTEAD OF DELETE ROW (instead_of_del) ! NOTICE: OLD: (20,31) ! NOTICE: main_view INSTEAD OF DELETE ROW (instead_of_del) ! NOTICE: OLD: (21,32) ! NOTICE: main_view AFTER DELETE STATEMENT (after_view_del_stmt) ! DELETE 3 ! DELETE FROM main_view WHERE a = 31 RETURNING a, b; ! NOTICE: main_view BEFORE DELETE STATEMENT (before_view_del_stmt) ! NOTICE: main_view INSTEAD OF DELETE ROW (instead_of_del) ! NOTICE: OLD: (31,10) ! NOTICE: main_view AFTER DELETE STATEMENT (after_view_del_stmt) ! a | b ! ----+---- ! 31 | 10 ! (1 row) ! ! DELETE 1 ! \set QUIET true ! -- Describe view should list triggers ! \d main_view ! View "public.main_view" ! Column | Type | Modifiers ! --------+---------+----------- ! a | integer | ! b | integer | ! Triggers: ! after_del_stmt_trig AFTER DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt') ! after_ins_stmt_trig AFTER INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt') ! after_upd_stmt_trig AFTER UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt') ! before_del_stmt_trig BEFORE DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt') ! before_ins_stmt_trig BEFORE INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt') ! before_upd_stmt_trig BEFORE UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt') ! instead_of_delete_trig INSTEAD OF DELETE ON main_view FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_del') ! instead_of_insert_trig INSTEAD OF INSERT ON main_view FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_ins') ! instead_of_update_trig INSTEAD OF UPDATE ON main_view FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd') ! ! -- Test dropping view triggers ! DROP TRIGGER instead_of_insert_trig ON main_view; ! DROP TRIGGER instead_of_delete_trig ON main_view; ! \d+ main_view ! View "public.main_view" ! Column | Type | Modifiers | Storage | Description ! --------+---------+-----------+---------+------------- ! a | integer | | plain | ! b | integer | | plain | ! View definition: ! SELECT main_table.a, ! main_table.b ! FROM main_table; ! Triggers: ! after_del_stmt_trig AFTER DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt') ! after_ins_stmt_trig AFTER INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_ins_stmt') ! after_upd_stmt_trig AFTER UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_upd_stmt') ! before_del_stmt_trig BEFORE DELETE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_del_stmt') ! before_ins_stmt_trig BEFORE INSERT ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_ins_stmt') ! before_upd_stmt_trig BEFORE UPDATE ON main_view FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('before_view_upd_stmt') ! instead_of_update_trig INSTEAD OF UPDATE ON main_view FOR EACH ROW EXECUTE PROCEDURE view_trigger('instead_of_upd') ! ! DROP VIEW main_view; ! -- ! -- Test triggers on a join view ! -- ! CREATE TABLE country_table ( ! country_id serial primary key, ! country_name text unique not null, ! continent text not null ! ); ! INSERT INTO country_table (country_name, continent) ! VALUES ('Japan', 'Asia'), ! ('UK', 'Europe'), ! ('USA', 'North America') ! RETURNING *; ! country_id | country_name | continent ! ------------+--------------+--------------- ! 1 | Japan | Asia ! 2 | UK | Europe ! 3 | USA | North America ! (3 rows) ! ! CREATE TABLE city_table ( ! city_id serial primary key, ! city_name text not null, ! population bigint, ! country_id int references country_table ! ); ! CREATE VIEW city_view AS ! SELECT city_id, city_name, population, country_name, continent ! FROM city_table ci ! LEFT JOIN country_table co ON co.country_id = ci.country_id; ! CREATE FUNCTION city_insert() RETURNS trigger LANGUAGE plpgsql AS $$ ! declare ! ctry_id int; ! begin ! if NEW.country_name IS NOT NULL then ! SELECT country_id, continent INTO ctry_id, NEW.continent ! FROM country_table WHERE country_name = NEW.country_name; ! if NOT FOUND then ! raise exception 'No such country: "%"', NEW.country_name; ! end if; ! else ! NEW.continent := NULL; ! end if; ! ! if NEW.city_id IS NOT NULL then ! INSERT INTO city_table ! VALUES(NEW.city_id, NEW.city_name, NEW.population, ctry_id); ! else ! INSERT INTO city_table(city_name, population, country_id) ! VALUES(NEW.city_name, NEW.population, ctry_id) ! RETURNING city_id INTO NEW.city_id; ! end if; ! ! RETURN NEW; ! end; ! $$; ! CREATE TRIGGER city_insert_trig INSTEAD OF INSERT ON city_view ! FOR EACH ROW EXECUTE PROCEDURE city_insert(); ! CREATE FUNCTION city_delete() RETURNS trigger LANGUAGE plpgsql AS $$ ! begin ! DELETE FROM city_table WHERE city_id = OLD.city_id; ! if NOT FOUND then RETURN NULL; end if; ! RETURN OLD; ! end; ! $$; ! CREATE TRIGGER city_delete_trig INSTEAD OF DELETE ON city_view ! FOR EACH ROW EXECUTE PROCEDURE city_delete(); ! CREATE FUNCTION city_update() RETURNS trigger LANGUAGE plpgsql AS $$ ! declare ! ctry_id int; ! begin ! if NEW.country_name IS DISTINCT FROM OLD.country_name then ! SELECT country_id, continent INTO ctry_id, NEW.continent ! FROM country_table WHERE country_name = NEW.country_name; ! if NOT FOUND then ! raise exception 'No such country: "%"', NEW.country_name; ! end if; ! ! UPDATE city_table SET city_name = NEW.city_name, ! population = NEW.population, ! country_id = ctry_id ! WHERE city_id = OLD.city_id; ! else ! UPDATE city_table SET city_name = NEW.city_name, ! population = NEW.population ! WHERE city_id = OLD.city_id; ! NEW.continent := OLD.continent; ! end if; ! ! if NOT FOUND then RETURN NULL; end if; ! RETURN NEW; ! end; ! $$; ! CREATE TRIGGER city_update_trig INSTEAD OF UPDATE ON city_view ! FOR EACH ROW EXECUTE PROCEDURE city_update(); ! \set QUIET false ! -- INSERT .. RETURNING ! INSERT INTO city_view(city_name) VALUES('Tokyo') RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 1 | Tokyo | | | ! (1 row) ! ! INSERT 0 1 ! INSERT INTO city_view(city_name, population) VALUES('London', 7556900) RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 2 | London | 7556900 | | ! (1 row) ! ! INSERT 0 1 ! INSERT INTO city_view(city_name, country_name) VALUES('Washington DC', 'USA') RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+---------------+------------+--------------+--------------- ! 3 | Washington DC | | USA | North America ! (1 row) ! ! INSERT 0 1 ! INSERT INTO city_view(city_id, city_name) VALUES(123456, 'New York') RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 123456 | New York | | | ! (1 row) ! ! INSERT 0 1 ! INSERT INTO city_view VALUES(234567, 'Birmingham', 1016800, 'UK', 'EU') RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+------------+------------+--------------+----------- ! 234567 | Birmingham | 1016800 | UK | Europe ! (1 row) ! ! INSERT 0 1 ! -- UPDATE .. RETURNING ! UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error ! ERROR: No such country: "Japon" ! UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match ! UPDATE 0 ! UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 1 | Tokyo | | Japan | Asia ! (1 row) ! ! UPDATE 1 ! UPDATE city_view SET population = 13010279 WHERE city_name = 'Tokyo' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 1 | Tokyo | 13010279 | Japan | Asia ! (1 row) ! ! UPDATE 1 ! UPDATE city_view SET country_name = 'UK' WHERE city_name = 'New York' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 123456 | New York | | UK | Europe ! (1 row) ! ! UPDATE 1 ! UPDATE city_view SET country_name = 'USA', population = 8391881 WHERE city_name = 'New York' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+--------------- ! 123456 | New York | 8391881 | USA | North America ! (1 row) ! ! UPDATE 1 ! UPDATE city_view SET continent = 'EU' WHERE continent = 'Europe' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+------------+------------+--------------+----------- ! 234567 | Birmingham | 1016800 | UK | Europe ! (1 row) ! ! UPDATE 1 ! UPDATE city_view v1 SET country_name = v2.country_name FROM city_view v2 ! WHERE v2.city_name = 'Birmingham' AND v1.city_name = 'London' RETURNING *; ! city_id | city_name | population | country_name | continent | city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+-----------+---------+------------+------------+--------------+----------- ! 2 | London | 7556900 | UK | Europe | 234567 | Birmingham | 1016800 | UK | Europe ! (1 row) ! ! UPDATE 1 ! -- DELETE .. RETURNING ! DELETE FROM city_view WHERE city_name = 'Birmingham' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+------------+------------+--------------+----------- ! 234567 | Birmingham | 1016800 | UK | Europe ! (1 row) ! ! DELETE 1 ! \set QUIET true ! -- read-only view with WHERE clause ! CREATE VIEW european_city_view AS ! SELECT * FROM city_view WHERE continent = 'Europe'; ! SELECT count(*) FROM european_city_view; ! count ! ------- ! 1 ! (1 row) ! ! CREATE FUNCTION no_op_trig_fn() RETURNS trigger LANGUAGE plpgsql ! AS 'begin RETURN NULL; end'; ! CREATE TRIGGER no_op_trig INSTEAD OF INSERT OR UPDATE OR DELETE ! ON european_city_view FOR EACH ROW EXECUTE PROCEDURE no_op_trig_fn(); ! \set QUIET false ! INSERT INTO european_city_view VALUES (0, 'x', 10000, 'y', 'z'); ! INSERT 0 0 ! UPDATE european_city_view SET population = 10000; ! UPDATE 0 ! DELETE FROM european_city_view; ! DELETE 0 ! \set QUIET true ! -- rules bypassing no-op triggers ! CREATE RULE european_city_insert_rule AS ON INSERT TO european_city_view ! DO INSTEAD INSERT INTO city_view ! VALUES (NEW.city_id, NEW.city_name, NEW.population, NEW.country_name, NEW.continent) ! RETURNING *; ! CREATE RULE european_city_update_rule AS ON UPDATE TO european_city_view ! DO INSTEAD UPDATE city_view SET ! city_name = NEW.city_name, ! population = NEW.population, ! country_name = NEW.country_name ! WHERE city_id = OLD.city_id ! RETURNING NEW.*; ! CREATE RULE european_city_delete_rule AS ON DELETE TO european_city_view ! DO INSTEAD DELETE FROM city_view WHERE city_id = OLD.city_id RETURNING *; ! \set QUIET false ! -- INSERT not limited by view's WHERE clause, but UPDATE AND DELETE are ! INSERT INTO european_city_view(city_name, country_name) ! VALUES ('Cambridge', 'USA') RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+--------------- ! 4 | Cambridge | | USA | North America ! (1 row) ! ! INSERT 0 1 ! UPDATE european_city_view SET country_name = 'UK' ! WHERE city_name = 'Cambridge'; ! UPDATE 0 ! DELETE FROM european_city_view WHERE city_name = 'Cambridge'; ! DELETE 0 ! -- UPDATE and DELETE via rule and trigger ! UPDATE city_view SET country_name = 'UK' ! WHERE city_name = 'Cambridge' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 4 | Cambridge | | UK | Europe ! (1 row) ! ! UPDATE 1 ! UPDATE european_city_view SET population = 122800 ! WHERE city_name = 'Cambridge' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 4 | Cambridge | 122800 | UK | Europe ! (1 row) ! ! UPDATE 1 ! DELETE FROM european_city_view WHERE city_name = 'Cambridge' RETURNING *; ! city_id | city_name | population | country_name | continent ! ---------+-----------+------------+--------------+----------- ! 4 | Cambridge | 122800 | UK | Europe ! (1 row) ! ! DELETE 1 ! -- join UPDATE test ! UPDATE city_view v SET population = 599657 ! FROM city_table ci, country_table co ! WHERE ci.city_name = 'Washington DC' and co.country_name = 'USA' ! AND v.city_id = ci.city_id AND v.country_name = co.country_name ! RETURNING co.country_id, v.country_name, ! v.city_id, v.city_name, v.population; ! country_id | country_name | city_id | city_name | population ! ------------+--------------+---------+---------------+------------ ! 3 | USA | 3 | Washington DC | 599657 ! (1 row) ! ! UPDATE 1 ! \set QUIET true ! SELECT * FROM city_view; ! city_id | city_name | population | country_name | continent ! ---------+---------------+------------+--------------+--------------- ! 1 | Tokyo | 13010279 | Japan | Asia ! 123456 | New York | 8391881 | USA | North America ! 2 | London | 7556900 | UK | Europe ! 3 | Washington DC | 599657 | USA | North America ! (4 rows) ! ! DROP TABLE city_table CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view city_view ! drop cascades to view european_city_view ! DROP TABLE country_table; ! -- Test pg_trigger_depth() ! create table depth_a (id int not null primary key); ! create table depth_b (id int not null primary key); ! create table depth_c (id int not null primary key); ! create function depth_a_tf() returns trigger ! language plpgsql as $$ ! begin ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! insert into depth_b values (new.id); ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! return new; ! end; ! $$; ! create trigger depth_a_tr before insert on depth_a ! for each row execute procedure depth_a_tf(); ! create function depth_b_tf() returns trigger ! language plpgsql as $$ ! begin ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! begin ! execute 'insert into depth_c values (' || new.id::text || ')'; ! exception ! when sqlstate 'U9999' then ! raise notice 'SQLSTATE = U9999: depth = %', pg_trigger_depth(); ! end; ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! if new.id = 1 then ! execute 'insert into depth_c values (' || new.id::text || ')'; ! end if; ! return new; ! end; ! $$; ! create trigger depth_b_tr before insert on depth_b ! for each row execute procedure depth_b_tf(); ! create function depth_c_tf() returns trigger ! language plpgsql as $$ ! begin ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! if new.id = 1 then ! raise exception sqlstate 'U9999'; ! end if; ! raise notice '%: depth = %', tg_name, pg_trigger_depth(); ! return new; ! end; ! $$; ! create trigger depth_c_tr before insert on depth_c ! for each row execute procedure depth_c_tf(); ! select pg_trigger_depth(); ! pg_trigger_depth ! ------------------ ! 0 ! (1 row) ! ! insert into depth_a values (1); ! NOTICE: depth_a_tr: depth = 1 ! NOTICE: depth_b_tr: depth = 2 ! CONTEXT: SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_c_tr: depth = 3 ! CONTEXT: SQL statement "insert into depth_c values (1)" ! PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement ! SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: SQLSTATE = U9999: depth = 2 ! CONTEXT: SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_b_tr: depth = 2 ! CONTEXT: SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_c_tr: depth = 3 ! CONTEXT: SQL statement "insert into depth_c values (1)" ! PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement ! SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! ERROR: U9999 ! CONTEXT: SQL statement "insert into depth_c values (1)" ! PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement ! SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! select pg_trigger_depth(); ! pg_trigger_depth ! ------------------ ! 0 ! (1 row) ! ! insert into depth_a values (2); ! NOTICE: depth_a_tr: depth = 1 ! NOTICE: depth_b_tr: depth = 2 ! CONTEXT: SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_c_tr: depth = 3 ! CONTEXT: SQL statement "insert into depth_c values (2)" ! PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement ! SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_c_tr: depth = 3 ! CONTEXT: SQL statement "insert into depth_c values (2)" ! PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement ! SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_b_tr: depth = 2 ! CONTEXT: SQL statement "insert into depth_b values (new.id)" ! PL/pgSQL function depth_a_tf() line 4 at SQL statement ! NOTICE: depth_a_tr: depth = 1 ! select pg_trigger_depth(); ! pg_trigger_depth ! ------------------ ! 0 ! (1 row) ! ! drop table depth_a, depth_b, depth_c; ! drop function depth_a_tf(); ! drop function depth_b_tf(); ! drop function depth_c_tf(); ! -- ! -- Test updates to rows during firing of BEFORE ROW triggers. ! -- As of 9.2, such cases should be rejected (see bug #6123). ! -- ! create temp table parent ( ! aid int not null primary key, ! val1 text, ! val2 text, ! val3 text, ! val4 text, ! bcnt int not null default 0); ! create temp table child ( ! bid int not null primary key, ! aid int not null, ! val1 text); ! create function parent_upd_func() ! returns trigger language plpgsql as ! $$ ! begin ! if old.val1 <> new.val1 then ! new.val2 = new.val1; ! delete from child where child.aid = new.aid and child.val1 = new.val1; ! end if; ! return new; ! end; ! $$; ! create trigger parent_upd_trig before update on parent ! for each row execute procedure parent_upd_func(); ! create function parent_del_func() ! returns trigger language plpgsql as ! $$ ! begin ! delete from child where aid = old.aid; ! return old; ! end; ! $$; ! create trigger parent_del_trig before delete on parent ! for each row execute procedure parent_del_func(); ! create function child_ins_func() ! returns trigger language plpgsql as ! $$ ! begin ! update parent set bcnt = bcnt + 1 where aid = new.aid; ! return new; ! end; ! $$; ! create trigger child_ins_trig after insert on child ! for each row execute procedure child_ins_func(); ! create function child_del_func() ! returns trigger language plpgsql as ! $$ ! begin ! update parent set bcnt = bcnt - 1 where aid = old.aid; ! return old; ! end; ! $$; ! create trigger child_del_trig after delete on child ! for each row execute procedure child_del_func(); ! insert into parent values (1, 'a', 'a', 'a', 'a', 0); ! insert into child values (10, 1, 'b'); ! select * from parent; select * from child; ! aid | val1 | val2 | val3 | val4 | bcnt ! -----+------+------+------+------+------ ! 1 | a | a | a | a | 1 ! (1 row) ! ! bid | aid | val1 ! -----+-----+------ ! 10 | 1 | b ! (1 row) ! ! update parent set val1 = 'b' where aid = 1; -- should fail ! ERROR: tuple to be updated was already modified by an operation triggered by the current command ! HINT: Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows. ! select * from parent; select * from child; ! aid | val1 | val2 | val3 | val4 | bcnt ! -----+------+------+------+------+------ ! 1 | a | a | a | a | 1 ! (1 row) ! ! bid | aid | val1 ! -----+-----+------ ! 10 | 1 | b ! (1 row) ! ! delete from parent where aid = 1; -- should fail ! ERROR: tuple to be updated was already modified by an operation triggered by the current command ! HINT: Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows. ! select * from parent; select * from child; ! aid | val1 | val2 | val3 | val4 | bcnt ! -----+------+------+------+------+------ ! 1 | a | a | a | a | 1 ! (1 row) ! ! bid | aid | val1 ! -----+-----+------ ! 10 | 1 | b ! (1 row) ! ! -- replace the trigger function with one that restarts the deletion after ! -- having modified a child ! create or replace function parent_del_func() ! returns trigger language plpgsql as ! $$ ! begin ! delete from child where aid = old.aid; ! if found then ! delete from parent where aid = old.aid; ! return null; -- cancel outer deletion ! end if; ! return old; ! end; ! $$; ! delete from parent where aid = 1; ! select * from parent; select * from child; ! aid | val1 | val2 | val3 | val4 | bcnt ! -----+------+------+------+------+------ ! (0 rows) ! ! bid | aid | val1 ! -----+-----+------ ! (0 rows) ! ! drop table parent, child; ! drop function parent_upd_func(); ! drop function parent_del_func(); ! drop function child_ins_func(); ! drop function child_del_func(); ! -- similar case, but with a self-referencing FK so that parent and child ! -- rows can be affected by a single operation ! create temp table self_ref_trigger ( ! id int primary key, ! parent int references self_ref_trigger, ! data text, ! nchildren int not null default 0 ! ); ! create function self_ref_trigger_ins_func() ! returns trigger language plpgsql as ! $$ ! begin ! if new.parent is not null then ! update self_ref_trigger set nchildren = nchildren + 1 ! where id = new.parent; ! end if; ! return new; ! end; ! $$; ! create trigger self_ref_trigger_ins_trig before insert on self_ref_trigger ! for each row execute procedure self_ref_trigger_ins_func(); ! create function self_ref_trigger_del_func() ! returns trigger language plpgsql as ! $$ ! begin ! if old.parent is not null then ! update self_ref_trigger set nchildren = nchildren - 1 ! where id = old.parent; ! end if; ! return old; ! end; ! $$; ! create trigger self_ref_trigger_del_trig before delete on self_ref_trigger ! for each row execute procedure self_ref_trigger_del_func(); ! insert into self_ref_trigger values (1, null, 'root'); ! insert into self_ref_trigger values (2, 1, 'root child A'); ! insert into self_ref_trigger values (3, 1, 'root child B'); ! insert into self_ref_trigger values (4, 2, 'grandchild 1'); ! insert into self_ref_trigger values (5, 3, 'grandchild 2'); ! update self_ref_trigger set data = 'root!' where id = 1; ! select * from self_ref_trigger; ! id | parent | data | nchildren ! ----+--------+--------------+----------- ! 2 | 1 | root child A | 1 ! 4 | 2 | grandchild 1 | 0 ! 3 | 1 | root child B | 1 ! 5 | 3 | grandchild 2 | 0 ! 1 | | root! | 2 ! (5 rows) ! ! delete from self_ref_trigger; ! ERROR: tuple to be updated was already modified by an operation triggered by the current command ! HINT: Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows. ! select * from self_ref_trigger; ! id | parent | data | nchildren ! ----+--------+--------------+----------- ! 2 | 1 | root child A | 1 ! 4 | 2 | grandchild 1 | 0 ! 3 | 1 | root child B | 1 ! 5 | 3 | grandchild 2 | 0 ! 1 | | root! | 2 ! (5 rows) ! ! drop table self_ref_trigger; ! drop function self_ref_trigger_ins_func(); ! drop function self_ref_trigger_del_func(); --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/inherit.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/inherit.out Tue Oct 28 15:53:05 2014 *************** *** 1,1457 **** ! -- ! -- Test inheritance features ! -- ! CREATE TABLE a (aa TEXT); ! CREATE TABLE b (bb TEXT) INHERITS (a); ! CREATE TABLE c (cc TEXT) INHERITS (a); ! CREATE TABLE d (dd TEXT) INHERITS (b,c,a); ! NOTICE: merging multiple inherited definitions of column "aa" ! NOTICE: merging multiple inherited definitions of column "aa" ! INSERT INTO a(aa) VALUES('aaa'); ! INSERT INTO a(aa) VALUES('aaaa'); ! INSERT INTO a(aa) VALUES('aaaaa'); ! INSERT INTO a(aa) VALUES('aaaaaa'); ! INSERT INTO a(aa) VALUES('aaaaaaa'); ! INSERT INTO a(aa) VALUES('aaaaaaaa'); ! INSERT INTO b(aa) VALUES('bbb'); ! INSERT INTO b(aa) VALUES('bbbb'); ! INSERT INTO b(aa) VALUES('bbbbb'); ! INSERT INTO b(aa) VALUES('bbbbbb'); ! INSERT INTO b(aa) VALUES('bbbbbbb'); ! INSERT INTO b(aa) VALUES('bbbbbbbb'); ! INSERT INTO c(aa) VALUES('ccc'); ! INSERT INTO c(aa) VALUES('cccc'); ! INSERT INTO c(aa) VALUES('ccccc'); ! INSERT INTO c(aa) VALUES('cccccc'); ! INSERT INTO c(aa) VALUES('ccccccc'); ! INSERT INTO c(aa) VALUES('cccccccc'); ! INSERT INTO d(aa) VALUES('ddd'); ! INSERT INTO d(aa) VALUES('dddd'); ! INSERT INTO d(aa) VALUES('ddddd'); ! INSERT INTO d(aa) VALUES('dddddd'); ! INSERT INTO d(aa) VALUES('ddddddd'); ! INSERT INTO d(aa) VALUES('dddddddd'); ! SELECT relname, a.* FROM a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---------- ! a | aaa ! a | aaaa ! a | aaaaa ! a | aaaaaa ! a | aaaaaaa ! a | aaaaaaaa ! b | bbb ! b | bbbb ! b | bbbbb ! b | bbbbbb ! b | bbbbbbb ! b | bbbbbbbb ! c | ccc ! c | cccc ! c | ccccc ! c | cccccc ! c | ccccccc ! c | cccccccc ! d | ddd ! d | dddd ! d | ddddd ! d | dddddd ! d | ddddddd ! d | dddddddd ! (24 rows) ! ! SELECT relname, b.* FROM b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----------+---- ! b | bbb | ! b | bbbb | ! b | bbbbb | ! b | bbbbbb | ! b | bbbbbbb | ! b | bbbbbbbb | ! d | ddd | ! d | dddd | ! d | ddddd | ! d | dddddd | ! d | ddddddd | ! d | dddddddd | ! (12 rows) ! ! SELECT relname, c.* FROM c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! d | ddd | ! d | dddd | ! d | ddddd | ! d | dddddd | ! d | ddddddd | ! d | dddddddd | ! (12 rows) ! ! SELECT relname, d.* FROM d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----------+----+----+---- ! d | ddd | | | ! d | dddd | | | ! d | ddddd | | | ! d | dddddd | | | ! d | ddddddd | | | ! d | dddddddd | | | ! (6 rows) ! ! SELECT relname, a.* FROM ONLY a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---------- ! a | aaa ! a | aaaa ! a | aaaaa ! a | aaaaaa ! a | aaaaaaa ! a | aaaaaaaa ! (6 rows) ! ! SELECT relname, b.* FROM ONLY b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----------+---- ! b | bbb | ! b | bbbb | ! b | bbbbb | ! b | bbbbbb | ! b | bbbbbbb | ! b | bbbbbbbb | ! (6 rows) ! ! SELECT relname, c.* FROM ONLY c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! (6 rows) ! ! SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----------+----+----+---- ! d | ddd | | | ! d | dddd | | | ! d | ddddd | | | ! d | dddddd | | | ! d | ddddddd | | | ! d | dddddddd | | | ! (6 rows) ! ! UPDATE a SET aa='zzzz' WHERE aa='aaaa'; ! UPDATE ONLY a SET aa='zzzzz' WHERE aa='aaaaa'; ! UPDATE b SET aa='zzz' WHERE aa='aaa'; ! UPDATE ONLY b SET aa='zzz' WHERE aa='aaa'; ! UPDATE a SET aa='zzzzzz' WHERE aa LIKE 'aaa%'; ! SELECT relname, a.* FROM a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---------- ! a | zzzz ! a | zzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! b | bbb ! b | bbbb ! b | bbbbb ! b | bbbbbb ! b | bbbbbbb ! b | bbbbbbbb ! c | ccc ! c | cccc ! c | ccccc ! c | cccccc ! c | ccccccc ! c | cccccccc ! d | ddd ! d | dddd ! d | ddddd ! d | dddddd ! d | ddddddd ! d | dddddddd ! (24 rows) ! ! SELECT relname, b.* FROM b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----------+---- ! b | bbb | ! b | bbbb | ! b | bbbbb | ! b | bbbbbb | ! b | bbbbbbb | ! b | bbbbbbbb | ! d | ddd | ! d | dddd | ! d | ddddd | ! d | dddddd | ! d | ddddddd | ! d | dddddddd | ! (12 rows) ! ! SELECT relname, c.* FROM c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! d | ddd | ! d | dddd | ! d | ddddd | ! d | dddddd | ! d | ddddddd | ! d | dddddddd | ! (12 rows) ! ! SELECT relname, d.* FROM d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----------+----+----+---- ! d | ddd | | | ! d | dddd | | | ! d | ddddd | | | ! d | dddddd | | | ! d | ddddddd | | | ! d | dddddddd | | | ! (6 rows) ! ! SELECT relname, a.* FROM ONLY a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+-------- ! a | zzzz ! a | zzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! (6 rows) ! ! SELECT relname, b.* FROM ONLY b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----------+---- ! b | bbb | ! b | bbbb | ! b | bbbbb | ! b | bbbbbb | ! b | bbbbbbb | ! b | bbbbbbbb | ! (6 rows) ! ! SELECT relname, c.* FROM ONLY c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! (6 rows) ! ! SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----------+----+----+---- ! d | ddd | | | ! d | dddd | | | ! d | ddddd | | | ! d | dddddd | | | ! d | ddddddd | | | ! d | dddddddd | | | ! (6 rows) ! ! UPDATE b SET aa='new'; ! SELECT relname, a.* FROM a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---------- ! a | zzzz ! a | zzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! b | new ! b | new ! b | new ! b | new ! b | new ! b | new ! c | ccc ! c | cccc ! c | ccccc ! c | cccccc ! c | ccccccc ! c | cccccccc ! d | new ! d | new ! d | new ! d | new ! d | new ! d | new ! (24 rows) ! ! SELECT relname, b.* FROM b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+-----+---- ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! (12 rows) ! ! SELECT relname, c.* FROM c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! (12 rows) ! ! SELECT relname, d.* FROM d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+-----+----+----+---- ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! (6 rows) ! ! SELECT relname, a.* FROM ONLY a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+-------- ! a | zzzz ! a | zzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! a | zzzzzz ! (6 rows) ! ! SELECT relname, b.* FROM ONLY b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+-----+---- ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! (6 rows) ! ! SELECT relname, c.* FROM ONLY c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----------+---- ! c | ccc | ! c | cccc | ! c | ccccc | ! c | cccccc | ! c | ccccccc | ! c | cccccccc | ! (6 rows) ! ! SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+-----+----+----+---- ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! (6 rows) ! ! UPDATE a SET aa='new'; ! DELETE FROM ONLY c WHERE aa='new'; ! SELECT relname, a.* FROM a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+----- ! a | new ! a | new ! a | new ! a | new ! a | new ! a | new ! b | new ! b | new ! b | new ! b | new ! b | new ! b | new ! d | new ! d | new ! d | new ! d | new ! d | new ! d | new ! (18 rows) ! ! SELECT relname, b.* FROM b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+-----+---- ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! (12 rows) ! ! SELECT relname, c.* FROM c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+-----+---- ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! d | new | ! (6 rows) ! ! SELECT relname, d.* FROM d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+-----+----+----+---- ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! (6 rows) ! ! SELECT relname, a.* FROM ONLY a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+----- ! a | new ! a | new ! a | new ! a | new ! a | new ! a | new ! (6 rows) ! ! SELECT relname, b.* FROM ONLY b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+-----+---- ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! b | new | ! (6 rows) ! ! SELECT relname, c.* FROM ONLY c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----+---- ! (0 rows) ! ! SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+-----+----+----+---- ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! d | new | | | ! (6 rows) ! ! DELETE FROM a; ! SELECT relname, a.* FROM a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---- ! (0 rows) ! ! SELECT relname, b.* FROM b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----+---- ! (0 rows) ! ! SELECT relname, c.* FROM c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----+---- ! (0 rows) ! ! SELECT relname, d.* FROM d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----+----+----+---- ! (0 rows) ! ! SELECT relname, a.* FROM ONLY a, pg_class where a.tableoid = pg_class.oid; ! relname | aa ! ---------+---- ! (0 rows) ! ! SELECT relname, b.* FROM ONLY b, pg_class where b.tableoid = pg_class.oid; ! relname | aa | bb ! ---------+----+---- ! (0 rows) ! ! SELECT relname, c.* FROM ONLY c, pg_class where c.tableoid = pg_class.oid; ! relname | aa | cc ! ---------+----+---- ! (0 rows) ! ! SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid; ! relname | aa | bb | cc | dd ! ---------+----+----+----+---- ! (0 rows) ! ! -- Confirm PRIMARY KEY adds NOT NULL constraint to child table ! CREATE TEMP TABLE z (b TEXT, PRIMARY KEY(aa, b)) inherits (a); ! INSERT INTO z VALUES (NULL, 'text'); -- should fail ! ERROR: null value in column "aa" violates not-null constraint ! DETAIL: Failing row contains (null, text). ! -- Check UPDATE with inherited target and an inherited source table ! create temp table foo(f1 int, f2 int); ! create temp table foo2(f3 int) inherits (foo); ! create temp table bar(f1 int, f2 int); ! create temp table bar2(f3 int) inherits (bar); ! insert into foo values(1,1); ! insert into foo values(3,3); ! insert into foo2 values(2,2,2); ! insert into foo2 values(3,3,3); ! insert into bar values(1,1); ! insert into bar values(2,2); ! insert into bar values(3,3); ! insert into bar values(4,4); ! insert into bar2 values(1,1,1); ! insert into bar2 values(2,2,2); ! insert into bar2 values(3,3,3); ! insert into bar2 values(4,4,4); ! update bar set f2 = f2 + 100 where f1 in (select f1 from foo); ! select tableoid::regclass::text as relname, bar.* from bar order by 1,2; ! relname | f1 | f2 ! ---------+----+----- ! bar | 1 | 101 ! bar | 2 | 102 ! bar | 3 | 103 ! bar | 4 | 4 ! bar2 | 1 | 101 ! bar2 | 2 | 102 ! bar2 | 3 | 103 ! bar2 | 4 | 4 ! (8 rows) ! ! -- Check UPDATE with inherited target and an appendrel subquery ! update bar set f2 = f2 + 100 ! from ! ( select f1 from foo union all select f1+3 from foo ) ss ! where bar.f1 = ss.f1; ! select tableoid::regclass::text as relname, bar.* from bar order by 1,2; ! relname | f1 | f2 ! ---------+----+----- ! bar | 1 | 201 ! bar | 2 | 202 ! bar | 3 | 203 ! bar | 4 | 104 ! bar2 | 1 | 201 ! bar2 | 2 | 202 ! bar2 | 3 | 203 ! bar2 | 4 | 104 ! (8 rows) ! ! /* Test multiple inheritance of column defaults */ ! CREATE TABLE firstparent (tomorrow date default now()::date + 1); ! CREATE TABLE secondparent (tomorrow date default now() :: date + 1); ! CREATE TABLE jointchild () INHERITS (firstparent, secondparent); -- ok ! NOTICE: merging multiple inherited definitions of column "tomorrow" ! CREATE TABLE thirdparent (tomorrow date default now()::date - 1); ! CREATE TABLE otherchild () INHERITS (firstparent, thirdparent); -- not ok ! NOTICE: merging multiple inherited definitions of column "tomorrow" ! ERROR: column "tomorrow" inherits conflicting default values ! HINT: To resolve the conflict, specify a default explicitly. ! CREATE TABLE otherchild (tomorrow date default now()) ! INHERITS (firstparent, thirdparent); -- ok, child resolves ambiguous default ! NOTICE: merging multiple inherited definitions of column "tomorrow" ! NOTICE: merging column "tomorrow" with inherited definition ! DROP TABLE firstparent, secondparent, jointchild, thirdparent, otherchild; ! -- Test changing the type of inherited columns ! insert into d values('test','one','two','three'); ! alter table a alter column aa type integer using bit_length(aa); ! select * from d; ! aa | bb | cc | dd ! ----+-----+-----+------- ! 32 | one | two | three ! (1 row) ! ! -- Test non-inheritable parent constraints ! create table p1(ff1 int); ! alter table p1 add constraint p1chk check (ff1 > 0) no inherit; ! alter table p1 add constraint p2chk check (ff1 > 10); ! -- connoinherit should be true for NO INHERIT constraint ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.connoinherit from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2; ! relname | conname | contype | conislocal | coninhcount | connoinherit ! ---------+---------+---------+------------+-------------+-------------- ! p1 | p1chk | c | t | 0 | t ! p1 | p2chk | c | t | 0 | f ! (2 rows) ! ! -- Test that child does not inherit NO INHERIT constraints ! create table c1 () inherits (p1); ! \d p1 ! Table "public.p1" ! Column | Type | Modifiers ! --------+---------+----------- ! ff1 | integer | ! Check constraints: ! "p1chk" CHECK (ff1 > 0) NO INHERIT ! "p2chk" CHECK (ff1 > 10) ! Number of child tables: 1 (Use \d+ to list them.) ! ! \d c1 ! Table "public.c1" ! Column | Type | Modifiers ! --------+---------+----------- ! ff1 | integer | ! Check constraints: ! "p2chk" CHECK (ff1 > 10) ! Inherits: p1 ! ! drop table p1 cascade; ! NOTICE: drop cascades to table c1 ! -- Tests for casting between the rowtypes of parent and child ! -- tables. See the pgsql-hackers thread beginning Dec. 4/04 ! create table base (i integer); ! create table derived () inherits (base); ! insert into derived (i) values (0); ! select derived::base from derived; ! derived ! --------- ! (0) ! (1 row) ! ! drop table derived; ! drop table base; ! create table p1(ff1 int); ! create table p2(f1 text); ! create function p2text(p2) returns text as 'select $1.f1' language sql; ! create table c1(f3 int) inherits(p1,p2); ! insert into c1 values(123456789, 'hi', 42); ! select p2text(c1.*) from c1; ! p2text ! -------- ! hi ! (1 row) ! ! drop function p2text(p2); ! drop table c1; ! drop table p2; ! drop table p1; ! CREATE TABLE ac (aa TEXT); ! alter table ac add constraint ac_check check (aa is not null); ! CREATE TABLE bc (bb TEXT) INHERITS (ac); ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+----------+---------+------------+-------------+------------------ ! ac | ac_check | c | t | 0 | (aa IS NOT NULL) ! bc | ac_check | c | f | 1 | (aa IS NOT NULL) ! (2 rows) ! ! insert into ac (aa) values (NULL); ! ERROR: new row for relation "ac" violates check constraint "ac_check" ! DETAIL: Failing row contains (null). ! insert into bc (aa) values (NULL); ! ERROR: new row for relation "bc" violates check constraint "ac_check" ! DETAIL: Failing row contains (null, null). ! alter table bc drop constraint ac_check; -- fail, disallowed ! ERROR: cannot drop inherited constraint "ac_check" of relation "bc" ! alter table ac drop constraint ac_check; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+-------- ! (0 rows) ! ! -- try the unnamed-constraint case ! alter table ac add check (aa is not null); ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+-------------+---------+------------+-------------+------------------ ! ac | ac_aa_check | c | t | 0 | (aa IS NOT NULL) ! bc | ac_aa_check | c | f | 1 | (aa IS NOT NULL) ! (2 rows) ! ! insert into ac (aa) values (NULL); ! ERROR: new row for relation "ac" violates check constraint "ac_aa_check" ! DETAIL: Failing row contains (null). ! insert into bc (aa) values (NULL); ! ERROR: new row for relation "bc" violates check constraint "ac_aa_check" ! DETAIL: Failing row contains (null, null). ! alter table bc drop constraint ac_aa_check; -- fail, disallowed ! ERROR: cannot drop inherited constraint "ac_aa_check" of relation "bc" ! alter table ac drop constraint ac_aa_check; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+-------- ! (0 rows) ! ! alter table ac add constraint ac_check check (aa is not null); ! alter table bc no inherit ac; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+----------+---------+------------+-------------+------------------ ! ac | ac_check | c | t | 0 | (aa IS NOT NULL) ! bc | ac_check | c | t | 0 | (aa IS NOT NULL) ! (2 rows) ! ! alter table bc drop constraint ac_check; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+----------+---------+------------+-------------+------------------ ! ac | ac_check | c | t | 0 | (aa IS NOT NULL) ! (1 row) ! ! alter table ac drop constraint ac_check; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+-------- ! (0 rows) ! ! drop table bc; ! drop table ac; ! create table ac (a int constraint check_a check (a <> 0)); ! create table bc (a int constraint check_a check (a <> 0), b int constraint check_b check (b <> 0)) inherits (ac); ! NOTICE: merging column "a" with inherited definition ! NOTICE: merging constraint "check_a" with inherited definition ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+---------- ! ac | check_a | c | t | 0 | (a <> 0) ! bc | check_a | c | t | 1 | (a <> 0) ! bc | check_b | c | t | 0 | (b <> 0) ! (3 rows) ! ! drop table bc; ! drop table ac; ! create table ac (a int constraint check_a check (a <> 0)); ! create table bc (b int constraint check_b check (b <> 0)); ! create table cc (c int constraint check_c check (c <> 0)) inherits (ac, bc); ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+---------- ! ac | check_a | c | t | 0 | (a <> 0) ! bc | check_b | c | t | 0 | (b <> 0) ! cc | check_a | c | f | 1 | (a <> 0) ! cc | check_b | c | f | 1 | (b <> 0) ! cc | check_c | c | t | 0 | (c <> 0) ! (5 rows) ! ! alter table cc no inherit bc; ! select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc', 'cc') order by 1,2; ! relname | conname | contype | conislocal | coninhcount | consrc ! ---------+---------+---------+------------+-------------+---------- ! ac | check_a | c | t | 0 | (a <> 0) ! bc | check_b | c | t | 0 | (b <> 0) ! cc | check_a | c | f | 1 | (a <> 0) ! cc | check_b | c | t | 0 | (b <> 0) ! cc | check_c | c | t | 0 | (c <> 0) ! (5 rows) ! ! drop table cc; ! drop table bc; ! drop table ac; ! create table p1(f1 int); ! create table p2(f2 int); ! create table c1(f3 int) inherits(p1,p2); ! insert into c1 values(1,-1,2); ! alter table p2 add constraint cc check (f2>0); -- fail ! ERROR: check constraint "cc" is violated by some row ! alter table p2 add check (f2>0); -- check it without a name, too ! ERROR: check constraint "p2_f2_check" is violated by some row ! delete from c1; ! insert into c1 values(1,1,2); ! alter table p2 add check (f2>0); ! insert into c1 values(1,-1,2); -- fail ! ERROR: new row for relation "c1" violates check constraint "p2_f2_check" ! DETAIL: Failing row contains (1, -1, 2). ! create table c2(f3 int) inherits(p1,p2); ! \d c2 ! Table "public.c2" ! Column | Type | Modifiers ! --------+---------+----------- ! f1 | integer | ! f2 | integer | ! f3 | integer | ! Check constraints: ! "p2_f2_check" CHECK (f2 > 0) ! Inherits: p1, ! p2 ! ! create table c3 (f4 int) inherits(c1,c2); ! NOTICE: merging multiple inherited definitions of column "f1" ! NOTICE: merging multiple inherited definitions of column "f2" ! NOTICE: merging multiple inherited definitions of column "f3" ! \d c3 ! Table "public.c3" ! Column | Type | Modifiers ! --------+---------+----------- ! f1 | integer | ! f2 | integer | ! f3 | integer | ! f4 | integer | ! Check constraints: ! "p2_f2_check" CHECK (f2 > 0) ! Inherits: c1, ! c2 ! ! drop table p1 cascade; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to table c1 ! drop cascades to table c2 ! drop cascades to table c3 ! drop table p2 cascade; ! create table pp1 (f1 int); ! create table cc1 (f2 text, f3 int) inherits (pp1); ! alter table pp1 add column a1 int check (a1 > 0); ! \d cc1 ! Table "public.cc1" ! Column | Type | Modifiers ! --------+---------+----------- ! f1 | integer | ! f2 | text | ! f3 | integer | ! a1 | integer | ! Check constraints: ! "pp1_a1_check" CHECK (a1 > 0) ! Inherits: pp1 ! ! create table cc2(f4 float) inherits(pp1,cc1); ! NOTICE: merging multiple inherited definitions of column "f1" ! NOTICE: merging multiple inherited definitions of column "a1" ! \d cc2 ! Table "public.cc2" ! Column | Type | Modifiers ! --------+------------------+----------- ! f1 | integer | ! a1 | integer | ! f2 | text | ! f3 | integer | ! f4 | double precision | ! Check constraints: ! "pp1_a1_check" CHECK (a1 > 0) ! Inherits: pp1, ! cc1 ! ! alter table pp1 add column a2 int check (a2 > 0); ! NOTICE: merging definition of column "a2" for child "cc2" ! NOTICE: merging constraint "pp1_a2_check" with inherited definition ! \d cc2 ! Table "public.cc2" ! Column | Type | Modifiers ! --------+------------------+----------- ! f1 | integer | ! a1 | integer | ! f2 | text | ! f3 | integer | ! f4 | double precision | ! a2 | integer | ! Check constraints: ! "pp1_a1_check" CHECK (a1 > 0) ! "pp1_a2_check" CHECK (a2 > 0) ! Inherits: pp1, ! cc1 ! ! drop table pp1 cascade; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to table cc1 ! drop cascades to table cc2 ! -- Test for renaming in simple multiple inheritance ! CREATE TABLE inht1 (a int, b int); ! CREATE TABLE inhs1 (b int, c int); ! CREATE TABLE inhts (d int) INHERITS (inht1, inhs1); ! NOTICE: merging multiple inherited definitions of column "b" ! ALTER TABLE inht1 RENAME a TO aa; ! ALTER TABLE inht1 RENAME b TO bb; -- to be failed ! ERROR: cannot rename inherited column "b" ! ALTER TABLE inhts RENAME aa TO aaa; -- to be failed ! ERROR: cannot rename inherited column "aa" ! ALTER TABLE inhts RENAME d TO dd; ! \d+ inhts ! Table "public.inhts" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! aa | integer | | plain | | ! b | integer | | plain | | ! c | integer | | plain | | ! dd | integer | | plain | | ! Inherits: inht1, ! inhs1 ! ! DROP TABLE inhts; ! -- Test for renaming in diamond inheritance ! CREATE TABLE inht2 (x int) INHERITS (inht1); ! CREATE TABLE inht3 (y int) INHERITS (inht1); ! CREATE TABLE inht4 (z int) INHERITS (inht2, inht3); ! NOTICE: merging multiple inherited definitions of column "aa" ! NOTICE: merging multiple inherited definitions of column "b" ! ALTER TABLE inht1 RENAME aa TO aaa; ! \d+ inht4 ! Table "public.inht4" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! aaa | integer | | plain | | ! b | integer | | plain | | ! x | integer | | plain | | ! y | integer | | plain | | ! z | integer | | plain | | ! Inherits: inht2, ! inht3 ! ! CREATE TABLE inhts (d int) INHERITS (inht2, inhs1); ! NOTICE: merging multiple inherited definitions of column "b" ! ALTER TABLE inht1 RENAME aaa TO aaaa; ! ALTER TABLE inht1 RENAME b TO bb; -- to be failed ! ERROR: cannot rename inherited column "b" ! \d+ inhts ! Table "public.inhts" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! aaaa | integer | | plain | | ! b | integer | | plain | | ! x | integer | | plain | | ! c | integer | | plain | | ! d | integer | | plain | | ! Inherits: inht2, ! inhs1 ! ! WITH RECURSIVE r AS ( ! SELECT 'inht1'::regclass AS inhrelid ! UNION ALL ! SELECT c.inhrelid FROM pg_inherits c, r WHERE r.inhrelid = c.inhparent ! ) ! SELECT a.attrelid::regclass, a.attname, a.attinhcount, e.expected ! FROM (SELECT inhrelid, count(*) AS expected FROM pg_inherits ! WHERE inhparent IN (SELECT inhrelid FROM r) GROUP BY inhrelid) e ! JOIN pg_attribute a ON e.inhrelid = a.attrelid WHERE NOT attislocal ! ORDER BY a.attrelid::regclass::name, a.attnum; ! attrelid | attname | attinhcount | expected ! ----------+---------+-------------+---------- ! inht2 | aaaa | 1 | 1 ! inht2 | b | 1 | 1 ! inht3 | aaaa | 1 | 1 ! inht3 | b | 1 | 1 ! inht4 | aaaa | 2 | 2 ! inht4 | b | 2 | 2 ! inht4 | x | 1 | 2 ! inht4 | y | 1 | 2 ! inhts | aaaa | 1 | 1 ! inhts | b | 2 | 1 ! inhts | x | 1 | 1 ! inhts | c | 1 | 1 ! (12 rows) ! ! DROP TABLE inht1, inhs1 CASCADE; ! NOTICE: drop cascades to 4 other objects ! DETAIL: drop cascades to table inht2 ! drop cascades to table inhts ! drop cascades to table inht3 ! drop cascades to table inht4 ! -- Test non-inheritable indices [UNIQUE, EXCLUDE] contraints ! CREATE TABLE test_constraints (id int, val1 varchar, val2 int, UNIQUE(val1, val2)); ! CREATE TABLE test_constraints_inh () INHERITS (test_constraints); ! \d+ test_constraints ! Table "public.test_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+-------------------+-----------+----------+--------------+------------- ! id | integer | | plain | | ! val1 | character varying | | extended | | ! val2 | integer | | plain | | ! Indexes: ! "test_constraints_val1_val2_key" UNIQUE CONSTRAINT, btree (val1, val2) ! Child tables: test_constraints_inh ! ! ALTER TABLE ONLY test_constraints DROP CONSTRAINT test_constraints_val1_val2_key; ! \d+ test_constraints ! Table "public.test_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+-------------------+-----------+----------+--------------+------------- ! id | integer | | plain | | ! val1 | character varying | | extended | | ! val2 | integer | | plain | | ! Child tables: test_constraints_inh ! ! \d+ test_constraints_inh ! Table "public.test_constraints_inh" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+-------------------+-----------+----------+--------------+------------- ! id | integer | | plain | | ! val1 | character varying | | extended | | ! val2 | integer | | plain | | ! Inherits: test_constraints ! ! DROP TABLE test_constraints_inh; ! DROP TABLE test_constraints; ! CREATE TABLE test_ex_constraints ( ! c circle, ! EXCLUDE USING gist (c WITH &&) ! ); ! CREATE TABLE test_ex_constraints_inh () INHERITS (test_ex_constraints); ! \d+ test_ex_constraints ! Table "public.test_ex_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+--------+-----------+---------+--------------+------------- ! c | circle | | plain | | ! Indexes: ! "test_ex_constraints_c_excl" EXCLUDE USING gist (c WITH &&) ! Child tables: test_ex_constraints_inh ! ! ALTER TABLE test_ex_constraints DROP CONSTRAINT test_ex_constraints_c_excl; ! \d+ test_ex_constraints ! Table "public.test_ex_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+--------+-----------+---------+--------------+------------- ! c | circle | | plain | | ! Child tables: test_ex_constraints_inh ! ! \d+ test_ex_constraints_inh ! Table "public.test_ex_constraints_inh" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+--------+-----------+---------+--------------+------------- ! c | circle | | plain | | ! Inherits: test_ex_constraints ! ! DROP TABLE test_ex_constraints_inh; ! DROP TABLE test_ex_constraints; ! -- Test non-inheritable foreign key contraints ! CREATE TABLE test_primary_constraints(id int PRIMARY KEY); ! CREATE TABLE test_foreign_constraints(id1 int REFERENCES test_primary_constraints(id)); ! CREATE TABLE test_foreign_constraints_inh () INHERITS (test_foreign_constraints); ! \d+ test_primary_constraints ! Table "public.test_primary_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! id | integer | not null | plain | | ! Indexes: ! "test_primary_constraints_pkey" PRIMARY KEY, btree (id) ! Referenced by: ! TABLE "test_foreign_constraints" CONSTRAINT "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id) ! ! \d+ test_foreign_constraints ! Table "public.test_foreign_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! id1 | integer | | plain | | ! Foreign-key constraints: ! "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id) ! Child tables: test_foreign_constraints_inh ! ! ALTER TABLE test_foreign_constraints DROP CONSTRAINT test_foreign_constraints_id1_fkey; ! \d+ test_foreign_constraints ! Table "public.test_foreign_constraints" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! id1 | integer | | plain | | ! Child tables: test_foreign_constraints_inh ! ! \d+ test_foreign_constraints_inh ! Table "public.test_foreign_constraints_inh" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+---------+-----------+---------+--------------+------------- ! id1 | integer | | plain | | ! Inherits: test_foreign_constraints ! ! DROP TABLE test_foreign_constraints_inh; ! DROP TABLE test_foreign_constraints; ! DROP TABLE test_primary_constraints; ! -- ! -- Test parameterized append plans for inheritance trees ! -- ! create temp table patest0 (id, x) as ! select x, x from generate_series(0,1000) x; ! create temp table patest1() inherits (patest0); ! insert into patest1 ! select x, x from generate_series(0,1000) x; ! create temp table patest2() inherits (patest0); ! insert into patest2 ! select x, x from generate_series(0,1000) x; ! create index patest0i on patest0(id); ! create index patest1i on patest1(id); ! create index patest2i on patest2(id); ! analyze patest0; ! analyze patest1; ! analyze patest2; ! explain (costs off) ! select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; ! QUERY PLAN ! -------------------------------------------------- ! Nested Loop ! -> Limit ! -> Seq Scan on int4_tbl ! -> Append ! -> Index Scan using patest0i on patest0 ! Index Cond: (id = int4_tbl.f1) ! -> Index Scan using patest1i on patest1 ! Index Cond: (id = int4_tbl.f1) ! -> Index Scan using patest2i on patest2 ! Index Cond: (id = int4_tbl.f1) ! (10 rows) ! ! select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; ! id | x | f1 ! ----+---+---- ! 0 | 0 | 0 ! 0 | 0 | 0 ! 0 | 0 | 0 ! (3 rows) ! ! drop index patest2i; ! explain (costs off) ! select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; ! QUERY PLAN ! -------------------------------------------------- ! Nested Loop ! -> Limit ! -> Seq Scan on int4_tbl ! -> Append ! -> Index Scan using patest0i on patest0 ! Index Cond: (id = int4_tbl.f1) ! -> Index Scan using patest1i on patest1 ! Index Cond: (id = int4_tbl.f1) ! -> Seq Scan on patest2 ! Filter: (int4_tbl.f1 = id) ! (10 rows) ! ! select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; ! id | x | f1 ! ----+---+---- ! 0 | 0 | 0 ! 0 | 0 | 0 ! 0 | 0 | 0 ! (3 rows) ! ! drop table patest0 cascade; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to table patest1 ! drop cascades to table patest2 ! -- ! -- Test merge-append plans for inheritance trees ! -- ! create table matest0 (id serial primary key, name text); ! create table matest1 (id integer primary key) inherits (matest0); ! NOTICE: merging column "id" with inherited definition ! create table matest2 (id integer primary key) inherits (matest0); ! NOTICE: merging column "id" with inherited definition ! create table matest3 (id integer primary key) inherits (matest0); ! NOTICE: merging column "id" with inherited definition ! create index matest0i on matest0 ((1-id)); ! create index matest1i on matest1 ((1-id)); ! -- create index matest2i on matest2 ((1-id)); -- intentionally missing ! create index matest3i on matest3 ((1-id)); ! insert into matest1 (name) values ('Test 1'); ! insert into matest1 (name) values ('Test 2'); ! insert into matest2 (name) values ('Test 3'); ! insert into matest2 (name) values ('Test 4'); ! insert into matest3 (name) values ('Test 5'); ! insert into matest3 (name) values ('Test 6'); ! set enable_indexscan = off; -- force use of seqscan/sort, so no merge ! explain (verbose, costs off) select * from matest0 order by 1-id; ! QUERY PLAN ! ------------------------------------------------------------ ! Sort ! Output: matest0.id, matest0.name, ((1 - matest0.id)) ! Sort Key: ((1 - matest0.id)) ! -> Result ! Output: matest0.id, matest0.name, (1 - matest0.id) ! -> Append ! -> Seq Scan on public.matest0 ! Output: matest0.id, matest0.name ! -> Seq Scan on public.matest1 ! Output: matest1.id, matest1.name ! -> Seq Scan on public.matest2 ! Output: matest2.id, matest2.name ! -> Seq Scan on public.matest3 ! Output: matest3.id, matest3.name ! (14 rows) ! ! select * from matest0 order by 1-id; ! id | name ! ----+-------- ! 6 | Test 6 ! 5 | Test 5 ! 4 | Test 4 ! 3 | Test 3 ! 2 | Test 2 ! 1 | Test 1 ! (6 rows) ! ! explain (verbose, costs off) select min(1-id) from matest0; ! QUERY PLAN ! ---------------------------------------- ! Aggregate ! Output: min((1 - matest0.id)) ! -> Append ! -> Seq Scan on public.matest0 ! Output: matest0.id ! -> Seq Scan on public.matest1 ! Output: matest1.id ! -> Seq Scan on public.matest2 ! Output: matest2.id ! -> Seq Scan on public.matest3 ! Output: matest3.id ! (11 rows) ! ! select min(1-id) from matest0; ! min ! ----- ! -5 ! (1 row) ! ! reset enable_indexscan; ! set enable_seqscan = off; -- plan with fewest seqscans should be merge ! explain (verbose, costs off) select * from matest0 order by 1-id; ! QUERY PLAN ! ------------------------------------------------------------------ ! Merge Append ! Sort Key: ((1 - matest0.id)) ! -> Index Scan using matest0i on public.matest0 ! Output: matest0.id, matest0.name, (1 - matest0.id) ! -> Index Scan using matest1i on public.matest1 ! Output: matest1.id, matest1.name, (1 - matest1.id) ! -> Sort ! Output: matest2.id, matest2.name, ((1 - matest2.id)) ! Sort Key: ((1 - matest2.id)) ! -> Seq Scan on public.matest2 ! Output: matest2.id, matest2.name, (1 - matest2.id) ! -> Index Scan using matest3i on public.matest3 ! Output: matest3.id, matest3.name, (1 - matest3.id) ! (13 rows) ! ! select * from matest0 order by 1-id; ! id | name ! ----+-------- ! 6 | Test 6 ! 5 | Test 5 ! 4 | Test 4 ! 3 | Test 3 ! 2 | Test 2 ! 1 | Test 1 ! (6 rows) ! ! explain (verbose, costs off) select min(1-id) from matest0; ! QUERY PLAN ! -------------------------------------------------------------------------- ! Result ! Output: $0 ! InitPlan 1 (returns $0) ! -> Limit ! Output: ((1 - matest0.id)) ! -> Result ! Output: ((1 - matest0.id)) ! -> Merge Append ! Sort Key: ((1 - matest0.id)) ! -> Index Scan using matest0i on public.matest0 ! Output: matest0.id, (1 - matest0.id) ! Index Cond: ((1 - matest0.id) IS NOT NULL) ! -> Index Scan using matest1i on public.matest1 ! Output: matest1.id, (1 - matest1.id) ! Index Cond: ((1 - matest1.id) IS NOT NULL) ! -> Sort ! Output: matest2.id, ((1 - matest2.id)) ! Sort Key: ((1 - matest2.id)) ! -> Bitmap Heap Scan on public.matest2 ! Output: matest2.id, (1 - matest2.id) ! Filter: ((1 - matest2.id) IS NOT NULL) ! -> Bitmap Index Scan on matest2_pkey ! -> Index Scan using matest3i on public.matest3 ! Output: matest3.id, (1 - matest3.id) ! Index Cond: ((1 - matest3.id) IS NOT NULL) ! (25 rows) ! ! select min(1-id) from matest0; ! min ! ----- ! -5 ! (1 row) ! ! reset enable_seqscan; ! drop table matest0 cascade; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to table matest1 ! drop cascades to table matest2 ! drop cascades to table matest3 ! -- ! -- Test merge-append for UNION ALL append relations ! -- ! set enable_seqscan = off; ! set enable_indexscan = on; ! set enable_bitmapscan = off; ! -- Check handling of duplicated, constant, or volatile targetlist items ! explain (costs off) ! SELECT thousand, tenthous FROM tenk1 ! UNION ALL ! SELECT thousand, thousand FROM tenk1 ! ORDER BY thousand, tenthous; ! QUERY PLAN ! ------------------------------------------------------------------------- ! Merge Append ! Sort Key: tenk1.thousand, tenk1.tenthous ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 ! -> Sort ! Sort Key: tenk1_1.thousand, tenk1_1.thousand ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1 ! (6 rows) ! ! explain (costs off) ! SELECT thousand, tenthous, thousand+tenthous AS x FROM tenk1 ! UNION ALL ! SELECT 42, 42, hundred FROM tenk1 ! ORDER BY thousand, tenthous; ! QUERY PLAN ! ------------------------------------------------------------------ ! Merge Append ! Sort Key: tenk1.thousand, tenk1.tenthous ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 ! -> Sort ! Sort Key: (42), (42) ! -> Index Only Scan using tenk1_hundred on tenk1 tenk1_1 ! (6 rows) ! ! explain (costs off) ! SELECT thousand, tenthous FROM tenk1 ! UNION ALL ! SELECT thousand, random()::integer FROM tenk1 ! ORDER BY thousand, tenthous; ! QUERY PLAN ! ------------------------------------------------------------------------- ! Merge Append ! Sort Key: tenk1.thousand, tenk1.tenthous ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 ! -> Sort ! Sort Key: tenk1_1.thousand, ((random())::integer) ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1 ! (6 rows) ! ! -- Check min/max aggregate optimization ! explain (costs off) ! SELECT min(x) FROM ! (SELECT unique1 AS x FROM tenk1 a ! UNION ALL ! SELECT unique2 AS x FROM tenk1 b) s; ! QUERY PLAN ! -------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Merge Append ! Sort Key: a.unique1 ! -> Index Only Scan using tenk1_unique1 on tenk1 a ! Index Cond: (unique1 IS NOT NULL) ! -> Index Only Scan using tenk1_unique2 on tenk1 b ! Index Cond: (unique2 IS NOT NULL) ! (9 rows) ! ! explain (costs off) ! SELECT min(y) FROM ! (SELECT unique1 AS x, unique1 AS y FROM tenk1 a ! UNION ALL ! SELECT unique2 AS x, unique2 AS y FROM tenk1 b) s; ! QUERY PLAN ! -------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Merge Append ! Sort Key: a.unique1 ! -> Index Only Scan using tenk1_unique1 on tenk1 a ! Index Cond: (unique1 IS NOT NULL) ! -> Index Only Scan using tenk1_unique2 on tenk1 b ! Index Cond: (unique2 IS NOT NULL) ! (9 rows) ! ! -- XXX planner doesn't recognize that index on unique2 is sufficiently sorted ! explain (costs off) ! SELECT x, y FROM ! (SELECT thousand AS x, tenthous AS y FROM tenk1 a ! UNION ALL ! SELECT unique2 AS x, unique2 AS y FROM tenk1 b) s ! ORDER BY x, y; ! QUERY PLAN ! ------------------------------------------------------------- ! Merge Append ! Sort Key: a.thousand, a.tenthous ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 a ! -> Sort ! Sort Key: b.unique2, b.unique2 ! -> Index Only Scan using tenk1_unique2 on tenk1 b ! (6 rows) ! ! -- exercise rescan code path via a repeatedly-evaluated subquery ! explain (costs off) ! SELECT ! ARRAY(SELECT f.i FROM ( ! (SELECT d + g.i FROM generate_series(4, 30, 3) d ORDER BY 1) ! UNION ALL ! (SELECT d + g.i FROM generate_series(0, 30, 5) d ORDER BY 1) ! ) f(i) ! ORDER BY f.i LIMIT 10) ! FROM generate_series(1, 3) g(i); ! QUERY PLAN ! ---------------------------------------------------------------- ! Function Scan on generate_series g ! SubPlan 1 ! -> Limit ! -> Merge Append ! Sort Key: ((d.d + g.i)) ! -> Sort ! Sort Key: ((d.d + g.i)) ! -> Function Scan on generate_series d ! -> Sort ! Sort Key: ((d_1.d + g.i)) ! -> Function Scan on generate_series d_1 ! (11 rows) ! ! SELECT ! ARRAY(SELECT f.i FROM ( ! (SELECT d + g.i FROM generate_series(4, 30, 3) d ORDER BY 1) ! UNION ALL ! (SELECT d + g.i FROM generate_series(0, 30, 5) d ORDER BY 1) ! ) f(i) ! ORDER BY f.i LIMIT 10) ! FROM generate_series(1, 3) g(i); ! array ! ------------------------------ ! {1,5,6,8,11,11,14,16,17,20} ! {2,6,7,9,12,12,15,17,18,21} ! {3,7,8,10,13,13,16,18,19,22} ! (3 rows) ! ! reset enable_seqscan; ! reset enable_indexscan; ! reset enable_bitmapscan; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/create_table_like.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/create_table_like.out Tue Oct 28 15:53:05 2014 *************** *** 1,230 **** ! /* Test inheritance of structure (LIKE) */ ! CREATE TABLE inhx (xx text DEFAULT 'text'); ! /* ! * Test double inheritance ! * ! * Ensure that defaults are NOT included unless ! * INCLUDING DEFAULTS is specified ! */ ! CREATE TABLE ctla (aa TEXT); ! CREATE TABLE ctlb (bb TEXT) INHERITS (ctla); ! CREATE TABLE foo (LIKE nonexistent); ! ERROR: relation "nonexistent" does not exist ! LINE 1: CREATE TABLE foo (LIKE nonexistent); ! ^ ! CREATE TABLE inhe (ee text, LIKE inhx) inherits (ctlb); ! INSERT INTO inhe VALUES ('ee-col1', 'ee-col2', DEFAULT, 'ee-col4'); ! SELECT * FROM inhe; /* Columns aa, bb, xx value NULL, ee */ ! aa | bb | ee | xx ! ---------+---------+----+--------- ! ee-col1 | ee-col2 | | ee-col4 ! (1 row) ! ! SELECT * FROM inhx; /* Empty set since LIKE inherits structure only */ ! xx ! ---- ! (0 rows) ! ! SELECT * FROM ctlb; /* Has ee entry */ ! aa | bb ! ---------+--------- ! ee-col1 | ee-col2 ! (1 row) ! ! SELECT * FROM ctla; /* Has ee entry */ ! aa ! --------- ! ee-col1 ! (1 row) ! ! CREATE TABLE inhf (LIKE inhx, LIKE inhx); /* Throw error */ ! ERROR: column "xx" specified more than once ! CREATE TABLE inhf (LIKE inhx INCLUDING DEFAULTS INCLUDING CONSTRAINTS); ! INSERT INTO inhf DEFAULT VALUES; ! SELECT * FROM inhf; /* Single entry with value 'text' */ ! xx ! ------ ! text ! (1 row) ! ! ALTER TABLE inhx add constraint foo CHECK (xx = 'text'); ! ALTER TABLE inhx ADD PRIMARY KEY (xx); ! CREATE TABLE inhg (LIKE inhx); /* Doesn't copy constraint */ ! INSERT INTO inhg VALUES ('foo'); ! DROP TABLE inhg; ! CREATE TABLE inhg (x text, LIKE inhx INCLUDING CONSTRAINTS, y text); /* Copies constraints */ ! INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Succeeds */ ! INSERT INTO inhg VALUES ('x', 'text', 'y'); /* Succeeds -- Unique constraints not copied */ ! INSERT INTO inhg VALUES ('x', 'foo', 'y'); /* fails due to constraint */ ! ERROR: new row for relation "inhg" violates check constraint "foo" ! DETAIL: Failing row contains (x, foo, y). ! SELECT * FROM inhg; /* Two records with three columns in order x=x, xx=text, y=y */ ! x | xx | y ! ---+------+--- ! x | text | y ! x | text | y ! (2 rows) ! ! DROP TABLE inhg; ! CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, y text); /* copies indexes */ ! INSERT INTO inhg VALUES (5, 10); ! INSERT INTO inhg VALUES (20, 10); -- should fail ! ERROR: duplicate key value violates unique constraint "inhg_pkey" ! DETAIL: Key (xx)=(10) already exists. ! DROP TABLE inhg; ! /* Multiple primary keys creation should fail */ ! CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, PRIMARY KEY(x)); /* fails */ ! ERROR: multiple primary keys for table "inhg" are not allowed ! CREATE TABLE inhz (xx text DEFAULT 'text', yy int UNIQUE); ! CREATE UNIQUE INDEX inhz_xx_idx on inhz (xx) WHERE xx <> 'test'; ! /* Ok to create multiple unique indexes */ ! CREATE TABLE inhg (x text UNIQUE, LIKE inhz INCLUDING INDEXES); ! INSERT INTO inhg (xx, yy, x) VALUES ('test', 5, 10); ! INSERT INTO inhg (xx, yy, x) VALUES ('test', 10, 15); ! INSERT INTO inhg (xx, yy, x) VALUES ('foo', 10, 15); -- should fail ! ERROR: duplicate key value violates unique constraint "inhg_x_key" ! DETAIL: Key (x)=(15) already exists. ! DROP TABLE inhg; ! DROP TABLE inhz; ! -- including storage and comments ! CREATE TABLE ctlt1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text); ! CREATE INDEX ctlt1_b_key ON ctlt1 (b); ! CREATE INDEX ctlt1_fnidx ON ctlt1 ((a || b)); ! COMMENT ON COLUMN ctlt1.a IS 'A'; ! COMMENT ON COLUMN ctlt1.b IS 'B'; ! COMMENT ON CONSTRAINT ctlt1_a_check ON ctlt1 IS 't1_a_check'; ! COMMENT ON INDEX ctlt1_pkey IS 'index pkey'; ! COMMENT ON INDEX ctlt1_b_key IS 'index b_key'; ! ALTER TABLE ctlt1 ALTER COLUMN a SET STORAGE MAIN; ! CREATE TABLE ctlt2 (c text); ! ALTER TABLE ctlt2 ALTER COLUMN c SET STORAGE EXTERNAL; ! COMMENT ON COLUMN ctlt2.c IS 'C'; ! CREATE TABLE ctlt3 (a text CHECK (length(a) < 5), c text); ! ALTER TABLE ctlt3 ALTER COLUMN c SET STORAGE EXTERNAL; ! ALTER TABLE ctlt3 ALTER COLUMN a SET STORAGE MAIN; ! COMMENT ON COLUMN ctlt3.a IS 'A3'; ! COMMENT ON COLUMN ctlt3.c IS 'C'; ! COMMENT ON CONSTRAINT ctlt3_a_check ON ctlt3 IS 't3_a_check'; ! CREATE TABLE ctlt4 (a text, c text); ! ALTER TABLE ctlt4 ALTER COLUMN c SET STORAGE EXTERNAL; ! CREATE TABLE ctlt12_storage (LIKE ctlt1 INCLUDING STORAGE, LIKE ctlt2 INCLUDING STORAGE); ! \d+ ctlt12_storage ! Table "public.ctlt12_storage" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | main | | ! b | text | | extended | | ! c | text | | external | | ! ! CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDING COMMENTS); ! \d+ ctlt12_comments ! Table "public.ctlt12_comments" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | extended | | A ! b | text | | extended | | B ! c | text | | extended | | C ! ! CREATE TABLE ctlt1_inh (LIKE ctlt1 INCLUDING CONSTRAINTS INCLUDING COMMENTS) INHERITS (ctlt1); ! NOTICE: merging column "a" with inherited definition ! NOTICE: merging column "b" with inherited definition ! NOTICE: merging constraint "ctlt1_a_check" with inherited definition ! \d+ ctlt1_inh ! Table "public.ctlt1_inh" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | main | | A ! b | text | | extended | | B ! Check constraints: ! "ctlt1_a_check" CHECK (length(a) > 2) ! Inherits: ctlt1 ! ! SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt1_inh'::regclass; ! description ! ------------- ! t1_a_check ! (1 row) ! ! CREATE TABLE ctlt13_inh () INHERITS (ctlt1, ctlt3); ! NOTICE: merging multiple inherited definitions of column "a" ! \d+ ctlt13_inh ! Table "public.ctlt13_inh" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | main | | ! b | text | | extended | | ! c | text | | external | | ! Check constraints: ! "ctlt1_a_check" CHECK (length(a) > 2) ! "ctlt3_a_check" CHECK (length(a) < 5) ! Inherits: ctlt1, ! ctlt3 ! ! CREATE TABLE ctlt13_like (LIKE ctlt3 INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (ctlt1); ! NOTICE: merging column "a" with inherited definition ! \d+ ctlt13_like ! Table "public.ctlt13_like" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | main | | A3 ! b | text | | extended | | ! c | text | | external | | C ! Check constraints: ! "ctlt1_a_check" CHECK (length(a) > 2) ! "ctlt3_a_check" CHECK (length(a) < 5) ! Inherits: ctlt1 ! ! SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt13_like'::regclass; ! description ! ------------- ! t3_a_check ! (1 row) ! ! CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL); ! \d+ ctlt_all ! Table "public.ctlt_all" ! Column | Type | Modifiers | Storage | Stats target | Description ! --------+------+-----------+----------+--------------+------------- ! a | text | not null | main | | A ! b | text | | extended | | B ! Indexes: ! "ctlt_all_pkey" PRIMARY KEY, btree (a) ! "ctlt_all_b_idx" btree (b) ! "ctlt_all_expr_idx" btree ((a || b)) ! Check constraints: ! "ctlt1_a_check" CHECK (length(a) > 2) ! ! SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 'ctlt_all'::regclass ORDER BY c.relname, objsubid; ! relname | objsubid | description ! ----------------+----------+------------- ! ctlt_all_b_idx | 0 | index b_key ! ctlt_all_pkey | 0 | index pkey ! (2 rows) ! ! CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4); ! NOTICE: merging multiple inherited definitions of column "a" ! ERROR: inherited column "a" has a storage parameter conflict ! DETAIL: MAIN versus EXTENDED ! CREATE TABLE inh_error2 (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); ! NOTICE: merging column "a" with inherited definition ! ERROR: column "a" has a storage parameter conflict ! DETAIL: MAIN versus EXTENDED ! DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE; ! NOTICE: drop cascades to table inhe ! /* LIKE with other relation kinds */ ! CREATE TABLE ctlt4 (a int, b text); ! CREATE SEQUENCE ctlseq1; ! CREATE TABLE ctlt10 (LIKE ctlseq1); -- fail ! ERROR: "ctlseq1" is not a table, view, materialized view, composite type, or foreign table ! LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1); ! ^ ! CREATE VIEW ctlv1 AS SELECT * FROM ctlt4; ! CREATE TABLE ctlt11 (LIKE ctlv1); ! CREATE TABLE ctlt11a (LIKE ctlv1 INCLUDING ALL); ! CREATE TYPE ctlty1 AS (a int, b text); ! CREATE TABLE ctlt12 (LIKE ctlty1); ! DROP SEQUENCE ctlseq1; ! DROP TYPE ctlty1; ! DROP VIEW ctlv1; ! DROP TABLE IF EXISTS ctlt4, ctlt10, ctlt11, ctlt11a, ctlt12; ! NOTICE: table "ctlt10" does not exist, skipping --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/typed_table.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/typed_table.out Tue Oct 28 15:53:05 2014 *************** *** 1,108 **** ! CREATE TABLE ttable1 OF nothing; ! ERROR: type "nothing" does not exist ! CREATE TYPE person_type AS (id int, name text); ! CREATE TABLE persons OF person_type; ! CREATE TABLE IF NOT EXISTS persons OF person_type; ! NOTICE: relation "persons" already exists, skipping ! SELECT * FROM persons; ! id | name ! ----+------ ! (0 rows) ! ! \d persons ! Table "public.persons" ! Column | Type | Modifiers ! --------+---------+----------- ! id | integer | ! name | text | ! Typed table of type: person_type ! ! CREATE FUNCTION get_all_persons() RETURNS SETOF person_type ! LANGUAGE SQL ! AS $$ ! SELECT * FROM persons; ! $$; ! SELECT * FROM get_all_persons(); ! id | name ! ----+------ ! (0 rows) ! ! -- certain ALTER TABLE operations on typed tables are not allowed ! ALTER TABLE persons ADD COLUMN comment text; ! ERROR: cannot add column to typed table ! ALTER TABLE persons DROP COLUMN name; ! ERROR: cannot drop column from typed table ! ALTER TABLE persons RENAME COLUMN id TO num; ! ERROR: cannot rename column of typed table ! ALTER TABLE persons ALTER COLUMN name TYPE varchar; ! ERROR: cannot alter column type of typed table ! CREATE TABLE stuff (id int); ! ALTER TABLE persons INHERIT stuff; ! ERROR: cannot change inheritance of typed table ! CREATE TABLE personsx OF person_type (myname WITH OPTIONS NOT NULL); -- error ! ERROR: column "myname" does not exist ! CREATE TABLE persons2 OF person_type ( ! id WITH OPTIONS PRIMARY KEY, ! UNIQUE (name) ! ); ! \d persons2 ! Table "public.persons2" ! Column | Type | Modifiers ! --------+---------+----------- ! id | integer | not null ! name | text | ! Indexes: ! "persons2_pkey" PRIMARY KEY, btree (id) ! "persons2_name_key" UNIQUE CONSTRAINT, btree (name) ! Typed table of type: person_type ! ! CREATE TABLE persons3 OF person_type ( ! PRIMARY KEY (id), ! name WITH OPTIONS DEFAULT '' ! ); ! \d persons3 ! Table "public.persons3" ! Column | Type | Modifiers ! --------+---------+------------------ ! id | integer | not null ! name | text | default ''::text ! Indexes: ! "persons3_pkey" PRIMARY KEY, btree (id) ! Typed table of type: person_type ! ! CREATE TABLE persons4 OF person_type ( ! name WITH OPTIONS NOT NULL, ! name WITH OPTIONS DEFAULT '' -- error, specified more than once ! ); ! ERROR: column "name" specified more than once ! DROP TYPE person_type RESTRICT; ! ERROR: cannot drop type person_type because other objects depend on it ! DETAIL: table persons depends on type person_type ! function get_all_persons() depends on type person_type ! table persons2 depends on type person_type ! table persons3 depends on type person_type ! HINT: Use DROP ... CASCADE to drop the dependent objects too. ! DROP TYPE person_type CASCADE; ! NOTICE: drop cascades to 4 other objects ! DETAIL: drop cascades to table persons ! drop cascades to function get_all_persons() ! drop cascades to table persons2 ! drop cascades to table persons3 ! CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used ! ERROR: type stuff is not a composite type ! DROP TABLE stuff; ! -- implicit casting ! CREATE TYPE person_type AS (id int, name text); ! CREATE TABLE persons OF person_type; ! INSERT INTO persons VALUES (1, 'test'); ! CREATE FUNCTION namelen(person_type) RETURNS int LANGUAGE SQL AS $$ SELECT length($1.name) $$; ! SELECT id, namelen(persons) FROM persons; ! id | namelen ! ----+--------- ! 1 | 4 ! (1 row) ! ! DROP TYPE person_type CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to table persons ! drop cascades to function namelen(person_type) --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/vacuum.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/vacuum.out Tue Oct 28 15:53:05 2014 *************** *** 1,71 **** ! -- ! -- VACUUM ! -- ! CREATE TABLE vactst (i INT); ! INSERT INTO vactst VALUES (1); ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst VALUES (0); ! SELECT count(*) FROM vactst; ! count ! ------- ! 2049 ! (1 row) ! ! DELETE FROM vactst WHERE i != 0; ! SELECT * FROM vactst; ! i ! --- ! 0 ! (1 row) ! ! VACUUM FULL vactst; ! UPDATE vactst SET i = i + 1; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst SELECT * FROM vactst; ! INSERT INTO vactst VALUES (0); ! SELECT count(*) FROM vactst; ! count ! ------- ! 2049 ! (1 row) ! ! DELETE FROM vactst WHERE i != 0; ! VACUUM (FULL) vactst; ! DELETE FROM vactst; ! SELECT * FROM vactst; ! i ! --- ! (0 rows) ! ! VACUUM (FULL, FREEZE) vactst; ! VACUUM (ANALYZE, FULL) vactst; ! CREATE TABLE vaccluster (i INT PRIMARY KEY); ! ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey; ! INSERT INTO vaccluster SELECT * FROM vactst; ! CLUSTER vaccluster; ! VACUUM FULL pg_am; ! VACUUM FULL pg_class; ! VACUUM FULL pg_database; ! VACUUM FULL vaccluster; ! VACUUM FULL vactst; ! DROP TABLE vaccluster; ! DROP TABLE vactst; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/drop_if_exists.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/drop_if_exists.out Tue Oct 28 15:53:05 2014 *************** *** 1,298 **** ! -- ! -- IF EXISTS tests ! -- ! -- table (will be really dropped at the end) ! DROP TABLE test_exists; ! ERROR: table "test_exists" does not exist ! DROP TABLE IF EXISTS test_exists; ! NOTICE: table "test_exists" does not exist, skipping ! CREATE TABLE test_exists (a int, b text); ! -- view ! DROP VIEW test_view_exists; ! ERROR: view "test_view_exists" does not exist ! DROP VIEW IF EXISTS test_view_exists; ! NOTICE: view "test_view_exists" does not exist, skipping ! CREATE VIEW test_view_exists AS select * from test_exists; ! DROP VIEW IF EXISTS test_view_exists; ! DROP VIEW test_view_exists; ! ERROR: view "test_view_exists" does not exist ! -- index ! DROP INDEX test_index_exists; ! ERROR: index "test_index_exists" does not exist ! DROP INDEX IF EXISTS test_index_exists; ! NOTICE: index "test_index_exists" does not exist, skipping ! CREATE INDEX test_index_exists on test_exists(a); ! DROP INDEX IF EXISTS test_index_exists; ! DROP INDEX test_index_exists; ! ERROR: index "test_index_exists" does not exist ! -- sequence ! DROP SEQUENCE test_sequence_exists; ! ERROR: sequence "test_sequence_exists" does not exist ! DROP SEQUENCE IF EXISTS test_sequence_exists; ! NOTICE: sequence "test_sequence_exists" does not exist, skipping ! CREATE SEQUENCE test_sequence_exists; ! DROP SEQUENCE IF EXISTS test_sequence_exists; ! DROP SEQUENCE test_sequence_exists; ! ERROR: sequence "test_sequence_exists" does not exist ! -- schema ! DROP SCHEMA test_schema_exists; ! ERROR: schema "test_schema_exists" does not exist ! DROP SCHEMA IF EXISTS test_schema_exists; ! NOTICE: schema "test_schema_exists" does not exist, skipping ! CREATE SCHEMA test_schema_exists; ! DROP SCHEMA IF EXISTS test_schema_exists; ! DROP SCHEMA test_schema_exists; ! ERROR: schema "test_schema_exists" does not exist ! -- type ! DROP TYPE test_type_exists; ! ERROR: type "test_type_exists" does not exist ! DROP TYPE IF EXISTS test_type_exists; ! NOTICE: type "test_type_exists" does not exist, skipping ! CREATE type test_type_exists as (a int, b text); ! DROP TYPE IF EXISTS test_type_exists; ! DROP TYPE test_type_exists; ! ERROR: type "test_type_exists" does not exist ! -- domain ! DROP DOMAIN test_domain_exists; ! ERROR: type "test_domain_exists" does not exist ! DROP DOMAIN IF EXISTS test_domain_exists; ! NOTICE: type "test_domain_exists" does not exist, skipping ! CREATE domain test_domain_exists as int not null check (value > 0); ! DROP DOMAIN IF EXISTS test_domain_exists; ! DROP DOMAIN test_domain_exists; ! ERROR: type "test_domain_exists" does not exist ! --- ! --- role/user/group ! --- ! CREATE USER tu1; ! CREATE ROLE tr1; ! CREATE GROUP tg1; ! DROP USER tu2; ! ERROR: role "tu2" does not exist ! DROP USER IF EXISTS tu1, tu2; ! NOTICE: role "tu2" does not exist, skipping ! DROP USER tu1; ! ERROR: role "tu1" does not exist ! DROP ROLE tr2; ! ERROR: role "tr2" does not exist ! DROP ROLE IF EXISTS tr1, tr2; ! NOTICE: role "tr2" does not exist, skipping ! DROP ROLE tr1; ! ERROR: role "tr1" does not exist ! DROP GROUP tg2; ! ERROR: role "tg2" does not exist ! DROP GROUP IF EXISTS tg1, tg2; ! NOTICE: role "tg2" does not exist, skipping ! DROP GROUP tg1; ! ERROR: role "tg1" does not exist ! -- collation ! DROP COLLATION IF EXISTS test_collation_exists; ! NOTICE: collation "test_collation_exists" does not exist, skipping ! -- conversion ! DROP CONVERSION test_conversion_exists; ! ERROR: conversion "test_conversion_exists" does not exist ! DROP CONVERSION IF EXISTS test_conversion_exists; ! NOTICE: conversion "test_conversion_exists" does not exist, skipping ! CREATE CONVERSION test_conversion_exists ! FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8; ! DROP CONVERSION test_conversion_exists; ! -- text search parser ! DROP TEXT SEARCH PARSER test_tsparser_exists; ! ERROR: text search parser "test_tsparser_exists" does not exist ! DROP TEXT SEARCH PARSER IF EXISTS test_tsparser_exists; ! NOTICE: text search parser "test_tsparser_exists" does not exist, skipping ! -- text search dictionary ! DROP TEXT SEARCH DICTIONARY test_tsdict_exists; ! ERROR: text search dictionary "test_tsdict_exists" does not exist ! DROP TEXT SEARCH DICTIONARY IF EXISTS test_tsdict_exists; ! NOTICE: text search dictionary "test_tsdict_exists" does not exist, skipping ! CREATE TEXT SEARCH DICTIONARY test_tsdict_exists ( ! Template=ispell, ! DictFile=ispell_sample, ! AffFile=ispell_sample ! ); ! DROP TEXT SEARCH DICTIONARY test_tsdict_exists; ! -- test search template ! DROP TEXT SEARCH TEMPLATE test_tstemplate_exists; ! ERROR: text search template "test_tstemplate_exists" does not exist ! DROP TEXT SEARCH TEMPLATE IF EXISTS test_tstemplate_exists; ! NOTICE: text search template "test_tstemplate_exists" does not exist, skipping ! -- text search configuration ! DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists; ! ERROR: text search configuration "test_tsconfig_exists" does not exist ! DROP TEXT SEARCH CONFIGURATION IF EXISTS test_tsconfig_exists; ! NOTICE: text search configuration "test_tsconfig_exists" does not exist, skipping ! CREATE TEXT SEARCH CONFIGURATION test_tsconfig_exists (COPY=english); ! DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists; ! -- extension ! DROP EXTENSION test_extension_exists; ! ERROR: extension "test_extension_exists" does not exist ! DROP EXTENSION IF EXISTS test_extension_exists; ! NOTICE: extension "test_extension_exists" does not exist, skipping ! -- functions ! DROP FUNCTION test_function_exists(); ! ERROR: function test_function_exists() does not exist ! DROP FUNCTION IF EXISTS test_function_exists(); ! NOTICE: function test_function_exists() does not exist, skipping ! DROP FUNCTION test_function_exists(int, text, int[]); ! ERROR: function test_function_exists(integer, text, integer[]) does not exist ! DROP FUNCTION IF EXISTS test_function_exists(int, text, int[]); ! NOTICE: function test_function_exists(pg_catalog.int4,text,pg_catalog.int4[]) does not exist, skipping ! -- aggregate ! DROP AGGREGATE test_aggregate_exists(*); ! ERROR: aggregate test_aggregate_exists(*) does not exist ! DROP AGGREGATE IF EXISTS test_aggregate_exists(*); ! NOTICE: aggregate test_aggregate_exists() does not exist, skipping ! DROP AGGREGATE test_aggregate_exists(int); ! ERROR: aggregate test_aggregate_exists(integer) does not exist ! DROP AGGREGATE IF EXISTS test_aggregate_exists(int); ! NOTICE: aggregate test_aggregate_exists(pg_catalog.int4) does not exist, skipping ! -- operator ! DROP OPERATOR @#@ (int, int); ! ERROR: operator does not exist: integer @#@ integer ! DROP OPERATOR IF EXISTS @#@ (int, int); ! NOTICE: operator @#@ does not exist, skipping ! CREATE OPERATOR @#@ ! (leftarg = int8, rightarg = int8, procedure = int8xor); ! DROP OPERATOR @#@ (int8, int8); ! -- language ! DROP LANGUAGE test_language_exists; ! ERROR: language "test_language_exists" does not exist ! DROP LANGUAGE IF EXISTS test_language_exists; ! NOTICE: language "test_language_exists" does not exist, skipping ! -- cast ! DROP CAST (text AS text); ! ERROR: cast from type text to type text does not exist ! DROP CAST IF EXISTS (text AS text); ! NOTICE: cast from type text to type text does not exist, skipping ! -- trigger ! DROP TRIGGER test_trigger_exists ON test_exists; ! ERROR: trigger "test_trigger_exists" for table "test_exists" does not exist ! DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists; ! NOTICE: trigger "test_trigger_exists" for relation "test_exists" does not exist, skipping ! DROP TRIGGER test_trigger_exists ON no_such_table; ! ERROR: relation "no_such_table" does not exist ! DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table; ! NOTICE: relation "no_such_table" does not exist, skipping ! DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table; ! ERROR: schema "no_such_schema" does not exist ! DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table; ! NOTICE: schema "no_such_schema" does not exist, skipping ! CREATE TRIGGER test_trigger_exists ! BEFORE UPDATE ON test_exists ! FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); ! DROP TRIGGER test_trigger_exists ON test_exists; ! -- rule ! DROP RULE test_rule_exists ON test_exists; ! ERROR: rule "test_rule_exists" for relation "test_exists" does not exist ! DROP RULE IF EXISTS test_rule_exists ON test_exists; ! NOTICE: rule "test_rule_exists" for relation "test_exists" does not exist, skipping ! DROP RULE test_rule_exists ON no_such_table; ! ERROR: relation "no_such_table" does not exist ! DROP RULE IF EXISTS test_rule_exists ON no_such_table; ! NOTICE: relation "no_such_table" does not exist, skipping ! DROP RULE test_rule_exists ON no_such_schema.no_such_table; ! ERROR: schema "no_such_schema" does not exist ! DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table; ! NOTICE: schema "no_such_schema" does not exist, skipping ! CREATE RULE test_rule_exists AS ON INSERT TO test_exists ! DO INSTEAD ! INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text); ! DROP RULE test_rule_exists ON test_exists; ! -- foreign data wrapper ! DROP FOREIGN DATA WRAPPER test_fdw_exists; ! ERROR: foreign-data wrapper "test_fdw_exists" does not exist ! DROP FOREIGN DATA WRAPPER IF EXISTS test_fdw_exists; ! NOTICE: foreign-data wrapper "test_fdw_exists" does not exist, skipping ! -- foreign server ! DROP SERVER test_server_exists; ! ERROR: server "test_server_exists" does not exist ! DROP SERVER IF EXISTS test_server_exists; ! NOTICE: server "test_server_exists" does not exist, skipping ! -- operator class ! DROP OPERATOR CLASS test_operator_class USING btree; ! ERROR: operator class "test_operator_class" does not exist for access method "btree" ! DROP OPERATOR CLASS IF EXISTS test_operator_class USING btree; ! NOTICE: operator class "test_operator_class" does not exist for access method "btree", skipping ! DROP OPERATOR CLASS test_operator_class USING no_such_am; ! ERROR: access method "no_such_am" does not exist ! DROP OPERATOR CLASS IF EXISTS test_operator_class USING no_such_am; ! ERROR: access method "no_such_am" does not exist ! -- operator family ! DROP OPERATOR FAMILY test_operator_family USING btree; ! ERROR: operator family "test_operator_family" does not exist for access method "btree" ! DROP OPERATOR FAMILY IF EXISTS test_operator_family USING btree; ! NOTICE: operator family "test_operator_family" does not exist for access method "btree", skipping ! DROP OPERATOR FAMILY test_operator_family USING no_such_am; ! ERROR: access method "no_such_am" does not exist ! DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am; ! ERROR: access method "no_such_am" does not exist ! -- drop the table ! DROP TABLE IF EXISTS test_exists; ! DROP TABLE test_exists; ! ERROR: table "test_exists" does not exist ! -- be tolerant with missing schemas, types, etc ! DROP AGGREGATE IF EXISTS no_such_schema.foo(int); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP AGGREGATE IF EXISTS foo(no_such_type); ! NOTICE: type "no_such_type" does not exist, skipping ! DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP CAST IF EXISTS (INTEGER AS no_such_type2); ! NOTICE: type "no_such_type2" does not exist, skipping ! DROP CAST IF EXISTS (no_such_type1 AS INTEGER); ! NOTICE: type "no_such_type1" does not exist, skipping ! DROP CAST IF EXISTS (INTEGER AS no_such_schema.bar); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP CAST IF EXISTS (no_such_schema.foo AS INTEGER); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP COLLATION IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP CONVERSION IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP DOMAIN IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP FOREIGN TABLE IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP FUNCTION IF EXISTS no_such_schema.foo(); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP FUNCTION IF EXISTS foo(no_such_type); ! NOTICE: type "no_such_type" does not exist, skipping ! DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP INDEX IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP OPERATOR IF EXISTS no_such_schema.+ (int, int); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP OPERATOR IF EXISTS + (no_such_type, no_such_type); ! NOTICE: type "no_such_type" does not exist, skipping ! DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP OPERATOR IF EXISTS # (NONE, no_such_schema.no_such_type); ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP RULE IF EXISTS foo ON no_such_schema.bar; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP SEQUENCE IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TABLE IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TRIGGER IF EXISTS foo ON no_such_schema.bar; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP TYPE IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping ! DROP VIEW IF EXISTS no_such_schema.foo; ! NOTICE: schema "no_such_schema" does not exist, skipping --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/updatable_views.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/updatable_views.out Tue Oct 28 15:53:05 2014 *************** *** 1,2266 **** ! -- ! -- UPDATABLE VIEWS ! -- ! -- check that non-updatable views and columns are rejected with useful error ! -- messages ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW ro_view1 AS SELECT DISTINCT a, b FROM base_tbl; -- DISTINCT not supported ! CREATE VIEW ro_view2 AS SELECT a, b FROM base_tbl GROUP BY a, b; -- GROUP BY not supported ! CREATE VIEW ro_view3 AS SELECT 1 FROM base_tbl HAVING max(a) > 0; -- HAVING not supported ! CREATE VIEW ro_view4 AS SELECT count(*) FROM base_tbl; -- Aggregate functions not supported ! CREATE VIEW ro_view5 AS SELECT a, rank() OVER() FROM base_tbl; -- Window functions not supported ! CREATE VIEW ro_view6 AS SELECT a, b FROM base_tbl UNION SELECT -a, b FROM base_tbl; -- Set ops not supported ! CREATE VIEW ro_view7 AS WITH t AS (SELECT a, b FROM base_tbl) SELECT * FROM t; -- WITH not supported ! CREATE VIEW ro_view8 AS SELECT a, b FROM base_tbl ORDER BY a OFFSET 1; -- OFFSET not supported ! CREATE VIEW ro_view9 AS SELECT a, b FROM base_tbl ORDER BY a LIMIT 1; -- LIMIT not supported ! CREATE VIEW ro_view10 AS SELECT 1 AS a; -- No base relations ! CREATE VIEW ro_view11 AS SELECT b1.a, b2.b FROM base_tbl b1, base_tbl b2; -- Multiple base relations ! CREATE VIEW ro_view12 AS SELECT * FROM generate_series(1, 10) AS g(a); -- SRF in rangetable ! CREATE VIEW ro_view13 AS SELECT a, b FROM (SELECT * FROM base_tbl) AS t; -- Subselect in rangetable ! CREATE VIEW rw_view14 AS SELECT ctid, a, b FROM base_tbl; -- System columns may be part of an updatable view ! CREATE VIEW rw_view15 AS SELECT a, upper(b) FROM base_tbl; -- Expression/function may be part of an updatable view ! CREATE VIEW rw_view16 AS SELECT a, b, a AS aa FROM base_tbl; -- Repeated column may be part of an updatable view ! CREATE VIEW ro_view17 AS SELECT * FROM ro_view1; -- Base relation not updatable ! CREATE VIEW ro_view18 AS SELECT * FROM (VALUES(1)) AS tmp(a); -- VALUES in rangetable ! CREATE SEQUENCE seq; ! CREATE VIEW ro_view19 AS SELECT * FROM seq; -- View based on a sequence ! CREATE VIEW ro_view20 AS SELECT a, b, generate_series(1, a) g FROM base_tbl; -- SRF in targetlist not supported ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! ro_view1 | NO ! ro_view10 | NO ! ro_view11 | NO ! ro_view12 | NO ! ro_view13 | NO ! ro_view17 | NO ! ro_view18 | NO ! ro_view19 | NO ! ro_view2 | NO ! ro_view20 | NO ! ro_view3 | NO ! ro_view4 | NO ! ro_view5 | NO ! ro_view6 | NO ! ro_view7 | NO ! ro_view8 | NO ! ro_view9 | NO ! rw_view14 | YES ! rw_view15 | YES ! rw_view16 | YES ! (20 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! ro_view1 | NO | NO ! ro_view10 | NO | NO ! ro_view11 | NO | NO ! ro_view12 | NO | NO ! ro_view13 | NO | NO ! ro_view17 | NO | NO ! ro_view18 | NO | NO ! ro_view19 | NO | NO ! ro_view2 | NO | NO ! ro_view20 | NO | NO ! ro_view3 | NO | NO ! ro_view4 | NO | NO ! ro_view5 | NO | NO ! ro_view6 | NO | NO ! ro_view7 | NO | NO ! ro_view8 | NO | NO ! ro_view9 | NO | NO ! rw_view14 | YES | YES ! rw_view15 | YES | YES ! rw_view16 | YES | YES ! (20 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+---------------+-------------- ! ro_view1 | a | NO ! ro_view1 | b | NO ! ro_view10 | a | NO ! ro_view11 | a | NO ! ro_view11 | b | NO ! ro_view12 | a | NO ! ro_view13 | a | NO ! ro_view13 | b | NO ! ro_view17 | a | NO ! ro_view17 | b | NO ! ro_view18 | a | NO ! ro_view19 | sequence_name | NO ! ro_view19 | last_value | NO ! ro_view19 | start_value | NO ! ro_view19 | increment_by | NO ! ro_view19 | max_value | NO ! ro_view19 | min_value | NO ! ro_view19 | cache_value | NO ! ro_view19 | log_cnt | NO ! ro_view19 | is_cycled | NO ! ro_view19 | is_called | NO ! ro_view2 | a | NO ! ro_view2 | b | NO ! ro_view20 | a | NO ! ro_view20 | b | NO ! ro_view20 | g | NO ! ro_view3 | ?column? | NO ! ro_view4 | count | NO ! ro_view5 | a | NO ! ro_view5 | rank | NO ! ro_view6 | a | NO ! ro_view6 | b | NO ! ro_view7 | a | NO ! ro_view7 | b | NO ! ro_view8 | a | NO ! ro_view8 | b | NO ! ro_view9 | a | NO ! ro_view9 | b | NO ! rw_view14 | ctid | NO ! rw_view14 | a | YES ! rw_view14 | b | YES ! rw_view15 | a | YES ! rw_view15 | upper | NO ! rw_view16 | a | YES ! rw_view16 | b | YES ! rw_view16 | aa | YES ! (46 rows) ! ! -- Read-only views ! DELETE FROM ro_view1; ! ERROR: cannot delete from view "ro_view1" ! DETAIL: Views containing DISTINCT are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! DELETE FROM ro_view2; ! ERROR: cannot delete from view "ro_view2" ! DETAIL: Views containing GROUP BY are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! DELETE FROM ro_view3; ! ERROR: cannot delete from view "ro_view3" ! DETAIL: Views containing HAVING are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! DELETE FROM ro_view4; ! ERROR: cannot delete from view "ro_view4" ! DETAIL: Views that return aggregate functions are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! DELETE FROM ro_view5; ! ERROR: cannot delete from view "ro_view5" ! DETAIL: Views that return window functions are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! DELETE FROM ro_view6; ! ERROR: cannot delete from view "ro_view6" ! DETAIL: Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! UPDATE ro_view7 SET a=a+1; ! ERROR: cannot update view "ro_view7" ! DETAIL: Views containing WITH are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view8 SET a=a+1; ! ERROR: cannot update view "ro_view8" ! DETAIL: Views containing LIMIT or OFFSET are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view9 SET a=a+1; ! ERROR: cannot update view "ro_view9" ! DETAIL: Views containing LIMIT or OFFSET are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view10 SET a=a+1; ! ERROR: cannot update view "ro_view10" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view11 SET a=a+1; ! ERROR: cannot update view "ro_view11" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view12 SET a=a+1; ! ERROR: cannot update view "ro_view12" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! INSERT INTO ro_view13 VALUES (3, 'Row 3'); ! ERROR: cannot insert into view "ro_view13" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule. ! -- Partially updatable view ! INSERT INTO rw_view14 VALUES (null, 3, 'Row 3'); -- should fail ! ERROR: cannot insert into column "ctid" of view "rw_view14" ! DETAIL: View columns that refer to system columns are not updatable. ! INSERT INTO rw_view14 (a, b) VALUES (3, 'Row 3'); -- should be OK ! UPDATE rw_view14 SET ctid=null WHERE a=3; -- should fail ! ERROR: cannot update column "ctid" of view "rw_view14" ! DETAIL: View columns that refer to system columns are not updatable. ! UPDATE rw_view14 SET b='ROW 3' WHERE a=3; -- should be OK ! SELECT * FROM base_tbl; ! a | b ! ----+-------- ! -2 | Row -2 ! -1 | Row -1 ! 0 | Row 0 ! 1 | Row 1 ! 2 | Row 2 ! 3 | ROW 3 ! (6 rows) ! ! DELETE FROM rw_view14 WHERE a=3; -- should be OK ! -- Partially updatable view ! INSERT INTO rw_view15 VALUES (3, 'ROW 3'); -- should fail ! ERROR: cannot insert into column "upper" of view "rw_view15" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! INSERT INTO rw_view15 (a) VALUES (3); -- should be OK ! ALTER VIEW rw_view15 ALTER COLUMN upper SET DEFAULT 'NOT SET'; ! INSERT INTO rw_view15 (a) VALUES (4); -- should fail ! ERROR: cannot insert into column "upper" of view "rw_view15" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view15 SET upper='ROW 3' WHERE a=3; -- should fail ! ERROR: cannot update column "upper" of view "rw_view15" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view15 SET upper=DEFAULT WHERE a=3; -- should fail ! ERROR: cannot update column "upper" of view "rw_view15" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view15 SET a=4 WHERE a=3; -- should be OK ! SELECT * FROM base_tbl; ! a | b ! ----+------------- ! -2 | Row -2 ! -1 | Row -1 ! 0 | Row 0 ! 1 | Row 1 ! 2 | Row 2 ! 4 | Unspecified ! (6 rows) ! ! DELETE FROM rw_view15 WHERE a=4; -- should be OK ! -- Partially updatable view ! INSERT INTO rw_view16 VALUES (3, 'Row 3', 3); -- should fail ! ERROR: multiple assignments to same column "a" ! INSERT INTO rw_view16 (a, b) VALUES (3, 'Row 3'); -- should be OK ! UPDATE rw_view16 SET a=3, aa=-3 WHERE a=3; -- should fail ! ERROR: multiple assignments to same column "a" ! UPDATE rw_view16 SET aa=-3 WHERE a=3; -- should be OK ! SELECT * FROM base_tbl; ! a | b ! ----+-------- ! -2 | Row -2 ! -1 | Row -1 ! 0 | Row 0 ! 1 | Row 1 ! 2 | Row 2 ! -3 | Row 3 ! (6 rows) ! ! DELETE FROM rw_view16 WHERE a=-3; -- should be OK ! -- Read-only views ! INSERT INTO ro_view17 VALUES (3, 'ROW 3'); ! ERROR: cannot insert into view "ro_view1" ! DETAIL: Views containing DISTINCT are not automatically updatable. ! HINT: To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule. ! DELETE FROM ro_view18; ! ERROR: cannot delete from view "ro_view18" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule. ! UPDATE ro_view19 SET max_value=1000; ! ERROR: cannot update view "ro_view19" ! DETAIL: Views that do not select from a single table or view are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! UPDATE ro_view20 SET b=upper(b); ! ERROR: cannot update view "ro_view20" ! DETAIL: Views that return set-returning functions are not automatically updatable. ! HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule. ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 16 other objects ! DETAIL: drop cascades to view ro_view1 ! drop cascades to view ro_view17 ! drop cascades to view ro_view2 ! drop cascades to view ro_view3 ! drop cascades to view ro_view5 ! drop cascades to view ro_view6 ! drop cascades to view ro_view7 ! drop cascades to view ro_view8 ! drop cascades to view ro_view9 ! drop cascades to view ro_view11 ! drop cascades to view ro_view13 ! drop cascades to view rw_view15 ! drop cascades to view rw_view16 ! drop cascades to view ro_view20 ! drop cascades to view ro_view4 ! drop cascades to view rw_view14 ! DROP VIEW ro_view10, ro_view12, ro_view18; ! DROP SEQUENCE seq CASCADE; ! NOTICE: drop cascades to view ro_view19 ! -- simple updatable view ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a>0; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name = 'rw_view1'; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! (1 row) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name = 'rw_view1'; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | YES | YES ! (1 row) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name = 'rw_view1' ! ORDER BY ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | YES ! rw_view1 | b | YES ! (2 rows) ! ! INSERT INTO rw_view1 VALUES (3, 'Row 3'); ! INSERT INTO rw_view1 (a) VALUES (4); ! UPDATE rw_view1 SET a=5 WHERE a=4; ! DELETE FROM rw_view1 WHERE b='Row 2'; ! SELECT * FROM base_tbl; ! a | b ! ----+------------- ! -2 | Row -2 ! -1 | Row -1 ! 0 | Row 0 ! 1 | Row 1 ! 3 | Row 3 ! 5 | Unspecified ! (6 rows) ! ! EXPLAIN (costs off) UPDATE rw_view1 SET a=6 WHERE a=5; ! QUERY PLAN ! -------------------------------------------------- ! Update on base_tbl ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: ((a > 0) AND (a = 5)) ! (3 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view1 WHERE a=5; ! QUERY PLAN ! -------------------------------------------------- ! Delete on base_tbl ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: ((a > 0) AND (a = 5)) ! (3 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- view on top of view ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW rw_view1 AS SELECT b AS bb, a AS aa FROM base_tbl WHERE a>0; ! CREATE VIEW rw_view2 AS SELECT aa AS aaa, bb AS bbb FROM rw_view1 WHERE aa<10; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name = 'rw_view2'; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view2 | YES ! (1 row) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name = 'rw_view2'; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view2 | YES | YES ! (1 row) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name = 'rw_view2' ! ORDER BY ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view2 | aaa | YES ! rw_view2 | bbb | YES ! (2 rows) ! ! INSERT INTO rw_view2 VALUES (3, 'Row 3'); ! INSERT INTO rw_view2 (aaa) VALUES (4); ! SELECT * FROM rw_view2; ! aaa | bbb ! -----+------------- ! 1 | Row 1 ! 2 | Row 2 ! 3 | Row 3 ! 4 | Unspecified ! (4 rows) ! ! UPDATE rw_view2 SET bbb='Row 4' WHERE aaa=4; ! DELETE FROM rw_view2 WHERE aaa=2; ! SELECT * FROM rw_view2; ! aaa | bbb ! -----+------- ! 1 | Row 1 ! 3 | Row 3 ! 4 | Row 4 ! (3 rows) ! ! EXPLAIN (costs off) UPDATE rw_view2 SET aaa=5 WHERE aaa=4; ! QUERY PLAN ! -------------------------------------------------------- ! Update on base_tbl ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: ((a < 10) AND (a > 0) AND (a = 4)) ! (3 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view2 WHERE aaa=4; ! QUERY PLAN ! -------------------------------------------------------- ! Delete on base_tbl ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: ((a < 10) AND (a > 0) AND (a = 4)) ! (3 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- view on top of view with rules ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a>0 OFFSET 0; -- not updatable without rules/triggers ! CREATE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a<10; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | NO ! rw_view2 | NO ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | NO | NO ! rw_view2 | NO | NO ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE RULE rw_view1_ins_rule AS ON INSERT TO rw_view1 ! DO INSTEAD INSERT INTO base_tbl VALUES (NEW.a, NEW.b) RETURNING *; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! rw_view2 | YES ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | NO | YES ! rw_view2 | NO | YES ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE RULE rw_view1_upd_rule AS ON UPDATE TO rw_view1 ! DO INSTEAD UPDATE base_tbl SET b=NEW.b WHERE a=OLD.a RETURNING NEW.*; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! rw_view2 | YES ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | NO | YES ! rw_view2 | NO | YES ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE RULE rw_view1_del_rule AS ON DELETE TO rw_view1 ! DO INSTEAD DELETE FROM base_tbl WHERE a=OLD.a RETURNING OLD.*; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! rw_view2 | YES ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | YES | YES ! rw_view2 | YES | YES ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | YES ! rw_view1 | b | YES ! rw_view2 | a | YES ! rw_view2 | b | YES ! (4 rows) ! ! INSERT INTO rw_view2 VALUES (3, 'Row 3') RETURNING *; ! a | b ! ---+------- ! 3 | Row 3 ! (1 row) ! ! UPDATE rw_view2 SET b='Row three' WHERE a=3 RETURNING *; ! a | b ! ---+----------- ! 3 | Row three ! (1 row) ! ! SELECT * FROM rw_view2; ! a | b ! ---+----------- ! 1 | Row 1 ! 2 | Row 2 ! 3 | Row three ! (3 rows) ! ! DELETE FROM rw_view2 WHERE a=3 RETURNING *; ! a | b ! ---+----------- ! 3 | Row three ! (1 row) ! ! SELECT * FROM rw_view2; ! a | b ! ---+------- ! 1 | Row 1 ! 2 | Row 2 ! (2 rows) ! ! EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2; ! QUERY PLAN ! ---------------------------------------------------------------- ! Update on base_tbl ! -> Nested Loop ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: (a = 2) ! -> Subquery Scan on rw_view1 ! Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) ! -> Bitmap Heap Scan on base_tbl base_tbl_1 ! Recheck Cond: (a > 0) ! -> Bitmap Index Scan on base_tbl_pkey ! Index Cond: (a > 0) ! (10 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2; ! QUERY PLAN ! ---------------------------------------------------------------- ! Delete on base_tbl ! -> Nested Loop ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: (a = 2) ! -> Subquery Scan on rw_view1 ! Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) ! -> Bitmap Heap Scan on base_tbl base_tbl_1 ! Recheck Cond: (a > 0) ! -> Bitmap Index Scan on base_tbl_pkey ! Index Cond: (a > 0) ! (10 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- view on top of view with triggers ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a>0 OFFSET 0; -- not updatable without rules/triggers ! CREATE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a<10; ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | NO ! rw_view2 | NO ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into, ! is_trigger_updatable, is_trigger_deletable, ! is_trigger_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! rw_view1 | NO | NO | NO | NO | NO ! rw_view2 | NO | NO | NO | NO | NO ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE FUNCTION rw_view1_trig_fn() ! RETURNS trigger AS ! $$ ! BEGIN ! IF TG_OP = 'INSERT' THEN ! INSERT INTO base_tbl VALUES (NEW.a, NEW.b); ! RETURN NEW; ! ELSIF TG_OP = 'UPDATE' THEN ! UPDATE base_tbl SET b=NEW.b WHERE a=OLD.a; ! RETURN NEW; ! ELSIF TG_OP = 'DELETE' THEN ! DELETE FROM base_tbl WHERE a=OLD.a; ! RETURN OLD; ! END IF; ! END; ! $$ ! LANGUAGE plpgsql; ! CREATE TRIGGER rw_view1_ins_trig INSTEAD OF INSERT ON rw_view1 ! FOR EACH ROW EXECUTE PROCEDURE rw_view1_trig_fn(); ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | NO ! rw_view2 | NO ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into, ! is_trigger_updatable, is_trigger_deletable, ! is_trigger_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! rw_view1 | NO | NO | NO | NO | YES ! rw_view2 | NO | NO | NO | NO | NO ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE TRIGGER rw_view1_upd_trig INSTEAD OF UPDATE ON rw_view1 ! FOR EACH ROW EXECUTE PROCEDURE rw_view1_trig_fn(); ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | NO ! rw_view2 | NO ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into, ! is_trigger_updatable, is_trigger_deletable, ! is_trigger_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! rw_view1 | NO | NO | YES | NO | YES ! rw_view2 | NO | NO | NO | NO | NO ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! CREATE TRIGGER rw_view1_del_trig INSTEAD OF DELETE ON rw_view1 ! FOR EACH ROW EXECUTE PROCEDURE rw_view1_trig_fn(); ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | NO ! rw_view2 | NO ! (2 rows) ! ! SELECT table_name, is_updatable, is_insertable_into, ! is_trigger_updatable, is_trigger_deletable, ! is_trigger_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! rw_view1 | NO | NO | YES | YES | YES ! rw_view2 | NO | NO | NO | NO | NO ! (2 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE 'rw_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | a | NO ! rw_view1 | b | NO ! rw_view2 | a | NO ! rw_view2 | b | NO ! (4 rows) ! ! INSERT INTO rw_view2 VALUES (3, 'Row 3') RETURNING *; ! a | b ! ---+------- ! 3 | Row 3 ! (1 row) ! ! UPDATE rw_view2 SET b='Row three' WHERE a=3 RETURNING *; ! a | b ! ---+----------- ! 3 | Row three ! (1 row) ! ! SELECT * FROM rw_view2; ! a | b ! ---+----------- ! 1 | Row 1 ! 2 | Row 2 ! 3 | Row three ! (3 rows) ! ! DELETE FROM rw_view2 WHERE a=3 RETURNING *; ! a | b ! ---+----------- ! 3 | Row three ! (1 row) ! ! SELECT * FROM rw_view2; ! a | b ! ---+------- ! 1 | Row 1 ! 2 | Row 2 ! (2 rows) ! ! EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2; ! QUERY PLAN ! ---------------------------------------------------------- ! Update on rw_view1 rw_view1_1 ! -> Subquery Scan on rw_view1 ! Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) ! -> Bitmap Heap Scan on base_tbl ! Recheck Cond: (a > 0) ! -> Bitmap Index Scan on base_tbl_pkey ! Index Cond: (a > 0) ! (7 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2; ! QUERY PLAN ! ---------------------------------------------------------- ! Delete on rw_view1 rw_view1_1 ! -> Subquery Scan on rw_view1 ! Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) ! -> Bitmap Heap Scan on base_tbl ! Recheck Cond: (a > 0) ! -> Bitmap Index Scan on base_tbl_pkey ! Index Cond: (a > 0) ! (7 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! DROP FUNCTION rw_view1_trig_fn(); ! -- update using whole row from view ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); ! CREATE VIEW rw_view1 AS SELECT b AS bb, a AS aa FROM base_tbl; ! CREATE FUNCTION rw_view1_aa(x rw_view1) ! RETURNS int AS $$ SELECT x.aa $$ LANGUAGE sql; ! UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v)=2 ! RETURNING rw_view1_aa(v), v.bb; ! rw_view1_aa | bb ! -------------+--------------- ! 2 | Updated row 2 ! (1 row) ! ! SELECT * FROM base_tbl; ! a | b ! ----+--------------- ! -2 | Row -2 ! -1 | Row -1 ! 0 | Row 0 ! 1 | Row 1 ! 2 | Updated row 2 ! (5 rows) ! ! EXPLAIN (costs off) ! UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v)=2 ! RETURNING rw_view1_aa(v), v.bb; ! QUERY PLAN ! -------------------------------------------------- ! Update on base_tbl ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: (a = 2) ! (3 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to function rw_view1_aa(rw_view1) ! -- permissions checks ! CREATE USER view_user1; ! CREATE USER view_user2; ! SET SESSION AUTHORIZATION view_user1; ! CREATE TABLE base_tbl(a int, b text, c float); ! INSERT INTO base_tbl VALUES (1, 'Row 1', 1.0); ! CREATE VIEW rw_view1 AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl; ! INSERT INTO rw_view1 VALUES ('Row 2', 2.0, 2); ! GRANT SELECT ON base_tbl TO view_user2; ! GRANT SELECT ON rw_view1 TO view_user2; ! GRANT UPDATE (a,c) ON base_tbl TO view_user2; ! GRANT UPDATE (bb,cc) ON rw_view1 TO view_user2; ! RESET SESSION AUTHORIZATION; ! SET SESSION AUTHORIZATION view_user2; ! CREATE VIEW rw_view2 AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl; ! SELECT * FROM base_tbl; -- ok ! a | b | c ! ---+-------+--- ! 1 | Row 1 | 1 ! 2 | Row 2 | 2 ! (2 rows) ! ! SELECT * FROM rw_view1; -- ok ! bb | cc | aa ! -------+----+---- ! Row 1 | 1 | 1 ! Row 2 | 2 | 2 ! (2 rows) ! ! SELECT * FROM rw_view2; -- ok ! bb | cc | aa ! -------+----+---- ! Row 1 | 1 | 1 ! Row 2 | 2 | 2 ! (2 rows) ! ! INSERT INTO base_tbl VALUES (3, 'Row 3', 3.0); -- not allowed ! ERROR: permission denied for relation base_tbl ! INSERT INTO rw_view1 VALUES ('Row 3', 3.0, 3); -- not allowed ! ERROR: permission denied for relation rw_view1 ! INSERT INTO rw_view2 VALUES ('Row 3', 3.0, 3); -- not allowed ! ERROR: permission denied for relation base_tbl ! UPDATE base_tbl SET a=a, c=c; -- ok ! UPDATE base_tbl SET b=b; -- not allowed ! ERROR: permission denied for relation base_tbl ! UPDATE rw_view1 SET bb=bb, cc=cc; -- ok ! UPDATE rw_view1 SET aa=aa; -- not allowed ! ERROR: permission denied for relation rw_view1 ! UPDATE rw_view2 SET aa=aa, cc=cc; -- ok ! UPDATE rw_view2 SET bb=bb; -- not allowed ! ERROR: permission denied for relation base_tbl ! DELETE FROM base_tbl; -- not allowed ! ERROR: permission denied for relation base_tbl ! DELETE FROM rw_view1; -- not allowed ! ERROR: permission denied for relation rw_view1 ! DELETE FROM rw_view2; -- not allowed ! ERROR: permission denied for relation base_tbl ! RESET SESSION AUTHORIZATION; ! SET SESSION AUTHORIZATION view_user1; ! GRANT INSERT, DELETE ON base_tbl TO view_user2; ! RESET SESSION AUTHORIZATION; ! SET SESSION AUTHORIZATION view_user2; ! INSERT INTO base_tbl VALUES (3, 'Row 3', 3.0); -- ok ! INSERT INTO rw_view1 VALUES ('Row 4', 4.0, 4); -- not allowed ! ERROR: permission denied for relation rw_view1 ! INSERT INTO rw_view2 VALUES ('Row 4', 4.0, 4); -- ok ! DELETE FROM base_tbl WHERE a=1; -- ok ! DELETE FROM rw_view1 WHERE aa=2; -- not allowed ! ERROR: permission denied for relation rw_view1 ! DELETE FROM rw_view2 WHERE aa=2; -- ok ! SELECT * FROM base_tbl; ! a | b | c ! ---+-------+--- ! 3 | Row 3 | 3 ! 4 | Row 4 | 4 ! (2 rows) ! ! RESET SESSION AUTHORIZATION; ! SET SESSION AUTHORIZATION view_user1; ! REVOKE INSERT, DELETE ON base_tbl FROM view_user2; ! GRANT INSERT, DELETE ON rw_view1 TO view_user2; ! RESET SESSION AUTHORIZATION; ! SET SESSION AUTHORIZATION view_user2; ! INSERT INTO base_tbl VALUES (5, 'Row 5', 5.0); -- not allowed ! ERROR: permission denied for relation base_tbl ! INSERT INTO rw_view1 VALUES ('Row 5', 5.0, 5); -- ok ! INSERT INTO rw_view2 VALUES ('Row 6', 6.0, 6); -- not allowed ! ERROR: permission denied for relation base_tbl ! DELETE FROM base_tbl WHERE a=3; -- not allowed ! ERROR: permission denied for relation base_tbl ! DELETE FROM rw_view1 WHERE aa=3; -- ok ! DELETE FROM rw_view2 WHERE aa=4; -- not allowed ! ERROR: permission denied for relation base_tbl ! SELECT * FROM base_tbl; ! a | b | c ! ---+-------+--- ! 4 | Row 4 | 4 ! 5 | Row 5 | 5 ! (2 rows) ! ! RESET SESSION AUTHORIZATION; ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! DROP USER view_user1; ! DROP USER view_user2; ! -- column defaults ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified', c serial); ! INSERT INTO base_tbl VALUES (1, 'Row 1'); ! INSERT INTO base_tbl VALUES (2, 'Row 2'); ! INSERT INTO base_tbl VALUES (3); ! CREATE VIEW rw_view1 AS SELECT a AS aa, b AS bb FROM base_tbl; ! ALTER VIEW rw_view1 ALTER COLUMN bb SET DEFAULT 'View default'; ! INSERT INTO rw_view1 VALUES (4, 'Row 4'); ! INSERT INTO rw_view1 (aa) VALUES (5); ! SELECT * FROM base_tbl; ! a | b | c ! ---+--------------+--- ! 1 | Row 1 | 1 ! 2 | Row 2 | 2 ! 3 | Unspecified | 3 ! 4 | Row 4 | 4 ! 5 | View default | 5 ! (5 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- Table having triggers ! CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified'); ! INSERT INTO base_tbl VALUES (1, 'Row 1'); ! INSERT INTO base_tbl VALUES (2, 'Row 2'); ! CREATE FUNCTION rw_view1_trig_fn() ! RETURNS trigger AS ! $$ ! BEGIN ! IF TG_OP = 'INSERT' THEN ! UPDATE base_tbl SET b=NEW.b WHERE a=1; ! RETURN NULL; ! END IF; ! RETURN NULL; ! END; ! $$ ! LANGUAGE plpgsql; ! CREATE TRIGGER rw_view1_ins_trig AFTER INSERT ON base_tbl ! FOR EACH ROW EXECUTE PROCEDURE rw_view1_trig_fn(); ! CREATE VIEW rw_view1 AS SELECT a AS aa, b AS bb FROM base_tbl; ! INSERT INTO rw_view1 VALUES (3, 'Row 3'); ! select * from base_tbl; ! a | b ! ---+------- ! 2 | Row 2 ! 3 | Row 3 ! 1 | Row 3 ! (3 rows) ! ! DROP VIEW rw_view1; ! DROP TRIGGER rw_view1_ins_trig on base_tbl; ! DROP FUNCTION rw_view1_trig_fn(); ! DROP TABLE base_tbl; ! -- view with ORDER BY ! CREATE TABLE base_tbl (a int, b int); ! INSERT INTO base_tbl VALUES (1,2), (4,5), (3,-3); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl ORDER BY a+b; ! SELECT * FROM rw_view1; ! a | b ! ---+---- ! 3 | -3 ! 1 | 2 ! 4 | 5 ! (3 rows) ! ! INSERT INTO rw_view1 VALUES (7,-8); ! SELECT * FROM rw_view1; ! a | b ! ---+---- ! 7 | -8 ! 3 | -3 ! 1 | 2 ! 4 | 5 ! (4 rows) ! ! EXPLAIN (verbose, costs off) UPDATE rw_view1 SET b = b + 1 RETURNING *; ! QUERY PLAN ! ------------------------------------------------------------- ! Update on public.base_tbl ! Output: base_tbl.a, base_tbl.b ! -> Seq Scan on public.base_tbl ! Output: base_tbl.a, (base_tbl.b + 1), base_tbl.ctid ! (4 rows) ! ! UPDATE rw_view1 SET b = b + 1 RETURNING *; ! a | b ! ---+---- ! 1 | 3 ! 4 | 6 ! 3 | -2 ! 7 | -7 ! (4 rows) ! ! SELECT * FROM rw_view1; ! a | b ! ---+---- ! 7 | -7 ! 3 | -2 ! 1 | 3 ! 4 | 6 ! (4 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- multiple array-column updates ! CREATE TABLE base_tbl (a int, arr int[]); ! INSERT INTO base_tbl VALUES (1,ARRAY[2]), (3,ARRAY[4]); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl; ! UPDATE rw_view1 SET arr[1] = 42, arr[2] = 77 WHERE a = 3; ! SELECT * FROM rw_view1; ! a | arr ! ---+--------- ! 1 | {2} ! 3 | {42,77} ! (2 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- views with updatable and non-updatable columns ! CREATE TABLE base_tbl(a float); ! INSERT INTO base_tbl SELECT i/10.0 FROM generate_series(1,10) g(i); ! CREATE VIEW rw_view1 AS ! SELECT ctid, sin(a) s, a, cos(a) c ! FROM base_tbl ! WHERE a != 0 ! ORDER BY abs(a); ! INSERT INTO rw_view1 VALUES (null, null, 1.1, null); -- should fail ! ERROR: cannot insert into column "ctid" of view "rw_view1" ! DETAIL: View columns that refer to system columns are not updatable. ! INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail ! ERROR: cannot insert into column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK ! a | s | c ! -----+-------------------+------------------- ! 1.1 | 0.891207360061435 | 0.453596121425577 ! (1 row) ! ! UPDATE rw_view1 SET s = s WHERE a = 1.1; -- should fail ! ERROR: cannot update column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view1 SET a = 1.05 WHERE a = 1.1 RETURNING s; -- OK ! s ! ------------------- ! 0.867423225594017 ! (1 row) ! ! DELETE FROM rw_view1 WHERE a = 1.05; -- OK ! CREATE VIEW rw_view2 AS ! SELECT s, c, s/c t, a base_a, ctid ! FROM rw_view1; ! INSERT INTO rw_view2 VALUES (null, null, null, 1.1, null); -- should fail ! ERROR: cannot insert into column "t" of view "rw_view2" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! INSERT INTO rw_view2(s, c, base_a) VALUES (null, null, 1.1); -- should fail ! ERROR: cannot insert into column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! INSERT INTO rw_view2(base_a) VALUES (1.1) RETURNING t; -- OK ! t ! ------------------ ! 1.96475965724865 ! (1 row) ! ! UPDATE rw_view2 SET s = s WHERE base_a = 1.1; -- should fail ! ERROR: cannot update column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view2 SET t = t WHERE base_a = 1.1; -- should fail ! ERROR: cannot update column "t" of view "rw_view2" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view2 SET base_a = 1.05 WHERE base_a = 1.1; -- OK ! DELETE FROM rw_view2 WHERE base_a = 1.05 RETURNING base_a, s, c, t; -- OK ! base_a | s | c | t ! --------+-------------------+-------------------+------------------ ! 1.05 | 0.867423225594017 | 0.497571047891727 | 1.74331530998317 ! (1 row) ! ! CREATE VIEW rw_view3 AS ! SELECT s, c, s/c t, ctid ! FROM rw_view1; ! INSERT INTO rw_view3 VALUES (null, null, null, null); -- should fail ! ERROR: cannot insert into column "t" of view "rw_view3" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! INSERT INTO rw_view3(s) VALUES (null); -- should fail ! ERROR: cannot insert into column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! UPDATE rw_view3 SET s = s; -- should fail ! ERROR: cannot update column "s" of view "rw_view1" ! DETAIL: View columns that are not columns of their base relation are not updatable. ! DELETE FROM rw_view3 WHERE s = sin(0.1); -- should be OK ! SELECT * FROM base_tbl ORDER BY a; ! a ! ----- ! 0.2 ! 0.3 ! 0.4 ! 0.5 ! 0.6 ! 0.7 ! 0.8 ! 0.9 ! 1 ! (9 rows) ! ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! rw_view2 | YES ! rw_view3 | NO ! (3 rows) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | YES | YES ! rw_view2 | YES | YES ! rw_view3 | NO | NO ! (3 rows) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name LIKE E'r_\\_view%' ! ORDER BY table_name, ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | ctid | NO ! rw_view1 | s | NO ! rw_view1 | a | YES ! rw_view1 | c | NO ! rw_view2 | s | NO ! rw_view2 | c | NO ! rw_view2 | t | NO ! rw_view2 | base_a | YES ! rw_view2 | ctid | NO ! rw_view3 | s | NO ! rw_view3 | c | NO ! rw_view3 | t | NO ! rw_view3 | ctid | NO ! (13 rows) ! ! SELECT events & 4 != 0 AS upd, ! events & 8 != 0 AS ins, ! events & 16 != 0 AS del ! FROM pg_catalog.pg_relation_is_updatable('rw_view3'::regclass, false) t(events); ! upd | ins | del ! -----+-----+----- ! f | f | t ! (1 row) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! drop cascades to view rw_view3 ! -- inheritance tests ! CREATE TABLE base_tbl_parent (a int); ! CREATE TABLE base_tbl_child (CHECK (a > 0)) INHERITS (base_tbl_parent); ! INSERT INTO base_tbl_parent SELECT * FROM generate_series(-8, -1); ! INSERT INTO base_tbl_child SELECT * FROM generate_series(1, 8); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl_parent; ! CREATE VIEW rw_view2 AS SELECT * FROM ONLY base_tbl_parent; ! SELECT * FROM rw_view1 ORDER BY a; ! a ! ---- ! -8 ! -7 ! -6 ! -5 ! -4 ! -3 ! -2 ! -1 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! (16 rows) ! ! SELECT * FROM ONLY rw_view1 ORDER BY a; ! a ! ---- ! -8 ! -7 ! -6 ! -5 ! -4 ! -3 ! -2 ! -1 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! (16 rows) ! ! SELECT * FROM rw_view2 ORDER BY a; ! a ! ---- ! -8 ! -7 ! -6 ! -5 ! -4 ! -3 ! -2 ! -1 ! (8 rows) ! ! INSERT INTO rw_view1 VALUES (-100), (100); ! INSERT INTO rw_view2 VALUES (-200), (200); ! UPDATE rw_view1 SET a = a*10 WHERE a IN (-1, 1); -- Should produce -10 and 10 ! UPDATE ONLY rw_view1 SET a = a*10 WHERE a IN (-2, 2); -- Should produce -20 and 20 ! UPDATE rw_view2 SET a = a*10 WHERE a IN (-3, 3); -- Should produce -30 only ! UPDATE ONLY rw_view2 SET a = a*10 WHERE a IN (-4, 4); -- Should produce -40 only ! DELETE FROM rw_view1 WHERE a IN (-5, 5); -- Should delete -5 and 5 ! DELETE FROM ONLY rw_view1 WHERE a IN (-6, 6); -- Should delete -6 and 6 ! DELETE FROM rw_view2 WHERE a IN (-7, 7); -- Should delete -7 only ! DELETE FROM ONLY rw_view2 WHERE a IN (-8, 8); -- Should delete -8 only ! SELECT * FROM ONLY base_tbl_parent ORDER BY a; ! a ! ------ ! -200 ! -100 ! -40 ! -30 ! -20 ! -10 ! 100 ! 200 ! (8 rows) ! ! SELECT * FROM base_tbl_child ORDER BY a; ! a ! ---- ! 3 ! 4 ! 7 ! 8 ! 10 ! 20 ! (6 rows) ! ! DROP TABLE base_tbl_parent, base_tbl_child CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- simple WITH CHECK OPTION ! CREATE TABLE base_tbl (a int, b int DEFAULT 10); ! INSERT INTO base_tbl VALUES (1,2), (2,3), (1,-1); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a < b ! WITH LOCAL CHECK OPTION; ! \d+ rw_view1 ! View "public.rw_view1" ! Column | Type | Modifiers | Storage | Description ! --------+---------+-----------+---------+------------- ! a | integer | | plain | ! b | integer | | plain | ! View definition: ! SELECT base_tbl.a, ! base_tbl.b ! FROM base_tbl ! WHERE base_tbl.a < base_tbl.b; ! Options: check_option=local ! ! SELECT * FROM information_schema.views WHERE table_name = 'rw_view1'; ! table_catalog | table_schema | table_name | view_definition | check_option | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ---------------+--------------+------------+------------------------------------+--------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! regression | public | rw_view1 | SELECT base_tbl.a, +| LOCAL | YES | YES | NO | NO | NO ! | | | base_tbl.b +| | | | | | ! | | | FROM base_tbl +| | | | | | ! | | | WHERE (base_tbl.a < base_tbl.b); | | | | | | ! (1 row) ! ! INSERT INTO rw_view1 VALUES(3,4); -- ok ! INSERT INTO rw_view1 VALUES(4,3); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (4, 3). ! INSERT INTO rw_view1 VALUES(5,null); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (5, null). ! UPDATE rw_view1 SET b = 5 WHERE a = 3; -- ok ! UPDATE rw_view1 SET b = -5 WHERE a = 3; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (3, -5). ! INSERT INTO rw_view1(a) VALUES (9); -- ok ! INSERT INTO rw_view1(a) VALUES (10); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (10, 10). ! SELECT * FROM base_tbl; ! a | b ! ---+---- ! 1 | 2 ! 2 | 3 ! 1 | -1 ! 3 | 5 ! 9 | 10 ! (5 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- WITH LOCAL/CASCADED CHECK OPTION ! CREATE TABLE base_tbl (a int); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a > 0; ! CREATE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a < 10 ! WITH CHECK OPTION; -- implicitly cascaded ! \d+ rw_view2 ! View "public.rw_view2" ! Column | Type | Modifiers | Storage | Description ! --------+---------+-----------+---------+------------- ! a | integer | | plain | ! View definition: ! SELECT rw_view1.a ! FROM rw_view1 ! WHERE rw_view1.a < 10; ! Options: check_option=cascaded ! ! SELECT * FROM information_schema.views WHERE table_name = 'rw_view2'; ! table_catalog | table_schema | table_name | view_definition | check_option | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ---------------+--------------+------------+----------------------------+--------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! regression | public | rw_view2 | SELECT rw_view1.a +| CASCADED | YES | YES | NO | NO | NO ! | | | FROM rw_view1 +| | | | | | ! | | | WHERE (rw_view1.a < 10); | | | | | | ! (1 row) ! ! INSERT INTO rw_view2 VALUES (-5); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (-5). ! INSERT INTO rw_view2 VALUES (5); -- ok ! INSERT INTO rw_view2 VALUES (15); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (15). ! SELECT * FROM base_tbl; ! a ! --- ! 5 ! (1 row) ! ! UPDATE rw_view2 SET a = a - 10; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (-5). ! UPDATE rw_view2 SET a = a + 10; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (15). ! CREATE OR REPLACE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a < 10 ! WITH LOCAL CHECK OPTION; ! \d+ rw_view2 ! View "public.rw_view2" ! Column | Type | Modifiers | Storage | Description ! --------+---------+-----------+---------+------------- ! a | integer | | plain | ! View definition: ! SELECT rw_view1.a ! FROM rw_view1 ! WHERE rw_view1.a < 10; ! Options: check_option=local ! ! SELECT * FROM information_schema.views WHERE table_name = 'rw_view2'; ! table_catalog | table_schema | table_name | view_definition | check_option | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ---------------+--------------+------------+----------------------------+--------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! regression | public | rw_view2 | SELECT rw_view1.a +| LOCAL | YES | YES | NO | NO | NO ! | | | FROM rw_view1 +| | | | | | ! | | | WHERE (rw_view1.a < 10); | | | | | | ! (1 row) ! ! INSERT INTO rw_view2 VALUES (-10); -- ok, but not in view ! INSERT INTO rw_view2 VALUES (20); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (20). ! SELECT * FROM base_tbl; ! a ! ----- ! 5 ! -10 ! (2 rows) ! ! ALTER VIEW rw_view1 SET (check_option=here); -- invalid ! ERROR: invalid value for "check_option" option ! DETAIL: Valid values are "local" and "cascaded". ! ALTER VIEW rw_view1 SET (check_option=local); ! INSERT INTO rw_view2 VALUES (-20); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (-20). ! INSERT INTO rw_view2 VALUES (30); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (30). ! ALTER VIEW rw_view2 RESET (check_option); ! \d+ rw_view2 ! View "public.rw_view2" ! Column | Type | Modifiers | Storage | Description ! --------+---------+-----------+---------+------------- ! a | integer | | plain | ! View definition: ! SELECT rw_view1.a ! FROM rw_view1 ! WHERE rw_view1.a < 10; ! ! SELECT * FROM information_schema.views WHERE table_name = 'rw_view2'; ! table_catalog | table_schema | table_name | view_definition | check_option | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ---------------+--------------+------------+----------------------------+--------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! regression | public | rw_view2 | SELECT rw_view1.a +| NONE | YES | YES | NO | NO | NO ! | | | FROM rw_view1 +| | | | | | ! | | | WHERE (rw_view1.a < 10); | | | | | | ! (1 row) ! ! INSERT INTO rw_view2 VALUES (30); -- ok, but not in view ! SELECT * FROM base_tbl; ! a ! ----- ! 5 ! -10 ! 30 ! (3 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- WITH CHECK OPTION with no local view qual ! CREATE TABLE base_tbl (a int); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WITH CHECK OPTION; ! CREATE VIEW rw_view2 AS SELECT * FROM rw_view1 WHERE a > 0; ! CREATE VIEW rw_view3 AS SELECT * FROM rw_view2 WITH CHECK OPTION; ! SELECT * FROM information_schema.views WHERE table_name LIKE E'rw\\_view_' ORDER BY table_name; ! table_catalog | table_schema | table_name | view_definition | check_option | is_updatable | is_insertable_into | is_trigger_updatable | is_trigger_deletable | is_trigger_insertable_into ! ---------------+--------------+------------+---------------------------+--------------+--------------+--------------------+----------------------+----------------------+---------------------------- ! regression | public | rw_view1 | SELECT base_tbl.a +| CASCADED | YES | YES | NO | NO | NO ! | | | FROM base_tbl; | | | | | | ! regression | public | rw_view2 | SELECT rw_view1.a +| NONE | YES | YES | NO | NO | NO ! | | | FROM rw_view1 +| | | | | | ! | | | WHERE (rw_view1.a > 0); | | | | | | ! regression | public | rw_view3 | SELECT rw_view2.a +| CASCADED | YES | YES | NO | NO | NO ! | | | FROM rw_view2; | | | | | | ! (3 rows) ! ! INSERT INTO rw_view1 VALUES (-1); -- ok ! INSERT INTO rw_view1 VALUES (1); -- ok ! INSERT INTO rw_view2 VALUES (-2); -- ok, but not in view ! INSERT INTO rw_view2 VALUES (2); -- ok ! INSERT INTO rw_view3 VALUES (-3); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (-3). ! INSERT INTO rw_view3 VALUES (3); -- ok ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! drop cascades to view rw_view3 ! -- WITH CHECK OPTION with scalar array ops ! CREATE TABLE base_tbl (a int, b int[]); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a = ANY (b) ! WITH CHECK OPTION; ! INSERT INTO rw_view1 VALUES (1, ARRAY[1,2,3]); -- ok ! INSERT INTO rw_view1 VALUES (10, ARRAY[4,5]); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (10, {4,5}). ! UPDATE rw_view1 SET b[2] = -b[2] WHERE a = 1; -- ok ! UPDATE rw_view1 SET b[1] = -b[1] WHERE a = 1; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (1, {-1,-2,3}). ! PREPARE ins(int, int[]) AS INSERT INTO rw_view1 VALUES($1, $2); ! EXECUTE ins(2, ARRAY[1,2,3]); -- ok ! EXECUTE ins(10, ARRAY[4,5]); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (10, {4,5}). ! DEALLOCATE PREPARE ins; ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- WITH CHECK OPTION with subquery ! CREATE TABLE base_tbl (a int); ! CREATE TABLE ref_tbl (a int PRIMARY KEY); ! INSERT INTO ref_tbl SELECT * FROM generate_series(1,10); ! CREATE VIEW rw_view1 AS ! SELECT * FROM base_tbl b ! WHERE EXISTS(SELECT 1 FROM ref_tbl r WHERE r.a = b.a) ! WITH CHECK OPTION; ! INSERT INTO rw_view1 VALUES (5); -- ok ! INSERT INTO rw_view1 VALUES (15); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (15). ! UPDATE rw_view1 SET a = a + 5; -- ok ! UPDATE rw_view1 SET a = a + 5; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (15). ! EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (5); ! QUERY PLAN ! --------------------------------------------------------------- ! Insert on base_tbl b ! -> Result ! SubPlan 1 ! -> Index Only Scan using ref_tbl_pkey on ref_tbl r ! Index Cond: (a = b.a) ! SubPlan 2 ! -> Seq Scan on ref_tbl r_1 ! (7 rows) ! ! EXPLAIN (costs off) UPDATE rw_view1 SET a = a + 5; ! QUERY PLAN ! ----------------------------------------------------------------- ! Update on base_tbl b ! -> Hash Semi Join ! Hash Cond: (b.a = r.a) ! -> Seq Scan on base_tbl b ! -> Hash ! -> Seq Scan on ref_tbl r ! SubPlan 1 ! -> Index Only Scan using ref_tbl_pkey on ref_tbl r_1 ! Index Cond: (a = b.a) ! SubPlan 2 ! -> Seq Scan on ref_tbl r_2 ! (11 rows) ! ! DROP TABLE base_tbl, ref_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- WITH CHECK OPTION with BEFORE trigger on base table ! CREATE TABLE base_tbl (a int, b int); ! CREATE FUNCTION base_tbl_trig_fn() ! RETURNS trigger AS ! $$ ! BEGIN ! NEW.b := 10; ! RETURN NEW; ! END; ! $$ ! LANGUAGE plpgsql; ! CREATE TRIGGER base_tbl_trig BEFORE INSERT OR UPDATE ON base_tbl ! FOR EACH ROW EXECUTE PROCEDURE base_tbl_trig_fn(); ! CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a < b WITH CHECK OPTION; ! INSERT INTO rw_view1 VALUES (5,0); -- ok ! INSERT INTO rw_view1 VALUES (15, 20); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (15, 10). ! UPDATE rw_view1 SET a = 20, b = 30; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view1" ! DETAIL: Failing row contains (20, 10). ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! DROP FUNCTION base_tbl_trig_fn(); ! -- WITH LOCAL CHECK OPTION with INSTEAD OF trigger on base view ! CREATE TABLE base_tbl (a int, b int); ! CREATE VIEW rw_view1 AS SELECT a FROM base_tbl WHERE a < b; ! CREATE FUNCTION rw_view1_trig_fn() ! RETURNS trigger AS ! $$ ! BEGIN ! IF TG_OP = 'INSERT' THEN ! INSERT INTO base_tbl VALUES (NEW.a, 10); ! RETURN NEW; ! ELSIF TG_OP = 'UPDATE' THEN ! UPDATE base_tbl SET a=NEW.a WHERE a=OLD.a; ! RETURN NEW; ! ELSIF TG_OP = 'DELETE' THEN ! DELETE FROM base_tbl WHERE a=OLD.a; ! RETURN OLD; ! END IF; ! END; ! $$ ! LANGUAGE plpgsql; ! CREATE TRIGGER rw_view1_trig ! INSTEAD OF INSERT OR UPDATE OR DELETE ON rw_view1 ! FOR EACH ROW EXECUTE PROCEDURE rw_view1_trig_fn(); ! CREATE VIEW rw_view2 AS ! SELECT * FROM rw_view1 WHERE a > 0 WITH LOCAL CHECK OPTION; ! INSERT INTO rw_view2 VALUES (-5); -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (-5). ! INSERT INTO rw_view2 VALUES (5); -- ok ! INSERT INTO rw_view2 VALUES (50); -- ok, but not in view ! UPDATE rw_view2 SET a = a - 10; -- should fail ! ERROR: new row violates WITH CHECK OPTION for "rw_view2" ! DETAIL: Failing row contains (-5). ! SELECT * FROM base_tbl; ! a | b ! ----+---- ! 5 | 10 ! 50 | 10 ! (2 rows) ! ! -- Check option won't cascade down to base view with INSTEAD OF triggers ! ALTER VIEW rw_view2 SET (check_option=cascaded); ! INSERT INTO rw_view2 VALUES (100); -- ok, but not in view (doesn't fail rw_view1's check) ! UPDATE rw_view2 SET a = 200 WHERE a = 5; -- ok, but not in view (doesn't fail rw_view1's check) ! SELECT * FROM base_tbl; ! a | b ! -----+---- ! 50 | 10 ! 100 | 10 ! 200 | 10 ! (3 rows) ! ! -- Neither local nor cascaded check options work with INSTEAD rules ! DROP TRIGGER rw_view1_trig ON rw_view1; ! CREATE RULE rw_view1_ins_rule AS ON INSERT TO rw_view1 ! DO INSTEAD INSERT INTO base_tbl VALUES (NEW.a, 10); ! CREATE RULE rw_view1_upd_rule AS ON UPDATE TO rw_view1 ! DO INSTEAD UPDATE base_tbl SET a=NEW.a WHERE a=OLD.a; ! INSERT INTO rw_view2 VALUES (-10); -- ok, but not in view (doesn't fail rw_view2's check) ! INSERT INTO rw_view2 VALUES (5); -- ok ! INSERT INTO rw_view2 VALUES (20); -- ok, but not in view (doesn't fail rw_view1's check) ! UPDATE rw_view2 SET a = 30 WHERE a = 5; -- ok, but not in view (doesn't fail rw_view1's check) ! INSERT INTO rw_view2 VALUES (5); -- ok ! UPDATE rw_view2 SET a = -5 WHERE a = 5; -- ok, but not in view (doesn't fail rw_view2's check) ! SELECT * FROM base_tbl; ! a | b ! -----+---- ! 50 | 10 ! 100 | 10 ! 200 | 10 ! -10 | 10 ! 20 | 10 ! 30 | 10 ! -5 | 10 ! (7 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! DROP FUNCTION rw_view1_trig_fn(); ! CREATE TABLE base_tbl (a int); ! CREATE VIEW rw_view1 AS SELECT a,10 AS b FROM base_tbl; ! CREATE RULE rw_view1_ins_rule AS ON INSERT TO rw_view1 ! DO INSTEAD INSERT INTO base_tbl VALUES (NEW.a); ! CREATE VIEW rw_view2 AS ! SELECT * FROM rw_view1 WHERE a > b WITH LOCAL CHECK OPTION; ! INSERT INTO rw_view2 VALUES (2,3); -- ok, but not in view (doesn't fail rw_view2's check) ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- security barrier view ! CREATE TABLE base_tbl (person text, visibility text); ! INSERT INTO base_tbl VALUES ('Tom', 'public'), ! ('Dick', 'private'), ! ('Harry', 'public'); ! CREATE VIEW rw_view1 AS ! SELECT person FROM base_tbl WHERE visibility = 'public'; ! CREATE FUNCTION snoop(anyelement) ! RETURNS boolean AS ! $$ ! BEGIN ! RAISE NOTICE 'snooped value: %', $1; ! RETURN true; ! END; ! $$ ! LANGUAGE plpgsql COST 0.000001; ! CREATE OR REPLACE FUNCTION leakproof(anyelement) ! RETURNS boolean AS ! $$ ! BEGIN ! RETURN true; ! END; ! $$ ! LANGUAGE plpgsql STRICT IMMUTABLE LEAKPROOF; ! SELECT * FROM rw_view1 WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Dick ! NOTICE: snooped value: Harry ! person ! -------- ! Tom ! Harry ! (2 rows) ! ! UPDATE rw_view1 SET person=person WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Dick ! NOTICE: snooped value: Harry ! DELETE FROM rw_view1 WHERE NOT snoop(person); ! NOTICE: snooped value: Dick ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! ALTER VIEW rw_view1 SET (security_barrier = true); ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name = 'rw_view1'; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view1 | YES ! (1 row) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name = 'rw_view1'; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view1 | YES | YES ! (1 row) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name = 'rw_view1' ! ORDER BY ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view1 | person | YES ! (1 row) ! ! SELECT * FROM rw_view1 WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! person ! -------- ! Tom ! Harry ! (2 rows) ! ! UPDATE rw_view1 SET person=person WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! DELETE FROM rw_view1 WHERE NOT snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! EXPLAIN (costs off) SELECT * FROM rw_view1 WHERE snoop(person); ! QUERY PLAN ! ----------------------------------------------- ! Subquery Scan on rw_view1 ! Filter: snoop(rw_view1.person) ! -> Seq Scan on base_tbl ! Filter: (visibility = 'public'::text) ! (4 rows) ! ! EXPLAIN (costs off) UPDATE rw_view1 SET person=person WHERE snoop(person); ! QUERY PLAN ! ----------------------------------------------------- ! Update on base_tbl base_tbl_1 ! -> Subquery Scan on base_tbl ! Filter: snoop(base_tbl.person) ! -> Seq Scan on base_tbl base_tbl_2 ! Filter: (visibility = 'public'::text) ! (5 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view1 WHERE NOT snoop(person); ! QUERY PLAN ! ----------------------------------------------------- ! Delete on base_tbl base_tbl_1 ! -> Subquery Scan on base_tbl ! Filter: (NOT snoop(base_tbl.person)) ! -> Seq Scan on base_tbl base_tbl_2 ! Filter: (visibility = 'public'::text) ! (5 rows) ! ! -- security barrier view on top of security barrier view ! CREATE VIEW rw_view2 WITH (security_barrier = true) AS ! SELECT * FROM rw_view1 WHERE snoop(person); ! SELECT table_name, is_insertable_into ! FROM information_schema.tables ! WHERE table_name = 'rw_view2'; ! table_name | is_insertable_into ! ------------+-------------------- ! rw_view2 | YES ! (1 row) ! ! SELECT table_name, is_updatable, is_insertable_into ! FROM information_schema.views ! WHERE table_name = 'rw_view2'; ! table_name | is_updatable | is_insertable_into ! ------------+--------------+-------------------- ! rw_view2 | YES | YES ! (1 row) ! ! SELECT table_name, column_name, is_updatable ! FROM information_schema.columns ! WHERE table_name = 'rw_view2' ! ORDER BY ordinal_position; ! table_name | column_name | is_updatable ! ------------+-------------+-------------- ! rw_view2 | person | YES ! (1 row) ! ! SELECT * FROM rw_view2 WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! NOTICE: snooped value: Harry ! person ! -------- ! Tom ! Harry ! (2 rows) ! ! UPDATE rw_view2 SET person=person WHERE snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! NOTICE: snooped value: Harry ! DELETE FROM rw_view2 WHERE NOT snoop(person); ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Tom ! NOTICE: snooped value: Harry ! NOTICE: snooped value: Harry ! EXPLAIN (costs off) SELECT * FROM rw_view2 WHERE snoop(person); ! QUERY PLAN ! ----------------------------------------------------- ! Subquery Scan on rw_view2 ! Filter: snoop(rw_view2.person) ! -> Subquery Scan on rw_view1 ! Filter: snoop(rw_view1.person) ! -> Seq Scan on base_tbl ! Filter: (visibility = 'public'::text) ! (6 rows) ! ! EXPLAIN (costs off) UPDATE rw_view2 SET person=person WHERE snoop(person); ! QUERY PLAN ! ----------------------------------------------------------- ! Update on base_tbl base_tbl_1 ! -> Subquery Scan on base_tbl ! Filter: snoop(base_tbl.person) ! -> Subquery Scan on base_tbl_2 ! Filter: snoop(base_tbl_2.person) ! -> Seq Scan on base_tbl base_tbl_3 ! Filter: (visibility = 'public'::text) ! (7 rows) ! ! EXPLAIN (costs off) DELETE FROM rw_view2 WHERE NOT snoop(person); ! QUERY PLAN ! ----------------------------------------------------------- ! Delete on base_tbl base_tbl_1 ! -> Subquery Scan on base_tbl ! Filter: (NOT snoop(base_tbl.person)) ! -> Subquery Scan on base_tbl_2 ! Filter: snoop(base_tbl_2.person) ! -> Seq Scan on base_tbl base_tbl_3 ! Filter: (visibility = 'public'::text) ! (7 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to view rw_view1 ! drop cascades to view rw_view2 ! -- security barrier view on top of table with rules ! CREATE TABLE base_tbl(id int PRIMARY KEY, data text, deleted boolean); ! INSERT INTO base_tbl VALUES (1, 'Row 1', false), (2, 'Row 2', true); ! CREATE RULE base_tbl_ins_rule AS ON INSERT TO base_tbl ! WHERE EXISTS (SELECT 1 FROM base_tbl t WHERE t.id = new.id) ! DO INSTEAD ! UPDATE base_tbl SET data = new.data, deleted = false WHERE id = new.id; ! CREATE RULE base_tbl_del_rule AS ON DELETE TO base_tbl ! DO INSTEAD ! UPDATE base_tbl SET deleted = true WHERE id = old.id; ! CREATE VIEW rw_view1 WITH (security_barrier=true) AS ! SELECT id, data FROM base_tbl WHERE NOT deleted; ! SELECT * FROM rw_view1; ! id | data ! ----+------- ! 1 | Row 1 ! (1 row) ! ! EXPLAIN (costs off) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); ! QUERY PLAN ! ------------------------------------------------------------------------- ! Update on base_tbl base_tbl_1 ! -> Nested Loop ! -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1 ! Index Cond: (id = 1) ! -> Subquery Scan on base_tbl ! Filter: snoop(base_tbl.data) ! -> Index Scan using base_tbl_pkey on base_tbl base_tbl_2 ! Index Cond: (id = 1) ! Filter: (NOT deleted) ! (9 rows) ! ! DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); ! NOTICE: snooped value: Row 1 ! EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (2, 'New row 2'); ! QUERY PLAN ! ----------------------------------------------------------- ! Insert on base_tbl ! InitPlan 1 (returns $0) ! -> Index Only Scan using base_tbl_pkey on base_tbl t ! Index Cond: (id = 2) ! -> Result ! One-Time Filter: ($0 IS NOT TRUE) ! ! Update on base_tbl ! InitPlan 1 (returns $0) ! -> Index Only Scan using base_tbl_pkey on base_tbl t ! Index Cond: (id = 2) ! -> Result ! One-Time Filter: $0 ! -> Index Scan using base_tbl_pkey on base_tbl ! Index Cond: (id = 2) ! (15 rows) ! ! INSERT INTO rw_view1 VALUES (2, 'New row 2'); ! SELECT * FROM base_tbl; ! id | data | deleted ! ----+-----------+--------- ! 1 | Row 1 | t ! 2 | New row 2 | f ! (2 rows) ! ! DROP TABLE base_tbl CASCADE; ! NOTICE: drop cascades to view rw_view1 ! -- security barrier view based on inheiritance set ! CREATE TABLE t1 (a int, b float, c text); ! CREATE INDEX t1_a_idx ON t1(a); ! INSERT INTO t1 ! SELECT i,i,'t1' FROM generate_series(1,10) g(i); ! ANALYZE t1; ! CREATE TABLE t11 (d text) INHERITS (t1); ! CREATE INDEX t11_a_idx ON t11(a); ! INSERT INTO t11 ! SELECT i,i,'t11','t11d' FROM generate_series(1,10) g(i); ! ANALYZE t11; ! CREATE TABLE t12 (e int[]) INHERITS (t1); ! CREATE INDEX t12_a_idx ON t12(a); ! INSERT INTO t12 ! SELECT i,i,'t12','{1,2}'::int[] FROM generate_series(1,10) g(i); ! ANALYZE t12; ! CREATE TABLE t111 () INHERITS (t11, t12); ! NOTICE: merging multiple inherited definitions of column "a" ! NOTICE: merging multiple inherited definitions of column "b" ! NOTICE: merging multiple inherited definitions of column "c" ! CREATE INDEX t111_a_idx ON t111(a); ! INSERT INTO t111 ! SELECT i,i,'t111','t111d','{1,1,1}'::int[] FROM generate_series(1,10) g(i); ! ANALYZE t111; ! CREATE VIEW v1 WITH (security_barrier=true) AS ! SELECT *, (SELECT d FROM t11 WHERE t11.a = t1.a LIMIT 1) AS d ! FROM t1 ! WHERE a > 5 AND EXISTS(SELECT 1 FROM t12 WHERE t12.a = t1.a); ! SELECT * FROM v1 WHERE a=3; -- should not see anything ! a | b | c | d ! ---+---+---+--- ! (0 rows) ! ! SELECT * FROM v1 WHERE a=8; ! a | b | c | d ! ---+---+------+------ ! 8 | 8 | t1 | t11d ! 8 | 8 | t11 | t11d ! 8 | 8 | t12 | t11d ! 8 | 8 | t111 | t11d ! (4 rows) ! ! EXPLAIN (VERBOSE, COSTS OFF) ! UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; ! QUERY PLAN ! ------------------------------------------------------------------------------------------- ! Update on public.t1 t1_4 ! -> Subquery Scan on t1 ! Output: 100, t1.b, t1.c, t1.ctid ! Filter: snoop(t1.a) ! -> Nested Loop Semi Join ! Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c ! -> Seq Scan on public.t1 t1_5 ! Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c ! Filter: ((t1_5.a > 5) AND (t1_5.a = 3) AND leakproof(t1_5.a)) ! -> Append ! -> Seq Scan on public.t12 ! Output: t12.a ! Filter: (t12.a = 3) ! -> Seq Scan on public.t111 ! Output: t111.a ! Filter: (t111.a = 3) ! -> Subquery Scan on t1_1 ! Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid ! Filter: snoop(t1_1.a) ! -> Nested Loop Semi Join ! Output: t11.ctid, t11.a, t11.b, t11.c, t11.d ! -> Seq Scan on public.t11 ! Output: t11.ctid, t11.a, t11.b, t11.c, t11.d ! Filter: ((t11.a > 5) AND (t11.a = 3) AND leakproof(t11.a)) ! -> Append ! -> Seq Scan on public.t12 t12_1 ! Output: t12_1.a ! Filter: (t12_1.a = 3) ! -> Seq Scan on public.t111 t111_1 ! Output: t111_1.a ! Filter: (t111_1.a = 3) ! -> Subquery Scan on t1_2 ! Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid ! Filter: snoop(t1_2.a) ! -> Nested Loop Semi Join ! Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e ! -> Seq Scan on public.t12 t12_2 ! Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e ! Filter: ((t12_2.a > 5) AND (t12_2.a = 3) AND leakproof(t12_2.a)) ! -> Append ! -> Seq Scan on public.t12 t12_3 ! Output: t12_3.a ! Filter: (t12_3.a = 3) ! -> Seq Scan on public.t111 t111_2 ! Output: t111_2.a ! Filter: (t111_2.a = 3) ! -> Subquery Scan on t1_3 ! Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid ! Filter: snoop(t1_3.a) ! -> Nested Loop Semi Join ! Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e ! -> Seq Scan on public.t111 t111_3 ! Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e ! Filter: ((t111_3.a > 5) AND (t111_3.a = 3) AND leakproof(t111_3.a)) ! -> Append ! -> Seq Scan on public.t12 t12_4 ! Output: t12_4.a ! Filter: (t12_4.a = 3) ! -> Seq Scan on public.t111 t111_4 ! Output: t111_4.a ! Filter: (t111_4.a = 3) ! (61 rows) ! ! UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; ! SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 ! a | b | c | d ! ---+---+---+--- ! (0 rows) ! ! SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 ! a | b | c ! ---+---+--- ! (0 rows) ! ! EXPLAIN (VERBOSE, COSTS OFF) ! UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; ! QUERY PLAN ! ------------------------------------------------------------------------------------------- ! Update on public.t1 t1_4 ! -> Subquery Scan on t1 ! Output: (t1.a + 1), t1.b, t1.c, t1.ctid ! Filter: snoop(t1.a) ! -> Nested Loop Semi Join ! Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c ! -> Seq Scan on public.t1 t1_5 ! Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c ! Filter: ((t1_5.a > 5) AND (t1_5.a = 8) AND leakproof(t1_5.a)) ! -> Append ! -> Seq Scan on public.t12 ! Output: t12.a ! Filter: (t12.a = 8) ! -> Seq Scan on public.t111 ! Output: t111.a ! Filter: (t111.a = 8) ! -> Subquery Scan on t1_1 ! Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid ! Filter: snoop(t1_1.a) ! -> Nested Loop Semi Join ! Output: t11.a, t11.ctid, t11.b, t11.c, t11.d ! -> Seq Scan on public.t11 ! Output: t11.a, t11.ctid, t11.b, t11.c, t11.d ! Filter: ((t11.a > 5) AND (t11.a = 8) AND leakproof(t11.a)) ! -> Append ! -> Seq Scan on public.t12 t12_1 ! Output: t12_1.a ! Filter: (t12_1.a = 8) ! -> Seq Scan on public.t111 t111_1 ! Output: t111_1.a ! Filter: (t111_1.a = 8) ! -> Subquery Scan on t1_2 ! Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid ! Filter: snoop(t1_2.a) ! -> Nested Loop Semi Join ! Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e ! -> Seq Scan on public.t12 t12_2 ! Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e ! Filter: ((t12_2.a > 5) AND (t12_2.a = 8) AND leakproof(t12_2.a)) ! -> Append ! -> Seq Scan on public.t12 t12_3 ! Output: t12_3.a ! Filter: (t12_3.a = 8) ! -> Seq Scan on public.t111 t111_2 ! Output: t111_2.a ! Filter: (t111_2.a = 8) ! -> Subquery Scan on t1_3 ! Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid ! Filter: snoop(t1_3.a) ! -> Nested Loop Semi Join ! Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e ! -> Seq Scan on public.t111 t111_3 ! Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e ! Filter: ((t111_3.a > 5) AND (t111_3.a = 8) AND leakproof(t111_3.a)) ! -> Append ! -> Seq Scan on public.t12 t12_4 ! Output: t12_4.a ! Filter: (t12_4.a = 8) ! -> Seq Scan on public.t111 t111_4 ! Output: t111_4.a ! Filter: (t111_4.a = 8) ! (61 rows) ! ! UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; ! NOTICE: snooped value: 8 ! NOTICE: snooped value: 8 ! NOTICE: snooped value: 8 ! NOTICE: snooped value: 8 ! SELECT * FROM v1 WHERE b=8; ! a | b | c | d ! ---+---+------+------ ! 9 | 8 | t1 | t11d ! 9 | 8 | t11 | t11d ! 9 | 8 | t12 | t11d ! 9 | 8 | t111 | t11d ! (4 rows) ! ! DELETE FROM v1 WHERE snoop(a) AND leakproof(a); -- should not delete everything, just where a>5 ! NOTICE: snooped value: 6 ! NOTICE: snooped value: 7 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 10 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 6 ! NOTICE: snooped value: 7 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 10 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 6 ! NOTICE: snooped value: 7 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 10 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 6 ! NOTICE: snooped value: 7 ! NOTICE: snooped value: 9 ! NOTICE: snooped value: 10 ! NOTICE: snooped value: 9 ! TABLE t1; -- verify all a<=5 are intact ! a | b | c ! ---+---+------ ! 1 | 1 | t1 ! 2 | 2 | t1 ! 3 | 3 | t1 ! 4 | 4 | t1 ! 5 | 5 | t1 ! 1 | 1 | t11 ! 2 | 2 | t11 ! 3 | 3 | t11 ! 4 | 4 | t11 ! 5 | 5 | t11 ! 1 | 1 | t12 ! 2 | 2 | t12 ! 3 | 3 | t12 ! 4 | 4 | t12 ! 5 | 5 | t12 ! 1 | 1 | t111 ! 2 | 2 | t111 ! 3 | 3 | t111 ! 4 | 4 | t111 ! 5 | 5 | t111 ! (20 rows) ! ! DROP TABLE t1, t11, t12, t111 CASCADE; ! NOTICE: drop cascades to view v1 ! DROP FUNCTION snoop(anyelement); ! DROP FUNCTION leakproof(anyelement); --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/sanity_check.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/sanity_check.out Tue Oct 28 15:53:05 2014 *************** *** 1,190 **** ! VACUUM; ! -- ! -- sanity check, if we don't have indices the test will take years to ! -- complete. But skip TOAST relations (since they will have varying ! -- names depending on the current OID counter) as well as temp tables ! -- of other backends (to avoid timing-dependent behavior). ! -- ! -- temporarily disable fancy output, so catalog changes create less diff noise ! \a\t ! SELECT relname, relhasindex ! FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = relnamespace ! WHERE relkind = 'r' AND (nspname ~ '^pg_temp_') IS NOT TRUE ! ORDER BY relname; ! a|f ! a_star|f ! abstime_tbl|f ! aggtest|f ! array_index_op_test|t ! array_op_test|f ! b|f ! b_star|f ! box_tbl|f ! bprime|f ! bt_f8_heap|t ! bt_i4_heap|t ! bt_name_heap|t ! bt_txt_heap|t ! c|f ! c_star|f ! char_tbl|f ! check2_tbl|f ! check_tbl|f ! circle_tbl|t ! city|f ! copy_tbl|f ! d|f ! d_star|f ! date_tbl|f ! default_tbl|f ! defaultexpr_tbl|f ! dept|f ! dupindexcols|t ! e_star|f ! emp|f ! equipment_r|f ! f_star|f ! fast_emp4000|t ! float4_tbl|f ! float8_tbl|f ! func_index_heap|t ! hash_f8_heap|t ! hash_i4_heap|t ! hash_name_heap|t ! hash_txt_heap|t ! hobbies_r|f ! ihighway|t ! inet_tbl|f ! inhf|f ! inhx|t ! insert_tbl|f ! int2_tbl|f ! int4_tbl|f ! int8_tbl|f ! interval_tbl|f ! iportaltest|f ! kd_point_tbl|t ! line_tbl|f ! log_table|f ! lseg_tbl|f ! main_table|f ! money_data|f ! num_data|f ! num_exp_add|t ! num_exp_div|t ! num_exp_ln|t ! num_exp_log10|t ! num_exp_mul|t ! num_exp_power_10_ln|t ! num_exp_sqrt|t ! num_exp_sub|t ! num_input_test|f ! num_result|f ! onek|t ! onek2|t ! path_tbl|f ! person|f ! pg_aggregate|t ! pg_am|t ! pg_amop|t ! pg_amproc|t ! pg_attrdef|t ! pg_attribute|t ! pg_auth_members|t ! pg_authid|t ! pg_cast|t ! pg_class|t ! pg_collation|t ! pg_constraint|t ! pg_conversion|t ! pg_database|t ! pg_db_role_setting|t ! pg_default_acl|t ! pg_depend|t ! pg_description|t ! pg_enum|t ! pg_event_trigger|t ! pg_extension|t ! pg_foreign_data_wrapper|t ! pg_foreign_server|t ! pg_foreign_table|t ! pg_index|t ! pg_inherits|t ! pg_language|t ! pg_largeobject|t ! pg_largeobject_metadata|t ! pg_namespace|t ! pg_opclass|t ! pg_operator|t ! pg_opfamily|t ! pg_pltemplate|t ! pg_proc|t ! pg_range|t ! pg_rewrite|t ! pg_rowsecurity|t ! pg_seclabel|t ! pg_shdepend|t ! pg_shdescription|t ! pg_shseclabel|t ! pg_statistic|t ! pg_tablespace|t ! pg_trigger|t ! pg_ts_config|t ! pg_ts_config_map|t ! pg_ts_dict|t ! pg_ts_parser|t ! pg_ts_template|t ! pg_type|t ! pg_user_mapping|t ! point_tbl|t ! polygon_tbl|t ! quad_point_tbl|t ! radix_text_tbl|t ! ramp|f ! real_city|f ! reltime_tbl|f ! road|t ! shighway|t ! slow_emp4000|f ! sql_features|f ! sql_implementation_info|f ! sql_languages|f ! sql_packages|f ! sql_parts|f ! sql_sizing|f ! sql_sizing_profiles|f ! stud_emp|f ! student|f ! tenk1|t ! tenk2|t ! test_range_excl|t ! test_range_gist|t ! test_range_spgist|t ! test_tsvector|f ! testjsonb|f ! text_tbl|f ! time_tbl|f ! timestamp_tbl|f ! timestamptz_tbl|f ! timetz_tbl|f ! tinterval_tbl|f ! varchar_tbl|f ! -- restore normal output mode ! \a\t ! -- ! -- another sanity check: every system catalog that has OIDs should have ! -- a unique index on OID. This ensures that the OIDs will be unique, ! -- even after the OID counter wraps around. ! -- We exclude non-system tables from the check by looking at nspname. ! -- ! SELECT relname, nspname ! FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = relnamespace ! WHERE relhasoids ! AND ((nspname ~ '^pg_') IS NOT FALSE) ! AND NOT EXISTS (SELECT 1 FROM pg_index i WHERE indrelid = c.oid ! AND indkey[0] = -2 AND indnatts = 1 ! AND indisunique AND indimmediate); ! relname | nspname ! ---------+--------- ! (0 rows) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/errors.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/errors.out Tue Oct 28 15:53:05 2014 *************** *** 1,447 **** ! -- ! -- ERRORS ! -- ! -- bad in postquel, but ok in postsql ! select 1; ! ?column? ! ---------- ! 1 ! (1 row) ! ! -- ! -- UNSUPPORTED STUFF ! -- doesn't work ! -- notify pg_class ! -- ! -- ! -- SELECT ! -- this used to be a syntax error, but now we allow an empty target list ! select; ! -- ! (1 row) ! ! -- no such relation ! select * from nonesuch; ! ERROR: relation "nonesuch" does not exist ! LINE 1: select * from nonesuch; ! ^ ! -- bad name in target list ! select nonesuch from pg_database; ! ERROR: column "nonesuch" does not exist ! LINE 1: select nonesuch from pg_database; ! ^ ! -- empty distinct list isn't OK ! select distinct from pg_database; ! ERROR: SELECT DISTINCT must have at least one column ! -- bad attribute name on lhs of operator ! select * from pg_database where nonesuch = pg_database.datname; ! ERROR: column "nonesuch" does not exist ! LINE 1: select * from pg_database where nonesuch = pg_database.datna... ! ^ ! -- bad attribute name on rhs of operator ! select * from pg_database where pg_database.datname = nonesuch; ! ERROR: column "nonesuch" does not exist ! LINE 1: ...ect * from pg_database where pg_database.datname = nonesuch; ! ^ ! -- bad attribute name in select distinct on ! select distinct on (foobar) * from pg_database; ! ERROR: column "foobar" does not exist ! LINE 1: select distinct on (foobar) * from pg_database; ! ^ ! -- ! -- DELETE ! -- missing relation name (this had better not wildcard!) ! delete from; ! ERROR: syntax error at or near ";" ! LINE 1: delete from; ! ^ ! -- no such relation ! delete from nonesuch; ! ERROR: relation "nonesuch" does not exist ! LINE 1: delete from nonesuch; ! ^ ! -- ! -- DROP ! -- missing relation name (this had better not wildcard!) ! drop table; ! ERROR: syntax error at or near ";" ! LINE 1: drop table; ! ^ ! -- no such relation ! drop table nonesuch; ! ERROR: table "nonesuch" does not exist ! -- ! -- ALTER TABLE ! -- relation renaming ! -- missing relation name ! alter table rename; ! ERROR: syntax error at or near ";" ! LINE 1: alter table rename; ! ^ ! -- no such relation ! alter table nonesuch rename to newnonesuch; ! ERROR: relation "nonesuch" does not exist ! -- no such relation ! alter table nonesuch rename to stud_emp; ! ERROR: relation "nonesuch" does not exist ! -- conflict ! alter table stud_emp rename to aggtest; ! ERROR: relation "aggtest" already exists ! -- self-conflict ! alter table stud_emp rename to stud_emp; ! ERROR: relation "stud_emp" already exists ! -- attribute renaming ! -- no such relation ! alter table nonesuchrel rename column nonesuchatt to newnonesuchatt; ! ERROR: relation "nonesuchrel" does not exist ! -- no such attribute ! alter table emp rename column nonesuchatt to newnonesuchatt; ! ERROR: column "nonesuchatt" does not exist ! -- conflict ! alter table emp rename column salary to manager; ! ERROR: column "manager" of relation "stud_emp" already exists ! -- conflict ! alter table emp rename column salary to oid; ! ERROR: column name "oid" conflicts with a system column name ! -- ! -- TRANSACTION STUFF ! -- not in a xact ! abort; ! WARNING: there is no transaction in progress ! -- not in a xact ! end; ! WARNING: there is no transaction in progress ! -- ! -- CREATE AGGREGATE ! -- sfunc/finalfunc type disagreement ! create aggregate newavg2 (sfunc = int4pl, ! basetype = int4, ! stype = int4, ! finalfunc = int2um, ! initcond = '0'); ! ERROR: function int2um(integer) does not exist ! -- left out basetype ! create aggregate newcnt1 (sfunc = int4inc, ! stype = int4, ! initcond = '0'); ! ERROR: aggregate input type must be specified ! -- ! -- DROP INDEX ! -- missing index name ! drop index; ! ERROR: syntax error at or near ";" ! LINE 1: drop index; ! ^ ! -- bad index name ! drop index 314159; ! ERROR: syntax error at or near "314159" ! LINE 1: drop index 314159; ! ^ ! -- no such index ! drop index nonesuch; ! ERROR: index "nonesuch" does not exist ! -- ! -- DROP AGGREGATE ! -- missing aggregate name ! drop aggregate; ! ERROR: syntax error at or near ";" ! LINE 1: drop aggregate; ! ^ ! -- missing aggregate type ! drop aggregate newcnt1; ! ERROR: syntax error at or near ";" ! LINE 1: drop aggregate newcnt1; ! ^ ! -- bad aggregate name ! drop aggregate 314159 (int); ! ERROR: syntax error at or near "314159" ! LINE 1: drop aggregate 314159 (int); ! ^ ! -- bad aggregate type ! drop aggregate newcnt (nonesuch); ! ERROR: type "nonesuch" does not exist ! -- no such aggregate ! drop aggregate nonesuch (int4); ! ERROR: aggregate nonesuch(integer) does not exist ! -- no such aggregate for type ! drop aggregate newcnt (float4); ! ERROR: aggregate newcnt(real) does not exist ! -- ! -- DROP FUNCTION ! -- missing function name ! drop function (); ! ERROR: syntax error at or near "(" ! LINE 1: drop function (); ! ^ ! -- bad function name ! drop function 314159(); ! ERROR: syntax error at or near "314159" ! LINE 1: drop function 314159(); ! ^ ! -- no such function ! drop function nonesuch(); ! ERROR: function nonesuch() does not exist ! -- ! -- DROP TYPE ! -- missing type name ! drop type; ! ERROR: syntax error at or near ";" ! LINE 1: drop type; ! ^ ! -- bad type name ! drop type 314159; ! ERROR: syntax error at or near "314159" ! LINE 1: drop type 314159; ! ^ ! -- no such type ! drop type nonesuch; ! ERROR: type "nonesuch" does not exist ! -- ! -- DROP OPERATOR ! -- missing everything ! drop operator; ! ERROR: syntax error at or near ";" ! LINE 1: drop operator; ! ^ ! -- bad operator name ! drop operator equals; ! ERROR: syntax error at or near ";" ! LINE 1: drop operator equals; ! ^ ! -- missing type list ! drop operator ===; ! ERROR: syntax error at or near ";" ! LINE 1: drop operator ===; ! ^ ! -- missing parentheses ! drop operator int4, int4; ! ERROR: syntax error at or near "," ! LINE 1: drop operator int4, int4; ! ^ ! -- missing operator name ! drop operator (int4, int4); ! ERROR: syntax error at or near "(" ! LINE 1: drop operator (int4, int4); ! ^ ! -- missing type list contents ! drop operator === (); ! ERROR: syntax error at or near ")" ! LINE 1: drop operator === (); ! ^ ! -- no such operator ! drop operator === (int4); ! ERROR: missing argument ! LINE 1: drop operator === (int4); ! ^ ! HINT: Use NONE to denote the missing argument of a unary operator. ! -- no such operator by that name ! drop operator === (int4, int4); ! ERROR: operator does not exist: integer === integer ! -- no such type1 ! drop operator = (nonesuch); ! ERROR: missing argument ! LINE 1: drop operator = (nonesuch); ! ^ ! HINT: Use NONE to denote the missing argument of a unary operator. ! -- no such type1 ! drop operator = ( , int4); ! ERROR: syntax error at or near "," ! LINE 1: drop operator = ( , int4); ! ^ ! -- no such type1 ! drop operator = (nonesuch, int4); ! ERROR: type "nonesuch" does not exist ! -- no such type2 ! drop operator = (int4, nonesuch); ! ERROR: type "nonesuch" does not exist ! -- no such type2 ! drop operator = (int4, ); ! ERROR: syntax error at or near ")" ! LINE 1: drop operator = (int4, ); ! ^ ! -- ! -- DROP RULE ! -- missing rule name ! drop rule; ! ERROR: syntax error at or near ";" ! LINE 1: drop rule; ! ^ ! -- bad rule name ! drop rule 314159; ! ERROR: syntax error at or near "314159" ! LINE 1: drop rule 314159; ! ^ ! -- no such rule ! drop rule nonesuch on noplace; ! ERROR: relation "noplace" does not exist ! -- these postquel variants are no longer supported ! drop tuple rule nonesuch; ! ERROR: syntax error at or near "tuple" ! LINE 1: drop tuple rule nonesuch; ! ^ ! drop instance rule nonesuch on noplace; ! ERROR: syntax error at or near "instance" ! LINE 1: drop instance rule nonesuch on noplace; ! ^ ! drop rewrite rule nonesuch; ! ERROR: syntax error at or near "rewrite" ! LINE 1: drop rewrite rule nonesuch; ! ^ ! -- ! -- Check that division-by-zero is properly caught. ! -- ! select 1/0; ! ERROR: division by zero ! select 1::int8/0; ! ERROR: division by zero ! select 1/0::int8; ! ERROR: division by zero ! select 1::int2/0; ! ERROR: division by zero ! select 1/0::int2; ! ERROR: division by zero ! select 1::numeric/0; ! ERROR: division by zero ! select 1/0::numeric; ! ERROR: division by zero ! select 1::float8/0; ! ERROR: division by zero ! select 1/0::float8; ! ERROR: division by zero ! select 1::float4/0; ! ERROR: division by zero ! select 1/0::float4; ! ERROR: division by zero ! -- ! -- Test psql's reporting of syntax error location ! -- ! xxx; ! ERROR: syntax error at or near "xxx" ! LINE 1: xxx; ! ^ ! CREATE foo; ! ERROR: syntax error at or near "foo" ! LINE 1: CREATE foo; ! ^ ! CREATE TABLE ; ! ERROR: syntax error at or near ";" ! LINE 1: CREATE TABLE ; ! ^ ! CREATE TABLE ! \g ! ERROR: syntax error at end of input ! LINE 1: CREATE TABLE ! ^ ! INSERT INTO foo VALUES(123) foo; ! ERROR: syntax error at or near "foo" ! LINE 1: INSERT INTO foo VALUES(123) foo; ! ^ ! INSERT INTO 123 ! VALUES(123); ! ERROR: syntax error at or near "123" ! LINE 1: INSERT INTO 123 ! ^ ! INSERT INTO foo ! VALUES(123) 123 ! ; ! ERROR: syntax error at or near "123" ! LINE 2: VALUES(123) 123 ! ^ ! -- with a tab ! CREATE TABLE foo ! (id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, ! id3 INTEGER NOT NUL, ! id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL); ! ERROR: syntax error at or near "NUL" ! LINE 3: id3 INTEGER NOT NUL, ! ^ ! -- long line to be truncated on the left ! CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, ! id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL); ! ERROR: syntax error at or near "NUL" ! LINE 1: ...OT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, ! ^ ! -- long line to be truncated on the right ! CREATE TABLE foo( ! id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY); ! ERROR: syntax error at or near "NUL" ! LINE 2: id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQ... ! ^ ! -- long line to be truncated both ways ! CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL); ! ERROR: syntax error at or near "NUL" ! LINE 1: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I... ! ^ ! -- long line to be truncated on the left, many lines ! CREATE ! TEMPORARY ! TABLE ! foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, ! id4 INT4 ! UNIQUE ! NOT ! NULL, ! id5 TEXT ! UNIQUE ! NOT ! NULL) ! ; ! ERROR: syntax error at or near "NUL" ! LINE 4: ...OT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, ! ^ ! -- long line to be truncated on the right, many lines ! CREATE ! TEMPORARY ! TABLE ! foo( ! id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY) ! ; ! ERROR: syntax error at or near "NUL" ! LINE 5: id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQ... ! ^ ! -- long line to be truncated both ways, many lines ! CREATE ! TEMPORARY ! TABLE ! foo ! (id ! INT4 ! UNIQUE NOT NULL, idx INT4 UNIQUE NOT NULL, idy INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, ! idz INT4 UNIQUE NOT NULL, ! idv INT4 UNIQUE NOT NULL); ! ERROR: syntax error at or near "NUL" ! LINE 7: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I... ! ^ ! -- more than 10 lines... ! CREATE ! TEMPORARY ! TABLE ! foo ! (id ! INT4 ! UNIQUE ! NOT ! NULL ! , ! idm ! INT4 ! UNIQUE ! NOT ! NULL, ! idx INT4 UNIQUE NOT NULL, idy INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, ! idz INT4 UNIQUE NOT NULL, ! idv ! INT4 ! UNIQUE ! NOT ! NULL); ! ERROR: syntax error at or near "NUL" ! LINE 16: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I... ! ^ ! -- Check that stack depth detection mechanism works and ! -- max_stack_depth is not set too high ! create function infinite_recurse() returns int as ! 'select infinite_recurse()' language sql; ! \set VERBOSITY terse ! select infinite_recurse(); ! ERROR: stack depth limit exceeded --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select.out Sun Dec 12 20:21:38 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select.out Tue Oct 28 15:53:05 2014 *************** *** 1,783 **** ! -- ! -- SELECT ! -- ! -- btree index ! -- awk '{if($1<10){print;}else{next;}}' onek.data | sort +0n -1 ! -- ! SELECT * FROM onek ! WHERE onek.unique1 < 10 ! ORDER BY onek.unique1; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 0 | 998 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | AAAAAA | KMBAAA | OOOOxx ! 1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx ! 2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx ! 3 | 431 | 1 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 6 | 7 | DAAAAA | PQAAAA | VVVVxx ! 4 | 833 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 8 | 9 | EAAAAA | BGBAAA | HHHHxx ! 5 | 541 | 1 | 1 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 10 | 11 | FAAAAA | VUAAAA | HHHHxx ! 6 | 978 | 0 | 2 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 12 | 13 | GAAAAA | QLBAAA | OOOOxx ! 7 | 647 | 1 | 3 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 14 | 15 | HAAAAA | XYAAAA | VVVVxx ! 8 | 653 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 16 | 17 | IAAAAA | DZAAAA | HHHHxx ! 9 | 49 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 18 | 19 | JAAAAA | XBAAAA | HHHHxx ! (10 rows) ! ! -- ! -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 ! -- ! SELECT onek.unique1, onek.stringu1 FROM onek ! WHERE onek.unique1 < 20 ! ORDER BY unique1 using >; ! unique1 | stringu1 ! ---------+---------- ! 19 | TAAAAA ! 18 | SAAAAA ! 17 | RAAAAA ! 16 | QAAAAA ! 15 | PAAAAA ! 14 | OAAAAA ! 13 | NAAAAA ! 12 | MAAAAA ! 11 | LAAAAA ! 10 | KAAAAA ! 9 | JAAAAA ! 8 | IAAAAA ! 7 | HAAAAA ! 6 | GAAAAA ! 5 | FAAAAA ! 4 | EAAAAA ! 3 | DAAAAA ! 2 | CAAAAA ! 1 | BAAAAA ! 0 | AAAAAA ! (20 rows) ! ! -- ! -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 ! -- ! SELECT onek.unique1, onek.stringu1 FROM onek ! WHERE onek.unique1 > 980 ! ORDER BY stringu1 using <; ! unique1 | stringu1 ! ---------+---------- ! 988 | AMAAAA ! 989 | BMAAAA ! 990 | CMAAAA ! 991 | DMAAAA ! 992 | EMAAAA ! 993 | FMAAAA ! 994 | GMAAAA ! 995 | HMAAAA ! 996 | IMAAAA ! 997 | JMAAAA ! 998 | KMAAAA ! 999 | LMAAAA ! 981 | TLAAAA ! 982 | ULAAAA ! 983 | VLAAAA ! 984 | WLAAAA ! 985 | XLAAAA ! 986 | YLAAAA ! 987 | ZLAAAA ! (19 rows) ! ! -- ! -- awk '{if($1>980){print $1,$16;}else{next;}}' onek.data | ! -- sort +1d -2 +0nr -1 ! -- ! SELECT onek.unique1, onek.string4 FROM onek ! WHERE onek.unique1 > 980 ! ORDER BY string4 using <, unique1 using >; ! unique1 | string4 ! ---------+--------- ! 999 | AAAAxx ! 995 | AAAAxx ! 983 | AAAAxx ! 982 | AAAAxx ! 981 | AAAAxx ! 998 | HHHHxx ! 997 | HHHHxx ! 993 | HHHHxx ! 990 | HHHHxx ! 986 | HHHHxx ! 996 | OOOOxx ! 991 | OOOOxx ! 988 | OOOOxx ! 987 | OOOOxx ! 985 | OOOOxx ! 994 | VVVVxx ! 992 | VVVVxx ! 989 | VVVVxx ! 984 | VVVVxx ! (19 rows) ! ! -- ! -- awk '{if($1>980){print $1,$16;}else{next;}}' onek.data | ! -- sort +1dr -2 +0n -1 ! -- ! SELECT onek.unique1, onek.string4 FROM onek ! WHERE onek.unique1 > 980 ! ORDER BY string4 using >, unique1 using <; ! unique1 | string4 ! ---------+--------- ! 984 | VVVVxx ! 989 | VVVVxx ! 992 | VVVVxx ! 994 | VVVVxx ! 985 | OOOOxx ! 987 | OOOOxx ! 988 | OOOOxx ! 991 | OOOOxx ! 996 | OOOOxx ! 986 | HHHHxx ! 990 | HHHHxx ! 993 | HHHHxx ! 997 | HHHHxx ! 998 | HHHHxx ! 981 | AAAAxx ! 982 | AAAAxx ! 983 | AAAAxx ! 995 | AAAAxx ! 999 | AAAAxx ! (19 rows) ! ! -- ! -- awk '{if($1<20){print $1,$16;}else{next;}}' onek.data | ! -- sort +0nr -1 +1d -2 ! -- ! SELECT onek.unique1, onek.string4 FROM onek ! WHERE onek.unique1 < 20 ! ORDER BY unique1 using >, string4 using <; ! unique1 | string4 ! ---------+--------- ! 19 | OOOOxx ! 18 | VVVVxx ! 17 | HHHHxx ! 16 | OOOOxx ! 15 | VVVVxx ! 14 | AAAAxx ! 13 | OOOOxx ! 12 | AAAAxx ! 11 | OOOOxx ! 10 | AAAAxx ! 9 | HHHHxx ! 8 | HHHHxx ! 7 | VVVVxx ! 6 | OOOOxx ! 5 | HHHHxx ! 4 | HHHHxx ! 3 | VVVVxx ! 2 | OOOOxx ! 1 | OOOOxx ! 0 | OOOOxx ! (20 rows) ! ! -- ! -- awk '{if($1<20){print $1,$16;}else{next;}}' onek.data | ! -- sort +0n -1 +1dr -2 ! -- ! SELECT onek.unique1, onek.string4 FROM onek ! WHERE onek.unique1 < 20 ! ORDER BY unique1 using <, string4 using >; ! unique1 | string4 ! ---------+--------- ! 0 | OOOOxx ! 1 | OOOOxx ! 2 | OOOOxx ! 3 | VVVVxx ! 4 | HHHHxx ! 5 | HHHHxx ! 6 | OOOOxx ! 7 | VVVVxx ! 8 | HHHHxx ! 9 | HHHHxx ! 10 | AAAAxx ! 11 | OOOOxx ! 12 | AAAAxx ! 13 | OOOOxx ! 14 | AAAAxx ! 15 | VVVVxx ! 16 | OOOOxx ! 17 | HHHHxx ! 18 | VVVVxx ! 19 | OOOOxx ! (20 rows) ! ! -- ! -- test partial btree indexes ! -- ! -- As of 7.2, planner probably won't pick an indexscan without stats, ! -- so ANALYZE first. Also, we want to prevent it from picking a bitmapscan ! -- followed by sort, because that could hide index ordering problems. ! -- ! ANALYZE onek2; ! SET enable_seqscan TO off; ! SET enable_bitmapscan TO off; ! SET enable_sort TO off; ! -- ! -- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 ! -- ! SELECT onek2.* FROM onek2 WHERE onek2.unique1 < 10; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 0 | 998 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | AAAAAA | KMBAAA | OOOOxx ! 1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx ! 2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx ! 3 | 431 | 1 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 6 | 7 | DAAAAA | PQAAAA | VVVVxx ! 4 | 833 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 8 | 9 | EAAAAA | BGBAAA | HHHHxx ! 5 | 541 | 1 | 1 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 10 | 11 | FAAAAA | VUAAAA | HHHHxx ! 6 | 978 | 0 | 2 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 12 | 13 | GAAAAA | QLBAAA | OOOOxx ! 7 | 647 | 1 | 3 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 14 | 15 | HAAAAA | XYAAAA | VVVVxx ! 8 | 653 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 16 | 17 | IAAAAA | DZAAAA | HHHHxx ! 9 | 49 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 18 | 19 | JAAAAA | XBAAAA | HHHHxx ! (10 rows) ! ! -- ! -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 ! -- ! SELECT onek2.unique1, onek2.stringu1 FROM onek2 ! WHERE onek2.unique1 < 20 ! ORDER BY unique1 using >; ! unique1 | stringu1 ! ---------+---------- ! 19 | TAAAAA ! 18 | SAAAAA ! 17 | RAAAAA ! 16 | QAAAAA ! 15 | PAAAAA ! 14 | OAAAAA ! 13 | NAAAAA ! 12 | MAAAAA ! 11 | LAAAAA ! 10 | KAAAAA ! 9 | JAAAAA ! 8 | IAAAAA ! 7 | HAAAAA ! 6 | GAAAAA ! 5 | FAAAAA ! 4 | EAAAAA ! 3 | DAAAAA ! 2 | CAAAAA ! 1 | BAAAAA ! 0 | AAAAAA ! (20 rows) ! ! -- ! -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 ! -- ! SELECT onek2.unique1, onek2.stringu1 FROM onek2 ! WHERE onek2.unique1 > 980; ! unique1 | stringu1 ! ---------+---------- ! 981 | TLAAAA ! 982 | ULAAAA ! 983 | VLAAAA ! 984 | WLAAAA ! 985 | XLAAAA ! 986 | YLAAAA ! 987 | ZLAAAA ! 988 | AMAAAA ! 989 | BMAAAA ! 990 | CMAAAA ! 991 | DMAAAA ! 992 | EMAAAA ! 993 | FMAAAA ! 994 | GMAAAA ! 995 | HMAAAA ! 996 | IMAAAA ! 997 | JMAAAA ! 998 | KMAAAA ! 999 | LMAAAA ! (19 rows) ! ! RESET enable_seqscan; ! RESET enable_bitmapscan; ! RESET enable_sort; ! SELECT two, stringu1, ten, string4 ! INTO TABLE tmp ! FROM onek; ! -- ! -- awk '{print $1,$2;}' person.data | ! -- awk '{if(NF!=2){print $3,$2;}else{print;}}' - emp.data | ! -- awk '{if(NF!=2){print $3,$2;}else{print;}}' - student.data | ! -- awk 'BEGIN{FS=" ";}{if(NF!=2){print $4,$5;}else{print;}}' - stud_emp.data ! -- ! -- SELECT name, age FROM person*; ??? check if different ! SELECT p.name, p.age FROM person* p; ! name | age ! ---------+----- ! mike | 40 ! joe | 20 ! sally | 34 ! sandra | 19 ! alex | 30 ! sue | 50 ! denise | 24 ! sarah | 88 ! teresa | 38 ! nan | 28 ! leah | 68 ! wendy | 78 ! melissa | 28 ! joan | 18 ! mary | 8 ! jane | 58 ! liza | 38 ! jean | 28 ! jenifer | 38 ! juanita | 58 ! susan | 78 ! zena | 98 ! martie | 88 ! chris | 78 ! pat | 18 ! zola | 58 ! louise | 98 ! edna | 18 ! bertha | 88 ! sumi | 38 ! koko | 88 ! gina | 18 ! rean | 48 ! sharon | 78 ! paula | 68 ! julie | 68 ! belinda | 38 ! karen | 48 ! carina | 58 ! diane | 18 ! esther | 98 ! trudy | 88 ! fanny | 8 ! carmen | 78 ! lita | 25 ! pamela | 48 ! sandy | 38 ! trisha | 88 ! uma | 78 ! velma | 68 ! sharon | 25 ! sam | 30 ! bill | 20 ! fred | 28 ! larry | 60 ! jeff | 23 ! cim | 30 ! linda | 19 ! (58 rows) ! ! -- ! -- awk '{print $1,$2;}' person.data | ! -- awk '{if(NF!=2){print $3,$2;}else{print;}}' - emp.data | ! -- awk '{if(NF!=2){print $3,$2;}else{print;}}' - student.data | ! -- awk 'BEGIN{FS=" ";}{if(NF!=1){print $4,$5;}else{print;}}' - stud_emp.data | ! -- sort +1nr -2 ! -- ! SELECT p.name, p.age FROM person* p ORDER BY age using >, name; ! name | age ! ---------+----- ! esther | 98 ! louise | 98 ! zena | 98 ! bertha | 88 ! koko | 88 ! martie | 88 ! sarah | 88 ! trisha | 88 ! trudy | 88 ! carmen | 78 ! chris | 78 ! sharon | 78 ! susan | 78 ! uma | 78 ! wendy | 78 ! julie | 68 ! leah | 68 ! paula | 68 ! velma | 68 ! larry | 60 ! carina | 58 ! jane | 58 ! juanita | 58 ! zola | 58 ! sue | 50 ! karen | 48 ! pamela | 48 ! rean | 48 ! mike | 40 ! belinda | 38 ! jenifer | 38 ! liza | 38 ! sandy | 38 ! sumi | 38 ! teresa | 38 ! sally | 34 ! alex | 30 ! cim | 30 ! sam | 30 ! fred | 28 ! jean | 28 ! melissa | 28 ! nan | 28 ! lita | 25 ! sharon | 25 ! denise | 24 ! jeff | 23 ! bill | 20 ! joe | 20 ! linda | 19 ! sandra | 19 ! diane | 18 ! edna | 18 ! gina | 18 ! joan | 18 ! pat | 18 ! fanny | 8 ! mary | 8 ! (58 rows) ! ! -- ! -- Test some cases involving whole-row Var referencing a subquery ! -- ! select foo from (select 1) as foo; ! foo ! ----- ! (1) ! (1 row) ! ! select foo from (select null) as foo; ! foo ! ----- ! () ! (1 row) ! ! select foo from (select 'xyzzy',1,null) as foo; ! foo ! ------------ ! (xyzzy,1,) ! (1 row) ! ! -- ! -- Test VALUES lists ! -- ! select * from onek, (values(147, 'RFAAAA'), (931, 'VJAAAA')) as v (i, j) ! WHERE onek.unique1 = v.i and onek.stringu1 = v.j; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 | i | j ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------+-----+-------- ! 147 | 0 | 1 | 3 | 7 | 7 | 7 | 47 | 147 | 147 | 147 | 14 | 15 | RFAAAA | AAAAAA | AAAAxx | 147 | RFAAAA ! 931 | 1 | 1 | 3 | 1 | 11 | 1 | 31 | 131 | 431 | 931 | 2 | 3 | VJAAAA | BAAAAA | HHHHxx | 931 | VJAAAA ! (2 rows) ! ! -- a more complex case ! -- looks like we're coding lisp :-) ! select * from onek, ! (values ((select i from ! (values(10000), (2), (389), (1000), (2000), ((select 10029))) as foo(i) ! order by i asc limit 1))) bar (i) ! where onek.unique1 = bar.i; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 | i ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------+--- ! 2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx | 2 ! (1 row) ! ! -- try VALUES in a subquery ! select * from onek ! where (unique1,ten) in (values (1,1), (20,0), (99,9), (17,99)) ! order by unique1; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx ! 20 | 306 | 0 | 0 | 0 | 0 | 0 | 20 | 20 | 20 | 20 | 0 | 1 | UAAAAA | ULAAAA | OOOOxx ! 99 | 101 | 1 | 3 | 9 | 19 | 9 | 99 | 99 | 99 | 99 | 18 | 19 | VDAAAA | XDAAAA | HHHHxx ! (3 rows) ! ! -- VALUES is also legal as a standalone query or a set-operation member ! VALUES (1,2), (3,4+4), (7,77.7); ! column1 | column2 ! ---------+--------- ! 1 | 2 ! 3 | 8 ! 7 | 77.7 ! (3 rows) ! ! VALUES (1,2), (3,4+4), (7,77.7) ! UNION ALL ! SELECT 2+2, 57 ! UNION ALL ! TABLE int8_tbl; ! column1 | column2 ! ------------------+------------------- ! 1 | 2 ! 3 | 8 ! 7 | 77.7 ! 4 | 57 ! 123 | 456 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! (9 rows) ! ! -- ! -- Test ORDER BY options ! -- ! CREATE TEMP TABLE foo (f1 int); ! INSERT INTO foo VALUES (42),(3),(10),(7),(null),(null),(1); ! SELECT * FROM foo ORDER BY f1; ! f1 ! ---- ! 1 ! 3 ! 7 ! 10 ! 42 ! ! ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 ASC; -- same thing ! f1 ! ---- ! 1 ! 3 ! 7 ! 10 ! 42 ! ! ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 NULLS FIRST; ! f1 ! ---- ! ! ! 1 ! 3 ! 7 ! 10 ! 42 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC; ! f1 ! ---- ! ! ! 42 ! 10 ! 7 ! 3 ! 1 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; ! f1 ! ---- ! 42 ! 10 ! 7 ! 3 ! 1 ! ! ! (7 rows) ! ! -- check if indexscans do the right things ! CREATE INDEX fooi ON foo (f1); ! SET enable_sort = false; ! SELECT * FROM foo ORDER BY f1; ! f1 ! ---- ! 1 ! 3 ! 7 ! 10 ! 42 ! ! ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 NULLS FIRST; ! f1 ! ---- ! ! ! 1 ! 3 ! 7 ! 10 ! 42 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC; ! f1 ! ---- ! ! ! 42 ! 10 ! 7 ! 3 ! 1 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; ! f1 ! ---- ! 42 ! 10 ! 7 ! 3 ! 1 ! ! ! (7 rows) ! ! DROP INDEX fooi; ! CREATE INDEX fooi ON foo (f1 DESC); ! SELECT * FROM foo ORDER BY f1; ! f1 ! ---- ! 1 ! 3 ! 7 ! 10 ! 42 ! ! ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 NULLS FIRST; ! f1 ! ---- ! ! ! 1 ! 3 ! 7 ! 10 ! 42 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC; ! f1 ! ---- ! ! ! 42 ! 10 ! 7 ! 3 ! 1 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; ! f1 ! ---- ! 42 ! 10 ! 7 ! 3 ! 1 ! ! ! (7 rows) ! ! DROP INDEX fooi; ! CREATE INDEX fooi ON foo (f1 DESC NULLS LAST); ! SELECT * FROM foo ORDER BY f1; ! f1 ! ---- ! 1 ! 3 ! 7 ! 10 ! 42 ! ! ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 NULLS FIRST; ! f1 ! ---- ! ! ! 1 ! 3 ! 7 ! 10 ! 42 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC; ! f1 ! ---- ! ! ! 42 ! 10 ! 7 ! 3 ! 1 ! (7 rows) ! ! SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; ! f1 ! ---- ! 42 ! 10 ! 7 ! 3 ! 1 ! ! ! (7 rows) ! ! -- ! -- Test some corner cases that have been known to confuse the planner ! -- ! -- ORDER BY on a constant doesn't really need any sorting ! SELECT 1 AS x ORDER BY x; ! x ! --- ! 1 ! (1 row) ! ! -- But ORDER BY on a set-valued expression does ! create function sillysrf(int) returns setof int as ! 'values (1),(10),(2),($1)' language sql immutable; ! select sillysrf(42); ! sillysrf ! ---------- ! 1 ! 10 ! 2 ! 42 ! (4 rows) ! ! select sillysrf(-1) order by 1; ! sillysrf ! ---------- ! -1 ! 1 ! 2 ! 10 ! (4 rows) ! ! drop function sillysrf(int); ! -- X = X isn't a no-op, it's effectively X IS NOT NULL assuming = is strict ! -- (see bug #5084) ! select * from (values (2),(null),(1)) v(k) where k = k order by k; ! k ! --- ! 1 ! 2 ! (2 rows) ! ! select * from (values (2),(null),(1)) v(k) where k = k; ! k ! --- ! 2 ! 1 ! (2 rows) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select_into.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select_into.out Tue Oct 28 15:53:05 2014 *************** *** 1,96 **** ! -- ! -- SELECT_INTO ! -- ! SELECT * ! INTO TABLE tmp1 ! FROM onek ! WHERE onek.unique1 < 2; ! DROP TABLE tmp1; ! SELECT * ! INTO TABLE tmp1 ! FROM onek2 ! WHERE onek2.unique1 < 2; ! DROP TABLE tmp1; ! -- ! -- SELECT INTO and INSERT permission, if owner is not allowed to insert. ! -- ! CREATE SCHEMA selinto_schema; ! CREATE USER selinto_user; ! ALTER DEFAULT PRIVILEGES FOR ROLE selinto_user ! REVOKE INSERT ON TABLES FROM selinto_user; ! GRANT ALL ON SCHEMA selinto_schema TO public; ! SET SESSION AUTHORIZATION selinto_user; ! SELECT * INTO TABLE selinto_schema.tmp1 ! FROM pg_class WHERE relname like '%a%'; -- Error ! ERROR: permission denied for relation tmp1 ! SELECT oid AS clsoid, relname, relnatts + 10 AS x ! INTO selinto_schema.tmp2 ! FROM pg_class WHERE relname like '%b%'; -- Error ! ERROR: permission denied for relation tmp2 ! CREATE TABLE selinto_schema.tmp3 (a,b,c) ! AS SELECT oid,relname,relacl FROM pg_class ! WHERE relname like '%c%'; -- Error ! ERROR: permission denied for relation tmp3 ! RESET SESSION AUTHORIZATION; ! ALTER DEFAULT PRIVILEGES FOR ROLE selinto_user ! GRANT INSERT ON TABLES TO selinto_user; ! SET SESSION AUTHORIZATION selinto_user; ! SELECT * INTO TABLE selinto_schema.tmp1 ! FROM pg_class WHERE relname like '%a%'; -- OK ! SELECT oid AS clsoid, relname, relnatts + 10 AS x ! INTO selinto_schema.tmp2 ! FROM pg_class WHERE relname like '%b%'; -- OK ! CREATE TABLE selinto_schema.tmp3 (a,b,c) ! AS SELECT oid,relname,relacl FROM pg_class ! WHERE relname like '%c%'; -- OK ! RESET SESSION AUTHORIZATION; ! DROP SCHEMA selinto_schema CASCADE; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to table selinto_schema.tmp1 ! drop cascades to table selinto_schema.tmp2 ! drop cascades to table selinto_schema.tmp3 ! DROP USER selinto_user; ! -- ! -- CREATE TABLE AS/SELECT INTO as last command in a SQL function ! -- have been known to cause problems ! -- ! CREATE FUNCTION make_table() RETURNS VOID ! AS $$ ! CREATE TABLE created_table AS SELECT * FROM int8_tbl; ! $$ LANGUAGE SQL; ! SELECT make_table(); ! make_table ! ------------ ! ! (1 row) ! ! SELECT * FROM created_table; ! q1 | q2 ! ------------------+------------------- ! 123 | 456 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! (5 rows) ! ! DROP TABLE created_table; ! -- ! -- Disallowed uses of SELECT ... INTO. All should fail ! -- ! DECLARE foo CURSOR FOR SELECT 1 INTO b; ! ERROR: SELECT ... INTO is not allowed here ! LINE 1: DECLARE foo CURSOR FOR SELECT 1 INTO b; ! ^ ! COPY (SELECT 1 INTO frak UNION SELECT 2) TO 'blob'; ! ERROR: COPY (SELECT INTO) is not supported ! SELECT * FROM (SELECT 1 INTO f) bar; ! ERROR: SELECT ... INTO is not allowed here ! LINE 1: SELECT * FROM (SELECT 1 INTO f) bar; ! ^ ! CREATE VIEW foo AS SELECT 1 INTO b; ! ERROR: views must not contain SELECT INTO ! INSERT INTO b SELECT 1 INTO f; ! ERROR: SELECT ... INTO is not allowed here ! LINE 1: INSERT INTO b SELECT 1 INTO f; ! ^ --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select_distinct.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select_distinct.out Tue Oct 28 15:53:05 2014 *************** *** 1,222 **** ! -- ! -- SELECT_DISTINCT ! -- ! -- ! -- awk '{print $3;}' onek.data | sort -n | uniq ! -- ! SELECT DISTINCT two FROM tmp ORDER BY 1; ! two ! ----- ! 0 ! 1 ! (2 rows) ! ! -- ! -- awk '{print $5;}' onek.data | sort -n | uniq ! -- ! SELECT DISTINCT ten FROM tmp ORDER BY 1; ! ten ! ----- ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! 9 ! (10 rows) ! ! -- ! -- awk '{print $16;}' onek.data | sort -d | uniq ! -- ! SELECT DISTINCT string4 FROM tmp ORDER BY 1; ! string4 ! --------- ! AAAAxx ! HHHHxx ! OOOOxx ! VVVVxx ! (4 rows) ! ! -- ! -- awk '{print $3,$16,$5;}' onek.data | sort -d | uniq | ! -- sort +0n -1 +1d -2 +2n -3 ! -- ! SELECT DISTINCT two, string4, ten ! FROM tmp ! ORDER BY two using <, string4 using <, ten using <; ! two | string4 | ten ! -----+---------+----- ! 0 | AAAAxx | 0 ! 0 | AAAAxx | 2 ! 0 | AAAAxx | 4 ! 0 | AAAAxx | 6 ! 0 | AAAAxx | 8 ! 0 | HHHHxx | 0 ! 0 | HHHHxx | 2 ! 0 | HHHHxx | 4 ! 0 | HHHHxx | 6 ! 0 | HHHHxx | 8 ! 0 | OOOOxx | 0 ! 0 | OOOOxx | 2 ! 0 | OOOOxx | 4 ! 0 | OOOOxx | 6 ! 0 | OOOOxx | 8 ! 0 | VVVVxx | 0 ! 0 | VVVVxx | 2 ! 0 | VVVVxx | 4 ! 0 | VVVVxx | 6 ! 0 | VVVVxx | 8 ! 1 | AAAAxx | 1 ! 1 | AAAAxx | 3 ! 1 | AAAAxx | 5 ! 1 | AAAAxx | 7 ! 1 | AAAAxx | 9 ! 1 | HHHHxx | 1 ! 1 | HHHHxx | 3 ! 1 | HHHHxx | 5 ! 1 | HHHHxx | 7 ! 1 | HHHHxx | 9 ! 1 | OOOOxx | 1 ! 1 | OOOOxx | 3 ! 1 | OOOOxx | 5 ! 1 | OOOOxx | 7 ! 1 | OOOOxx | 9 ! 1 | VVVVxx | 1 ! 1 | VVVVxx | 3 ! 1 | VVVVxx | 5 ! 1 | VVVVxx | 7 ! 1 | VVVVxx | 9 ! (40 rows) ! ! -- ! -- awk '{print $2;}' person.data | ! -- awk '{if(NF!=1){print $2;}else{print;}}' - emp.data | ! -- awk '{if(NF!=1){print $2;}else{print;}}' - student.data | ! -- awk 'BEGIN{FS=" ";}{if(NF!=1){print $5;}else{print;}}' - stud_emp.data | ! -- sort -n -r | uniq ! -- ! SELECT DISTINCT p.age FROM person* p ORDER BY age using >; ! age ! ----- ! 98 ! 88 ! 78 ! 68 ! 60 ! 58 ! 50 ! 48 ! 40 ! 38 ! 34 ! 30 ! 28 ! 25 ! 24 ! 23 ! 20 ! 19 ! 18 ! 8 ! (20 rows) ! ! -- ! -- Also, some tests of IS DISTINCT FROM, which doesn't quite deserve its ! -- very own regression file. ! -- ! CREATE TEMP TABLE disttable (f1 integer); ! INSERT INTO DISTTABLE VALUES(1); ! INSERT INTO DISTTABLE VALUES(2); ! INSERT INTO DISTTABLE VALUES(3); ! INSERT INTO DISTTABLE VALUES(NULL); ! -- basic cases ! SELECT f1, f1 IS DISTINCT FROM 2 as "not 2" FROM disttable; ! f1 | not 2 ! ----+------- ! 1 | t ! 2 | f ! 3 | t ! | t ! (4 rows) ! ! SELECT f1, f1 IS DISTINCT FROM NULL as "not null" FROM disttable; ! f1 | not null ! ----+---------- ! 1 | t ! 2 | t ! 3 | t ! | f ! (4 rows) ! ! SELECT f1, f1 IS DISTINCT FROM f1 as "false" FROM disttable; ! f1 | false ! ----+------- ! 1 | f ! 2 | f ! 3 | f ! | f ! (4 rows) ! ! SELECT f1, f1 IS DISTINCT FROM f1+1 as "not null" FROM disttable; ! f1 | not null ! ----+---------- ! 1 | t ! 2 | t ! 3 | t ! | f ! (4 rows) ! ! -- check that optimizer constant-folds it properly ! SELECT 1 IS DISTINCT FROM 2 as "yes"; ! yes ! ----- ! t ! (1 row) ! ! SELECT 2 IS DISTINCT FROM 2 as "no"; ! no ! ---- ! f ! (1 row) ! ! SELECT 2 IS DISTINCT FROM null as "yes"; ! yes ! ----- ! t ! (1 row) ! ! SELECT null IS DISTINCT FROM null as "no"; ! no ! ---- ! f ! (1 row) ! ! -- negated form ! SELECT 1 IS NOT DISTINCT FROM 2 as "no"; ! no ! ---- ! f ! (1 row) ! ! SELECT 2 IS NOT DISTINCT FROM 2 as "yes"; ! yes ! ----- ! t ! (1 row) ! ! SELECT 2 IS NOT DISTINCT FROM null as "no"; ! no ! ---- ! f ! (1 row) ! ! SELECT null IS NOT DISTINCT FROM null as "yes"; ! yes ! ----- ! t ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select_distinct_on.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select_distinct_on.out Tue Oct 28 15:53:05 2014 *************** *** 1,75 **** ! -- ! -- SELECT_DISTINCT_ON ! -- ! SELECT DISTINCT ON (string4) string4, two, ten ! FROM tmp ! ORDER BY string4 using <, two using >, ten using <; ! string4 | two | ten ! ---------+-----+----- ! AAAAxx | 1 | 1 ! HHHHxx | 1 | 1 ! OOOOxx | 1 | 1 ! VVVVxx | 1 | 1 ! (4 rows) ! ! -- this will fail due to conflict of ordering requirements ! SELECT DISTINCT ON (string4, ten) string4, two, ten ! FROM tmp ! ORDER BY string4 using <, two using <, ten using <; ! ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions ! LINE 1: SELECT DISTINCT ON (string4, ten) string4, two, ten ! ^ ! SELECT DISTINCT ON (string4, ten) string4, ten, two ! FROM tmp ! ORDER BY string4 using <, ten using >, two using <; ! string4 | ten | two ! ---------+-----+----- ! AAAAxx | 9 | 1 ! AAAAxx | 8 | 0 ! AAAAxx | 7 | 1 ! AAAAxx | 6 | 0 ! AAAAxx | 5 | 1 ! AAAAxx | 4 | 0 ! AAAAxx | 3 | 1 ! AAAAxx | 2 | 0 ! AAAAxx | 1 | 1 ! AAAAxx | 0 | 0 ! HHHHxx | 9 | 1 ! HHHHxx | 8 | 0 ! HHHHxx | 7 | 1 ! HHHHxx | 6 | 0 ! HHHHxx | 5 | 1 ! HHHHxx | 4 | 0 ! HHHHxx | 3 | 1 ! HHHHxx | 2 | 0 ! HHHHxx | 1 | 1 ! HHHHxx | 0 | 0 ! OOOOxx | 9 | 1 ! OOOOxx | 8 | 0 ! OOOOxx | 7 | 1 ! OOOOxx | 6 | 0 ! OOOOxx | 5 | 1 ! OOOOxx | 4 | 0 ! OOOOxx | 3 | 1 ! OOOOxx | 2 | 0 ! OOOOxx | 1 | 1 ! OOOOxx | 0 | 0 ! VVVVxx | 9 | 1 ! VVVVxx | 8 | 0 ! VVVVxx | 7 | 1 ! VVVVxx | 6 | 0 ! VVVVxx | 5 | 1 ! VVVVxx | 4 | 0 ! VVVVxx | 3 | 1 ! VVVVxx | 2 | 0 ! VVVVxx | 1 | 1 ! VVVVxx | 0 | 0 ! (40 rows) ! ! -- bug #5049: early 8.4.x chokes on volatile DISTINCT ON clauses ! select distinct on (1) floor(random()) as r, f1 from int4_tbl order by 1,2; ! r | f1 ! ---+------------- ! 0 | -2147483647 ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select_implicit.out Sun Dec 12 20:21:38 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select_implicit.out Tue Oct 28 15:53:05 2014 *************** *** 1,336 **** ! -- ! -- SELECT_IMPLICIT ! -- Test cases for queries with ordering terms missing from the target list. ! -- This used to be called "junkfilter.sql". ! -- The parser uses the term "resjunk" to handle these cases. ! -- - thomas 1998-07-09 ! -- ! -- load test data ! CREATE TABLE test_missing_target (a int, b int, c char(8), d char); ! INSERT INTO test_missing_target VALUES (0, 1, 'XXXX', 'A'); ! INSERT INTO test_missing_target VALUES (1, 2, 'ABAB', 'b'); ! INSERT INTO test_missing_target VALUES (2, 2, 'ABAB', 'c'); ! INSERT INTO test_missing_target VALUES (3, 3, 'BBBB', 'D'); ! INSERT INTO test_missing_target VALUES (4, 3, 'BBBB', 'e'); ! INSERT INTO test_missing_target VALUES (5, 3, 'bbbb', 'F'); ! INSERT INTO test_missing_target VALUES (6, 4, 'cccc', 'g'); ! INSERT INTO test_missing_target VALUES (7, 4, 'cccc', 'h'); ! INSERT INTO test_missing_target VALUES (8, 4, 'CCCC', 'I'); ! INSERT INTO test_missing_target VALUES (9, 4, 'CCCC', 'j'); ! -- w/ existing GROUP BY target ! SELECT c, count(*) FROM test_missing_target GROUP BY test_missing_target.c ORDER BY c; ! c | count ! ----------+------- ! ABAB | 2 ! BBBB | 2 ! CCCC | 2 ! XXXX | 1 ! bbbb | 1 ! cccc | 2 ! (6 rows) ! ! -- w/o existing GROUP BY target using a relation name in GROUP BY clause ! SELECT count(*) FROM test_missing_target GROUP BY test_missing_target.c ORDER BY c; ! count ! ------- ! 2 ! 2 ! 2 ! 1 ! 1 ! 2 ! (6 rows) ! ! -- w/o existing GROUP BY target and w/o existing a different ORDER BY target ! -- failure expected ! SELECT count(*) FROM test_missing_target GROUP BY a ORDER BY b; ! ERROR: column "test_missing_target.b" must appear in the GROUP BY clause or be used in an aggregate function ! LINE 1: ...ECT count(*) FROM test_missing_target GROUP BY a ORDER BY b; ! ^ ! -- w/o existing GROUP BY target and w/o existing same ORDER BY target ! SELECT count(*) FROM test_missing_target GROUP BY b ORDER BY b; ! count ! ------- ! 1 ! 2 ! 3 ! 4 ! (4 rows) ! ! -- w/ existing GROUP BY target using a relation name in target ! SELECT test_missing_target.b, count(*) ! FROM test_missing_target GROUP BY b ORDER BY b; ! b | count ! ---+------- ! 1 | 1 ! 2 | 2 ! 3 | 3 ! 4 | 4 ! (4 rows) ! ! -- w/o existing GROUP BY target ! SELECT c FROM test_missing_target ORDER BY a; ! c ! ---------- ! XXXX ! ABAB ! ABAB ! BBBB ! BBBB ! bbbb ! cccc ! cccc ! CCCC ! CCCC ! (10 rows) ! ! -- w/o existing ORDER BY target ! SELECT count(*) FROM test_missing_target GROUP BY b ORDER BY b desc; ! count ! ------- ! 4 ! 3 ! 2 ! 1 ! (4 rows) ! ! -- group using reference number ! SELECT count(*) FROM test_missing_target ORDER BY 1 desc; ! count ! ------- ! 10 ! (1 row) ! ! -- order using reference number ! SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1; ! c | count ! ----------+------- ! ABAB | 2 ! BBBB | 2 ! CCCC | 2 ! XXXX | 1 ! bbbb | 1 ! cccc | 2 ! (6 rows) ! ! -- group using reference number out of range ! -- failure expected ! SELECT c, count(*) FROM test_missing_target GROUP BY 3; ! ERROR: GROUP BY position 3 is not in select list ! LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3; ! ^ ! -- group w/o existing GROUP BY and ORDER BY target under ambiguous condition ! -- failure expected ! SELECT count(*) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY b ORDER BY b; ! ERROR: column reference "b" is ambiguous ! LINE 3: GROUP BY b ORDER BY b; ! ^ ! -- order w/ target under ambiguous condition ! -- failure NOT expected ! SELECT a, a FROM test_missing_target ! ORDER BY a; ! a | a ! ---+--- ! 0 | 0 ! 1 | 1 ! 2 | 2 ! 3 | 3 ! 4 | 4 ! 5 | 5 ! 6 | 6 ! 7 | 7 ! 8 | 8 ! 9 | 9 ! (10 rows) ! ! -- order expression w/ target under ambiguous condition ! -- failure NOT expected ! SELECT a/2, a/2 FROM test_missing_target ! ORDER BY a/2; ! ?column? | ?column? ! ----------+---------- ! 0 | 0 ! 0 | 0 ! 1 | 1 ! 1 | 1 ! 2 | 2 ! 2 | 2 ! 3 | 3 ! 3 | 3 ! 4 | 4 ! 4 | 4 ! (10 rows) ! ! -- group expression w/ target under ambiguous condition ! -- failure NOT expected ! SELECT a/2, a/2 FROM test_missing_target ! GROUP BY a/2 ORDER BY a/2; ! ?column? | ?column? ! ----------+---------- ! 0 | 0 ! 1 | 1 ! 2 | 2 ! 3 | 3 ! 4 | 4 ! (5 rows) ! ! -- group w/ existing GROUP BY target under ambiguous condition ! SELECT x.b, count(*) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b ORDER BY x.b; ! b | count ! ---+------- ! 1 | 1 ! 2 | 2 ! 3 | 3 ! 4 | 4 ! (4 rows) ! ! -- group w/o existing GROUP BY target under ambiguous condition ! SELECT count(*) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b ORDER BY x.b; ! count ! ------- ! 1 ! 2 ! 3 ! 4 ! (4 rows) ! ! -- group w/o existing GROUP BY target under ambiguous condition ! -- into a table ! SELECT count(*) INTO TABLE test_missing_target2 ! FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b ORDER BY x.b; ! SELECT * FROM test_missing_target2; ! count ! ------- ! 1 ! 2 ! 3 ! 4 ! (4 rows) ! ! -- Functions and expressions ! -- w/ existing GROUP BY target ! SELECT a%2, count(b) FROM test_missing_target ! GROUP BY test_missing_target.a%2 ! ORDER BY test_missing_target.a%2; ! ?column? | count ! ----------+------- ! 0 | 5 ! 1 | 5 ! (2 rows) ! ! -- w/o existing GROUP BY target using a relation name in GROUP BY clause ! SELECT count(c) FROM test_missing_target ! GROUP BY lower(test_missing_target.c) ! ORDER BY lower(test_missing_target.c); ! count ! ------- ! 2 ! 3 ! 4 ! 1 ! (4 rows) ! ! -- w/o existing GROUP BY target and w/o existing a different ORDER BY target ! -- failure expected ! SELECT count(a) FROM test_missing_target GROUP BY a ORDER BY b; ! ERROR: column "test_missing_target.b" must appear in the GROUP BY clause or be used in an aggregate function ! LINE 1: ...ECT count(a) FROM test_missing_target GROUP BY a ORDER BY b; ! ^ ! -- w/o existing GROUP BY target and w/o existing same ORDER BY target ! SELECT count(b) FROM test_missing_target GROUP BY b/2 ORDER BY b/2; ! count ! ------- ! 1 ! 5 ! 4 ! (3 rows) ! ! -- w/ existing GROUP BY target using a relation name in target ! SELECT lower(test_missing_target.c), count(c) ! FROM test_missing_target GROUP BY lower(c) ORDER BY lower(c); ! lower | count ! -------+------- ! abab | 2 ! bbbb | 3 ! cccc | 4 ! xxxx | 1 ! (4 rows) ! ! -- w/o existing GROUP BY target ! SELECT a FROM test_missing_target ORDER BY upper(d); ! a ! --- ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! 9 ! (10 rows) ! ! -- w/o existing ORDER BY target ! SELECT count(b) FROM test_missing_target ! GROUP BY (b + 1) / 2 ORDER BY (b + 1) / 2 desc; ! count ! ------- ! 7 ! 3 ! (2 rows) ! ! -- group w/o existing GROUP BY and ORDER BY target under ambiguous condition ! -- failure expected ! SELECT count(x.a) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY b/2 ORDER BY b/2; ! ERROR: column reference "b" is ambiguous ! LINE 3: GROUP BY b/2 ORDER BY b/2; ! ^ ! -- group w/ existing GROUP BY target under ambiguous condition ! SELECT x.b/2, count(x.b) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b/2 ORDER BY x.b/2; ! ?column? | count ! ----------+------- ! 0 | 1 ! 1 | 5 ! 2 | 4 ! (3 rows) ! ! -- group w/o existing GROUP BY target under ambiguous condition ! -- failure expected due to ambiguous b in count(b) ! SELECT count(b) FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b/2; ! ERROR: column reference "b" is ambiguous ! LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar... ! ^ ! -- group w/o existing GROUP BY target under ambiguous condition ! -- into a table ! SELECT count(x.b) INTO TABLE test_missing_target3 ! FROM test_missing_target x, test_missing_target y ! WHERE x.a = y.a ! GROUP BY x.b/2 ORDER BY x.b/2; ! SELECT * FROM test_missing_target3; ! count ! ------- ! 1 ! 5 ! 4 ! (3 rows) ! ! -- Cleanup ! DROP TABLE test_missing_target; ! DROP TABLE test_missing_target2; ! DROP TABLE test_missing_target3; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/select_having.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/select_having.out Tue Oct 28 15:53:05 2014 *************** *** 1,93 **** ! -- ! -- SELECT_HAVING ! -- ! -- load test data ! CREATE TABLE test_having (a int, b int, c char(8), d char); ! INSERT INTO test_having VALUES (0, 1, 'XXXX', 'A'); ! INSERT INTO test_having VALUES (1, 2, 'AAAA', 'b'); ! INSERT INTO test_having VALUES (2, 2, 'AAAA', 'c'); ! INSERT INTO test_having VALUES (3, 3, 'BBBB', 'D'); ! INSERT INTO test_having VALUES (4, 3, 'BBBB', 'e'); ! INSERT INTO test_having VALUES (5, 3, 'bbbb', 'F'); ! INSERT INTO test_having VALUES (6, 4, 'cccc', 'g'); ! INSERT INTO test_having VALUES (7, 4, 'cccc', 'h'); ! INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); ! INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); ! SELECT b, c FROM test_having ! GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; ! b | c ! ---+---------- ! 1 | XXXX ! 3 | bbbb ! (2 rows) ! ! -- HAVING is effectively equivalent to WHERE in this case ! SELECT b, c FROM test_having ! GROUP BY b, c HAVING b = 3 ORDER BY b, c; ! b | c ! ---+---------- ! 3 | BBBB ! 3 | bbbb ! (2 rows) ! ! SELECT lower(c), count(c) FROM test_having ! GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) ! ORDER BY lower(c); ! lower | count ! -------+------- ! bbbb | 3 ! cccc | 4 ! xxxx | 1 ! (3 rows) ! ! SELECT c, max(a) FROM test_having ! GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) ! ORDER BY c; ! c | max ! ----------+----- ! XXXX | 0 ! bbbb | 5 ! (2 rows) ! ! -- test degenerate cases involving HAVING without GROUP BY ! -- Per SQL spec, these should generate 0 or 1 row, even without aggregates ! SELECT min(a), max(a) FROM test_having HAVING min(a) = max(a); ! min | max ! -----+----- ! (0 rows) ! ! SELECT min(a), max(a) FROM test_having HAVING min(a) < max(a); ! min | max ! -----+----- ! 0 | 9 ! (1 row) ! ! -- errors: ungrouped column references ! SELECT a FROM test_having HAVING min(a) < max(a); ! ERROR: column "test_having.a" must appear in the GROUP BY clause or be used in an aggregate function ! LINE 1: SELECT a FROM test_having HAVING min(a) < max(a); ! ^ ! SELECT 1 AS one FROM test_having HAVING a > 1; ! ERROR: column "test_having.a" must appear in the GROUP BY clause or be used in an aggregate function ! LINE 1: SELECT 1 AS one FROM test_having HAVING a > 1; ! ^ ! -- the really degenerate case: need not scan table at all ! SELECT 1 AS one FROM test_having HAVING 1 > 2; ! one ! ----- ! (0 rows) ! ! SELECT 1 AS one FROM test_having HAVING 1 < 2; ! one ! ----- ! 1 ! (1 row) ! ! -- and just to prove that we aren't scanning the table: ! SELECT 1 AS one FROM test_having WHERE 1/a = 1 HAVING 1 < 2; ! one ! ----- ! 1 ! (1 row) ! ! DROP TABLE test_having; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/subselect.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/subselect.out Tue Oct 28 15:53:05 2014 *************** *** 1,823 **** ! -- ! -- SUBSELECT ! -- ! SELECT 1 AS one WHERE 1 IN (SELECT 1); ! one ! ----- ! 1 ! (1 row) ! ! SELECT 1 AS zero WHERE 1 NOT IN (SELECT 1); ! zero ! ------ ! (0 rows) ! ! SELECT 1 AS zero WHERE 1 IN (SELECT 2); ! zero ! ------ ! (0 rows) ! ! -- Check grammar's handling of extra parens in assorted contexts ! SELECT * FROM (SELECT 1 AS x) ss; ! x ! --- ! 1 ! (1 row) ! ! SELECT * FROM ((SELECT 1 AS x)) ss; ! x ! --- ! 1 ! (1 row) ! ! (SELECT 2) UNION SELECT 2; ! ?column? ! ---------- ! 2 ! (1 row) ! ! ((SELECT 2)) UNION SELECT 2; ! ?column? ! ---------- ! 2 ! (1 row) ! ! SELECT ((SELECT 2) UNION SELECT 2); ! ?column? ! ---------- ! 2 ! (1 row) ! ! SELECT (((SELECT 2)) UNION SELECT 2); ! ?column? ! ---------- ! 2 ! (1 row) ! ! SELECT (SELECT ARRAY[1,2,3])[1]; ! array ! ------- ! 1 ! (1 row) ! ! SELECT ((SELECT ARRAY[1,2,3]))[2]; ! array ! ------- ! 2 ! (1 row) ! ! SELECT (((SELECT ARRAY[1,2,3])))[3]; ! array ! ------- ! 3 ! (1 row) ! ! -- Set up some simple test tables ! CREATE TABLE SUBSELECT_TBL ( ! f1 integer, ! f2 integer, ! f3 float ! ); ! INSERT INTO SUBSELECT_TBL VALUES (1, 2, 3); ! INSERT INTO SUBSELECT_TBL VALUES (2, 3, 4); ! INSERT INTO SUBSELECT_TBL VALUES (3, 4, 5); ! INSERT INTO SUBSELECT_TBL VALUES (1, 1, 1); ! INSERT INTO SUBSELECT_TBL VALUES (2, 2, 2); ! INSERT INTO SUBSELECT_TBL VALUES (3, 3, 3); ! INSERT INTO SUBSELECT_TBL VALUES (6, 7, 8); ! INSERT INTO SUBSELECT_TBL VALUES (8, 9, NULL); ! SELECT '' AS eight, * FROM SUBSELECT_TBL; ! eight | f1 | f2 | f3 ! -------+----+----+---- ! | 1 | 2 | 3 ! | 2 | 3 | 4 ! | 3 | 4 | 5 ! | 1 | 1 | 1 ! | 2 | 2 | 2 ! | 3 | 3 | 3 ! | 6 | 7 | 8 ! | 8 | 9 | ! (8 rows) ! ! -- Uncorrelated subselects ! SELECT '' AS two, f1 AS "Constant Select" FROM SUBSELECT_TBL ! WHERE f1 IN (SELECT 1); ! two | Constant Select ! -----+----------------- ! | 1 ! | 1 ! (2 rows) ! ! SELECT '' AS six, f1 AS "Uncorrelated Field" FROM SUBSELECT_TBL ! WHERE f1 IN (SELECT f2 FROM SUBSELECT_TBL); ! six | Uncorrelated Field ! -----+-------------------- ! | 1 ! | 2 ! | 3 ! | 1 ! | 2 ! | 3 ! (6 rows) ! ! SELECT '' AS six, f1 AS "Uncorrelated Field" FROM SUBSELECT_TBL ! WHERE f1 IN (SELECT f2 FROM SUBSELECT_TBL WHERE ! f2 IN (SELECT f1 FROM SUBSELECT_TBL)); ! six | Uncorrelated Field ! -----+-------------------- ! | 1 ! | 2 ! | 3 ! | 1 ! | 2 ! | 3 ! (6 rows) ! ! SELECT '' AS three, f1, f2 ! FROM SUBSELECT_TBL ! WHERE (f1, f2) NOT IN (SELECT f2, CAST(f3 AS int4) FROM SUBSELECT_TBL ! WHERE f3 IS NOT NULL); ! three | f1 | f2 ! -------+----+---- ! | 1 | 2 ! | 6 | 7 ! | 8 | 9 ! (3 rows) ! ! -- Correlated subselects ! SELECT '' AS six, f1 AS "Correlated Field", f2 AS "Second Field" ! FROM SUBSELECT_TBL upper ! WHERE f1 IN (SELECT f2 FROM SUBSELECT_TBL WHERE f1 = upper.f1); ! six | Correlated Field | Second Field ! -----+------------------+-------------- ! | 1 | 2 ! | 2 | 3 ! | 3 | 4 ! | 1 | 1 ! | 2 | 2 ! | 3 | 3 ! (6 rows) ! ! SELECT '' AS six, f1 AS "Correlated Field", f3 AS "Second Field" ! FROM SUBSELECT_TBL upper ! WHERE f1 IN ! (SELECT f2 FROM SUBSELECT_TBL WHERE CAST(upper.f2 AS float) = f3); ! six | Correlated Field | Second Field ! -----+------------------+-------------- ! | 2 | 4 ! | 3 | 5 ! | 1 | 1 ! | 2 | 2 ! | 3 | 3 ! (5 rows) ! ! SELECT '' AS six, f1 AS "Correlated Field", f3 AS "Second Field" ! FROM SUBSELECT_TBL upper ! WHERE f3 IN (SELECT upper.f1 + f2 FROM SUBSELECT_TBL ! WHERE f2 = CAST(f3 AS integer)); ! six | Correlated Field | Second Field ! -----+------------------+-------------- ! | 1 | 3 ! | 2 | 4 ! | 3 | 5 ! | 6 | 8 ! (4 rows) ! ! SELECT '' AS five, f1 AS "Correlated Field" ! FROM SUBSELECT_TBL ! WHERE (f1, f2) IN (SELECT f2, CAST(f3 AS int4) FROM SUBSELECT_TBL ! WHERE f3 IS NOT NULL); ! five | Correlated Field ! ------+------------------ ! | 2 ! | 3 ! | 1 ! | 2 ! | 3 ! (5 rows) ! ! -- ! -- Use some existing tables in the regression test ! -- ! SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field" ! FROM SUBSELECT_TBL ss ! WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL ! WHERE f1 != ss.f1 AND f1 < 2147483647); ! eight | Correlated Field | Second Field ! -------+------------------+-------------- ! | 2 | 4 ! | 3 | 5 ! | 2 | 2 ! | 3 | 3 ! | 6 | 8 ! | 8 | ! (6 rows) ! ! select q1, float8(count(*)) / (select count(*) from int8_tbl) ! from int8_tbl group by q1 order by q1; ! q1 | ?column? ! ------------------+---------- ! 123 | 0.4 ! 4567890123456789 | 0.6 ! (2 rows) ! ! -- ! -- Test cases to catch unpleasant interactions between IN-join processing ! -- and subquery pullup. ! -- ! select count(*) from ! (select 1 from tenk1 a ! where unique1 IN (select hundred from tenk1 b)) ss; ! count ! ------- ! 100 ! (1 row) ! ! select count(distinct ss.ten) from ! (select ten from tenk1 a ! where unique1 IN (select hundred from tenk1 b)) ss; ! count ! ------- ! 10 ! (1 row) ! ! select count(*) from ! (select 1 from tenk1 a ! where unique1 IN (select distinct hundred from tenk1 b)) ss; ! count ! ------- ! 100 ! (1 row) ! ! select count(distinct ss.ten) from ! (select ten from tenk1 a ! where unique1 IN (select distinct hundred from tenk1 b)) ss; ! count ! ------- ! 10 ! (1 row) ! ! -- ! -- Test cases to check for overenthusiastic optimization of ! -- "IN (SELECT DISTINCT ...)" and related cases. Per example from ! -- Luca Pireddu and Michael Fuhr. ! -- ! CREATE TEMP TABLE foo (id integer); ! CREATE TEMP TABLE bar (id1 integer, id2 integer); ! INSERT INTO foo VALUES (1); ! INSERT INTO bar VALUES (1, 1); ! INSERT INTO bar VALUES (2, 2); ! INSERT INTO bar VALUES (3, 1); ! -- These cases require an extra level of distinct-ing above subquery s ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT DISTINCT id1, id2 FROM bar) AS s); ! id ! ---- ! 1 ! (1 row) ! ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT id1,id2 FROM bar GROUP BY id1,id2) AS s); ! id ! ---- ! 1 ! (1 row) ! ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT id1, id2 FROM bar UNION ! SELECT id1, id2 FROM bar) AS s); ! id ! ---- ! 1 ! (1 row) ! ! -- These cases do not ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT DISTINCT ON (id2) id1, id2 FROM bar) AS s); ! id ! ---- ! 1 ! (1 row) ! ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT id2 FROM bar GROUP BY id2) AS s); ! id ! ---- ! 1 ! (1 row) ! ! SELECT * FROM foo WHERE id IN ! (SELECT id2 FROM (SELECT id2 FROM bar UNION ! SELECT id2 FROM bar) AS s); ! id ! ---- ! 1 ! (1 row) ! ! -- ! -- Test case to catch problems with multiply nested sub-SELECTs not getting ! -- recalculated properly. Per bug report from Didier Moens. ! -- ! CREATE TABLE orderstest ( ! approver_ref integer, ! po_ref integer, ! ordercanceled boolean ! ); ! INSERT INTO orderstest VALUES (1, 1, false); ! INSERT INTO orderstest VALUES (66, 5, false); ! INSERT INTO orderstest VALUES (66, 6, false); ! INSERT INTO orderstest VALUES (66, 7, false); ! INSERT INTO orderstest VALUES (66, 1, true); ! INSERT INTO orderstest VALUES (66, 8, false); ! INSERT INTO orderstest VALUES (66, 1, false); ! INSERT INTO orderstest VALUES (77, 1, false); ! INSERT INTO orderstest VALUES (1, 1, false); ! INSERT INTO orderstest VALUES (66, 1, false); ! INSERT INTO orderstest VALUES (1, 1, false); ! CREATE VIEW orders_view AS ! SELECT *, ! (SELECT CASE ! WHEN ord.approver_ref=1 THEN '---' ELSE 'Approved' ! END) AS "Approved", ! (SELECT CASE ! WHEN ord.ordercanceled ! THEN 'Canceled' ! ELSE ! (SELECT CASE ! WHEN ord.po_ref=1 ! THEN ! (SELECT CASE ! WHEN ord.approver_ref=1 ! THEN '---' ! ELSE 'Approved' ! END) ! ELSE 'PO' ! END) ! END) AS "Status", ! (CASE ! WHEN ord.ordercanceled ! THEN 'Canceled' ! ELSE ! (CASE ! WHEN ord.po_ref=1 ! THEN ! (CASE ! WHEN ord.approver_ref=1 ! THEN '---' ! ELSE 'Approved' ! END) ! ELSE 'PO' ! END) ! END) AS "Status_OK" ! FROM orderstest ord; ! SELECT * FROM orders_view; ! approver_ref | po_ref | ordercanceled | Approved | Status | Status_OK ! --------------+--------+---------------+----------+----------+----------- ! 1 | 1 | f | --- | --- | --- ! 66 | 5 | f | Approved | PO | PO ! 66 | 6 | f | Approved | PO | PO ! 66 | 7 | f | Approved | PO | PO ! 66 | 1 | t | Approved | Canceled | Canceled ! 66 | 8 | f | Approved | PO | PO ! 66 | 1 | f | Approved | Approved | Approved ! 77 | 1 | f | Approved | Approved | Approved ! 1 | 1 | f | --- | --- | --- ! 66 | 1 | f | Approved | Approved | Approved ! 1 | 1 | f | --- | --- | --- ! (11 rows) ! ! DROP TABLE orderstest cascade; ! NOTICE: drop cascades to view orders_view ! -- ! -- Test cases to catch situations where rule rewriter fails to propagate ! -- hasSubLinks flag correctly. Per example from Kyle Bateman. ! -- ! create temp table parts ( ! partnum text, ! cost float8 ! ); ! create temp table shipped ( ! ttype char(2), ! ordnum int4, ! partnum text, ! value float8 ! ); ! create temp view shipped_view as ! select * from shipped where ttype = 'wt'; ! create rule shipped_view_insert as on insert to shipped_view do instead ! insert into shipped values('wt', new.ordnum, new.partnum, new.value); ! insert into parts (partnum, cost) values (1, 1234.56); ! insert into shipped_view (ordnum, partnum, value) ! values (0, 1, (select cost from parts where partnum = '1')); ! select * from shipped_view; ! ttype | ordnum | partnum | value ! -------+--------+---------+--------- ! wt | 0 | 1 | 1234.56 ! (1 row) ! ! create rule shipped_view_update as on update to shipped_view do instead ! update shipped set partnum = new.partnum, value = new.value ! where ttype = new.ttype and ordnum = new.ordnum; ! update shipped_view set value = 11 ! from int4_tbl a join int4_tbl b ! on (a.f1 = (select f1 from int4_tbl c where c.f1=b.f1)) ! where ordnum = a.f1; ! select * from shipped_view; ! ttype | ordnum | partnum | value ! -------+--------+---------+------- ! wt | 0 | 1 | 11 ! (1 row) ! ! select f1, ss1 as relabel from ! (select *, (select sum(f1) from int4_tbl b where f1 >= a.f1) as ss1 ! from int4_tbl a) ss; ! f1 | relabel ! -------------+------------ ! 0 | 2147607103 ! 123456 | 2147607103 ! -123456 | 2147483647 ! 2147483647 | 2147483647 ! -2147483647 | 0 ! (5 rows) ! ! -- ! -- Test cases involving PARAM_EXEC parameters and min/max index optimizations. ! -- Per bug report from David Sanchez i Gregori. ! -- ! select * from ( ! select max(unique1) from tenk1 as a ! where exists (select 1 from tenk1 as b where b.thousand = a.unique2) ! ) ss; ! max ! ------ ! 9997 ! (1 row) ! ! select * from ( ! select min(unique1) from tenk1 as a ! where not exists (select 1 from tenk1 as b where b.unique2 = 10000) ! ) ss; ! min ! ----- ! 0 ! (1 row) ! ! -- ! -- Test that an IN implemented using a UniquePath does unique-ification ! -- with the right semantics, as per bug #4113. (Unfortunately we have ! -- no simple way to ensure that this test case actually chooses that type ! -- of plan, but it does in releases 7.4-8.3. Note that an ordering difference ! -- here might mean that some other plan type is being used, rendering the test ! -- pointless.) ! -- ! create temp table numeric_table (num_col numeric); ! insert into numeric_table values (1), (1.000000000000000000001), (2), (3); ! create temp table float_table (float_col float8); ! insert into float_table values (1), (2), (3); ! select * from float_table ! where float_col in (select num_col from numeric_table); ! float_col ! ----------- ! 1 ! 2 ! 3 ! (3 rows) ! ! select * from numeric_table ! where num_col in (select float_col from float_table); ! num_col ! ------------------------- ! 1 ! 1.000000000000000000001 ! 2 ! 3 ! (4 rows) ! ! -- ! -- Test case for bug #4290: bogus calculation of subplan param sets ! -- ! create temp table ta (id int primary key, val int); ! insert into ta values(1,1); ! insert into ta values(2,2); ! create temp table tb (id int primary key, aval int); ! insert into tb values(1,1); ! insert into tb values(2,1); ! insert into tb values(3,2); ! insert into tb values(4,2); ! create temp table tc (id int primary key, aid int); ! insert into tc values(1,1); ! insert into tc values(2,2); ! select ! ( select min(tb.id) from tb ! where tb.aval = (select ta.val from ta where ta.id = tc.aid) ) as min_tb_id ! from tc; ! min_tb_id ! ----------- ! 1 ! 3 ! (2 rows) ! ! -- ! -- Test case for 8.3 "failed to locate grouping columns" bug ! -- ! create temp table t1 (f1 numeric(14,0), f2 varchar(30)); ! select * from ! (select distinct f1, f2, (select f2 from t1 x where x.f1 = up.f1) as fs ! from t1 up) ss ! group by f1,f2,fs; ! f1 | f2 | fs ! ----+----+---- ! (0 rows) ! ! -- ! -- Test case for bug #5514 (mishandling of whole-row Vars in subselects) ! -- ! create temp table table_a(id integer); ! insert into table_a values (42); ! create temp view view_a as select * from table_a; ! select view_a from view_a; ! view_a ! -------- ! (42) ! (1 row) ! ! select (select view_a) from view_a; ! view_a ! -------- ! (42) ! (1 row) ! ! select (select (select view_a)) from view_a; ! view_a ! -------- ! (42) ! (1 row) ! ! select (select (a.*)::text) from view_a a; ! a ! ------ ! (42) ! (1 row) ! ! -- ! -- Check that whole-row Vars reading the result of a subselect don't include ! -- any junk columns therein ! -- ! select q from (select max(f1) from int4_tbl group by f1 order by f1) q; ! q ! --------------- ! (-2147483647) ! (-123456) ! (0) ! (123456) ! (2147483647) ! (5 rows) ! ! with q as (select max(f1) from int4_tbl group by f1 order by f1) ! select q from q; ! q ! --------------- ! (-2147483647) ! (-123456) ! (0) ! (123456) ! (2147483647) ! (5 rows) ! ! -- ! -- Test case for sublinks pushed down into subselects via join alias expansion ! -- ! select ! (select sq1) as qq1 ! from ! (select exists(select 1 from int4_tbl where f1 = q2) as sq1, 42 as dummy ! from int8_tbl) sq0 ! join ! int4_tbl i4 on dummy = i4.f1; ! qq1 ! ----- ! (0 rows) ! ! -- ! -- Test case for cross-type partial matching in hashed subplan (bug #7597) ! -- ! create temp table outer_7597 (f1 int4, f2 int4); ! insert into outer_7597 values (0, 0); ! insert into outer_7597 values (1, 0); ! insert into outer_7597 values (0, null); ! insert into outer_7597 values (1, null); ! create temp table inner_7597(c1 int8, c2 int8); ! insert into inner_7597 values(0, null); ! select * from outer_7597 where (f1, f2) not in (select * from inner_7597); ! f1 | f2 ! ----+---- ! 1 | 0 ! 1 | ! (2 rows) ! ! -- ! -- Test case for premature memory release during hashing of subplan output ! -- ! select '1'::text in (select '1'::name union all select '1'::name); ! ?column? ! ---------- ! t ! (1 row) ! ! -- ! -- Test case for planner bug with nested EXISTS handling ! -- ! select a.thousand from tenk1 a, tenk1 b ! where a.thousand = b.thousand ! and exists ( select 1 from tenk1 c where b.hundred = c.hundred ! and not exists ( select 1 from tenk1 d ! where a.thousand = d.thousand ) ); ! thousand ! ---------- ! (0 rows) ! ! -- ! -- Check that nested sub-selects are not pulled up if they contain volatiles ! -- ! explain (verbose, costs off) ! select x, x from ! (select (select now()) as x from (values(1),(2)) v(y)) ss; ! QUERY PLAN ! --------------------------- ! Values Scan on "*VALUES*" ! Output: $0, $1 ! InitPlan 1 (returns $0) ! -> Result ! Output: now() ! InitPlan 2 (returns $1) ! -> Result ! Output: now() ! (8 rows) ! ! explain (verbose, costs off) ! select x, x from ! (select (select random()) as x from (values(1),(2)) v(y)) ss; ! QUERY PLAN ! ---------------------------------- ! Subquery Scan on ss ! Output: ss.x, ss.x ! -> Values Scan on "*VALUES*" ! Output: $0 ! InitPlan 1 (returns $0) ! -> Result ! Output: random() ! (7 rows) ! ! explain (verbose, costs off) ! select x, x from ! (select (select now() where y=y) as x from (values(1),(2)) v(y)) ss; ! QUERY PLAN ! ---------------------------------------------------------------------- ! Values Scan on "*VALUES*" ! Output: (SubPlan 1), (SubPlan 2) ! SubPlan 1 ! -> Result ! Output: now() ! One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1) ! SubPlan 2 ! -> Result ! Output: now() ! One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1) ! (10 rows) ! ! explain (verbose, costs off) ! select x, x from ! (select (select random() where y=y) as x from (values(1),(2)) v(y)) ss; ! QUERY PLAN ! ---------------------------------------------------------------------------- ! Subquery Scan on ss ! Output: ss.x, ss.x ! -> Values Scan on "*VALUES*" ! Output: (SubPlan 1) ! SubPlan 1 ! -> Result ! Output: random() ! One-Time Filter: ("*VALUES*".column1 = "*VALUES*".column1) ! (8 rows) ! ! -- ! -- Check we behave sanely in corner case of empty SELECT list (bug #8648) ! -- ! create temp table nocolumns(); ! select exists(select * from nocolumns); ! exists ! -------- ! f ! (1 row) ! ! -- ! -- Check sane behavior with nested IN SubLinks ! -- ! explain (verbose, costs off) ! select * from int4_tbl where ! (case when f1 in (select unique1 from tenk1 a) then f1 else null end) in ! (select ten from tenk1 b); ! QUERY PLAN ! --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ! Nested Loop Semi Join ! Output: int4_tbl.f1 ! Join Filter: (CASE WHEN (hashed SubPlan 1) THEN int4_tbl.f1 ELSE NULL::integer END = b.ten) ! -> Seq Scan on public.int4_tbl ! Output: int4_tbl.f1 ! -> Seq Scan on public.tenk1 b ! Output: b.unique1, b.unique2, b.two, b.four, b.ten, b.twenty, b.hundred, b.thousand, b.twothousand, b.fivethous, b.tenthous, b.odd, b.even, b.stringu1, b.stringu2, b.string4 ! SubPlan 1 ! -> Index Only Scan using tenk1_unique1 on public.tenk1 a ! Output: a.unique1 ! (10 rows) ! ! select * from int4_tbl where ! (case when f1 in (select unique1 from tenk1 a) then f1 else null end) in ! (select ten from tenk1 b); ! f1 ! ---- ! 0 ! (1 row) ! ! -- ! -- Check for incorrect optimization when IN subquery contains a SRF ! -- ! explain (verbose, costs off) ! select * from int4_tbl o where (f1, f1) in ! (select f1, generate_series(1,2) / 10 g from int4_tbl i group by f1); ! QUERY PLAN ! ---------------------------------------------------------------------- ! Hash Join ! Output: o.f1 ! Hash Cond: (o.f1 = "ANY_subquery".f1) ! -> Seq Scan on public.int4_tbl o ! Output: o.f1 ! -> Hash ! Output: "ANY_subquery".f1, "ANY_subquery".g ! -> HashAggregate ! Output: "ANY_subquery".f1, "ANY_subquery".g ! Group Key: "ANY_subquery".f1, "ANY_subquery".g ! -> Subquery Scan on "ANY_subquery" ! Output: "ANY_subquery".f1, "ANY_subquery".g ! Filter: ("ANY_subquery".f1 = "ANY_subquery".g) ! -> HashAggregate ! Output: i.f1, (generate_series(1, 2) / 10) ! Group Key: i.f1 ! -> Seq Scan on public.int4_tbl i ! Output: i.f1 ! (18 rows) ! ! select * from int4_tbl o where (f1, f1) in ! (select f1, generate_series(1,2) / 10 g from int4_tbl i group by f1); ! f1 ! ---- ! 0 ! (1 row) ! ! -- ! -- check for over-optimization of whole-row Var referencing an Append plan ! -- ! select (select q from ! (select 1,2,3 where f1 > 0 ! union all ! select 4,5,6.0 where f1 <= 0 ! ) q ) ! from int4_tbl; ! q ! ----------- ! (4,5,6.0) ! (1,2,3) ! (4,5,6.0) ! (1,2,3) ! (4,5,6.0) ! (5 rows) ! ! -- ! -- Check that volatile quals aren't pushed down past a DISTINCT: ! -- nextval() should not be called more than the nominal number of times ! -- ! create temp sequence ts1; ! select * from ! (select distinct ten from tenk1) ss ! where ten < 10 + nextval('ts1') ! order by 1; ! ten ! ----- ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! 9 ! (10 rows) ! ! select nextval('ts1'); ! nextval ! --------- ! 11 ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/union.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/union.out Tue Oct 28 15:53:05 2014 *************** *** 1,712 **** ! -- ! -- UNION (also INTERSECT, EXCEPT) ! -- ! -- Simple UNION constructs ! SELECT 1 AS two UNION SELECT 2; ! two ! ----- ! 1 ! 2 ! (2 rows) ! ! SELECT 1 AS one UNION SELECT 1; ! one ! ----- ! 1 ! (1 row) ! ! SELECT 1 AS two UNION ALL SELECT 2; ! two ! ----- ! 1 ! 2 ! (2 rows) ! ! SELECT 1 AS two UNION ALL SELECT 1; ! two ! ----- ! 1 ! 1 ! (2 rows) ! ! SELECT 1 AS three UNION SELECT 2 UNION SELECT 3; ! three ! ------- ! 1 ! 2 ! 3 ! (3 rows) ! ! SELECT 1 AS two UNION SELECT 2 UNION SELECT 2; ! two ! ----- ! 1 ! 2 ! (2 rows) ! ! SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2; ! three ! ------- ! 1 ! 2 ! 2 ! (3 rows) ! ! SELECT 1.1 AS two UNION SELECT 2.2; ! two ! ----- ! 1.1 ! 2.2 ! (2 rows) ! ! -- Mixed types ! SELECT 1.1 AS two UNION SELECT 2; ! two ! ----- ! 1.1 ! 2 ! (2 rows) ! ! SELECT 1 AS two UNION SELECT 2.2; ! two ! ----- ! 1 ! 2.2 ! (2 rows) ! ! SELECT 1 AS one UNION SELECT 1.0::float8; ! one ! ----- ! 1 ! (1 row) ! ! SELECT 1.1 AS two UNION ALL SELECT 2; ! two ! ----- ! 1.1 ! 2 ! (2 rows) ! ! SELECT 1.0::float8 AS two UNION ALL SELECT 1; ! two ! ----- ! 1 ! 1 ! (2 rows) ! ! SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3; ! three ! ------- ! 1.1 ! 2 ! 3 ! (3 rows) ! ! SELECT 1.1::float8 AS two UNION SELECT 2 UNION SELECT 2.0::float8 ORDER BY 1; ! two ! ----- ! 1.1 ! 2 ! (2 rows) ! ! SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2; ! three ! ------- ! 1.1 ! 2 ! 2 ! (3 rows) ! ! SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2); ! two ! ----- ! 1.1 ! 2 ! (2 rows) ! ! -- ! -- Try testing from tables... ! -- ! SELECT f1 AS five FROM FLOAT8_TBL ! UNION ! SELECT f1 FROM FLOAT8_TBL ! ORDER BY 1; ! five ! ----------------------- ! -1.2345678901234e+200 ! -1004.3 ! -34.84 ! -1.2345678901234e-200 ! 0 ! (5 rows) ! ! SELECT f1 AS ten FROM FLOAT8_TBL ! UNION ALL ! SELECT f1 FROM FLOAT8_TBL; ! ten ! ----------------------- ! 0 ! -34.84 ! -1004.3 ! -1.2345678901234e+200 ! -1.2345678901234e-200 ! 0 ! -34.84 ! -1004.3 ! -1.2345678901234e+200 ! -1.2345678901234e-200 ! (10 rows) ! ! SELECT f1 AS nine FROM FLOAT8_TBL ! UNION ! SELECT f1 FROM INT4_TBL ! ORDER BY 1; ! nine ! ----------------------- ! -1.2345678901234e+200 ! -2147483647 ! -123456 ! -1004.3 ! -34.84 ! -1.2345678901234e-200 ! 0 ! 123456 ! 2147483647 ! (9 rows) ! ! SELECT f1 AS ten FROM FLOAT8_TBL ! UNION ALL ! SELECT f1 FROM INT4_TBL; ! ten ! ----------------------- ! 0 ! -34.84 ! -1004.3 ! -1.2345678901234e+200 ! -1.2345678901234e-200 ! 0 ! 123456 ! -123456 ! 2147483647 ! -2147483647 ! (10 rows) ! ! SELECT f1 AS five FROM FLOAT8_TBL ! WHERE f1 BETWEEN -1e6 AND 1e6 ! UNION ! SELECT f1 FROM INT4_TBL ! WHERE f1 BETWEEN 0 AND 1000000; ! five ! ----------------------- ! -1004.3 ! -34.84 ! -1.2345678901234e-200 ! 0 ! 123456 ! (5 rows) ! ! SELECT CAST(f1 AS char(4)) AS three FROM VARCHAR_TBL ! UNION ! SELECT f1 FROM CHAR_TBL ! ORDER BY 1; ! three ! ------- ! a ! ab ! abcd ! (3 rows) ! ! SELECT f1 AS three FROM VARCHAR_TBL ! UNION ! SELECT CAST(f1 AS varchar) FROM CHAR_TBL ! ORDER BY 1; ! three ! ------- ! a ! ab ! abcd ! (3 rows) ! ! SELECT f1 AS eight FROM VARCHAR_TBL ! UNION ALL ! SELECT f1 FROM CHAR_TBL; ! eight ! ------- ! a ! ab ! abcd ! abcd ! a ! ab ! abcd ! abcd ! (8 rows) ! ! SELECT f1 AS five FROM TEXT_TBL ! UNION ! SELECT f1 FROM VARCHAR_TBL ! UNION ! SELECT TRIM(TRAILING FROM f1) FROM CHAR_TBL ! ORDER BY 1; ! five ! ------------------- ! a ! ab ! abcd ! doh! ! hi de ho neighbor ! (5 rows) ! ! -- ! -- INTERSECT and EXCEPT ! -- ! SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl; ! q2 ! ------------------ ! 4567890123456789 ! 123 ! (2 rows) ! ! SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl; ! q2 ! ------------------ ! 4567890123456789 ! 4567890123456789 ! 123 ! (3 rows) ! ! SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; ! q2 ! ------------------- ! -4567890123456789 ! 456 ! (2 rows) ! ! SELECT q2 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl ORDER BY 1; ! q2 ! ------------------- ! -4567890123456789 ! 456 ! (2 rows) ! ! SELECT q2 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q1 FROM int8_tbl ORDER BY 1; ! q2 ! ------------------- ! -4567890123456789 ! 456 ! 4567890123456789 ! (3 rows) ! ! SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl; ! q1 ! ---- ! (0 rows) ! ! SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl; ! q1 ! ------------------ ! 4567890123456789 ! 123 ! (2 rows) ! ! SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl; ! q1 ! ------------------ ! 4567890123456789 ! 4567890123456789 ! 123 ! (3 rows) ! ! SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE; ! ERROR: FOR NO KEY UPDATE is not allowed with UNION/INTERSECT/EXCEPT ! -- ! -- Mixed types ! -- ! SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl; ! f1 ! ---- ! 0 ! (1 row) ! ! SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDER BY 1; ! f1 ! ----------------------- ! -1.2345678901234e+200 ! -1004.3 ! -34.84 ! -1.2345678901234e-200 ! (4 rows) ! ! -- ! -- Operator precedence and (((((extra))))) parentheses ! -- ! SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl; ! q1 ! ------------------- ! 4567890123456789 ! 123 ! 456 ! 4567890123456789 ! 123 ! 4567890123456789 ! -4567890123456789 ! (7 rows) ! ! SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))); ! q1 ! ------------------ ! 4567890123456789 ! 123 ! (2 rows) ! ! (((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl))) UNION ALL SELECT q2 FROM int8_tbl; ! q1 ! ------------------- ! 4567890123456789 ! 123 ! 456 ! 4567890123456789 ! 123 ! 4567890123456789 ! -4567890123456789 ! (7 rows) ! ! SELECT q1 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; ! q1 ! ------------------- ! -4567890123456789 ! 456 ! (2 rows) ! ! SELECT q1 FROM int8_tbl UNION ALL (((SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1))); ! q1 ! ------------------- ! 123 ! 123 ! 4567890123456789 ! 4567890123456789 ! 4567890123456789 ! -4567890123456789 ! 456 ! (7 rows) ! ! (((SELECT q1 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))) EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1; ! q1 ! ------------------- ! -4567890123456789 ! 456 ! (2 rows) ! ! -- ! -- Subqueries with ORDER BY & LIMIT clauses ! -- ! -- In this syntax, ORDER BY/LIMIT apply to the result of the EXCEPT ! SELECT q1,q2 FROM int8_tbl EXCEPT SELECT q2,q1 FROM int8_tbl ! ORDER BY q2,q1; ! q1 | q2 ! ------------------+------------------- ! 4567890123456789 | -4567890123456789 ! 123 | 456 ! (2 rows) ! ! -- This should fail, because q2 isn't a name of an EXCEPT output column ! SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1; ! ERROR: column "q2" does not exist ! LINE 1: ... int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1... ! ^ ! HINT: There is a column named "q2" in table "*SELECT* 2", but it cannot be referenced from this part of the query. ! -- But this should work: ! SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))); ! q1 ! ------------------ ! 4567890123456789 ! 123 ! (2 rows) ! ! -- ! -- New syntaxes (7.1) permit new tests ! -- ! (((((select * from int8_tbl))))); ! q1 | q2 ! ------------------+------------------- ! 123 | 456 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! (5 rows) ! ! -- ! -- Check handling of a case with unknown constants. We don't guarantee ! -- an undecorated constant will work in all cases, but historically this ! -- usage has worked, so test we don't break it. ! -- ! SELECT a.f1 FROM (SELECT 'test' AS f1 FROM varchar_tbl) a ! UNION ! SELECT b.f1 FROM (SELECT f1 FROM varchar_tbl) b ! ORDER BY 1; ! f1 ! ------ ! a ! ab ! abcd ! test ! (4 rows) ! ! -- This should fail, but it should produce an error cursor ! SELECT '3.4'::numeric UNION SELECT 'foo'; ! ERROR: invalid input syntax for type numeric: "foo" ! LINE 1: SELECT '3.4'::numeric UNION SELECT 'foo'; ! ^ ! -- ! -- Test that expression-index constraints can be pushed down through ! -- UNION or UNION ALL ! -- ! CREATE TEMP TABLE t1 (a text, b text); ! CREATE INDEX t1_ab_idx on t1 ((a || b)); ! CREATE TEMP TABLE t2 (ab text primary key); ! INSERT INTO t1 VALUES ('a', 'b'), ('x', 'y'); ! INSERT INTO t2 VALUES ('ab'), ('xy'); ! set enable_seqscan = off; ! set enable_indexscan = on; ! set enable_bitmapscan = off; ! explain (costs off) ! SELECT * FROM ! (SELECT a || b AS ab FROM t1 ! UNION ALL ! SELECT * FROM t2) t ! WHERE ab = 'ab'; ! QUERY PLAN ! --------------------------------------------- ! Append ! -> Index Scan using t1_ab_idx on t1 ! Index Cond: ((a || b) = 'ab'::text) ! -> Index Only Scan using t2_pkey on t2 ! Index Cond: (ab = 'ab'::text) ! (5 rows) ! ! explain (costs off) ! SELECT * FROM ! (SELECT a || b AS ab FROM t1 ! UNION ! SELECT * FROM t2) t ! WHERE ab = 'ab'; ! QUERY PLAN ! --------------------------------------------------- ! HashAggregate ! Group Key: ((t1.a || t1.b)) ! -> Append ! -> Index Scan using t1_ab_idx on t1 ! Index Cond: ((a || b) = 'ab'::text) ! -> Index Only Scan using t2_pkey on t2 ! Index Cond: (ab = 'ab'::text) ! (7 rows) ! ! -- ! -- Test that ORDER BY for UNION ALL can be pushed down to inheritance ! -- children. ! -- ! CREATE TEMP TABLE t1c (b text, a text); ! ALTER TABLE t1c INHERIT t1; ! CREATE TEMP TABLE t2c (primary key (ab)) INHERITS (t2); ! INSERT INTO t1c VALUES ('v', 'w'), ('c', 'd'), ('m', 'n'), ('e', 'f'); ! INSERT INTO t2c VALUES ('vw'), ('cd'), ('mn'), ('ef'); ! CREATE INDEX t1c_ab_idx on t1c ((a || b)); ! set enable_seqscan = on; ! set enable_indexonlyscan = off; ! explain (costs off) ! SELECT * FROM ! (SELECT a || b AS ab FROM t1 ! UNION ALL ! SELECT ab FROM t2) t ! ORDER BY 1 LIMIT 8; ! QUERY PLAN ! ------------------------------------------------ ! Limit ! -> Merge Append ! Sort Key: ((t1.a || t1.b)) ! -> Index Scan using t1_ab_idx on t1 ! -> Index Scan using t1c_ab_idx on t1c ! -> Index Scan using t2_pkey on t2 ! -> Index Scan using t2c_pkey on t2c ! (7 rows) ! ! SELECT * FROM ! (SELECT a || b AS ab FROM t1 ! UNION ALL ! SELECT ab FROM t2) t ! ORDER BY 1 LIMIT 8; ! ab ! ---- ! ab ! ab ! cd ! dc ! ef ! fe ! mn ! nm ! (8 rows) ! ! reset enable_seqscan; ! reset enable_indexscan; ! reset enable_bitmapscan; ! -- This simpler variant of the above test has been observed to fail differently ! create table events (event_id int primary key); ! create table other_events (event_id int primary key); ! create table events_child () inherits (events); ! explain (costs off) ! select event_id ! from (select event_id from events ! union all ! select event_id from other_events) ss ! order by event_id; ! QUERY PLAN ! ---------------------------------------------------------- ! Merge Append ! Sort Key: events.event_id ! -> Index Scan using events_pkey on events ! -> Sort ! Sort Key: events_child.event_id ! -> Seq Scan on events_child ! -> Index Scan using other_events_pkey on other_events ! (7 rows) ! ! drop table events_child, events, other_events; ! reset enable_indexonlyscan; ! -- Test constraint exclusion of UNION ALL subqueries ! explain (costs off) ! SELECT * FROM ! (SELECT 1 AS t, * FROM tenk1 a ! UNION ALL ! SELECT 2 AS t, * FROM tenk1 b) c ! WHERE t = 2; ! QUERY PLAN ! --------------------------- ! Append ! -> Seq Scan on tenk1 b ! (2 rows) ! ! -- Test that we push quals into UNION sub-selects only when it's safe ! explain (costs off) ! SELECT * FROM ! (SELECT 1 AS t, 2 AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x < 4; ! QUERY PLAN ! -------------------------------------------- ! Unique ! -> Sort ! Sort Key: (1), (2) ! -> Append ! -> Result ! -> Result ! One-Time Filter: false ! (7 rows) ! ! SELECT * FROM ! (SELECT 1 AS t, 2 AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x < 4; ! t | x ! ---+--- ! 1 | 2 ! (1 row) ! ! explain (costs off) ! SELECT * FROM ! (SELECT 1 AS t, generate_series(1,10) AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x < 4 ! ORDER BY x; ! QUERY PLAN ! -------------------------------------------------------- ! Sort ! Sort Key: ss.x ! -> Subquery Scan on ss ! Filter: (ss.x < 4) ! -> HashAggregate ! Group Key: (1), (generate_series(1, 10)) ! -> Append ! -> Result ! -> Result ! (9 rows) ! ! SELECT * FROM ! (SELECT 1 AS t, generate_series(1,10) AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x < 4 ! ORDER BY x; ! t | x ! ---+--- ! 1 | 1 ! 1 | 2 ! 1 | 3 ! (3 rows) ! ! explain (costs off) ! SELECT * FROM ! (SELECT 1 AS t, (random()*3)::int AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x > 3; ! QUERY PLAN ! ---------------------------------------------------------------------------- ! Subquery Scan on ss ! Filter: (ss.x > 3) ! -> Unique ! -> Sort ! Sort Key: (1), (((random() * 3::double precision))::integer) ! -> Append ! -> Result ! -> Result ! (8 rows) ! ! SELECT * FROM ! (SELECT 1 AS t, (random()*3)::int AS x ! UNION ! SELECT 2 AS t, 4 AS x) ss ! WHERE x > 3; ! t | x ! ---+--- ! 2 | 4 ! (1 row) ! ! -- Test proper handling of parameterized appendrel paths when the ! -- potential join qual is expensive ! create function expensivefunc(int) returns int ! language plpgsql immutable strict cost 10000 ! as $$begin return $1; end$$; ! create temp table t3 as select generate_series(-1000,1000) as x; ! create index t3i on t3 (expensivefunc(x)); ! analyze t3; ! explain (costs off) ! select * from ! (select * from t3 a union all select * from t3 b) ss ! join int4_tbl on f1 = expensivefunc(x); ! QUERY PLAN ! ------------------------------------------------------------ ! Nested Loop ! -> Seq Scan on int4_tbl ! -> Append ! -> Index Scan using t3i on t3 a ! Index Cond: (expensivefunc(x) = int4_tbl.f1) ! -> Index Scan using t3i on t3 b ! Index Cond: (expensivefunc(x) = int4_tbl.f1) ! (7 rows) ! ! select * from ! (select * from t3 a union all select * from t3 b) ss ! join int4_tbl on f1 = expensivefunc(x); ! x | f1 ! ---+---- ! 0 | 0 ! 0 | 0 ! (2 rows) ! ! drop table t3; ! drop function expensivefunc(int); --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/case.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/case.out Tue Oct 28 15:53:05 2014 *************** *** 1,303 **** ! -- ! -- CASE ! -- Test the case statement ! -- ! CREATE TABLE CASE_TBL ( ! i integer, ! f double precision ! ); ! CREATE TABLE CASE2_TBL ( ! i integer, ! j integer ! ); ! INSERT INTO CASE_TBL VALUES (1, 10.1); ! INSERT INTO CASE_TBL VALUES (2, 20.2); ! INSERT INTO CASE_TBL VALUES (3, -30.3); ! INSERT INTO CASE_TBL VALUES (4, NULL); ! INSERT INTO CASE2_TBL VALUES (1, -1); ! INSERT INTO CASE2_TBL VALUES (2, -2); ! INSERT INTO CASE2_TBL VALUES (3, -3); ! INSERT INTO CASE2_TBL VALUES (2, -4); ! INSERT INTO CASE2_TBL VALUES (1, NULL); ! INSERT INTO CASE2_TBL VALUES (NULL, -6); ! -- ! -- Simplest examples without tables ! -- ! SELECT '3' AS "One", ! CASE ! WHEN 1 < 2 THEN 3 ! END AS "Simple WHEN"; ! One | Simple WHEN ! -----+------------- ! 3 | 3 ! (1 row) ! ! SELECT '' AS "One", ! CASE ! WHEN 1 > 2 THEN 3 ! END AS "Simple default"; ! One | Simple default ! --------+---------------- ! | ! (1 row) ! ! SELECT '3' AS "One", ! CASE ! WHEN 1 < 2 THEN 3 ! ELSE 4 ! END AS "Simple ELSE"; ! One | Simple ELSE ! -----+------------- ! 3 | 3 ! (1 row) ! ! SELECT '4' AS "One", ! CASE ! WHEN 1 > 2 THEN 3 ! ELSE 4 ! END AS "ELSE default"; ! One | ELSE default ! -----+-------------- ! 4 | 4 ! (1 row) ! ! SELECT '6' AS "One", ! CASE ! WHEN 1 > 2 THEN 3 ! WHEN 4 < 5 THEN 6 ! ELSE 7 ! END AS "Two WHEN with default"; ! One | Two WHEN with default ! -----+----------------------- ! 6 | 6 ! (1 row) ! ! -- Constant-expression folding shouldn't evaluate unreachable subexpressions ! SELECT CASE WHEN 1=0 THEN 1/0 WHEN 1=1 THEN 1 ELSE 2/0 END; ! case ! ------ ! 1 ! (1 row) ! ! SELECT CASE 1 WHEN 0 THEN 1/0 WHEN 1 THEN 1 ELSE 2/0 END; ! case ! ------ ! 1 ! (1 row) ! ! -- However we do not currently suppress folding of potentially ! -- reachable subexpressions ! SELECT CASE WHEN i > 100 THEN 1/0 ELSE 0 END FROM case_tbl; ! ERROR: division by zero ! -- Test for cases involving untyped literals in test expression ! SELECT CASE 'a' WHEN 'a' THEN 1 ELSE 2 END; ! case ! ------ ! 1 ! (1 row) ! ! -- ! -- Examples of targets involving tables ! -- ! SELECT '' AS "Five", ! CASE ! WHEN i >= 3 THEN i ! END AS ">= 3 or Null" ! FROM CASE_TBL; ! Five | >= 3 or Null ! ------+-------------- ! | ! | ! | 3 ! | 4 ! (4 rows) ! ! SELECT '' AS "Five", ! CASE WHEN i >= 3 THEN (i + i) ! ELSE i ! END AS "Simplest Math" ! FROM CASE_TBL; ! Five | Simplest Math ! ------+--------------- ! | 1 ! | 2 ! | 6 ! | 8 ! (4 rows) ! ! SELECT '' AS "Five", i AS "Value", ! CASE WHEN (i < 0) THEN 'small' ! WHEN (i = 0) THEN 'zero' ! WHEN (i = 1) THEN 'one' ! WHEN (i = 2) THEN 'two' ! ELSE 'big' ! END AS "Category" ! FROM CASE_TBL; ! Five | Value | Category ! ------+-------+---------- ! | 1 | one ! | 2 | two ! | 3 | big ! | 4 | big ! (4 rows) ! ! SELECT '' AS "Five", ! CASE WHEN ((i < 0) or (i < 0)) THEN 'small' ! WHEN ((i = 0) or (i = 0)) THEN 'zero' ! WHEN ((i = 1) or (i = 1)) THEN 'one' ! WHEN ((i = 2) or (i = 2)) THEN 'two' ! ELSE 'big' ! END AS "Category" ! FROM CASE_TBL; ! Five | Category ! ------+---------- ! | one ! | two ! | big ! | big ! (4 rows) ! ! -- ! -- Examples of qualifications involving tables ! -- ! -- ! -- NULLIF() and COALESCE() ! -- Shorthand forms for typical CASE constructs ! -- defined in the SQL standard. ! -- ! SELECT * FROM CASE_TBL WHERE COALESCE(f,i) = 4; ! i | f ! ---+--- ! 4 | ! (1 row) ! ! SELECT * FROM CASE_TBL WHERE NULLIF(f,i) = 2; ! i | f ! ---+--- ! (0 rows) ! ! SELECT COALESCE(a.f, b.i, b.j) ! FROM CASE_TBL a, CASE2_TBL b; ! coalesce ! ---------- ! 10.1 ! 20.2 ! -30.3 ! 1 ! 10.1 ! 20.2 ! -30.3 ! 2 ! 10.1 ! 20.2 ! -30.3 ! 3 ! 10.1 ! 20.2 ! -30.3 ! 2 ! 10.1 ! 20.2 ! -30.3 ! 1 ! 10.1 ! 20.2 ! -30.3 ! -6 ! (24 rows) ! ! SELECT * ! FROM CASE_TBL a, CASE2_TBL b ! WHERE COALESCE(a.f, b.i, b.j) = 2; ! i | f | i | j ! ---+---+---+---- ! 4 | | 2 | -2 ! 4 | | 2 | -4 ! (2 rows) ! ! SELECT '' AS Five, NULLIF(a.i,b.i) AS "NULLIF(a.i,b.i)", ! NULLIF(b.i, 4) AS "NULLIF(b.i,4)" ! FROM CASE_TBL a, CASE2_TBL b; ! five | NULLIF(a.i,b.i) | NULLIF(b.i,4) ! ------+-----------------+--------------- ! | | 1 ! | 2 | 1 ! | 3 | 1 ! | 4 | 1 ! | 1 | 2 ! | | 2 ! | 3 | 2 ! | 4 | 2 ! | 1 | 3 ! | 2 | 3 ! | | 3 ! | 4 | 3 ! | 1 | 2 ! | | 2 ! | 3 | 2 ! | 4 | 2 ! | | 1 ! | 2 | 1 ! | 3 | 1 ! | 4 | 1 ! | 1 | ! | 2 | ! | 3 | ! | 4 | ! (24 rows) ! ! SELECT '' AS "Two", * ! FROM CASE_TBL a, CASE2_TBL b ! WHERE COALESCE(f,b.i) = 2; ! Two | i | f | i | j ! -----+---+---+---+---- ! | 4 | | 2 | -2 ! | 4 | | 2 | -4 ! (2 rows) ! ! -- ! -- Examples of updates involving tables ! -- ! UPDATE CASE_TBL ! SET i = CASE WHEN i >= 3 THEN (- i) ! ELSE (2 * i) END; ! SELECT * FROM CASE_TBL; ! i | f ! ----+------- ! 2 | 10.1 ! 4 | 20.2 ! -3 | -30.3 ! -4 | ! (4 rows) ! ! UPDATE CASE_TBL ! SET i = CASE WHEN i >= 2 THEN (2 * i) ! ELSE (3 * i) END; ! SELECT * FROM CASE_TBL; ! i | f ! -----+------- ! 4 | 10.1 ! 8 | 20.2 ! -9 | -30.3 ! -12 | ! (4 rows) ! ! UPDATE CASE_TBL ! SET i = CASE WHEN b.i >= 2 THEN (2 * j) ! ELSE (3 * j) END ! FROM CASE2_TBL b ! WHERE j = -CASE_TBL.i; ! SELECT * FROM CASE_TBL; ! i | f ! -----+------- ! 8 | 20.2 ! -9 | -30.3 ! -12 | ! -8 | 10.1 ! (4 rows) ! ! -- ! -- Clean up ! -- ! DROP TABLE CASE_TBL; ! DROP TABLE CASE2_TBL; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/join.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/join.out Tue Oct 28 15:53:05 2014 *************** *** 1,4341 **** ! -- ! -- JOIN ! -- Test JOIN clauses ! -- ! CREATE TABLE J1_TBL ( ! i integer, ! j integer, ! t text ! ); ! CREATE TABLE J2_TBL ( ! i integer, ! k integer ! ); ! INSERT INTO J1_TBL VALUES (1, 4, 'one'); ! INSERT INTO J1_TBL VALUES (2, 3, 'two'); ! INSERT INTO J1_TBL VALUES (3, 2, 'three'); ! INSERT INTO J1_TBL VALUES (4, 1, 'four'); ! INSERT INTO J1_TBL VALUES (5, 0, 'five'); ! INSERT INTO J1_TBL VALUES (6, 6, 'six'); ! INSERT INTO J1_TBL VALUES (7, 7, 'seven'); ! INSERT INTO J1_TBL VALUES (8, 8, 'eight'); ! INSERT INTO J1_TBL VALUES (0, NULL, 'zero'); ! INSERT INTO J1_TBL VALUES (NULL, NULL, 'null'); ! INSERT INTO J1_TBL VALUES (NULL, 0, 'zero'); ! INSERT INTO J2_TBL VALUES (1, -1); ! INSERT INTO J2_TBL VALUES (2, 2); ! INSERT INTO J2_TBL VALUES (3, -3); ! INSERT INTO J2_TBL VALUES (2, 4); ! INSERT INTO J2_TBL VALUES (5, -5); ! INSERT INTO J2_TBL VALUES (5, -5); ! INSERT INTO J2_TBL VALUES (0, NULL); ! INSERT INTO J2_TBL VALUES (NULL, NULL); ! INSERT INTO J2_TBL VALUES (NULL, 0); ! -- ! -- CORRELATION NAMES ! -- Make sure that table/column aliases are supported ! -- before diving into more complex join syntax. ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL AS tx; ! xxx | i | j | t ! -----+---+---+------- ! | 1 | 4 | one ! | 2 | 3 | two ! | 3 | 2 | three ! | 4 | 1 | four ! | 5 | 0 | five ! | 6 | 6 | six ! | 7 | 7 | seven ! | 8 | 8 | eight ! | 0 | | zero ! | | | null ! | | 0 | zero ! (11 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL tx; ! xxx | i | j | t ! -----+---+---+------- ! | 1 | 4 | one ! | 2 | 3 | two ! | 3 | 2 | three ! | 4 | 1 | four ! | 5 | 0 | five ! | 6 | 6 | six ! | 7 | 7 | seven ! | 8 | 8 | eight ! | 0 | | zero ! | | | null ! | | 0 | zero ! (11 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL AS t1 (a, b, c); ! xxx | a | b | c ! -----+---+---+------- ! | 1 | 4 | one ! | 2 | 3 | two ! | 3 | 2 | three ! | 4 | 1 | four ! | 5 | 0 | five ! | 6 | 6 | six ! | 7 | 7 | seven ! | 8 | 8 | eight ! | 0 | | zero ! | | | null ! | | 0 | zero ! (11 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c); ! xxx | a | b | c ! -----+---+---+------- ! | 1 | 4 | one ! | 2 | 3 | two ! | 3 | 2 | three ! | 4 | 1 | four ! | 5 | 0 | five ! | 6 | 6 | six ! | 7 | 7 | seven ! | 8 | 8 | eight ! | 0 | | zero ! | | | null ! | | 0 | zero ! (11 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e); ! xxx | a | b | c | d | e ! -----+---+---+-------+---+---- ! | 1 | 4 | one | 1 | -1 ! | 2 | 3 | two | 1 | -1 ! | 3 | 2 | three | 1 | -1 ! | 4 | 1 | four | 1 | -1 ! | 5 | 0 | five | 1 | -1 ! | 6 | 6 | six | 1 | -1 ! | 7 | 7 | seven | 1 | -1 ! | 8 | 8 | eight | 1 | -1 ! | 0 | | zero | 1 | -1 ! | | | null | 1 | -1 ! | | 0 | zero | 1 | -1 ! | 1 | 4 | one | 2 | 2 ! | 2 | 3 | two | 2 | 2 ! | 3 | 2 | three | 2 | 2 ! | 4 | 1 | four | 2 | 2 ! | 5 | 0 | five | 2 | 2 ! | 6 | 6 | six | 2 | 2 ! | 7 | 7 | seven | 2 | 2 ! | 8 | 8 | eight | 2 | 2 ! | 0 | | zero | 2 | 2 ! | | | null | 2 | 2 ! | | 0 | zero | 2 | 2 ! | 1 | 4 | one | 3 | -3 ! | 2 | 3 | two | 3 | -3 ! | 3 | 2 | three | 3 | -3 ! | 4 | 1 | four | 3 | -3 ! | 5 | 0 | five | 3 | -3 ! | 6 | 6 | six | 3 | -3 ! | 7 | 7 | seven | 3 | -3 ! | 8 | 8 | eight | 3 | -3 ! | 0 | | zero | 3 | -3 ! | | | null | 3 | -3 ! | | 0 | zero | 3 | -3 ! | 1 | 4 | one | 2 | 4 ! | 2 | 3 | two | 2 | 4 ! | 3 | 2 | three | 2 | 4 ! | 4 | 1 | four | 2 | 4 ! | 5 | 0 | five | 2 | 4 ! | 6 | 6 | six | 2 | 4 ! | 7 | 7 | seven | 2 | 4 ! | 8 | 8 | eight | 2 | 4 ! | 0 | | zero | 2 | 4 ! | | | null | 2 | 4 ! | | 0 | zero | 2 | 4 ! | 1 | 4 | one | 5 | -5 ! | 2 | 3 | two | 5 | -5 ! | 3 | 2 | three | 5 | -5 ! | 4 | 1 | four | 5 | -5 ! | 5 | 0 | five | 5 | -5 ! | 6 | 6 | six | 5 | -5 ! | 7 | 7 | seven | 5 | -5 ! | 8 | 8 | eight | 5 | -5 ! | 0 | | zero | 5 | -5 ! | | | null | 5 | -5 ! | | 0 | zero | 5 | -5 ! | 1 | 4 | one | 5 | -5 ! | 2 | 3 | two | 5 | -5 ! | 3 | 2 | three | 5 | -5 ! | 4 | 1 | four | 5 | -5 ! | 5 | 0 | five | 5 | -5 ! | 6 | 6 | six | 5 | -5 ! | 7 | 7 | seven | 5 | -5 ! | 8 | 8 | eight | 5 | -5 ! | 0 | | zero | 5 | -5 ! | | | null | 5 | -5 ! | | 0 | zero | 5 | -5 ! | 1 | 4 | one | 0 | ! | 2 | 3 | two | 0 | ! | 3 | 2 | three | 0 | ! | 4 | 1 | four | 0 | ! | 5 | 0 | five | 0 | ! | 6 | 6 | six | 0 | ! | 7 | 7 | seven | 0 | ! | 8 | 8 | eight | 0 | ! | 0 | | zero | 0 | ! | | | null | 0 | ! | | 0 | zero | 0 | ! | 1 | 4 | one | | ! | 2 | 3 | two | | ! | 3 | 2 | three | | ! | 4 | 1 | four | | ! | 5 | 0 | five | | ! | 6 | 6 | six | | ! | 7 | 7 | seven | | ! | 8 | 8 | eight | | ! | 0 | | zero | | ! | | | null | | ! | | 0 | zero | | ! | 1 | 4 | one | | 0 ! | 2 | 3 | two | | 0 ! | 3 | 2 | three | | 0 ! | 4 | 1 | four | | 0 ! | 5 | 0 | five | | 0 ! | 6 | 6 | six | | 0 ! | 7 | 7 | seven | | 0 ! | 8 | 8 | eight | | 0 ! | 0 | | zero | | 0 ! | | | null | | 0 ! | | 0 | zero | | 0 ! (99 rows) ! ! SELECT '' AS "xxx", t1.a, t2.e ! FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e) ! WHERE t1.a = t2.d; ! xxx | a | e ! -----+---+---- ! | 0 | ! | 1 | -1 ! | 2 | 2 ! | 2 | 4 ! | 3 | -3 ! | 5 | -5 ! | 5 | -5 ! (7 rows) ! ! -- ! -- CROSS JOIN ! -- Qualifications are not allowed on cross joins, ! -- which degenerate into a standard unqualified inner join. ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL CROSS JOIN J2_TBL; ! xxx | i | j | t | i | k ! -----+---+---+-------+---+---- ! | 1 | 4 | one | 1 | -1 ! | 2 | 3 | two | 1 | -1 ! | 3 | 2 | three | 1 | -1 ! | 4 | 1 | four | 1 | -1 ! | 5 | 0 | five | 1 | -1 ! | 6 | 6 | six | 1 | -1 ! | 7 | 7 | seven | 1 | -1 ! | 8 | 8 | eight | 1 | -1 ! | 0 | | zero | 1 | -1 ! | | | null | 1 | -1 ! | | 0 | zero | 1 | -1 ! | 1 | 4 | one | 2 | 2 ! | 2 | 3 | two | 2 | 2 ! | 3 | 2 | three | 2 | 2 ! | 4 | 1 | four | 2 | 2 ! | 5 | 0 | five | 2 | 2 ! | 6 | 6 | six | 2 | 2 ! | 7 | 7 | seven | 2 | 2 ! | 8 | 8 | eight | 2 | 2 ! | 0 | | zero | 2 | 2 ! | | | null | 2 | 2 ! | | 0 | zero | 2 | 2 ! | 1 | 4 | one | 3 | -3 ! | 2 | 3 | two | 3 | -3 ! | 3 | 2 | three | 3 | -3 ! | 4 | 1 | four | 3 | -3 ! | 5 | 0 | five | 3 | -3 ! | 6 | 6 | six | 3 | -3 ! | 7 | 7 | seven | 3 | -3 ! | 8 | 8 | eight | 3 | -3 ! | 0 | | zero | 3 | -3 ! | | | null | 3 | -3 ! | | 0 | zero | 3 | -3 ! | 1 | 4 | one | 2 | 4 ! | 2 | 3 | two | 2 | 4 ! | 3 | 2 | three | 2 | 4 ! | 4 | 1 | four | 2 | 4 ! | 5 | 0 | five | 2 | 4 ! | 6 | 6 | six | 2 | 4 ! | 7 | 7 | seven | 2 | 4 ! | 8 | 8 | eight | 2 | 4 ! | 0 | | zero | 2 | 4 ! | | | null | 2 | 4 ! | | 0 | zero | 2 | 4 ! | 1 | 4 | one | 5 | -5 ! | 2 | 3 | two | 5 | -5 ! | 3 | 2 | three | 5 | -5 ! | 4 | 1 | four | 5 | -5 ! | 5 | 0 | five | 5 | -5 ! | 6 | 6 | six | 5 | -5 ! | 7 | 7 | seven | 5 | -5 ! | 8 | 8 | eight | 5 | -5 ! | 0 | | zero | 5 | -5 ! | | | null | 5 | -5 ! | | 0 | zero | 5 | -5 ! | 1 | 4 | one | 5 | -5 ! | 2 | 3 | two | 5 | -5 ! | 3 | 2 | three | 5 | -5 ! | 4 | 1 | four | 5 | -5 ! | 5 | 0 | five | 5 | -5 ! | 6 | 6 | six | 5 | -5 ! | 7 | 7 | seven | 5 | -5 ! | 8 | 8 | eight | 5 | -5 ! | 0 | | zero | 5 | -5 ! | | | null | 5 | -5 ! | | 0 | zero | 5 | -5 ! | 1 | 4 | one | 0 | ! | 2 | 3 | two | 0 | ! | 3 | 2 | three | 0 | ! | 4 | 1 | four | 0 | ! | 5 | 0 | five | 0 | ! | 6 | 6 | six | 0 | ! | 7 | 7 | seven | 0 | ! | 8 | 8 | eight | 0 | ! | 0 | | zero | 0 | ! | | | null | 0 | ! | | 0 | zero | 0 | ! | 1 | 4 | one | | ! | 2 | 3 | two | | ! | 3 | 2 | three | | ! | 4 | 1 | four | | ! | 5 | 0 | five | | ! | 6 | 6 | six | | ! | 7 | 7 | seven | | ! | 8 | 8 | eight | | ! | 0 | | zero | | ! | | | null | | ! | | 0 | zero | | ! | 1 | 4 | one | | 0 ! | 2 | 3 | two | | 0 ! | 3 | 2 | three | | 0 ! | 4 | 1 | four | | 0 ! | 5 | 0 | five | | 0 ! | 6 | 6 | six | | 0 ! | 7 | 7 | seven | | 0 ! | 8 | 8 | eight | | 0 ! | 0 | | zero | | 0 ! | | | null | | 0 ! | | 0 | zero | | 0 ! (99 rows) ! ! -- ambiguous column ! SELECT '' AS "xxx", i, k, t ! FROM J1_TBL CROSS JOIN J2_TBL; ! ERROR: column reference "i" is ambiguous ! LINE 1: SELECT '' AS "xxx", i, k, t ! ^ ! -- resolve previous ambiguity by specifying the table name ! SELECT '' AS "xxx", t1.i, k, t ! FROM J1_TBL t1 CROSS JOIN J2_TBL t2; ! xxx | i | k | t ! -----+---+----+------- ! | 1 | -1 | one ! | 2 | -1 | two ! | 3 | -1 | three ! | 4 | -1 | four ! | 5 | -1 | five ! | 6 | -1 | six ! | 7 | -1 | seven ! | 8 | -1 | eight ! | 0 | -1 | zero ! | | -1 | null ! | | -1 | zero ! | 1 | 2 | one ! | 2 | 2 | two ! | 3 | 2 | three ! | 4 | 2 | four ! | 5 | 2 | five ! | 6 | 2 | six ! | 7 | 2 | seven ! | 8 | 2 | eight ! | 0 | 2 | zero ! | | 2 | null ! | | 2 | zero ! | 1 | -3 | one ! | 2 | -3 | two ! | 3 | -3 | three ! | 4 | -3 | four ! | 5 | -3 | five ! | 6 | -3 | six ! | 7 | -3 | seven ! | 8 | -3 | eight ! | 0 | -3 | zero ! | | -3 | null ! | | -3 | zero ! | 1 | 4 | one ! | 2 | 4 | two ! | 3 | 4 | three ! | 4 | 4 | four ! | 5 | 4 | five ! | 6 | 4 | six ! | 7 | 4 | seven ! | 8 | 4 | eight ! | 0 | 4 | zero ! | | 4 | null ! | | 4 | zero ! | 1 | -5 | one ! | 2 | -5 | two ! | 3 | -5 | three ! | 4 | -5 | four ! | 5 | -5 | five ! | 6 | -5 | six ! | 7 | -5 | seven ! | 8 | -5 | eight ! | 0 | -5 | zero ! | | -5 | null ! | | -5 | zero ! | 1 | -5 | one ! | 2 | -5 | two ! | 3 | -5 | three ! | 4 | -5 | four ! | 5 | -5 | five ! | 6 | -5 | six ! | 7 | -5 | seven ! | 8 | -5 | eight ! | 0 | -5 | zero ! | | -5 | null ! | | -5 | zero ! | 1 | | one ! | 2 | | two ! | 3 | | three ! | 4 | | four ! | 5 | | five ! | 6 | | six ! | 7 | | seven ! | 8 | | eight ! | 0 | | zero ! | | | null ! | | | zero ! | 1 | | one ! | 2 | | two ! | 3 | | three ! | 4 | | four ! | 5 | | five ! | 6 | | six ! | 7 | | seven ! | 8 | | eight ! | 0 | | zero ! | | | null ! | | | zero ! | 1 | 0 | one ! | 2 | 0 | two ! | 3 | 0 | three ! | 4 | 0 | four ! | 5 | 0 | five ! | 6 | 0 | six ! | 7 | 0 | seven ! | 8 | 0 | eight ! | 0 | 0 | zero ! | | 0 | null ! | | 0 | zero ! (99 rows) ! ! SELECT '' AS "xxx", ii, tt, kk ! FROM (J1_TBL CROSS JOIN J2_TBL) ! AS tx (ii, jj, tt, ii2, kk); ! xxx | ii | tt | kk ! -----+----+-------+---- ! | 1 | one | -1 ! | 2 | two | -1 ! | 3 | three | -1 ! | 4 | four | -1 ! | 5 | five | -1 ! | 6 | six | -1 ! | 7 | seven | -1 ! | 8 | eight | -1 ! | 0 | zero | -1 ! | | null | -1 ! | | zero | -1 ! | 1 | one | 2 ! | 2 | two | 2 ! | 3 | three | 2 ! | 4 | four | 2 ! | 5 | five | 2 ! | 6 | six | 2 ! | 7 | seven | 2 ! | 8 | eight | 2 ! | 0 | zero | 2 ! | | null | 2 ! | | zero | 2 ! | 1 | one | -3 ! | 2 | two | -3 ! | 3 | three | -3 ! | 4 | four | -3 ! | 5 | five | -3 ! | 6 | six | -3 ! | 7 | seven | -3 ! | 8 | eight | -3 ! | 0 | zero | -3 ! | | null | -3 ! | | zero | -3 ! | 1 | one | 4 ! | 2 | two | 4 ! | 3 | three | 4 ! | 4 | four | 4 ! | 5 | five | 4 ! | 6 | six | 4 ! | 7 | seven | 4 ! | 8 | eight | 4 ! | 0 | zero | 4 ! | | null | 4 ! | | zero | 4 ! | 1 | one | -5 ! | 2 | two | -5 ! | 3 | three | -5 ! | 4 | four | -5 ! | 5 | five | -5 ! | 6 | six | -5 ! | 7 | seven | -5 ! | 8 | eight | -5 ! | 0 | zero | -5 ! | | null | -5 ! | | zero | -5 ! | 1 | one | -5 ! | 2 | two | -5 ! | 3 | three | -5 ! | 4 | four | -5 ! | 5 | five | -5 ! | 6 | six | -5 ! | 7 | seven | -5 ! | 8 | eight | -5 ! | 0 | zero | -5 ! | | null | -5 ! | | zero | -5 ! | 1 | one | ! | 2 | two | ! | 3 | three | ! | 4 | four | ! | 5 | five | ! | 6 | six | ! | 7 | seven | ! | 8 | eight | ! | 0 | zero | ! | | null | ! | | zero | ! | 1 | one | ! | 2 | two | ! | 3 | three | ! | 4 | four | ! | 5 | five | ! | 6 | six | ! | 7 | seven | ! | 8 | eight | ! | 0 | zero | ! | | null | ! | | zero | ! | 1 | one | 0 ! | 2 | two | 0 ! | 3 | three | 0 ! | 4 | four | 0 ! | 5 | five | 0 ! | 6 | six | 0 ! | 7 | seven | 0 ! | 8 | eight | 0 ! | 0 | zero | 0 ! | | null | 0 ! | | zero | 0 ! (99 rows) ! ! SELECT '' AS "xxx", tx.ii, tx.jj, tx.kk ! FROM (J1_TBL t1 (a, b, c) CROSS JOIN J2_TBL t2 (d, e)) ! AS tx (ii, jj, tt, ii2, kk); ! xxx | ii | jj | kk ! -----+----+----+---- ! | 1 | 4 | -1 ! | 2 | 3 | -1 ! | 3 | 2 | -1 ! | 4 | 1 | -1 ! | 5 | 0 | -1 ! | 6 | 6 | -1 ! | 7 | 7 | -1 ! | 8 | 8 | -1 ! | 0 | | -1 ! | | | -1 ! | | 0 | -1 ! | 1 | 4 | 2 ! | 2 | 3 | 2 ! | 3 | 2 | 2 ! | 4 | 1 | 2 ! | 5 | 0 | 2 ! | 6 | 6 | 2 ! | 7 | 7 | 2 ! | 8 | 8 | 2 ! | 0 | | 2 ! | | | 2 ! | | 0 | 2 ! | 1 | 4 | -3 ! | 2 | 3 | -3 ! | 3 | 2 | -3 ! | 4 | 1 | -3 ! | 5 | 0 | -3 ! | 6 | 6 | -3 ! | 7 | 7 | -3 ! | 8 | 8 | -3 ! | 0 | | -3 ! | | | -3 ! | | 0 | -3 ! | 1 | 4 | 4 ! | 2 | 3 | 4 ! | 3 | 2 | 4 ! | 4 | 1 | 4 ! | 5 | 0 | 4 ! | 6 | 6 | 4 ! | 7 | 7 | 4 ! | 8 | 8 | 4 ! | 0 | | 4 ! | | | 4 ! | | 0 | 4 ! | 1 | 4 | -5 ! | 2 | 3 | -5 ! | 3 | 2 | -5 ! | 4 | 1 | -5 ! | 5 | 0 | -5 ! | 6 | 6 | -5 ! | 7 | 7 | -5 ! | 8 | 8 | -5 ! | 0 | | -5 ! | | | -5 ! | | 0 | -5 ! | 1 | 4 | -5 ! | 2 | 3 | -5 ! | 3 | 2 | -5 ! | 4 | 1 | -5 ! | 5 | 0 | -5 ! | 6 | 6 | -5 ! | 7 | 7 | -5 ! | 8 | 8 | -5 ! | 0 | | -5 ! | | | -5 ! | | 0 | -5 ! | 1 | 4 | ! | 2 | 3 | ! | 3 | 2 | ! | 4 | 1 | ! | 5 | 0 | ! | 6 | 6 | ! | 7 | 7 | ! | 8 | 8 | ! | 0 | | ! | | | ! | | 0 | ! | 1 | 4 | ! | 2 | 3 | ! | 3 | 2 | ! | 4 | 1 | ! | 5 | 0 | ! | 6 | 6 | ! | 7 | 7 | ! | 8 | 8 | ! | 0 | | ! | | | ! | | 0 | ! | 1 | 4 | 0 ! | 2 | 3 | 0 ! | 3 | 2 | 0 ! | 4 | 1 | 0 ! | 5 | 0 | 0 ! | 6 | 6 | 0 ! | 7 | 7 | 0 ! | 8 | 8 | 0 ! | 0 | | 0 ! | | | 0 ! | | 0 | 0 ! (99 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL CROSS JOIN J2_TBL a CROSS JOIN J2_TBL b; ! xxx | i | j | t | i | k | i | k ! -----+---+---+-------+---+----+---+---- ! | 1 | 4 | one | 1 | -1 | 1 | -1 ! | 1 | 4 | one | 1 | -1 | 2 | 2 ! | 1 | 4 | one | 1 | -1 | 3 | -3 ! | 1 | 4 | one | 1 | -1 | 2 | 4 ! | 1 | 4 | one | 1 | -1 | 5 | -5 ! | 1 | 4 | one | 1 | -1 | 5 | -5 ! | 1 | 4 | one | 1 | -1 | 0 | ! | 1 | 4 | one | 1 | -1 | | ! | 1 | 4 | one | 1 | -1 | | 0 ! | 2 | 3 | two | 1 | -1 | 1 | -1 ! | 2 | 3 | two | 1 | -1 | 2 | 2 ! | 2 | 3 | two | 1 | -1 | 3 | -3 ! | 2 | 3 | two | 1 | -1 | 2 | 4 ! | 2 | 3 | two | 1 | -1 | 5 | -5 ! | 2 | 3 | two | 1 | -1 | 5 | -5 ! | 2 | 3 | two | 1 | -1 | 0 | ! | 2 | 3 | two | 1 | -1 | | ! | 2 | 3 | two | 1 | -1 | | 0 ! | 3 | 2 | three | 1 | -1 | 1 | -1 ! | 3 | 2 | three | 1 | -1 | 2 | 2 ! | 3 | 2 | three | 1 | -1 | 3 | -3 ! | 3 | 2 | three | 1 | -1 | 2 | 4 ! | 3 | 2 | three | 1 | -1 | 5 | -5 ! | 3 | 2 | three | 1 | -1 | 5 | -5 ! | 3 | 2 | three | 1 | -1 | 0 | ! | 3 | 2 | three | 1 | -1 | | ! | 3 | 2 | three | 1 | -1 | | 0 ! | 4 | 1 | four | 1 | -1 | 1 | -1 ! | 4 | 1 | four | 1 | -1 | 2 | 2 ! | 4 | 1 | four | 1 | -1 | 3 | -3 ! | 4 | 1 | four | 1 | -1 | 2 | 4 ! | 4 | 1 | four | 1 | -1 | 5 | -5 ! | 4 | 1 | four | 1 | -1 | 5 | -5 ! | 4 | 1 | four | 1 | -1 | 0 | ! | 4 | 1 | four | 1 | -1 | | ! | 4 | 1 | four | 1 | -1 | | 0 ! | 5 | 0 | five | 1 | -1 | 1 | -1 ! | 5 | 0 | five | 1 | -1 | 2 | 2 ! | 5 | 0 | five | 1 | -1 | 3 | -3 ! | 5 | 0 | five | 1 | -1 | 2 | 4 ! | 5 | 0 | five | 1 | -1 | 5 | -5 ! | 5 | 0 | five | 1 | -1 | 5 | -5 ! | 5 | 0 | five | 1 | -1 | 0 | ! | 5 | 0 | five | 1 | -1 | | ! | 5 | 0 | five | 1 | -1 | | 0 ! | 6 | 6 | six | 1 | -1 | 1 | -1 ! | 6 | 6 | six | 1 | -1 | 2 | 2 ! | 6 | 6 | six | 1 | -1 | 3 | -3 ! | 6 | 6 | six | 1 | -1 | 2 | 4 ! | 6 | 6 | six | 1 | -1 | 5 | -5 ! | 6 | 6 | six | 1 | -1 | 5 | -5 ! | 6 | 6 | six | 1 | -1 | 0 | ! | 6 | 6 | six | 1 | -1 | | ! | 6 | 6 | six | 1 | -1 | | 0 ! | 7 | 7 | seven | 1 | -1 | 1 | -1 ! | 7 | 7 | seven | 1 | -1 | 2 | 2 ! | 7 | 7 | seven | 1 | -1 | 3 | -3 ! | 7 | 7 | seven | 1 | -1 | 2 | 4 ! | 7 | 7 | seven | 1 | -1 | 5 | -5 ! | 7 | 7 | seven | 1 | -1 | 5 | -5 ! | 7 | 7 | seven | 1 | -1 | 0 | ! | 7 | 7 | seven | 1 | -1 | | ! | 7 | 7 | seven | 1 | -1 | | 0 ! | 8 | 8 | eight | 1 | -1 | 1 | -1 ! | 8 | 8 | eight | 1 | -1 | 2 | 2 ! | 8 | 8 | eight | 1 | -1 | 3 | -3 ! | 8 | 8 | eight | 1 | -1 | 2 | 4 ! | 8 | 8 | eight | 1 | -1 | 5 | -5 ! | 8 | 8 | eight | 1 | -1 | 5 | -5 ! | 8 | 8 | eight | 1 | -1 | 0 | ! | 8 | 8 | eight | 1 | -1 | | ! | 8 | 8 | eight | 1 | -1 | | 0 ! | 0 | | zero | 1 | -1 | 1 | -1 ! | 0 | | zero | 1 | -1 | 2 | 2 ! | 0 | | zero | 1 | -1 | 3 | -3 ! | 0 | | zero | 1 | -1 | 2 | 4 ! | 0 | | zero | 1 | -1 | 5 | -5 ! | 0 | | zero | 1 | -1 | 5 | -5 ! | 0 | | zero | 1 | -1 | 0 | ! | 0 | | zero | 1 | -1 | | ! | 0 | | zero | 1 | -1 | | 0 ! | | | null | 1 | -1 | 1 | -1 ! | | | null | 1 | -1 | 2 | 2 ! | | | null | 1 | -1 | 3 | -3 ! | | | null | 1 | -1 | 2 | 4 ! | | | null | 1 | -1 | 5 | -5 ! | | | null | 1 | -1 | 5 | -5 ! | | | null | 1 | -1 | 0 | ! | | | null | 1 | -1 | | ! | | | null | 1 | -1 | | 0 ! | | 0 | zero | 1 | -1 | 1 | -1 ! | | 0 | zero | 1 | -1 | 2 | 2 ! | | 0 | zero | 1 | -1 | 3 | -3 ! | | 0 | zero | 1 | -1 | 2 | 4 ! | | 0 | zero | 1 | -1 | 5 | -5 ! | | 0 | zero | 1 | -1 | 5 | -5 ! | | 0 | zero | 1 | -1 | 0 | ! | | 0 | zero | 1 | -1 | | ! | | 0 | zero | 1 | -1 | | 0 ! | 1 | 4 | one | 2 | 2 | 1 | -1 ! | 1 | 4 | one | 2 | 2 | 2 | 2 ! | 1 | 4 | one | 2 | 2 | 3 | -3 ! | 1 | 4 | one | 2 | 2 | 2 | 4 ! | 1 | 4 | one | 2 | 2 | 5 | -5 ! | 1 | 4 | one | 2 | 2 | 5 | -5 ! | 1 | 4 | one | 2 | 2 | 0 | ! | 1 | 4 | one | 2 | 2 | | ! | 1 | 4 | one | 2 | 2 | | 0 ! | 2 | 3 | two | 2 | 2 | 1 | -1 ! | 2 | 3 | two | 2 | 2 | 2 | 2 ! | 2 | 3 | two | 2 | 2 | 3 | -3 ! | 2 | 3 | two | 2 | 2 | 2 | 4 ! | 2 | 3 | two | 2 | 2 | 5 | -5 ! | 2 | 3 | two | 2 | 2 | 5 | -5 ! | 2 | 3 | two | 2 | 2 | 0 | ! | 2 | 3 | two | 2 | 2 | | ! | 2 | 3 | two | 2 | 2 | | 0 ! | 3 | 2 | three | 2 | 2 | 1 | -1 ! | 3 | 2 | three | 2 | 2 | 2 | 2 ! | 3 | 2 | three | 2 | 2 | 3 | -3 ! | 3 | 2 | three | 2 | 2 | 2 | 4 ! | 3 | 2 | three | 2 | 2 | 5 | -5 ! | 3 | 2 | three | 2 | 2 | 5 | -5 ! | 3 | 2 | three | 2 | 2 | 0 | ! | 3 | 2 | three | 2 | 2 | | ! | 3 | 2 | three | 2 | 2 | | 0 ! | 4 | 1 | four | 2 | 2 | 1 | -1 ! | 4 | 1 | four | 2 | 2 | 2 | 2 ! | 4 | 1 | four | 2 | 2 | 3 | -3 ! | 4 | 1 | four | 2 | 2 | 2 | 4 ! | 4 | 1 | four | 2 | 2 | 5 | -5 ! | 4 | 1 | four | 2 | 2 | 5 | -5 ! | 4 | 1 | four | 2 | 2 | 0 | ! | 4 | 1 | four | 2 | 2 | | ! | 4 | 1 | four | 2 | 2 | | 0 ! | 5 | 0 | five | 2 | 2 | 1 | -1 ! | 5 | 0 | five | 2 | 2 | 2 | 2 ! | 5 | 0 | five | 2 | 2 | 3 | -3 ! | 5 | 0 | five | 2 | 2 | 2 | 4 ! | 5 | 0 | five | 2 | 2 | 5 | -5 ! | 5 | 0 | five | 2 | 2 | 5 | -5 ! | 5 | 0 | five | 2 | 2 | 0 | ! | 5 | 0 | five | 2 | 2 | | ! | 5 | 0 | five | 2 | 2 | | 0 ! | 6 | 6 | six | 2 | 2 | 1 | -1 ! | 6 | 6 | six | 2 | 2 | 2 | 2 ! | 6 | 6 | six | 2 | 2 | 3 | -3 ! | 6 | 6 | six | 2 | 2 | 2 | 4 ! | 6 | 6 | six | 2 | 2 | 5 | -5 ! | 6 | 6 | six | 2 | 2 | 5 | -5 ! | 6 | 6 | six | 2 | 2 | 0 | ! | 6 | 6 | six | 2 | 2 | | ! | 6 | 6 | six | 2 | 2 | | 0 ! | 7 | 7 | seven | 2 | 2 | 1 | -1 ! | 7 | 7 | seven | 2 | 2 | 2 | 2 ! | 7 | 7 | seven | 2 | 2 | 3 | -3 ! | 7 | 7 | seven | 2 | 2 | 2 | 4 ! | 7 | 7 | seven | 2 | 2 | 5 | -5 ! | 7 | 7 | seven | 2 | 2 | 5 | -5 ! | 7 | 7 | seven | 2 | 2 | 0 | ! | 7 | 7 | seven | 2 | 2 | | ! | 7 | 7 | seven | 2 | 2 | | 0 ! | 8 | 8 | eight | 2 | 2 | 1 | -1 ! | 8 | 8 | eight | 2 | 2 | 2 | 2 ! | 8 | 8 | eight | 2 | 2 | 3 | -3 ! | 8 | 8 | eight | 2 | 2 | 2 | 4 ! | 8 | 8 | eight | 2 | 2 | 5 | -5 ! | 8 | 8 | eight | 2 | 2 | 5 | -5 ! | 8 | 8 | eight | 2 | 2 | 0 | ! | 8 | 8 | eight | 2 | 2 | | ! | 8 | 8 | eight | 2 | 2 | | 0 ! | 0 | | zero | 2 | 2 | 1 | -1 ! | 0 | | zero | 2 | 2 | 2 | 2 ! | 0 | | zero | 2 | 2 | 3 | -3 ! | 0 | | zero | 2 | 2 | 2 | 4 ! | 0 | | zero | 2 | 2 | 5 | -5 ! | 0 | | zero | 2 | 2 | 5 | -5 ! | 0 | | zero | 2 | 2 | 0 | ! | 0 | | zero | 2 | 2 | | ! | 0 | | zero | 2 | 2 | | 0 ! | | | null | 2 | 2 | 1 | -1 ! | | | null | 2 | 2 | 2 | 2 ! | | | null | 2 | 2 | 3 | -3 ! | | | null | 2 | 2 | 2 | 4 ! | | | null | 2 | 2 | 5 | -5 ! | | | null | 2 | 2 | 5 | -5 ! | | | null | 2 | 2 | 0 | ! | | | null | 2 | 2 | | ! | | | null | 2 | 2 | | 0 ! | | 0 | zero | 2 | 2 | 1 | -1 ! | | 0 | zero | 2 | 2 | 2 | 2 ! | | 0 | zero | 2 | 2 | 3 | -3 ! | | 0 | zero | 2 | 2 | 2 | 4 ! | | 0 | zero | 2 | 2 | 5 | -5 ! | | 0 | zero | 2 | 2 | 5 | -5 ! | | 0 | zero | 2 | 2 | 0 | ! | | 0 | zero | 2 | 2 | | ! | | 0 | zero | 2 | 2 | | 0 ! | 1 | 4 | one | 3 | -3 | 1 | -1 ! | 1 | 4 | one | 3 | -3 | 2 | 2 ! | 1 | 4 | one | 3 | -3 | 3 | -3 ! | 1 | 4 | one | 3 | -3 | 2 | 4 ! | 1 | 4 | one | 3 | -3 | 5 | -5 ! | 1 | 4 | one | 3 | -3 | 5 | -5 ! | 1 | 4 | one | 3 | -3 | 0 | ! | 1 | 4 | one | 3 | -3 | | ! | 1 | 4 | one | 3 | -3 | | 0 ! | 2 | 3 | two | 3 | -3 | 1 | -1 ! | 2 | 3 | two | 3 | -3 | 2 | 2 ! | 2 | 3 | two | 3 | -3 | 3 | -3 ! | 2 | 3 | two | 3 | -3 | 2 | 4 ! | 2 | 3 | two | 3 | -3 | 5 | -5 ! | 2 | 3 | two | 3 | -3 | 5 | -5 ! | 2 | 3 | two | 3 | -3 | 0 | ! | 2 | 3 | two | 3 | -3 | | ! | 2 | 3 | two | 3 | -3 | | 0 ! | 3 | 2 | three | 3 | -3 | 1 | -1 ! | 3 | 2 | three | 3 | -3 | 2 | 2 ! | 3 | 2 | three | 3 | -3 | 3 | -3 ! | 3 | 2 | three | 3 | -3 | 2 | 4 ! | 3 | 2 | three | 3 | -3 | 5 | -5 ! | 3 | 2 | three | 3 | -3 | 5 | -5 ! | 3 | 2 | three | 3 | -3 | 0 | ! | 3 | 2 | three | 3 | -3 | | ! | 3 | 2 | three | 3 | -3 | | 0 ! | 4 | 1 | four | 3 | -3 | 1 | -1 ! | 4 | 1 | four | 3 | -3 | 2 | 2 ! | 4 | 1 | four | 3 | -3 | 3 | -3 ! | 4 | 1 | four | 3 | -3 | 2 | 4 ! | 4 | 1 | four | 3 | -3 | 5 | -5 ! | 4 | 1 | four | 3 | -3 | 5 | -5 ! | 4 | 1 | four | 3 | -3 | 0 | ! | 4 | 1 | four | 3 | -3 | | ! | 4 | 1 | four | 3 | -3 | | 0 ! | 5 | 0 | five | 3 | -3 | 1 | -1 ! | 5 | 0 | five | 3 | -3 | 2 | 2 ! | 5 | 0 | five | 3 | -3 | 3 | -3 ! | 5 | 0 | five | 3 | -3 | 2 | 4 ! | 5 | 0 | five | 3 | -3 | 5 | -5 ! | 5 | 0 | five | 3 | -3 | 5 | -5 ! | 5 | 0 | five | 3 | -3 | 0 | ! | 5 | 0 | five | 3 | -3 | | ! | 5 | 0 | five | 3 | -3 | | 0 ! | 6 | 6 | six | 3 | -3 | 1 | -1 ! | 6 | 6 | six | 3 | -3 | 2 | 2 ! | 6 | 6 | six | 3 | -3 | 3 | -3 ! | 6 | 6 | six | 3 | -3 | 2 | 4 ! | 6 | 6 | six | 3 | -3 | 5 | -5 ! | 6 | 6 | six | 3 | -3 | 5 | -5 ! | 6 | 6 | six | 3 | -3 | 0 | ! | 6 | 6 | six | 3 | -3 | | ! | 6 | 6 | six | 3 | -3 | | 0 ! | 7 | 7 | seven | 3 | -3 | 1 | -1 ! | 7 | 7 | seven | 3 | -3 | 2 | 2 ! | 7 | 7 | seven | 3 | -3 | 3 | -3 ! | 7 | 7 | seven | 3 | -3 | 2 | 4 ! | 7 | 7 | seven | 3 | -3 | 5 | -5 ! | 7 | 7 | seven | 3 | -3 | 5 | -5 ! | 7 | 7 | seven | 3 | -3 | 0 | ! | 7 | 7 | seven | 3 | -3 | | ! | 7 | 7 | seven | 3 | -3 | | 0 ! | 8 | 8 | eight | 3 | -3 | 1 | -1 ! | 8 | 8 | eight | 3 | -3 | 2 | 2 ! | 8 | 8 | eight | 3 | -3 | 3 | -3 ! | 8 | 8 | eight | 3 | -3 | 2 | 4 ! | 8 | 8 | eight | 3 | -3 | 5 | -5 ! | 8 | 8 | eight | 3 | -3 | 5 | -5 ! | 8 | 8 | eight | 3 | -3 | 0 | ! | 8 | 8 | eight | 3 | -3 | | ! | 8 | 8 | eight | 3 | -3 | | 0 ! | 0 | | zero | 3 | -3 | 1 | -1 ! | 0 | | zero | 3 | -3 | 2 | 2 ! | 0 | | zero | 3 | -3 | 3 | -3 ! | 0 | | zero | 3 | -3 | 2 | 4 ! | 0 | | zero | 3 | -3 | 5 | -5 ! | 0 | | zero | 3 | -3 | 5 | -5 ! | 0 | | zero | 3 | -3 | 0 | ! | 0 | | zero | 3 | -3 | | ! | 0 | | zero | 3 | -3 | | 0 ! | | | null | 3 | -3 | 1 | -1 ! | | | null | 3 | -3 | 2 | 2 ! | | | null | 3 | -3 | 3 | -3 ! | | | null | 3 | -3 | 2 | 4 ! | | | null | 3 | -3 | 5 | -5 ! | | | null | 3 | -3 | 5 | -5 ! | | | null | 3 | -3 | 0 | ! | | | null | 3 | -3 | | ! | | | null | 3 | -3 | | 0 ! | | 0 | zero | 3 | -3 | 1 | -1 ! | | 0 | zero | 3 | -3 | 2 | 2 ! | | 0 | zero | 3 | -3 | 3 | -3 ! | | 0 | zero | 3 | -3 | 2 | 4 ! | | 0 | zero | 3 | -3 | 5 | -5 ! | | 0 | zero | 3 | -3 | 5 | -5 ! | | 0 | zero | 3 | -3 | 0 | ! | | 0 | zero | 3 | -3 | | ! | | 0 | zero | 3 | -3 | | 0 ! | 1 | 4 | one | 2 | 4 | 1 | -1 ! | 1 | 4 | one | 2 | 4 | 2 | 2 ! | 1 | 4 | one | 2 | 4 | 3 | -3 ! | 1 | 4 | one | 2 | 4 | 2 | 4 ! | 1 | 4 | one | 2 | 4 | 5 | -5 ! | 1 | 4 | one | 2 | 4 | 5 | -5 ! | 1 | 4 | one | 2 | 4 | 0 | ! | 1 | 4 | one | 2 | 4 | | ! | 1 | 4 | one | 2 | 4 | | 0 ! | 2 | 3 | two | 2 | 4 | 1 | -1 ! | 2 | 3 | two | 2 | 4 | 2 | 2 ! | 2 | 3 | two | 2 | 4 | 3 | -3 ! | 2 | 3 | two | 2 | 4 | 2 | 4 ! | 2 | 3 | two | 2 | 4 | 5 | -5 ! | 2 | 3 | two | 2 | 4 | 5 | -5 ! | 2 | 3 | two | 2 | 4 | 0 | ! | 2 | 3 | two | 2 | 4 | | ! | 2 | 3 | two | 2 | 4 | | 0 ! | 3 | 2 | three | 2 | 4 | 1 | -1 ! | 3 | 2 | three | 2 | 4 | 2 | 2 ! | 3 | 2 | three | 2 | 4 | 3 | -3 ! | 3 | 2 | three | 2 | 4 | 2 | 4 ! | 3 | 2 | three | 2 | 4 | 5 | -5 ! | 3 | 2 | three | 2 | 4 | 5 | -5 ! | 3 | 2 | three | 2 | 4 | 0 | ! | 3 | 2 | three | 2 | 4 | | ! | 3 | 2 | three | 2 | 4 | | 0 ! | 4 | 1 | four | 2 | 4 | 1 | -1 ! | 4 | 1 | four | 2 | 4 | 2 | 2 ! | 4 | 1 | four | 2 | 4 | 3 | -3 ! | 4 | 1 | four | 2 | 4 | 2 | 4 ! | 4 | 1 | four | 2 | 4 | 5 | -5 ! | 4 | 1 | four | 2 | 4 | 5 | -5 ! | 4 | 1 | four | 2 | 4 | 0 | ! | 4 | 1 | four | 2 | 4 | | ! | 4 | 1 | four | 2 | 4 | | 0 ! | 5 | 0 | five | 2 | 4 | 1 | -1 ! | 5 | 0 | five | 2 | 4 | 2 | 2 ! | 5 | 0 | five | 2 | 4 | 3 | -3 ! | 5 | 0 | five | 2 | 4 | 2 | 4 ! | 5 | 0 | five | 2 | 4 | 5 | -5 ! | 5 | 0 | five | 2 | 4 | 5 | -5 ! | 5 | 0 | five | 2 | 4 | 0 | ! | 5 | 0 | five | 2 | 4 | | ! | 5 | 0 | five | 2 | 4 | | 0 ! | 6 | 6 | six | 2 | 4 | 1 | -1 ! | 6 | 6 | six | 2 | 4 | 2 | 2 ! | 6 | 6 | six | 2 | 4 | 3 | -3 ! | 6 | 6 | six | 2 | 4 | 2 | 4 ! | 6 | 6 | six | 2 | 4 | 5 | -5 ! | 6 | 6 | six | 2 | 4 | 5 | -5 ! | 6 | 6 | six | 2 | 4 | 0 | ! | 6 | 6 | six | 2 | 4 | | ! | 6 | 6 | six | 2 | 4 | | 0 ! | 7 | 7 | seven | 2 | 4 | 1 | -1 ! | 7 | 7 | seven | 2 | 4 | 2 | 2 ! | 7 | 7 | seven | 2 | 4 | 3 | -3 ! | 7 | 7 | seven | 2 | 4 | 2 | 4 ! | 7 | 7 | seven | 2 | 4 | 5 | -5 ! | 7 | 7 | seven | 2 | 4 | 5 | -5 ! | 7 | 7 | seven | 2 | 4 | 0 | ! | 7 | 7 | seven | 2 | 4 | | ! | 7 | 7 | seven | 2 | 4 | | 0 ! | 8 | 8 | eight | 2 | 4 | 1 | -1 ! | 8 | 8 | eight | 2 | 4 | 2 | 2 ! | 8 | 8 | eight | 2 | 4 | 3 | -3 ! | 8 | 8 | eight | 2 | 4 | 2 | 4 ! | 8 | 8 | eight | 2 | 4 | 5 | -5 ! | 8 | 8 | eight | 2 | 4 | 5 | -5 ! | 8 | 8 | eight | 2 | 4 | 0 | ! | 8 | 8 | eight | 2 | 4 | | ! | 8 | 8 | eight | 2 | 4 | | 0 ! | 0 | | zero | 2 | 4 | 1 | -1 ! | 0 | | zero | 2 | 4 | 2 | 2 ! | 0 | | zero | 2 | 4 | 3 | -3 ! | 0 | | zero | 2 | 4 | 2 | 4 ! | 0 | | zero | 2 | 4 | 5 | -5 ! | 0 | | zero | 2 | 4 | 5 | -5 ! | 0 | | zero | 2 | 4 | 0 | ! | 0 | | zero | 2 | 4 | | ! | 0 | | zero | 2 | 4 | | 0 ! | | | null | 2 | 4 | 1 | -1 ! | | | null | 2 | 4 | 2 | 2 ! | | | null | 2 | 4 | 3 | -3 ! | | | null | 2 | 4 | 2 | 4 ! | | | null | 2 | 4 | 5 | -5 ! | | | null | 2 | 4 | 5 | -5 ! | | | null | 2 | 4 | 0 | ! | | | null | 2 | 4 | | ! | | | null | 2 | 4 | | 0 ! | | 0 | zero | 2 | 4 | 1 | -1 ! | | 0 | zero | 2 | 4 | 2 | 2 ! | | 0 | zero | 2 | 4 | 3 | -3 ! | | 0 | zero | 2 | 4 | 2 | 4 ! | | 0 | zero | 2 | 4 | 5 | -5 ! | | 0 | zero | 2 | 4 | 5 | -5 ! | | 0 | zero | 2 | 4 | 0 | ! | | 0 | zero | 2 | 4 | | ! | | 0 | zero | 2 | 4 | | 0 ! | 1 | 4 | one | 5 | -5 | 1 | -1 ! | 1 | 4 | one | 5 | -5 | 2 | 2 ! | 1 | 4 | one | 5 | -5 | 3 | -3 ! | 1 | 4 | one | 5 | -5 | 2 | 4 ! | 1 | 4 | one | 5 | -5 | 5 | -5 ! | 1 | 4 | one | 5 | -5 | 5 | -5 ! | 1 | 4 | one | 5 | -5 | 0 | ! | 1 | 4 | one | 5 | -5 | | ! | 1 | 4 | one | 5 | -5 | | 0 ! | 2 | 3 | two | 5 | -5 | 1 | -1 ! | 2 | 3 | two | 5 | -5 | 2 | 2 ! | 2 | 3 | two | 5 | -5 | 3 | -3 ! | 2 | 3 | two | 5 | -5 | 2 | 4 ! | 2 | 3 | two | 5 | -5 | 5 | -5 ! | 2 | 3 | two | 5 | -5 | 5 | -5 ! | 2 | 3 | two | 5 | -5 | 0 | ! | 2 | 3 | two | 5 | -5 | | ! | 2 | 3 | two | 5 | -5 | | 0 ! | 3 | 2 | three | 5 | -5 | 1 | -1 ! | 3 | 2 | three | 5 | -5 | 2 | 2 ! | 3 | 2 | three | 5 | -5 | 3 | -3 ! | 3 | 2 | three | 5 | -5 | 2 | 4 ! | 3 | 2 | three | 5 | -5 | 5 | -5 ! | 3 | 2 | three | 5 | -5 | 5 | -5 ! | 3 | 2 | three | 5 | -5 | 0 | ! | 3 | 2 | three | 5 | -5 | | ! | 3 | 2 | three | 5 | -5 | | 0 ! | 4 | 1 | four | 5 | -5 | 1 | -1 ! | 4 | 1 | four | 5 | -5 | 2 | 2 ! | 4 | 1 | four | 5 | -5 | 3 | -3 ! | 4 | 1 | four | 5 | -5 | 2 | 4 ! | 4 | 1 | four | 5 | -5 | 5 | -5 ! | 4 | 1 | four | 5 | -5 | 5 | -5 ! | 4 | 1 | four | 5 | -5 | 0 | ! | 4 | 1 | four | 5 | -5 | | ! | 4 | 1 | four | 5 | -5 | | 0 ! | 5 | 0 | five | 5 | -5 | 1 | -1 ! | 5 | 0 | five | 5 | -5 | 2 | 2 ! | 5 | 0 | five | 5 | -5 | 3 | -3 ! | 5 | 0 | five | 5 | -5 | 2 | 4 ! | 5 | 0 | five | 5 | -5 | 5 | -5 ! | 5 | 0 | five | 5 | -5 | 5 | -5 ! | 5 | 0 | five | 5 | -5 | 0 | ! | 5 | 0 | five | 5 | -5 | | ! | 5 | 0 | five | 5 | -5 | | 0 ! | 6 | 6 | six | 5 | -5 | 1 | -1 ! | 6 | 6 | six | 5 | -5 | 2 | 2 ! | 6 | 6 | six | 5 | -5 | 3 | -3 ! | 6 | 6 | six | 5 | -5 | 2 | 4 ! | 6 | 6 | six | 5 | -5 | 5 | -5 ! | 6 | 6 | six | 5 | -5 | 5 | -5 ! | 6 | 6 | six | 5 | -5 | 0 | ! | 6 | 6 | six | 5 | -5 | | ! | 6 | 6 | six | 5 | -5 | | 0 ! | 7 | 7 | seven | 5 | -5 | 1 | -1 ! | 7 | 7 | seven | 5 | -5 | 2 | 2 ! | 7 | 7 | seven | 5 | -5 | 3 | -3 ! | 7 | 7 | seven | 5 | -5 | 2 | 4 ! | 7 | 7 | seven | 5 | -5 | 5 | -5 ! | 7 | 7 | seven | 5 | -5 | 5 | -5 ! | 7 | 7 | seven | 5 | -5 | 0 | ! | 7 | 7 | seven | 5 | -5 | | ! | 7 | 7 | seven | 5 | -5 | | 0 ! | 8 | 8 | eight | 5 | -5 | 1 | -1 ! | 8 | 8 | eight | 5 | -5 | 2 | 2 ! | 8 | 8 | eight | 5 | -5 | 3 | -3 ! | 8 | 8 | eight | 5 | -5 | 2 | 4 ! | 8 | 8 | eight | 5 | -5 | 5 | -5 ! | 8 | 8 | eight | 5 | -5 | 5 | -5 ! | 8 | 8 | eight | 5 | -5 | 0 | ! | 8 | 8 | eight | 5 | -5 | | ! | 8 | 8 | eight | 5 | -5 | | 0 ! | 0 | | zero | 5 | -5 | 1 | -1 ! | 0 | | zero | 5 | -5 | 2 | 2 ! | 0 | | zero | 5 | -5 | 3 | -3 ! | 0 | | zero | 5 | -5 | 2 | 4 ! | 0 | | zero | 5 | -5 | 5 | -5 ! | 0 | | zero | 5 | -5 | 5 | -5 ! | 0 | | zero | 5 | -5 | 0 | ! | 0 | | zero | 5 | -5 | | ! | 0 | | zero | 5 | -5 | | 0 ! | | | null | 5 | -5 | 1 | -1 ! | | | null | 5 | -5 | 2 | 2 ! | | | null | 5 | -5 | 3 | -3 ! | | | null | 5 | -5 | 2 | 4 ! | | | null | 5 | -5 | 5 | -5 ! | | | null | 5 | -5 | 5 | -5 ! | | | null | 5 | -5 | 0 | ! | | | null | 5 | -5 | | ! | | | null | 5 | -5 | | 0 ! | | 0 | zero | 5 | -5 | 1 | -1 ! | | 0 | zero | 5 | -5 | 2 | 2 ! | | 0 | zero | 5 | -5 | 3 | -3 ! | | 0 | zero | 5 | -5 | 2 | 4 ! | | 0 | zero | 5 | -5 | 5 | -5 ! | | 0 | zero | 5 | -5 | 5 | -5 ! | | 0 | zero | 5 | -5 | 0 | ! | | 0 | zero | 5 | -5 | | ! | | 0 | zero | 5 | -5 | | 0 ! | 1 | 4 | one | 5 | -5 | 1 | -1 ! | 1 | 4 | one | 5 | -5 | 2 | 2 ! | 1 | 4 | one | 5 | -5 | 3 | -3 ! | 1 | 4 | one | 5 | -5 | 2 | 4 ! | 1 | 4 | one | 5 | -5 | 5 | -5 ! | 1 | 4 | one | 5 | -5 | 5 | -5 ! | 1 | 4 | one | 5 | -5 | 0 | ! | 1 | 4 | one | 5 | -5 | | ! | 1 | 4 | one | 5 | -5 | | 0 ! | 2 | 3 | two | 5 | -5 | 1 | -1 ! | 2 | 3 | two | 5 | -5 | 2 | 2 ! | 2 | 3 | two | 5 | -5 | 3 | -3 ! | 2 | 3 | two | 5 | -5 | 2 | 4 ! | 2 | 3 | two | 5 | -5 | 5 | -5 ! | 2 | 3 | two | 5 | -5 | 5 | -5 ! | 2 | 3 | two | 5 | -5 | 0 | ! | 2 | 3 | two | 5 | -5 | | ! | 2 | 3 | two | 5 | -5 | | 0 ! | 3 | 2 | three | 5 | -5 | 1 | -1 ! | 3 | 2 | three | 5 | -5 | 2 | 2 ! | 3 | 2 | three | 5 | -5 | 3 | -3 ! | 3 | 2 | three | 5 | -5 | 2 | 4 ! | 3 | 2 | three | 5 | -5 | 5 | -5 ! | 3 | 2 | three | 5 | -5 | 5 | -5 ! | 3 | 2 | three | 5 | -5 | 0 | ! | 3 | 2 | three | 5 | -5 | | ! | 3 | 2 | three | 5 | -5 | | 0 ! | 4 | 1 | four | 5 | -5 | 1 | -1 ! | 4 | 1 | four | 5 | -5 | 2 | 2 ! | 4 | 1 | four | 5 | -5 | 3 | -3 ! | 4 | 1 | four | 5 | -5 | 2 | 4 ! | 4 | 1 | four | 5 | -5 | 5 | -5 ! | 4 | 1 | four | 5 | -5 | 5 | -5 ! | 4 | 1 | four | 5 | -5 | 0 | ! | 4 | 1 | four | 5 | -5 | | ! | 4 | 1 | four | 5 | -5 | | 0 ! | 5 | 0 | five | 5 | -5 | 1 | -1 ! | 5 | 0 | five | 5 | -5 | 2 | 2 ! | 5 | 0 | five | 5 | -5 | 3 | -3 ! | 5 | 0 | five | 5 | -5 | 2 | 4 ! | 5 | 0 | five | 5 | -5 | 5 | -5 ! | 5 | 0 | five | 5 | -5 | 5 | -5 ! | 5 | 0 | five | 5 | -5 | 0 | ! | 5 | 0 | five | 5 | -5 | | ! | 5 | 0 | five | 5 | -5 | | 0 ! | 6 | 6 | six | 5 | -5 | 1 | -1 ! | 6 | 6 | six | 5 | -5 | 2 | 2 ! | 6 | 6 | six | 5 | -5 | 3 | -3 ! | 6 | 6 | six | 5 | -5 | 2 | 4 ! | 6 | 6 | six | 5 | -5 | 5 | -5 ! | 6 | 6 | six | 5 | -5 | 5 | -5 ! | 6 | 6 | six | 5 | -5 | 0 | ! | 6 | 6 | six | 5 | -5 | | ! | 6 | 6 | six | 5 | -5 | | 0 ! | 7 | 7 | seven | 5 | -5 | 1 | -1 ! | 7 | 7 | seven | 5 | -5 | 2 | 2 ! | 7 | 7 | seven | 5 | -5 | 3 | -3 ! | 7 | 7 | seven | 5 | -5 | 2 | 4 ! | 7 | 7 | seven | 5 | -5 | 5 | -5 ! | 7 | 7 | seven | 5 | -5 | 5 | -5 ! | 7 | 7 | seven | 5 | -5 | 0 | ! | 7 | 7 | seven | 5 | -5 | | ! | 7 | 7 | seven | 5 | -5 | | 0 ! | 8 | 8 | eight | 5 | -5 | 1 | -1 ! | 8 | 8 | eight | 5 | -5 | 2 | 2 ! | 8 | 8 | eight | 5 | -5 | 3 | -3 ! | 8 | 8 | eight | 5 | -5 | 2 | 4 ! | 8 | 8 | eight | 5 | -5 | 5 | -5 ! | 8 | 8 | eight | 5 | -5 | 5 | -5 ! | 8 | 8 | eight | 5 | -5 | 0 | ! | 8 | 8 | eight | 5 | -5 | | ! | 8 | 8 | eight | 5 | -5 | | 0 ! | 0 | | zero | 5 | -5 | 1 | -1 ! | 0 | | zero | 5 | -5 | 2 | 2 ! | 0 | | zero | 5 | -5 | 3 | -3 ! | 0 | | zero | 5 | -5 | 2 | 4 ! | 0 | | zero | 5 | -5 | 5 | -5 ! | 0 | | zero | 5 | -5 | 5 | -5 ! | 0 | | zero | 5 | -5 | 0 | ! | 0 | | zero | 5 | -5 | | ! | 0 | | zero | 5 | -5 | | 0 ! | | | null | 5 | -5 | 1 | -1 ! | | | null | 5 | -5 | 2 | 2 ! | | | null | 5 | -5 | 3 | -3 ! | | | null | 5 | -5 | 2 | 4 ! | | | null | 5 | -5 | 5 | -5 ! | | | null | 5 | -5 | 5 | -5 ! | | | null | 5 | -5 | 0 | ! | | | null | 5 | -5 | | ! | | | null | 5 | -5 | | 0 ! | | 0 | zero | 5 | -5 | 1 | -1 ! | | 0 | zero | 5 | -5 | 2 | 2 ! | | 0 | zero | 5 | -5 | 3 | -3 ! | | 0 | zero | 5 | -5 | 2 | 4 ! | | 0 | zero | 5 | -5 | 5 | -5 ! | | 0 | zero | 5 | -5 | 5 | -5 ! | | 0 | zero | 5 | -5 | 0 | ! | | 0 | zero | 5 | -5 | | ! | | 0 | zero | 5 | -5 | | 0 ! | 1 | 4 | one | 0 | | 1 | -1 ! | 1 | 4 | one | 0 | | 2 | 2 ! | 1 | 4 | one | 0 | | 3 | -3 ! | 1 | 4 | one | 0 | | 2 | 4 ! | 1 | 4 | one | 0 | | 5 | -5 ! | 1 | 4 | one | 0 | | 5 | -5 ! | 1 | 4 | one | 0 | | 0 | ! | 1 | 4 | one | 0 | | | ! | 1 | 4 | one | 0 | | | 0 ! | 2 | 3 | two | 0 | | 1 | -1 ! | 2 | 3 | two | 0 | | 2 | 2 ! | 2 | 3 | two | 0 | | 3 | -3 ! | 2 | 3 | two | 0 | | 2 | 4 ! | 2 | 3 | two | 0 | | 5 | -5 ! | 2 | 3 | two | 0 | | 5 | -5 ! | 2 | 3 | two | 0 | | 0 | ! | 2 | 3 | two | 0 | | | ! | 2 | 3 | two | 0 | | | 0 ! | 3 | 2 | three | 0 | | 1 | -1 ! | 3 | 2 | three | 0 | | 2 | 2 ! | 3 | 2 | three | 0 | | 3 | -3 ! | 3 | 2 | three | 0 | | 2 | 4 ! | 3 | 2 | three | 0 | | 5 | -5 ! | 3 | 2 | three | 0 | | 5 | -5 ! | 3 | 2 | three | 0 | | 0 | ! | 3 | 2 | three | 0 | | | ! | 3 | 2 | three | 0 | | | 0 ! | 4 | 1 | four | 0 | | 1 | -1 ! | 4 | 1 | four | 0 | | 2 | 2 ! | 4 | 1 | four | 0 | | 3 | -3 ! | 4 | 1 | four | 0 | | 2 | 4 ! | 4 | 1 | four | 0 | | 5 | -5 ! | 4 | 1 | four | 0 | | 5 | -5 ! | 4 | 1 | four | 0 | | 0 | ! | 4 | 1 | four | 0 | | | ! | 4 | 1 | four | 0 | | | 0 ! | 5 | 0 | five | 0 | | 1 | -1 ! | 5 | 0 | five | 0 | | 2 | 2 ! | 5 | 0 | five | 0 | | 3 | -3 ! | 5 | 0 | five | 0 | | 2 | 4 ! | 5 | 0 | five | 0 | | 5 | -5 ! | 5 | 0 | five | 0 | | 5 | -5 ! | 5 | 0 | five | 0 | | 0 | ! | 5 | 0 | five | 0 | | | ! | 5 | 0 | five | 0 | | | 0 ! | 6 | 6 | six | 0 | | 1 | -1 ! | 6 | 6 | six | 0 | | 2 | 2 ! | 6 | 6 | six | 0 | | 3 | -3 ! | 6 | 6 | six | 0 | | 2 | 4 ! | 6 | 6 | six | 0 | | 5 | -5 ! | 6 | 6 | six | 0 | | 5 | -5 ! | 6 | 6 | six | 0 | | 0 | ! | 6 | 6 | six | 0 | | | ! | 6 | 6 | six | 0 | | | 0 ! | 7 | 7 | seven | 0 | | 1 | -1 ! | 7 | 7 | seven | 0 | | 2 | 2 ! | 7 | 7 | seven | 0 | | 3 | -3 ! | 7 | 7 | seven | 0 | | 2 | 4 ! | 7 | 7 | seven | 0 | | 5 | -5 ! | 7 | 7 | seven | 0 | | 5 | -5 ! | 7 | 7 | seven | 0 | | 0 | ! | 7 | 7 | seven | 0 | | | ! | 7 | 7 | seven | 0 | | | 0 ! | 8 | 8 | eight | 0 | | 1 | -1 ! | 8 | 8 | eight | 0 | | 2 | 2 ! | 8 | 8 | eight | 0 | | 3 | -3 ! | 8 | 8 | eight | 0 | | 2 | 4 ! | 8 | 8 | eight | 0 | | 5 | -5 ! | 8 | 8 | eight | 0 | | 5 | -5 ! | 8 | 8 | eight | 0 | | 0 | ! | 8 | 8 | eight | 0 | | | ! | 8 | 8 | eight | 0 | | | 0 ! | 0 | | zero | 0 | | 1 | -1 ! | 0 | | zero | 0 | | 2 | 2 ! | 0 | | zero | 0 | | 3 | -3 ! | 0 | | zero | 0 | | 2 | 4 ! | 0 | | zero | 0 | | 5 | -5 ! | 0 | | zero | 0 | | 5 | -5 ! | 0 | | zero | 0 | | 0 | ! | 0 | | zero | 0 | | | ! | 0 | | zero | 0 | | | 0 ! | | | null | 0 | | 1 | -1 ! | | | null | 0 | | 2 | 2 ! | | | null | 0 | | 3 | -3 ! | | | null | 0 | | 2 | 4 ! | | | null | 0 | | 5 | -5 ! | | | null | 0 | | 5 | -5 ! | | | null | 0 | | 0 | ! | | | null | 0 | | | ! | | | null | 0 | | | 0 ! | | 0 | zero | 0 | | 1 | -1 ! | | 0 | zero | 0 | | 2 | 2 ! | | 0 | zero | 0 | | 3 | -3 ! | | 0 | zero | 0 | | 2 | 4 ! | | 0 | zero | 0 | | 5 | -5 ! | | 0 | zero | 0 | | 5 | -5 ! | | 0 | zero | 0 | | 0 | ! | | 0 | zero | 0 | | | ! | | 0 | zero | 0 | | | 0 ! | 1 | 4 | one | | | 1 | -1 ! | 1 | 4 | one | | | 2 | 2 ! | 1 | 4 | one | | | 3 | -3 ! | 1 | 4 | one | | | 2 | 4 ! | 1 | 4 | one | | | 5 | -5 ! | 1 | 4 | one | | | 5 | -5 ! | 1 | 4 | one | | | 0 | ! | 1 | 4 | one | | | | ! | 1 | 4 | one | | | | 0 ! | 2 | 3 | two | | | 1 | -1 ! | 2 | 3 | two | | | 2 | 2 ! | 2 | 3 | two | | | 3 | -3 ! | 2 | 3 | two | | | 2 | 4 ! | 2 | 3 | two | | | 5 | -5 ! | 2 | 3 | two | | | 5 | -5 ! | 2 | 3 | two | | | 0 | ! | 2 | 3 | two | | | | ! | 2 | 3 | two | | | | 0 ! | 3 | 2 | three | | | 1 | -1 ! | 3 | 2 | three | | | 2 | 2 ! | 3 | 2 | three | | | 3 | -3 ! | 3 | 2 | three | | | 2 | 4 ! | 3 | 2 | three | | | 5 | -5 ! | 3 | 2 | three | | | 5 | -5 ! | 3 | 2 | three | | | 0 | ! | 3 | 2 | three | | | | ! | 3 | 2 | three | | | | 0 ! | 4 | 1 | four | | | 1 | -1 ! | 4 | 1 | four | | | 2 | 2 ! | 4 | 1 | four | | | 3 | -3 ! | 4 | 1 | four | | | 2 | 4 ! | 4 | 1 | four | | | 5 | -5 ! | 4 | 1 | four | | | 5 | -5 ! | 4 | 1 | four | | | 0 | ! | 4 | 1 | four | | | | ! | 4 | 1 | four | | | | 0 ! | 5 | 0 | five | | | 1 | -1 ! | 5 | 0 | five | | | 2 | 2 ! | 5 | 0 | five | | | 3 | -3 ! | 5 | 0 | five | | | 2 | 4 ! | 5 | 0 | five | | | 5 | -5 ! | 5 | 0 | five | | | 5 | -5 ! | 5 | 0 | five | | | 0 | ! | 5 | 0 | five | | | | ! | 5 | 0 | five | | | | 0 ! | 6 | 6 | six | | | 1 | -1 ! | 6 | 6 | six | | | 2 | 2 ! | 6 | 6 | six | | | 3 | -3 ! | 6 | 6 | six | | | 2 | 4 ! | 6 | 6 | six | | | 5 | -5 ! | 6 | 6 | six | | | 5 | -5 ! | 6 | 6 | six | | | 0 | ! | 6 | 6 | six | | | | ! | 6 | 6 | six | | | | 0 ! | 7 | 7 | seven | | | 1 | -1 ! | 7 | 7 | seven | | | 2 | 2 ! | 7 | 7 | seven | | | 3 | -3 ! | 7 | 7 | seven | | | 2 | 4 ! | 7 | 7 | seven | | | 5 | -5 ! | 7 | 7 | seven | | | 5 | -5 ! | 7 | 7 | seven | | | 0 | ! | 7 | 7 | seven | | | | ! | 7 | 7 | seven | | | | 0 ! | 8 | 8 | eight | | | 1 | -1 ! | 8 | 8 | eight | | | 2 | 2 ! | 8 | 8 | eight | | | 3 | -3 ! | 8 | 8 | eight | | | 2 | 4 ! | 8 | 8 | eight | | | 5 | -5 ! | 8 | 8 | eight | | | 5 | -5 ! | 8 | 8 | eight | | | 0 | ! | 8 | 8 | eight | | | | ! | 8 | 8 | eight | | | | 0 ! | 0 | | zero | | | 1 | -1 ! | 0 | | zero | | | 2 | 2 ! | 0 | | zero | | | 3 | -3 ! | 0 | | zero | | | 2 | 4 ! | 0 | | zero | | | 5 | -5 ! | 0 | | zero | | | 5 | -5 ! | 0 | | zero | | | 0 | ! | 0 | | zero | | | | ! | 0 | | zero | | | | 0 ! | | | null | | | 1 | -1 ! | | | null | | | 2 | 2 ! | | | null | | | 3 | -3 ! | | | null | | | 2 | 4 ! | | | null | | | 5 | -5 ! | | | null | | | 5 | -5 ! | | | null | | | 0 | ! | | | null | | | | ! | | | null | | | | 0 ! | | 0 | zero | | | 1 | -1 ! | | 0 | zero | | | 2 | 2 ! | | 0 | zero | | | 3 | -3 ! | | 0 | zero | | | 2 | 4 ! | | 0 | zero | | | 5 | -5 ! | | 0 | zero | | | 5 | -5 ! | | 0 | zero | | | 0 | ! | | 0 | zero | | | | ! | | 0 | zero | | | | 0 ! | 1 | 4 | one | | 0 | 1 | -1 ! | 1 | 4 | one | | 0 | 2 | 2 ! | 1 | 4 | one | | 0 | 3 | -3 ! | 1 | 4 | one | | 0 | 2 | 4 ! | 1 | 4 | one | | 0 | 5 | -5 ! | 1 | 4 | one | | 0 | 5 | -5 ! | 1 | 4 | one | | 0 | 0 | ! | 1 | 4 | one | | 0 | | ! | 1 | 4 | one | | 0 | | 0 ! | 2 | 3 | two | | 0 | 1 | -1 ! | 2 | 3 | two | | 0 | 2 | 2 ! | 2 | 3 | two | | 0 | 3 | -3 ! | 2 | 3 | two | | 0 | 2 | 4 ! | 2 | 3 | two | | 0 | 5 | -5 ! | 2 | 3 | two | | 0 | 5 | -5 ! | 2 | 3 | two | | 0 | 0 | ! | 2 | 3 | two | | 0 | | ! | 2 | 3 | two | | 0 | | 0 ! | 3 | 2 | three | | 0 | 1 | -1 ! | 3 | 2 | three | | 0 | 2 | 2 ! | 3 | 2 | three | | 0 | 3 | -3 ! | 3 | 2 | three | | 0 | 2 | 4 ! | 3 | 2 | three | | 0 | 5 | -5 ! | 3 | 2 | three | | 0 | 5 | -5 ! | 3 | 2 | three | | 0 | 0 | ! | 3 | 2 | three | | 0 | | ! | 3 | 2 | three | | 0 | | 0 ! | 4 | 1 | four | | 0 | 1 | -1 ! | 4 | 1 | four | | 0 | 2 | 2 ! | 4 | 1 | four | | 0 | 3 | -3 ! | 4 | 1 | four | | 0 | 2 | 4 ! | 4 | 1 | four | | 0 | 5 | -5 ! | 4 | 1 | four | | 0 | 5 | -5 ! | 4 | 1 | four | | 0 | 0 | ! | 4 | 1 | four | | 0 | | ! | 4 | 1 | four | | 0 | | 0 ! | 5 | 0 | five | | 0 | 1 | -1 ! | 5 | 0 | five | | 0 | 2 | 2 ! | 5 | 0 | five | | 0 | 3 | -3 ! | 5 | 0 | five | | 0 | 2 | 4 ! | 5 | 0 | five | | 0 | 5 | -5 ! | 5 | 0 | five | | 0 | 5 | -5 ! | 5 | 0 | five | | 0 | 0 | ! | 5 | 0 | five | | 0 | | ! | 5 | 0 | five | | 0 | | 0 ! | 6 | 6 | six | | 0 | 1 | -1 ! | 6 | 6 | six | | 0 | 2 | 2 ! | 6 | 6 | six | | 0 | 3 | -3 ! | 6 | 6 | six | | 0 | 2 | 4 ! | 6 | 6 | six | | 0 | 5 | -5 ! | 6 | 6 | six | | 0 | 5 | -5 ! | 6 | 6 | six | | 0 | 0 | ! | 6 | 6 | six | | 0 | | ! | 6 | 6 | six | | 0 | | 0 ! | 7 | 7 | seven | | 0 | 1 | -1 ! | 7 | 7 | seven | | 0 | 2 | 2 ! | 7 | 7 | seven | | 0 | 3 | -3 ! | 7 | 7 | seven | | 0 | 2 | 4 ! | 7 | 7 | seven | | 0 | 5 | -5 ! | 7 | 7 | seven | | 0 | 5 | -5 ! | 7 | 7 | seven | | 0 | 0 | ! | 7 | 7 | seven | | 0 | | ! | 7 | 7 | seven | | 0 | | 0 ! | 8 | 8 | eight | | 0 | 1 | -1 ! | 8 | 8 | eight | | 0 | 2 | 2 ! | 8 | 8 | eight | | 0 | 3 | -3 ! | 8 | 8 | eight | | 0 | 2 | 4 ! | 8 | 8 | eight | | 0 | 5 | -5 ! | 8 | 8 | eight | | 0 | 5 | -5 ! | 8 | 8 | eight | | 0 | 0 | ! | 8 | 8 | eight | | 0 | | ! | 8 | 8 | eight | | 0 | | 0 ! | 0 | | zero | | 0 | 1 | -1 ! | 0 | | zero | | 0 | 2 | 2 ! | 0 | | zero | | 0 | 3 | -3 ! | 0 | | zero | | 0 | 2 | 4 ! | 0 | | zero | | 0 | 5 | -5 ! | 0 | | zero | | 0 | 5 | -5 ! | 0 | | zero | | 0 | 0 | ! | 0 | | zero | | 0 | | ! | 0 | | zero | | 0 | | 0 ! | | | null | | 0 | 1 | -1 ! | | | null | | 0 | 2 | 2 ! | | | null | | 0 | 3 | -3 ! | | | null | | 0 | 2 | 4 ! | | | null | | 0 | 5 | -5 ! | | | null | | 0 | 5 | -5 ! | | | null | | 0 | 0 | ! | | | null | | 0 | | ! | | | null | | 0 | | 0 ! | | 0 | zero | | 0 | 1 | -1 ! | | 0 | zero | | 0 | 2 | 2 ! | | 0 | zero | | 0 | 3 | -3 ! | | 0 | zero | | 0 | 2 | 4 ! | | 0 | zero | | 0 | 5 | -5 ! | | 0 | zero | | 0 | 5 | -5 ! | | 0 | zero | | 0 | 0 | ! | | 0 | zero | | 0 | | ! | | 0 | zero | | 0 | | 0 ! (891 rows) ! ! -- ! -- ! -- Inner joins (equi-joins) ! -- ! -- ! -- ! -- Inner joins (equi-joins) with USING clause ! -- The USING syntax changes the shape of the resulting table ! -- by including a column in the USING clause only once in the result. ! -- ! -- Inner equi-join on specified column ! SELECT '' AS "xxx", * ! FROM J1_TBL INNER JOIN J2_TBL USING (i); ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! -- Same as above, slightly different syntax ! SELECT '' AS "xxx", * ! FROM J1_TBL JOIN J2_TBL USING (i); ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, d) USING (a) ! ORDER BY a, d; ! xxx | a | b | c | d ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, b) USING (b) ! ORDER BY b, t1.a; ! xxx | b | a | c | a ! -----+---+---+-------+--- ! | 0 | 5 | five | ! | 0 | | zero | ! | 2 | 3 | three | 2 ! | 4 | 1 | one | 2 ! (4 rows) ! ! -- ! -- NATURAL JOIN ! -- Inner equi-join on all columns with the same name ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL NATURAL JOIN J2_TBL; ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (a, d); ! xxx | a | b | c | d ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (d, a); ! xxx | a | b | c | d ! -----+---+---+------+--- ! | 0 | | zero | ! | 2 | 3 | two | 2 ! | 4 | 1 | four | 2 ! (3 rows) ! ! -- mismatch number of columns ! -- currently, Postgres will fill in with underlying names ! SELECT '' AS "xxx", * ! FROM J1_TBL t1 (a, b) NATURAL JOIN J2_TBL t2 (a); ! xxx | a | b | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! (7 rows) ! ! -- ! -- Inner joins (equi-joins) ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.i); ! xxx | i | j | t | i | k ! -----+---+---+-------+---+---- ! | 0 | | zero | 0 | ! | 1 | 4 | one | 1 | -1 ! | 2 | 3 | two | 2 | 2 ! | 2 | 3 | two | 2 | 4 ! | 3 | 2 | three | 3 | -3 ! | 5 | 0 | five | 5 | -5 ! | 5 | 0 | five | 5 | -5 ! (7 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.k); ! xxx | i | j | t | i | k ! -----+---+---+------+---+--- ! | 0 | | zero | | 0 ! | 2 | 3 | two | 2 | 2 ! | 4 | 1 | four | 2 | 4 ! (3 rows) ! ! -- ! -- Non-equi-joins ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i <= J2_TBL.k); ! xxx | i | j | t | i | k ! -----+---+---+-------+---+--- ! | 1 | 4 | one | 2 | 2 ! | 2 | 3 | two | 2 | 2 ! | 0 | | zero | 2 | 2 ! | 1 | 4 | one | 2 | 4 ! | 2 | 3 | two | 2 | 4 ! | 3 | 2 | three | 2 | 4 ! | 4 | 1 | four | 2 | 4 ! | 0 | | zero | 2 | 4 ! | 0 | | zero | | 0 ! (9 rows) ! ! -- ! -- Outer joins ! -- Note that OUTER is a noise word ! -- ! SELECT '' AS "xxx", * ! FROM J1_TBL LEFT OUTER JOIN J2_TBL USING (i) ! ORDER BY i, k, t; ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 4 | 1 | four | ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | 6 | 6 | six | ! | 7 | 7 | seven | ! | 8 | 8 | eight | ! | | | null | ! | | 0 | zero | ! (13 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL LEFT JOIN J2_TBL USING (i) ! ORDER BY i, k, t; ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 4 | 1 | four | ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | 6 | 6 | six | ! | 7 | 7 | seven | ! | 8 | 8 | eight | ! | | | null | ! | | 0 | zero | ! (13 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL RIGHT OUTER JOIN J2_TBL USING (i); ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | | | | ! | | | | 0 ! (9 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL RIGHT JOIN J2_TBL USING (i); ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | | | | ! | | | | 0 ! (9 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL FULL OUTER JOIN J2_TBL USING (i) ! ORDER BY i, k, t; ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 4 | 1 | four | ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | 6 | 6 | six | ! | 7 | 7 | seven | ! | 8 | 8 | eight | ! | | | | 0 ! | | | null | ! | | 0 | zero | ! | | | | ! (15 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL FULL JOIN J2_TBL USING (i) ! ORDER BY i, k, t; ! xxx | i | j | t | k ! -----+---+---+-------+---- ! | 0 | | zero | ! | 1 | 4 | one | -1 ! | 2 | 3 | two | 2 ! | 2 | 3 | two | 4 ! | 3 | 2 | three | -3 ! | 4 | 1 | four | ! | 5 | 0 | five | -5 ! | 5 | 0 | five | -5 ! | 6 | 6 | six | ! | 7 | 7 | seven | ! | 8 | 8 | eight | ! | | | | 0 ! | | | null | ! | | 0 | zero | ! | | | | ! (15 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (k = 1); ! xxx | i | j | t | k ! -----+---+---+---+--- ! (0 rows) ! ! SELECT '' AS "xxx", * ! FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (i = 1); ! xxx | i | j | t | k ! -----+---+---+-----+---- ! | 1 | 4 | one | -1 ! (1 row) ! ! -- ! -- More complicated constructs ! -- ! -- ! -- Multiway full join ! -- ! CREATE TABLE t1 (name TEXT, n INTEGER); ! CREATE TABLE t2 (name TEXT, n INTEGER); ! CREATE TABLE t3 (name TEXT, n INTEGER); ! INSERT INTO t1 VALUES ( 'bb', 11 ); ! INSERT INTO t2 VALUES ( 'bb', 12 ); ! INSERT INTO t2 VALUES ( 'cc', 22 ); ! INSERT INTO t2 VALUES ( 'ee', 42 ); ! INSERT INTO t3 VALUES ( 'bb', 13 ); ! INSERT INTO t3 VALUES ( 'cc', 23 ); ! INSERT INTO t3 VALUES ( 'dd', 33 ); ! SELECT * FROM t1 FULL JOIN t2 USING (name) FULL JOIN t3 USING (name); ! name | n | n | n ! ------+----+----+---- ! bb | 11 | 12 | 13 ! cc | | 22 | 23 ! dd | | | 33 ! ee | | 42 | ! (4 rows) ! ! -- ! -- Test interactions of join syntax and subqueries ! -- ! -- Basic cases (we expect planner to pull up the subquery here) ! SELECT * FROM ! (SELECT * FROM t2) as s2 ! INNER JOIN ! (SELECT * FROM t3) s3 ! USING (name); ! name | n | n ! ------+----+---- ! bb | 12 | 13 ! cc | 22 | 23 ! (2 rows) ! ! SELECT * FROM ! (SELECT * FROM t2) as s2 ! LEFT JOIN ! (SELECT * FROM t3) s3 ! USING (name); ! name | n | n ! ------+----+---- ! bb | 12 | 13 ! cc | 22 | 23 ! ee | 42 | ! (3 rows) ! ! SELECT * FROM ! (SELECT * FROM t2) as s2 ! FULL JOIN ! (SELECT * FROM t3) s3 ! USING (name); ! name | n | n ! ------+----+---- ! bb | 12 | 13 ! cc | 22 | 23 ! dd | | 33 ! ee | 42 | ! (4 rows) ! ! -- Cases with non-nullable expressions in subquery results; ! -- make sure these go to null as expected ! SELECT * FROM ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL INNER JOIN ! (SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3; ! name | s2_n | s2_2 | s3_n | s3_2 ! ------+------+------+------+------ ! bb | 12 | 2 | 13 | 3 ! cc | 22 | 2 | 23 | 3 ! (2 rows) ! ! SELECT * FROM ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL LEFT JOIN ! (SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3; ! name | s2_n | s2_2 | s3_n | s3_2 ! ------+------+------+------+------ ! bb | 12 | 2 | 13 | 3 ! cc | 22 | 2 | 23 | 3 ! ee | 42 | 2 | | ! (3 rows) ! ! SELECT * FROM ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL FULL JOIN ! (SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3; ! name | s2_n | s2_2 | s3_n | s3_2 ! ------+------+------+------+------ ! bb | 12 | 2 | 13 | 3 ! cc | 22 | 2 | 23 | 3 ! dd | | | 33 | 3 ! ee | 42 | 2 | | ! (4 rows) ! ! SELECT * FROM ! (SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1 ! NATURAL INNER JOIN ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL INNER JOIN ! (SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3; ! name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2 ! ------+------+------+------+------+------+------ ! bb | 11 | 1 | 12 | 2 | 13 | 3 ! (1 row) ! ! SELECT * FROM ! (SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1 ! NATURAL FULL JOIN ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL FULL JOIN ! (SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3; ! name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2 ! ------+------+------+------+------+------+------ ! bb | 11 | 1 | 12 | 2 | 13 | 3 ! cc | | | 22 | 2 | 23 | 3 ! dd | | | | | 33 | 3 ! ee | | | 42 | 2 | | ! (4 rows) ! ! SELECT * FROM ! (SELECT name, n as s1_n FROM t1) as s1 ! NATURAL FULL JOIN ! (SELECT * FROM ! (SELECT name, n as s2_n FROM t2) as s2 ! NATURAL FULL JOIN ! (SELECT name, n as s3_n FROM t3) as s3 ! ) ss2; ! name | s1_n | s2_n | s3_n ! ------+------+------+------ ! bb | 11 | 12 | 13 ! cc | | 22 | 23 ! dd | | | 33 ! ee | | 42 | ! (4 rows) ! ! SELECT * FROM ! (SELECT name, n as s1_n FROM t1) as s1 ! NATURAL FULL JOIN ! (SELECT * FROM ! (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2 ! NATURAL FULL JOIN ! (SELECT name, n as s3_n FROM t3) as s3 ! ) ss2; ! name | s1_n | s2_n | s2_2 | s3_n ! ------+------+------+------+------ ! bb | 11 | 12 | 2 | 13 ! cc | | 22 | 2 | 23 ! dd | | | | 33 ! ee | | 42 | 2 | ! (4 rows) ! ! -- Test for propagation of nullability constraints into sub-joins ! create temp table x (x1 int, x2 int); ! insert into x values (1,11); ! insert into x values (2,22); ! insert into x values (3,null); ! insert into x values (4,44); ! insert into x values (5,null); ! create temp table y (y1 int, y2 int); ! insert into y values (1,111); ! insert into y values (2,222); ! insert into y values (3,333); ! insert into y values (4,null); ! select * from x; ! x1 | x2 ! ----+---- ! 1 | 11 ! 2 | 22 ! 3 | ! 4 | 44 ! 5 | ! (5 rows) ! ! select * from y; ! y1 | y2 ! ----+----- ! 1 | 111 ! 2 | 222 ! 3 | 333 ! 4 | ! (4 rows) ! ! select * from x left join y on (x1 = y1 and x2 is not null); ! x1 | x2 | y1 | y2 ! ----+----+----+----- ! 1 | 11 | 1 | 111 ! 2 | 22 | 2 | 222 ! 3 | | | ! 4 | 44 | 4 | ! 5 | | | ! (5 rows) ! ! select * from x left join y on (x1 = y1 and y2 is not null); ! x1 | x2 | y1 | y2 ! ----+----+----+----- ! 1 | 11 | 1 | 111 ! 2 | 22 | 2 | 222 ! 3 | | 3 | 333 ! 4 | 44 | | ! 5 | | | ! (5 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 3 | | 3 | 333 | 3 | ! 4 | 44 | 4 | | 4 | 44 ! 5 | | | | 5 | ! (5 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1 and x2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 3 | | 3 | 333 | | ! 4 | 44 | 4 | | 4 | 44 ! 5 | | | | | ! (5 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1 and y2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 3 | | 3 | 333 | 3 | ! 4 | 44 | 4 | | | ! 5 | | | | | ! (5 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1 and xx2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 3 | | 3 | 333 | | ! 4 | 44 | 4 | | 4 | 44 ! 5 | | | | | ! (5 rows) ! ! -- these should NOT give the same answers as above ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1) where (x2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 4 | 44 | 4 | | 4 | 44 ! (3 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1) where (y2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 3 | | 3 | 333 | 3 | ! (3 rows) ! ! select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) ! on (x1 = xx1) where (xx2 is not null); ! x1 | x2 | y1 | y2 | xx1 | xx2 ! ----+----+----+-----+-----+----- ! 1 | 11 | 1 | 111 | 1 | 11 ! 2 | 22 | 2 | 222 | 2 | 22 ! 4 | 44 | 4 | | 4 | 44 ! (3 rows) ! ! -- ! -- regression test: check for bug with propagation of implied equality ! -- to outside an IN ! -- ! select count(*) from tenk1 a where unique1 in ! (select unique1 from tenk1 b join tenk1 c using (unique1) ! where b.unique2 = 42); ! count ! ------- ! 1 ! (1 row) ! ! -- ! -- regression test: check for failure to generate a plan with multiple ! -- degenerate IN clauses ! -- ! select count(*) from tenk1 x where ! x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and ! x.unique1 = 0 and ! x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1); ! count ! ------- ! 1 ! (1 row) ! ! -- try that with GEQO too ! begin; ! set geqo = on; ! set geqo_threshold = 2; ! select count(*) from tenk1 x where ! x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and ! x.unique1 = 0 and ! x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1); ! count ! ------- ! 1 ! (1 row) ! ! rollback; ! -- ! -- Clean up ! -- ! DROP TABLE t1; ! DROP TABLE t2; ! DROP TABLE t3; ! DROP TABLE J1_TBL; ! DROP TABLE J2_TBL; ! -- Both DELETE and UPDATE allow the specification of additional tables ! -- to "join" against to determine which rows should be modified. ! CREATE TEMP TABLE t1 (a int, b int); ! CREATE TEMP TABLE t2 (a int, b int); ! CREATE TEMP TABLE t3 (x int, y int); ! INSERT INTO t1 VALUES (5, 10); ! INSERT INTO t1 VALUES (15, 20); ! INSERT INTO t1 VALUES (100, 100); ! INSERT INTO t1 VALUES (200, 1000); ! INSERT INTO t2 VALUES (200, 2000); ! INSERT INTO t3 VALUES (5, 20); ! INSERT INTO t3 VALUES (6, 7); ! INSERT INTO t3 VALUES (7, 8); ! INSERT INTO t3 VALUES (500, 100); ! DELETE FROM t3 USING t1 table1 WHERE t3.x = table1.a; ! SELECT * FROM t3; ! x | y ! -----+----- ! 6 | 7 ! 7 | 8 ! 500 | 100 ! (3 rows) ! ! DELETE FROM t3 USING t1 JOIN t2 USING (a) WHERE t3.x > t1.a; ! SELECT * FROM t3; ! x | y ! ---+--- ! 6 | 7 ! 7 | 8 ! (2 rows) ! ! DELETE FROM t3 USING t3 t3_other WHERE t3.x = t3_other.x AND t3.y = t3_other.y; ! SELECT * FROM t3; ! x | y ! ---+--- ! (0 rows) ! ! -- Test join against inheritance tree ! create temp table t2a () inherits (t2); ! insert into t2a values (200, 2001); ! select * from t1 left join t2 on (t1.a = t2.a); ! a | b | a | b ! -----+------+-----+------ ! 5 | 10 | | ! 15 | 20 | | ! 100 | 100 | | ! 200 | 1000 | 200 | 2000 ! 200 | 1000 | 200 | 2001 ! (5 rows) ! ! -- ! -- regression test for 8.1 merge right join bug ! -- ! CREATE TEMP TABLE tt1 ( tt1_id int4, joincol int4 ); ! INSERT INTO tt1 VALUES (1, 11); ! INSERT INTO tt1 VALUES (2, NULL); ! CREATE TEMP TABLE tt2 ( tt2_id int4, joincol int4 ); ! INSERT INTO tt2 VALUES (21, 11); ! INSERT INTO tt2 VALUES (22, 11); ! set enable_hashjoin to off; ! set enable_nestloop to off; ! -- these should give the same results ! select tt1.*, tt2.* from tt1 left join tt2 on tt1.joincol = tt2.joincol; ! tt1_id | joincol | tt2_id | joincol ! --------+---------+--------+--------- ! 1 | 11 | 21 | 11 ! 1 | 11 | 22 | 11 ! 2 | | | ! (3 rows) ! ! select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol; ! tt1_id | joincol | tt2_id | joincol ! --------+---------+--------+--------- ! 1 | 11 | 21 | 11 ! 1 | 11 | 22 | 11 ! 2 | | | ! (3 rows) ! ! reset enable_hashjoin; ! reset enable_nestloop; ! -- ! -- regression test for 8.2 bug with improper re-ordering of left joins ! -- ! create temp table tt3(f1 int, f2 text); ! insert into tt3 select x, repeat('xyzzy', 100) from generate_series(1,10000) x; ! create index tt3i on tt3(f1); ! analyze tt3; ! create temp table tt4(f1 int); ! insert into tt4 values (0),(1),(9999); ! analyze tt4; ! SELECT a.f1 ! FROM tt4 a ! LEFT JOIN ( ! SELECT b.f1 ! FROM tt3 b LEFT JOIN tt3 c ON (b.f1 = c.f1) ! WHERE c.f1 IS NULL ! ) AS d ON (a.f1 = d.f1) ! WHERE d.f1 IS NULL; ! f1 ! ------ ! 0 ! 1 ! 9999 ! (3 rows) ! ! -- ! -- regression test for problems of the sort depicted in bug #3494 ! -- ! create temp table tt5(f1 int, f2 int); ! create temp table tt6(f1 int, f2 int); ! insert into tt5 values(1, 10); ! insert into tt5 values(1, 11); ! insert into tt6 values(1, 9); ! insert into tt6 values(1, 2); ! insert into tt6 values(2, 9); ! select * from tt5,tt6 where tt5.f1 = tt6.f1 and tt5.f1 = tt5.f2 - tt6.f2; ! f1 | f2 | f1 | f2 ! ----+----+----+---- ! 1 | 10 | 1 | 9 ! (1 row) ! ! -- ! -- regression test for problems of the sort depicted in bug #3588 ! -- ! create temp table xx (pkxx int); ! create temp table yy (pkyy int, pkxx int); ! insert into xx values (1); ! insert into xx values (2); ! insert into xx values (3); ! insert into yy values (101, 1); ! insert into yy values (201, 2); ! insert into yy values (301, NULL); ! select yy.pkyy as yy_pkyy, yy.pkxx as yy_pkxx, yya.pkyy as yya_pkyy, ! xxa.pkxx as xxa_pkxx, xxb.pkxx as xxb_pkxx ! from yy ! left join (SELECT * FROM yy where pkyy = 101) as yya ON yy.pkyy = yya.pkyy ! left join xx xxa on yya.pkxx = xxa.pkxx ! left join xx xxb on coalesce (xxa.pkxx, 1) = xxb.pkxx; ! yy_pkyy | yy_pkxx | yya_pkyy | xxa_pkxx | xxb_pkxx ! ---------+---------+----------+----------+---------- ! 101 | 1 | 101 | 1 | 1 ! 201 | 2 | | | 1 ! 301 | | | | 1 ! (3 rows) ! ! -- ! -- regression test for improper pushing of constants across outer-join clauses ! -- (as seen in early 8.2.x releases) ! -- ! create temp table zt1 (f1 int primary key); ! create temp table zt2 (f2 int primary key); ! create temp table zt3 (f3 int primary key); ! insert into zt1 values(53); ! insert into zt2 values(53); ! select * from ! zt2 left join zt3 on (f2 = f3) ! left join zt1 on (f3 = f1) ! where f2 = 53; ! f2 | f3 | f1 ! ----+----+---- ! 53 | | ! (1 row) ! ! create temp view zv1 as select *,'dummy'::text AS junk from zt1; ! select * from ! zt2 left join zt3 on (f2 = f3) ! left join zv1 on (f3 = f1) ! where f2 = 53; ! f2 | f3 | f1 | junk ! ----+----+----+------ ! 53 | | | ! (1 row) ! ! -- ! -- regression test for improper extraction of OR indexqual conditions ! -- (as seen in early 8.3.x releases) ! -- ! select a.unique2, a.ten, b.tenthous, b.unique2, b.hundred ! from tenk1 a left join tenk1 b on a.unique2 = b.tenthous ! where a.unique1 = 42 and ! ((b.unique2 is null and a.ten = 2) or b.hundred = 3); ! unique2 | ten | tenthous | unique2 | hundred ! ---------+-----+----------+---------+--------- ! (0 rows) ! ! -- ! -- test proper positioning of one-time quals in EXISTS (8.4devel bug) ! -- ! prepare foo(bool) as ! select count(*) from tenk1 a left join tenk1 b ! on (a.unique2 = b.unique1 and exists ! (select 1 from tenk1 c where c.thousand = b.unique2 and $1)); ! execute foo(true); ! count ! ------- ! 10000 ! (1 row) ! ! execute foo(false); ! count ! ------- ! 10000 ! (1 row) ! ! -- ! -- test for sane behavior with noncanonical merge clauses, per bug #4926 ! -- ! begin; ! set enable_mergejoin = 1; ! set enable_hashjoin = 0; ! set enable_nestloop = 0; ! create temp table a (i integer); ! create temp table b (x integer, y integer); ! select * from a left join b on i = x and i = y and x = i; ! i | x | y ! ---+---+--- ! (0 rows) ! ! rollback; ! -- ! -- test NULL behavior of whole-row Vars, per bug #5025 ! -- ! select t1.q2, count(t2.*) ! from int8_tbl t1 left join int8_tbl t2 on (t1.q2 = t2.q1) ! group by t1.q2 order by 1; ! q2 | count ! -------------------+------- ! -4567890123456789 | 0 ! 123 | 2 ! 456 | 0 ! 4567890123456789 | 6 ! (4 rows) ! ! select t1.q2, count(t2.*) ! from int8_tbl t1 left join (select * from int8_tbl) t2 on (t1.q2 = t2.q1) ! group by t1.q2 order by 1; ! q2 | count ! -------------------+------- ! -4567890123456789 | 0 ! 123 | 2 ! 456 | 0 ! 4567890123456789 | 6 ! (4 rows) ! ! select t1.q2, count(t2.*) ! from int8_tbl t1 left join (select * from int8_tbl offset 0) t2 on (t1.q2 = t2.q1) ! group by t1.q2 order by 1; ! q2 | count ! -------------------+------- ! -4567890123456789 | 0 ! 123 | 2 ! 456 | 0 ! 4567890123456789 | 6 ! (4 rows) ! ! select t1.q2, count(t2.*) ! from int8_tbl t1 left join ! (select q1, case when q2=1 then 1 else q2 end as q2 from int8_tbl) t2 ! on (t1.q2 = t2.q1) ! group by t1.q2 order by 1; ! q2 | count ! -------------------+------- ! -4567890123456789 | 0 ! 123 | 2 ! 456 | 0 ! 4567890123456789 | 6 ! (4 rows) ! ! -- ! -- test incorrect failure to NULL pulled-up subexpressions ! -- ! begin; ! create temp table a ( ! code char not null, ! constraint a_pk primary key (code) ! ); ! create temp table b ( ! a char not null, ! num integer not null, ! constraint b_pk primary key (a, num) ! ); ! create temp table c ( ! name char not null, ! a char, ! constraint c_pk primary key (name) ! ); ! insert into a (code) values ('p'); ! insert into a (code) values ('q'); ! insert into b (a, num) values ('p', 1); ! insert into b (a, num) values ('p', 2); ! insert into c (name, a) values ('A', 'p'); ! insert into c (name, a) values ('B', 'q'); ! insert into c (name, a) values ('C', null); ! select c.name, ss.code, ss.b_cnt, ss.const ! from c left join ! (select a.code, coalesce(b_grp.cnt, 0) as b_cnt, -1 as const ! from a left join ! (select count(1) as cnt, b.a from b group by b.a) as b_grp ! on a.code = b_grp.a ! ) as ss ! on (c.a = ss.code) ! order by c.name; ! name | code | b_cnt | const ! ------+------+-------+------- ! A | p | 2 | -1 ! B | q | 0 | -1 ! C | | | ! (3 rows) ! ! rollback; ! -- ! -- test incorrect handling of placeholders that only appear in targetlists, ! -- per bug #6154 ! -- ! SELECT * FROM ! ( SELECT 1 as key1 ) sub1 ! LEFT JOIN ! ( SELECT sub3.key3, sub4.value2, COALESCE(sub4.value2, 66) as value3 FROM ! ( SELECT 1 as key3 ) sub3 ! LEFT JOIN ! ( SELECT sub5.key5, COALESCE(sub6.value1, 1) as value2 FROM ! ( SELECT 1 as key5 ) sub5 ! LEFT JOIN ! ( SELECT 2 as key6, 42 as value1 ) sub6 ! ON sub5.key5 = sub6.key6 ! ) sub4 ! ON sub4.key5 = sub3.key3 ! ) sub2 ! ON sub1.key1 = sub2.key3; ! key1 | key3 | value2 | value3 ! ------+------+--------+-------- ! 1 | 1 | 1 | 1 ! (1 row) ! ! -- test the path using join aliases, too ! SELECT * FROM ! ( SELECT 1 as key1 ) sub1 ! LEFT JOIN ! ( SELECT sub3.key3, value2, COALESCE(value2, 66) as value3 FROM ! ( SELECT 1 as key3 ) sub3 ! LEFT JOIN ! ( SELECT sub5.key5, COALESCE(sub6.value1, 1) as value2 FROM ! ( SELECT 1 as key5 ) sub5 ! LEFT JOIN ! ( SELECT 2 as key6, 42 as value1 ) sub6 ! ON sub5.key5 = sub6.key6 ! ) sub4 ! ON sub4.key5 = sub3.key3 ! ) sub2 ! ON sub1.key1 = sub2.key3; ! key1 | key3 | value2 | value3 ! ------+------+--------+-------- ! 1 | 1 | 1 | 1 ! (1 row) ! ! -- ! -- test case where a PlaceHolderVar is used as a nestloop parameter ! -- ! EXPLAIN (COSTS OFF) ! SELECT qq, unique1 ! FROM ! ( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1 ! FULL OUTER JOIN ! ( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2 ! USING (qq) ! INNER JOIN tenk1 c ON qq = unique2; ! QUERY PLAN ! ------------------------------------------------------------------------------------------------------- ! Nested Loop ! -> Hash Full Join ! Hash Cond: (COALESCE(a.q1, 0::bigint) = COALESCE(b.q2, (-1)::bigint)) ! -> Seq Scan on int8_tbl a ! -> Hash ! -> Seq Scan on int8_tbl b ! -> Index Scan using tenk1_unique2 on tenk1 c ! Index Cond: (unique2 = COALESCE((COALESCE(a.q1, 0::bigint)), (COALESCE(b.q2, (-1)::bigint)))) ! (8 rows) ! ! SELECT qq, unique1 ! FROM ! ( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1 ! FULL OUTER JOIN ! ( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2 ! USING (qq) ! INNER JOIN tenk1 c ON qq = unique2; ! qq | unique1 ! -----+--------- ! 123 | 4596 ! 123 | 4596 ! 456 | 7318 ! (3 rows) ! ! -- ! -- nested nestloops can require nested PlaceHolderVars ! -- ! create temp table nt1 ( ! id int primary key, ! a1 boolean, ! a2 boolean ! ); ! create temp table nt2 ( ! id int primary key, ! nt1_id int, ! b1 boolean, ! b2 boolean, ! foreign key (nt1_id) references nt1(id) ! ); ! create temp table nt3 ( ! id int primary key, ! nt2_id int, ! c1 boolean, ! foreign key (nt2_id) references nt2(id) ! ); ! insert into nt1 values (1,true,true); ! insert into nt1 values (2,true,false); ! insert into nt1 values (3,false,false); ! insert into nt2 values (1,1,true,true); ! insert into nt2 values (2,2,true,false); ! insert into nt2 values (3,3,false,false); ! insert into nt3 values (1,1,true); ! insert into nt3 values (2,2,false); ! insert into nt3 values (3,3,true); ! explain (costs off) ! select nt3.id ! from nt3 as nt3 ! left join ! (select nt2.*, (nt2.b1 and ss1.a3) AS b3 ! from nt2 as nt2 ! left join ! (select nt1.*, (nt1.id is not null) as a3 from nt1) as ss1 ! on ss1.id = nt2.nt1_id ! ) as ss2 ! on ss2.id = nt3.nt2_id ! where nt3.id = 1 and ss2.b3; ! QUERY PLAN ! ----------------------------------------------- ! Nested Loop ! -> Nested Loop ! -> Index Scan using nt3_pkey on nt3 ! Index Cond: (id = 1) ! -> Index Scan using nt2_pkey on nt2 ! Index Cond: (id = nt3.nt2_id) ! -> Index Only Scan using nt1_pkey on nt1 ! Index Cond: (id = nt2.nt1_id) ! Filter: (nt2.b1 AND (id IS NOT NULL)) ! (9 rows) ! ! select nt3.id ! from nt3 as nt3 ! left join ! (select nt2.*, (nt2.b1 and ss1.a3) AS b3 ! from nt2 as nt2 ! left join ! (select nt1.*, (nt1.id is not null) as a3 from nt1) as ss1 ! on ss1.id = nt2.nt1_id ! ) as ss2 ! on ss2.id = nt3.nt2_id ! where nt3.id = 1 and ss2.b3; ! id ! ---- ! 1 ! (1 row) ! ! -- ! -- test case where a PlaceHolderVar is propagated into a subquery ! -- ! explain (costs off) ! select * from ! int8_tbl t1 left join ! (select q1 as x, 42 as y from int8_tbl t2) ss ! on t1.q2 = ss.x ! where ! 1 = (select 1 from int8_tbl t3 where ss.y is not null limit 1) ! order by 1,2; ! QUERY PLAN ! ----------------------------------------------------------- ! Sort ! Sort Key: t1.q1, t1.q2 ! -> Hash Left Join ! Hash Cond: (t1.q2 = t2.q1) ! Filter: (1 = (SubPlan 1)) ! -> Seq Scan on int8_tbl t1 ! -> Hash ! -> Seq Scan on int8_tbl t2 ! SubPlan 1 ! -> Limit ! -> Result ! One-Time Filter: ((42) IS NOT NULL) ! -> Seq Scan on int8_tbl t3 ! (13 rows) ! ! select * from ! int8_tbl t1 left join ! (select q1 as x, 42 as y from int8_tbl t2) ss ! on t1.q2 = ss.x ! where ! 1 = (select 1 from int8_tbl t3 where ss.y is not null limit 1) ! order by 1,2; ! q1 | q2 | x | y ! ------------------+------------------+------------------+---- ! 123 | 4567890123456789 | 4567890123456789 | 42 ! 123 | 4567890123456789 | 4567890123456789 | 42 ! 123 | 4567890123456789 | 4567890123456789 | 42 ! 4567890123456789 | 123 | 123 | 42 ! 4567890123456789 | 123 | 123 | 42 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 42 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 42 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 42 ! (8 rows) ! ! -- ! -- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE ! -- ! select * from int4_tbl a full join int4_tbl b on true; ! f1 | f1 ! -------------+------------- ! 0 | 0 ! 0 | 123456 ! 0 | -123456 ! 0 | 2147483647 ! 0 | -2147483647 ! 123456 | 0 ! 123456 | 123456 ! 123456 | -123456 ! 123456 | 2147483647 ! 123456 | -2147483647 ! -123456 | 0 ! -123456 | 123456 ! -123456 | -123456 ! -123456 | 2147483647 ! -123456 | -2147483647 ! 2147483647 | 0 ! 2147483647 | 123456 ! 2147483647 | -123456 ! 2147483647 | 2147483647 ! 2147483647 | -2147483647 ! -2147483647 | 0 ! -2147483647 | 123456 ! -2147483647 | -123456 ! -2147483647 | 2147483647 ! -2147483647 | -2147483647 ! (25 rows) ! ! select * from int4_tbl a full join int4_tbl b on false; ! f1 | f1 ! -------------+------------- ! | 0 ! | 123456 ! | -123456 ! | 2147483647 ! | -2147483647 ! 0 | ! 123456 | ! -123456 | ! 2147483647 | ! -2147483647 | ! (10 rows) ! ! -- ! -- test for ability to use a cartesian join when necessary ! -- ! explain (costs off) ! select * from ! tenk1 join int4_tbl on f1 = twothousand, ! int4(sin(1)) q1, ! int4(sin(0)) q2 ! where q1 = thousand or q2 = thousand; ! QUERY PLAN ! ------------------------------------------------------------------------ ! Hash Join ! Hash Cond: (tenk1.twothousand = int4_tbl.f1) ! -> Nested Loop ! -> Nested Loop ! -> Function Scan on q1 ! -> Function Scan on q2 ! -> Bitmap Heap Scan on tenk1 ! Recheck Cond: ((q1.q1 = thousand) OR (q2.q2 = thousand)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_thous_tenthous ! Index Cond: (q1.q1 = thousand) ! -> Bitmap Index Scan on tenk1_thous_tenthous ! Index Cond: (q2.q2 = thousand) ! -> Hash ! -> Seq Scan on int4_tbl ! (15 rows) ! ! explain (costs off) ! select * from ! tenk1 join int4_tbl on f1 = twothousand, ! int4(sin(1)) q1, ! int4(sin(0)) q2 ! where thousand = (q1 + q2); ! QUERY PLAN ! -------------------------------------------------------------- ! Hash Join ! Hash Cond: (tenk1.twothousand = int4_tbl.f1) ! -> Nested Loop ! -> Nested Loop ! -> Function Scan on q1 ! -> Function Scan on q2 ! -> Bitmap Heap Scan on tenk1 ! Recheck Cond: (thousand = (q1.q1 + q2.q2)) ! -> Bitmap Index Scan on tenk1_thous_tenthous ! Index Cond: (thousand = (q1.q1 + q2.q2)) ! -> Hash ! -> Seq Scan on int4_tbl ! (12 rows) ! ! -- ! -- test extraction of restriction OR clauses from join OR clause ! -- (we used to only do this for indexable clauses) ! -- ! explain (costs off) ! select * from tenk1 a join tenk1 b on ! (a.unique1 = 1 and b.unique1 = 2) or (a.unique2 = 3 and b.hundred = 4); ! QUERY PLAN ! ------------------------------------------------------------------------------------------------- ! Nested Loop ! Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = 3) AND (b.hundred = 4))) ! -> Bitmap Heap Scan on tenk1 b ! Recheck Cond: ((unique1 = 2) OR (hundred = 4)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_unique1 ! Index Cond: (unique1 = 2) ! -> Bitmap Index Scan on tenk1_hundred ! Index Cond: (hundred = 4) ! -> Materialize ! -> Bitmap Heap Scan on tenk1 a ! Recheck Cond: ((unique1 = 1) OR (unique2 = 3)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_unique1 ! Index Cond: (unique1 = 1) ! -> Bitmap Index Scan on tenk1_unique2 ! Index Cond: (unique2 = 3) ! (17 rows) ! ! explain (costs off) ! select * from tenk1 a join tenk1 b on ! (a.unique1 = 1 and b.unique1 = 2) or (a.unique2 = 3 and b.ten = 4); ! QUERY PLAN ! --------------------------------------------------------------------------------------------- ! Nested Loop ! Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = 3) AND (b.ten = 4))) ! -> Seq Scan on tenk1 b ! Filter: ((unique1 = 2) OR (ten = 4)) ! -> Materialize ! -> Bitmap Heap Scan on tenk1 a ! Recheck Cond: ((unique1 = 1) OR (unique2 = 3)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_unique1 ! Index Cond: (unique1 = 1) ! -> Bitmap Index Scan on tenk1_unique2 ! Index Cond: (unique2 = 3) ! (12 rows) ! ! explain (costs off) ! select * from tenk1 a join tenk1 b on ! (a.unique1 = 1 and b.unique1 = 2) or ! ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); ! QUERY PLAN ! ---------------------------------------------------------------------------------------------------------------------- ! Nested Loop ! Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR (((a.unique2 = 3) OR (a.unique2 = 7)) AND (b.hundred = 4))) ! -> Bitmap Heap Scan on tenk1 b ! Recheck Cond: ((unique1 = 2) OR (hundred = 4)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_unique1 ! Index Cond: (unique1 = 2) ! -> Bitmap Index Scan on tenk1_hundred ! Index Cond: (hundred = 4) ! -> Materialize ! -> Bitmap Heap Scan on tenk1 a ! Recheck Cond: ((unique1 = 1) OR (unique2 = 3) OR (unique2 = 7)) ! -> BitmapOr ! -> Bitmap Index Scan on tenk1_unique1 ! Index Cond: (unique1 = 1) ! -> Bitmap Index Scan on tenk1_unique2 ! Index Cond: (unique2 = 3) ! -> Bitmap Index Scan on tenk1_unique2 ! Index Cond: (unique2 = 7) ! (19 rows) ! ! -- ! -- test placement of movable quals in a parameterized join tree ! -- ! explain (costs off) ! select * from tenk1 t1 left join ! (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2) ! on t1.hundred = t2.hundred and t1.ten = t3.ten ! where t1.unique1 = 1; ! QUERY PLAN ! -------------------------------------------------------- ! Nested Loop Left Join ! -> Index Scan using tenk1_unique1 on tenk1 t1 ! Index Cond: (unique1 = 1) ! -> Nested Loop ! Join Filter: (t1.ten = t3.ten) ! -> Bitmap Heap Scan on tenk1 t2 ! Recheck Cond: (t1.hundred = hundred) ! -> Bitmap Index Scan on tenk1_hundred ! Index Cond: (t1.hundred = hundred) ! -> Index Scan using tenk1_unique2 on tenk1 t3 ! Index Cond: (unique2 = t2.thousand) ! (11 rows) ! ! explain (costs off) ! select * from tenk1 t1 left join ! (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2) ! on t1.hundred = t2.hundred and t1.ten + t2.ten = t3.ten ! where t1.unique1 = 1; ! QUERY PLAN ! -------------------------------------------------------- ! Nested Loop Left Join ! -> Index Scan using tenk1_unique1 on tenk1 t1 ! Index Cond: (unique1 = 1) ! -> Nested Loop ! Join Filter: ((t1.ten + t2.ten) = t3.ten) ! -> Bitmap Heap Scan on tenk1 t2 ! Recheck Cond: (t1.hundred = hundred) ! -> Bitmap Index Scan on tenk1_hundred ! Index Cond: (t1.hundred = hundred) ! -> Index Scan using tenk1_unique2 on tenk1 t3 ! Index Cond: (unique2 = t2.thousand) ! (11 rows) ! ! explain (costs off) ! select count(*) from ! tenk1 a join tenk1 b on a.unique1 = b.unique2 ! left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand ! join int4_tbl on b.thousand = f1; ! QUERY PLAN ! ------------------------------------------------------------------------- ! Aggregate ! -> Nested Loop Left Join ! Join Filter: (a.unique2 = b.unique1) ! -> Nested Loop ! -> Nested Loop ! -> Seq Scan on int4_tbl ! -> Bitmap Heap Scan on tenk1 b ! Recheck Cond: (thousand = int4_tbl.f1) ! -> Bitmap Index Scan on tenk1_thous_tenthous ! Index Cond: (thousand = int4_tbl.f1) ! -> Index Scan using tenk1_unique1 on tenk1 a ! Index Cond: (unique1 = b.unique2) ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 c ! Index Cond: (thousand = a.thousand) ! (14 rows) ! ! select count(*) from ! tenk1 a join tenk1 b on a.unique1 = b.unique2 ! left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand ! join int4_tbl on b.thousand = f1; ! count ! ------- ! 10 ! (1 row) ! ! explain (costs off) ! select b.unique1 from ! tenk1 a join tenk1 b on a.unique1 = b.unique2 ! left join tenk1 c on b.unique1 = 42 and c.thousand = a.thousand ! join int4_tbl i1 on b.thousand = f1 ! right join int4_tbl i2 on i2.f1 = b.tenthous ! order by 1; ! QUERY PLAN ! ----------------------------------------------------------------------------------------- ! Sort ! Sort Key: b.unique1 ! -> Nested Loop Left Join ! -> Seq Scan on int4_tbl i2 ! -> Nested Loop Left Join ! Join Filter: (b.unique1 = 42) ! -> Nested Loop ! -> Nested Loop ! -> Seq Scan on int4_tbl i1 ! -> Index Scan using tenk1_thous_tenthous on tenk1 b ! Index Cond: ((thousand = i1.f1) AND (i2.f1 = tenthous)) ! -> Index Scan using tenk1_unique1 on tenk1 a ! Index Cond: (unique1 = b.unique2) ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 c ! Index Cond: (thousand = a.thousand) ! (15 rows) ! ! select b.unique1 from ! tenk1 a join tenk1 b on a.unique1 = b.unique2 ! left join tenk1 c on b.unique1 = 42 and c.thousand = a.thousand ! join int4_tbl i1 on b.thousand = f1 ! right join int4_tbl i2 on i2.f1 = b.tenthous ! order by 1; ! unique1 ! --------- ! 0 ! ! ! ! ! (5 rows) ! ! explain (costs off) ! select * from ! ( ! select unique1, q1, coalesce(unique1, -1) + q1 as fault ! from int8_tbl left join tenk1 on (q2 = unique2) ! ) ss ! where fault = 122 ! order by fault; ! QUERY PLAN ! ----------------------------------------------------------------- ! Nested Loop Left Join ! Filter: ((COALESCE(tenk1.unique1, (-1)) + int8_tbl.q1) = 122) ! -> Seq Scan on int8_tbl ! -> Index Scan using tenk1_unique2 on tenk1 ! Index Cond: (int8_tbl.q2 = unique2) ! (5 rows) ! ! select * from ! ( ! select unique1, q1, coalesce(unique1, -1) + q1 as fault ! from int8_tbl left join tenk1 on (q2 = unique2) ! ) ss ! where fault = 122 ! order by fault; ! unique1 | q1 | fault ! ---------+-----+------- ! | 123 | 122 ! (1 row) ! ! -- ! -- test handling of potential equivalence clauses above outer joins ! -- ! explain (costs off) ! select q1, unique2, thousand, hundred ! from int8_tbl a left join tenk1 b on q1 = unique2 ! where coalesce(thousand,123) = q1 and q1 = coalesce(hundred,123); ! QUERY PLAN ! -------------------------------------------------------------------------------------- ! Nested Loop Left Join ! Filter: ((COALESCE(b.thousand, 123) = a.q1) AND (a.q1 = COALESCE(b.hundred, 123))) ! -> Seq Scan on int8_tbl a ! -> Index Scan using tenk1_unique2 on tenk1 b ! Index Cond: (a.q1 = unique2) ! (5 rows) ! ! select q1, unique2, thousand, hundred ! from int8_tbl a left join tenk1 b on q1 = unique2 ! where coalesce(thousand,123) = q1 and q1 = coalesce(hundred,123); ! q1 | unique2 | thousand | hundred ! ----+---------+----------+--------- ! (0 rows) ! ! explain (costs off) ! select f1, unique2, case when unique2 is null then f1 else 0 end ! from int4_tbl a left join tenk1 b on f1 = unique2 ! where (case when unique2 is null then f1 else 0 end) = 0; ! QUERY PLAN ! -------------------------------------------------------------------- ! Nested Loop Left Join ! Filter: (CASE WHEN (b.unique2 IS NULL) THEN a.f1 ELSE 0 END = 0) ! -> Seq Scan on int4_tbl a ! -> Index Only Scan using tenk1_unique2 on tenk1 b ! Index Cond: (unique2 = a.f1) ! (5 rows) ! ! select f1, unique2, case when unique2 is null then f1 else 0 end ! from int4_tbl a left join tenk1 b on f1 = unique2 ! where (case when unique2 is null then f1 else 0 end) = 0; ! f1 | unique2 | case ! ----+---------+------ ! 0 | 0 | 0 ! (1 row) ! ! -- ! -- another case with equivalence clauses above outer joins (bug #8591) ! -- ! explain (costs off) ! select a.unique1, b.unique1, c.unique1, coalesce(b.twothousand, a.twothousand) ! from tenk1 a left join tenk1 b on b.thousand = a.unique1 left join tenk1 c on c.unique2 = coalesce(b.twothousand, a.twothousand) ! where a.unique2 = 5530 and coalesce(b.twothousand, a.twothousand) = 44; ! QUERY PLAN ! --------------------------------------------------------------------------------------------- ! Nested Loop Left Join ! -> Nested Loop Left Join ! Filter: (COALESCE(b.twothousand, a.twothousand) = 44) ! -> Index Scan using tenk1_unique2 on tenk1 a ! Index Cond: (unique2 = 5530) ! -> Bitmap Heap Scan on tenk1 b ! Recheck Cond: (thousand = a.unique1) ! -> Bitmap Index Scan on tenk1_thous_tenthous ! Index Cond: (thousand = a.unique1) ! -> Index Scan using tenk1_unique2 on tenk1 c ! Index Cond: ((unique2 = COALESCE(b.twothousand, a.twothousand)) AND (unique2 = 44)) ! (11 rows) ! ! select a.unique1, b.unique1, c.unique1, coalesce(b.twothousand, a.twothousand) ! from tenk1 a left join tenk1 b on b.thousand = a.unique1 left join tenk1 c on c.unique2 = coalesce(b.twothousand, a.twothousand) ! where a.unique2 = 5530 and coalesce(b.twothousand, a.twothousand) = 44; ! unique1 | unique1 | unique1 | coalesce ! ---------+---------+---------+---------- ! (0 rows) ! ! -- ! -- check handling of join aliases when flattening multiple levels of subquery ! -- ! explain (verbose, costs off) ! select foo1.join_key as foo1_id, foo3.join_key AS foo3_id, bug_field from ! (values (0),(1)) foo1(join_key) ! left join ! (select join_key, bug_field from ! (select ss1.join_key, ss1.bug_field from ! (select f1 as join_key, 666 as bug_field from int4_tbl i1) ss1 ! ) foo2 ! left join ! (select unique2 as join_key from tenk1 i2) ss2 ! using (join_key) ! ) foo3 ! using (join_key); ! QUERY PLAN ! -------------------------------------------------------------------------- ! Nested Loop Left Join ! Output: "*VALUES*".column1, i1.f1, (666) ! Join Filter: ("*VALUES*".column1 = i1.f1) ! -> Values Scan on "*VALUES*" ! Output: "*VALUES*".column1 ! -> Materialize ! Output: i1.f1, (666) ! -> Nested Loop Left Join ! Output: i1.f1, 666 ! -> Seq Scan on public.int4_tbl i1 ! Output: i1.f1 ! -> Index Only Scan using tenk1_unique2 on public.tenk1 i2 ! Output: i2.unique2 ! Index Cond: (i2.unique2 = i1.f1) ! (14 rows) ! ! select foo1.join_key as foo1_id, foo3.join_key AS foo3_id, bug_field from ! (values (0),(1)) foo1(join_key) ! left join ! (select join_key, bug_field from ! (select ss1.join_key, ss1.bug_field from ! (select f1 as join_key, 666 as bug_field from int4_tbl i1) ss1 ! ) foo2 ! left join ! (select unique2 as join_key from tenk1 i2) ss2 ! using (join_key) ! ) foo3 ! using (join_key); ! foo1_id | foo3_id | bug_field ! ---------+---------+----------- ! 0 | 0 | 666 ! 1 | | ! (2 rows) ! ! -- ! -- test ability to push constants through outer join clauses ! -- ! explain (costs off) ! select * from int4_tbl a left join tenk1 b on f1 = unique2 where f1 = 0; ! QUERY PLAN ! ------------------------------------------------- ! Nested Loop Left Join ! Join Filter: (a.f1 = b.unique2) ! -> Seq Scan on int4_tbl a ! Filter: (f1 = 0) ! -> Index Scan using tenk1_unique2 on tenk1 b ! Index Cond: (unique2 = 0) ! (6 rows) ! ! explain (costs off) ! select * from tenk1 a full join tenk1 b using(unique2) where unique2 = 42; ! QUERY PLAN ! ------------------------------------------------- ! Merge Full Join ! Merge Cond: (a.unique2 = b.unique2) ! -> Index Scan using tenk1_unique2 on tenk1 a ! Index Cond: (unique2 = 42) ! -> Index Scan using tenk1_unique2 on tenk1 b ! Index Cond: (unique2 = 42) ! (6 rows) ! ! -- ! -- test join removal ! -- ! begin; ! CREATE TEMP TABLE a (id int PRIMARY KEY, b_id int); ! CREATE TEMP TABLE b (id int PRIMARY KEY, c_id int); ! CREATE TEMP TABLE c (id int PRIMARY KEY); ! CREATE TEMP TABLE d (a int, b int); ! INSERT INTO a VALUES (0, 0), (1, NULL); ! INSERT INTO b VALUES (0, 0), (1, NULL); ! INSERT INTO c VALUES (0), (1); ! INSERT INTO d VALUES (1,3), (2,2), (3,1); ! -- all three cases should be optimizable into a simple seqscan ! explain (costs off) SELECT a.* FROM a LEFT JOIN b ON a.b_id = b.id; ! QUERY PLAN ! --------------- ! Seq Scan on a ! (1 row) ! ! explain (costs off) SELECT b.* FROM b LEFT JOIN c ON b.c_id = c.id; ! QUERY PLAN ! --------------- ! Seq Scan on b ! (1 row) ! ! explain (costs off) ! SELECT a.* FROM a LEFT JOIN (b left join c on b.c_id = c.id) ! ON (a.b_id = b.id); ! QUERY PLAN ! --------------- ! Seq Scan on a ! (1 row) ! ! -- check optimization of outer join within another special join ! explain (costs off) ! select id from a where id in ( ! select b.id from b left join c on b.id = c.id ! ); ! QUERY PLAN ! ---------------------------- ! Hash Semi Join ! Hash Cond: (a.id = b.id) ! -> Seq Scan on a ! -> Hash ! -> Seq Scan on b ! (5 rows) ! ! -- check that join removal works for a left join when joining a subquery ! -- that is guaranteed to be unique by its GROUP BY clause ! explain (costs off) ! select d.* from d left join (select * from b group by b.id, b.c_id) s ! on d.a = s.id and d.b = s.c_id; ! QUERY PLAN ! --------------- ! Seq Scan on d ! (1 row) ! ! -- similarly, but keying off a DISTINCT clause ! explain (costs off) ! select d.* from d left join (select distinct * from b) s ! on d.a = s.id and d.b = s.c_id; ! QUERY PLAN ! --------------- ! Seq Scan on d ! (1 row) ! ! -- join removal is not possible when the GROUP BY contains a column that is ! -- not in the join condition ! explain (costs off) ! select d.* from d left join (select * from b group by b.id, b.c_id) s ! on d.a = s.id; ! QUERY PLAN ! --------------------------------------------- ! Merge Left Join ! Merge Cond: (d.a = s.id) ! -> Sort ! Sort Key: d.a ! -> Seq Scan on d ! -> Sort ! Sort Key: s.id ! -> Subquery Scan on s ! -> HashAggregate ! Group Key: b.id, b.c_id ! -> Seq Scan on b ! (11 rows) ! ! -- similarly, but keying off a DISTINCT clause ! explain (costs off) ! select d.* from d left join (select distinct * from b) s ! on d.a = s.id; ! QUERY PLAN ! --------------------------------------------- ! Merge Left Join ! Merge Cond: (d.a = s.id) ! -> Sort ! Sort Key: d.a ! -> Seq Scan on d ! -> Sort ! Sort Key: s.id ! -> Subquery Scan on s ! -> HashAggregate ! Group Key: b.id, b.c_id ! -> Seq Scan on b ! (11 rows) ! ! -- check join removal works when uniqueness of the join condition is enforced ! -- by a UNION ! explain (costs off) ! select d.* from d left join (select id from a union select id from b) s ! on d.a = s.id; ! QUERY PLAN ! --------------- ! Seq Scan on d ! (1 row) ! ! -- check join removal with a cross-type comparison operator ! explain (costs off) ! select i8.* from int8_tbl i8 left join (select f1 from int4_tbl group by f1) i4 ! on i8.q1 = i4.f1; ! QUERY PLAN ! ------------------------- ! Seq Scan on int8_tbl i8 ! (1 row) ! ! rollback; ! create temp table parent (k int primary key, pd int); ! create temp table child (k int unique, cd int); ! insert into parent values (1, 10), (2, 20), (3, 30); ! insert into child values (1, 100), (4, 400); ! -- this case is optimizable ! select p.* from parent p left join child c on (p.k = c.k); ! k | pd ! ---+---- ! 1 | 10 ! 2 | 20 ! 3 | 30 ! (3 rows) ! ! explain (costs off) ! select p.* from parent p left join child c on (p.k = c.k); ! QUERY PLAN ! ---------------------- ! Seq Scan on parent p ! (1 row) ! ! -- this case is not ! select p.*, linked from parent p ! left join (select c.*, true as linked from child c) as ss ! on (p.k = ss.k); ! k | pd | linked ! ---+----+-------- ! 1 | 10 | t ! 2 | 20 | ! 3 | 30 | ! (3 rows) ! ! explain (costs off) ! select p.*, linked from parent p ! left join (select c.*, true as linked from child c) as ss ! on (p.k = ss.k); ! QUERY PLAN ! --------------------------------- ! Hash Left Join ! Hash Cond: (p.k = c.k) ! -> Seq Scan on parent p ! -> Hash ! -> Seq Scan on child c ! (5 rows) ! ! -- check for a 9.0rc1 bug: join removal breaks pseudoconstant qual handling ! select p.* from ! parent p left join child c on (p.k = c.k) ! where p.k = 1 and p.k = 2; ! k | pd ! ---+---- ! (0 rows) ! ! explain (costs off) ! select p.* from ! parent p left join child c on (p.k = c.k) ! where p.k = 1 and p.k = 2; ! QUERY PLAN ! ------------------------------------------------ ! Result ! One-Time Filter: false ! -> Index Scan using parent_pkey on parent p ! Index Cond: (k = 1) ! (4 rows) ! ! select p.* from ! (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k ! where p.k = 1 and p.k = 2; ! k | pd ! ---+---- ! (0 rows) ! ! explain (costs off) ! select p.* from ! (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k ! where p.k = 1 and p.k = 2; ! QUERY PLAN ! -------------------------- ! Result ! One-Time Filter: false ! (2 rows) ! ! -- bug 5255: this is not optimizable by join removal ! begin; ! CREATE TEMP TABLE a (id int PRIMARY KEY); ! CREATE TEMP TABLE b (id int PRIMARY KEY, a_id int); ! INSERT INTO a VALUES (0), (1); ! INSERT INTO b VALUES (0, 0), (1, NULL); ! SELECT * FROM b LEFT JOIN a ON (b.a_id = a.id) WHERE (a.id IS NULL OR a.id > 0); ! id | a_id | id ! ----+------+---- ! 1 | | ! (1 row) ! ! SELECT b.* FROM b LEFT JOIN a ON (b.a_id = a.id) WHERE (a.id IS NULL OR a.id > 0); ! id | a_id ! ----+------ ! 1 | ! (1 row) ! ! rollback; ! -- another join removal bug: this is not optimizable, either ! begin; ! create temp table innertab (id int8 primary key, dat1 int8); ! insert into innertab values(123, 42); ! SELECT * FROM ! (SELECT 1 AS x) ss1 ! LEFT JOIN ! (SELECT q1, q2, COALESCE(dat1, q1) AS y ! FROM int8_tbl LEFT JOIN innertab ON q2 = id) ss2 ! ON true; ! x | q1 | q2 | y ! ---+------------------+-------------------+------------------ ! 1 | 123 | 456 | 123 ! 1 | 123 | 4567890123456789 | 123 ! 1 | 4567890123456789 | 123 | 42 ! 1 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 1 | 4567890123456789 | -4567890123456789 | 4567890123456789 ! (5 rows) ! ! rollback; ! -- bug #8444: we've historically allowed duplicate aliases within aliased JOINs ! select * from ! int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error ! ERROR: column reference "f1" is ambiguous ! LINE 2: ..._tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; ! ^ ! select * from ! int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1; -- error ! ERROR: invalid reference to FROM-clause entry for table "y" ! LINE 2: ...bl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1; ! ^ ! HINT: There is an entry for table "y", but it cannot be referenced from this part of the query. ! select * from ! int8_tbl x join (int4_tbl x cross join int4_tbl y(ff)) j on q1 = f1; -- ok ! q1 | q2 | f1 | ff ! ----+----+----+---- ! (0 rows) ! ! -- ! -- Test LATERAL ! -- ! select unique2, x.* ! from tenk1 a, lateral (select * from int4_tbl b where f1 = a.unique1) x; ! unique2 | f1 ! ---------+---- ! 9998 | 0 ! (1 row) ! ! explain (costs off) ! select unique2, x.* ! from tenk1 a, lateral (select * from int4_tbl b where f1 = a.unique1) x; ! QUERY PLAN ! ------------------------------------------------- ! Nested Loop ! -> Seq Scan on int4_tbl b ! -> Index Scan using tenk1_unique1 on tenk1 a ! Index Cond: (unique1 = b.f1) ! (4 rows) ! ! select unique2, x.* ! from int4_tbl x, lateral (select unique2 from tenk1 where f1 = unique1) ss; ! unique2 | f1 ! ---------+---- ! 9998 | 0 ! (1 row) ! ! explain (costs off) ! select unique2, x.* ! from int4_tbl x, lateral (select unique2 from tenk1 where f1 = unique1) ss; ! QUERY PLAN ! ----------------------------------------------- ! Nested Loop ! -> Seq Scan on int4_tbl x ! -> Index Scan using tenk1_unique1 on tenk1 ! Index Cond: (unique1 = x.f1) ! (4 rows) ! ! explain (costs off) ! select unique2, x.* ! from int4_tbl x cross join lateral (select unique2 from tenk1 where f1 = unique1) ss; ! QUERY PLAN ! ----------------------------------------------- ! Nested Loop ! -> Seq Scan on int4_tbl x ! -> Index Scan using tenk1_unique1 on tenk1 ! Index Cond: (unique1 = x.f1) ! (4 rows) ! ! select unique2, x.* ! from int4_tbl x left join lateral (select unique1, unique2 from tenk1 where f1 = unique1) ss on true; ! unique2 | f1 ! ---------+------------- ! 9998 | 0 ! | 123456 ! | -123456 ! | 2147483647 ! | -2147483647 ! (5 rows) ! ! explain (costs off) ! select unique2, x.* ! from int4_tbl x left join lateral (select unique1, unique2 from tenk1 where f1 = unique1) ss on true; ! QUERY PLAN ! ----------------------------------------------- ! Nested Loop Left Join ! -> Seq Scan on int4_tbl x ! -> Index Scan using tenk1_unique1 on tenk1 ! Index Cond: (x.f1 = unique1) ! (4 rows) ! ! -- check scoping of lateral versus parent references ! -- the first of these should return int8_tbl.q2, the second int8_tbl.q1 ! select *, (select r from (select q1 as q2) x, (select q2 as r) y) from int8_tbl; ! q1 | q2 | r ! ------------------+-------------------+------------------- ! 123 | 456 | 456 ! 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | -4567890123456789 ! (5 rows) ! ! select *, (select r from (select q1 as q2) x, lateral (select q2 as r) y) from int8_tbl; ! q1 | q2 | r ! ------------------+-------------------+------------------ ! 123 | 456 | 123 ! 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 ! (5 rows) ! ! -- lateral with function in FROM ! select count(*) from tenk1 a, lateral generate_series(1,two) g; ! count ! ------- ! 5000 ! (1 row) ! ! explain (costs off) ! select count(*) from tenk1 a, lateral generate_series(1,two) g; ! QUERY PLAN ! ------------------------------------------------ ! Aggregate ! -> Nested Loop ! -> Seq Scan on tenk1 a ! -> Function Scan on generate_series g ! (4 rows) ! ! explain (costs off) ! select count(*) from tenk1 a cross join lateral generate_series(1,two) g; ! QUERY PLAN ! ------------------------------------------------ ! Aggregate ! -> Nested Loop ! -> Seq Scan on tenk1 a ! -> Function Scan on generate_series g ! (4 rows) ! ! -- don't need the explicit LATERAL keyword for functions ! explain (costs off) ! select count(*) from tenk1 a, generate_series(1,two) g; ! QUERY PLAN ! ------------------------------------------------ ! Aggregate ! -> Nested Loop ! -> Seq Scan on tenk1 a ! -> Function Scan on generate_series g ! (4 rows) ! ! -- lateral with UNION ALL subselect ! explain (costs off) ! select * from generate_series(100,200) g, ! lateral (select * from int8_tbl a where g = q1 union all ! select * from int8_tbl b where g = q2) ss; ! QUERY PLAN ! ------------------------------------------ ! Nested Loop ! -> Function Scan on generate_series g ! -> Append ! -> Seq Scan on int8_tbl a ! Filter: (g.g = q1) ! -> Seq Scan on int8_tbl b ! Filter: (g.g = q2) ! (7 rows) ! ! select * from generate_series(100,200) g, ! lateral (select * from int8_tbl a where g = q1 union all ! select * from int8_tbl b where g = q2) ss; ! g | q1 | q2 ! -----+------------------+------------------ ! 123 | 123 | 456 ! 123 | 123 | 4567890123456789 ! 123 | 4567890123456789 | 123 ! (3 rows) ! ! -- lateral with VALUES ! explain (costs off) ! select count(*) from tenk1 a, ! tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x; ! QUERY PLAN ! ------------------------------------------------------------------ ! Aggregate ! -> Hash Join ! Hash Cond: ("*VALUES*".column1 = b.unique2) ! -> Nested Loop ! -> Index Only Scan using tenk1_unique1 on tenk1 a ! -> Values Scan on "*VALUES*" ! -> Hash ! -> Index Only Scan using tenk1_unique2 on tenk1 b ! (8 rows) ! ! select count(*) from tenk1 a, ! tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x; ! count ! ------- ! 10000 ! (1 row) ! ! -- lateral injecting a strange outer join condition ! explain (costs off) ! select * from int8_tbl a, ! int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z) ! on x.q2 = ss.z; ! QUERY PLAN ! ------------------------------------------ ! Nested Loop ! -> Seq Scan on int8_tbl a ! -> Hash Left Join ! Hash Cond: (x.q2 = (a.q1)) ! -> Seq Scan on int8_tbl x ! -> Hash ! -> Seq Scan on int4_tbl y ! (7 rows) ! ! select * from int8_tbl a, ! int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z) ! on x.q2 = ss.z; ! q1 | q2 | q1 | q2 | z ! ------------------+-------------------+------------------+-------------------+------------------ ! 123 | 456 | 123 | 456 | ! 123 | 456 | 123 | 4567890123456789 | ! 123 | 456 | 4567890123456789 | 123 | 123 ! 123 | 456 | 4567890123456789 | 123 | 123 ! 123 | 456 | 4567890123456789 | 123 | 123 ! 123 | 456 | 4567890123456789 | 123 | 123 ! 123 | 456 | 4567890123456789 | 123 | 123 ! 123 | 456 | 4567890123456789 | 4567890123456789 | ! 123 | 456 | 4567890123456789 | -4567890123456789 | ! 123 | 4567890123456789 | 123 | 456 | ! 123 | 4567890123456789 | 123 | 4567890123456789 | ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | ! 123 | 4567890123456789 | 4567890123456789 | -4567890123456789 | ! 4567890123456789 | 123 | 123 | 456 | ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | 123 | ! 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 4567890123456789 | -4567890123456789 | ! 4567890123456789 | 4567890123456789 | 123 | 456 | ! 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 | ! 4567890123456789 | -4567890123456789 | 123 | 456 | ! 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 123 | ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 | ! (57 rows) ! ! -- lateral reference to a join alias variable ! select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1, ! lateral (select x) ss2(y); ! x | f1 | y ! ---+----+--- ! 0 | 0 | 0 ! (1 row) ! ! select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1, ! lateral (values(x)) ss2(y); ! x | f1 | y ! -------------+-------------+------------- ! 0 | 0 | 0 ! 123456 | 123456 | 123456 ! -123456 | -123456 | -123456 ! 2147483647 | 2147483647 | 2147483647 ! -2147483647 | -2147483647 | -2147483647 ! (5 rows) ! ! select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j, ! lateral (select x) ss2(y); ! x | f1 | y ! ---+----+--- ! 0 | 0 | 0 ! (1 row) ! ! -- lateral references requiring pullup ! select * from (values(1)) x(lb), ! lateral generate_series(lb,4) x4; ! lb | x4 ! ----+---- ! 1 | 1 ! 1 | 2 ! 1 | 3 ! 1 | 4 ! (4 rows) ! ! select * from (select f1/1000000000 from int4_tbl) x(lb), ! lateral generate_series(lb,4) x4; ! lb | x4 ! ----+---- ! 0 | 0 ! 0 | 1 ! 0 | 2 ! 0 | 3 ! 0 | 4 ! 0 | 0 ! 0 | 1 ! 0 | 2 ! 0 | 3 ! 0 | 4 ! 0 | 0 ! 0 | 1 ! 0 | 2 ! 0 | 3 ! 0 | 4 ! 2 | 2 ! 2 | 3 ! 2 | 4 ! -2 | -2 ! -2 | -1 ! -2 | 0 ! -2 | 1 ! -2 | 2 ! -2 | 3 ! -2 | 4 ! (25 rows) ! ! select * from (values(1)) x(lb), ! lateral (values(lb)) y(lbcopy); ! lb | lbcopy ! ----+-------- ! 1 | 1 ! (1 row) ! ! select * from (values(1)) x(lb), ! lateral (select lb from int4_tbl) y(lbcopy); ! lb | lbcopy ! ----+-------- ! 1 | 1 ! 1 | 1 ! 1 | 1 ! 1 | 1 ! 1 | 1 ! (5 rows) ! ! select * from ! int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1, ! lateral (values(x.q1,y.q1,y.q2)) v(xq1,yq1,yq2); ! q1 | q2 | q1 | q2 | xq1 | yq1 | yq2 ! ------------------+-------------------+------------------+-------------------+------------------+------------------+------------------- ! 123 | 456 | | | 123 | | ! 123 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | -4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 456 | 4567890123456789 | 123 | 456 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 123 ! 4567890123456789 | -4567890123456789 | | | 4567890123456789 | | ! (10 rows) ! ! select * from ! int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1, ! lateral (select x.q1,y.q1,y.q2) v(xq1,yq1,yq2); ! q1 | q2 | q1 | q2 | xq1 | yq1 | yq2 ! ------------------+-------------------+------------------+-------------------+------------------+------------------+------------------- ! 123 | 456 | | | 123 | | ! 123 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 123 | 4567890123456789 | -4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 456 | 4567890123456789 | 123 | 456 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 | 4567890123456789 | 123 ! 4567890123456789 | -4567890123456789 | | | 4567890123456789 | | ! (10 rows) ! ! select x.* from ! int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1, ! lateral (select x.q1,y.q1,y.q2) v(xq1,yq1,yq2); ! q1 | q2 ! ------------------+------------------- ! 123 | 456 ! 123 | 4567890123456789 ! 123 | 4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! (10 rows) ! ! select v.* from ! (int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1) ! left join int4_tbl z on z.f1 = x.q2, ! lateral (select x.q1,y.q1 union all select x.q2,y.q2) v(vx,vy); ! vx | vy ! -------------------+------------------- ! 123 | ! 456 | ! 123 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 123 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 123 | 456 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | ! -4567890123456789 | ! (20 rows) ! ! select v.* from ! (int8_tbl x left join (select q1,(select coalesce(q2,0)) q2 from int8_tbl) y on x.q2 = y.q1) ! left join int4_tbl z on z.f1 = x.q2, ! lateral (select x.q1,y.q1 union all select x.q2,y.q2) v(vx,vy); ! vx | vy ! -------------------+------------------- ! 123 | ! 456 | ! 123 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 123 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 123 | 456 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | ! -4567890123456789 | ! (20 rows) ! ! create temp table dual(); ! insert into dual default values; ! analyze dual; ! select v.* from ! (int8_tbl x left join (select q1,(select coalesce(q2,0)) q2 from int8_tbl) y on x.q2 = y.q1) ! left join int4_tbl z on z.f1 = x.q2, ! lateral (select x.q1,y.q1 from dual union all select x.q2,y.q2 from dual) v(vx,vy); ! vx | vy ! -------------------+------------------- ! 123 | ! 456 | ! 123 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | 123 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! 123 | 456 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 ! 4567890123456789 | ! -4567890123456789 | ! (20 rows) ! ! explain (verbose, costs off) ! select * from ! int8_tbl a left join ! lateral (select *, a.q2 as x from int8_tbl b) ss on a.q2 = ss.q1; ! QUERY PLAN ! ------------------------------------------ ! Nested Loop Left Join ! Output: a.q1, a.q2, b.q1, b.q2, (a.q2) ! -> Seq Scan on public.int8_tbl a ! Output: a.q1, a.q2 ! -> Seq Scan on public.int8_tbl b ! Output: b.q1, b.q2, a.q2 ! Filter: (a.q2 = b.q1) ! (7 rows) ! ! select * from ! int8_tbl a left join ! lateral (select *, a.q2 as x from int8_tbl b) ss on a.q2 = ss.q1; ! q1 | q2 | q1 | q2 | x ! ------------------+-------------------+------------------+-------------------+------------------ ! 123 | 456 | | | ! 123 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 456 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | | | ! (10 rows) ! ! explain (verbose, costs off) ! select * from ! int8_tbl a left join ! lateral (select *, coalesce(a.q2, 42) as x from int8_tbl b) ss on a.q2 = ss.q1; ! QUERY PLAN ! ---------------------------------------------------------------- ! Nested Loop Left Join ! Output: a.q1, a.q2, b.q1, b.q2, (COALESCE(a.q2, 42::bigint)) ! -> Seq Scan on public.int8_tbl a ! Output: a.q1, a.q2 ! -> Seq Scan on public.int8_tbl b ! Output: b.q1, b.q2, COALESCE(a.q2, 42::bigint) ! Filter: (a.q2 = b.q1) ! (7 rows) ! ! select * from ! int8_tbl a left join ! lateral (select *, coalesce(a.q2, 42) as x from int8_tbl b) ss on a.q2 = ss.q1; ! q1 | q2 | q1 | q2 | x ! ------------------+-------------------+------------------+-------------------+------------------ ! 123 | 456 | | | ! 123 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 123 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 ! 4567890123456789 | 123 | 123 | 456 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | | | ! (10 rows) ! ! -- lateral can result in join conditions appearing below their ! -- real semantic level ! explain (verbose, costs off) ! select * from int4_tbl i left join ! lateral (select * from int2_tbl j where i.f1 = j.f1) k on true; ! QUERY PLAN ! ------------------------------------------- ! Hash Left Join ! Output: i.f1, j.f1 ! Hash Cond: (i.f1 = j.f1) ! -> Seq Scan on public.int4_tbl i ! Output: i.f1 ! -> Hash ! Output: j.f1 ! -> Seq Scan on public.int2_tbl j ! Output: j.f1 ! (9 rows) ! ! select * from int4_tbl i left join ! lateral (select * from int2_tbl j where i.f1 = j.f1) k on true; ! f1 | f1 ! -------------+---- ! 0 | 0 ! 123456 | ! -123456 | ! 2147483647 | ! -2147483647 | ! (5 rows) ! ! explain (verbose, costs off) ! select * from int4_tbl i left join ! lateral (select coalesce(i) from int2_tbl j where i.f1 = j.f1) k on true; ! QUERY PLAN ! ------------------------------------- ! Nested Loop Left Join ! Output: i.f1, (COALESCE(i.*)) ! -> Seq Scan on public.int4_tbl i ! Output: i.f1, i.* ! -> Seq Scan on public.int2_tbl j ! Output: j.f1, COALESCE(i.*) ! Filter: (i.f1 = j.f1) ! (7 rows) ! ! select * from int4_tbl i left join ! lateral (select coalesce(i) from int2_tbl j where i.f1 = j.f1) k on true; ! f1 | coalesce ! -------------+---------- ! 0 | (0) ! 123456 | ! -123456 | ! 2147483647 | ! -2147483647 | ! (5 rows) ! ! explain (verbose, costs off) ! select * from int4_tbl a, ! lateral ( ! select * from int4_tbl b left join int8_tbl c on (b.f1 = q1 and a.f1 = q2) ! ) ss; ! QUERY PLAN ! ------------------------------------------------- ! Nested Loop ! Output: a.f1, b.f1, c.q1, c.q2 ! -> Seq Scan on public.int4_tbl a ! Output: a.f1 ! -> Hash Left Join ! Output: b.f1, c.q1, c.q2 ! Hash Cond: (b.f1 = c.q1) ! -> Seq Scan on public.int4_tbl b ! Output: b.f1 ! -> Hash ! Output: c.q1, c.q2 ! -> Seq Scan on public.int8_tbl c ! Output: c.q1, c.q2 ! Filter: (a.f1 = c.q2) ! (14 rows) ! ! select * from int4_tbl a, ! lateral ( ! select * from int4_tbl b left join int8_tbl c on (b.f1 = q1 and a.f1 = q2) ! ) ss; ! f1 | f1 | q1 | q2 ! -------------+-------------+----+---- ! 0 | 0 | | ! 0 | 123456 | | ! 0 | -123456 | | ! 0 | 2147483647 | | ! 0 | -2147483647 | | ! 123456 | 0 | | ! 123456 | 123456 | | ! 123456 | -123456 | | ! 123456 | 2147483647 | | ! 123456 | -2147483647 | | ! -123456 | 0 | | ! -123456 | 123456 | | ! -123456 | -123456 | | ! -123456 | 2147483647 | | ! -123456 | -2147483647 | | ! 2147483647 | 0 | | ! 2147483647 | 123456 | | ! 2147483647 | -123456 | | ! 2147483647 | 2147483647 | | ! 2147483647 | -2147483647 | | ! -2147483647 | 0 | | ! -2147483647 | 123456 | | ! -2147483647 | -123456 | | ! -2147483647 | 2147483647 | | ! -2147483647 | -2147483647 | | ! (25 rows) ! ! -- lateral reference in a PlaceHolderVar evaluated at join level ! explain (verbose, costs off) ! select * from ! int8_tbl a left join lateral ! (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from ! int8_tbl b cross join int8_tbl c) ss ! on a.q2 = ss.bq1; ! QUERY PLAN ! ------------------------------------------------------------- ! Nested Loop Left Join ! Output: a.q1, a.q2, b.q1, c.q1, (LEAST(a.q1, b.q1, c.q1)) ! -> Seq Scan on public.int8_tbl a ! Output: a.q1, a.q2 ! -> Nested Loop ! Output: b.q1, c.q1, LEAST(a.q1, b.q1, c.q1) ! Join Filter: (a.q2 = b.q1) ! -> Seq Scan on public.int8_tbl b ! Output: b.q1, b.q2 ! -> Materialize ! Output: c.q1 ! -> Seq Scan on public.int8_tbl c ! Output: c.q1 ! (13 rows) ! ! select * from ! int8_tbl a left join lateral ! (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from ! int8_tbl b cross join int8_tbl c) ss ! on a.q2 = ss.bq1; ! q1 | q2 | bq1 | cq1 | least ! ------------------+-------------------+------------------+------------------+------------------ ! 123 | 456 | | | ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 123 | 123 ! 4567890123456789 | 123 | 123 | 123 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 123 | 123 ! 4567890123456789 | 123 | 123 | 123 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 123 | 123 | 4567890123456789 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 123 | 123 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 ! 4567890123456789 | -4567890123456789 | | | ! (42 rows) ! ! -- case requiring nested PlaceHolderVars ! explain (verbose, costs off) ! select * from ! int8_tbl c left join ( ! int8_tbl a left join (select q1, coalesce(q2,42) as x from int8_tbl b) ss1 ! on a.q2 = ss1.q1 ! cross join ! lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2 ! ) on c.q2 = ss2.q1, ! lateral (select ss2.y) ss3; ! QUERY PLAN ! ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ! Nested Loop ! Output: c.q1, c.q2, a.q1, a.q2, b.q1, (COALESCE(b.q2, 42::bigint)), d.q1, (COALESCE((COALESCE(b.q2, 42::bigint)), d.q2)), ((COALESCE((COALESCE(b.q2, 42::bigint)), d.q2))) ! -> Hash Right Join ! Output: c.q1, c.q2, a.q1, a.q2, b.q1, d.q1, (COALESCE(b.q2, 42::bigint)), (COALESCE((COALESCE(b.q2, 42::bigint)), d.q2)) ! Hash Cond: (d.q1 = c.q2) ! -> Nested Loop ! Output: a.q1, a.q2, b.q1, d.q1, (COALESCE(b.q2, 42::bigint)), (COALESCE((COALESCE(b.q2, 42::bigint)), d.q2)) ! -> Hash Left Join ! Output: a.q1, a.q2, b.q1, (COALESCE(b.q2, 42::bigint)) ! Hash Cond: (a.q2 = b.q1) ! -> Seq Scan on public.int8_tbl a ! Output: a.q1, a.q2 ! -> Hash ! Output: b.q1, (COALESCE(b.q2, 42::bigint)) ! -> Seq Scan on public.int8_tbl b ! Output: b.q1, COALESCE(b.q2, 42::bigint) ! -> Seq Scan on public.int8_tbl d ! Output: d.q1, COALESCE((COALESCE(b.q2, 42::bigint)), d.q2) ! -> Hash ! Output: c.q1, c.q2 ! -> Seq Scan on public.int8_tbl c ! Output: c.q1, c.q2 ! -> Result ! Output: (COALESCE((COALESCE(b.q2, 42::bigint)), d.q2)) ! (24 rows) ! ! -- case that breaks the old ph_may_need optimization ! explain (verbose, costs off) ! select c.*,a.*,ss1.q1,ss2.q1,ss3.* from ! int8_tbl c left join ( ! int8_tbl a left join ! (select q1, coalesce(q2,f1) as x from int8_tbl b, int4_tbl b2 ! where q1 < f1) ss1 ! on a.q2 = ss1.q1 ! cross join ! lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2 ! ) on c.q2 = ss2.q1, ! lateral (select * from int4_tbl i where ss2.y > f1) ss3; ! QUERY PLAN ! --------------------------------------------------------------------------------------------------------- ! Nested Loop ! Output: c.q1, c.q2, a.q1, a.q2, b.q1, d.q1, i.f1 ! Join Filter: ((COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2)) > i.f1) ! -> Hash Right Join ! Output: c.q1, c.q2, a.q1, a.q2, b.q1, d.q1, (COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2)) ! Hash Cond: (d.q1 = c.q2) ! -> Nested Loop ! Output: a.q1, a.q2, b.q1, d.q1, (COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2)) ! -> Hash Right Join ! Output: a.q1, a.q2, b.q1, (COALESCE(b.q2, (b2.f1)::bigint)) ! Hash Cond: (b.q1 = a.q2) ! -> Nested Loop ! Output: b.q1, COALESCE(b.q2, (b2.f1)::bigint) ! Join Filter: (b.q1 < b2.f1) ! -> Seq Scan on public.int8_tbl b ! Output: b.q1, b.q2 ! -> Materialize ! Output: b2.f1 ! -> Seq Scan on public.int4_tbl b2 ! Output: b2.f1 ! -> Hash ! Output: a.q1, a.q2 ! -> Seq Scan on public.int8_tbl a ! Output: a.q1, a.q2 ! -> Seq Scan on public.int8_tbl d ! Output: d.q1, COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2) ! -> Hash ! Output: c.q1, c.q2 ! -> Seq Scan on public.int8_tbl c ! Output: c.q1, c.q2 ! -> Materialize ! Output: i.f1 ! -> Seq Scan on public.int4_tbl i ! Output: i.f1 ! (34 rows) ! ! -- check processing of postponed quals (bug #9041) ! explain (verbose, costs off) ! select * from ! (select 1 as x) x cross join (select 2 as y) y ! left join lateral ( ! select * from (select 3 as z) z where z.z = x.x ! ) zz on zz.z = y.y; ! QUERY PLAN ! ---------------------------------------------- ! Nested Loop Left Join ! Output: (1), (2), (3) ! Join Filter: (((3) = (1)) AND ((3) = (2))) ! -> Nested Loop ! Output: (1), (2) ! -> Result ! Output: 1 ! -> Result ! Output: 2 ! -> Result ! Output: 3 ! (11 rows) ! ! -- test some error cases where LATERAL should have been used but wasn't ! select f1,g from int4_tbl a, (select f1 as g) ss; ! ERROR: column "f1" does not exist ! LINE 1: select f1,g from int4_tbl a, (select f1 as g) ss; ! ^ ! HINT: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query. ! select f1,g from int4_tbl a, (select a.f1 as g) ss; ! ERROR: invalid reference to FROM-clause entry for table "a" ! LINE 1: select f1,g from int4_tbl a, (select a.f1 as g) ss; ! ^ ! HINT: There is an entry for table "a", but it cannot be referenced from this part of the query. ! select f1,g from int4_tbl a cross join (select f1 as g) ss; ! ERROR: column "f1" does not exist ! LINE 1: select f1,g from int4_tbl a cross join (select f1 as g) ss; ! ^ ! HINT: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query. ! select f1,g from int4_tbl a cross join (select a.f1 as g) ss; ! ERROR: invalid reference to FROM-clause entry for table "a" ! LINE 1: select f1,g from int4_tbl a cross join (select a.f1 as g) ss... ! ^ ! HINT: There is an entry for table "a", but it cannot be referenced from this part of the query. ! -- SQL:2008 says the left table is in scope but illegal to access here ! select f1,g from int4_tbl a right join lateral generate_series(0, a.f1) g on true; ! ERROR: invalid reference to FROM-clause entry for table "a" ! LINE 1: ... int4_tbl a right join lateral generate_series(0, a.f1) g on... ! ^ ! DETAIL: The combining JOIN type must be INNER or LEFT for a LATERAL reference. ! select f1,g from int4_tbl a full join lateral generate_series(0, a.f1) g on true; ! ERROR: invalid reference to FROM-clause entry for table "a" ! LINE 1: ...m int4_tbl a full join lateral generate_series(0, a.f1) g on... ! ^ ! DETAIL: The combining JOIN type must be INNER or LEFT for a LATERAL reference. ! -- check we complain about ambiguous table references ! select * from ! int8_tbl x cross join (int4_tbl x cross join lateral (select x.f1) ss); ! ERROR: table reference "x" is ambiguous ! LINE 2: ...cross join (int4_tbl x cross join lateral (select x.f1) ss); ! ^ ! -- LATERAL can be used to put an aggregate into the FROM clause of its query ! select 1 from tenk1 a, lateral (select max(a.unique1) from int4_tbl b) ss; ! ERROR: aggregate functions are not allowed in FROM clause of their own query level ! LINE 1: select 1 from tenk1 a, lateral (select max(a.unique1) from i... ! ^ ! -- check behavior of LATERAL in UPDATE/DELETE ! create temp table xx1 as select f1 as x1, -f1 as x2 from int4_tbl; ! -- error, can't do this: ! update xx1 set x2 = f1 from (select * from int4_tbl where f1 = x1) ss; ! ERROR: column "x1" does not exist ! LINE 1: ... set x2 = f1 from (select * from int4_tbl where f1 = x1) ss; ! ^ ! HINT: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query. ! update xx1 set x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss; ! ERROR: invalid reference to FROM-clause entry for table "xx1" ! LINE 1: ...t x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss... ! ^ ! HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query. ! -- can't do it even with LATERAL: ! update xx1 set x2 = f1 from lateral (select * from int4_tbl where f1 = x1) ss; ! ERROR: invalid reference to FROM-clause entry for table "xx1" ! LINE 1: ...= f1 from lateral (select * from int4_tbl where f1 = x1) ss; ! ^ ! HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query. ! -- we might in future allow something like this, but for now it's an error: ! update xx1 set x2 = f1 from xx1, lateral (select * from int4_tbl where f1 = x1) ss; ! ERROR: table name "xx1" specified more than once ! -- also errors: ! delete from xx1 using (select * from int4_tbl where f1 = x1) ss; ! ERROR: column "x1" does not exist ! LINE 1: ...te from xx1 using (select * from int4_tbl where f1 = x1) ss; ! ^ ! HINT: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query. ! delete from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss; ! ERROR: invalid reference to FROM-clause entry for table "xx1" ! LINE 1: ...from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss... ! ^ ! HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query. ! delete from xx1 using lateral (select * from int4_tbl where f1 = x1) ss; ! ERROR: invalid reference to FROM-clause entry for table "xx1" ! LINE 1: ...xx1 using lateral (select * from int4_tbl where f1 = x1) ss; ! ^ ! HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query. --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/aggregates.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/aggregates.out Tue Oct 28 15:53:05 2014 *************** *** 1,1582 **** ! -- ! -- AGGREGATES ! -- ! SELECT avg(four) AS avg_1 FROM onek; ! avg_1 ! -------------------- ! 1.5000000000000000 ! (1 row) ! ! SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; ! avg_32 ! --------------------- ! 32.6666666666666667 ! (1 row) ! ! -- In 7.1, avg(float4) is computed using float8 arithmetic. ! -- Round the result to 3 digits to avoid platform-specific results. ! SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest; ! avg_107_943 ! ------------- ! 107.943 ! (1 row) ! ! SELECT avg(gpa) AS avg_3_4 FROM ONLY student; ! avg_3_4 ! --------- ! 3.4 ! (1 row) ! ! SELECT sum(four) AS sum_1500 FROM onek; ! sum_1500 ! ---------- ! 1500 ! (1 row) ! ! SELECT sum(a) AS sum_198 FROM aggtest; ! sum_198 ! --------- ! 198 ! (1 row) ! ! SELECT sum(b) AS avg_431_773 FROM aggtest; ! avg_431_773 ! ------------- ! 431.773 ! (1 row) ! ! SELECT sum(gpa) AS avg_6_8 FROM ONLY student; ! avg_6_8 ! --------- ! 6.8 ! (1 row) ! ! SELECT max(four) AS max_3 FROM onek; ! max_3 ! ------- ! 3 ! (1 row) ! ! SELECT max(a) AS max_100 FROM aggtest; ! max_100 ! --------- ! 100 ! (1 row) ! ! SELECT max(aggtest.b) AS max_324_78 FROM aggtest; ! max_324_78 ! ------------ ! 324.78 ! (1 row) ! ! SELECT max(student.gpa) AS max_3_7 FROM student; ! max_3_7 ! --------- ! 3.7 ! (1 row) ! ! SELECT stddev_pop(b) FROM aggtest; ! stddev_pop ! ----------------- ! 131.10703231895 ! (1 row) ! ! SELECT stddev_samp(b) FROM aggtest; ! stddev_samp ! ------------------ ! 151.389360803998 ! (1 row) ! ! SELECT var_pop(b) FROM aggtest; ! var_pop ! ------------------ ! 17189.0539234823 ! (1 row) ! ! SELECT var_samp(b) FROM aggtest; ! var_samp ! ------------------ ! 22918.7385646431 ! (1 row) ! ! SELECT stddev_pop(b::numeric) FROM aggtest; ! stddev_pop ! ------------------ ! 131.107032862199 ! (1 row) ! ! SELECT stddev_samp(b::numeric) FROM aggtest; ! stddev_samp ! ------------------ ! 151.389361431288 ! (1 row) ! ! SELECT var_pop(b::numeric) FROM aggtest; ! var_pop ! -------------------- ! 17189.054065929769 ! (1 row) ! ! SELECT var_samp(b::numeric) FROM aggtest; ! var_samp ! -------------------- ! 22918.738754573025 ! (1 row) ! ! -- population variance is defined for a single tuple, sample variance ! -- is not ! SELECT var_pop(1.0), var_samp(2.0); ! var_pop | var_samp ! ---------+---------- ! 0 | ! (1 row) ! ! SELECT stddev_pop(3.0::numeric), stddev_samp(4.0::numeric); ! stddev_pop | stddev_samp ! ------------+------------- ! 0 | ! (1 row) ! ! -- verify correct results for null and NaN inputs ! select sum(null::int4) from generate_series(1,3); ! sum ! ----- ! ! (1 row) ! ! select sum(null::int8) from generate_series(1,3); ! sum ! ----- ! ! (1 row) ! ! select sum(null::numeric) from generate_series(1,3); ! sum ! ----- ! ! (1 row) ! ! select sum(null::float8) from generate_series(1,3); ! sum ! ----- ! ! (1 row) ! ! select avg(null::int4) from generate_series(1,3); ! avg ! ----- ! ! (1 row) ! ! select avg(null::int8) from generate_series(1,3); ! avg ! ----- ! ! (1 row) ! ! select avg(null::numeric) from generate_series(1,3); ! avg ! ----- ! ! (1 row) ! ! select avg(null::float8) from generate_series(1,3); ! avg ! ----- ! ! (1 row) ! ! select sum('NaN'::numeric) from generate_series(1,3); ! sum ! ----- ! NaN ! (1 row) ! ! select avg('NaN'::numeric) from generate_series(1,3); ! avg ! ----- ! NaN ! (1 row) ! ! -- SQL2003 binary aggregates ! SELECT regr_count(b, a) FROM aggtest; ! regr_count ! ------------ ! 4 ! (1 row) ! ! SELECT regr_sxx(b, a) FROM aggtest; ! regr_sxx ! ---------- ! 5099 ! (1 row) ! ! SELECT regr_syy(b, a) FROM aggtest; ! regr_syy ! ------------------ ! 68756.2156939293 ! (1 row) ! ! SELECT regr_sxy(b, a) FROM aggtest; ! regr_sxy ! ------------------ ! 2614.51582155004 ! (1 row) ! ! SELECT regr_avgx(b, a), regr_avgy(b, a) FROM aggtest; ! regr_avgx | regr_avgy ! -----------+------------------ ! 49.5 | 107.943152273074 ! (1 row) ! ! SELECT regr_r2(b, a) FROM aggtest; ! regr_r2 ! -------------------- ! 0.0194977982031803 ! (1 row) ! ! SELECT regr_slope(b, a), regr_intercept(b, a) FROM aggtest; ! regr_slope | regr_intercept ! -------------------+------------------ ! 0.512750700441271 | 82.5619926012309 ! (1 row) ! ! SELECT covar_pop(b, a), covar_samp(b, a) FROM aggtest; ! covar_pop | covar_samp ! -----------------+------------------ ! 653.62895538751 | 871.505273850014 ! (1 row) ! ! SELECT corr(b, a) FROM aggtest; ! corr ! ------------------- ! 0.139634516517873 ! (1 row) ! ! SELECT count(four) AS cnt_1000 FROM onek; ! cnt_1000 ! ---------- ! 1000 ! (1 row) ! ! SELECT count(DISTINCT four) AS cnt_4 FROM onek; ! cnt_4 ! ------- ! 4 ! (1 row) ! ! select ten, count(*), sum(four) from onek ! group by ten order by ten; ! ten | count | sum ! -----+-------+----- ! 0 | 100 | 100 ! 1 | 100 | 200 ! 2 | 100 | 100 ! 3 | 100 | 200 ! 4 | 100 | 100 ! 5 | 100 | 200 ! 6 | 100 | 100 ! 7 | 100 | 200 ! 8 | 100 | 100 ! 9 | 100 | 200 ! (10 rows) ! ! select ten, count(four), sum(DISTINCT four) from onek ! group by ten order by ten; ! ten | count | sum ! -----+-------+----- ! 0 | 100 | 2 ! 1 | 100 | 4 ! 2 | 100 | 2 ! 3 | 100 | 4 ! 4 | 100 | 2 ! 5 | 100 | 4 ! 6 | 100 | 2 ! 7 | 100 | 4 ! 8 | 100 | 2 ! 9 | 100 | 4 ! (10 rows) ! ! -- user-defined aggregates ! SELECT newavg(four) AS avg_1 FROM onek; ! avg_1 ! -------------------- ! 1.5000000000000000 ! (1 row) ! ! SELECT newsum(four) AS sum_1500 FROM onek; ! sum_1500 ! ---------- ! 1500 ! (1 row) ! ! SELECT newcnt(four) AS cnt_1000 FROM onek; ! cnt_1000 ! ---------- ! 1000 ! (1 row) ! ! SELECT newcnt(*) AS cnt_1000 FROM onek; ! cnt_1000 ! ---------- ! 1000 ! (1 row) ! ! SELECT oldcnt(*) AS cnt_1000 FROM onek; ! cnt_1000 ! ---------- ! 1000 ! (1 row) ! ! SELECT sum2(q1,q2) FROM int8_tbl; ! sum2 ! ------------------- ! 18271560493827981 ! (1 row) ! ! -- test for outer-level aggregates ! -- this should work ! select ten, sum(distinct four) from onek a ! group by ten ! having exists (select 1 from onek b where sum(distinct a.four) = b.four); ! ten | sum ! -----+----- ! 0 | 2 ! 2 | 2 ! 4 | 2 ! 6 | 2 ! 8 | 2 ! (5 rows) ! ! -- this should fail because subquery has an agg of its own in WHERE ! select ten, sum(distinct four) from onek a ! group by ten ! having exists (select 1 from onek b ! where sum(distinct a.four + b.four) = b.four); ! ERROR: aggregate functions are not allowed in WHERE ! LINE 4: where sum(distinct a.four + b.four) = b.four)... ! ^ ! -- Test handling of sublinks within outer-level aggregates. ! -- Per bug report from Daniel Grace. ! select ! (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1))) ! from tenk1 o; ! max ! ------ ! 9999 ! (1 row) ! ! -- ! -- test for bitwise integer aggregates ! -- ! CREATE TEMPORARY TABLE bitwise_test( ! i2 INT2, ! i4 INT4, ! i8 INT8, ! i INTEGER, ! x INT2, ! y BIT(4) ! ); ! -- empty case ! SELECT ! BIT_AND(i2) AS "?", ! BIT_OR(i4) AS "?" ! FROM bitwise_test; ! ? | ? ! ---+--- ! | ! (1 row) ! ! COPY bitwise_test FROM STDIN NULL 'null'; ! SELECT ! BIT_AND(i2) AS "1", ! BIT_AND(i4) AS "1", ! BIT_AND(i8) AS "1", ! BIT_AND(i) AS "?", ! BIT_AND(x) AS "0", ! BIT_AND(y) AS "0100", ! BIT_OR(i2) AS "7", ! BIT_OR(i4) AS "7", ! BIT_OR(i8) AS "7", ! BIT_OR(i) AS "?", ! BIT_OR(x) AS "7", ! BIT_OR(y) AS "1101" ! FROM bitwise_test; ! 1 | 1 | 1 | ? | 0 | 0100 | 7 | 7 | 7 | ? | 7 | 1101 ! ---+---+---+---+---+------+---+---+---+---+---+------ ! 1 | 1 | 1 | 1 | 0 | 0100 | 7 | 7 | 7 | 3 | 7 | 1101 ! (1 row) ! ! -- ! -- test boolean aggregates ! -- ! -- first test all possible transition and final states ! SELECT ! -- boolean and transitions ! -- null because strict ! booland_statefunc(NULL, NULL) IS NULL AS "t", ! booland_statefunc(TRUE, NULL) IS NULL AS "t", ! booland_statefunc(FALSE, NULL) IS NULL AS "t", ! booland_statefunc(NULL, TRUE) IS NULL AS "t", ! booland_statefunc(NULL, FALSE) IS NULL AS "t", ! -- and actual computations ! booland_statefunc(TRUE, TRUE) AS "t", ! NOT booland_statefunc(TRUE, FALSE) AS "t", ! NOT booland_statefunc(FALSE, TRUE) AS "t", ! NOT booland_statefunc(FALSE, FALSE) AS "t"; ! t | t | t | t | t | t | t | t | t ! ---+---+---+---+---+---+---+---+--- ! t | t | t | t | t | t | t | t | t ! (1 row) ! ! SELECT ! -- boolean or transitions ! -- null because strict ! boolor_statefunc(NULL, NULL) IS NULL AS "t", ! boolor_statefunc(TRUE, NULL) IS NULL AS "t", ! boolor_statefunc(FALSE, NULL) IS NULL AS "t", ! boolor_statefunc(NULL, TRUE) IS NULL AS "t", ! boolor_statefunc(NULL, FALSE) IS NULL AS "t", ! -- actual computations ! boolor_statefunc(TRUE, TRUE) AS "t", ! boolor_statefunc(TRUE, FALSE) AS "t", ! boolor_statefunc(FALSE, TRUE) AS "t", ! NOT boolor_statefunc(FALSE, FALSE) AS "t"; ! t | t | t | t | t | t | t | t | t ! ---+---+---+---+---+---+---+---+--- ! t | t | t | t | t | t | t | t | t ! (1 row) ! ! CREATE TEMPORARY TABLE bool_test( ! b1 BOOL, ! b2 BOOL, ! b3 BOOL, ! b4 BOOL); ! -- empty case ! SELECT ! BOOL_AND(b1) AS "n", ! BOOL_OR(b3) AS "n" ! FROM bool_test; ! n | n ! ---+--- ! | ! (1 row) ! ! COPY bool_test FROM STDIN NULL 'null'; ! SELECT ! BOOL_AND(b1) AS "f", ! BOOL_AND(b2) AS "t", ! BOOL_AND(b3) AS "f", ! BOOL_AND(b4) AS "n", ! BOOL_AND(NOT b2) AS "f", ! BOOL_AND(NOT b3) AS "t" ! FROM bool_test; ! f | t | f | n | f | t ! ---+---+---+---+---+--- ! f | t | f | | f | t ! (1 row) ! ! SELECT ! EVERY(b1) AS "f", ! EVERY(b2) AS "t", ! EVERY(b3) AS "f", ! EVERY(b4) AS "n", ! EVERY(NOT b2) AS "f", ! EVERY(NOT b3) AS "t" ! FROM bool_test; ! f | t | f | n | f | t ! ---+---+---+---+---+--- ! f | t | f | | f | t ! (1 row) ! ! SELECT ! BOOL_OR(b1) AS "t", ! BOOL_OR(b2) AS "t", ! BOOL_OR(b3) AS "f", ! BOOL_OR(b4) AS "n", ! BOOL_OR(NOT b2) AS "f", ! BOOL_OR(NOT b3) AS "t" ! FROM bool_test; ! t | t | f | n | f | t ! ---+---+---+---+---+--- ! t | t | f | | f | t ! (1 row) ! ! -- ! -- Test cases that should be optimized into indexscans instead of ! -- the generic aggregate implementation. ! -- ! -- Basic cases ! explain (costs off) ! select min(unique1) from tenk1; ! QUERY PLAN ! ------------------------------------------------------------ ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan using tenk1_unique1 on tenk1 ! Index Cond: (unique1 IS NOT NULL) ! (5 rows) ! ! select min(unique1) from tenk1; ! min ! ----- ! 0 ! (1 row) ! ! explain (costs off) ! select max(unique1) from tenk1; ! QUERY PLAN ! --------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique1 on tenk1 ! Index Cond: (unique1 IS NOT NULL) ! (5 rows) ! ! select max(unique1) from tenk1; ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique1) from tenk1 where unique1 < 42; ! QUERY PLAN ! ------------------------------------------------------------------------ ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique1 on tenk1 ! Index Cond: ((unique1 IS NOT NULL) AND (unique1 < 42)) ! (5 rows) ! ! select max(unique1) from tenk1 where unique1 < 42; ! max ! ----- ! 41 ! (1 row) ! ! explain (costs off) ! select max(unique1) from tenk1 where unique1 > 42; ! QUERY PLAN ! ------------------------------------------------------------------------ ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique1 on tenk1 ! Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42)) ! (5 rows) ! ! select max(unique1) from tenk1 where unique1 > 42; ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique1) from tenk1 where unique1 > 42000; ! QUERY PLAN ! --------------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique1 on tenk1 ! Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42000)) ! (5 rows) ! ! select max(unique1) from tenk1 where unique1 > 42000; ! max ! ----- ! ! (1 row) ! ! -- multi-column index (uses tenk1_thous_tenthous) ! explain (costs off) ! select max(tenthous) from tenk1 where thousand = 33; ! QUERY PLAN ! ---------------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_thous_tenthous on tenk1 ! Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL)) ! (5 rows) ! ! select max(tenthous) from tenk1 where thousand = 33; ! max ! ------ ! 9033 ! (1 row) ! ! explain (costs off) ! select min(tenthous) from tenk1 where thousand = 33; ! QUERY PLAN ! -------------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan using tenk1_thous_tenthous on tenk1 ! Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL)) ! (5 rows) ! ! select min(tenthous) from tenk1 where thousand = 33; ! min ! ----- ! 33 ! (1 row) ! ! -- check parameter propagation into an indexscan subquery ! explain (costs off) ! select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt ! from int4_tbl; ! QUERY PLAN ! ----------------------------------------------------------------------------------------- ! Seq Scan on int4_tbl ! SubPlan 2 ! -> Result ! InitPlan 1 (returns $1) ! -> Limit ! -> Index Only Scan using tenk1_unique1 on tenk1 ! Index Cond: ((unique1 IS NOT NULL) AND (unique1 > int4_tbl.f1)) ! (7 rows) ! ! select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt ! from int4_tbl; ! f1 | gt ! -------------+---- ! 0 | 1 ! 123456 | ! -123456 | 0 ! 2147483647 | ! -2147483647 | 0 ! (5 rows) ! ! -- check some cases that were handled incorrectly in 8.3.0 ! explain (costs off) ! select distinct max(unique2) from tenk1; ! QUERY PLAN ! --------------------------------------------------------------------- ! HashAggregate ! Group Key: $0 ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique2 on tenk1 ! Index Cond: (unique2 IS NOT NULL) ! -> Result ! (7 rows) ! ! select distinct max(unique2) from tenk1; ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique2) from tenk1 order by 1; ! QUERY PLAN ! --------------------------------------------------------------------- ! Sort ! Sort Key: ($0) ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique2 on tenk1 ! Index Cond: (unique2 IS NOT NULL) ! -> Result ! (7 rows) ! ! select max(unique2) from tenk1 order by 1; ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique2) from tenk1 order by max(unique2); ! QUERY PLAN ! --------------------------------------------------------------------- ! Sort ! Sort Key: ($0) ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique2 on tenk1 ! Index Cond: (unique2 IS NOT NULL) ! -> Result ! (7 rows) ! ! select max(unique2) from tenk1 order by max(unique2); ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique2) from tenk1 order by max(unique2)+1; ! QUERY PLAN ! --------------------------------------------------------------------- ! Sort ! Sort Key: (($0 + 1)) ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique2 on tenk1 ! Index Cond: (unique2 IS NOT NULL) ! -> Result ! (7 rows) ! ! select max(unique2) from tenk1 order by max(unique2)+1; ! max ! ------ ! 9999 ! (1 row) ! ! explain (costs off) ! select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; ! QUERY PLAN ! --------------------------------------------------------------------- ! Sort ! Sort Key: (generate_series(1, 3)) ! InitPlan 1 (returns $0) ! -> Limit ! -> Index Only Scan Backward using tenk1_unique2 on tenk1 ! Index Cond: (unique2 IS NOT NULL) ! -> Result ! (7 rows) ! ! select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; ! max | g ! ------+--- ! 9999 | 3 ! 9999 | 2 ! 9999 | 1 ! (3 rows) ! ! -- try it on an inheritance tree ! create table minmaxtest(f1 int); ! create table minmaxtest1() inherits (minmaxtest); ! create table minmaxtest2() inherits (minmaxtest); ! create table minmaxtest3() inherits (minmaxtest); ! create index minmaxtesti on minmaxtest(f1); ! create index minmaxtest1i on minmaxtest1(f1); ! create index minmaxtest2i on minmaxtest2(f1 desc); ! create index minmaxtest3i on minmaxtest3(f1) where f1 is not null; ! insert into minmaxtest values(11), (12); ! insert into minmaxtest1 values(13), (14); ! insert into minmaxtest2 values(15), (16); ! insert into minmaxtest3 values(17), (18); ! explain (costs off) ! select min(f1), max(f1) from minmaxtest; ! QUERY PLAN ! ---------------------------------------------------------------------------------------------- ! Result ! InitPlan 1 (returns $0) ! -> Limit ! -> Merge Append ! Sort Key: minmaxtest.f1 ! -> Index Only Scan using minmaxtesti on minmaxtest ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest1i on minmaxtest1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest2i on minmaxtest2 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest3i on minmaxtest3 ! Index Cond: (f1 IS NOT NULL) ! InitPlan 2 (returns $1) ! -> Limit ! -> Merge Append ! Sort Key: minmaxtest_1.f1 ! -> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest1_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1 ! Index Cond: (f1 IS NOT NULL) ! (25 rows) ! ! select min(f1), max(f1) from minmaxtest; ! min | max ! -----+----- ! 11 | 18 ! (1 row) ! ! -- DISTINCT doesn't do anything useful here, but it shouldn't fail ! explain (costs off) ! select distinct min(f1), max(f1) from minmaxtest; ! QUERY PLAN ! ---------------------------------------------------------------------------------------------- ! HashAggregate ! Group Key: $0, $1 ! InitPlan 1 (returns $0) ! -> Limit ! -> Merge Append ! Sort Key: minmaxtest.f1 ! -> Index Only Scan using minmaxtesti on minmaxtest ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest1i on minmaxtest1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest2i on minmaxtest2 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest3i on minmaxtest3 ! Index Cond: (f1 IS NOT NULL) ! InitPlan 2 (returns $1) ! -> Limit ! -> Merge Append ! Sort Key: minmaxtest_1.f1 ! -> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest1_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1 ! Index Cond: (f1 IS NOT NULL) ! -> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1 ! Index Cond: (f1 IS NOT NULL) ! -> Result ! (27 rows) ! ! select distinct min(f1), max(f1) from minmaxtest; ! min | max ! -----+----- ! 11 | 18 ! (1 row) ! ! drop table minmaxtest cascade; ! NOTICE: drop cascades to 3 other objects ! DETAIL: drop cascades to table minmaxtest1 ! drop cascades to table minmaxtest2 ! drop cascades to table minmaxtest3 ! -- check for correct detection of nested-aggregate errors ! select max(min(unique1)) from tenk1; ! ERROR: aggregate function calls cannot be nested ! LINE 1: select max(min(unique1)) from tenk1; ! ^ ! select (select max(min(unique1)) from int8_tbl) from tenk1; ! ERROR: aggregate function calls cannot be nested ! LINE 1: select (select max(min(unique1)) from int8_tbl) from tenk1; ! ^ ! -- ! -- Test combinations of DISTINCT and/or ORDER BY ! -- ! select array_agg(a order by b) ! from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); ! array_agg ! ----------- ! {3,4,2,1} ! (1 row) ! ! select array_agg(a order by a) ! from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); ! array_agg ! ----------- ! {1,2,3,4} ! (1 row) ! ! select array_agg(a order by a desc) ! from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); ! array_agg ! ----------- ! {4,3,2,1} ! (1 row) ! ! select array_agg(b order by a desc) ! from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); ! array_agg ! ----------- ! {2,1,3,4} ! (1 row) ! ! select array_agg(distinct a) ! from (values (1),(2),(1),(3),(null),(2)) v(a); ! array_agg ! -------------- ! {1,2,3,NULL} ! (1 row) ! ! select array_agg(distinct a order by a) ! from (values (1),(2),(1),(3),(null),(2)) v(a); ! array_agg ! -------------- ! {1,2,3,NULL} ! (1 row) ! ! select array_agg(distinct a order by a desc) ! from (values (1),(2),(1),(3),(null),(2)) v(a); ! array_agg ! -------------- ! {NULL,3,2,1} ! (1 row) ! ! select array_agg(distinct a order by a desc nulls last) ! from (values (1),(2),(1),(3),(null),(2)) v(a); ! array_agg ! -------------- ! {3,2,1,NULL} ! (1 row) ! ! -- multi-arg aggs, strict/nonstrict, distinct/order by ! select aggfstr(a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! aggfstr ! --------------------------------------- ! {"(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select aggfns(a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! aggfns ! ----------------------------------------------- ! {"(1,3,foo)","(0,,)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select aggfstr(distinct a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! aggfstr ! --------------------------------------- ! {"(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select aggfns(distinct a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! aggfns ! ----------------------------------------------- ! {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select aggfstr(distinct a,b,c order by b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! aggfstr ! --------------------------------------- ! {"(3,1,baz)","(2,2,bar)","(1,3,foo)"} ! (1 row) ! ! select aggfns(distinct a,b,c order by b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! aggfns ! ----------------------------------------------- ! {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} ! (1 row) ! ! -- test specific code paths ! select aggfns(distinct a,a,c order by c using ~<~,a) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! aggfns ! ------------------------------------------------ ! {"(2,2,bar)","(3,3,baz)","(1,1,foo)","(0,0,)"} ! (1 row) ! ! select aggfns(distinct a,a,c order by c using ~<~) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! aggfns ! ------------------------------------------------ ! {"(2,2,bar)","(3,3,baz)","(1,1,foo)","(0,0,)"} ! (1 row) ! ! select aggfns(distinct a,a,c order by a) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! aggfns ! ------------------------------------------------ ! {"(0,0,)","(1,1,foo)","(2,2,bar)","(3,3,baz)"} ! (1 row) ! ! select aggfns(distinct a,b,c order by a,c using ~<~,b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! aggfns ! ----------------------------------------------- ! {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! -- check node I/O via view creation and usage, also deparsing logic ! create view agg_view1 as ! select aggfns(a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(1,3,foo)","(0,,)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(v.a, v.b, v.c) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(distinct a,b,c) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(DISTINCT v.a, v.b, v.c) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c),+ ! generate_series(1, 3) i(i); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(distinct a,b,c order by b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,3) i; ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(DISTINCT v.a, v.b, v.c ORDER BY v.b) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c),+ ! generate_series(1, 3) i(i); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(a,b,c order by b+1) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(v.a, v.b, v.c ORDER BY (v.b + 1)) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(a,a,c order by b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! select * from agg_view1; ! aggfns ! ------------------------------------------------ ! {"(3,3,baz)","(2,2,bar)","(1,1,foo)","(0,0,)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(v.a, v.a, v.c ORDER BY v.b) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(a,b,c order by c using ~<~) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(2,2,bar)","(3,1,baz)","(1,3,foo)","(0,,)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(v.a, v.b, v.c ORDER BY v.c USING ~<~ NULLS LAST) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); ! (1 row) ! ! create or replace view agg_view1 as ! select aggfns(distinct a,b,c order by a,c using ~<~,b) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! select * from agg_view1; ! aggfns ! ----------------------------------------------- ! {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! select pg_get_viewdef('agg_view1'::regclass); ! pg_get_viewdef ! --------------------------------------------------------------------------------------------------------------------- ! SELECT aggfns(DISTINCT v.a, v.b, v.c ORDER BY v.a, v.c USING ~<~ NULLS LAST, v.b) AS aggfns + ! FROM ( VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c),+ ! generate_series(1, 2) i(i); ! (1 row) ! ! drop view agg_view1; ! -- incorrect DISTINCT usage errors ! select aggfns(distinct a,b,c order by i) ! from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select aggfns(distinct a,b,c order by i) ! ^ ! select aggfns(distinct a,b,c order by a,b+1) ! from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select aggfns(distinct a,b,c order by a,b+1) ! ^ ! select aggfns(distinct a,b,c order by a,b,i,c) ! from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select aggfns(distinct a,b,c order by a,b,i,c) ! ^ ! select aggfns(distinct a,a,c order by a,b) ! from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select aggfns(distinct a,a,c order by a,b) ! ^ ! -- string_agg tests ! select string_agg(a,',') from (values('aaaa'),('bbbb'),('cccc')) g(a); ! string_agg ! ---------------- ! aaaa,bbbb,cccc ! (1 row) ! ! select string_agg(a,',') from (values('aaaa'),(null),('bbbb'),('cccc')) g(a); ! string_agg ! ---------------- ! aaaa,bbbb,cccc ! (1 row) ! ! select string_agg(a,'AB') from (values(null),(null),('bbbb'),('cccc')) g(a); ! string_agg ! ------------ ! bbbbABcccc ! (1 row) ! ! select string_agg(a,',') from (values(null),(null)) g(a); ! string_agg ! ------------ ! ! (1 row) ! ! -- check some implicit casting cases, as per bug #5564 ! select string_agg(distinct f1, ',' order by f1) from varchar_tbl; -- ok ! string_agg ! ------------ ! a,ab,abcd ! (1 row) ! ! select string_agg(distinct f1::text, ',' order by f1) from varchar_tbl; -- not ok ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select string_agg(distinct f1::text, ',' order by f1) from v... ! ^ ! select string_agg(distinct f1, ',' order by f1::text) from varchar_tbl; -- not ok ! ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list ! LINE 1: select string_agg(distinct f1, ',' order by f1::text) from v... ! ^ ! select string_agg(distinct f1::text, ',' order by f1::text) from varchar_tbl; -- ok ! string_agg ! ------------ ! a,ab,abcd ! (1 row) ! ! -- string_agg bytea tests ! create table bytea_test_table(v bytea); ! select string_agg(v, '') from bytea_test_table; ! string_agg ! ------------ ! ! (1 row) ! ! insert into bytea_test_table values(decode('ff','hex')); ! select string_agg(v, '') from bytea_test_table; ! string_agg ! ------------ ! \xff ! (1 row) ! ! insert into bytea_test_table values(decode('aa','hex')); ! select string_agg(v, '') from bytea_test_table; ! string_agg ! ------------ ! \xffaa ! (1 row) ! ! select string_agg(v, NULL) from bytea_test_table; ! string_agg ! ------------ ! \xffaa ! (1 row) ! ! select string_agg(v, decode('ee', 'hex')) from bytea_test_table; ! string_agg ! ------------ ! \xffeeaa ! (1 row) ! ! drop table bytea_test_table; ! -- FILTER tests ! select min(unique1) filter (where unique1 > 100) from tenk1; ! min ! ----- ! 101 ! (1 row) ! ! select ten, sum(distinct four) filter (where four::text ~ '123') from onek a ! group by ten; ! ten | sum ! -----+----- ! 0 | ! 1 | ! 2 | ! 3 | ! 4 | ! 5 | ! 6 | ! 7 | ! 8 | ! 9 | ! (10 rows) ! ! select ten, sum(distinct four) filter (where four > 10) from onek a ! group by ten ! having exists (select 1 from onek b where sum(distinct a.four) = b.four); ! ten | sum ! -----+----- ! 0 | ! 2 | ! 4 | ! 6 | ! 8 | ! (5 rows) ! ! select max(foo COLLATE "C") filter (where (bar collate "POSIX") > '0') ! from (values ('a', 'b')) AS v(foo,bar); ! max ! ----- ! a ! (1 row) ! ! -- outer reference in FILTER (PostgreSQL extension) ! select (select count(*) ! from (values (1)) t0(inner_c)) ! from (values (2),(3)) t1(outer_c); -- inner query is aggregation query ! count ! ------- ! 1 ! 1 ! (2 rows) ! ! select (select count(*) filter (where outer_c <> 0) ! from (values (1)) t0(inner_c)) ! from (values (2),(3)) t1(outer_c); -- outer query is aggregation query ! count ! ------- ! 2 ! (1 row) ! ! select (select count(inner_c) filter (where outer_c <> 0) ! from (values (1)) t0(inner_c)) ! from (values (2),(3)) t1(outer_c); -- inner query is aggregation query ! count ! ------- ! 1 ! 1 ! (2 rows) ! ! select ! (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1)) ! filter (where o.unique1 < 10)) ! from tenk1 o; -- outer query is aggregation query ! max ! ------ ! 9998 ! (1 row) ! ! -- subquery in FILTER clause (PostgreSQL extension) ! select sum(unique1) FILTER (WHERE ! unique1 IN (SELECT unique1 FROM onek where unique1 < 100)) FROM tenk1; ! sum ! ------ ! 4950 ! (1 row) ! ! -- exercise lots of aggregate parts with FILTER ! select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) ! from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), ! generate_series(1,2) i; ! aggfns ! --------------------------- ! {"(2,2,bar)","(3,1,baz)"} ! (1 row) ! ! -- ordered-set aggregates ! select p, percentile_cont(p) within group (order by x::float8) ! from generate_series(1,5) x, ! (values (0::float8),(0.1),(0.25),(0.4),(0.5),(0.6),(0.75),(0.9),(1)) v(p) ! group by p order by p; ! p | percentile_cont ! ------+----------------- ! 0 | 1 ! 0.1 | 1.4 ! 0.25 | 2 ! 0.4 | 2.6 ! 0.5 | 3 ! 0.6 | 3.4 ! 0.75 | 4 ! 0.9 | 4.6 ! 1 | 5 ! (9 rows) ! ! select p, percentile_cont(p order by p) within group (order by x) -- error ! from generate_series(1,5) x, ! (values (0::float8),(0.1),(0.25),(0.4),(0.5),(0.6),(0.75),(0.9),(1)) v(p) ! group by p order by p; ! ERROR: cannot use multiple ORDER BY clauses with WITHIN GROUP ! LINE 1: select p, percentile_cont(p order by p) within group (order ... ! ^ ! select p, sum() within group (order by x::float8) -- error ! from generate_series(1,5) x, ! (values (0::float8),(0.1),(0.25),(0.4),(0.5),(0.6),(0.75),(0.9),(1)) v(p) ! group by p order by p; ! ERROR: sum is not an ordered-set aggregate, so it cannot have WITHIN GROUP ! LINE 1: select p, sum() within group (order by x::float8) ! ^ ! select p, percentile_cont(p,p) -- error ! from generate_series(1,5) x, ! (values (0::float8),(0.1),(0.25),(0.4),(0.5),(0.6),(0.75),(0.9),(1)) v(p) ! group by p order by p; ! ERROR: WITHIN GROUP is required for ordered-set aggregate percentile_cont ! LINE 1: select p, percentile_cont(p,p) ! ^ ! select percentile_cont(0.5) within group (order by b) from aggtest; ! percentile_cont ! ------------------ ! 53.4485001564026 ! (1 row) ! ! select percentile_cont(0.5) within group (order by b), sum(b) from aggtest; ! percentile_cont | sum ! ------------------+--------- ! 53.4485001564026 | 431.773 ! (1 row) ! ! select percentile_cont(0.5) within group (order by thousand) from tenk1; ! percentile_cont ! ----------------- ! 499.5 ! (1 row) ! ! select percentile_disc(0.5) within group (order by thousand) from tenk1; ! percentile_disc ! ----------------- ! 499 ! (1 row) ! ! select rank(3) within group (order by x) ! from (values (1),(1),(2),(2),(3),(3),(4)) v(x); ! rank ! ------ ! 5 ! (1 row) ! ! select cume_dist(3) within group (order by x) ! from (values (1),(1),(2),(2),(3),(3),(4)) v(x); ! cume_dist ! ----------- ! 0.875 ! (1 row) ! ! select percent_rank(3) within group (order by x) ! from (values (1),(1),(2),(2),(3),(3),(4),(5)) v(x); ! percent_rank ! -------------- ! 0.5 ! (1 row) ! ! select dense_rank(3) within group (order by x) ! from (values (1),(1),(2),(2),(3),(3),(4)) v(x); ! dense_rank ! ------------ ! 3 ! (1 row) ! ! select percentile_disc(array[0,0.1,0.25,0.5,0.75,0.9,1]) within group (order by thousand) ! from tenk1; ! percentile_disc ! ---------------------------- ! {0,99,249,499,749,899,999} ! (1 row) ! ! select percentile_cont(array[0,0.25,0.5,0.75,1]) within group (order by thousand) ! from tenk1; ! percentile_cont ! ----------------------------- ! {0,249.75,499.5,749.25,999} ! (1 row) ! ! select percentile_disc(array[[null,1,0.5],[0.75,0.25,null]]) within group (order by thousand) ! from tenk1; ! percentile_disc ! --------------------------------- ! {{NULL,999,499},{749,249,NULL}} ! (1 row) ! ! select percentile_cont(array[0,1,0.25,0.75,0.5,1]) within group (order by x) ! from generate_series(1,6) x; ! percentile_cont ! ----------------------- ! {1,6,2.25,4.75,3.5,6} ! (1 row) ! ! select ten, mode() within group (order by string4) from tenk1 group by ten; ! ten | mode ! -----+-------- ! 0 | HHHHxx ! 1 | OOOOxx ! 2 | VVVVxx ! 3 | OOOOxx ! 4 | HHHHxx ! 5 | HHHHxx ! 6 | OOOOxx ! 7 | AAAAxx ! 8 | VVVVxx ! 9 | VVVVxx ! (10 rows) ! ! select percentile_disc(array[0.25,0.5,0.75]) within group (order by x) ! from unnest('{fred,jim,fred,jack,jill,fred,jill,jim,jim,sheila,jim,sheila}'::text[]) u(x); ! percentile_disc ! ----------------- ! {fred,jill,jim} ! (1 row) ! ! -- check collation propagates up in suitable cases: ! select pg_collation_for(percentile_disc(1) within group (order by x collate "POSIX")) ! from (values ('fred'),('jim')) v(x); ! pg_collation_for ! ------------------ ! "POSIX" ! (1 row) ! ! -- ordered-set aggs created with CREATE AGGREGATE ! select test_rank(3) within group (order by x) ! from (values (1),(1),(2),(2),(3),(3),(4)) v(x); ! test_rank ! ----------- ! 5 ! (1 row) ! ! select test_percentile_disc(0.5) within group (order by thousand) from tenk1; ! test_percentile_disc ! ---------------------- ! 499 ! (1 row) ! ! -- ordered-set aggs can't use ungrouped vars in direct args: ! select rank(x) within group (order by x) from generate_series(1,5) x; ! ERROR: column "x.x" must appear in the GROUP BY clause or be used in an aggregate function ! LINE 1: select rank(x) within group (order by x) from generate_serie... ! ^ ! DETAIL: Direct arguments of an ordered-set aggregate must use only grouped columns. ! -- outer-level agg can't use a grouped arg of a lower level, either: ! select array(select percentile_disc(a) within group (order by x) ! from (values (0.3),(0.7)) v(a) group by a) ! from generate_series(1,5) g(x); ! ERROR: outer-level aggregate cannot contain a lower-level variable in its direct arguments ! LINE 1: select array(select percentile_disc(a) within group (order b... ! ^ ! -- agg in the direct args is a grouping violation, too: ! select rank(sum(x)) within group (order by x) from generate_series(1,5) x; ! ERROR: aggregate function calls cannot be nested ! LINE 1: select rank(sum(x)) within group (order by x) from generate_... ! ^ ! -- hypothetical-set type unification and argument-count failures: ! select rank(3) within group (order by x) from (values ('fred'),('jim')) v(x); ! ERROR: WITHIN GROUP types text and integer cannot be matched ! LINE 1: select rank(3) within group (order by x) from (values ('fred... ! ^ ! select rank(3) within group (order by stringu1,stringu2) from tenk1; ! ERROR: function rank(integer, name, name) does not exist ! LINE 1: select rank(3) within group (order by stringu1,stringu2) fro... ! ^ ! HINT: To use the hypothetical-set aggregate rank, the number of hypothetical direct arguments (here 1) must match the number of ordering columns (here 2). ! select rank('fred') within group (order by x) from generate_series(1,5) x; ! ERROR: invalid input syntax for integer: "fred" ! LINE 1: select rank('fred') within group (order by x) from generate_... ! ^ ! select rank('adam'::text collate "C") within group (order by x collate "POSIX") ! from (values ('fred'),('jim')) v(x); ! ERROR: collation mismatch between explicit collations "C" and "POSIX" ! LINE 1: ...adam'::text collate "C") within group (order by x collate "P... ! ^ ! -- hypothetical-set type unification successes: ! select rank('adam'::varchar) within group (order by x) from (values ('fred'),('jim')) v(x); ! rank ! ------ ! 1 ! (1 row) ! ! select rank('3') within group (order by x) from generate_series(1,5) x; ! rank ! ------ ! 3 ! (1 row) ! ! -- divide by zero check ! select percent_rank(0) within group (order by x) from generate_series(1,0) x; ! percent_rank ! -------------- ! 0 ! (1 row) ! ! -- deparse and multiple features: ! create view aggordview1 as ! select ten, ! percentile_disc(0.5) within group (order by thousand) as p50, ! percentile_disc(0.5) within group (order by thousand) filter (where hundred=1) as px, ! rank(5,'AZZZZ',50) within group (order by hundred, string4 desc, hundred) ! from tenk1 ! group by ten order by ten; ! select pg_get_viewdef('aggordview1'); ! pg_get_viewdef ! ------------------------------------------------------------------------------------------------------------------------------- ! SELECT tenk1.ten, + ! percentile_disc((0.5)::double precision) WITHIN GROUP (ORDER BY tenk1.thousand) AS p50, + ! percentile_disc((0.5)::double precision) WITHIN GROUP (ORDER BY tenk1.thousand) FILTER (WHERE (tenk1.hundred = 1)) AS px,+ ! rank(5, 'AZZZZ'::name, 50) WITHIN GROUP (ORDER BY tenk1.hundred, tenk1.string4 DESC, tenk1.hundred) AS rank + ! FROM tenk1 + ! GROUP BY tenk1.ten + ! ORDER BY tenk1.ten; ! (1 row) ! ! select * from aggordview1 order by ten; ! ten | p50 | px | rank ! -----+-----+-----+------ ! 0 | 490 | | 101 ! 1 | 491 | 401 | 101 ! 2 | 492 | | 101 ! 3 | 493 | | 101 ! 4 | 494 | | 101 ! 5 | 495 | | 67 ! 6 | 496 | | 1 ! 7 | 497 | | 1 ! 8 | 498 | | 1 ! 9 | 499 | | 1 ! (10 rows) ! ! drop view aggordview1; ! -- variadic aggregates ! select least_agg(q1,q2) from int8_tbl; ! least_agg ! ------------------- ! -4567890123456789 ! (1 row) ! ! select least_agg(variadic array[q1,q2]) from int8_tbl; ! least_agg ! ------------------- ! -4567890123456789 ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/transactions.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/transactions.out Tue Oct 28 15:53:05 2014 *************** *** 1,623 **** ! -- ! -- TRANSACTIONS ! -- ! BEGIN; ! SELECT * ! INTO TABLE xacttest ! FROM aggtest; ! INSERT INTO xacttest (a, b) VALUES (777, 777.777); ! END; ! -- should retrieve one value-- ! SELECT a FROM xacttest WHERE a > 100; ! a ! ----- ! 777 ! (1 row) ! ! BEGIN; ! CREATE TABLE disappear (a int4); ! DELETE FROM aggtest; ! -- should be empty ! SELECT * FROM aggtest; ! a | b ! ---+--- ! (0 rows) ! ! ABORT; ! -- should not exist ! SELECT oid FROM pg_class WHERE relname = 'disappear'; ! oid ! ----- ! (0 rows) ! ! -- should have members again ! SELECT * FROM aggtest; ! a | b ! -----+--------- ! 56 | 7.8 ! 100 | 99.097 ! 0 | 0.09561 ! 42 | 324.78 ! (4 rows) ! ! -- Read-only tests ! CREATE TABLE writetest (a int); ! CREATE TEMPORARY TABLE temptest (a int); ! BEGIN; ! SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! SET TRANSACTION READ WRITE; --fail ! ERROR: transaction read-write mode must be set before any query ! COMMIT; ! BEGIN; ! SET TRANSACTION READ ONLY; -- ok ! SET TRANSACTION READ WRITE; -- ok ! SET TRANSACTION READ ONLY; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! SAVEPOINT x; ! SET TRANSACTION READ ONLY; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! SET TRANSACTION READ ONLY; -- ok ! SET TRANSACTION READ WRITE; --fail ! ERROR: cannot set transaction read-write mode inside a read-only transaction ! COMMIT; ! BEGIN; ! SET TRANSACTION READ WRITE; -- ok ! SAVEPOINT x; ! SET TRANSACTION READ WRITE; -- ok ! SET TRANSACTION READ ONLY; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! SET TRANSACTION READ ONLY; -- ok ! SET TRANSACTION READ WRITE; --fail ! ERROR: cannot set transaction read-write mode inside a read-only transaction ! COMMIT; ! BEGIN; ! SET TRANSACTION READ WRITE; -- ok ! SAVEPOINT x; ! SET TRANSACTION READ ONLY; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! ROLLBACK TO SAVEPOINT x; ! SHOW transaction_read_only; -- off ! transaction_read_only ! ----------------------- ! off ! (1 row) ! ! SAVEPOINT y; ! SET TRANSACTION READ ONLY; -- ok ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! RELEASE SAVEPOINT y; ! SHOW transaction_read_only; -- off ! transaction_read_only ! ----------------------- ! off ! (1 row) ! ! COMMIT; ! SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY; ! DROP TABLE writetest; -- fail ! ERROR: cannot execute DROP TABLE in a read-only transaction ! INSERT INTO writetest VALUES (1); -- fail ! ERROR: cannot execute INSERT in a read-only transaction ! SELECT * FROM writetest; -- ok ! a ! --- ! (0 rows) ! ! DELETE FROM temptest; -- ok ! UPDATE temptest SET a = 0 FROM writetest WHERE temptest.a = 1 AND writetest.a = temptest.a; -- ok ! PREPARE test AS UPDATE writetest SET a = 0; -- ok ! EXECUTE test; -- fail ! ERROR: cannot execute UPDATE in a read-only transaction ! SELECT * FROM writetest, temptest; -- ok ! a | a ! ---+--- ! (0 rows) ! ! CREATE TABLE test AS SELECT * FROM writetest; -- fail ! ERROR: cannot execute CREATE TABLE AS in a read-only transaction ! START TRANSACTION READ WRITE; ! DROP TABLE writetest; -- ok ! COMMIT; ! -- Subtransactions, basic tests ! -- create & drop tables ! SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE; ! CREATE TABLE foobar (a int); ! BEGIN; ! CREATE TABLE foo (a int); ! SAVEPOINT one; ! DROP TABLE foo; ! CREATE TABLE bar (a int); ! ROLLBACK TO SAVEPOINT one; ! RELEASE SAVEPOINT one; ! SAVEPOINT two; ! CREATE TABLE baz (a int); ! RELEASE SAVEPOINT two; ! drop TABLE foobar; ! CREATE TABLE barbaz (a int); ! COMMIT; ! -- should exist: barbaz, baz, foo ! SELECT * FROM foo; -- should be empty ! a ! --- ! (0 rows) ! ! SELECT * FROM bar; -- shouldn't exist ! ERROR: relation "bar" does not exist ! LINE 1: SELECT * FROM bar; ! ^ ! SELECT * FROM barbaz; -- should be empty ! a ! --- ! (0 rows) ! ! SELECT * FROM baz; -- should be empty ! a ! --- ! (0 rows) ! ! -- inserts ! BEGIN; ! INSERT INTO foo VALUES (1); ! SAVEPOINT one; ! INSERT into bar VALUES (1); ! ERROR: relation "bar" does not exist ! LINE 1: INSERT into bar VALUES (1); ! ^ ! ROLLBACK TO one; ! RELEASE SAVEPOINT one; ! SAVEPOINT two; ! INSERT into barbaz VALUES (1); ! RELEASE two; ! SAVEPOINT three; ! SAVEPOINT four; ! INSERT INTO foo VALUES (2); ! RELEASE SAVEPOINT four; ! ROLLBACK TO SAVEPOINT three; ! RELEASE SAVEPOINT three; ! INSERT INTO foo VALUES (3); ! COMMIT; ! SELECT * FROM foo; -- should have 1 and 3 ! a ! --- ! 1 ! 3 ! (2 rows) ! ! SELECT * FROM barbaz; -- should have 1 ! a ! --- ! 1 ! (1 row) ! ! -- test whole-tree commit ! BEGIN; ! SAVEPOINT one; ! SELECT foo; ! ERROR: column "foo" does not exist ! LINE 1: SELECT foo; ! ^ ! ROLLBACK TO SAVEPOINT one; ! RELEASE SAVEPOINT one; ! SAVEPOINT two; ! CREATE TABLE savepoints (a int); ! SAVEPOINT three; ! INSERT INTO savepoints VALUES (1); ! SAVEPOINT four; ! INSERT INTO savepoints VALUES (2); ! SAVEPOINT five; ! INSERT INTO savepoints VALUES (3); ! ROLLBACK TO SAVEPOINT five; ! COMMIT; ! COMMIT; -- should not be in a transaction block ! WARNING: there is no transaction in progress ! SELECT * FROM savepoints; ! a ! --- ! 1 ! 2 ! (2 rows) ! ! -- test whole-tree rollback ! BEGIN; ! SAVEPOINT one; ! DELETE FROM savepoints WHERE a=1; ! RELEASE SAVEPOINT one; ! SAVEPOINT two; ! DELETE FROM savepoints WHERE a=1; ! SAVEPOINT three; ! DELETE FROM savepoints WHERE a=2; ! ROLLBACK; ! COMMIT; -- should not be in a transaction block ! WARNING: there is no transaction in progress ! SELECT * FROM savepoints; ! a ! --- ! 1 ! 2 ! (2 rows) ! ! -- test whole-tree commit on an aborted subtransaction ! BEGIN; ! INSERT INTO savepoints VALUES (4); ! SAVEPOINT one; ! INSERT INTO savepoints VALUES (5); ! SELECT foo; ! ERROR: column "foo" does not exist ! LINE 1: SELECT foo; ! ^ ! COMMIT; ! SELECT * FROM savepoints; ! a ! --- ! 1 ! 2 ! (2 rows) ! ! BEGIN; ! INSERT INTO savepoints VALUES (6); ! SAVEPOINT one; ! INSERT INTO savepoints VALUES (7); ! RELEASE SAVEPOINT one; ! INSERT INTO savepoints VALUES (8); ! COMMIT; ! -- rows 6 and 8 should have been created by the same xact ! SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=8; ! ?column? ! ---------- ! t ! (1 row) ! ! -- rows 6 and 7 should have been created by different xacts ! SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=7; ! ?column? ! ---------- ! f ! (1 row) ! ! BEGIN; ! INSERT INTO savepoints VALUES (9); ! SAVEPOINT one; ! INSERT INTO savepoints VALUES (10); ! ROLLBACK TO SAVEPOINT one; ! INSERT INTO savepoints VALUES (11); ! COMMIT; ! SELECT a FROM savepoints WHERE a in (9, 10, 11); ! a ! ---- ! 9 ! 11 ! (2 rows) ! ! -- rows 9 and 11 should have been created by different xacts ! SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=9 AND b.a=11; ! ?column? ! ---------- ! f ! (1 row) ! ! BEGIN; ! INSERT INTO savepoints VALUES (12); ! SAVEPOINT one; ! INSERT INTO savepoints VALUES (13); ! SAVEPOINT two; ! INSERT INTO savepoints VALUES (14); ! ROLLBACK TO SAVEPOINT one; ! INSERT INTO savepoints VALUES (15); ! SAVEPOINT two; ! INSERT INTO savepoints VALUES (16); ! SAVEPOINT three; ! INSERT INTO savepoints VALUES (17); ! COMMIT; ! SELECT a FROM savepoints WHERE a BETWEEN 12 AND 17; ! a ! ---- ! 12 ! 15 ! 16 ! 17 ! (4 rows) ! ! BEGIN; ! INSERT INTO savepoints VALUES (18); ! SAVEPOINT one; ! INSERT INTO savepoints VALUES (19); ! SAVEPOINT two; ! INSERT INTO savepoints VALUES (20); ! ROLLBACK TO SAVEPOINT one; ! INSERT INTO savepoints VALUES (21); ! ROLLBACK TO SAVEPOINT one; ! INSERT INTO savepoints VALUES (22); ! COMMIT; ! SELECT a FROM savepoints WHERE a BETWEEN 18 AND 22; ! a ! ---- ! 18 ! 22 ! (2 rows) ! ! DROP TABLE savepoints; ! -- only in a transaction block: ! SAVEPOINT one; ! ERROR: SAVEPOINT can only be used in transaction blocks ! ROLLBACK TO SAVEPOINT one; ! ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks ! RELEASE SAVEPOINT one; ! ERROR: RELEASE SAVEPOINT can only be used in transaction blocks ! -- Only "rollback to" allowed in aborted state ! BEGIN; ! SAVEPOINT one; ! SELECT 0/0; ! ERROR: division by zero ! SAVEPOINT two; -- ignored till the end of ... ! ERROR: current transaction is aborted, commands ignored until end of transaction block ! RELEASE SAVEPOINT one; -- ignored till the end of ... ! ERROR: current transaction is aborted, commands ignored until end of transaction block ! ROLLBACK TO SAVEPOINT one; ! SELECT 1; ! ?column? ! ---------- ! 1 ! (1 row) ! ! COMMIT; ! SELECT 1; -- this should work ! ?column? ! ---------- ! 1 ! (1 row) ! ! -- check non-transactional behavior of cursors ! BEGIN; ! DECLARE c CURSOR FOR SELECT unique2 FROM tenk1 ORDER BY unique2; ! SAVEPOINT one; ! FETCH 10 FROM c; ! unique2 ! --------- ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! 9 ! (10 rows) ! ! ROLLBACK TO SAVEPOINT one; ! FETCH 10 FROM c; ! unique2 ! --------- ! 10 ! 11 ! 12 ! 13 ! 14 ! 15 ! 16 ! 17 ! 18 ! 19 ! (10 rows) ! ! RELEASE SAVEPOINT one; ! FETCH 10 FROM c; ! unique2 ! --------- ! 20 ! 21 ! 22 ! 23 ! 24 ! 25 ! 26 ! 27 ! 28 ! 29 ! (10 rows) ! ! CLOSE c; ! DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1 ORDER BY unique2; ! SAVEPOINT two; ! FETCH 10 FROM c; ! ERROR: division by zero ! ROLLBACK TO SAVEPOINT two; ! -- c is now dead to the world ... ! FETCH 10 FROM c; ! ERROR: portal "c" cannot be run ! ROLLBACK TO SAVEPOINT two; ! RELEASE SAVEPOINT two; ! FETCH 10 FROM c; ! ERROR: portal "c" cannot be run ! COMMIT; ! -- ! -- Check that "stable" functions are really stable. They should not be ! -- able to see the partial results of the calling query. (Ideally we would ! -- also check that they don't see commits of concurrent transactions, but ! -- that's a mite hard to do within the limitations of pg_regress.) ! -- ! select * from xacttest; ! a | b ! -----+--------- ! 56 | 7.8 ! 100 | 99.097 ! 0 | 0.09561 ! 42 | 324.78 ! 777 | 777.777 ! (5 rows) ! ! create or replace function max_xacttest() returns smallint language sql as ! 'select max(a) from xacttest' stable; ! begin; ! update xacttest set a = max_xacttest() + 10 where a > 0; ! select * from xacttest; ! a | b ! -----+--------- ! 0 | 0.09561 ! 787 | 7.8 ! 787 | 99.097 ! 787 | 324.78 ! 787 | 777.777 ! (5 rows) ! ! rollback; ! -- But a volatile function can see the partial results of the calling query ! create or replace function max_xacttest() returns smallint language sql as ! 'select max(a) from xacttest' volatile; ! begin; ! update xacttest set a = max_xacttest() + 10 where a > 0; ! select * from xacttest; ! a | b ! -----+--------- ! 0 | 0.09561 ! 787 | 7.8 ! 797 | 99.097 ! 807 | 324.78 ! 817 | 777.777 ! (5 rows) ! ! rollback; ! -- Now the same test with plpgsql (since it depends on SPI which is different) ! create or replace function max_xacttest() returns smallint language plpgsql as ! 'begin return max(a) from xacttest; end' stable; ! begin; ! update xacttest set a = max_xacttest() + 10 where a > 0; ! select * from xacttest; ! a | b ! -----+--------- ! 0 | 0.09561 ! 787 | 7.8 ! 787 | 99.097 ! 787 | 324.78 ! 787 | 777.777 ! (5 rows) ! ! rollback; ! create or replace function max_xacttest() returns smallint language plpgsql as ! 'begin return max(a) from xacttest; end' volatile; ! begin; ! update xacttest set a = max_xacttest() + 10 where a > 0; ! select * from xacttest; ! a | b ! -----+--------- ! 0 | 0.09561 ! 787 | 7.8 ! 797 | 99.097 ! 807 | 324.78 ! 817 | 777.777 ! (5 rows) ! ! rollback; ! -- test case for problems with dropping an open relation during abort ! BEGIN; ! savepoint x; ! CREATE TABLE koju (a INT UNIQUE); ! INSERT INTO koju VALUES (1); ! INSERT INTO koju VALUES (1); ! ERROR: duplicate key value violates unique constraint "koju_a_key" ! DETAIL: Key (a)=(1) already exists. ! rollback to x; ! CREATE TABLE koju (a INT UNIQUE); ! INSERT INTO koju VALUES (1); ! INSERT INTO koju VALUES (1); ! ERROR: duplicate key value violates unique constraint "koju_a_key" ! DETAIL: Key (a)=(1) already exists. ! ROLLBACK; ! DROP TABLE foo; ! DROP TABLE baz; ! DROP TABLE barbaz; ! -- test case for problems with revalidating an open relation during abort ! create function inverse(int) returns float8 as ! $$ ! begin ! analyze revalidate_bug; ! return 1::float8/$1; ! exception ! when division_by_zero then return 0; ! end$$ language plpgsql volatile; ! create table revalidate_bug (c float8 unique); ! insert into revalidate_bug values (1); ! insert into revalidate_bug values (inverse(0)); ! drop table revalidate_bug; ! drop function inverse(int); ! -- verify that cursors created during an aborted subtransaction are ! -- closed, but that we do not rollback the effect of any FETCHs ! -- performed in the aborted subtransaction ! begin; ! savepoint x; ! create table abc (a int); ! insert into abc values (5); ! insert into abc values (10); ! declare foo cursor for select * from abc; ! fetch from foo; ! a ! --- ! 5 ! (1 row) ! ! rollback to x; ! -- should fail ! fetch from foo; ! ERROR: cursor "foo" does not exist ! commit; ! begin; ! create table abc (a int); ! insert into abc values (5); ! insert into abc values (10); ! insert into abc values (15); ! declare foo cursor for select * from abc; ! fetch from foo; ! a ! --- ! 5 ! (1 row) ! ! savepoint x; ! fetch from foo; ! a ! ---- ! 10 ! (1 row) ! ! rollback to x; ! fetch from foo; ! a ! ---- ! 15 ! (1 row) ! ! abort; ! -- Test for successful cleanup of an aborted transaction at session exit. ! -- THIS MUST BE THE LAST TEST IN THIS FILE. ! begin; ! select 1/0; ! ERROR: division by zero ! rollback to X; ! ERROR: no such savepoint ! -- DO NOT ADD ANYTHING HERE. --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/random.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/random.out Tue Oct 28 15:53:05 2014 *************** *** 1,52 **** ! -- ! -- RANDOM ! -- Test the random function ! -- ! -- count the number of tuples originally, should be 1000 ! SELECT count(*) FROM onek; ! count ! ------- ! 1000 ! (1 row) ! ! -- pick three random rows, they shouldn't match ! (SELECT unique1 AS random ! FROM onek ORDER BY random() LIMIT 1) ! INTERSECT ! (SELECT unique1 AS random ! FROM onek ORDER BY random() LIMIT 1) ! INTERSECT ! (SELECT unique1 AS random ! FROM onek ORDER BY random() LIMIT 1); ! random ! -------- ! (0 rows) ! ! -- count roughly 1/10 of the tuples ! SELECT count(*) AS random INTO RANDOM_TBL ! FROM onek WHERE random() < 1.0/10; ! -- select again, the count should be different ! INSERT INTO RANDOM_TBL (random) ! SELECT count(*) ! FROM onek WHERE random() < 1.0/10; ! -- select again, the count should be different ! INSERT INTO RANDOM_TBL (random) ! SELECT count(*) ! FROM onek WHERE random() < 1.0/10; ! -- select again, the count should be different ! INSERT INTO RANDOM_TBL (random) ! SELECT count(*) ! FROM onek WHERE random() < 1.0/10; ! -- now test that they are different counts ! SELECT random, count(random) FROM RANDOM_TBL ! GROUP BY random HAVING count(random) > 3; ! random | count ! --------+------- ! (0 rows) ! ! SELECT AVG(random) FROM RANDOM_TBL ! HAVING AVG(random) NOT BETWEEN 80 AND 120; ! avg ! ----- ! (0 rows) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/portals.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/portals.out Tue Oct 28 15:53:05 2014 *************** *** 1,1287 **** ! -- ! -- Cursor regression tests ! -- ! BEGIN; ! DECLARE foo1 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo2 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo3 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo4 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo5 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo6 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo7 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo8 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo9 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo10 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo11 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo12 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; ! DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! FETCH 1 in foo1; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (1 row) ! ! FETCH 2 in foo2; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! (2 rows) ! ! FETCH 3 in foo3; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! (3 rows) ! ! FETCH 4 in foo4; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! (4 rows) ! ! FETCH 5 in foo5; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! (5 rows) ! ! FETCH 6 in foo6; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! (6 rows) ! ! FETCH 7 in foo7; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! (7 rows) ! ! FETCH 8 in foo8; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! (8 rows) ! ! FETCH 9 in foo9; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! (9 rows) ! ! FETCH 10 in foo10; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! (10 rows) ! ! FETCH 11 in foo11; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! (11 rows) ! ! FETCH 12 in foo12; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! (12 rows) ! ! FETCH 13 in foo13; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! (13 rows) ! ! FETCH 14 in foo14; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! (14 rows) ! ! FETCH 15 in foo15; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! (15 rows) ! ! FETCH 16 in foo16; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! (16 rows) ! ! FETCH 17 in foo17; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! (17 rows) ! ! FETCH 18 in foo18; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! (18 rows) ! ! FETCH 19 in foo19; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! (19 rows) ! ! FETCH 20 in foo20; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! (20 rows) ! ! FETCH 21 in foo21; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! 9460 | 20 | 0 | 0 | 0 | 0 | 60 | 460 | 1460 | 4460 | 9460 | 120 | 121 | WZAAAA | UAAAAA | AAAAxx ! (21 rows) ! ! FETCH 22 in foo22; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! 9460 | 20 | 0 | 0 | 0 | 0 | 60 | 460 | 1460 | 4460 | 9460 | 120 | 121 | WZAAAA | UAAAAA | AAAAxx ! 59 | 21 | 1 | 3 | 9 | 19 | 59 | 59 | 59 | 59 | 59 | 118 | 119 | HCAAAA | VAAAAA | HHHHxx ! (22 rows) ! ! FETCH 23 in foo23; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! 9460 | 20 | 0 | 0 | 0 | 0 | 60 | 460 | 1460 | 4460 | 9460 | 120 | 121 | WZAAAA | UAAAAA | AAAAxx ! 59 | 21 | 1 | 3 | 9 | 19 | 59 | 59 | 59 | 59 | 59 | 118 | 119 | HCAAAA | VAAAAA | HHHHxx ! 8020 | 22 | 0 | 0 | 0 | 0 | 20 | 20 | 20 | 3020 | 8020 | 40 | 41 | MWAAAA | WAAAAA | OOOOxx ! (23 rows) ! ! FETCH backward 1 in foo23; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 59 | 21 | 1 | 3 | 9 | 19 | 59 | 59 | 59 | 59 | 59 | 118 | 119 | HCAAAA | VAAAAA | HHHHxx ! (1 row) ! ! FETCH backward 2 in foo22; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 9460 | 20 | 0 | 0 | 0 | 0 | 60 | 460 | 1460 | 4460 | 9460 | 120 | 121 | WZAAAA | UAAAAA | AAAAxx ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! (2 rows) ! ! FETCH backward 3 in foo21; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 6969 | 19 | 1 | 1 | 9 | 9 | 69 | 969 | 969 | 1969 | 6969 | 138 | 139 | BIAAAA | TAAAAA | VVVVxx ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! (3 rows) ! ! FETCH backward 4 in foo20; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 6621 | 18 | 1 | 1 | 1 | 1 | 21 | 621 | 621 | 1621 | 6621 | 42 | 43 | RUAAAA | SAAAAA | OOOOxx ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! (4 rows) ! ! FETCH backward 5 in foo19; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5785 | 17 | 1 | 1 | 5 | 5 | 85 | 785 | 1785 | 785 | 5785 | 170 | 171 | NOAAAA | RAAAAA | HHHHxx ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! (5 rows) ! ! FETCH backward 6 in foo18; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5387 | 16 | 1 | 3 | 7 | 7 | 87 | 387 | 1387 | 387 | 5387 | 174 | 175 | FZAAAA | QAAAAA | AAAAxx ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! (6 rows) ! ! FETCH backward 7 in foo17; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5006 | 15 | 0 | 2 | 6 | 6 | 6 | 6 | 1006 | 6 | 5006 | 12 | 13 | OKAAAA | PAAAAA | VVVVxx ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! (7 rows) ! ! FETCH backward 8 in foo16; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5471 | 14 | 1 | 3 | 1 | 11 | 71 | 471 | 1471 | 471 | 5471 | 142 | 143 | LCAAAA | OAAAAA | OOOOxx ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! (8 rows) ! ! FETCH backward 9 in foo15; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 6243 | 13 | 1 | 3 | 3 | 3 | 43 | 243 | 243 | 1243 | 6243 | 86 | 87 | DGAAAA | NAAAAA | HHHHxx ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! (9 rows) ! ! FETCH backward 10 in foo14; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5222 | 12 | 0 | 2 | 2 | 2 | 22 | 222 | 1222 | 222 | 5222 | 44 | 45 | WSAAAA | MAAAAA | AAAAxx ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! (10 rows) ! ! FETCH backward 11 in foo13; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1504 | 11 | 0 | 0 | 4 | 4 | 4 | 504 | 1504 | 1504 | 1504 | 8 | 9 | WFAAAA | LAAAAA | VVVVxx ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! (11 rows) ! ! FETCH backward 12 in foo12; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1314 | 10 | 0 | 2 | 4 | 14 | 14 | 314 | 1314 | 1314 | 1314 | 28 | 29 | OYAAAA | KAAAAA | OOOOxx ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (11 rows) ! ! FETCH backward 13 in foo11; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 3043 | 9 | 1 | 3 | 3 | 3 | 43 | 43 | 1043 | 3043 | 3043 | 86 | 87 | BNAAAA | JAAAAA | HHHHxx ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (10 rows) ! ! FETCH backward 14 in foo10; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 4321 | 8 | 1 | 1 | 1 | 1 | 21 | 321 | 321 | 4321 | 4321 | 42 | 43 | FKAAAA | IAAAAA | AAAAxx ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (9 rows) ! ! FETCH backward 15 in foo9; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 6701 | 7 | 1 | 1 | 1 | 1 | 1 | 701 | 701 | 1701 | 6701 | 2 | 3 | TXAAAA | HAAAAA | VVVVxx ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (8 rows) ! ! FETCH backward 16 in foo8; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 5057 | 6 | 1 | 1 | 7 | 17 | 57 | 57 | 1057 | 57 | 5057 | 114 | 115 | NMAAAA | GAAAAA | OOOOxx ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (7 rows) ! ! FETCH backward 17 in foo7; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8009 | 5 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 3009 | 8009 | 18 | 19 | BWAAAA | FAAAAA | HHHHxx ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (6 rows) ! ! FETCH backward 18 in foo6; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 7164 | 4 | 0 | 0 | 4 | 4 | 64 | 164 | 1164 | 2164 | 7164 | 128 | 129 | OPAAAA | EAAAAA | AAAAxx ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (5 rows) ! ! FETCH backward 19 in foo5; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 9850 | 3 | 0 | 2 | 0 | 10 | 50 | 850 | 1850 | 4850 | 9850 | 100 | 101 | WOAAAA | DAAAAA | VVVVxx ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (4 rows) ! ! FETCH backward 20 in foo4; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (3 rows) ! ! FETCH backward 21 in foo3; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (2 rows) ! ! FETCH backward 22 in foo2; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (1 row) ! ! FETCH backward 23 in foo1; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! (0 rows) ! ! CLOSE foo1; ! CLOSE foo2; ! CLOSE foo3; ! CLOSE foo4; ! CLOSE foo5; ! CLOSE foo6; ! CLOSE foo7; ! CLOSE foo8; ! CLOSE foo9; ! CLOSE foo10; ! CLOSE foo11; ! CLOSE foo12; ! -- leave some cursors open, to test that auto-close works. ! -- record this in the system view as well (don't query the time field there ! -- however) ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors ORDER BY 1; ! name | statement | is_holdable | is_binary | is_scrollable ! -------+-----------------------------------------------------------------------+-------------+-----------+--------------- ! foo13 | DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! foo14 | DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t ! foo15 | DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! foo16 | DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t ! foo17 | DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! foo18 | DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t ! foo19 | DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! foo20 | DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t ! foo21 | DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! foo22 | DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t ! foo23 | DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t ! (11 rows) ! ! END; ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; ! name | statement | is_holdable | is_binary | is_scrollable ! ------+-----------+-------------+-----------+--------------- ! (0 rows) ! ! -- ! -- NO SCROLL disallows backward fetching ! -- ! BEGIN; ! DECLARE foo24 NO SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; ! FETCH 1 FROM foo24; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (1 row) ! ! FETCH BACKWARD 1 FROM foo24; -- should fail ! ERROR: cursor can only scan forward ! HINT: Declare it with SCROLL option to enable backward scan. ! END; ! -- ! -- Cursors outside transaction blocks ! -- ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; ! name | statement | is_holdable | is_binary | is_scrollable ! ------+-----------+-------------+-----------+--------------- ! (0 rows) ! ! BEGIN; ! DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; ! FETCH FROM foo25; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 8800 | 0 | 0 | 0 | 0 | 0 | 0 | 800 | 800 | 3800 | 8800 | 0 | 1 | MAAAAA | AAAAAA | AAAAxx ! (1 row) ! ! FETCH FROM foo25; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! (1 row) ! ! COMMIT; ! FETCH FROM foo25; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 3420 | 2 | 0 | 0 | 0 | 0 | 20 | 420 | 1420 | 3420 | 3420 | 40 | 41 | OBAAAA | CAAAAA | OOOOxx ! (1 row) ! ! FETCH BACKWARD FROM foo25; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 1891 | 1 | 1 | 3 | 1 | 11 | 91 | 891 | 1891 | 1891 | 1891 | 182 | 183 | TUAAAA | BAAAAA | HHHHxx ! (1 row) ! ! FETCH ABSOLUTE -1 FROM foo25; ! unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ! ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ! 2968 | 9999 | 0 | 0 | 8 | 8 | 68 | 968 | 968 | 2968 | 2968 | 136 | 137 | EKAAAA | PUOAAA | VVVVxx ! (1 row) ! ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; ! name | statement | is_holdable | is_binary | is_scrollable ! -------+----------------------------------------------------------------+-------------+-----------+--------------- ! foo25 | DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; | t | f | t ! (1 row) ! ! CLOSE foo25; ! -- ! -- ROLLBACK should close holdable cursors ! -- ! BEGIN; ! DECLARE foo26 CURSOR WITH HOLD FOR SELECT * FROM tenk1 ORDER BY unique2; ! ROLLBACK; ! -- should fail ! FETCH FROM foo26; ! ERROR: cursor "foo26" does not exist ! -- ! -- Parameterized DECLARE needs to insert param values into the cursor portal ! -- ! BEGIN; ! CREATE FUNCTION declares_cursor(text) ! RETURNS void ! AS 'DECLARE c CURSOR FOR SELECT stringu1 FROM tenk1 WHERE stringu1 LIKE $1;' ! LANGUAGE SQL; ! SELECT declares_cursor('AB%'); ! declares_cursor ! ----------------- ! ! (1 row) ! ! FETCH ALL FROM c; ! stringu1 ! ---------- ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! ABAAAA ! (15 rows) ! ! ROLLBACK; ! -- ! -- Test behavior of both volatile and stable functions inside a cursor; ! -- in particular we want to see what happens during commit of a holdable ! -- cursor ! -- ! create temp table tt1(f1 int); ! create function count_tt1_v() returns int8 as ! 'select count(*) from tt1' language sql volatile; ! create function count_tt1_s() returns int8 as ! 'select count(*) from tt1' language sql stable; ! begin; ! insert into tt1 values(1); ! declare c1 cursor for select count_tt1_v(), count_tt1_s(); ! insert into tt1 values(2); ! fetch all from c1; ! count_tt1_v | count_tt1_s ! -------------+------------- ! 2 | 1 ! (1 row) ! ! rollback; ! begin; ! insert into tt1 values(1); ! declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); ! insert into tt1 values(2); ! commit; ! delete from tt1; ! fetch all from c2; ! count_tt1_v | count_tt1_s ! -------------+------------- ! 2 | 1 ! (1 row) ! ! drop function count_tt1_v(); ! drop function count_tt1_s(); ! -- Create a cursor with the BINARY option and check the pg_cursors view ! BEGIN; ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; ! name | statement | is_holdable | is_binary | is_scrollable ! ------+----------------------------------------------------------------------+-------------+-----------+--------------- ! c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f ! (1 row) ! ! DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors ORDER BY 1; ! name | statement | is_holdable | is_binary | is_scrollable ! ------+----------------------------------------------------------------------+-------------+-----------+--------------- ! bc | DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; | f | t | t ! c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f ! (2 rows) ! ! ROLLBACK; ! -- We should not see the portal that is created internally to ! -- implement EXECUTE in pg_cursors ! PREPARE cprep AS ! SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; ! EXECUTE cprep; ! name | statement | is_holdable | is_binary | is_scrollable ! ------+----------------------------------------------------------------------+-------------+-----------+--------------- ! c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f ! (1 row) ! ! -- test CLOSE ALL; ! SELECT name FROM pg_cursors ORDER BY 1; ! name ! ------ ! c2 ! (1 row) ! ! CLOSE ALL; ! SELECT name FROM pg_cursors ORDER BY 1; ! name ! ------ ! (0 rows) ! ! BEGIN; ! DECLARE foo1 CURSOR WITH HOLD FOR SELECT 1; ! DECLARE foo2 CURSOR WITHOUT HOLD FOR SELECT 1; ! SELECT name FROM pg_cursors ORDER BY 1; ! name ! ------ ! foo1 ! foo2 ! (2 rows) ! ! CLOSE ALL; ! SELECT name FROM pg_cursors ORDER BY 1; ! name ! ------ ! (0 rows) ! ! COMMIT; ! -- ! -- Tests for updatable cursors ! -- ! CREATE TEMP TABLE uctest(f1 int, f2 text); ! INSERT INTO uctest VALUES (1, 'one'), (2, 'two'), (3, 'three'); ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 1 | one ! 2 | two ! 3 | three ! (3 rows) ! ! -- Check DELETE WHERE CURRENT ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest; ! FETCH 2 FROM c1; ! f1 | f2 ! ----+----- ! 1 | one ! 2 | two ! (2 rows) ! ! DELETE FROM uctest WHERE CURRENT OF c1; ! -- should show deletion ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 1 | one ! 3 | three ! (2 rows) ! ! -- cursor did not move ! FETCH ALL FROM c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! -- cursor is insensitive ! MOVE BACKWARD ALL IN c1; ! FETCH ALL FROM c1; ! f1 | f2 ! ----+------- ! 1 | one ! 2 | two ! 3 | three ! (3 rows) ! ! COMMIT; ! -- should still see deletion ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 1 | one ! 3 | three ! (2 rows) ! ! -- Check UPDATE WHERE CURRENT; this time use FOR UPDATE ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; ! FETCH c1; ! f1 | f2 ! ----+----- ! 1 | one ! (1 row) ! ! UPDATE uctest SET f1 = 8 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 3 | three ! 8 | one ! (2 rows) ! ! COMMIT; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 3 | three ! 8 | one ! (2 rows) ! ! -- Check repeated-update and update-then-delete cases ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest; ! FETCH c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 8 | one ! 13 | three ! (2 rows) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 8 | one ! 23 | three ! (2 rows) ! ! -- insensitive cursor should not show effects of updates or deletes ! FETCH RELATIVE 0 FROM c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! DELETE FROM uctest WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! DELETE FROM uctest WHERE CURRENT OF c1; -- no-op ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! FETCH RELATIVE 0 FROM c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! ROLLBACK; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 3 | three ! 8 | one ! (2 rows) ! ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; ! FETCH c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 8 | one ! 13 | three ! (2 rows) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 8 | one ! 23 | three ! (2 rows) ! ! DELETE FROM uctest WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! DELETE FROM uctest WHERE CURRENT OF c1; -- no-op ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op ! SELECT * FROM uctest; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! --- sensitive cursors can't currently scroll back, so this is an error: ! FETCH RELATIVE 0 FROM c1; ! ERROR: cursor can only scan forward ! HINT: Declare it with SCROLL option to enable backward scan. ! ROLLBACK; ! SELECT * FROM uctest; ! f1 | f2 ! ----+------- ! 3 | three ! 8 | one ! (2 rows) ! ! -- Check inheritance cases ! CREATE TEMP TABLE ucchild () inherits (uctest); ! INSERT INTO ucchild values(100, 'hundred'); ! SELECT * FROM uctest; ! f1 | f2 ! -----+--------- ! 3 | three ! 8 | one ! 100 | hundred ! (3 rows) ! ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; ! FETCH 1 FROM c1; ! f1 | f2 ! ----+------- ! 3 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! FETCH 1 FROM c1; ! f1 | f2 ! ----+----- ! 8 | one ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! FETCH 1 FROM c1; ! f1 | f2 ! -----+--------- ! 100 | hundred ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! FETCH 1 FROM c1; ! f1 | f2 ! ----+---- ! (0 rows) ! ! COMMIT; ! SELECT * FROM uctest; ! f1 | f2 ! -----+--------- ! 13 | three ! 18 | one ! 110 | hundred ! (3 rows) ! ! -- Can update from a self-join, but only if FOR UPDATE says which to use ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; ! FETCH 1 FROM c1; ! f1 | f2 | f1 | f2 ! ----+-----+----+------- ! 18 | one | 13 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ! ERROR: cursor "c1" is not a simply updatable scan of table "uctest" ! ROLLBACK; ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; ! FETCH 1 FROM c1; ! f1 | f2 | f1 | f2 ! ----+-----+----+------- ! 18 | one | 13 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ! ERROR: cursor "c1" has multiple FOR UPDATE/SHARE references to table "uctest" ! ROLLBACK; ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; ! FETCH 1 FROM c1; ! f1 | f2 | f1 | f2 ! ----+-----+----+------- ! 18 | one | 13 | three ! (1 row) ! ! UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ! SELECT * FROM uctest; ! f1 | f2 ! -----+--------- ! 13 | three ! 28 | one ! 110 | hundred ! (3 rows) ! ! ROLLBACK; ! -- Check various error cases ! DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no such cursor ! ERROR: cursor "c1" does not exist ! DECLARE cx CURSOR WITH HOLD FOR SELECT * FROM uctest; ! DELETE FROM uctest WHERE CURRENT OF cx; -- fail, can't use held cursor ! ERROR: cursor "cx" is held from a previous transaction ! BEGIN; ! DECLARE c CURSOR FOR SELECT * FROM tenk2; ! DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ! ERROR: cursor "c" is not a simply updatable scan of table "uctest" ! ROLLBACK; ! BEGIN; ! DECLARE c CURSOR FOR SELECT * FROM tenk2 FOR SHARE; ! DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ! ERROR: cursor "c" does not have a FOR UPDATE/SHARE reference to table "uctest" ! ROLLBACK; ! BEGIN; ! DECLARE c CURSOR FOR SELECT * FROM tenk1 JOIN tenk2 USING (unique1); ! DELETE FROM tenk1 WHERE CURRENT OF c; -- fail, cursor is on a join ! ERROR: cursor "c" is not a simply updatable scan of table "tenk1" ! ROLLBACK; ! BEGIN; ! DECLARE c CURSOR FOR SELECT f1,count(*) FROM uctest GROUP BY f1; ! DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor is on aggregation ! ERROR: cursor "c" is not a simply updatable scan of table "uctest" ! ROLLBACK; ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM uctest; ! DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no current row ! ERROR: cursor "c1" is not positioned on a row ! ROLLBACK; ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT MIN(f1) FROM uctest FOR UPDATE; ! ERROR: FOR UPDATE is not allowed with aggregate functions ! ROLLBACK; ! -- WHERE CURRENT OF may someday work with views, but today is not that day. ! -- For now, just make sure it errors out cleanly. ! CREATE TEMP VIEW ucview AS SELECT * FROM uctest; ! CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD ! DELETE FROM uctest WHERE f1 = OLD.f1; ! BEGIN; ! DECLARE c1 CURSOR FOR SELECT * FROM ucview; ! FETCH FROM c1; ! f1 | f2 ! ----+------- ! 13 | three ! (1 row) ! ! DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported ! ERROR: WHERE CURRENT OF on a view is not implemented ! ROLLBACK; ! -- Make sure snapshot management works okay, per bug report in ! -- 235395b90909301035v7228ce63q392931f15aa74b31@mail.gmail.com ! BEGIN; ! SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! CREATE TABLE cursor (a int); ! INSERT INTO cursor VALUES (1); ! DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE; ! UPDATE cursor SET a = 2; ! FETCH ALL FROM c1; ! a ! --- ! (0 rows) ! ! COMMIT; ! DROP TABLE cursor; ! -- Check rewinding a cursor containing a stable function in LIMIT, ! -- per bug report in 8336843.9833.1399385291498.JavaMail.root@quick ! begin; ! create function nochange(int) returns int ! as 'select $1 limit 1' language sql stable; ! declare c cursor for select * from int8_tbl limit nochange(3); ! fetch all from c; ! q1 | q2 ! ------------------+------------------ ! 123 | 456 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! (3 rows) ! ! move backward all in c; ! fetch all from c; ! q1 | q2 ! ------------------+------------------ ! 123 | 456 ! 123 | 4567890123456789 ! 4567890123456789 | 123 ! (3 rows) ! ! rollback; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/arrays.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/arrays.out Tue Oct 28 15:53:05 2014 *************** *** 1,1831 **** ! -- ! -- ARRAYS ! -- ! CREATE TABLE arrtest ( ! a int2[], ! b int4[][][], ! c name[], ! d text[][], ! e float8[], ! f char(5)[], ! g varchar(5)[] ! ); ! -- ! -- only the 'e' array is 0-based, the others are 1-based. ! -- ! INSERT INTO arrtest (a[1:5], b[1:1][1:2][1:2], c, d, f, g) ! VALUES ('{1,2,3,4,5}', '{{{0,0},{1,2}}}', '{}', '{}', '{}', '{}'); ! UPDATE arrtest SET e[0] = '1.1'; ! UPDATE arrtest SET e[1] = '2.2'; ! INSERT INTO arrtest (f) ! VALUES ('{"too long"}'); ! ERROR: value too long for type character(5) ! INSERT INTO arrtest (a, b[1:2][1:2], c, d, e, f, g) ! VALUES ('{11,12,23}', '{{3,4},{4,5}}', '{"foobar"}', ! '{{"elt1", "elt2"}}', '{"3.4", "6.7"}', ! '{"abc","abcde"}', '{"abc","abcde"}'); ! INSERT INTO arrtest (a, b[1:2], c, d[1:2]) ! VALUES ('{}', '{3,4}', '{foo,bar}', '{bar,foo}'); ! SELECT * FROM arrtest; ! a | b | c | d | e | f | g ! -------------+-----------------+-----------+---------------+-----------------+-----------------+------------- ! {1,2,3,4,5} | {{{0,0},{1,2}}} | {} | {} | [0:1]={1.1,2.2} | {} | {} ! {11,12,23} | {{3,4},{4,5}} | {foobar} | {{elt1,elt2}} | {3.4,6.7} | {"abc ",abcde} | {abc,abcde} ! {} | {3,4} | {foo,bar} | {bar,foo} | | | ! (3 rows) ! ! SELECT arrtest.a[1], ! arrtest.b[1][1][1], ! arrtest.c[1], ! arrtest.d[1][1], ! arrtest.e[0] ! FROM arrtest; ! a | b | c | d | e ! ----+---+--------+------+----- ! 1 | 0 | | | 1.1 ! 11 | | foobar | elt1 | ! | | foo | | ! (3 rows) ! ! SELECT a[1], b[1][1][1], c[1], d[1][1], e[0] ! FROM arrtest; ! a | b | c | d | e ! ----+---+--------+------+----- ! 1 | 0 | | | 1.1 ! 11 | | foobar | elt1 | ! | | foo | | ! (3 rows) ! ! SELECT a[1:3], ! b[1:1][1:2][1:2], ! c[1:2], ! d[1:1][1:2] ! FROM arrtest; ! a | b | c | d ! ------------+-----------------+-----------+--------------- ! {1,2,3} | {{{0,0},{1,2}}} | {} | {} ! {11,12,23} | {} | {foobar} | {{elt1,elt2}} ! {} | {} | {foo,bar} | {} ! (3 rows) ! ! SELECT array_ndims(a) AS a,array_ndims(b) AS b,array_ndims(c) AS c ! FROM arrtest; ! a | b | c ! ---+---+--- ! 1 | 3 | ! 1 | 2 | 1 ! | 1 | 1 ! (3 rows) ! ! SELECT array_dims(a) AS a,array_dims(b) AS b,array_dims(c) AS c ! FROM arrtest; ! a | b | c ! -------+-----------------+------- ! [1:5] | [1:1][1:2][1:2] | ! [1:3] | [1:2][1:2] | [1:1] ! | [1:2] | [1:2] ! (3 rows) ! ! -- returns nothing ! SELECT * ! FROM arrtest ! WHERE a[1] < 5 and ! c = '{"foobar"}'::_name; ! a | b | c | d | e | f | g ! ---+---+---+---+---+---+--- ! (0 rows) ! ! UPDATE arrtest ! SET a[1:2] = '{16,25}' ! WHERE NOT a = '{}'::_int2; ! UPDATE arrtest ! SET b[1:1][1:1][1:2] = '{113, 117}', ! b[1:1][1:2][2:2] = '{142, 147}' ! WHERE array_dims(b) = '[1:1][1:2][1:2]'; ! UPDATE arrtest ! SET c[2:2] = '{"new_word"}' ! WHERE array_dims(c) is not null; ! SELECT a,b,c FROM arrtest; ! a | b | c ! ---------------+-----------------------+------------------- ! {16,25,3,4,5} | {{{113,142},{1,147}}} | {} ! {} | {3,4} | {foo,new_word} ! {16,25,23} | {{3,4},{4,5}} | {foobar,new_word} ! (3 rows) ! ! SELECT a[1:3], ! b[1:1][1:2][1:2], ! c[1:2], ! d[1:1][2:2] ! FROM arrtest; ! a | b | c | d ! ------------+-----------------------+-------------------+---------- ! {16,25,3} | {{{113,142},{1,147}}} | {} | {} ! {} | {} | {foo,new_word} | {} ! {16,25,23} | {} | {foobar,new_word} | {{elt2}} ! (3 rows) ! ! INSERT INTO arrtest(a) VALUES('{1,null,3}'); ! SELECT a FROM arrtest; ! a ! --------------- ! {16,25,3,4,5} ! {} ! {16,25,23} ! {1,NULL,3} ! (4 rows) ! ! UPDATE arrtest SET a[4] = NULL WHERE a[2] IS NULL; ! SELECT a FROM arrtest WHERE a[2] IS NULL; ! a ! ----------------- ! [4:4]={NULL} ! {1,NULL,3,NULL} ! (2 rows) ! ! DELETE FROM arrtest WHERE a[2] IS NULL AND b IS NULL; ! SELECT a,b,c FROM arrtest; ! a | b | c ! ---------------+-----------------------+------------------- ! {16,25,3,4,5} | {{{113,142},{1,147}}} | {} ! {16,25,23} | {{3,4},{4,5}} | {foobar,new_word} ! [4:4]={NULL} | {3,4} | {foo,new_word} ! (3 rows) ! ! -- ! -- test array extension ! -- ! CREATE TEMP TABLE arrtest1 (i int[], t text[]); ! insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); ! select * from arrtest1; ! i | t ! --------------+--------------------- ! {1,2,NULL,4} | {one,two,NULL,four} ! (1 row) ! ! update arrtest1 set i[2] = 22, t[2] = 'twenty-two'; ! select * from arrtest1; ! i | t ! ---------------+---------------------------- ! {1,22,NULL,4} | {one,twenty-two,NULL,four} ! (1 row) ! ! update arrtest1 set i[5] = 5, t[5] = 'five'; ! select * from arrtest1; ! i | t ! -----------------+--------------------------------- ! {1,22,NULL,4,5} | {one,twenty-two,NULL,four,five} ! (1 row) ! ! update arrtest1 set i[8] = 8, t[8] = 'eight'; ! select * from arrtest1; ! i | t ! -----------------------------+------------------------------------------------- ! {1,22,NULL,4,5,NULL,NULL,8} | {one,twenty-two,NULL,four,five,NULL,NULL,eight} ! (1 row) ! ! update arrtest1 set i[0] = 0, t[0] = 'zero'; ! select * from arrtest1; ! i | t ! -------------------------------------+------------------------------------------------------------ ! [0:8]={0,1,22,NULL,4,5,NULL,NULL,8} | [0:8]={zero,one,twenty-two,NULL,four,five,NULL,NULL,eight} ! (1 row) ! ! update arrtest1 set i[-3] = -3, t[-3] = 'minus-three'; ! select * from arrtest1; ! i | t ! ---------------------------------------------------+----------------------------------------------------------------------------------- ! [-3:8]={-3,NULL,NULL,0,1,22,NULL,4,5,NULL,NULL,8} | [-3:8]={minus-three,NULL,NULL,zero,one,twenty-two,NULL,four,five,NULL,NULL,eight} ! (1 row) ! ! update arrtest1 set i[0:2] = array[10,11,12], t[0:2] = array['ten','eleven','twelve']; ! select * from arrtest1; ! i | t ! -----------------------------------------------------+--------------------------------------------------------------------------------- ! [-3:8]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,8} | [-3:8]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,eight} ! (1 row) ! ! update arrtest1 set i[8:10] = array[18,null,20], t[8:10] = array['p18',null,'p20']; ! select * from arrtest1; ! i | t ! ---------------------------------------------------------------+----------------------------------------------------------------------------------------- ! [-3:10]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20} | [-3:10]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20} ! (1 row) ! ! update arrtest1 set i[11:12] = array[null,22], t[11:12] = array[null,'p22']; ! select * from arrtest1; ! i | t ! -----------------------------------------------------------------------+-------------------------------------------------------------------------------------------------- ! [-3:12]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22} | [-3:12]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22} ! (1 row) ! ! update arrtest1 set i[15:16] = array[null,26], t[15:16] = array[null,'p26']; ! select * from arrtest1; ! i | t ! -----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------- ! [-3:16]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-3:16]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} ! (1 row) ! ! update arrtest1 set i[-5:-3] = array[-15,-14,-13], t[-5:-3] = array['m15','m14','m13']; ! select * from arrtest1; ! i | t ! --------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------- ! [-5:16]={-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-5:16]={m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} ! (1 row) ! ! update arrtest1 set i[-7:-6] = array[-17,null], t[-7:-6] = array['m17',null]; ! select * from arrtest1; ! i | t ! -----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------ ! [-7:16]={-17,NULL,-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-7:16]={m17,NULL,m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} ! (1 row) ! ! update arrtest1 set i[-12:-10] = array[-22,null,-20], t[-12:-10] = array['m22',null,'m20']; ! select * from arrtest1; ! i | t ! -----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------ ! [-12:16]={-22,NULL,-20,NULL,NULL,-17,NULL,-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-12:16]={m22,NULL,m20,NULL,NULL,m17,NULL,m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} ! (1 row) ! ! delete from arrtest1; ! insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); ! select * from arrtest1; ! i | t ! --------------+--------------------- ! {1,2,NULL,4} | {one,two,NULL,four} ! (1 row) ! ! update arrtest1 set i[0:5] = array[0,1,2,null,4,5], t[0:5] = array['z','p1','p2',null,'p4','p5']; ! select * from arrtest1; ! i | t ! ------------------------+---------------------------- ! [0:5]={0,1,2,NULL,4,5} | [0:5]={z,p1,p2,NULL,p4,p5} ! (1 row) ! ! -- ! -- array expressions and operators ! -- ! -- table creation and INSERTs ! CREATE TEMP TABLE arrtest2 (i integer ARRAY[4], f float8[], n numeric[], t text[], d timestamp[]); ! INSERT INTO arrtest2 VALUES( ! ARRAY[[[113,142],[1,147]]], ! ARRAY[1.1,1.2,1.3]::float8[], ! ARRAY[1.1,1.2,1.3], ! ARRAY[[['aaa','aab'],['aba','abb'],['aca','acb']],[['baa','bab'],['bba','bbb'],['bca','bcb']]], ! ARRAY['19620326','19931223','19970117']::timestamp[] ! ); ! -- some more test data ! CREATE TEMP TABLE arrtest_f (f0 int, f1 text, f2 float8); ! insert into arrtest_f values(1,'cat1',1.21); ! insert into arrtest_f values(2,'cat1',1.24); ! insert into arrtest_f values(3,'cat1',1.18); ! insert into arrtest_f values(4,'cat1',1.26); ! insert into arrtest_f values(5,'cat1',1.15); ! insert into arrtest_f values(6,'cat2',1.15); ! insert into arrtest_f values(7,'cat2',1.26); ! insert into arrtest_f values(8,'cat2',1.32); ! insert into arrtest_f values(9,'cat2',1.30); ! CREATE TEMP TABLE arrtest_i (f0 int, f1 text, f2 int); ! insert into arrtest_i values(1,'cat1',21); ! insert into arrtest_i values(2,'cat1',24); ! insert into arrtest_i values(3,'cat1',18); ! insert into arrtest_i values(4,'cat1',26); ! insert into arrtest_i values(5,'cat1',15); ! insert into arrtest_i values(6,'cat2',15); ! insert into arrtest_i values(7,'cat2',26); ! insert into arrtest_i values(8,'cat2',32); ! insert into arrtest_i values(9,'cat2',30); ! -- expressions ! SELECT t.f[1][3][1] AS "131", t.f[2][2][1] AS "221" FROM ( ! SELECT ARRAY[[[111,112],[121,122],[131,132]],[[211,212],[221,122],[231,232]]] AS f ! ) AS t; ! 131 | 221 ! -----+----- ! 131 | 221 ! (1 row) ! ! SELECT ARRAY[[[[[['hello'],['world']]]]]]; ! array ! --------------------------- ! {{{{{{hello},{world}}}}}} ! (1 row) ! ! SELECT ARRAY[ARRAY['hello'],ARRAY['world']]; ! array ! ------------------- ! {{hello},{world}} ! (1 row) ! ! SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY"; ! ARRAY ! ----------------------------------------------- ! {1.15,1.15,1.18,1.21,1.24,1.26,1.26,1.3,1.32} ! (1 row) ! ! -- with nulls ! SELECT '{1,null,3}'::int[]; ! int4 ! ------------ ! {1,NULL,3} ! (1 row) ! ! SELECT ARRAY[1,NULL,3]; ! array ! ------------ ! {1,NULL,3} ! (1 row) ! ! -- functions ! SELECT array_append(array[42], 6) AS "{42,6}"; ! {42,6} ! -------- ! {42,6} ! (1 row) ! ! SELECT array_prepend(6, array[42]) AS "{6,42}"; ! {6,42} ! -------- ! {6,42} ! (1 row) ! ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; ! {1,2,3,4} ! ----------- ! {1,2,3,4} ! (1 row) ! ! SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; ! {{1,2},{3,4},{5,6}} ! --------------------- ! {{1,2},{3,4},{5,6}} ! (1 row) ! ! SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; ! {{3,4},{5,6},{1,2}} ! --------------------- ! {{3,4},{5,6},{1,2}} ! (1 row) ! ! -- operators ! SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; ! a ! --------------- ! {16,25,3,4,5} ! (1 row) ! ! SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; ! FALSE ! ------- ! f ! (1 row) ! ! SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; ! {1,2,3} ! --------- ! {1,2,3} ! (1 row) ! ! SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; ! {0,1,2} ! --------- ! {0,1,2} ! (1 row) ! ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; ! {1,2,3,4} ! ----------- ! {1,2,3,4} ! (1 row) ! ! SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; ! ARRAY ! -------------------------------------- ! {{{hello,world}},{{happy,birthday}}} ! (1 row) ! ! SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; ! {{1,2},{3,4},{5,6}} ! --------------------- ! {{1,2},{3,4},{5,6}} ! (1 row) ! ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; ! {0,0,1,1,2,2} ! --------------- ! {0,0,1,1,2,2} ! (1 row) ! ! SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; ! {0,1,2,3} ! ----------- ! {0,1,2,3} ! (1 row) ! ! SELECT * FROM array_op_test WHERE i @> '{32}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} ! (6 rows) ! ! SELECT * FROM array_op_test WHERE i && '{32}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} ! (6 rows) ! ! SELECT * FROM array_op_test WHERE i @> '{17}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} ! 53 | {38,17} | {AAAAAAAAAAA21658} ! 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! (8 rows) ! ! SELECT * FROM array_op_test WHERE i && '{17}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} ! 53 | {38,17} | {AAAAAAAAAAA21658} ! 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! (8 rows) ! ! SELECT * FROM array_op_test WHERE i @> '{32,17}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! (3 rows) ! ! SELECT * FROM array_op_test WHERE i && '{32,17}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------ ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} ! 53 | {38,17} | {AAAAAAAAAAA21658} ! 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} ! (11 rows) ! ! SELECT * FROM array_op_test WHERE i <@ '{38,34,32,89}' ORDER BY seqno; ! seqno | i | t ! -------+---------------+---------------------------------------------------------------------------------------------------------------------------- ! 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 101 | {} | {} ! (4 rows) ! ! SELECT * FROM array_op_test WHERE i = '{}' ORDER BY seqno; ! seqno | i | t ! -------+----+---- ! 101 | {} | {} ! (1 row) ! ! SELECT * FROM array_op_test WHERE i @> '{}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ! 1 | {92,75,71,52,64,83} | {AAAAAAAA44066,AAAAAA1059,AAAAAAAAAAA176,AAAAAAA48038} ! 2 | {3,6} | {AAAAAA98232,AAAAAAAA79710,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAAAAAAA55798,AAAAAAAAA12793} ! 3 | {37,64,95,43,3,41,13,30,11,43} | {AAAAAAAAAA48845,AAAAA75968,AAAAA95309,AAA54451,AAAAAAAAAA22292,AAAAAAA99836,A96617,AA17009,AAAAAAAAAAAAAA95246} ! 4 | {71,39,99,55,33,75,45} | {AAAAAAAAA53663,AAAAAAAAAAAAAAA67062,AAAAAAAAAA64777,AAA99043,AAAAAAAAAAAAAAAAAAA91804,39557} ! 5 | {50,42,77,50,4} | {AAAAAAAAAAAAAAAAA26540,AAAAAAA79710,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA176,AAAAA95309,AAAAAAAAAAA46154,AAAAAA66777,AAAAAAAAA27249,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA70104} ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 7 | {12,51,88,64,8} | {AAAAAAAAAAAAAAAAAA12591,AAAAAAAAAAAAAAAAA50407,AAAAAAAAAAAA67946} ! 8 | {60,84} | {AAAAAAA81898,AAAAAA1059,AAAAAAAAAAAA81511,AAAAA961,AAAAAAAAAAAAAAAA31334,AAAAA64741,AA6416,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAA50407} ! 9 | {56,52,35,27,80,44,81,22} | {AAAAAAAAAAAAAAA73034,AAAAAAAAAAAAA7929,AAAAAAA66161,AA88409,39557,A27153,AAAAAAAA9523,AAAAAAAAAAA99000} ! 10 | {71,5,45} | {AAAAAAAAAAA21658,AAAAAAAAAAAA21089,AAA54451,AAAAAAAAAAAAAAAAAA54141,AAAAAAAAAAAAAA28620,AAAAAAAAAAA21658,AAAAAAAAAAA74076,AAAAAAAAA27249} ! 11 | {41,86,74,48,22,74,47,50} | {AAAAAAAA9523,AAAAAAAAAAAA37562,AAAAAAAAAAAAAAAA14047,AAAAAAAAAAA46154,AAAA41702,AAAAAAAAAAAAAAAAA764,AAAAA62737,39557} ! 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} ! 13 | {3,52,34,23} | {AAAAAA98232,AAAA49534,AAAAAAAAAAA21658} ! 14 | {78,57,19} | {AAAA8857,AAAAAAAAAAAAAAA73034,AAAAAAAA81587,AAAAAAAAAAAAAAA68526,AAAAA75968,AAAAAAAAAAAAAA65909,AAAAAAAAA10012,AAAAAAAAAAAAAA65909} ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 16 | {14,63,85,11} | {AAAAAA66777} ! 17 | {7,10,81,85} | {AAAAAA43678,AAAAAAA12144,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAAAAA15356} ! 18 | {1} | {AAAAAAAAAAA33576,AAAAA95309,64261,AAA59323,AAAAAAAAAAAAAA95246,55847,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAAAA64374} ! 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} ! 20 | {72,89,70,51,54,37,8,49,79} | {AAAAAA58494} ! 21 | {2,8,65,10,5,79,43} | {AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAAAAA91804,AAAAA64669,AAAAAAAAAAAAAAAA1443,AAAAAAAAAAAAAAAA23657,AAAAA12179,AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAA31334,AAAAAAAAAAAAAAAA41303,AAAAAAAAAAAAAAAAAAA85420} ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 23 | {40,90,5,38,72,40,30,10,43,55} | {A6053,AAAAAAAAAAA6119,AA44673,AAAAAAAAAAAAAAAAA764,AA17009,AAAAA17383,AAAAA70514,AAAAA33250,AAAAA95309,AAAAAAAAAAAA37562} ! 24 | {94,61,99,35,48} | {AAAAAAAAAAA50956,AAAAAAAAAAA15165,AAAA85070,AAAAAAAAAAAAAAA36627,AAAAA961,AAAAAAAAAA55219} ! 25 | {31,1,10,11,27,79,38} | {AAAAAAAAAAAAAAAAAA59334,45449} ! 26 | {71,10,9,69,75} | {47735,AAAAAAA21462,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA91804,AAAAAAAAA72121,AAAAAAAAAAAAAAAAAAA1205,AAAAA41597,AAAA8857,AAAAAAAAAAAAAAAAAAA15356,AA17009} ! 27 | {94} | {AA6416,A6053,AAAAAAA21462,AAAAAAA57334,AAAAAAAAAAAAAAAAAA12591,AA88409,AAAAAAAAAAAAA70254} ! 28 | {14,33,6,34,14} | {AAAAAAAAAAAAAAA13198,AAAAAAAA69452,AAAAAAAAAAA82945,AAAAAAA12144,AAAAAAAAA72121,AAAAAAAAAA18601} ! 29 | {39,21} | {AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA38885,AAAA85070,AAAAAAAAAAAAAAAAAAA70104,AAAAA66674,AAAAAAAAAAAAA62007,AAAAAAAA69452,AAAAAAA1242,AAAAAAAAAAAAAAAA1729,AAAA35194} ! 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} ! 31 | {80,24,18,21,54} | {AAAAAAAAAAAAAAA13198,AAAAAAAAAAAAAAAAAAA70415,A27153,AAAAAAAAA53663,AAAAAAAAAAAAAAAAA50407,A68938} ! 32 | {58,79,82,80,67,75,98,10,41} | {AAAAAAAAAAAAAAAAAA61286,AAA54451,AAAAAAAAAAAAAAAAAAA87527,A96617,51533} ! 33 | {74,73} | {A85417,AAAAAAA56483,AAAAA17383,AAAAAAAAAAAAA62159,AAAAAAAAAAAA52814,AAAAAAAAAAAAA85723,AAAAAAAAAAAAAAAAAA55796} ! 34 | {70,45} | {AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAA28620,AAAAAAAAAA55219,AAAAAAAA23648,AAAAAAAAAA22292,AAAAAAA1242} ! 35 | {23,40} | {AAAAAAAAAAAA52814,AAAA48949,AAAAAAAAA34727,AAAA8857,AAAAAAAAAAAAAAAAAAA62179,AAAAAAAAAAAAAAA68526,AAAAAAA99836,AAAAAAAA50094,AAAA91194,AAAAAAAAAAAAA73084} ! 36 | {79,82,14,52,30,5,79} | {AAAAAAAAA53663,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA89194,AA88409,AAAAAAAAAAAAAAA81326,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAA33598} ! 37 | {53,11,81,39,3,78,58,64,74} | {AAAAAAAAAAAAAAAAAAA17075,AAAAAAA66161,AAAAAAAA23648,AAAAAAAAAAAAAA10611} ! 38 | {59,5,4,95,28} | {AAAAAAAAAAA82945,A96617,47735,AAAAA12179,AAAAA64669,AAAAAA99807,AA74433,AAAAAAAAAAAAAAAAA59387} ! 39 | {82,43,99,16,74} | {AAAAAAAAAAAAAAA67062,AAAAAAA57334,AAAAAAAAAAAAAA65909,A27153,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAA64777,AAAAAAAAAAAA81511,AAAAAAAAAAAAAA65909,AAAAAAAAAAAAAA28620} ! 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} ! 41 | {19,26,63,12,93,73,27,94} | {AAAAAAA79710,AAAAAAAAAA55219,AAAA41702,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAAAAA63050,AAAAAAA99836,AAAAAAAAAAAAAA8666} ! 42 | {15,76,82,75,8,91} | {AAAAAAAAAAA176,AAAAAA38063,45449,AAAAAA54032,AAAAAAA81898,AA6416,AAAAAAAAAAAAAAAAAAA62179,45449,AAAAA60038,AAAAAAAA81587} ! 43 | {39,87,91,97,79,28} | {AAAAAAAAAAA74076,A96617,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAAAAA55796,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAA67946} ! 44 | {40,58,68,29,54} | {AAAAAAA81898,AAAAAA66777,AAAAAA98232} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 46 | {53,24} | {AAAAAAAAAAA53908,AAAAAA54032,AAAAA17383,AAAA48949,AAAAAAAAAA18601,AAAAA64669,45449,AAAAAAAAAAA98051,AAAAAAAAAAAAAAAAAA71621} ! 47 | {98,23,64,12,75,61} | {AAA59323,AAAAA95309,AAAAAAAAAAAAAAAA31334,AAAAAAAAA27249,AAAAA17383,AAAAAAAAAAAA37562,AAAAAA1059,A84822,55847,AAAAA70466} ! 48 | {76,14} | {AAAAAAAAAAAAA59671,AAAAAAAAAAAAAAAAAAA91804,AAAAAA66777,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAA73084,AAAAAAA79710,AAAAAAAAAAAAAAA40402,AAAAAAAAAAAAAAAAAAA65037} ! 49 | {56,5,54,37,49} | {AA21643,AAAAAAAAAAA92631,AAAAAAAA81587} ! 50 | {20,12,37,64,93} | {AAAAAAAAAA5483,AAAAAAAAAAAAAAAAAAA1205,AA6416,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAAAA47955} ! 51 | {47} | {AAAAAAAAAAAAAA96505,AAAAAAAAAAAAAAAAAA36842,AAAAA95309,AAAAAAAA81587,AA6416,AAAA91194,AAAAAA58494,AAAAAA1059,AAAAAAAA69452} ! 52 | {89,0} | {AAAAAAAAAAAAAAAAAA47955,AAAAAAA48038,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAA73084,AAAAA70466,AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA46154,AA66862} ! 53 | {38,17} | {AAAAAAAAAAA21658} ! 54 | {70,47} | {AAAAAAAAAAAAAAAAAA54141,AAAAA40681,AAAAAAA48038,AAAAAAAAAAAAAAAA29150,AAAAA41597,AAAAAAAAAAAAAAAAAA59334,AA15322} ! 55 | {47,79,47,64,72,25,71,24,93} | {AAAAAAAAAAAAAAAAAA55796,AAAAA62737} ! 56 | {33,7,60,54,93,90,77,85,39} | {AAAAAAAAAAAAAAAAAA32918,AA42406} ! 57 | {23,45,10,42,36,21,9,96} | {AAAAAAAAAAAAAAAAAAA70415} ! 58 | {92} | {AAAAAAAAAAAAAAAA98414,AAAAAAAA23648,AAAAAAAAAAAAAAAAAA55796,AA25381,AAAAAAAAAAA6119} ! 59 | {9,69,46,77} | {39557,AAAAAAA89932,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAAAAAA26540,AAA20874,AA6416,AAAAAAAAAAAAAAAAAA47955} ! 60 | {62,2,59,38,89} | {AAAAAAA89932,AAAAAAAAAAAAAAAAAAA15356,AA99927,AA17009,AAAAAAAAAAAAAAA35875} ! 61 | {72,2,44,95,54,54,13} | {AAAAAAAAAAAAAAAAAAA91804} ! 62 | {83,72,29,73} | {AAAAAAAAAAAAA15097,AAAA8857,AAAAAAAAAAAA35809,AAAAAAAAAAAA52814,AAAAAAAAAAAAAAAAAAA38885,AAAAAAAAAAAAAAAAAA24183,AAAAAA43678,A96617} ! 63 | {11,4,61,87} | {AAAAAAAAA27249,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAA13198,AAA20874,39557,51533,AAAAAAAAAAA53908,AAAAAAAAAAAAAA96505,AAAAAAAA78938} ! 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} ! 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} ! 66 | {31,23,70,52,4,33,48,25} | {AAAAAAAAAAAAAAAAA69675,AAAAAAAA50094,AAAAAAAAAAA92631,AAAA35194,39557,AAAAAAA99836} ! 67 | {31,94,7,10} | {AAAAAA38063,A96617,AAAA35194,AAAAAAAAAAAA67946} ! 68 | {90,43,38} | {AA75092,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAA92631,AAAAAAAAA10012,AAAAAAAAAAAAA7929,AA21643} ! 69 | {67,35,99,85,72,86,44} | {AAAAAAAAAAAAAAAAAAA1205,AAAAAAAA50094,AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAAAAAAA47955} ! 70 | {56,70,83} | {AAAA41702,AAAAAAAAAAA82945,AA21643,AAAAAAAAAAA99000,A27153,AA25381,AAAAAAAAAAAAAA96505,AAAAAAA1242} ! 71 | {74,26} | {AAAAAAAAAAA50956,AA74433,AAAAAAA21462,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAA70254,AAAAAAAAAA43419,39557} ! 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} ! 73 | {88,25,96,78,65,15,29,19} | {AAA54451,AAAAAAAAA27249,AAAAAAA9228,AAAAAAAAAAAAAAA67062,AAAAAAAAAAAAAAAAAAA70415,AAAAA17383,AAAAAAAAAAAAAAAA33598} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 75 | {12,96,83,24,71,89,55} | {AAAA48949,AAAAAAAA29716,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAA29150,AAA28075,AAAAAAAAAAAAAAAAA43052} ! 76 | {92,55,10,7} | {AAAAAAAAAAAAAAA67062} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 78 | {55,89,44,84,34} | {AAAAAAAAAAA6119,AAAAAAAAAAAAAA8666,AA99927,AA42406,AAAAAAA81898,AAAAAAA9228,AAAAAAAAAAA92631,AA21643,AAAAAAAAAAAAAA28620} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! 80 | {74,89,44,80,0} | {AAAA35194,AAAAAAAA79710,AAA20874,AAAAAAAAAAAAAAAAAAA70104,AAAAAAAAAAAAA73084,AAAAAAA57334,AAAAAAA9228,AAAAAAAAAAAAA62007} ! 81 | {63,77,54,48,61,53,97} | {AAAAAAAAAAAAAAA81326,AAAAAAAAAA22292,AA25381,AAAAAAAAAAA74076,AAAAAAA81898,AAAAAAAAA72121} ! 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} ! 83 | {14,10} | {AAAAAAAAAA22292,AAAAAAAAAAAAA70254,AAAAAAAAAAA6119} ! 84 | {11,83,35,13,96,94} | {AAAAA95309,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAAA24183} ! 85 | {39,60} | {AAAAAAAAAAAAAAAA55798,AAAAAAAAAA22292,AAAAAAA66161,AAAAAAA21462,AAAAAAAAAAAAAAAAAA12591,55847,AAAAAA98232,AAAAAAAAAAA46154} ! 86 | {33,81,72,74,45,36,82} | {AAAAAAAA81587,AAAAAAAAAAAAAA96505,45449,AAAA80176} ! 87 | {57,27,50,12,97,68} | {AAAAAAAAAAAAAAAAA26540,AAAAAAAAA10012,AAAAAAAAAAAA35809,AAAAAAAAAAAAAAAA29150,AAAAAAAAAAA82945,AAAAAA66777,31228,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAA96505} ! 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! 90 | {88,75} | {AAAAA60038,AAAAAAAA23648,AAAAAAAAAAA99000,AAAA41702,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAA68526} ! 91 | {78} | {AAAAAAAAAAAAA62007,AAA99043} ! 92 | {85,63,49,45} | {AAAAAAA89932,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA21089} ! 93 | {11} | {AAAAAAAAAAA176,AAAAAAAAAAAAAA8666,AAAAAAAAAAAAAAA453,AAAAAAAAAAAAA85723,A68938,AAAAAAAAAAAAA9821,AAAAAAA48038,AAAAAAAAAAAAAAAAA59387,AA99927,AAAAA17383} ! 94 | {98,9,85,62,88,91,60,61,38,86} | {AAAAAAAA81587,AAAAA17383,AAAAAAAA81587} ! 95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483} ! 96 | {23,97,43} | {AAAAAAAAAA646,A87088} ! 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 99 | {37,86} | {AAAAAAAAAAAAAAAAAA32918,AAAAA70514,AAAAAAAAA10012,AAAAAAAAAAAAAAAAA59387,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA15356} ! 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} ! 101 | {} | {} ! 102 | {NULL} | {NULL} ! (102 rows) ! ! SELECT * FROM array_op_test WHERE i && '{}' ORDER BY seqno; ! seqno | i | t ! -------+---+--- ! (0 rows) ! ! SELECT * FROM array_op_test WHERE i <@ '{}' ORDER BY seqno; ! seqno | i | t ! -------+----+---- ! 101 | {} | {} ! (1 row) ! ! SELECT * FROM array_op_test WHERE i = '{NULL}' ORDER BY seqno; ! seqno | i | t ! -------+--------+-------- ! 102 | {NULL} | {NULL} ! (1 row) ! ! SELECT * FROM array_op_test WHERE i @> '{NULL}' ORDER BY seqno; ! seqno | i | t ! -------+---+--- ! (0 rows) ! ! SELECT * FROM array_op_test WHERE i && '{NULL}' ORDER BY seqno; ! seqno | i | t ! -------+---+--- ! (0 rows) ! ! SELECT * FROM array_op_test WHERE i <@ '{NULL}' ORDER BY seqno; ! seqno | i | t ! -------+----+---- ! 101 | {} | {} ! (1 row) ! ! SELECT * FROM array_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno; ! seqno | i | t ! -------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! (4 rows) ! ! SELECT * FROM array_op_test WHERE t && '{AAAAAAAA72908}' ORDER BY seqno; ! seqno | i | t ! -------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! (4 rows) ! ! SELECT * FROM array_op_test WHERE t @> '{AAAAAAAAAA646}' ORDER BY seqno; ! seqno | i | t ! -------+------------------+-------------------------------------------------------------------- ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! 96 | {23,97,43} | {AAAAAAAAAA646,A87088} ! (3 rows) ! ! SELECT * FROM array_op_test WHERE t && '{AAAAAAAAAA646}' ORDER BY seqno; ! seqno | i | t ! -------+------------------+-------------------------------------------------------------------- ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! 96 | {23,97,43} | {AAAAAAAAAA646,A87088} ! (3 rows) ! ! SELECT * FROM array_op_test WHERE t @> '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno; ! seqno | i | t ! -------+------+-------------------------------------------------------------------- ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! (1 row) ! ! SELECT * FROM array_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno; ! seqno | i | t ! -------+-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------- ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! 96 | {23,97,43} | {AAAAAAAAAA646,A87088} ! (6 rows) ! ! SELECT * FROM array_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}' ORDER BY seqno; ! seqno | i | t ! -------+--------------------+----------------------------------------------------------------------------------------------------------- ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 101 | {} | {} ! (3 rows) ! ! SELECT * FROM array_op_test WHERE t = '{}' ORDER BY seqno; ! seqno | i | t ! -------+----+---- ! 101 | {} | {} ! (1 row) ! ! SELECT * FROM array_op_test WHERE t @> '{}' ORDER BY seqno; ! seqno | i | t ! -------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ! 1 | {92,75,71,52,64,83} | {AAAAAAAA44066,AAAAAA1059,AAAAAAAAAAA176,AAAAAAA48038} ! 2 | {3,6} | {AAAAAA98232,AAAAAAAA79710,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAAAAAAA55798,AAAAAAAAA12793} ! 3 | {37,64,95,43,3,41,13,30,11,43} | {AAAAAAAAAA48845,AAAAA75968,AAAAA95309,AAA54451,AAAAAAAAAA22292,AAAAAAA99836,A96617,AA17009,AAAAAAAAAAAAAA95246} ! 4 | {71,39,99,55,33,75,45} | {AAAAAAAAA53663,AAAAAAAAAAAAAAA67062,AAAAAAAAAA64777,AAA99043,AAAAAAAAAAAAAAAAAAA91804,39557} ! 5 | {50,42,77,50,4} | {AAAAAAAAAAAAAAAAA26540,AAAAAAA79710,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA176,AAAAA95309,AAAAAAAAAAA46154,AAAAAA66777,AAAAAAAAA27249,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA70104} ! 6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657} ! 7 | {12,51,88,64,8} | {AAAAAAAAAAAAAAAAAA12591,AAAAAAAAAAAAAAAAA50407,AAAAAAAAAAAA67946} ! 8 | {60,84} | {AAAAAAA81898,AAAAAA1059,AAAAAAAAAAAA81511,AAAAA961,AAAAAAAAAAAAAAAA31334,AAAAA64741,AA6416,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAA50407} ! 9 | {56,52,35,27,80,44,81,22} | {AAAAAAAAAAAAAAA73034,AAAAAAAAAAAAA7929,AAAAAAA66161,AA88409,39557,A27153,AAAAAAAA9523,AAAAAAAAAAA99000} ! 10 | {71,5,45} | {AAAAAAAAAAA21658,AAAAAAAAAAAA21089,AAA54451,AAAAAAAAAAAAAAAAAA54141,AAAAAAAAAAAAAA28620,AAAAAAAAAAA21658,AAAAAAAAAAA74076,AAAAAAAAA27249} ! 11 | {41,86,74,48,22,74,47,50} | {AAAAAAAA9523,AAAAAAAAAAAA37562,AAAAAAAAAAAAAAAA14047,AAAAAAAAAAA46154,AAAA41702,AAAAAAAAAAAAAAAAA764,AAAAA62737,39557} ! 12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576} ! 13 | {3,52,34,23} | {AAAAAA98232,AAAA49534,AAAAAAAAAAA21658} ! 14 | {78,57,19} | {AAAA8857,AAAAAAAAAAAAAAA73034,AAAAAAAA81587,AAAAAAAAAAAAAAA68526,AAAAA75968,AAAAAAAAAAAAAA65909,AAAAAAAAA10012,AAAAAAAAAAAAAA65909} ! 15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309} ! 16 | {14,63,85,11} | {AAAAAA66777} ! 17 | {7,10,81,85} | {AAAAAA43678,AAAAAAA12144,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAAAAA15356} ! 18 | {1} | {AAAAAAAAAAA33576,AAAAA95309,64261,AAA59323,AAAAAAAAAAAAAA95246,55847,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAAAA64374} ! 19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938} ! 20 | {72,89,70,51,54,37,8,49,79} | {AAAAAA58494} ! 21 | {2,8,65,10,5,79,43} | {AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAAAAA91804,AAAAA64669,AAAAAAAAAAAAAAAA1443,AAAAAAAAAAAAAAAA23657,AAAAA12179,AAAAAAAAAAAAAAAAA88852,AAAAAAAAAAAAAAAA31334,AAAAAAAAAAAAAAAA41303,AAAAAAAAAAAAAAAAAAA85420} ! 22 | {11,6,56,62,53,30} | {AAAAAAAA72908} ! 23 | {40,90,5,38,72,40,30,10,43,55} | {A6053,AAAAAAAAAAA6119,AA44673,AAAAAAAAAAAAAAAAA764,AA17009,AAAAA17383,AAAAA70514,AAAAA33250,AAAAA95309,AAAAAAAAAAAA37562} ! 24 | {94,61,99,35,48} | {AAAAAAAAAAA50956,AAAAAAAAAAA15165,AAAA85070,AAAAAAAAAAAAAAA36627,AAAAA961,AAAAAAAAAA55219} ! 25 | {31,1,10,11,27,79,38} | {AAAAAAAAAAAAAAAAAA59334,45449} ! 26 | {71,10,9,69,75} | {47735,AAAAAAA21462,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA91804,AAAAAAAAA72121,AAAAAAAAAAAAAAAAAAA1205,AAAAA41597,AAAA8857,AAAAAAAAAAAAAAAAAAA15356,AA17009} ! 27 | {94} | {AA6416,A6053,AAAAAAA21462,AAAAAAA57334,AAAAAAAAAAAAAAAAAA12591,AA88409,AAAAAAAAAAAAA70254} ! 28 | {14,33,6,34,14} | {AAAAAAAAAAAAAAA13198,AAAAAAAA69452,AAAAAAAAAAA82945,AAAAAAA12144,AAAAAAAAA72121,AAAAAAAAAA18601} ! 29 | {39,21} | {AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAAAAA38885,AAAA85070,AAAAAAAAAAAAAAAAAAA70104,AAAAA66674,AAAAAAAAAAAAA62007,AAAAAAAA69452,AAAAAAA1242,AAAAAAAAAAAAAAAA1729,AAAA35194} ! 30 | {26,81,47,91,34} | {AAAAAAAAAAAAAAAAAAA70104,AAAAAAA80240} ! 31 | {80,24,18,21,54} | {AAAAAAAAAAAAAAA13198,AAAAAAAAAAAAAAAAAAA70415,A27153,AAAAAAAAA53663,AAAAAAAAAAAAAAAAA50407,A68938} ! 32 | {58,79,82,80,67,75,98,10,41} | {AAAAAAAAAAAAAAAAAA61286,AAA54451,AAAAAAAAAAAAAAAAAAA87527,A96617,51533} ! 33 | {74,73} | {A85417,AAAAAAA56483,AAAAA17383,AAAAAAAAAAAAA62159,AAAAAAAAAAAA52814,AAAAAAAAAAAAA85723,AAAAAAAAAAAAAAAAAA55796} ! 34 | {70,45} | {AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAA28620,AAAAAAAAAA55219,AAAAAAAA23648,AAAAAAAAAA22292,AAAAAAA1242} ! 35 | {23,40} | {AAAAAAAAAAAA52814,AAAA48949,AAAAAAAAA34727,AAAA8857,AAAAAAAAAAAAAAAAAAA62179,AAAAAAAAAAAAAAA68526,AAAAAAA99836,AAAAAAAA50094,AAAA91194,AAAAAAAAAAAAA73084} ! 36 | {79,82,14,52,30,5,79} | {AAAAAAAAA53663,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA89194,AA88409,AAAAAAAAAAAAAAA81326,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAA33598} ! 37 | {53,11,81,39,3,78,58,64,74} | {AAAAAAAAAAAAAAAAAAA17075,AAAAAAA66161,AAAAAAAA23648,AAAAAAAAAAAAAA10611} ! 38 | {59,5,4,95,28} | {AAAAAAAAAAA82945,A96617,47735,AAAAA12179,AAAAA64669,AAAAAA99807,AA74433,AAAAAAAAAAAAAAAAA59387} ! 39 | {82,43,99,16,74} | {AAAAAAAAAAAAAAA67062,AAAAAAA57334,AAAAAAAAAAAAAA65909,A27153,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAA64777,AAAAAAAAAAAA81511,AAAAAAAAAAAAAA65909,AAAAAAAAAAAAAA28620} ! 40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623} ! 41 | {19,26,63,12,93,73,27,94} | {AAAAAAA79710,AAAAAAAAAA55219,AAAA41702,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA71621,AAAAAAAAAAAAAAAAA63050,AAAAAAA99836,AAAAAAAAAAAAAA8666} ! 42 | {15,76,82,75,8,91} | {AAAAAAAAAAA176,AAAAAA38063,45449,AAAAAA54032,AAAAAAA81898,AA6416,AAAAAAAAAAAAAAAAAAA62179,45449,AAAAA60038,AAAAAAAA81587} ! 43 | {39,87,91,97,79,28} | {AAAAAAAAAAA74076,A96617,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAAAAA55796,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAA67946} ! 44 | {40,58,68,29,54} | {AAAAAAA81898,AAAAAA66777,AAAAAA98232} ! 45 | {99,45} | {AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611} ! 46 | {53,24} | {AAAAAAAAAAA53908,AAAAAA54032,AAAAA17383,AAAA48949,AAAAAAAAAA18601,AAAAA64669,45449,AAAAAAAAAAA98051,AAAAAAAAAAAAAAAAAA71621} ! 47 | {98,23,64,12,75,61} | {AAA59323,AAAAA95309,AAAAAAAAAAAAAAAA31334,AAAAAAAAA27249,AAAAA17383,AAAAAAAAAAAA37562,AAAAAA1059,A84822,55847,AAAAA70466} ! 48 | {76,14} | {AAAAAAAAAAAAA59671,AAAAAAAAAAAAAAAAAAA91804,AAAAAA66777,AAAAAAAAAAAAAAAAAAA89194,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAA73084,AAAAAAA79710,AAAAAAAAAAAAAAA40402,AAAAAAAAAAAAAAAAAAA65037} ! 49 | {56,5,54,37,49} | {AA21643,AAAAAAAAAAA92631,AAAAAAAA81587} ! 50 | {20,12,37,64,93} | {AAAAAAAAAA5483,AAAAAAAAAAAAAAAAAAA1205,AA6416,AAAAAAAAAAAAAAAAA63050,AAAAAAAAAAAAAAAAAA47955} ! 51 | {47} | {AAAAAAAAAAAAAA96505,AAAAAAAAAAAAAAAAAA36842,AAAAA95309,AAAAAAAA81587,AA6416,AAAA91194,AAAAAA58494,AAAAAA1059,AAAAAAAA69452} ! 52 | {89,0} | {AAAAAAAAAAAAAAAAAA47955,AAAAAAA48038,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAA73084,AAAAA70466,AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA46154,AA66862} ! 53 | {38,17} | {AAAAAAAAAAA21658} ! 54 | {70,47} | {AAAAAAAAAAAAAAAAAA54141,AAAAA40681,AAAAAAA48038,AAAAAAAAAAAAAAAA29150,AAAAA41597,AAAAAAAAAAAAAAAAAA59334,AA15322} ! 55 | {47,79,47,64,72,25,71,24,93} | {AAAAAAAAAAAAAAAAAA55796,AAAAA62737} ! 56 | {33,7,60,54,93,90,77,85,39} | {AAAAAAAAAAAAAAAAAA32918,AA42406} ! 57 | {23,45,10,42,36,21,9,96} | {AAAAAAAAAAAAAAAAAAA70415} ! 58 | {92} | {AAAAAAAAAAAAAAAA98414,AAAAAAAA23648,AAAAAAAAAAAAAAAAAA55796,AA25381,AAAAAAAAAAA6119} ! 59 | {9,69,46,77} | {39557,AAAAAAA89932,AAAAAAAAAAAAAAAAA43052,AAAAAAAAAAAAAAAAA26540,AAA20874,AA6416,AAAAAAAAAAAAAAAAAA47955} ! 60 | {62,2,59,38,89} | {AAAAAAA89932,AAAAAAAAAAAAAAAAAAA15356,AA99927,AA17009,AAAAAAAAAAAAAAA35875} ! 61 | {72,2,44,95,54,54,13} | {AAAAAAAAAAAAAAAAAAA91804} ! 62 | {83,72,29,73} | {AAAAAAAAAAAAA15097,AAAA8857,AAAAAAAAAAAA35809,AAAAAAAAAAAA52814,AAAAAAAAAAAAAAAAAAA38885,AAAAAAAAAAAAAAAAAA24183,AAAAAA43678,A96617} ! 63 | {11,4,61,87} | {AAAAAAAAA27249,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAA13198,AAA20874,39557,51533,AAAAAAAAAAA53908,AAAAAAAAAAAAAA96505,AAAAAAAA78938} ! 64 | {26,19,34,24,81,78} | {A96617,AAAAAAAAAAAAAAAAAAA70104,A68938,AAAAAAAAAAA53908,AAAAAAAAAAAAAAA453,AA17009,AAAAAAA80240} ! 65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012} ! 66 | {31,23,70,52,4,33,48,25} | {AAAAAAAAAAAAAAAAA69675,AAAAAAAA50094,AAAAAAAAAAA92631,AAAA35194,39557,AAAAAAA99836} ! 67 | {31,94,7,10} | {AAAAAA38063,A96617,AAAA35194,AAAAAAAAAAAA67946} ! 68 | {90,43,38} | {AA75092,AAAAAAAAAAAAAAAAA69675,AAAAAAAAAAA92631,AAAAAAAAA10012,AAAAAAAAAAAAA7929,AA21643} ! 69 | {67,35,99,85,72,86,44} | {AAAAAAAAAAAAAAAAAAA1205,AAAAAAAA50094,AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAAAAAAA47955} ! 70 | {56,70,83} | {AAAA41702,AAAAAAAAAAA82945,AA21643,AAAAAAAAAAA99000,A27153,AA25381,AAAAAAAAAAAAAA96505,AAAAAAA1242} ! 71 | {74,26} | {AAAAAAAAAAA50956,AA74433,AAAAAAA21462,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAA36627,AAAAAAAAAAAAA70254,AAAAAAAAAA43419,39557} ! 72 | {22,1,16,78,20,91,83} | {47735,AAAAAAA56483,AAAAAAAAAAAAA93788,AA42406,AAAAAAAAAAAAA73084,AAAAAAAA72908,AAAAAAAAAAAAAAAAAA61286,AAAAA66674,AAAAAAAAAAAAAAAAA50407} ! 73 | {88,25,96,78,65,15,29,19} | {AAA54451,AAAAAAAAA27249,AAAAAAA9228,AAAAAAAAAAAAAAA67062,AAAAAAAAAAAAAAAAAAA70415,AAAAA17383,AAAAAAAAAAAAAAAA33598} ! 74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956} ! 75 | {12,96,83,24,71,89,55} | {AAAA48949,AAAAAAAA29716,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA67946,AAAAAAAAAAAAAAAA29150,AAA28075,AAAAAAAAAAAAAAAAA43052} ! 76 | {92,55,10,7} | {AAAAAAAAAAAAAAA67062} ! 77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066} ! 78 | {55,89,44,84,34} | {AAAAAAAAAAA6119,AAAAAAAAAAAAAA8666,AA99927,AA42406,AAAAAAA81898,AAAAAAA9228,AAAAAAAAAAA92631,AA21643,AAAAAAAAAAAAAA28620} ! 79 | {45} | {AAAAAAAAAA646,AAAAAAAAAAAAAAAAAAA70415,AAAAAA43678,AAAAAAAA72908} ! 80 | {74,89,44,80,0} | {AAAA35194,AAAAAAAA79710,AAA20874,AAAAAAAAAAAAAAAAAAA70104,AAAAAAAAAAAAA73084,AAAAAAA57334,AAAAAAA9228,AAAAAAAAAAAAA62007} ! 81 | {63,77,54,48,61,53,97} | {AAAAAAAAAAAAAAA81326,AAAAAAAAAA22292,AA25381,AAAAAAAAAAA74076,AAAAAAA81898,AAAAAAAAA72121} ! 82 | {34,60,4,79,78,16,86,89,42,50} | {AAAAA40681,AAAAAAAAAAAAAAAAAA12591,AAAAAAA80240,AAAAAAAAAAAAAAAA55798,AAAAAAAAAAAAAAAAAAA70104} ! 83 | {14,10} | {AAAAAAAAAA22292,AAAAAAAAAAAAA70254,AAAAAAAAAAA6119} ! 84 | {11,83,35,13,96,94} | {AAAAA95309,AAAAAAAAAAAAAAAAAA32918,AAAAAAAAAAAAAAAAAA24183} ! 85 | {39,60} | {AAAAAAAAAAAAAAAA55798,AAAAAAAAAA22292,AAAAAAA66161,AAAAAAA21462,AAAAAAAAAAAAAAAAAA12591,55847,AAAAAA98232,AAAAAAAAAAA46154} ! 86 | {33,81,72,74,45,36,82} | {AAAAAAAA81587,AAAAAAAAAAAAAA96505,45449,AAAA80176} ! 87 | {57,27,50,12,97,68} | {AAAAAAAAAAAAAAAAA26540,AAAAAAAAA10012,AAAAAAAAAAAA35809,AAAAAAAAAAAAAAAA29150,AAAAAAAAAAA82945,AAAAAA66777,31228,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAA96505} ! 88 | {41,90,77,24,6,24} | {AAAA35194,AAAA35194,AAAAAAA80240,AAAAAAAAAAA46154,AAAAAA58494,AAAAAAAAAAAAAAAAAAA17075,AAAAAAAAAAAAAAAAAA59334,AAAAAAAAAAAAAAAAAAA91804,AA74433} ! 89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673} ! 90 | {88,75} | {AAAAA60038,AAAAAAAA23648,AAAAAAAAAAA99000,AAAA41702,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAA68526} ! 91 | {78} | {AAAAAAAAAAAAA62007,AAA99043} ! 92 | {85,63,49,45} | {AAAAAAA89932,AAAAAAAAAAAAA22860,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAAA21089} ! 93 | {11} | {AAAAAAAAAAA176,AAAAAAAAAAAAAA8666,AAAAAAAAAAAAAAA453,AAAAAAAAAAAAA85723,A68938,AAAAAAAAAAAAA9821,AAAAAAA48038,AAAAAAAAAAAAAAAAA59387,AA99927,AAAAA17383} ! 94 | {98,9,85,62,88,91,60,61,38,86} | {AAAAAAAA81587,AAAAA17383,AAAAAAAA81587} ! 95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483} ! 96 | {23,97,43} | {AAAAAAAAAA646,A87088} ! 97 | {54,2,86,65} | {47735,AAAAAAA99836,AAAAAAAAAAAAAAAAA6897,AAAAAAAAAAAAAAAA29150,AAAAAAA80240,AAAAAAAAAAAAAAAA98414,AAAAAAA56483,AAAAAAAAAAAAAAAA29150,AAAAAAA39692,AA21643} ! 98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845} ! 99 | {37,86} | {AAAAAAAAAAAAAAAAAA32918,AAAAA70514,AAAAAAAAA10012,AAAAAAAAAAAAAAAAA59387,AAAAAAAAAA64777,AAAAAAAAAAAAAAAAAAA15356} ! 100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523} ! 101 | {} | {} ! 102 | {NULL} | {NULL} ! (102 rows) ! ! SELECT * FROM array_op_test WHERE t && '{}' ORDER BY seqno; ! seqno | i | t ! -------+---+--- ! (0 rows) ! ! SELECT * FROM array_op_test WHERE t <@ '{}' ORDER BY seqno; ! seqno | i | t ! -------+----+---- ! 101 | {} | {} ! (1 row) ! ! -- array casts ! SELECT ARRAY[1,2,3]::text[]::int[]::float8[] AS "{1,2,3}"; ! {1,2,3} ! --------- ! {1,2,3} ! (1 row) ! ! SELECT ARRAY[1,2,3]::text[]::int[]::float8[] is of (float8[]) as "TRUE"; ! TRUE ! ------ ! t ! (1 row) ! ! SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] AS "{{a,bc},{def,hijk}}"; ! {{a,bc},{def,hijk}} ! --------------------- ! {{a,bc},{def,hijk}} ! (1 row) ! ! SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] is of (varchar[]) as "TRUE"; ! TRUE ! ------ ! t ! (1 row) ! ! SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}"; ! {{{{{{a,bb,ccc}}}}}} ! ---------------------- ! {{{{{{a,bb,ccc}}}}}} ! (1 row) ! ! -- scalar op any/all (array) ! select 33 = any ('{1,2,3}'); ! ?column? ! ---------- ! f ! (1 row) ! ! select 33 = any ('{1,2,33}'); ! ?column? ! ---------- ! t ! (1 row) ! ! select 33 = all ('{1,2,33}'); ! ?column? ! ---------- ! f ! (1 row) ! ! select 33 >= all ('{1,2,33}'); ! ?column? ! ---------- ! t ! (1 row) ! ! -- boundary cases ! select null::int >= all ('{1,2,33}'); ! ?column? ! ---------- ! ! (1 row) ! ! select null::int >= all ('{}'); ! ?column? ! ---------- ! t ! (1 row) ! ! select null::int >= any ('{}'); ! ?column? ! ---------- ! f ! (1 row) ! ! -- cross-datatype ! select 33.4 = any (array[1,2,3]); ! ?column? ! ---------- ! f ! (1 row) ! ! select 33.4 > all (array[1,2,3]); ! ?column? ! ---------- ! t ! (1 row) ! ! -- errors ! select 33 * any ('{1,2,3}'); ! ERROR: op ANY/ALL (array) requires operator to yield boolean ! LINE 1: select 33 * any ('{1,2,3}'); ! ^ ! select 33 * any (44); ! ERROR: op ANY/ALL (array) requires array on right side ! LINE 1: select 33 * any (44); ! ^ ! -- nulls ! select 33 = any (null::int[]); ! ?column? ! ---------- ! ! (1 row) ! ! select null::int = any ('{1,2,3}'); ! ?column? ! ---------- ! ! (1 row) ! ! select 33 = any ('{1,null,3}'); ! ?column? ! ---------- ! ! (1 row) ! ! select 33 = any ('{1,null,33}'); ! ?column? ! ---------- ! t ! (1 row) ! ! select 33 = all (null::int[]); ! ?column? ! ---------- ! ! (1 row) ! ! select null::int = all ('{1,2,3}'); ! ?column? ! ---------- ! ! (1 row) ! ! select 33 = all ('{1,null,3}'); ! ?column? ! ---------- ! f ! (1 row) ! ! select 33 = all ('{33,null,33}'); ! ?column? ! ---------- ! ! (1 row) ! ! -- test indexes on arrays ! create temp table arr_tbl (f1 int[] unique); ! insert into arr_tbl values ('{1,2,3}'); ! insert into arr_tbl values ('{1,2}'); ! -- failure expected: ! insert into arr_tbl values ('{1,2,3}'); ! ERROR: duplicate key value violates unique constraint "arr_tbl_f1_key" ! DETAIL: Key (f1)=({1,2,3}) already exists. ! insert into arr_tbl values ('{2,3,4}'); ! insert into arr_tbl values ('{1,5,3}'); ! insert into arr_tbl values ('{1,2,10}'); ! set enable_seqscan to off; ! set enable_bitmapscan to off; ! select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}'; ! f1 ! ---------- ! {1,2,10} ! {1,5,3} ! (2 rows) ! ! select * from arr_tbl where f1 >= '{1,2,3}' and f1 < '{1,5,3}'; ! f1 ! ---------- ! {1,2,3} ! {1,2,10} ! (2 rows) ! ! -- note: if above selects don't produce the expected tuple order, ! -- then you didn't get an indexscan plan, and something is busted. ! reset enable_seqscan; ! reset enable_bitmapscan; ! -- test [not] (like|ilike) (any|all) (...) ! select 'foo' like any (array['%a', '%o']); -- t ! ?column? ! ---------- ! t ! (1 row) ! ! select 'foo' like any (array['%a', '%b']); -- f ! ?column? ! ---------- ! f ! (1 row) ! ! select 'foo' like all (array['f%', '%o']); -- t ! ?column? ! ---------- ! t ! (1 row) ! ! select 'foo' like all (array['f%', '%b']); -- f ! ?column? ! ---------- ! f ! (1 row) ! ! select 'foo' not like any (array['%a', '%b']); -- t ! ?column? ! ---------- ! t ! (1 row) ! ! select 'foo' not like all (array['%a', '%o']); -- f ! ?column? ! ---------- ! f ! (1 row) ! ! select 'foo' ilike any (array['%A', '%O']); -- t ! ?column? ! ---------- ! t ! (1 row) ! ! select 'foo' ilike all (array['F%', '%O']); -- t ! ?column? ! ---------- ! t ! (1 row) ! ! -- ! -- General array parser tests ! -- ! -- none of the following should be accepted ! select '{{1,{2}},{2,3}}'::text[]; ! ERROR: malformed array literal: "{{1,{2}},{2,3}}" ! LINE 1: select '{{1,{2}},{2,3}}'::text[]; ! ^ ! select '{{},{}}'::text[]; ! ERROR: malformed array literal: "{{},{}}" ! LINE 1: select '{{},{}}'::text[]; ! ^ ! select E'{{1,2},\\{2,3}}'::text[]; ! ERROR: malformed array literal: "{{1,2},\{2,3}}" ! LINE 1: select E'{{1,2},\\{2,3}}'::text[]; ! ^ ! select '{{"1 2" x},{3}}'::text[]; ! ERROR: malformed array literal: "{{"1 2" x},{3}}" ! LINE 1: select '{{"1 2" x},{3}}'::text[]; ! ^ ! select '{}}'::text[]; ! ERROR: malformed array literal: "{}}" ! LINE 1: select '{}}'::text[]; ! ^ ! select '{ }}'::text[]; ! ERROR: malformed array literal: "{ }}" ! LINE 1: select '{ }}'::text[]; ! ^ ! select array[]; ! ERROR: cannot determine type of empty array ! LINE 1: select array[]; ! ^ ! HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[]. ! -- none of the above should be accepted ! -- all of the following should be accepted ! select '{}'::text[]; ! text ! ------ ! {} ! (1 row) ! ! select '{{{1,2,3,4},{2,3,4,5}},{{3,4,5,6},{4,5,6,7}}}'::text[]; ! text ! ----------------------------------------------- ! {{{1,2,3,4},{2,3,4,5}},{{3,4,5,6},{4,5,6,7}}} ! (1 row) ! ! select '{0 second ,0 second}'::interval[]; ! interval ! --------------- ! {"@ 0","@ 0"} ! (1 row) ! ! select '{ { "," } , { 3 } }'::text[]; ! text ! ------------- ! {{","},{3}} ! (1 row) ! ! select ' { { " 0 second " , 0 second } }'::text[]; ! text ! ------------------------------- ! {{" 0 second ","0 second"}} ! (1 row) ! ! select '{ ! 0 second, ! @ 1 hour @ 42 minutes @ 20 seconds ! }'::interval[]; ! interval ! ------------------------------------ ! {"@ 0","@ 1 hour 42 mins 20 secs"} ! (1 row) ! ! select array[]::text[]; ! array ! ------- ! {} ! (1 row) ! ! select '[0:1]={1.1,2.2}'::float8[]; ! float8 ! ----------------- ! [0:1]={1.1,2.2} ! (1 row) ! ! -- all of the above should be accepted ! -- tests for array aggregates ! CREATE TEMP TABLE arraggtest ( f1 INT[], f2 TEXT[][], f3 FLOAT[]); ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{1,2,3,4}','{{grey,red},{blue,blue}}','{1.6, 0.0}'); ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{1,2,3}','{{grey,red},{grey,blue}}','{1.6}'); ! SELECT max(f1), min(f1), max(f2), min(f2), max(f3), min(f3) FROM arraggtest; ! max | min | max | min | max | min ! -----------+---------+--------------------------+--------------------------+---------+------- ! {1,2,3,4} | {1,2,3} | {{grey,red},{grey,blue}} | {{grey,red},{blue,blue}} | {1.6,0} | {1.6} ! (1 row) ! ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{3,3,2,4,5,6}','{{white,yellow},{pink,orange}}','{2.1,3.3,1.8,1.7,1.6}'); ! SELECT max(f1), min(f1), max(f2), min(f2), max(f3), min(f3) FROM arraggtest; ! max | min | max | min | max | min ! ---------------+---------+--------------------------------+--------------------------+-----------------------+------- ! {3,3,2,4,5,6} | {1,2,3} | {{white,yellow},{pink,orange}} | {{grey,red},{blue,blue}} | {2.1,3.3,1.8,1.7,1.6} | {1.6} ! (1 row) ! ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{2}','{{black,red},{green,orange}}','{1.6,2.2,2.6,0.4}'); ! SELECT max(f1), min(f1), max(f2), min(f2), max(f3), min(f3) FROM arraggtest; ! max | min | max | min | max | min ! ---------------+---------+--------------------------------+------------------------------+-----------------------+------- ! {3,3,2,4,5,6} | {1,2,3} | {{white,yellow},{pink,orange}} | {{black,red},{green,orange}} | {2.1,3.3,1.8,1.7,1.6} | {1.6} ! (1 row) ! ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{4,2,6,7,8,1}','{{red},{black},{purple},{blue},{blue}}',NULL); ! SELECT max(f1), min(f1), max(f2), min(f2), max(f3), min(f3) FROM arraggtest; ! max | min | max | min | max | min ! ---------------+---------+--------------------------------+------------------------------+-----------------------+------- ! {4,2,6,7,8,1} | {1,2,3} | {{white,yellow},{pink,orange}} | {{black,red},{green,orange}} | {2.1,3.3,1.8,1.7,1.6} | {1.6} ! (1 row) ! ! INSERT INTO arraggtest (f1, f2, f3) VALUES ! ('{}','{{pink,white,blue,red,grey,orange}}','{2.1,1.87,1.4,2.2}'); ! SELECT max(f1), min(f1), max(f2), min(f2), max(f3), min(f3) FROM arraggtest; ! max | min | max | min | max | min ! ---------------+-----+--------------------------------+------------------------------+-----------------------+------- ! {4,2,6,7,8,1} | {} | {{white,yellow},{pink,orange}} | {{black,red},{green,orange}} | {2.1,3.3,1.8,1.7,1.6} | {1.6} ! (1 row) ! ! -- A few simple tests for arrays of composite types ! create type comptype as (f1 int, f2 text); ! create table comptable (c1 comptype, c2 comptype[]); ! -- XXX would like to not have to specify row() construct types here ... ! insert into comptable ! values (row(1,'foo'), array[row(2,'bar')::comptype, row(3,'baz')::comptype]); ! -- check that implicitly named array type _comptype isn't a problem ! create type _comptype as enum('fooey'); ! select * from comptable; ! c1 | c2 ! ---------+----------------------- ! (1,foo) | {"(2,bar)","(3,baz)"} ! (1 row) ! ! select c2[2].f2 from comptable; ! f2 ! ----- ! baz ! (1 row) ! ! drop type _comptype; ! drop table comptable; ! drop type comptype; ! create or replace function unnest1(anyarray) ! returns setof anyelement as $$ ! select $1[s] from generate_subscripts($1,1) g(s); ! $$ language sql immutable; ! create or replace function unnest2(anyarray) ! returns setof anyelement as $$ ! select $1[s1][s2] from generate_subscripts($1,1) g1(s1), ! generate_subscripts($1,2) g2(s2); ! $$ language sql immutable; ! select * from unnest1(array[1,2,3]); ! unnest1 ! --------- ! 1 ! 2 ! 3 ! (3 rows) ! ! select * from unnest2(array[[1,2,3],[4,5,6]]); ! unnest2 ! --------- ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! (6 rows) ! ! drop function unnest1(anyarray); ! drop function unnest2(anyarray); ! select array_fill(null::integer, array[3,3],array[2,2]); ! array_fill ! ----------------------------------------------------------------- ! [2:4][2:4]={{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}} ! (1 row) ! ! select array_fill(null::integer, array[3,3]); ! array_fill ! ------------------------------------------------------ ! {{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}} ! (1 row) ! ! select array_fill(null::text, array[3,3],array[2,2]); ! array_fill ! ----------------------------------------------------------------- ! [2:4][2:4]={{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}} ! (1 row) ! ! select array_fill(null::text, array[3,3]); ! array_fill ! ------------------------------------------------------ ! {{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}} ! (1 row) ! ! select array_fill(7, array[3,3],array[2,2]); ! array_fill ! -------------------------------------- ! [2:4][2:4]={{7,7,7},{7,7,7},{7,7,7}} ! (1 row) ! ! select array_fill(7, array[3,3]); ! array_fill ! --------------------------- ! {{7,7,7},{7,7,7},{7,7,7}} ! (1 row) ! ! select array_fill('juhu'::text, array[3,3],array[2,2]); ! array_fill ! ----------------------------------------------------------------- ! [2:4][2:4]={{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}} ! (1 row) ! ! select array_fill('juhu'::text, array[3,3]); ! array_fill ! ------------------------------------------------------ ! {{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}} ! (1 row) ! ! -- raise exception ! select array_fill(1, null, array[2,2]); ! ERROR: dimension array or low bound array cannot be null ! select array_fill(1, array[2,2], null); ! ERROR: dimension array or low bound array cannot be null ! select array_fill(1, array[3,3], array[1,1,1]); ! ERROR: wrong number of array subscripts ! DETAIL: Low bound array has different size than dimensions array. ! select array_fill(1, array[1,2,null]); ! ERROR: dimension values cannot be null ! select string_to_array('1|2|3', '|'); ! string_to_array ! ----------------- ! {1,2,3} ! (1 row) ! ! select string_to_array('1|2|3|', '|'); ! string_to_array ! ----------------- ! {1,2,3,""} ! (1 row) ! ! select string_to_array('1||2|3||', '||'); ! string_to_array ! ----------------- ! {1,2|3,""} ! (1 row) ! ! select string_to_array('1|2|3', ''); ! string_to_array ! ----------------- ! {1|2|3} ! (1 row) ! ! select string_to_array('', '|'); ! string_to_array ! ----------------- ! {} ! (1 row) ! ! select string_to_array('1|2|3', NULL); ! string_to_array ! ----------------- ! {1,|,2,|,3} ! (1 row) ! ! select string_to_array(NULL, '|') IS NULL; ! ?column? ! ---------- ! t ! (1 row) ! ! select string_to_array('abc', ''); ! string_to_array ! ----------------- ! {abc} ! (1 row) ! ! select string_to_array('abc', '', 'abc'); ! string_to_array ! ----------------- ! {NULL} ! (1 row) ! ! select string_to_array('abc', ','); ! string_to_array ! ----------------- ! {abc} ! (1 row) ! ! select string_to_array('abc', ',', 'abc'); ! string_to_array ! ----------------- ! {NULL} ! (1 row) ! ! select string_to_array('1,2,3,4,,6', ','); ! string_to_array ! ----------------- ! {1,2,3,4,"",6} ! (1 row) ! ! select string_to_array('1,2,3,4,,6', ',', ''); ! string_to_array ! ------------------ ! {1,2,3,4,NULL,6} ! (1 row) ! ! select string_to_array('1,2,3,4,*,6', ',', '*'); ! string_to_array ! ------------------ ! {1,2,3,4,NULL,6} ! (1 row) ! ! select array_to_string(NULL::int4[], ',') IS NULL; ! ?column? ! ---------- ! t ! (1 row) ! ! select array_to_string('{}'::int4[], ','); ! array_to_string ! ----------------- ! ! (1 row) ! ! select array_to_string(array[1,2,3,4,NULL,6], ','); ! array_to_string ! ----------------- ! 1,2,3,4,6 ! (1 row) ! ! select array_to_string(array[1,2,3,4,NULL,6], ',', '*'); ! array_to_string ! ----------------- ! 1,2,3,4,*,6 ! (1 row) ! ! select array_to_string(array[1,2,3,4,NULL,6], NULL); ! array_to_string ! ----------------- ! ! (1 row) ! ! select array_to_string(array[1,2,3,4,NULL,6], ',', NULL); ! array_to_string ! ----------------- ! 1,2,3,4,6 ! (1 row) ! ! select array_to_string(string_to_array('1|2|3', '|'), '|'); ! array_to_string ! ----------------- ! 1|2|3 ! (1 row) ! ! select array_length(array[1,2,3], 1); ! array_length ! -------------- ! 3 ! (1 row) ! ! select array_length(array[[1,2,3], [4,5,6]], 0); ! array_length ! -------------- ! ! (1 row) ! ! select array_length(array[[1,2,3], [4,5,6]], 1); ! array_length ! -------------- ! 2 ! (1 row) ! ! select array_length(array[[1,2,3], [4,5,6]], 2); ! array_length ! -------------- ! 3 ! (1 row) ! ! select array_length(array[[1,2,3], [4,5,6]], 3); ! array_length ! -------------- ! ! (1 row) ! ! select cardinality(NULL::int[]); ! cardinality ! ------------- ! ! (1 row) ! ! select cardinality('{}'::int[]); ! cardinality ! ------------- ! 0 ! (1 row) ! ! select cardinality(array[1,2,3]); ! cardinality ! ------------- ! 3 ! (1 row) ! ! select cardinality('[2:4]={5,6,7}'::int[]); ! cardinality ! ------------- ! 3 ! (1 row) ! ! select cardinality('{{1,2}}'::int[]); ! cardinality ! ------------- ! 2 ! (1 row) ! ! select cardinality('{{1,2},{3,4},{5,6}}'::int[]); ! cardinality ! ------------- ! 6 ! (1 row) ! ! select cardinality('{{{1,9},{5,6}},{{2,3},{3,4}}}'::int[]); ! cardinality ! ------------- ! 8 ! (1 row) ! ! select array_agg(unique1) from (select unique1 from tenk1 where unique1 < 15 order by unique1) ss; ! array_agg ! -------------------------------------- ! {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14} ! (1 row) ! ! select array_agg(ten) from (select ten from tenk1 where unique1 < 15 order by unique1) ss; ! array_agg ! --------------------------------- ! {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4} ! (1 row) ! ! select array_agg(nullif(ten, 4)) from (select ten from tenk1 where unique1 < 15 order by unique1) ss; ! array_agg ! --------------------------------------- ! {0,1,2,3,NULL,5,6,7,8,9,0,1,2,3,NULL} ! (1 row) ! ! select array_agg(unique1) from tenk1 where unique1 < -15; ! array_agg ! ----------- ! ! (1 row) ! ! select unnest(array[1,2,3]); ! unnest ! -------- ! 1 ! 2 ! 3 ! (3 rows) ! ! select * from unnest(array[1,2,3]); ! unnest ! -------- ! 1 ! 2 ! 3 ! (3 rows) ! ! select unnest(array[1,2,3,4.5]::float8[]); ! unnest ! -------- ! 1 ! 2 ! 3 ! 4.5 ! (4 rows) ! ! select unnest(array[1,2,3,4.5]::numeric[]); ! unnest ! -------- ! 1 ! 2 ! 3 ! 4.5 ! (4 rows) ! ! select unnest(array[1,2,3,null,4,null,null,5,6]); ! unnest ! -------- ! 1 ! 2 ! 3 ! ! 4 ! ! ! 5 ! 6 ! (9 rows) ! ! select unnest(array[1,2,3,null,4,null,null,5,6]::text[]); ! unnest ! -------- ! 1 ! 2 ! 3 ! ! 4 ! ! ! 5 ! 6 ! (9 rows) ! ! select abs(unnest(array[1,2,null,-3])); ! abs ! ----- ! 1 ! 2 ! ! 3 ! (4 rows) ! ! select array_remove(array[1,2,2,3], 2); ! array_remove ! -------------- ! {1,3} ! (1 row) ! ! select array_remove(array[1,2,2,3], 5); ! array_remove ! -------------- ! {1,2,2,3} ! (1 row) ! ! select array_remove(array[1,NULL,NULL,3], NULL); ! array_remove ! -------------- ! {1,3} ! (1 row) ! ! select array_remove(array['A','CC','D','C','RR'], 'RR'); ! array_remove ! -------------- ! {A,CC,D,C} ! (1 row) ! ! select array_remove('{{1,2,2},{1,4,3}}', 2); -- not allowed ! ERROR: removing elements from multidimensional arrays is not supported ! select array_remove(array['X','X','X'], 'X') = '{}'; ! ?column? ! ---------- ! t ! (1 row) ! ! select array_replace(array[1,2,5,4],5,3); ! array_replace ! --------------- ! {1,2,3,4} ! (1 row) ! ! select array_replace(array[1,2,5,4],5,NULL); ! array_replace ! --------------- ! {1,2,NULL,4} ! (1 row) ! ! select array_replace(array[1,2,NULL,4,NULL],NULL,5); ! array_replace ! --------------- ! {1,2,5,4,5} ! (1 row) ! ! select array_replace(array['A','B','DD','B'],'B','CC'); ! array_replace ! --------------- ! {A,CC,DD,CC} ! (1 row) ! ! select array_replace(array[1,NULL,3],NULL,NULL); ! array_replace ! --------------- ! {1,NULL,3} ! (1 row) ! ! select array_replace(array['AB',NULL,'CDE'],NULL,'12'); ! array_replace ! --------------- ! {AB,12,CDE} ! (1 row) ! ! -- Insert/update on a column that is array of composite ! create temp table t1 (f1 int8_tbl[]); ! insert into t1 (f1[5].q1) values(42); ! select * from t1; ! f1 ! ----------------- ! [5:5]={"(42,)"} ! (1 row) ! ! update t1 set f1[5].q2 = 43; ! select * from t1; ! f1 ! ------------------- ! [5:5]={"(42,43)"} ! (1 row) ! ! -- Check that arrays of composites are safely detoasted when needed ! create temp table src (f1 text); ! insert into src ! select string_agg(random()::text,'') from generate_series(1,10000); ! create type textandtext as (c1 text, c2 text); ! create temp table dest (f1 textandtext[]); ! insert into dest select array[row(f1,f1)::textandtext] from src; ! select length(md5((f1[1]).c2)) from dest; ! length ! -------- ! 32 ! (1 row) ! ! delete from src; ! select length(md5((f1[1]).c2)) from dest; ! length ! -------- ! 32 ! (1 row) ! ! truncate table src; ! drop table src; ! select length(md5((f1[1]).c2)) from dest; ! length ! -------- ! 32 ! (1 row) ! ! drop table dest; ! drop type textandtext; ! -- Tests for polymorphic-array form of width_bucket() ! -- this exercises the varwidth and float8 code paths ! SELECT ! op, ! width_bucket(op::numeric, ARRAY[1, 3, 5, 10.0]::numeric[]) AS wb_n1, ! width_bucket(op::numeric, ARRAY[0, 5.5, 9.99]::numeric[]) AS wb_n2, ! width_bucket(op::numeric, ARRAY[-6, -5, 2.0]::numeric[]) AS wb_n3, ! width_bucket(op::float8, ARRAY[1, 3, 5, 10.0]::float8[]) AS wb_f1, ! width_bucket(op::float8, ARRAY[0, 5.5, 9.99]::float8[]) AS wb_f2, ! width_bucket(op::float8, ARRAY[-6, -5, 2.0]::float8[]) AS wb_f3 ! FROM (VALUES ! (-5.2), ! (-0.0000000001), ! (0.000000000001), ! (1), ! (1.99999999999999), ! (2), ! (2.00000000000001), ! (3), ! (4), ! (4.5), ! (5), ! (5.5), ! (6), ! (7), ! (8), ! (9), ! (9.99999999999999), ! (10), ! (10.0000000000001) ! ) v(op); ! op | wb_n1 | wb_n2 | wb_n3 | wb_f1 | wb_f2 | wb_f3 ! ------------------+-------+-------+-------+-------+-------+------- ! -5.2 | 0 | 0 | 1 | 0 | 0 | 1 ! -0.0000000001 | 0 | 0 | 2 | 0 | 0 | 2 ! 0.000000000001 | 0 | 1 | 2 | 0 | 1 | 2 ! 1 | 1 | 1 | 2 | 1 | 1 | 2 ! 1.99999999999999 | 1 | 1 | 2 | 1 | 1 | 2 ! 2 | 1 | 1 | 3 | 1 | 1 | 3 ! 2.00000000000001 | 1 | 1 | 3 | 1 | 1 | 3 ! 3 | 2 | 1 | 3 | 2 | 1 | 3 ! 4 | 2 | 1 | 3 | 2 | 1 | 3 ! 4.5 | 2 | 1 | 3 | 2 | 1 | 3 ! 5 | 3 | 1 | 3 | 3 | 1 | 3 ! 5.5 | 3 | 2 | 3 | 3 | 2 | 3 ! 6 | 3 | 2 | 3 | 3 | 2 | 3 ! 7 | 3 | 2 | 3 | 3 | 2 | 3 ! 8 | 3 | 2 | 3 | 3 | 2 | 3 ! 9 | 3 | 2 | 3 | 3 | 2 | 3 ! 9.99999999999999 | 3 | 3 | 3 | 3 | 3 | 3 ! 10 | 4 | 3 | 3 | 4 | 3 | 3 ! 10.0000000000001 | 4 | 3 | 3 | 4 | 3 | 3 ! (19 rows) ! ! -- ensure float8 path handles NaN properly ! SELECT ! op, ! width_bucket(op, ARRAY[1, 3, 9, 'NaN', 'NaN']::float8[]) AS wb ! FROM (VALUES ! (-5.2::float8), ! (4::float8), ! (77::float8), ! ('NaN'::float8) ! ) v(op); ! op | wb ! ------+---- ! -5.2 | 0 ! 4 | 2 ! 77 | 3 ! NaN | 5 ! (4 rows) ! ! -- these exercise the generic fixed-width code path ! SELECT ! op, ! width_bucket(op, ARRAY[1, 3, 5, 10]) AS wb_1 ! FROM generate_series(0,11) as op; ! op | wb_1 ! ----+------ ! 0 | 0 ! 1 | 1 ! 2 | 1 ! 3 | 2 ! 4 | 2 ! 5 | 3 ! 6 | 3 ! 7 | 3 ! 8 | 3 ! 9 | 3 ! 10 | 4 ! 11 | 4 ! (12 rows) ! ! SELECT width_bucket(now(), ! array['yesterday', 'today', 'tomorrow']::timestamptz[]); ! width_bucket ! -------------- ! 2 ! (1 row) ! ! -- corner cases ! SELECT width_bucket(5, ARRAY[3]); ! width_bucket ! -------------- ! 1 ! (1 row) ! ! SELECT width_bucket(5, '{}'); ! width_bucket ! -------------- ! 0 ! (1 row) ! ! -- error cases ! SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]); ! ERROR: function width_bucket(text, integer[]) does not exist ! LINE 1: SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]); ! ^ ! HINT: No function matches the given name and argument types. You might need to add explicit type casts. ! SELECT width_bucket(5, ARRAY[3, 4, NULL]); ! ERROR: thresholds array must not contain NULLs ! SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]); ! ERROR: thresholds must be one-dimensional array --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/btree_index.out Sun Oct 3 21:26:00 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/btree_index.out Tue Oct 28 15:53:05 2014 *************** *** 1,129 **** ! -- ! -- BTREE_INDEX ! -- test retrieval of min/max keys for each index ! -- ! SELECT b.* ! FROM bt_i4_heap b ! WHERE b.seqno < 1; ! seqno | random ! -------+------------ ! 0 | 1935401906 ! (1 row) ! ! SELECT b.* ! FROM bt_i4_heap b ! WHERE b.seqno >= 9999; ! seqno | random ! -------+------------ ! 9999 | 1227676208 ! (1 row) ! ! SELECT b.* ! FROM bt_i4_heap b ! WHERE b.seqno = 4500; ! seqno | random ! -------+------------ ! 4500 | 2080851358 ! (1 row) ! ! SELECT b.* ! FROM bt_name_heap b ! WHERE b.seqno < '1'::name; ! seqno | random ! -------+------------ ! 0 | 1935401906 ! (1 row) ! ! SELECT b.* ! FROM bt_name_heap b ! WHERE b.seqno >= '9999'::name; ! seqno | random ! -------+------------ ! 9999 | 1227676208 ! (1 row) ! ! SELECT b.* ! FROM bt_name_heap b ! WHERE b.seqno = '4500'::name; ! seqno | random ! -------+------------ ! 4500 | 2080851358 ! (1 row) ! ! SELECT b.* ! FROM bt_txt_heap b ! WHERE b.seqno < '1'::text; ! seqno | random ! -------+------------ ! 0 | 1935401906 ! (1 row) ! ! SELECT b.* ! FROM bt_txt_heap b ! WHERE b.seqno >= '9999'::text; ! seqno | random ! -------+------------ ! 9999 | 1227676208 ! (1 row) ! ! SELECT b.* ! FROM bt_txt_heap b ! WHERE b.seqno = '4500'::text; ! seqno | random ! -------+------------ ! 4500 | 2080851358 ! (1 row) ! ! SELECT b.* ! FROM bt_f8_heap b ! WHERE b.seqno < '1'::float8; ! seqno | random ! -------+------------ ! 0 | 1935401906 ! (1 row) ! ! SELECT b.* ! FROM bt_f8_heap b ! WHERE b.seqno >= '9999'::float8; ! seqno | random ! -------+------------ ! 9999 | 1227676208 ! (1 row) ! ! SELECT b.* ! FROM bt_f8_heap b ! WHERE b.seqno = '4500'::float8; ! seqno | random ! -------+------------ ! 4500 | 2080851358 ! (1 row) ! ! -- ! -- Check correct optimization of LIKE (special index operator support) ! -- for both indexscan and bitmapscan cases ! -- ! set enable_seqscan to false; ! set enable_indexscan to true; ! set enable_bitmapscan to false; ! select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; ! proname ! ------------------------ ! RI_FKey_cascade_del ! RI_FKey_noaction_del ! RI_FKey_restrict_del ! RI_FKey_setdefault_del ! RI_FKey_setnull_del ! (5 rows) ! ! set enable_indexscan to false; ! set enable_bitmapscan to true; ! select proname from pg_proc where proname like E'RI\\_FKey%del' order by 1; ! proname ! ------------------------ ! RI_FKey_cascade_del ! RI_FKey_noaction_del ! RI_FKey_restrict_del ! RI_FKey_setdefault_del ! RI_FKey_setnull_del ! (5 rows) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/hash_index.out Sun Dec 12 20:21:38 2010 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/hash_index.out Tue Oct 28 15:53:05 2014 *************** *** 1,198 **** ! -- ! -- HASH_INDEX ! -- grep 843938989 hash.data ! -- ! SELECT * FROM hash_i4_heap ! WHERE hash_i4_heap.random = 843938989; ! seqno | random ! -------+----------- ! 15 | 843938989 ! (1 row) ! ! -- ! -- hash index ! -- grep 66766766 hash.data ! -- ! SELECT * FROM hash_i4_heap ! WHERE hash_i4_heap.random = 66766766; ! seqno | random ! -------+-------- ! (0 rows) ! ! -- ! -- hash index ! -- grep 1505703298 hash.data ! -- ! SELECT * FROM hash_name_heap ! WHERE hash_name_heap.random = '1505703298'::name; ! seqno | random ! -------+------------ ! 9838 | 1505703298 ! (1 row) ! ! -- ! -- hash index ! -- grep 7777777 hash.data ! -- ! SELECT * FROM hash_name_heap ! WHERE hash_name_heap.random = '7777777'::name; ! seqno | random ! -------+-------- ! (0 rows) ! ! -- ! -- hash index ! -- grep 1351610853 hash.data ! -- ! SELECT * FROM hash_txt_heap ! WHERE hash_txt_heap.random = '1351610853'::text; ! seqno | random ! -------+------------ ! 5677 | 1351610853 ! (1 row) ! ! -- ! -- hash index ! -- grep 111111112222222233333333 hash.data ! -- ! SELECT * FROM hash_txt_heap ! WHERE hash_txt_heap.random = '111111112222222233333333'::text; ! seqno | random ! -------+-------- ! (0 rows) ! ! -- ! -- hash index ! -- grep 444705537 hash.data ! -- ! SELECT * FROM hash_f8_heap ! WHERE hash_f8_heap.random = '444705537'::float8; ! seqno | random ! -------+----------- ! 7853 | 444705537 ! (1 row) ! ! -- ! -- hash index ! -- grep 88888888 hash.data ! -- ! SELECT * FROM hash_f8_heap ! WHERE hash_f8_heap.random = '88888888'::float8; ! seqno | random ! -------+-------- ! (0 rows) ! ! -- ! -- hash index ! -- grep '^90[^0-9]' hashovfl.data ! -- ! -- SELECT count(*) AS i988 FROM hash_ovfl_heap ! -- WHERE x = 90; ! -- ! -- hash index ! -- grep '^1000[^0-9]' hashovfl.data ! -- ! -- SELECT count(*) AS i0 FROM hash_ovfl_heap ! -- WHERE x = 1000; ! -- ! -- HASH ! -- ! UPDATE hash_i4_heap ! SET random = 1 ! WHERE hash_i4_heap.seqno = 1492; ! SELECT h.seqno AS i1492, h.random AS i1 ! FROM hash_i4_heap h ! WHERE h.random = 1; ! i1492 | i1 ! -------+---- ! 1492 | 1 ! (1 row) ! ! UPDATE hash_i4_heap ! SET seqno = 20000 ! WHERE hash_i4_heap.random = 1492795354; ! SELECT h.seqno AS i20000 ! FROM hash_i4_heap h ! WHERE h.random = 1492795354; ! i20000 ! -------- ! 20000 ! (1 row) ! ! UPDATE hash_name_heap ! SET random = '0123456789abcdef'::name ! WHERE hash_name_heap.seqno = 6543; ! SELECT h.seqno AS i6543, h.random AS c0_to_f ! FROM hash_name_heap h ! WHERE h.random = '0123456789abcdef'::name; ! i6543 | c0_to_f ! -------+------------------ ! 6543 | 0123456789abcdef ! (1 row) ! ! UPDATE hash_name_heap ! SET seqno = 20000 ! WHERE hash_name_heap.random = '76652222'::name; ! -- ! -- this is the row we just replaced; index scan should return zero rows ! -- ! SELECT h.seqno AS emptyset ! FROM hash_name_heap h ! WHERE h.random = '76652222'::name; ! emptyset ! ---------- ! (0 rows) ! ! UPDATE hash_txt_heap ! SET random = '0123456789abcdefghijklmnop'::text ! WHERE hash_txt_heap.seqno = 4002; ! SELECT h.seqno AS i4002, h.random AS c0_to_p ! FROM hash_txt_heap h ! WHERE h.random = '0123456789abcdefghijklmnop'::text; ! i4002 | c0_to_p ! -------+---------------------------- ! 4002 | 0123456789abcdefghijklmnop ! (1 row) ! ! UPDATE hash_txt_heap ! SET seqno = 20000 ! WHERE hash_txt_heap.random = '959363399'::text; ! SELECT h.seqno AS t20000 ! FROM hash_txt_heap h ! WHERE h.random = '959363399'::text; ! t20000 ! -------- ! 20000 ! (1 row) ! ! UPDATE hash_f8_heap ! SET random = '-1234.1234'::float8 ! WHERE hash_f8_heap.seqno = 8906; ! SELECT h.seqno AS i8096, h.random AS f1234_1234 ! FROM hash_f8_heap h ! WHERE h.random = '-1234.1234'::float8; ! i8096 | f1234_1234 ! -------+------------ ! 8906 | -1234.1234 ! (1 row) ! ! UPDATE hash_f8_heap ! SET seqno = 20000 ! WHERE hash_f8_heap.random = '488912369'::float8; ! SELECT h.seqno AS f20000 ! FROM hash_f8_heap h ! WHERE h.random = '488912369'::float8; ! f20000 ! -------- ! 20000 ! (1 row) ! ! -- UPDATE hash_ovfl_heap ! -- SET x = 1000 ! -- WHERE x = 90; ! -- this vacuums the index as well ! -- VACUUM hash_ovfl_heap; ! -- SELECT count(*) AS i0 FROM hash_ovfl_heap ! -- WHERE x = 90; ! -- SELECT count(*) AS i988 FROM hash_ovfl_heap ! -- WHERE x = 1000; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/update.out Thu Oct 16 14:31:37 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/update.out Tue Oct 28 15:53:05 2014 *************** *** 1,150 **** ! -- ! -- UPDATE syntax tests ! -- ! CREATE TABLE update_test ( ! a INT DEFAULT 10, ! b INT, ! c TEXT ! ); ! INSERT INTO update_test VALUES (5, 10, 'foo'); ! INSERT INTO update_test(b, a) VALUES (15, 10); ! SELECT * FROM update_test; ! a | b | c ! ----+----+----- ! 5 | 10 | foo ! 10 | 15 | ! (2 rows) ! ! UPDATE update_test SET a = DEFAULT, b = DEFAULT; ! SELECT * FROM update_test; ! a | b | c ! ----+---+----- ! 10 | | foo ! 10 | | ! (2 rows) ! ! -- aliases for the UPDATE target table ! UPDATE update_test AS t SET b = 10 WHERE t.a = 10; ! SELECT * FROM update_test; ! a | b | c ! ----+----+----- ! 10 | 10 | foo ! 10 | 10 | ! (2 rows) ! ! UPDATE update_test t SET b = t.b + 10 WHERE t.a = 10; ! SELECT * FROM update_test; ! a | b | c ! ----+----+----- ! 10 | 20 | foo ! 10 | 20 | ! (2 rows) ! ! -- ! -- Test VALUES in FROM ! -- ! UPDATE update_test SET a=v.i FROM (VALUES(100, 20)) AS v(i, j) ! WHERE update_test.b = v.j; ! SELECT * FROM update_test; ! a | b | c ! -----+----+----- ! 100 | 20 | foo ! 100 | 20 | ! (2 rows) ! ! -- ! -- Test multiple-set-clause syntax ! -- ! INSERT INTO update_test SELECT a,b+1,c FROM update_test; ! SELECT * FROM update_test; ! a | b | c ! -----+----+----- ! 100 | 20 | foo ! 100 | 20 | ! 100 | 21 | foo ! 100 | 21 | ! (4 rows) ! ! UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'foo'; ! SELECT * FROM update_test; ! a | b | c ! -----+----+------- ! 100 | 20 | ! 100 | 21 | ! 10 | 31 | bugle ! 10 | 32 | bugle ! (4 rows) ! ! UPDATE update_test SET (c,b) = ('car', a+b), a = a + 1 WHERE a = 10; ! SELECT * FROM update_test; ! a | b | c ! -----+----+----- ! 100 | 20 | ! 100 | 21 | ! 11 | 41 | car ! 11 | 42 | car ! (4 rows) ! ! -- fail, multi assignment to same column: ! UPDATE update_test SET (c,b) = ('car', a+b), b = a + 1 WHERE a = 10; ! ERROR: multiple assignments to same column "b" ! -- uncorrelated sub-select: ! UPDATE update_test ! SET (b,a) = (select a,b from update_test where b = 41 and c = 'car') ! WHERE a = 100 AND b = 20; ! SELECT * FROM update_test; ! a | b | c ! -----+----+----- ! 100 | 21 | ! 11 | 41 | car ! 11 | 42 | car ! 41 | 11 | ! (4 rows) ! ! -- correlated sub-select: ! UPDATE update_test o ! SET (b,a) = (select a+1,b from update_test i ! where i.a=o.a and i.b=o.b and i.c is not distinct from o.c); ! SELECT * FROM update_test; ! a | b | c ! ----+-----+----- ! 21 | 101 | ! 41 | 12 | car ! 42 | 12 | car ! 11 | 42 | ! (4 rows) ! ! -- fail, multiple rows supplied: ! UPDATE update_test SET (b,a) = (select a+1,b from update_test); ! ERROR: more than one row returned by a subquery used as an expression ! -- set to null if no rows supplied: ! UPDATE update_test SET (b,a) = (select a+1,b from update_test where a = 1000) ! WHERE a = 11; ! SELECT * FROM update_test; ! a | b | c ! ----+-----+----- ! 21 | 101 | ! 41 | 12 | car ! 42 | 12 | car ! | | ! (4 rows) ! ! -- if an alias for the target table is specified, don't allow references ! -- to the original table name ! UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10; ! ERROR: invalid reference to FROM-clause entry for table "update_test" ! LINE 1: UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a... ! ^ ! HINT: Perhaps you meant to reference the table alias "t". ! -- Make sure that we can update to a TOASTed value. ! UPDATE update_test SET c = repeat('x', 10000) WHERE c = 'car'; ! SELECT a, b, char_length(c) FROM update_test; ! a | b | char_length ! ----+-----+------------- ! 21 | 101 | ! | | ! 41 | 12 | 10000 ! 42 | 12 | 10000 ! (4 rows) ! ! DROP TABLE update_test; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/namespace.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/namespace.out Tue Oct 28 15:53:05 2014 *************** *** 1,71 **** ! -- ! -- Regression tests for schemas (namespaces) ! -- ! CREATE SCHEMA test_schema_1 ! CREATE UNIQUE INDEX abc_a_idx ON abc (a) ! CREATE VIEW abc_view AS ! SELECT a+1 AS a, b+1 AS b FROM abc ! CREATE TABLE abc ( ! a serial, ! b int UNIQUE ! ); ! -- verify that the objects were created ! SELECT COUNT(*) FROM pg_class WHERE relnamespace = ! (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1'); ! count ! ------- ! 5 ! (1 row) ! ! INSERT INTO test_schema_1.abc DEFAULT VALUES; ! INSERT INTO test_schema_1.abc DEFAULT VALUES; ! INSERT INTO test_schema_1.abc DEFAULT VALUES; ! SELECT * FROM test_schema_1.abc; ! a | b ! ---+--- ! 1 | ! 2 | ! 3 | ! (3 rows) ! ! SELECT * FROM test_schema_1.abc_view; ! a | b ! ---+--- ! 2 | ! 3 | ! 4 | ! (3 rows) ! ! ALTER SCHEMA test_schema_1 RENAME TO test_schema_renamed; ! SELECT COUNT(*) FROM pg_class WHERE relnamespace = ! (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1'); ! count ! ------- ! 0 ! (1 row) ! ! -- test IF NOT EXISTS cases ! CREATE SCHEMA test_schema_renamed; -- fail, already exists ! ERROR: schema "test_schema_renamed" already exists ! CREATE SCHEMA IF NOT EXISTS test_schema_renamed; -- ok with notice ! NOTICE: schema "test_schema_renamed" already exists, skipping ! CREATE SCHEMA IF NOT EXISTS test_schema_renamed -- fail, disallowed ! CREATE TABLE abc ( ! a serial, ! b int UNIQUE ! ); ! ERROR: CREATE SCHEMA IF NOT EXISTS cannot include schema elements ! LINE 2: CREATE TABLE abc ( ! ^ ! DROP SCHEMA test_schema_renamed CASCADE; ! NOTICE: drop cascades to 2 other objects ! DETAIL: drop cascades to table test_schema_renamed.abc ! drop cascades to view test_schema_renamed.abc_view ! -- verify that the objects were dropped ! SELECT COUNT(*) FROM pg_class WHERE relnamespace = ! (SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_renamed'); ! count ! ------- ! 0 ! (1 row) ! --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/prepared_xacts.out Tue Sep 27 16:30:52 2011 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/prepared_xacts.out Tue Oct 28 15:53:05 2014 *************** *** 1,254 **** ! -- ! -- PREPARED TRANSACTIONS (two-phase commit) ! -- ! -- We can't readily test persistence of prepared xacts within the ! -- regression script framework, unfortunately. Note that a crash ! -- isn't really needed ... stopping and starting the postmaster would ! -- be enough, but we can't even do that here. ! -- create a simple table that we'll use in the tests ! CREATE TABLE pxtest1 (foobar VARCHAR(10)); ! INSERT INTO pxtest1 VALUES ('aaa'); ! -- Test PREPARE TRANSACTION ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! bbb ! (1 row) ! ! PREPARE TRANSACTION 'foo1'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! (1 row) ! ! -- Test pg_prepared_xacts system view ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------ ! foo1 ! (1 row) ! ! -- Test ROLLBACK PREPARED ! ROLLBACK PREPARED 'foo1'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! (1 row) ! ! SELECT gid FROM pg_prepared_xacts; ! gid ! ----- ! (0 rows) ! ! -- Test COMMIT PREPARED ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! INSERT INTO pxtest1 VALUES ('ddd'); ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! ddd ! (2 rows) ! ! PREPARE TRANSACTION 'foo2'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! (1 row) ! ! COMMIT PREPARED 'foo2'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! ddd ! (2 rows) ! ! -- Test duplicate gids ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! eee ! (2 rows) ! ! PREPARE TRANSACTION 'foo3'; ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------ ! foo3 ! (1 row) ! ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! INSERT INTO pxtest1 VALUES ('fff'); ! -- This should fail, because the gid foo3 is already in use ! PREPARE TRANSACTION 'foo3'; ! ERROR: transaction identifier "foo3" is already in use ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! ddd ! (2 rows) ! ! ROLLBACK PREPARED 'foo3'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! ddd ! (2 rows) ! ! -- Test serialization failure (SSI) ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! eee ! (2 rows) ! ! PREPARE TRANSACTION 'foo4'; ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------ ! foo4 ! (1 row) ! ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! SELECT * FROM pxtest1; ! foobar ! -------- ! aaa ! ddd ! (2 rows) ! ! -- This should fail, because the two transactions have a write-skew anomaly ! INSERT INTO pxtest1 VALUES ('fff'); ! ERROR: could not serialize access due to read/write dependencies among transactions ! DETAIL: Reason code: Canceled on identification as a pivot, during write. ! HINT: The transaction might succeed if retried. ! PREPARE TRANSACTION 'foo5'; ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------ ! foo4 ! (1 row) ! ! ROLLBACK PREPARED 'foo4'; ! SELECT gid FROM pg_prepared_xacts; ! gid ! ----- ! (0 rows) ! ! -- Clean up ! DROP TABLE pxtest1; ! -- Test subtransactions ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! CREATE TABLE pxtest2 (a int); ! INSERT INTO pxtest2 VALUES (1); ! SAVEPOINT a; ! INSERT INTO pxtest2 VALUES (2); ! ROLLBACK TO a; ! SAVEPOINT b; ! INSERT INTO pxtest2 VALUES (3); ! PREPARE TRANSACTION 'regress-one'; ! CREATE TABLE pxtest3(fff int); ! -- Test shared invalidation ! BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ! DROP TABLE pxtest3; ! CREATE TABLE pxtest4 (a int); ! INSERT INTO pxtest4 VALUES (1); ! INSERT INTO pxtest4 VALUES (2); ! DECLARE foo CURSOR FOR SELECT * FROM pxtest4; ! -- Fetch 1 tuple, keeping the cursor open ! FETCH 1 FROM foo; ! a ! --- ! 1 ! (1 row) ! ! PREPARE TRANSACTION 'regress-two'; ! -- No such cursor ! FETCH 1 FROM foo; ! ERROR: cursor "foo" does not exist ! -- Table doesn't exist, the creation hasn't been committed yet ! SELECT * FROM pxtest2; ! ERROR: relation "pxtest2" does not exist ! LINE 1: SELECT * FROM pxtest2; ! ^ ! -- There should be two prepared transactions ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------------- ! regress-one ! regress-two ! (2 rows) ! ! -- pxtest3 should be locked because of the pending DROP ! set statement_timeout to 2000; ! SELECT * FROM pxtest3; ! ERROR: canceling statement due to statement timeout ! reset statement_timeout; ! -- Disconnect, we will continue testing in a different backend ! \c - ! -- There should still be two prepared transactions ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------------- ! regress-one ! regress-two ! (2 rows) ! ! -- pxtest3 should still be locked because of the pending DROP ! set statement_timeout to 2000; ! SELECT * FROM pxtest3; ! ERROR: canceling statement due to statement timeout ! reset statement_timeout; ! -- Commit table creation ! COMMIT PREPARED 'regress-one'; ! \d pxtest2 ! Table "public.pxtest2" ! Column | Type | Modifiers ! --------+---------+----------- ! a | integer | ! ! SELECT * FROM pxtest2; ! a ! --- ! 1 ! 3 ! (2 rows) ! ! -- There should be one prepared transaction ! SELECT gid FROM pg_prepared_xacts; ! gid ! ------------- ! regress-two ! (1 row) ! ! -- Commit table drop ! COMMIT PREPARED 'regress-two'; ! SELECT * FROM pxtest3; ! ERROR: relation "pxtest3" does not exist ! LINE 1: SELECT * FROM pxtest3; ! ^ ! -- There should be no prepared transactions ! SELECT gid FROM pg_prepared_xacts; ! gid ! ----- ! (0 rows) ! ! -- Clean up ! DROP TABLE pxtest2; ! DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled ! ERROR: table "pxtest3" does not exist ! DROP TABLE pxtest4; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/delete.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/delete.out Tue Oct 28 15:53:05 2014 *************** *** 1,33 **** ! CREATE TABLE delete_test ( ! id SERIAL PRIMARY KEY, ! a INT, ! b text ! ); ! INSERT INTO delete_test (a) VALUES (10); ! INSERT INTO delete_test (a, b) VALUES (50, repeat('x', 10000)); ! INSERT INTO delete_test (a) VALUES (100); ! -- allow an alias to be specified for DELETE's target table ! DELETE FROM delete_test AS dt WHERE dt.a > 75; ! -- if an alias is specified, don't allow the original table name ! -- to be referenced ! DELETE FROM delete_test dt WHERE delete_test.a > 25; ! ERROR: invalid reference to FROM-clause entry for table "delete_test" ! LINE 1: DELETE FROM delete_test dt WHERE delete_test.a > 25; ! ^ ! HINT: Perhaps you meant to reference the table alias "dt". ! SELECT id, a, char_length(b) FROM delete_test; ! id | a | char_length ! ----+----+------------- ! 1 | 10 | ! 2 | 50 | 10000 ! (2 rows) ! ! -- delete a row with a TOASTed value ! DELETE FROM delete_test WHERE a > 25; ! SELECT id, a, char_length(b) FROM delete_test; ! id | a | char_length ! ----+----+------------- ! 1 | 10 | ! (1 row) ! ! DROP TABLE delete_test; --- 1 ---- ! psql: FATAL: the database system is in recovery mode ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/misc.out Tue Oct 28 15:52:48 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/misc.out Tue Oct 28 15:53:07 2014 *************** *** 27,38 **** --- 27,45 ---- FROM onek WHERE onek.stringu1 = 'JBAAAA' and onek.stringu1 = tmp.stringu1; + ERROR: relation "tmp" does not exist + LINE 1: UPDATE tmp + ^ UPDATE tmp SET stringu1 = reverse_name(onek2.stringu1) FROM onek2 WHERE onek2.stringu1 = 'JCAAAA' and onek2.stringu1 = tmp.stringu1; + ERROR: relation "tmp" does not exist + LINE 1: UPDATE tmp + ^ DROP TABLE tmp; + ERROR: table "tmp" does not exist --UPDATE person* -- SET age = age + 1; --UPDATE person* *************** *** 576,592 **** SELECT user_relns() AS user_relns ORDER BY user_relns; ! user_relns ! --------------------- ! a a_star abstime_tbl aggtest - aggtype array_index_op_test array_op_test - arrtest - b b_star bb box_tbl --- 583,595 ---- SELECT user_relns() AS user_relns ORDER BY user_relns; ! user_relns ! ------------------------ a_star abstime_tbl aggtest array_index_op_test array_op_test b_star bb box_tbl *************** *** 595,615 **** bt_i4_heap bt_name_heap bt_txt_heap - c c_star char_tbl - check2_tbl - check_seq - check_tbl circle_tbl city ! copy_tbl ! d d_star date_tbl - default_seq - default_tbl - defaultexpr_tbl dept dupindexcols e_star --- 598,612 ---- bt_i4_heap bt_name_heap bt_txt_heap c_star char_tbl circle_tbl city ! concur_reindex_matview ! concur_reindex_tab ! concur_reindex_tab2 d_star date_tbl dept dupindexcols e_star *************** *** 628,637 **** iexit ihighway inet_tbl - inhf - inhx - insert_seq - insert_tbl int2_tbl int4_tbl int8_tbl --- 625,630 ---- *************** *** 639,647 **** iportaltest kd_point_tbl line_tbl - log_table lseg_tbl - main_table money_data num_data num_exp_add --- 632,638 ---- *************** *** 663,669 **** quad_point_tbl radix_text_tbl ramp - random_tbl real_city reltime_tbl road --- 654,659 ---- *************** *** 672,678 **** street stud_emp student - subselect_tbl t tenk1 tenk2 --- 662,667 ---- *************** *** 697,704 **** tvvm tvvmv varchar_tbl ! xacttest ! (120 rows) SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); name --- 686,692 ---- tvvm tvvmv varchar_tbl ! (101 rows) SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); name ====================================================================== *** /Users/decibel/pgsql/HEAD/src/test/regress/expected/with.out Mon May 5 19:06:09 2014 --- /Users/decibel/pgsql/HEAD/src/test/regress/results/with.out Tue Oct 28 15:53:09 2014 *************** *** 2083,2126 **** EXPLAIN (VERBOSE, COSTS OFF) WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 ) DELETE FROM a USING wcte WHERE aa = q2; ! QUERY PLAN ! ------------------------------------------------ ! Delete on public.a ! CTE wcte ! -> Insert on public.int8_tbl ! Output: int8_tbl.q2 ! -> Result ! Output: 42::bigint, 47::bigint ! -> Nested Loop ! Output: a.ctid, wcte.* ! Join Filter: (a.aa = wcte.q2) ! -> Seq Scan on public.a ! Output: a.ctid, a.aa ! -> CTE Scan on wcte ! Output: wcte.*, wcte.q2 ! -> Nested Loop ! Output: b.ctid, wcte.* ! Join Filter: (b.aa = wcte.q2) ! -> Seq Scan on public.b ! Output: b.ctid, b.aa ! -> CTE Scan on wcte ! Output: wcte.*, wcte.q2 ! -> Nested Loop ! Output: c.ctid, wcte.* ! Join Filter: (c.aa = wcte.q2) ! -> Seq Scan on public.c ! Output: c.ctid, c.aa ! -> CTE Scan on wcte ! Output: wcte.*, wcte.q2 ! -> Nested Loop ! Output: d.ctid, wcte.* ! Join Filter: (d.aa = wcte.q2) ! -> Seq Scan on public.d ! Output: d.ctid, d.aa ! -> CTE Scan on wcte ! Output: wcte.*, wcte.q2 ! (34 rows) ! -- error cases -- data-modifying WITH tries to use its own output WITH RECURSIVE t AS ( --- 2083,2091 ---- EXPLAIN (VERBOSE, COSTS OFF) WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 ) DELETE FROM a USING wcte WHERE aa = q2; ! ERROR: relation "a" does not exist ! LINE 3: DELETE FROM a USING wcte WHERE aa = q2; ! ^ -- error cases -- data-modifying WITH tries to use its own output WITH RECURSIVE t AS ( ======================================================================