mirror of https://github.com/postgres/postgres
Merge pull request #18 from percona/TDE_EXP_FILES_1075
Add TDE support and update expected files for tde_heap & tde_heap_basicpull/209/head
commit
5ad99f77be
@ -0,0 +1,578 @@ |
||||
-- |
||||
-- Create access method tests |
||||
-- |
||||
-- Make gist2 over gisthandler. In fact, it would be a synonym to gist. |
||||
CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler; |
||||
-- Verify return type checks for handlers |
||||
CREATE ACCESS METHOD bogus TYPE INDEX HANDLER int4in; |
||||
ERROR: function int4in(internal) does not exist |
||||
CREATE ACCESS METHOD bogus TYPE INDEX HANDLER heap_tableam_handler; |
||||
ERROR: function heap_tableam_handler must return type index_am_handler |
||||
-- Try to create gist2 index on fast_emp4000: fail because opclass doesn't exist |
||||
CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base); |
||||
ERROR: data type box has no default operator class for access method "gist2" |
||||
HINT: You must specify an operator class for the index or define a default operator class for the data type. |
||||
-- Make operator class for boxes using gist2 |
||||
CREATE OPERATOR CLASS box_ops DEFAULT |
||||
FOR TYPE box USING gist2 AS |
||||
OPERATOR 1 <<, |
||||
OPERATOR 2 &<, |
||||
OPERATOR 3 &&, |
||||
OPERATOR 4 &>, |
||||
OPERATOR 5 >>, |
||||
OPERATOR 6 ~=, |
||||
OPERATOR 7 @>, |
||||
OPERATOR 8 <@, |
||||
OPERATOR 9 &<|, |
||||
OPERATOR 10 <<|, |
||||
OPERATOR 11 |>>, |
||||
OPERATOR 12 |&>, |
||||
FUNCTION 1 gist_box_consistent(internal, box, smallint, oid, internal), |
||||
FUNCTION 2 gist_box_union(internal, internal), |
||||
-- don't need compress, decompress, or fetch functions |
||||
FUNCTION 5 gist_box_penalty(internal, internal, internal), |
||||
FUNCTION 6 gist_box_picksplit(internal, internal), |
||||
FUNCTION 7 gist_box_same(box, box, internal); |
||||
-- Create gist2 index on fast_emp4000 |
||||
CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base); |
||||
-- Now check the results from plain indexscan; temporarily drop existing |
||||
-- index grect2ind to ensure it doesn't capture the plan |
||||
BEGIN; |
||||
DROP INDEX grect2ind; |
||||
SET enable_seqscan = OFF; |
||||
SET enable_indexscan = ON; |
||||
SET enable_bitmapscan = OFF; |
||||
EXPLAIN (COSTS OFF) |
||||
SELECT * FROM fast_emp4000 |
||||
WHERE home_base <@ '(200,200),(2000,1000)'::box |
||||
ORDER BY (home_base[0])[0]; |
||||
QUERY PLAN |
||||
----------------------------------------------------------------- |
||||
Sort |
||||
Sort Key: ((home_base[0])[0]) |
||||
-> Index Only Scan using grect2ind2 on fast_emp4000 |
||||
Index Cond: (home_base <@ '(2000,1000),(200,200)'::box) |
||||
(4 rows) |
||||
|
||||
SELECT * FROM fast_emp4000 |
||||
WHERE home_base <@ '(200,200),(2000,1000)'::box |
||||
ORDER BY (home_base[0])[0]; |
||||
home_base |
||||
----------------------- |
||||
(337,455),(240,359) |
||||
(1444,403),(1346,344) |
||||
(2 rows) |
||||
|
||||
EXPLAIN (COSTS OFF) |
||||
SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; |
||||
QUERY PLAN |
||||
------------------------------------------------------------- |
||||
Aggregate |
||||
-> Index Only Scan using grect2ind2 on fast_emp4000 |
||||
Index Cond: (home_base && '(1000,1000),(0,0)'::box) |
||||
(3 rows) |
||||
|
||||
SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; |
||||
count |
||||
------- |
||||
2 |
||||
(1 row) |
||||
|
||||
EXPLAIN (COSTS OFF) |
||||
SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; |
||||
QUERY PLAN |
||||
-------------------------------------------------------- |
||||
Aggregate |
||||
-> Index Only Scan using grect2ind2 on fast_emp4000 |
||||
Index Cond: (home_base IS NULL) |
||||
(3 rows) |
||||
|
||||
SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL; |
||||
count |
||||
------- |
||||
278 |
||||
(1 row) |
||||
|
||||
ROLLBACK; |
||||
-- Try to drop access method: fail because of dependent objects |
||||
DROP ACCESS METHOD gist2; |
||||
ERROR: cannot drop access method gist2 because other objects depend on it |
||||
DETAIL: index grect2ind2 depends on operator class box_ops for access method gist2 |
||||
HINT: Use DROP ... CASCADE to drop the dependent objects too. |
||||
-- Drop access method cascade |
||||
-- To prevent a (rare) deadlock against autovacuum, |
||||
-- we must lock the table that owns the index that will be dropped |
||||
BEGIN; |
||||
LOCK TABLE fast_emp4000; |
||||
DROP ACCESS METHOD gist2 CASCADE; |
||||
NOTICE: drop cascades to index grect2ind2 |
||||
COMMIT; |
||||
-- |
||||
-- Test table access methods |
||||
-- |
||||
-- prevent empty values |
||||
SET default_table_access_method = ''; |
||||
ERROR: invalid value for parameter "default_table_access_method": "" |
||||
DETAIL: "default_table_access_method" cannot be empty. |
||||
-- prevent nonexistent values |
||||
SET default_table_access_method = 'I do not exist AM'; |
||||
ERROR: invalid value for parameter "default_table_access_method": "I do not exist AM" |
||||
DETAIL: Table access method "I do not exist AM" does not exist. |
||||
-- prevent setting it to an index AM |
||||
SET default_table_access_method = 'btree'; |
||||
ERROR: access method "btree" is not of type TABLE |
||||
-- Create a heap2 table am handler with heapam handler |
||||
CREATE ACCESS METHOD heap2 TYPE TABLE HANDLER heap_tableam_handler; |
||||
-- Verify return type checks for handlers |
||||
CREATE ACCESS METHOD bogus TYPE TABLE HANDLER int4in; |
||||
ERROR: function int4in(internal) does not exist |
||||
CREATE ACCESS METHOD bogus TYPE TABLE HANDLER bthandler; |
||||
ERROR: function bthandler must return type table_am_handler |
||||
SELECT amname, amhandler, amtype FROM pg_am where amtype = 't' ORDER BY 1, 2; |
||||
amname | amhandler | amtype |
||||
----------------+------------------------+-------- |
||||
heap | heap_tableam_handler | t |
||||
heap2 | heap_tableam_handler | t |
||||
tde_heap | pg_tdeam_handler | t |
||||
tde_heap_basic | pg_tdeam_basic_handler | t |
||||
(4 rows) |
||||
|
||||
-- First create tables employing the new AM using USING |
||||
-- plain CREATE TABLE |
||||
CREATE TABLE tableam_tbl_heap2(f1 int) USING heap2; |
||||
INSERT INTO tableam_tbl_heap2 VALUES(1); |
||||
SELECT f1 FROM tableam_tbl_heap2 ORDER BY f1; |
||||
f1 |
||||
---- |
||||
1 |
||||
(1 row) |
||||
|
||||
-- CREATE TABLE AS |
||||
CREATE TABLE tableam_tblas_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; |
||||
SELECT f1 FROM tableam_tbl_heap2 ORDER BY f1; |
||||
f1 |
||||
---- |
||||
1 |
||||
(1 row) |
||||
|
||||
-- SELECT INTO doesn't support USING |
||||
SELECT INTO tableam_tblselectinto_heap2 USING heap2 FROM tableam_tbl_heap2; |
||||
ERROR: syntax error at or near "USING" |
||||
LINE 1: SELECT INTO tableam_tblselectinto_heap2 USING heap2 FROM tab... |
||||
^ |
||||
-- CREATE VIEW doesn't support USING |
||||
CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; |
||||
ERROR: syntax error at or near "USING" |
||||
LINE 1: CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM ... |
||||
^ |
||||
-- CREATE SEQUENCE doesn't support USING |
||||
CREATE SEQUENCE tableam_seq_heap2 USING heap2; |
||||
ERROR: syntax error at or near "USING" |
||||
LINE 1: CREATE SEQUENCE tableam_seq_heap2 USING heap2; |
||||
^ |
||||
-- CREATE MATERIALIZED VIEW does support USING |
||||
CREATE MATERIALIZED VIEW tableam_tblmv_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2; |
||||
SELECT f1 FROM tableam_tblmv_heap2 ORDER BY f1; |
||||
f1 |
||||
---- |
||||
1 |
||||
(1 row) |
||||
|
||||
-- CREATE TABLE .. PARTITION BY supports USING. |
||||
CREATE TABLE tableam_parted_heap2 (a text, b int) PARTITION BY list (a) USING heap2; |
||||
SELECT a.amname FROM pg_class c, pg_am a |
||||
WHERE c.relname = 'tableam_parted_heap2' AND a.oid = c.relam; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
DROP TABLE tableam_parted_heap2; |
||||
CREATE TABLE tableam_parted_heap2 (a text, b int) PARTITION BY list (a); |
||||
-- new partitions will inherit from the current default, rather the partition root |
||||
SET default_table_access_method = 'heap'; |
||||
CREATE TABLE tableam_parted_a_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('a'); |
||||
SET default_table_access_method = 'heap2'; |
||||
CREATE TABLE tableam_parted_b_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('b'); |
||||
RESET default_table_access_method; |
||||
-- but the method can be explicitly specified |
||||
CREATE TABLE tableam_parted_c_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('c') USING heap; |
||||
CREATE TABLE tableam_parted_d_heap2 PARTITION OF tableam_parted_heap2 FOR VALUES IN ('d') USING heap2; |
||||
-- List all objects in AM |
||||
SELECT |
||||
pc.relkind, |
||||
pa.amname, |
||||
CASE WHEN relkind = 't' THEN |
||||
(SELECT 'toast for ' || relname::regclass FROM pg_class pcm WHERE pcm.reltoastrelid = pc.oid) |
||||
ELSE |
||||
relname::regclass::text |
||||
END COLLATE "C" AS relname |
||||
FROM pg_class AS pc, |
||||
pg_am AS pa |
||||
WHERE pa.oid = pc.relam |
||||
AND pa.amname = 'heap2' |
||||
ORDER BY 3, 1, 2; |
||||
relkind | amname | relname |
||||
---------+--------+---------------------------------- |
||||
r | heap2 | tableam_parted_b_heap2 |
||||
r | heap2 | tableam_parted_d_heap2 |
||||
r | heap2 | tableam_tbl_heap2 |
||||
r | heap2 | tableam_tblas_heap2 |
||||
m | heap2 | tableam_tblmv_heap2 |
||||
t | heap2 | toast for tableam_parted_b_heap2 |
||||
t | heap2 | toast for tableam_parted_d_heap2 |
||||
(7 rows) |
||||
|
||||
-- Show dependencies onto AM - there shouldn't be any for toast |
||||
SELECT pg_describe_object(classid,objid,objsubid) AS obj |
||||
FROM pg_depend, pg_am |
||||
WHERE pg_depend.refclassid = 'pg_am'::regclass |
||||
AND pg_am.oid = pg_depend.refobjid |
||||
AND pg_am.amname = 'heap2' |
||||
ORDER BY classid, objid, objsubid; |
||||
obj |
||||
--------------------------------------- |
||||
table tableam_tbl_heap2 |
||||
table tableam_tblas_heap2 |
||||
materialized view tableam_tblmv_heap2 |
||||
table tableam_parted_b_heap2 |
||||
table tableam_parted_d_heap2 |
||||
(5 rows) |
||||
|
||||
-- ALTER TABLE SET ACCESS METHOD |
||||
CREATE TABLE heaptable USING heap AS |
||||
SELECT a, repeat(a::text, 100) FROM generate_series(1,9) AS a; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; |
||||
amname |
||||
-------- |
||||
heap |
||||
(1 row) |
||||
|
||||
-- Switching to heap2 adds new dependency entry to the AM. |
||||
ALTER TABLE heaptable SET ACCESS METHOD heap2; |
||||
SELECT pg_describe_object(classid, objid, objsubid) as obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as objref, |
||||
deptype |
||||
FROM pg_depend |
||||
WHERE classid = 'pg_class'::regclass AND |
||||
objid = 'heaptable'::regclass |
||||
ORDER BY 1, 2; |
||||
obj | objref | deptype |
||||
-----------------+---------------------+--------- |
||||
table heaptable | access method heap2 | n |
||||
table heaptable | schema public | n |
||||
(2 rows) |
||||
|
||||
-- Switching to heap should not have a dependency entry to the AM. |
||||
ALTER TABLE heaptable SET ACCESS METHOD heap; |
||||
SELECT pg_describe_object(classid, objid, objsubid) as obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as objref, |
||||
deptype |
||||
FROM pg_depend |
||||
WHERE classid = 'pg_class'::regclass AND |
||||
objid = 'heaptable'::regclass |
||||
ORDER BY 1, 2; |
||||
obj | objref | deptype |
||||
-----------------+---------------+--------- |
||||
table heaptable | schema public | n |
||||
(1 row) |
||||
|
||||
ALTER TABLE heaptable SET ACCESS METHOD heap2; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
SELECT COUNT(a), COUNT(1) FILTER(WHERE a=1) FROM heaptable; |
||||
count | count |
||||
-------+------- |
||||
9 | 1 |
||||
(1 row) |
||||
|
||||
-- DEFAULT access method |
||||
BEGIN; |
||||
SET LOCAL default_table_access_method TO heap2; |
||||
ALTER TABLE heaptable SET ACCESS METHOD DEFAULT; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
SET LOCAL default_table_access_method TO heap; |
||||
ALTER TABLE heaptable SET ACCESS METHOD DEFAULT; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass; |
||||
amname |
||||
-------- |
||||
heap |
||||
(1 row) |
||||
|
||||
ROLLBACK; |
||||
-- ALTER MATERIALIZED VIEW SET ACCESS METHOD |
||||
CREATE MATERIALIZED VIEW heapmv USING heap AS SELECT * FROM heaptable; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heapmv'::regclass; |
||||
amname |
||||
-------- |
||||
heap |
||||
(1 row) |
||||
|
||||
ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap2; |
||||
SELECT amname FROM pg_class c, pg_am am |
||||
WHERE c.relam = am.oid AND c.oid = 'heapmv'::regclass; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
SELECT COUNT(a), COUNT(1) FILTER(WHERE a=1) FROM heapmv; |
||||
count | count |
||||
-------+------- |
||||
9 | 1 |
||||
(1 row) |
||||
|
||||
-- No support for multiple subcommands |
||||
ALTER TABLE heaptable SET ACCESS METHOD heap, SET ACCESS METHOD heap2; |
||||
ERROR: cannot have multiple SET ACCESS METHOD subcommands |
||||
ALTER TABLE heaptable SET ACCESS METHOD DEFAULT, SET ACCESS METHOD heap2; |
||||
ERROR: cannot have multiple SET ACCESS METHOD subcommands |
||||
ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap, SET ACCESS METHOD heap2; |
||||
ERROR: cannot have multiple SET ACCESS METHOD subcommands |
||||
DROP MATERIALIZED VIEW heapmv; |
||||
DROP TABLE heaptable; |
||||
-- Partitioned table with USING |
||||
CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x) USING heap2; |
||||
SELECT pg_describe_object(classid, objid, objsubid) AS obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj |
||||
FROM pg_depend, pg_am |
||||
WHERE pg_depend.refclassid = 'pg_am'::regclass |
||||
AND pg_am.oid = pg_depend.refobjid |
||||
AND pg_depend.objid = 'am_partitioned'::regclass; |
||||
obj | refobj |
||||
----------------------+--------------------- |
||||
table am_partitioned | access method heap2 |
||||
(1 row) |
||||
|
||||
DROP TABLE am_partitioned; |
||||
-- Partition hierarchies with access methods |
||||
BEGIN; |
||||
SET LOCAL default_table_access_method = 'heap'; |
||||
CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x); |
||||
-- pg_class.relam is 0, no dependency recorded between the AM and the |
||||
-- partitioned table. |
||||
SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; |
||||
relam |
||||
------- |
||||
0 |
||||
(1 row) |
||||
|
||||
SELECT pg_describe_object(classid, objid, objsubid) AS obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj |
||||
FROM pg_depend, pg_am |
||||
WHERE pg_depend.refclassid = 'pg_am'::regclass |
||||
AND pg_am.oid = pg_depend.refobjid |
||||
AND pg_depend.objid = 'am_partitioned'::regclass; |
||||
obj | refobj |
||||
-----+-------- |
||||
(0 rows) |
||||
|
||||
-- New default is set, with dependency added. |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD heap2; |
||||
SELECT a.amname FROM pg_class c, pg_am a |
||||
WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
SELECT pg_describe_object(classid, objid, objsubid) AS obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj |
||||
FROM pg_depend, pg_am |
||||
WHERE pg_depend.refclassid = 'pg_am'::regclass |
||||
AND pg_am.oid = pg_depend.refobjid |
||||
AND pg_depend.objid = 'am_partitioned'::regclass; |
||||
obj | refobj |
||||
----------------------+--------------------- |
||||
table am_partitioned | access method heap2 |
||||
(1 row) |
||||
|
||||
-- Default is set, with dependency updated. |
||||
SET LOCAL default_table_access_method = 'heap2'; |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD heap; |
||||
SELECT a.amname FROM pg_class c, pg_am a |
||||
WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; |
||||
amname |
||||
-------- |
||||
heap |
||||
(1 row) |
||||
|
||||
-- Dependency pinned, hence removed. |
||||
SELECT pg_describe_object(classid, objid, objsubid) AS obj, |
||||
pg_describe_object(refclassid, refobjid, refobjsubid) as refobj |
||||
FROM pg_depend, pg_am |
||||
WHERE pg_depend.refclassid = 'pg_am'::regclass |
||||
AND pg_am.oid = pg_depend.refobjid |
||||
AND pg_depend.objid = 'am_partitioned'::regclass; |
||||
obj | refobj |
||||
-----+-------- |
||||
(0 rows) |
||||
|
||||
-- Default and AM set in the clause are the same, relam should be set. |
||||
SET LOCAL default_table_access_method = 'heap2'; |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD heap2; |
||||
SELECT a.amname FROM pg_class c, pg_am a |
||||
WHERE c.relname = 'am_partitioned' AND a.oid = c.relam; |
||||
amname |
||||
-------- |
||||
heap2 |
||||
(1 row) |
||||
|
||||
-- Reset to default |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; |
||||
SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; |
||||
relam |
||||
------- |
||||
0 |
||||
(1 row) |
||||
|
||||
-- Upon ALTER TABLE SET ACCESS METHOD on a partitioned table, new partitions |
||||
-- will inherit the AM set. Existing partitioned are unchanged. |
||||
SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; |
||||
relam |
||||
------- |
||||
0 |
||||
(1 row) |
||||
|
||||
SET LOCAL default_table_access_method = 'heap'; |
||||
CREATE TABLE am_partitioned_0 PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 0); |
||||
SET LOCAL default_table_access_method = 'heap2'; |
||||
CREATE TABLE am_partitioned_1 PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 1); |
||||
SET LOCAL default_table_access_method = 'heap'; |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD heap2; |
||||
CREATE TABLE am_partitioned_2 PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 2); |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; |
||||
SELECT relam FROM pg_class WHERE relname = 'am_partitioned'; |
||||
relam |
||||
------- |
||||
0 |
||||
(1 row) |
||||
|
||||
CREATE TABLE am_partitioned_3 PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 3); |
||||
-- Partitioned table with relam at 0 |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD DEFAULT; |
||||
CREATE TABLE am_partitioned_5p PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 5) PARTITION BY hash(y); |
||||
-- Partitions of this partitioned table inherit default AM at creation |
||||
-- time. |
||||
CREATE TABLE am_partitioned_5p1 PARTITION OF am_partitioned_5p |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 1); |
||||
-- Partitioned table with relam set. |
||||
ALTER TABLE am_partitioned SET ACCESS METHOD heap2; |
||||
CREATE TABLE am_partitioned_6p PARTITION OF am_partitioned |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 6) PARTITION BY hash(y); |
||||
-- Partitions of this partitioned table inherit its AM. |
||||
CREATE TABLE am_partitioned_6p1 PARTITION OF am_partitioned_6p |
||||
FOR VALUES WITH (MODULUS 10, REMAINDER 1); |
||||
SELECT c.relname, a.amname FROM pg_class c, pg_am a |
||||
WHERE c.relam = a.oid AND |
||||
c.relname LIKE 'am_partitioned%' |
||||
UNION ALL |
||||
SELECT c.relname, 'default' FROM pg_class c |
||||
WHERE c.relam = 0 |
||||
AND c.relname LIKE 'am_partitioned%' ORDER BY 1; |
||||
relname | amname |
||||
--------------------+--------- |
||||
am_partitioned | heap2 |
||||
am_partitioned_0 | heap |
||||
am_partitioned_1 | heap2 |
||||
am_partitioned_2 | heap2 |
||||
am_partitioned_3 | heap |
||||
am_partitioned_5p | default |
||||
am_partitioned_5p1 | heap |
||||
am_partitioned_6p | heap2 |
||||
am_partitioned_6p1 | heap2 |
||||
(9 rows) |
||||
|
||||
DROP TABLE am_partitioned; |
||||
COMMIT; |
||||
-- Second, create objects in the new AM by changing the default AM |
||||
BEGIN; |
||||
SET LOCAL default_table_access_method = 'heap2'; |
||||
-- following tests should all respect the default AM |
||||
CREATE TABLE tableam_tbl_heapx(f1 int); |
||||
CREATE TABLE tableam_tblas_heapx AS SELECT * FROM tableam_tbl_heapx; |
||||
SELECT INTO tableam_tblselectinto_heapx FROM tableam_tbl_heapx; |
||||
CREATE MATERIALIZED VIEW tableam_tblmv_heapx USING heap2 AS SELECT * FROM tableam_tbl_heapx; |
||||
CREATE TABLE tableam_parted_heapx (a text, b int) PARTITION BY list (a); |
||||
CREATE TABLE tableam_parted_1_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('a', 'b'); |
||||
-- but an explicitly set AM overrides it |
||||
CREATE TABLE tableam_parted_2_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('c', 'd') USING heap; |
||||
-- sequences, views and foreign servers shouldn't have an AM |
||||
CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx; |
||||
CREATE SEQUENCE tableam_seq_heapx; |
||||
CREATE FOREIGN DATA WRAPPER fdw_heap2 VALIDATOR postgresql_fdw_validator; |
||||
CREATE SERVER fs_heap2 FOREIGN DATA WRAPPER fdw_heap2 ; |
||||
CREATE FOREIGN table tableam_fdw_heapx () SERVER fs_heap2; |
||||
-- Verify that new AM was used for tables, matviews, but not for sequences, views and fdws |
||||
SELECT |
||||
pc.relkind, |
||||
pa.amname, |
||||
CASE WHEN relkind = 't' THEN |
||||
(SELECT 'toast for ' || relname::regclass FROM pg_class pcm WHERE pcm.reltoastrelid = pc.oid) |
||||
ELSE |
||||
relname::regclass::text |
||||
END COLLATE "C" AS relname |
||||
FROM pg_class AS pc |
||||
LEFT JOIN pg_am AS pa ON (pa.oid = pc.relam) |
||||
WHERE pc.relname LIKE 'tableam_%_heapx' |
||||
ORDER BY 3, 1, 2; |
||||
relkind | amname | relname |
||||
---------+--------+----------------------------- |
||||
f | | tableam_fdw_heapx |
||||
r | heap2 | tableam_parted_1_heapx |
||||
r | heap | tableam_parted_2_heapx |
||||
p | | tableam_parted_heapx |
||||
S | | tableam_seq_heapx |
||||
r | heap2 | tableam_tbl_heapx |
||||
r | heap2 | tableam_tblas_heapx |
||||
m | heap2 | tableam_tblmv_heapx |
||||
r | heap2 | tableam_tblselectinto_heapx |
||||
v | | tableam_view_heapx |
||||
(10 rows) |
||||
|
||||
-- don't want to keep those tables, nor the default |
||||
ROLLBACK; |
||||
-- Third, check that we can neither create a table using a nonexistent |
||||
-- AM, nor using an index AM |
||||
CREATE TABLE i_am_a_failure() USING ""; |
||||
ERROR: zero-length delimited identifier at or near """" |
||||
LINE 1: CREATE TABLE i_am_a_failure() USING ""; |
||||
^ |
||||
CREATE TABLE i_am_a_failure() USING i_do_not_exist_am; |
||||
ERROR: access method "i_do_not_exist_am" does not exist |
||||
CREATE TABLE i_am_a_failure() USING "I do not exist AM"; |
||||
ERROR: access method "I do not exist AM" does not exist |
||||
CREATE TABLE i_am_a_failure() USING "btree"; |
||||
ERROR: access method "btree" is not of type TABLE |
||||
-- Other weird invalid cases that cause problems |
||||
CREATE FOREIGN TABLE fp PARTITION OF tableam_parted_a_heap2 DEFAULT SERVER x; |
||||
ERROR: "tableam_parted_a_heap2" is not partitioned |
||||
-- Drop table access method, which fails as objects depends on it |
||||
DROP ACCESS METHOD heap2; |
||||
ERROR: cannot drop access method heap2 because other objects depend on it |
||||
DETAIL: table tableam_tbl_heap2 depends on access method heap2 |
||||
table tableam_tblas_heap2 depends on access method heap2 |
||||
materialized view tableam_tblmv_heap2 depends on access method heap2 |
||||
table tableam_parted_b_heap2 depends on access method heap2 |
||||
table tableam_parted_d_heap2 depends on access method heap2 |
||||
HINT: Use DROP ... CASCADE to drop the dependent objects too. |
||||
-- we intentionally leave the objects created above alive, to verify pg_dump support |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,744 @@ |
||||
-- should fail, return type mismatch |
||||
create event trigger regress_event_trigger |
||||
on ddl_command_start |
||||
execute procedure pg_backend_pid(); |
||||
ERROR: function pg_backend_pid must return type event_trigger |
||||
-- OK |
||||
create function test_event_trigger() returns event_trigger as $$ |
||||
BEGIN |
||||
RAISE NOTICE 'test_event_trigger: % %', tg_event, tg_tag; |
||||
END |
||||
$$ language plpgsql; |
||||
-- should fail, can't call it as a plain function |
||||
SELECT test_event_trigger(); |
||||
ERROR: trigger functions can only be called as triggers |
||||
CONTEXT: compilation of PL/pgSQL function "test_event_trigger" near line 1 |
||||
-- should fail, event triggers cannot have declared arguments |
||||
create function test_event_trigger_arg(name text) |
||||
returns event_trigger as $$ BEGIN RETURN 1; END $$ language plpgsql; |
||||
ERROR: event trigger functions cannot have declared arguments |
||||
CONTEXT: compilation of PL/pgSQL function "test_event_trigger_arg" near line 1 |
||||
-- should fail, SQL functions cannot be event triggers |
||||
create function test_event_trigger_sql() returns event_trigger as $$ |
||||
SELECT 1 $$ language sql; |
||||
ERROR: SQL functions cannot return type event_trigger |
||||
-- should fail, no elephant_bootstrap entry point |
||||
create event trigger regress_event_trigger on elephant_bootstrap |
||||
execute procedure test_event_trigger(); |
||||
ERROR: unrecognized event name "elephant_bootstrap" |
||||
-- OK |
||||
create event trigger regress_event_trigger on ddl_command_start |
||||
execute procedure test_event_trigger(); |
||||
-- OK |
||||
create event trigger regress_event_trigger_end on ddl_command_end |
||||
execute function test_event_trigger(); |
||||
-- should fail, food is not a valid filter variable |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when food in ('sandwich') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: unrecognized filter variable "food" |
||||
-- should fail, sandwich is not a valid command tag |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('sandwich') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: filter value "sandwich" not recognized for filter variable "tag" |
||||
-- should fail, create skunkcabbage is not a valid command tag |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('create table', 'create skunkcabbage') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: filter value "create skunkcabbage" not recognized for filter variable "tag" |
||||
-- should fail, can't have event triggers on event triggers |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('DROP EVENT TRIGGER') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: event triggers are not supported for DROP EVENT TRIGGER |
||||
-- should fail, can't have event triggers on global objects |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('CREATE ROLE') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: event triggers are not supported for CREATE ROLE |
||||
-- should fail, can't have event triggers on global objects |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('CREATE DATABASE') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: event triggers are not supported for CREATE DATABASE |
||||
-- should fail, can't have event triggers on global objects |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('CREATE TABLESPACE') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: event triggers are not supported for CREATE TABLESPACE |
||||
-- should fail, can't have same filter variable twice |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('create table') and tag in ('CREATE FUNCTION') |
||||
execute procedure test_event_trigger(); |
||||
ERROR: filter variable "tag" specified more than once |
||||
-- should fail, can't have arguments |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
execute procedure test_event_trigger('argument not allowed'); |
||||
ERROR: syntax error at or near "'argument not allowed'" |
||||
LINE 2: execute procedure test_event_trigger('argument not allowe... |
||||
^ |
||||
-- OK |
||||
create event trigger regress_event_trigger2 on ddl_command_start |
||||
when tag in ('create table', 'CREATE FUNCTION') |
||||
execute procedure test_event_trigger(); |
||||
-- OK |
||||
comment on event trigger regress_event_trigger is 'test comment'; |
||||
-- drop as non-superuser should fail |
||||
create role regress_evt_user; |
||||
set role regress_evt_user; |
||||
create event trigger regress_event_trigger_noperms on ddl_command_start |
||||
execute procedure test_event_trigger(); |
||||
ERROR: permission denied to create event trigger "regress_event_trigger_noperms" |
||||
HINT: Must be superuser to create an event trigger. |
||||
reset role; |
||||
-- test enabling and disabling |
||||
alter event trigger regress_event_trigger disable; |
||||
-- fires _trigger2 and _trigger_end should fire, but not _trigger |
||||
create table event_trigger_fire1 (a int); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE |
||||
alter event trigger regress_event_trigger enable; |
||||
set session_replication_role = replica; |
||||
-- fires nothing |
||||
create table event_trigger_fire2 (a int); |
||||
alter event trigger regress_event_trigger enable replica; |
||||
-- fires only _trigger |
||||
create table event_trigger_fire3 (a int); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
alter event trigger regress_event_trigger enable always; |
||||
-- fires only _trigger |
||||
create table event_trigger_fire4 (a int); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
reset session_replication_role; |
||||
-- fires all three |
||||
create table event_trigger_fire5 (a int); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE |
||||
-- non-top-level command |
||||
create function f1() returns int |
||||
language plpgsql |
||||
as $$ |
||||
begin |
||||
create table event_trigger_fire6 (a int); |
||||
return 0; |
||||
end $$; |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE FUNCTION |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE FUNCTION |
||||
select f1(); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE |
||||
f1 |
||||
---- |
||||
0 |
||||
(1 row) |
||||
|
||||
-- non-top-level command |
||||
create procedure p1() |
||||
language plpgsql |
||||
as $$ |
||||
begin |
||||
create table event_trigger_fire7 (a int); |
||||
end $$; |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE PROCEDURE |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE PROCEDURE |
||||
call p1(); |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_start CREATE TABLE |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE TABLE |
||||
-- clean up |
||||
alter event trigger regress_event_trigger disable; |
||||
drop table event_trigger_fire2, event_trigger_fire3, event_trigger_fire4, event_trigger_fire5, event_trigger_fire6, event_trigger_fire7; |
||||
NOTICE: test_event_trigger: ddl_command_end DROP TABLE |
||||
drop routine f1(), p1(); |
||||
NOTICE: test_event_trigger: ddl_command_end DROP ROUTINE |
||||
-- regress_event_trigger_end should fire on these commands |
||||
grant all on table event_trigger_fire1 to public; |
||||
NOTICE: test_event_trigger: ddl_command_end GRANT |
||||
comment on table event_trigger_fire1 is 'here is a comment'; |
||||
NOTICE: test_event_trigger: ddl_command_end COMMENT |
||||
revoke all on table event_trigger_fire1 from public; |
||||
NOTICE: test_event_trigger: ddl_command_end REVOKE |
||||
drop table event_trigger_fire1; |
||||
NOTICE: test_event_trigger: ddl_command_end DROP TABLE |
||||
create foreign data wrapper useless; |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE FOREIGN DATA WRAPPER |
||||
create server useless_server foreign data wrapper useless; |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE SERVER |
||||
create user mapping for regress_evt_user server useless_server; |
||||
NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING |
||||
alter default privileges for role regress_evt_user |
||||
revoke delete on tables from regress_evt_user; |
||||
NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES |
||||
-- alter owner to non-superuser should fail |
||||
alter event trigger regress_event_trigger owner to regress_evt_user; |
||||
ERROR: permission denied to change owner of event trigger "regress_event_trigger" |
||||
HINT: The owner of an event trigger must be a superuser. |
||||
-- alter owner to superuser should work |
||||
alter role regress_evt_user superuser; |
||||
alter event trigger regress_event_trigger owner to regress_evt_user; |
||||
-- should fail, name collision |
||||
alter event trigger regress_event_trigger rename to regress_event_trigger2; |
||||
ERROR: event trigger "regress_event_trigger2" already exists |
||||
-- OK |
||||
alter event trigger regress_event_trigger rename to regress_event_trigger3; |
||||
-- should fail, doesn't exist any more |
||||
drop event trigger regress_event_trigger; |
||||
ERROR: event trigger "regress_event_trigger" does not exist |
||||
-- should fail, regress_evt_user owns some objects |
||||
drop role regress_evt_user; |
||||
ERROR: role "regress_evt_user" cannot be dropped because some objects depend on it |
||||
DETAIL: owner of event trigger regress_event_trigger3 |
||||
owner of user mapping for regress_evt_user on server useless_server |
||||
owner of default privileges on new relations belonging to role regress_evt_user |
||||
-- cleanup before next test |
||||
-- these are all OK; the second one should emit a NOTICE |
||||
drop event trigger if exists regress_event_trigger2; |
||||
drop event trigger if exists regress_event_trigger2; |
||||
NOTICE: event trigger "regress_event_trigger2" does not exist, skipping |
||||
drop event trigger regress_event_trigger3; |
||||
drop event trigger regress_event_trigger_end; |
||||
-- test support for dropped objects |
||||
CREATE SCHEMA schema_one authorization regress_evt_user; |
||||
CREATE SCHEMA schema_two authorization regress_evt_user; |
||||
CREATE SCHEMA audit_tbls authorization regress_evt_user; |
||||
CREATE TEMP TABLE a_temp_tbl (); |
||||
SET SESSION AUTHORIZATION regress_evt_user; |
||||
CREATE TABLE schema_one.table_one(a int); |
||||
CREATE TABLE schema_one."table two"(a int); |
||||
CREATE TABLE schema_one.table_three(a int); |
||||
CREATE TABLE audit_tbls.schema_one_table_two(the_value text); |
||||
CREATE TABLE schema_two.table_two(a int); |
||||
CREATE TABLE schema_two.table_three(a int, b text); |
||||
CREATE TABLE audit_tbls.schema_two_table_three(the_value text); |
||||
CREATE OR REPLACE FUNCTION schema_two.add(int, int) RETURNS int LANGUAGE plpgsql |
||||
CALLED ON NULL INPUT |
||||
AS $$ BEGIN RETURN coalesce($1,0) + coalesce($2,0); END; $$; |
||||
CREATE AGGREGATE schema_two.newton |
||||
(BASETYPE = int, SFUNC = schema_two.add, STYPE = int); |
||||
RESET SESSION AUTHORIZATION; |
||||
CREATE TABLE undroppable_objs ( |
||||
object_type text, |
||||
object_identity text |
||||
); |
||||
INSERT INTO undroppable_objs VALUES |
||||
('table', 'schema_one.table_three'), |
||||
('table', 'audit_tbls.schema_two_table_three'); |
||||
CREATE TABLE dropped_objects ( |
||||
type text, |
||||
schema text, |
||||
object text |
||||
); |
||||
-- This tests errors raised within event triggers; the one in audit_tbls |
||||
-- uses 2nd-level recursive invocation via test_evtrig_dropped_objects(). |
||||
CREATE OR REPLACE FUNCTION undroppable() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
DECLARE |
||||
obj record; |
||||
BEGIN |
||||
PERFORM 1 FROM pg_tables WHERE tablename = 'undroppable_objs'; |
||||
IF NOT FOUND THEN |
||||
RAISE NOTICE 'table undroppable_objs not found, skipping'; |
||||
RETURN; |
||||
END IF; |
||||
FOR obj IN |
||||
SELECT * FROM pg_event_trigger_dropped_objects() JOIN |
||||
undroppable_objs USING (object_type, object_identity) |
||||
LOOP |
||||
RAISE EXCEPTION 'object % of type % cannot be dropped', |
||||
obj.object_identity, obj.object_type; |
||||
END LOOP; |
||||
END; |
||||
$$; |
||||
CREATE EVENT TRIGGER undroppable ON sql_drop |
||||
EXECUTE PROCEDURE undroppable(); |
||||
CREATE OR REPLACE FUNCTION test_evtrig_dropped_objects() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
DECLARE |
||||
obj record; |
||||
BEGIN |
||||
FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() |
||||
LOOP |
||||
IF obj.object_type = 'table' THEN |
||||
EXECUTE format('DROP TABLE IF EXISTS audit_tbls.%I', |
||||
format('%s_%s', obj.schema_name, obj.object_name)); |
||||
END IF; |
||||
|
||||
INSERT INTO dropped_objects |
||||
(type, schema, object) VALUES |
||||
(obj.object_type, obj.schema_name, obj.object_identity); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
CREATE EVENT TRIGGER regress_event_trigger_drop_objects ON sql_drop |
||||
WHEN TAG IN ('drop table', 'drop function', 'drop view', |
||||
'drop owned', 'drop schema', 'alter table') |
||||
EXECUTE PROCEDURE test_evtrig_dropped_objects(); |
||||
ALTER TABLE schema_one.table_one DROP COLUMN a; |
||||
DROP SCHEMA schema_one, schema_two CASCADE; |
||||
NOTICE: drop cascades to 7 other objects |
||||
DETAIL: drop cascades to table schema_two.table_two |
||||
drop cascades to table schema_two.table_three |
||||
drop cascades to function schema_two.add(integer,integer) |
||||
drop cascades to function schema_two.newton(integer) |
||||
drop cascades to table schema_one.table_one |
||||
drop cascades to table schema_one."table two" |
||||
drop cascades to table schema_one.table_three |
||||
NOTICE: table "schema_two_table_two" does not exist, skipping |
||||
NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping |
||||
ERROR: object audit_tbls.schema_two_table_three of type table cannot be dropped |
||||
CONTEXT: PL/pgSQL function undroppable() line 14 at RAISE |
||||
SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three" |
||||
PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE |
||||
DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three'; |
||||
DROP SCHEMA schema_one, schema_two CASCADE; |
||||
NOTICE: drop cascades to 7 other objects |
||||
DETAIL: drop cascades to table schema_two.table_two |
||||
drop cascades to table schema_two.table_three |
||||
drop cascades to function schema_two.add(integer,integer) |
||||
drop cascades to function schema_two.newton(integer) |
||||
drop cascades to table schema_one.table_one |
||||
drop cascades to table schema_one."table two" |
||||
drop cascades to table schema_one.table_three |
||||
NOTICE: table "schema_two_table_two" does not exist, skipping |
||||
NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping |
||||
NOTICE: table "schema_one_table_one" does not exist, skipping |
||||
NOTICE: table "schema_one_table two" does not exist, skipping |
||||
NOTICE: table "schema_one_table_three" does not exist, skipping |
||||
ERROR: object schema_one.table_three of type table cannot be dropped |
||||
CONTEXT: PL/pgSQL function undroppable() line 14 at RAISE |
||||
DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three'; |
||||
DROP SCHEMA schema_one, schema_two CASCADE; |
||||
NOTICE: drop cascades to 7 other objects |
||||
DETAIL: drop cascades to table schema_two.table_two |
||||
drop cascades to table schema_two.table_three |
||||
drop cascades to function schema_two.add(integer,integer) |
||||
drop cascades to function schema_two.newton(integer) |
||||
drop cascades to table schema_one.table_one |
||||
drop cascades to table schema_one."table two" |
||||
drop cascades to table schema_one.table_three |
||||
NOTICE: table "schema_two_table_two" does not exist, skipping |
||||
NOTICE: table "audit_tbls_schema_two_table_three" does not exist, skipping |
||||
NOTICE: table "schema_one_table_one" does not exist, skipping |
||||
NOTICE: table "schema_one_table two" does not exist, skipping |
||||
NOTICE: table "schema_one_table_three" does not exist, skipping |
||||
SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast'; |
||||
type | schema | object |
||||
--------------+------------+------------------------------------- |
||||
table column | schema_one | schema_one.table_one.a |
||||
schema | | schema_two |
||||
table | schema_two | schema_two.table_two |
||||
type | schema_two | schema_two.table_two |
||||
type | schema_two | schema_two.table_two[] |
||||
table | audit_tbls | audit_tbls.schema_two_table_three |
||||
type | audit_tbls | audit_tbls.schema_two_table_three |
||||
type | audit_tbls | audit_tbls.schema_two_table_three[] |
||||
table | schema_two | schema_two.table_three |
||||
type | schema_two | schema_two.table_three |
||||
type | schema_two | schema_two.table_three[] |
||||
function | schema_two | schema_two.add(integer,integer) |
||||
aggregate | schema_two | schema_two.newton(integer) |
||||
schema | | schema_one |
||||
table | schema_one | schema_one.table_one |
||||
type | schema_one | schema_one.table_one |
||||
type | schema_one | schema_one.table_one[] |
||||
table | schema_one | schema_one."table two" |
||||
type | schema_one | schema_one."table two" |
||||
type | schema_one | schema_one."table two"[] |
||||
table | schema_one | schema_one.table_three |
||||
type | schema_one | schema_one.table_three |
||||
type | schema_one | schema_one.table_three[] |
||||
(23 rows) |
||||
|
||||
DROP OWNED BY regress_evt_user; |
||||
NOTICE: schema "audit_tbls" does not exist, skipping |
||||
SELECT * FROM dropped_objects WHERE type = 'schema'; |
||||
type | schema | object |
||||
--------+--------+------------ |
||||
schema | | schema_two |
||||
schema | | schema_one |
||||
schema | | audit_tbls |
||||
(3 rows) |
||||
|
||||
DROP ROLE regress_evt_user; |
||||
DROP EVENT TRIGGER regress_event_trigger_drop_objects; |
||||
DROP EVENT TRIGGER undroppable; |
||||
-- Event triggers on relations. |
||||
CREATE OR REPLACE FUNCTION event_trigger_report_dropped() |
||||
RETURNS event_trigger |
||||
LANGUAGE plpgsql |
||||
AS $$ |
||||
DECLARE r record; |
||||
BEGIN |
||||
FOR r IN SELECT * from pg_event_trigger_dropped_objects() |
||||
LOOP |
||||
IF NOT r.normal AND NOT r.original THEN |
||||
CONTINUE; |
||||
END IF; |
||||
RAISE NOTICE 'NORMAL: orig=% normal=% istemp=% type=% identity=% name=% args=%', |
||||
r.original, r.normal, r.is_temporary, r.object_type, |
||||
r.object_identity, r.address_names, r.address_args; |
||||
END LOOP; |
||||
END; $$; |
||||
CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop |
||||
EXECUTE PROCEDURE event_trigger_report_dropped(); |
||||
CREATE OR REPLACE FUNCTION event_trigger_report_end() |
||||
RETURNS event_trigger |
||||
LANGUAGE plpgsql |
||||
AS $$ |
||||
DECLARE r RECORD; |
||||
BEGIN |
||||
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands() |
||||
LOOP |
||||
RAISE NOTICE 'END: command_tag=% type=% identity=%', |
||||
r.command_tag, r.object_type, r.object_identity; |
||||
END LOOP; |
||||
END; $$; |
||||
CREATE EVENT TRIGGER regress_event_trigger_report_end ON ddl_command_end |
||||
EXECUTE PROCEDURE event_trigger_report_end(); |
||||
CREATE SCHEMA evttrig |
||||
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two', col_c SERIAL) |
||||
CREATE INDEX one_idx ON one (col_b) |
||||
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42) |
||||
CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY); |
||||
NOTICE: END: command_tag=CREATE SCHEMA type=schema identity=evttrig |
||||
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_a_seq |
||||
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_c_seq |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one |
||||
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey |
||||
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq |
||||
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.two |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two |
||||
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.id_col_d_seq |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.id |
||||
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq |
||||
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_idx |
||||
-- Partitioned tables with a partitioned index |
||||
CREATE TABLE evttrig.parted ( |
||||
id int PRIMARY KEY) |
||||
PARTITION BY RANGE (id); |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.parted |
||||
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.parted_pkey |
||||
CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id) |
||||
FOR VALUES FROM (1) TO (10); |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_1_10 |
||||
CREATE TABLE evttrig.part_10_20 PARTITION OF evttrig.parted (id) |
||||
FOR VALUES FROM (10) TO (20) PARTITION BY RANGE (id); |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_20 |
||||
CREATE TABLE evttrig.part_10_15 PARTITION OF evttrig.part_10_20 (id) |
||||
FOR VALUES FROM (10) TO (15); |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_15 |
||||
CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id) |
||||
FOR VALUES FROM (15) TO (20); |
||||
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_15_20 |
||||
ALTER TABLE evttrig.two DROP COLUMN col_c; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={} |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two |
||||
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={} |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one |
||||
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={} |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one |
||||
ALTER TABLE evttrig.one DROP COLUMN col_c; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.one.col_c name={evttrig,one,col_c} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_c name={evttrig,one,col_c} args={} |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one |
||||
ALTER TABLE evttrig.id ALTER COLUMN col_d SET DATA TYPE bigint; |
||||
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id |
||||
ALTER TABLE evttrig.id ALTER COLUMN col_d DROP IDENTITY, |
||||
ALTER COLUMN col_d SET DATA TYPE int; |
||||
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id |
||||
DROP INDEX evttrig.one_idx; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={} |
||||
DROP SCHEMA evttrig CASCADE; |
||||
NOTICE: drop cascades to 4 other objects |
||||
DETAIL: drop cascades to table evttrig.one |
||||
drop cascades to table evttrig.two |
||||
drop cascades to table evttrig.id |
||||
drop cascades to table evttrig.parted |
||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig name={evttrig} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one name={evttrig,one} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two name={evttrig,two} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.id name={evttrig,id} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.parted name={evttrig,parted} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_1_10 name={evttrig,part_1_10} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_20 name={evttrig,part_10_20} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_15 name={evttrig,part_10_15} args={} |
||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_15_20 name={evttrig,part_15_20} args={} |
||||
DROP TABLE a_temp_tbl; |
||||
NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={} |
||||
-- CREATE OPERATOR CLASS without FAMILY clause should report |
||||
-- both CREATE OPERATOR FAMILY and CREATE OPERATOR CLASS |
||||
CREATE OPERATOR CLASS evttrigopclass FOR TYPE int USING btree AS STORAGE int; |
||||
NOTICE: END: command_tag=CREATE OPERATOR FAMILY type=operator family identity=public.evttrigopclass USING btree |
||||
NOTICE: END: command_tag=CREATE OPERATOR CLASS type=operator class identity=public.evttrigopclass USING btree |
||||
DROP EVENT TRIGGER regress_event_trigger_report_dropped; |
||||
DROP EVENT TRIGGER regress_event_trigger_report_end; |
||||
-- only allowed from within an event trigger function, should fail |
||||
select pg_event_trigger_table_rewrite_oid(); |
||||
ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function |
||||
-- test Table Rewrite Event Trigger |
||||
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
BEGIN |
||||
RAISE EXCEPTION 'rewrites not allowed'; |
||||
END; |
||||
$$; |
||||
create event trigger no_rewrite_allowed on table_rewrite |
||||
execute procedure test_evtrig_no_rewrite(); |
||||
create table rewriteme (id serial primary key, foo float, bar timestamptz); |
||||
insert into rewriteme |
||||
select x * 1.001 from generate_series(1, 500) as t(x); |
||||
alter table rewriteme alter column foo type numeric; |
||||
ERROR: rewrites not allowed |
||||
CONTEXT: PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE |
||||
alter table rewriteme add column baz int default 0; |
||||
-- test with more than one reason to rewrite a single table |
||||
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
BEGIN |
||||
RAISE NOTICE 'Table ''%'' is being rewritten (reason = %)', |
||||
pg_event_trigger_table_rewrite_oid()::regclass, |
||||
pg_event_trigger_table_rewrite_reason(); |
||||
END; |
||||
$$; |
||||
alter table rewriteme |
||||
add column onemore int default 0, |
||||
add column another int default -1, |
||||
alter column foo type numeric(10,4); |
||||
NOTICE: Table 'rewriteme' is being rewritten (reason = 4) |
||||
-- matview rewrite when changing access method |
||||
CREATE MATERIALIZED VIEW heapmv USING heap AS SELECT 1 AS a; |
||||
ALTER MATERIALIZED VIEW heapmv SET ACCESS METHOD heap2; |
||||
NOTICE: Table 'heapmv' is being rewritten (reason = 8) |
||||
DROP MATERIALIZED VIEW heapmv; |
||||
-- shouldn't trigger a table_rewrite event |
||||
alter table rewriteme alter column foo type numeric(12,4); |
||||
begin; |
||||
set timezone to 'UTC'; |
||||
alter table rewriteme alter column bar type timestamp; |
||||
set timezone to '0'; |
||||
alter table rewriteme alter column bar type timestamptz; |
||||
set timezone to 'Europe/London'; |
||||
alter table rewriteme alter column bar type timestamp; -- does rewrite |
||||
NOTICE: Table 'rewriteme' is being rewritten (reason = 4) |
||||
rollback; |
||||
-- typed tables are rewritten when their type changes. Don't emit table |
||||
-- name, because firing order is not stable. |
||||
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
BEGIN |
||||
RAISE NOTICE 'Table is being rewritten (reason = %)', |
||||
pg_event_trigger_table_rewrite_reason(); |
||||
END; |
||||
$$; |
||||
create type rewritetype as (a int); |
||||
create table rewritemetoo1 of rewritetype; |
||||
create table rewritemetoo2 of rewritetype; |
||||
alter type rewritetype alter attribute a type text cascade; |
||||
NOTICE: Table is being rewritten (reason = 4) |
||||
NOTICE: Table is being rewritten (reason = 4) |
||||
-- but this doesn't work |
||||
create table rewritemetoo3 (a rewritetype); |
||||
alter type rewritetype alter attribute a type varchar cascade; |
||||
ERROR: cannot alter type "rewritetype" because column "rewritemetoo3.a" uses it |
||||
drop table rewriteme; |
||||
drop event trigger no_rewrite_allowed; |
||||
drop function test_evtrig_no_rewrite(); |
||||
-- Tests for REINDEX |
||||
CREATE OR REPLACE FUNCTION reindex_start_command() |
||||
RETURNS event_trigger AS $$ |
||||
BEGIN |
||||
RAISE NOTICE 'REINDEX START: % %', tg_event, tg_tag; |
||||
END; |
||||
$$ LANGUAGE plpgsql; |
||||
CREATE EVENT TRIGGER regress_reindex_start ON ddl_command_start |
||||
WHEN TAG IN ('REINDEX') |
||||
EXECUTE PROCEDURE reindex_start_command(); |
||||
CREATE FUNCTION reindex_end_command() |
||||
RETURNS event_trigger AS $$ |
||||
DECLARE |
||||
obj record; |
||||
BEGIN |
||||
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() |
||||
LOOP |
||||
RAISE NOTICE 'REINDEX END: command_tag=% type=% identity=%', |
||||
obj.command_tag, obj.object_type, obj.object_identity; |
||||
END LOOP; |
||||
END; |
||||
$$ LANGUAGE plpgsql; |
||||
CREATE EVENT TRIGGER regress_reindex_end ON ddl_command_end |
||||
WHEN TAG IN ('REINDEX') |
||||
EXECUTE PROCEDURE reindex_end_command(); |
||||
-- Extra event to force the use of a snapshot. |
||||
CREATE FUNCTION reindex_end_command_snap() RETURNS EVENT_TRIGGER |
||||
AS $$ BEGIN PERFORM 1; END $$ LANGUAGE plpgsql; |
||||
CREATE EVENT TRIGGER regress_reindex_end_snap ON ddl_command_end |
||||
EXECUTE FUNCTION reindex_end_command_snap(); |
||||
-- With simple relation |
||||
CREATE TABLE concur_reindex_tab (c1 int); |
||||
CREATE INDEX concur_reindex_ind ON concur_reindex_tab (c1); |
||||
-- Both start and end triggers enabled. |
||||
REINDEX INDEX concur_reindex_ind; |
||||
NOTICE: REINDEX START: ddl_command_start REINDEX |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
REINDEX TABLE concur_reindex_tab; |
||||
NOTICE: REINDEX START: ddl_command_start REINDEX |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
REINDEX INDEX CONCURRENTLY concur_reindex_ind; |
||||
NOTICE: REINDEX START: ddl_command_start REINDEX |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab; |
||||
NOTICE: REINDEX START: ddl_command_start REINDEX |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
-- with start trigger disabled. |
||||
ALTER EVENT TRIGGER regress_reindex_start DISABLE; |
||||
REINDEX INDEX concur_reindex_ind; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
REINDEX INDEX CONCURRENTLY concur_reindex_ind; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_ind |
||||
-- without an index |
||||
DROP INDEX concur_reindex_ind; |
||||
REINDEX TABLE concur_reindex_tab; |
||||
NOTICE: table "concur_reindex_tab" has no indexes to reindex |
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab; |
||||
NOTICE: table "concur_reindex_tab" has no indexes that can be reindexed concurrently |
||||
-- With a Schema |
||||
CREATE SCHEMA concur_reindex_schema; |
||||
-- No indexes |
||||
REINDEX SCHEMA concur_reindex_schema; |
||||
REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; |
||||
CREATE TABLE concur_reindex_schema.tab (a int); |
||||
CREATE INDEX ind ON concur_reindex_schema.tab (a); |
||||
-- One index reported |
||||
REINDEX SCHEMA concur_reindex_schema; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=concur_reindex_schema.ind |
||||
REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=concur_reindex_schema.ind |
||||
-- One table on schema but no indexes |
||||
DROP INDEX concur_reindex_schema.ind; |
||||
REINDEX SCHEMA concur_reindex_schema; |
||||
REINDEX SCHEMA CONCURRENTLY concur_reindex_schema; |
||||
DROP SCHEMA concur_reindex_schema CASCADE; |
||||
NOTICE: drop cascades to table concur_reindex_schema.tab |
||||
-- With a partitioned table, and nothing else. |
||||
CREATE TABLE concur_reindex_part (id int) PARTITION BY RANGE (id); |
||||
REINDEX TABLE concur_reindex_part; |
||||
REINDEX TABLE CONCURRENTLY concur_reindex_part; |
||||
-- Partition that would be reindexed, still nothing. |
||||
CREATE TABLE concur_reindex_child PARTITION OF concur_reindex_part |
||||
FOR VALUES FROM (0) TO (10); |
||||
REINDEX TABLE concur_reindex_part; |
||||
REINDEX TABLE CONCURRENTLY concur_reindex_part; |
||||
-- Now add some indexes. |
||||
CREATE INDEX concur_reindex_partidx ON concur_reindex_part (id); |
||||
REINDEX INDEX concur_reindex_partidx; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx |
||||
REINDEX INDEX CONCURRENTLY concur_reindex_partidx; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx |
||||
REINDEX TABLE concur_reindex_part; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx |
||||
REINDEX TABLE CONCURRENTLY concur_reindex_part; |
||||
NOTICE: REINDEX END: command_tag=REINDEX type=index identity=public.concur_reindex_child_id_idx |
||||
DROP TABLE concur_reindex_part; |
||||
-- Clean up |
||||
DROP EVENT TRIGGER regress_reindex_start; |
||||
DROP EVENT TRIGGER regress_reindex_end; |
||||
DROP EVENT TRIGGER regress_reindex_end_snap; |
||||
DROP FUNCTION reindex_end_command(); |
||||
DROP FUNCTION reindex_end_command_snap(); |
||||
DROP FUNCTION reindex_start_command(); |
||||
DROP TABLE concur_reindex_tab; |
||||
-- test Row Security Event Trigger |
||||
RESET SESSION AUTHORIZATION; |
||||
CREATE TABLE event_trigger_test (a integer, b text); |
||||
CREATE OR REPLACE FUNCTION start_command() |
||||
RETURNS event_trigger AS $$ |
||||
BEGIN |
||||
RAISE NOTICE '% - ddl_command_start', tg_tag; |
||||
END; |
||||
$$ LANGUAGE plpgsql; |
||||
CREATE OR REPLACE FUNCTION end_command() |
||||
RETURNS event_trigger AS $$ |
||||
BEGIN |
||||
RAISE NOTICE '% - ddl_command_end', tg_tag; |
||||
END; |
||||
$$ LANGUAGE plpgsql; |
||||
CREATE OR REPLACE FUNCTION drop_sql_command() |
||||
RETURNS event_trigger AS $$ |
||||
BEGIN |
||||
RAISE NOTICE '% - sql_drop', tg_tag; |
||||
END; |
||||
$$ LANGUAGE plpgsql; |
||||
CREATE EVENT TRIGGER start_rls_command ON ddl_command_start |
||||
WHEN TAG IN ('CREATE POLICY', 'ALTER POLICY', 'DROP POLICY') EXECUTE PROCEDURE start_command(); |
||||
CREATE EVENT TRIGGER end_rls_command ON ddl_command_end |
||||
WHEN TAG IN ('CREATE POLICY', 'ALTER POLICY', 'DROP POLICY') EXECUTE PROCEDURE end_command(); |
||||
CREATE EVENT TRIGGER sql_drop_command ON sql_drop |
||||
WHEN TAG IN ('DROP POLICY') EXECUTE PROCEDURE drop_sql_command(); |
||||
CREATE POLICY p1 ON event_trigger_test USING (FALSE); |
||||
NOTICE: CREATE POLICY - ddl_command_start |
||||
NOTICE: CREATE POLICY - ddl_command_end |
||||
ALTER POLICY p1 ON event_trigger_test USING (TRUE); |
||||
NOTICE: ALTER POLICY - ddl_command_start |
||||
NOTICE: ALTER POLICY - ddl_command_end |
||||
ALTER POLICY p1 ON event_trigger_test RENAME TO p2; |
||||
NOTICE: ALTER POLICY - ddl_command_start |
||||
NOTICE: ALTER POLICY - ddl_command_end |
||||
DROP POLICY p2 ON event_trigger_test; |
||||
NOTICE: DROP POLICY - ddl_command_start |
||||
NOTICE: DROP POLICY - sql_drop |
||||
NOTICE: DROP POLICY - ddl_command_end |
||||
-- Check the object addresses of all the event triggers. |
||||
SELECT |
||||
e.evtname, |
||||
pg_describe_object('pg_event_trigger'::regclass, e.oid, 0) as descr, |
||||
b.type, b.object_names, b.object_args, |
||||
pg_identify_object(a.classid, a.objid, a.objsubid) as ident |
||||
FROM pg_event_trigger as e, |
||||
LATERAL pg_identify_object_as_address('pg_event_trigger'::regclass, e.oid, 0) as b, |
||||
LATERAL pg_get_object_address(b.type, b.object_names, b.object_args) as a |
||||
ORDER BY e.evtname; |
||||
evtname | descr | type | object_names | object_args | ident |
||||
-------------------------------+---------------------------------------------+---------------+---------------------------------+-------------+-------------------------------------------------------------------------------- |
||||
end_rls_command | event trigger end_rls_command | event trigger | {end_rls_command} | {} | ("event trigger",,end_rls_command,end_rls_command) |
||||
pg_tde_trigger_create_index | event trigger pg_tde_trigger_create_index | event trigger | {pg_tde_trigger_create_index} | {} | ("event trigger",,pg_tde_trigger_create_index,pg_tde_trigger_create_index) |
||||
pg_tde_trigger_create_index_2 | event trigger pg_tde_trigger_create_index_2 | event trigger | {pg_tde_trigger_create_index_2} | {} | ("event trigger",,pg_tde_trigger_create_index_2,pg_tde_trigger_create_index_2) |
||||
sql_drop_command | event trigger sql_drop_command | event trigger | {sql_drop_command} | {} | ("event trigger",,sql_drop_command,sql_drop_command) |
||||
start_rls_command | event trigger start_rls_command | event trigger | {start_rls_command} | {} | ("event trigger",,start_rls_command,start_rls_command) |
||||
(5 rows) |
||||
|
||||
DROP EVENT TRIGGER start_rls_command; |
||||
DROP EVENT TRIGGER end_rls_command; |
||||
DROP EVENT TRIGGER sql_drop_command; |
||||
-- Check the GUC for disabling event triggers |
||||
CREATE FUNCTION test_event_trigger_guc() RETURNS event_trigger |
||||
LANGUAGE plpgsql AS $$ |
||||
DECLARE |
||||
obj record; |
||||
BEGIN |
||||
FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() |
||||
LOOP |
||||
RAISE NOTICE '% dropped %', tg_tag, obj.object_type; |
||||
END LOOP; |
||||
END; |
||||
$$; |
||||
CREATE EVENT TRIGGER test_event_trigger_guc |
||||
ON sql_drop |
||||
WHEN TAG IN ('DROP POLICY') EXECUTE FUNCTION test_event_trigger_guc(); |
||||
SET event_triggers = 'on'; |
||||
CREATE POLICY pguc ON event_trigger_test USING (FALSE); |
||||
DROP POLICY pguc ON event_trigger_test; |
||||
NOTICE: DROP POLICY dropped policy |
||||
CREATE POLICY pguc ON event_trigger_test USING (FALSE); |
||||
SET event_triggers = 'off'; |
||||
DROP POLICY pguc ON event_trigger_test; |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue