summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2016-10-25 08:44:12 +0000
committerPavan Deolasee2016-10-26 05:24:00 +0000
commit8895fa07ba93b7b36e618b8f7e40dc81dc3bc37e (patch)
treed14b3799225403d55cebe10a5bcfb6a6098e5e1c
parent85b492b8e1cc0a668f3abcd33ab51df8f5e14bbb (diff)
Fix a few regression test failures post cherry picking of patches.
-rw-r--r--src/test/regress/expected/brin.out8
-rw-r--r--src/test/regress/expected/create_view.out28
-rw-r--r--src/test/regress/expected/foreign_data_1.out8
-rw-r--r--src/test/regress/expected/gist.out4
-rw-r--r--src/test/regress/expected/groupingsets.out33
-rw-r--r--src/test/regress/expected/insert_conflict.out58
-rw-r--r--src/test/regress/expected/json.out12
-rw-r--r--src/test/regress/expected/jsonb.out10
-rw-r--r--src/test/regress/expected/plpgsql_1.out108
-rw-r--r--src/test/regress/expected/prepared_xacts_2.out6
-rw-r--r--src/test/regress/expected/rules.out14
-rw-r--r--src/test/regress/expected/updatable_views.out6
-rw-r--r--src/test/regress/output/largeobject_3.source2
-rw-r--r--src/test/regress/output/misc_1.source428
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/sql/create_view.sql38
-rw-r--r--src/test/regress/sql/groupingsets.sql62
-rw-r--r--src/test/regress/sql/inherit.sql21
-rw-r--r--src/test/regress/sql/privileges.sql84
-rw-r--r--src/test/regress/sql/transactions.sql32
20 files changed, 421 insertions, 543 deletions
diff --git a/src/test/regress/expected/brin.out b/src/test/regress/expected/brin.out
index 652687f2e4..dc76957a49 100644
--- a/src/test/regress/expected/brin.out
+++ b/src/test/regress/expected/brin.out
@@ -645,10 +645,10 @@ WARNING: did not get bitmap indexscan plan for (int4col,<=,int8,1999,100)
WARNING: did not get seqscan plan for (int4col,<=,int8,1999,100)
WARNING: did not get bitmap indexscan plan for (int4col,<,int8,1428427143,100)
WARNING: did not get seqscan plan for (int4col,<,int8,1428427143,100)
-WARNING: did not get bitmap indexscan plan for (textcol,>,text,ABABAB,100)
-WARNING: did not get seqscan plan for (textcol,>,text,ABABAB,100)
-WARNING: did not get bitmap indexscan plan for (textcol,>=,text,ABABAB,100)
-WARNING: did not get seqscan plan for (textcol,>=,text,ABABAB,100)
+WARNING: did not get bitmap indexscan plan for (textcol,>,text,AAAAAA,100)
+WARNING: did not get seqscan plan for (textcol,>,text,AAAAAA,100)
+WARNING: did not get bitmap indexscan plan for (textcol,>=,text,AAAAAA,100)
+WARNING: did not get seqscan plan for (textcol,>=,text,AAAAAA,100)
WARNING: did not get bitmap indexscan plan for (textcol,=,text,BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA,1)
WARNING: did not get seqscan plan for (textcol,=,text,BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA,1)
WARNING: did not get bitmap indexscan plan for (textcol,<=,text,ZZAAAA,100)
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index a1e3728fb7..4ebb5a3c70 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1503,6 +1503,34 @@ explain (costs off) select * from tt18v;
-> Seq Scan on int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1
(4 rows)
+-- check display of ScalarArrayOp with a sub-select
+select 'foo'::text = any(array['abc','def','foo']::text[]);
+ ?column?
+----------
+ t
+(1 row)
+
+select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
+ERROR: operator does not exist: text = text[]
+LINE 1: select 'foo'::text = any((select array['abc','def','foo']::t...
+ ^
+HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
+select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
+ ?column?
+----------
+ t
+(1 row)
+
+create view tt19v as
+select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
+ 'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
+select pg_get_viewdef('tt19v', true);
+ pg_get_viewdef
+----------------------------------------------------------------------------------------------------
+ SELECT 'foo'::text = ANY (ARRAY['abc'::text, 'def'::text, 'foo'::text]) AS c1, +
+ 'foo'::text = ANY ((( SELECT ARRAY['abc'::text, 'def'::text, 'foo'::text] AS "array"))) AS c2;
+(1 row)
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/expected/foreign_data_1.out b/src/test/regress/expected/foreign_data_1.out
index 5575f590c8..541b058c96 100644
--- a/src/test/regress/expected/foreign_data_1.out
+++ b/src/test/regress/expected/foreign_data_1.out
@@ -1411,15 +1411,15 @@ DROP FOREIGN TABLE IF EXISTS no_table;
NOTICE: foreign table "no_table" does not exist, skipping
DROP FOREIGN TABLE foreign_schema.foreign_table_1;
ERROR: foreign table "foreign_table_1" does not exist
--- REASSIGN OWNED/DROP OWNED of foreign objects
-REASSIGN OWNED BY regress_test_role TO regress_test_role2;
-DROP OWNED BY regress_test_role2;
-DROP OWNED BY regress_test_role2 CASCADE;
-- Cleanup
DROP SCHEMA foreign_schema CASCADE;
DROP ROLE regress_test_role; -- ERROR
+DROP SERVER s5 CASCADE;
+ERROR: server "s5" does not exist
DROP SERVER t1 CASCADE;
ERROR: server "t1" does not exist
+DROP SERVER t2;
+ERROR: server "t2" does not exist
DROP USER MAPPING FOR regress_test_role SERVER s6;
ERROR: role "regress_test_role" does not exist
-- This test causes some order dependent cascade detail output,
diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out
index 8bf5c42df5..f2ff91d898 100644
--- a/src/test/regress/expected/gist.out
+++ b/src/test/regress/expected/gist.out
@@ -63,7 +63,7 @@ select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5));
-- Also test an index-only knn-search
explain (costs off)
select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5))
-order by p <-> point(0.201, 0.201);
+order by p <-> point(0.2, 0.2);
QUERY PLAN
--------------------------------------------------------------
Remote Subquery Scan on all (datanode_1,datanode_2)
@@ -92,7 +92,7 @@ order by p <-> point(0.2, 0.2);
-- Check commuted case as well
explain (costs off)
select p from gist_tbl where p <@ box(point(0,0), point(0.5, 0.5))
-order by point(0.101, 0.101) <-> p;
+order by point(0.1, 0.1) <-> p;
QUERY PLAN
--------------------------------------------------------------
Remote Subquery Scan on all (datanode_1,datanode_2)
diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out
index 0cb9dea220..84e0ba4259 100644
--- a/src/test/regress/expected/groupingsets.out
+++ b/src/test/regress/expected/groupingsets.out
@@ -198,6 +198,39 @@ select ten, sum(distinct four) from onek a
group by grouping sets((ten,four),(ten))
having exists (select 1 from onek b where sum(distinct a.four) = b.four);
ERROR: GROUPING SETS, ROLLUP or CUBE is not yet supported
+-- Tests around pushdown of HAVING clauses, partially testing against previous bugs
+select a,count(*) from gstest2 group by rollup(a) order by a;
+ERROR: GROUPING SETS, ROLLUP or CUBE is not yet supported
+select a,count(*) from gstest2 group by rollup(a) having a is distinct from 1 order by a;
+ERROR: GROUPING SETS, ROLLUP or CUBE is not yet supported
+explain (costs off)
+ select a,count(*) from gstest2 group by rollup(a) having a is distinct from 1 order by a;
+ERROR: GROUPING SETS, ROLLUP or CUBE is not yet supported
+select v.c, (select count(*) from gstest2 group by () having v.c)
+ from (values (false),(true)) v(c) order by v.c;
+ c | count
+---+-------
+ f |
+ t | 9
+(2 rows)
+
+explain (costs off)
+ select v.c, (select count(*) from gstest2 group by () having v.c)
+ from (values (false),(true)) v(c) order by v.c;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: "*VALUES*".column1
+ -> Values Scan on "*VALUES*"
+ SubPlan 1
+ -> Aggregate
+ Group Key: ()
+ Filter: "*VALUES*".column1
+ -> Remote Subquery Scan on all (datanode_1,datanode_2)
+ -> Aggregate
+ -> Seq Scan on gstest2
+(10 rows)
+
-- HAVING with GROUPING queries
select ten, grouping(ten) from onek
group by grouping sets(ten) having grouping(ten) >= 0
diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out
index 4a4c2ea4b1..71e3cda8aa 100644
--- a/src/test/regress/expected/insert_conflict.out
+++ b/src/test/regress/expected/insert_conflict.out
@@ -404,64 +404,6 @@ ERROR: there is no unique or exclusion constraint matching the ON CONFLICT spec
insert into insertconflicttest values (23, 'Blackberry') on conflict (fruit) where fruit like '%berry' do update set fruit = excluded.fruit;
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
drop index partial_key_index;
---
--- Test that wholerow references to ON CONFLICT's EXCLUDED work
---
-create unique index plain on insertconflicttest(key);
--- Succeeds, updates existing row:
-insert into insertconflicttest as i values (23, 'Jackfruit') on conflict (key) do update set fruit = excluded.fruit
- where i.* != excluded.* returning *;
- key | fruit
------+-----------
- 23 | Jackfruit
-(1 row)
-
--- No update this time, though:
-insert into insertconflicttest as i values (23, 'Jackfruit') on conflict (key) do update set fruit = excluded.fruit
- where i.* != excluded.* returning *;
- key | fruit
------+-------
-(0 rows)
-
--- Predicate changed to require match rather than non-match, so updates once more:
-insert into insertconflicttest as i values (23, 'Jackfruit') on conflict (key) do update set fruit = excluded.fruit
- where i.* = excluded.* returning *;
- key | fruit
------+-----------
- 23 | Jackfruit
-(1 row)
-
--- Assign:
-insert into insertconflicttest as i values (23, 'Avocado') on conflict (key) do update set fruit = excluded.*::text
- returning *;
- key | fruit
------+--------------
- 23 | (23,Avocado)
-(1 row)
-
--- deparse whole row var in WHERE and SET clauses:
-explain (costs off) insert into insertconflicttest as i values (23, 'Avocado') on conflict (key) do update set fruit = excluded.fruit where excluded.* is null;
- QUERY PLAN
------------------------------------------------
- Remote Subquery Scan on all (datanode_1)
- -> Insert on insertconflicttest i
- Conflict Resolution: UPDATE
- Conflict Arbiter Indexes: plain
- Conflict Filter: (excluded.* IS NULL)
- -> Result
-(6 rows)
-
-explain (costs off) insert into insertconflicttest as i values (23, 'Avocado') on conflict (key) do update set fruit = excluded.*::text;
- QUERY PLAN
-------------------------------------------
- Remote Subquery Scan on all (datanode_1)
- -> Insert on insertconflicttest i
- Conflict Resolution: UPDATE
- Conflict Arbiter Indexes: plain
- -> Result
-(5 rows)
-
-drop index plain;
-- Cleanup
drop table insertconflicttest;
-- ******************************************************************
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 751815c517..3942c3bee9 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -474,18 +474,6 @@ SELECT json_agg(q)
{"x":3,"y":"txt3"}]
(1 row)
-UPDATE rows SET x = NULL WHERE x = 1;
-ERROR: could not plan this distributed update
-DETAIL: correlated UPDATE or updating distribution column currently not supported in Postgres-XL.
-SELECT json_agg(q ORDER BY x NULLS FIRST, y)
- FROM rows q;
- json_agg
------------------------
- [{"x":1,"y":"txt1"}, +
- {"x":2,"y":"txt2"}, +
- {"x":3,"y":"txt3"}]
-(1 row)
-
-- non-numeric output
SELECT row_to_json(q)
FROM (SELECT 'NaN'::float8 AS "float8field") q;
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index 3ef40f821e..171520275d 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -376,16 +376,6 @@ SELECT jsonb_agg(q)
[{"x": 1, "y": "txt1"}, {"x": 2, "y": "txt2"}, {"x": 3, "y": "txt3"}]
(1 row)
-UPDATE rows SET x = NULL WHERE x = 1;
-ERROR: could not plan this distributed update
-DETAIL: correlated UPDATE or updating distribution column currently not supported in Postgres-XL.
-SELECT jsonb_agg(q ORDER BY x NULLS FIRST, y)
- FROM rows q;
- jsonb_agg
------------------------------------------------------------------------
- [{"x": 1, "y": "txt1"}, {"x": 2, "y": "txt2"}, {"x": 3, "y": "txt3"}]
-(1 row)
-
-- jsonb extraction functions
CREATE TEMP TABLE test_jsonb (
json_type text,
diff --git a/src/test/regress/expected/plpgsql_1.out b/src/test/regress/expected/plpgsql_1.out
index 45936927e3..a337e4a440 100644
--- a/src/test/regress/expected/plpgsql_1.out
+++ b/src/test/regress/expected/plpgsql_1.out
@@ -2036,7 +2036,7 @@ select trap_matching_test(1);
ERROR: Internal subtransactions not supported in Postgres-XL
CONTEXT: PL/pgSQL function trap_matching_test(integer) line 6 during statement block entry
create temp table foo (f1 int);
-create function subxact_rollback_semantics() returns int as $$
+create function blockme() returns int as $$
declare x int;
begin
x := 1;
@@ -2044,46 +2044,31 @@ begin
begin
x := x + 1;
insert into foo values(x);
- raise exception 'inner';
+ -- we assume this will take longer than 2 seconds:
+ select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
exception
when others then
+ raise notice 'caught others?';
+ return -1;
+ when query_canceled then
+ raise notice 'nyeah nyeah, can''t stop me';
x := x * 10;
end;
insert into foo values(x);
return x;
end$$ language plpgsql;
-select subxact_rollback_semantics();
+set statement_timeout to 2000;
+select blockme();
ERROR: Internal subtransactions not supported in Postgres-XL
-CONTEXT: PL/pgSQL function subxact_rollback_semantics() line 6 during statement block entry
-select * from foo;
+CONTEXT: PL/pgSQL function blockme() line 6 during statement block entry
+reset statement_timeout;
+select * from foo order by 1;
f1
----
1
(1 row)
drop table foo;
-create function trap_timeout() returns void as $$
-begin
- declare x int;
- begin
- -- we assume this will take longer than 2 seconds:
- select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
- exception
- when others then
- raise notice 'caught others?';
- when query_canceled then
- raise notice 'nyeah nyeah, can''t stop me';
- end;
- -- Abort transaction to abandon the statement_timeout setting. Otherwise,
- -- the next top-level statement would be vulnerable to the timeout.
- raise exception 'end of function';
-end$$ language plpgsql;
-begin;
-set statement_timeout to 2000;
-select trap_timeout();
-ERROR: Internal subtransactions not supported in Postgres-XL
-CONTEXT: PL/pgSQL function trap_timeout() line 4 during statement block entry
-rollback;
-- Test for pass-by-ref values being stored in proper context
create function test_variable_storage() returns text as $$
declare x text;
@@ -3109,7 +3094,7 @@ begin
end$$ language plpgsql;
select footest();
ERROR: query returned no rows
-CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE statement
create or replace function footest() returns void as $$
declare x record;
begin
@@ -3119,7 +3104,7 @@ begin
end$$ language plpgsql;
select footest();
ERROR: query returned more than one row
-CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE statement
drop function footest();
-- test printing parameters after failure due to STRICT
set plpgsql.print_strict_params to true;
@@ -3171,7 +3156,7 @@ end$$ language plpgsql;
select footest();
ERROR: query returned no rows
DETAIL: parameters: $1 = '0', $2 = 'foo'
-CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE statement
create or replace function footest() returns void as $$
declare x record;
begin
@@ -3182,7 +3167,7 @@ end$$ language plpgsql;
select footest();
ERROR: query returned more than one row
DETAIL: parameters: $1 = '1'
-CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE statement
create or replace function footest() returns void as $$
declare x record;
begin
@@ -3192,7 +3177,7 @@ begin
end$$ language plpgsql;
select footest();
ERROR: query returned more than one row
-CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE
+CONTEXT: PL/pgSQL function footest() line 5 at EXECUTE statement
create or replace function footest() returns void as $$
-- override the global
#print_strict_params off
@@ -4184,7 +4169,7 @@ end;
$$ language plpgsql;
select stacked_diagnostics_test();
ERROR: GET STACKED DIAGNOSTICS cannot be used outside an exception handler
-CONTEXT: PL/pgSQL function stacked_diagnostics_test() line 6 at GET STACKED DIAGNOSTICS
+CONTEXT: PL/pgSQL function stacked_diagnostics_test() line 6 at GET DIAGNOSTICS
drop function zero_divide();
drop function stacked_diagnostics_test();
-- check cases where implicit SQLSTATE variable could be confused with
@@ -4628,63 +4613,6 @@ ERROR: current transaction is aborted, commands ignored until end of transactio
rollback;
drop function error2(p_name_table text);
drop function error1(text);
--- Test for proper handling of cast-expression caching
-create function sql_to_date(integer) returns date as $$
-select $1::text::date
-$$ language sql immutable strict;
-create cast (integer as date) with function sql_to_date(integer) as assignment;
-create function cast_invoker(integer) returns date as $$
-begin
- return $1;
-end$$ language plpgsql;
-select cast_invoker(20150717);
- cast_invoker
---------------
- 07-17-2015
-(1 row)
-
-select cast_invoker(20150718); -- second call crashed in pre-release 9.5
- cast_invoker
---------------
- 07-18-2015
-(1 row)
-
-begin;
-select cast_invoker(20150717);
- cast_invoker
---------------
- 07-17-2015
-(1 row)
-
-select cast_invoker(20150718);
- cast_invoker
---------------
- 07-18-2015
-(1 row)
-
-savepoint s1;
-ERROR: SAVEPOINT is not yet supported.
-select cast_invoker(20150718);
-ERROR: current transaction is aborted, commands ignored until end of transaction block
-select cast_invoker(-1); -- fails
-ERROR: current transaction is aborted, commands ignored until end of transaction block
-rollback to savepoint s1;
-ERROR: no such savepoint
-select cast_invoker(20150719);
-ERROR: current transaction is aborted, commands ignored until end of transaction block
-select cast_invoker(20150720);
-ERROR: current transaction is aborted, commands ignored until end of transaction block
-commit;
-drop function cast_invoker(integer);
-drop function sql_to_date(integer) cascade;
-NOTICE: drop cascades to cast from integer to date
--- Test handling of cast cache inside DO blocks
--- (to check the original crash case, this must be a cast not previously
--- used in this session)
-begin;
-do $$ declare x text[]; begin x := '{1.23, 4.56}'::numeric[]; end $$;
-do $$ declare x text[]; begin x := '{1.23, 4.56}'::numeric[]; end $$;
-end;
-- Test for consistent reporting of error context
create function fail() returns int language plpgsql as $$
begin
diff --git a/src/test/regress/expected/prepared_xacts_2.out b/src/test/regress/expected/prepared_xacts_2.out
index ce5a30c2eb..31c9501cf3 100644
--- a/src/test/regress/expected/prepared_xacts_2.out
+++ b/src/test/regress/expected/prepared_xacts_2.out
@@ -229,11 +229,10 @@ SELECT pgxc_prepared_xact FROM pgxc_prepared_xacts ORDER by 1;
(1 row)
-- pxtest3 should be locked because of the pending DROP
-begin;
set statement_timeout to 2000;
SELECT * FROM pxtest3;
ERROR: canceling statement due to statement timeout
-rollback;
+reset statement_timeout;
-- Disconnect, we will continue testing in a different backend
\c -
-- There should still be two prepared transactions
@@ -251,11 +250,10 @@ SELECT pgxc_prepared_xact FROM pgxc_prepared_xacts ORDER by 1;
(1 row)
-- pxtest3 should still be locked because of the pending DROP
-begin;
set statement_timeout to 2000;
SELECT * FROM pxtest3;
ERROR: canceling statement due to statement timeout
-rollback;
+reset statement_timeout;
-- Commit table creation
COMMIT PREPARED 'regress-one';
ERROR: prepared transaction with identifier "regress-one" does not exist
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index b1788dd4dc..7ac57e1f53 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2077,7 +2077,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
| JOIN pg_class c ON ((c.oid = s.starelid))) +
| JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) +
| LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) +
- | WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid))));
+ | WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text));
pg_tables | SELECT n.nspname AS schemaname, +
| c.relname AS tablename, +
| pg_get_userbyid(c.relowner) AS tableowner, +
@@ -3930,13 +3930,13 @@ SELECT tablename, rulename, definition FROM pg_rules
-- ensure explain works for on insert conflict rules
explain (costs off) INSERT INTO hats VALUES ('h8', 'forbidden') RETURNING *;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------------
Remote Subquery Scan on all (datanode_1)
-> Insert on hat_data
Conflict Resolution: UPDATE
Conflict Arbiter Indexes: hat_data_unique_idx
- Conflict Filter: ((excluded.hat_color <> 'forbidden'::bpchar) AND (hat_data.* <> excluded.*))
+ Conflict Filter: (excluded.hat_color <> 'forbidden'::bpchar)
-> Result
(6 rows)
@@ -3958,13 +3958,13 @@ EXPLAIN (nodes off, costs off) WITH data(hat_name, hat_color) AS (
INSERT INTO hats
SELECT * FROM data
RETURNING *;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------------
Remote Subquery Scan on all
-> Insert on hat_data
Conflict Resolution: UPDATE
Conflict Arbiter Indexes: hat_data_unique_idx
- Conflict Filter: ((excluded.hat_color <> 'forbidden'::bpchar) AND (hat_data.* <> excluded.*))
+ Conflict Filter: (excluded.hat_color <> 'forbidden'::bpchar)
CTE data
-> Values Scan on "*VALUES*"
-> Remote Subquery Scan on all
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index cc2ebdf5a1..bb126edfdb 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -1699,7 +1699,7 @@ ERROR: Postgres-XL does not support TRIGGER yet
DETAIL: The feature is not currently supported
CREATE VIEW rw_view1 AS SELECT * FROM base_tbl WHERE a < b WITH CHECK OPTION;
INSERT INTO rw_view1 VALUES (5,0); -- ok
-ERROR: new row violates check option for view "rw_view1"
+ERROR: new row violates WITH CHECK OPTION for "rw_view1"
DETAIL: Failing row contains (5, 0).
INSERT INTO rw_view1 VALUES (15, 20); -- should fail
UPDATE rw_view1 SET a = 20, b = 30; -- should fail
@@ -1734,7 +1734,7 @@ DETAIL: The feature is not currently supported
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 check option for view "rw_view2"
+ERROR: new row violates WITH CHECK OPTION for "rw_view2"
DETAIL: Failing row contains (-5, null).
INSERT INTO rw_view2 VALUES (5); -- ok
INSERT INTO rw_view2 VALUES (50); -- ok, but not in view
@@ -1749,7 +1749,7 @@ SELECT * FROM base_tbl;
-- 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)
-ERROR: new row violates check option for view "rw_view1"
+ERROR: new row violates WITH CHECK OPTION for "rw_view1"
DETAIL: Failing row contains (100, null).
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;
diff --git a/src/test/regress/output/largeobject_3.source b/src/test/regress/output/largeobject_3.source
index 18e22769d2..c2bd3f6a4b 100644
--- a/src/test/regress/output/largeobject_3.source
+++ b/src/test/regress/output/largeobject_3.source
@@ -20,7 +20,7 @@ DO $$
END
$$;
ERROR: query string argument of EXECUTE is null
-CONTEXT: PL/pgSQL function inline_code_block line 3 at EXECUTE
+CONTEXT: PL/pgSQL function inline_code_block line 3 at EXECUTE statement
SELECT
rol.rolname
FROM
diff --git a/src/test/regress/output/misc_1.source b/src/test/regress/output/misc_1.source
index 23ed7b3ea2..9df04295f1 100644
--- a/src/test/regress/output/misc_1.source
+++ b/src/test/regress/output/misc_1.source
@@ -450,353 +450,87 @@ SELECT class, aa, a FROM a_star* ORDER BY 1,2;
--
-- versions
--
---
--- postquel functions
---
---
--- mike does post_hacking,
--- joe and sally play basketball, and
--- everyone else does nothing.
---
-SELECT p.name, name(p.hobbies) FROM ONLY person p ORDER BY 1,2;
- name | name
--------+-------------
- joe | basketball
- mike | posthacking
- sally | basketball
-(3 rows)
-
---
--- as above, but jeff also does post_hacking.
---
-SELECT p.name, name(p.hobbies) FROM person* p ORDER BY 1,2;
- name | name
--------+-------------
- jeff | posthacking
- joe | basketball
- mike | posthacking
- sally | basketball
-(4 rows)
-
---
--- the next two queries demonstrate how functions generate bogus duplicates.
--- this is a "feature" ..
---
-SELECT DISTINCT hobbies_r.name, name(hobbies_r.equipment) FROM hobbies_r
- ORDER BY 1,2;
- name | name
--------------+---------------
- basketball | hightops
- posthacking | advil
- posthacking | peet's coffee
- skywalking | guts
-(4 rows)
-
-SELECT hobbies_r.name, (hobbies_r.equipment).name FROM hobbies_r ORDER BY 1,2;
- name | name
--------------+---------------
- basketball | hightops
- basketball | hightops
- posthacking | advil
- posthacking | advil
- posthacking | peet's coffee
- posthacking | peet's coffee
- skywalking | guts
-(7 rows)
-
---
--- mike needs advil and peet's coffee,
--- joe and sally need hightops, and
--- everyone else is fine.
---
-SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM ONLY person p ORDER BY 1,2,3;
- name | name | name
--------+-------------+---------------
- joe | basketball | hightops
- mike | posthacking | advil
- mike | posthacking | peet's coffee
- sally | basketball | hightops
-(4 rows)
-
---
--- as above, but jeff needs advil and peet's coffee as well.
---
-SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM person* p ORDER BY 1,2,3;
- name | name | name
--------+-------------+---------------
- jeff | posthacking | advil
- jeff | posthacking | peet's coffee
- joe | basketball | hightops
- mike | posthacking | advil
- mike | posthacking | peet's coffee
- sally | basketball | hightops
-(6 rows)
-
---
--- just like the last two, but make sure that the target list fixup and
--- unflattening is being done correctly.
---
-SELECT name(equipment(p.hobbies)), p.name, name(p.hobbies) FROM ONLY person p ORDER BY 1,2,3;
- name | name | name
----------------+-------+-------------
- advil | mike | posthacking
- hightops | joe | basketball
- hightops | sally | basketball
- peet's coffee | mike | posthacking
-(4 rows)
-
-SELECT (p.hobbies).equipment.name, p.name, name(p.hobbies) FROM person* p ORDER BY 1,2,3;
- name | name | name
----------------+-------+-------------
- advil | jeff | posthacking
- advil | mike | posthacking
- hightops | joe | basketball
- hightops | sally | basketball
- peet's coffee | jeff | posthacking
- peet's coffee | mike | posthacking
-(6 rows)
-
-SELECT (p.hobbies).equipment.name, name(p.hobbies), p.name FROM ONLY person p ORDER BY 1,2,3;
- name | name | name
----------------+-------------+-------
- advil | posthacking | mike
- hightops | basketball | joe
- hightops | basketball | sally
- peet's coffee | posthacking | mike
-(4 rows)
-
-SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p ORDER BY 1,2,3;
- name | name | name
----------------+-------------+-------
- advil | posthacking | jeff
- advil | posthacking | mike
- hightops | basketball | joe
- hightops | basketball | sally
- peet's coffee | posthacking | jeff
- peet's coffee | posthacking | mike
-(6 rows)
-
-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
- box_tbl
- bprime
- bt_f8_heap
- 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
- emp
- equipment_r
- f_star
- fast_emp4000
- float4_tbl
- float8_tbl
- foobar
- func_index_heap
- hash_f8_heap
- hash_i4_heap
- hash_name_heap
- hash_txt_heap
- hobbies_r
- iexit
- ihighway
- inet_tbl
- inhf
- inhx
- insert_seq
- insert_tbl
- int2_tbl
- int4_tbl
- int8_tbl
- interval_tbl
- iportaltest
- kd_point_tbl
- log_table
- lseg_tbl
- main_table
- money_data
- num_data
- num_exp_add
- num_exp_div
- num_exp_ln
- num_exp_log10
- num_exp_mul
- num_exp_power_10_ln
- num_exp_sqrt
- num_exp_sub
- num_input_test
- num_result
- onek
- onek2
- path_tbl
- person
- point_tbl
- polygon_tbl
- quad_point_tbl
- ramp
- random_tbl
- real_city
- reltime_tbl
- road
- shighway
- slow_emp4000
- street
- stud_emp
- student
- subselect_tbl
- suffix_text_tbl
- tenk1
- tenk2
- test_range_excl
- test_range_gist
- test_tsvector
- text_tbl
- time_tbl
- timestamp_tbl
- timestamptz_tbl
- timetz_tbl
- tinterval_tbl
- toyemp
- varchar_tbl
- xacttest
-(108 rows)
-
-SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment(hobby_construct_named(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named(hobby_construct_named(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named_ambiguous_1a(hobby_construct_named(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named_ambiguous_1b(hobby_construct_named(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named_ambiguous_1c(hobby_construct_named(text 'skywalking', text 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named_ambiguous_2a(text 'skywalking'));
- name
-------
- guts
-(1 row)
-
-SELECT name(equipment_named_ambiguous_2b(text 'skywalking')) ORDER BY 1;
- name
----------------
- advil
- guts
- hightops
- peet's coffee
-(4 rows)
-
-SELECT hobbies_by_name('basketball');
- hobbies_by_name
------------------
- joe
-(1 row)
-
-SELECT name, overpaid(emp.*) FROM emp ORDER BY 1,2;
- name | overpaid
---------+----------
- bill | t
- cim | f
- jeff | f
- linda | f
- sam | t
- sharon | t
-(6 rows)
-
---
--- Try a few cases with SQL-spec row constructor expressions
---
-SELECT * FROM equipment(ROW('skywalking', 'mer'));
- name | hobby
-------+------------
- guts | skywalking
-(1 row)
-
-SELECT name(equipment(ROW('skywalking', 'mer')));
- name
-------
- guts
-(1 row)
-
-SELECT *, name(equipment(h.*)) FROM hobbies_r h ORDER BY 1,2,3;
- name | person | name
--------------+--------+---------------
- basketball | joe | hightops
- basketball | sally | hightops
- posthacking | jeff | advil
- posthacking | jeff | peet's coffee
- posthacking | mike | advil
- posthacking | mike | peet's coffee
- skywalking | | guts
-(7 rows)
-
-SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h ORDER BY 1,2,3;
- name | person | name
--------------+--------+---------------
- basketball | joe | hightops
- basketball | sally | hightops
- posthacking | jeff | advil
- posthacking | jeff | peet's coffee
- posthacking | mike | advil
- posthacking | mike | peet's coffee
- skywalking | | guts
-(7 rows)
-
+-- --
+-- -- postquel functions
+-- --
+-- --
+-- -- mike does post_hacking,
+-- -- joe and sally play basketball, and
+-- -- everyone else does nothing.
+-- --
+-- SELECT p.name, name(p.hobbies) FROM ONLY person p ORDER BY 1,2;
+--
+-- --
+-- -- as above, but jeff also does post_hacking.
+-- --
+-- SELECT p.name, name(p.hobbies) FROM person* p ORDER BY 1,2;
+--
+-- --
+-- -- the next two queries demonstrate how functions generate bogus duplicates.
+-- -- this is a "feature" ..
+-- --
+-- SELECT DISTINCT hobbies_r.name, name(hobbies_r.equipment) FROM hobbies_r
+-- ORDER BY 1,2;
+--
+-- SELECT hobbies_r.name, (hobbies_r.equipment).name FROM hobbies_r ORDER BY 1,2;
+--
+-- --
+-- -- mike needs advil and peet's coffee,
+-- -- joe and sally need hightops, and
+-- -- everyone else is fine.
+-- --
+-- SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM ONLY person p ORDER BY 1,2,3;
+--
+-- --
+-- -- as above, but jeff needs advil and peet's coffee as well.
+-- --
+-- SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM person* p ORDER BY 1,2,3;
+--
+-- --
+-- -- just like the last two, but make sure that the target list fixup and
+-- -- unflattening is being done correctly.
+-- --
+-- SELECT name(equipment(p.hobbies)), p.name, name(p.hobbies) FROM ONLY person p ORDER BY 1,2,3;
+--
+-- SELECT (p.hobbies).equipment.name, p.name, name(p.hobbies) FROM person* p ORDER BY 1,2,3;
+--
+-- SELECT (p.hobbies).equipment.name, name(p.hobbies), p.name FROM ONLY person p ORDER BY 1,2,3;
+--
+-- SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p ORDER BY 1,2,3;
+--
+-- SELECT user_relns() AS user_relns
+-- ORDER BY user_relns;
+--
+-- SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment(hobby_construct_named(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment_named(hobby_construct_named(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment_named_ambiguous_1a(hobby_construct_named(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment_named_ambiguous_1b(hobby_construct_named(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment_named_ambiguous_1c(hobby_construct_named(text 'skywalking', text 'mer')));
+--
+-- SELECT name(equipment_named_ambiguous_2a(text 'skywalking'));
+--
+-- SELECT name(equipment_named_ambiguous_2b(text 'skywalking')) ORDER BY 1;
+--
+-- SELECT hobbies_by_name('basketball');
+--
+-- SELECT name, overpaid(emp.*) FROM emp ORDER BY 1,2;
+--
+-- --
+-- -- Try a few cases with SQL-spec row constructor expressions
+-- --
+-- SELECT * FROM equipment(ROW('skywalking', 'mer'));
+--
+-- SELECT name(equipment(ROW('skywalking', 'mer')));
+--
+-- SELECT *, name(equipment(h.*)) FROM hobbies_r h ORDER BY 1,2,3;
+--
+-- SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h ORDER BY 1,2,3;
--
-- check that old-style C functions work properly with TOASTed values
--
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 38ae7294d1..2e0e134b6f 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -100,7 +100,7 @@ test: rules
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps json jsonb json_encoding indirect_toast equivclass
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps json jsonb indirect_toast equivclass
# ----------
# As XL uses advisory locks internally running this test separately.
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 94094c423a..cc0ab6125d 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -469,6 +469,44 @@ alter table tt14t drop column f3;
select pg_get_viewdef('tt14v', true);
select * from tt14v;
+-- check display of whole-row variables in some corner cases
+
+create type nestedcomposite as (x int8_tbl);
+create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
+select * from tt15v;
+select pg_get_viewdef('tt15v', true);
+select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
+
+create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
+select * from tt16v;
+select pg_get_viewdef('tt16v', true);
+select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
+
+create view tt17v as select * from int8_tbl i where i in (values(i));
+select * from tt17v;
+select pg_get_viewdef('tt17v', true);
+select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
+
+-- check unique-ification of overlength names
+
+create view tt18v as
+ select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy
+ union all
+ select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz;
+select pg_get_viewdef('tt18v', true);
+explain (costs off) select * from tt18v;
+
+-- check display of ScalarArrayOp with a sub-select
+
+select 'foo'::text = any(array['abc','def','foo']::text[]);
+select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
+select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
+
+create view tt19v as
+select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
+ 'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
+select pg_get_viewdef('tt19v', true);
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql
index 0bffb8531c..71cc0ec900 100644
--- a/src/test/regress/sql/groupingsets.sql
+++ b/src/test/regress/sql/groupingsets.sql
@@ -73,6 +73,35 @@ select grouping(a), a, array_agg(b),
select a, b, sum(c), sum(sum(c)) over (order by a,b) as rsum
from gstest2 group by rollup (a,b) order by rsum, a, b;
+-- nesting with grouping sets
+select sum(c) from gstest2
+ group by grouping sets((), grouping sets((), grouping sets(())))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets((), grouping sets((), grouping sets(((a, b)))))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(grouping sets(rollup(c), grouping sets(cube(c))))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(a, grouping sets(a, cube(b)))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(grouping sets((a, (b))))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(grouping sets((a, b)))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(grouping sets(a, grouping sets(a), a))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets(grouping sets(a, grouping sets(a, grouping sets(a), ((a)), a, grouping sets(a), (a)), a))
+ order by 1 desc;
+select sum(c) from gstest2
+ group by grouping sets((a,(a,b)), grouping sets((a,(a,b)),a))
+ order by 1 desc;
+
-- empty input: first is 0 rows, second 1, third 3 etc.
select a, b, sum(v), count(*) from gstest_empty group by grouping sets ((a,b),a);
select a, b, sum(v), count(*) from gstest_empty group by grouping sets ((a,b),());
@@ -154,6 +183,35 @@ select ten, sum(distinct four) from onek a
group by grouping sets((ten,four),(ten))
having exists (select 1 from onek b where sum(distinct a.four) = b.four);
+-- Tests around pushdown of HAVING clauses, partially testing against previous bugs
+select a,count(*) from gstest2 group by rollup(a) order by a;
+select a,count(*) from gstest2 group by rollup(a) having a is distinct from 1 order by a;
+explain (costs off)
+ select a,count(*) from gstest2 group by rollup(a) having a is distinct from 1 order by a;
+
+select v.c, (select count(*) from gstest2 group by () having v.c)
+ from (values (false),(true)) v(c) order by v.c;
+explain (costs off)
+ select v.c, (select count(*) from gstest2 group by () having v.c)
+ from (values (false),(true)) v(c) order by v.c;
+
+-- HAVING with GROUPING queries
+select ten, grouping(ten) from onek
+group by grouping sets(ten) having grouping(ten) >= 0
+order by 2,1;
+select ten, grouping(ten) from onek
+group by grouping sets(ten, four) having grouping(ten) > 0
+order by 2,1;
+select ten, grouping(ten) from onek
+group by rollup(ten) having grouping(ten) > 0
+order by 2,1;
+select ten, grouping(ten) from onek
+group by cube(ten) having grouping(ten) > 0
+order by 2,1;
+select ten, grouping(ten) from onek
+group by (ten) having grouping(ten) >= 0
+order by 2,1;
+
-- FILTER queries
select ten, sum(distinct four) filter (where four::text ~ '123') from onek a
group by rollup(ten);
@@ -162,4 +220,8 @@ group by rollup(ten);
select * from (values (1),(2)) v(a) left join lateral (select v.a, four, ten, count(*) from onek group by cube(four,ten)) s on true order by v.a,four,ten;
select array(select row(v.a,s1.*) from (select two,four, count(*) from onek group by cube(two,four) order by two,four) s1) from (values (1),(2)) v(a);
+-- Grouping on text columns
+select sum(ten) from onek group by two, rollup(four::text) order by 1;
+select sum(ten) from onek group by rollup(four::text), two order by 1;
+
-- end
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index 7329bedee4..994a7e1646 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -473,6 +473,27 @@ reset enable_seqscan;
drop table matest0 cascade;
--
+-- Check that use of an index with an extraneous column doesn't produce
+-- a plan with extraneous sorting
+--
+
+create table matest0 (a int, b int, c int, d int);
+create table matest1 () inherits(matest0);
+create index matest0i on matest0 (b, c);
+create index matest1i on matest1 (b, c);
+
+set enable_nestloop = off; -- we want a plan with two MergeAppends
+
+explain (costs off)
+select t1.* from matest0 t1, matest0 t2
+where t1.b = t2.b and t2.c = t2.d
+order by t1.b limit 10;
+
+reset enable_nestloop;
+
+drop table matest0 cascade;
+
+--
-- Test merge-append for UNION ALL append relations
--
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index c6b42fa9d3..2db3b94962 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -976,3 +976,87 @@ DROP USER regressuser3;
DROP USER regressuser4;
DROP USER regressuser5;
DROP USER regressuser6;
+
+
+-- permissions with LOCK TABLE
+CREATE USER locktable_user;
+CREATE TABLE lock_table (a int);
+
+-- LOCK TABLE and SELECT permission
+GRANT SELECT ON lock_table TO locktable_user;
+SET SESSION AUTHORIZATION locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should fail
+ROLLBACK;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
+COMMIT;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
+ROLLBACK;
+\c
+REVOKE SELECT ON lock_table FROM locktable_user;
+
+-- LOCK TABLE and INSERT permission
+GRANT INSERT ON lock_table TO locktable_user;
+SET SESSION AUTHORIZATION locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
+ROLLBACK;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should fail
+ROLLBACK;
+\c
+REVOKE INSERT ON lock_table FROM locktable_user;
+
+-- LOCK TABLE and UPDATE permission
+GRANT UPDATE ON lock_table TO locktable_user;
+SET SESSION AUTHORIZATION locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
+ROLLBACK;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
+COMMIT;
+\c
+REVOKE UPDATE ON lock_table FROM locktable_user;
+
+-- LOCK TABLE and DELETE permission
+GRANT DELETE ON lock_table TO locktable_user;
+SET SESSION AUTHORIZATION locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
+ROLLBACK;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
+COMMIT;
+\c
+REVOKE DELETE ON lock_table FROM locktable_user;
+
+-- LOCK TABLE and TRUNCATE permission
+GRANT TRUNCATE ON lock_table TO locktable_user;
+SET SESSION AUTHORIZATION locktable_user;
+BEGIN;
+LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
+COMMIT;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should fail
+ROLLBACK;
+BEGIN;
+LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
+COMMIT;
+\c
+REVOKE TRUNCATE ON lock_table FROM locktable_user;
+
+-- clean up
+DROP TABLE lock_table;
+DROP USER locktable_user;
diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql
index d99fbf6500..6cdc986bb8 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -428,6 +428,38 @@ fetch from foo;
abort;
+
+-- Test for proper cleanup after a failure in a cursor portal
+-- that was created in an outer subtransaction
+CREATE FUNCTION invert(x float8) RETURNS float8 LANGUAGE plpgsql AS
+$$ begin return 1/x; end $$;
+
+CREATE FUNCTION create_temp_tab() RETURNS text
+LANGUAGE plpgsql AS $$
+BEGIN
+ CREATE TEMP TABLE new_table (f1 float8);
+ -- case of interest is that we fail while holding an open
+ -- relcache reference to new_table
+ INSERT INTO new_table SELECT invert(0.0);
+ RETURN 'foo';
+END $$;
+
+BEGIN;
+DECLARE ok CURSOR FOR SELECT * FROM int8_tbl;
+DECLARE ctt CURSOR FOR SELECT create_temp_tab();
+FETCH ok;
+SAVEPOINT s1;
+FETCH ok; -- should work
+FETCH ctt; -- error occurs here
+ROLLBACK TO s1;
+FETCH ok; -- should work
+FETCH ctt; -- must be rejected
+COMMIT;
+
+DROP FUNCTION create_temp_tab();
+DROP FUNCTION invert(x float8);
+
+
-- Test for successful cleanup of an aborted transaction at session exit.
-- THIS MUST BE THE LAST TEST IN THIS FILE.