mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events. Whenever a ddl_command_end event trigger is installed, DDL actions executed are saved to a list which can be inspected during execution of a function attached to ddl_command_end. The set-returning function pg_event_trigger_ddl_commands can be used to list actions so captured; it returns data about the type of command executed, as well as the affected object. This is sufficient for many uses of this feature. For the cases where it is not, we also provide a "command" column of a new pseudo-type pg_ddl_command, which is a pointer to a C structure that can be accessed by C code. The struct contains all the info necessary to completely inspect and even reconstruct the executed command. There is no actual deparse code here; that's expected to come later. What we have is enough infrastructure that the deparsing can be done in an external extension. The intention is that we will add some deparsing code in a later release, as an in-core extension. A new test module is included. It's probably insufficient as is, but it should be sufficient as a starting point for a more complete and future-proof approach. Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick, Abhijit Menon-Sen. Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier, Craig Ringer, David Steele. Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost, Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule. Based on original work by Dimitri Fontaine, though I didn't use his code. Discussion: https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
This commit is contained in:
@ -6,11 +6,12 @@ include $(top_builddir)/src/Makefile.global
|
||||
|
||||
SUBDIRS = \
|
||||
commit_ts \
|
||||
worker_spi \
|
||||
dummy_seclabel \
|
||||
test_ddl_deparse \
|
||||
test_parser \
|
||||
test_rls_hooks \
|
||||
test_shm_mq \
|
||||
test_parser
|
||||
worker_spi
|
||||
|
||||
all: submake-errcodes
|
||||
|
||||
|
19
src/test/modules/test_ddl_deparse/Makefile
Normal file
19
src/test/modules/test_ddl_deparse/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
MODULES = test_ddl_deparse
|
||||
PGFILEDESC = "test_ddl_deparse - regression testing for DDL deparsing"
|
||||
|
||||
EXTENSION = test_ddl_deparse
|
||||
DATA = test_ddl_deparse--1.0.sql
|
||||
|
||||
REGRESS = --schedule=$(srcdir)/regress_schedule
|
||||
EXTRA_INSTALL = contrib/pg_stat_statements
|
||||
|
||||
ifdef USE_PGXS
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
else
|
||||
subdir = src/test/modules/test_ddl_deparse
|
||||
top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
include $(top_srcdir)/contrib/contrib-global.mk
|
||||
endif
|
@ -0,0 +1,15 @@
|
||||
--
|
||||
-- ALTER_FUNCTION
|
||||
--
|
||||
ALTER FUNCTION plpgsql_function_trigger_1 ()
|
||||
SET SCHEMA foo;
|
||||
NOTICE: DDL test: type simple, tag ALTER FUNCTION
|
||||
ALTER FUNCTION foo.plpgsql_function_trigger_1()
|
||||
COST 10;
|
||||
NOTICE: DDL test: type simple, tag ALTER FUNCTION
|
||||
CREATE ROLE tmprole;
|
||||
ALTER FUNCTION plpgsql_function_trigger_2()
|
||||
OWNER TO tmprole;
|
||||
ERROR: function plpgsql_function_trigger_2() does not exist
|
||||
DROP OWNED BY tmprole;
|
||||
DROP ROLE tmprole;
|
@ -0,0 +1,15 @@
|
||||
--
|
||||
-- ALTER_SEQUENCE
|
||||
--
|
||||
ALTER SEQUENCE fkey_table_seq
|
||||
MINVALUE 10
|
||||
START 20
|
||||
CACHE 1
|
||||
NO CYCLE;
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
ALTER SEQUENCE fkey_table_seq
|
||||
RENAME TO fkey_table_seq_renamed;
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
ALTER SEQUENCE fkey_table_seq_renamed
|
||||
SET SCHEMA foo;
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
18
src/test/modules/test_ddl_deparse/expected/alter_table.out
Normal file
18
src/test/modules/test_ddl_deparse/expected/alter_table.out
Normal file
@ -0,0 +1,18 @@
|
||||
CREATE TABLE parent (
|
||||
a int
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
CREATE TABLE child () INHERITS (parent);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
CREATE TABLE grandchild () INHERITS (child);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
ALTER TABLE parent ADD COLUMN b serial;
|
||||
NOTICE: DDL test: type simple, tag CREATE SEQUENCE
|
||||
NOTICE: DDL test: type alter table, tag ALTER TABLE
|
||||
NOTICE: subcommand: ADD COLUMN (and recurse)
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
ALTER TABLE parent RENAME COLUMN b TO c;
|
||||
NOTICE: DDL test: type simple, tag ALTER TABLE
|
||||
ALTER TABLE parent ADD CONSTRAINT a_pos CHECK (a > 0);
|
||||
NOTICE: DDL test: type alter table, tag ALTER TABLE
|
||||
NOTICE: subcommand: ADD CONSTRAINT (and recurse)
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
--- ALTER_TYPE_ENUM
|
||||
---
|
||||
ALTER TYPE enum_test ADD VALUE 'zzz' AFTER 'baz';
|
||||
NOTICE: DDL test: type simple, tag ALTER TYPE
|
||||
ALTER TYPE enum_test ADD VALUE 'aaa' BEFORE 'foo';
|
||||
NOTICE: DDL test: type simple, tag ALTER TYPE
|
25
src/test/modules/test_ddl_deparse/expected/comment_on.out
Normal file
25
src/test/modules/test_ddl_deparse/expected/comment_on.out
Normal file
@ -0,0 +1,25 @@
|
||||
--
|
||||
-- COMMENT_ON
|
||||
--
|
||||
COMMENT ON SCHEMA foo IS 'This is schema foo';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON TYPE enum_test IS 'ENUM test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON TYPE int2range IS 'RANGE test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON DOMAIN japanese_postal_code IS 'DOMAIN test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON SEQUENCE fkey_table_seq IS 'SEQUENCE test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON TABLE datatype_table IS 'This table should contain all native datatypes';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON VIEW datatype_view IS 'This is a view';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON FUNCTION c_function_test() IS 'FUNCTION test';
|
||||
ERROR: function c_function_test() does not exist
|
||||
COMMENT ON TRIGGER trigger_1 ON datatype_table IS 'TRIGGER test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
COMMENT ON RULE rule_1 IS 'RULE test';
|
||||
NOTICE: DDL test: type simple, tag COMMENT
|
||||
-- should not fire
|
||||
COMMENT ON DATABASE contrib_regression IS 'contrib regression';
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
--- CREATE_CONVERSION
|
||||
---
|
||||
-- Simple test should suffice for this
|
||||
CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
|
||||
NOTICE: DDL test: type simple, tag CREATE CONVERSION
|
11
src/test/modules/test_ddl_deparse/expected/create_domain.out
Normal file
11
src/test/modules/test_ddl_deparse/expected/create_domain.out
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
--- CREATE_DOMAIN
|
||||
---
|
||||
CREATE DOMAIN domainvarchar VARCHAR(5);
|
||||
NOTICE: DDL test: type simple, tag CREATE DOMAIN
|
||||
CREATE DOMAIN japanese_postal_code AS TEXT
|
||||
CHECK(
|
||||
VALUE ~ '^\d{3}$'
|
||||
OR VALUE ~ '^\d{3}-\d{4}$'
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE DOMAIN
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
--- CREATE_EXTENSION
|
||||
---
|
||||
CREATE EXTENSION pg_stat_statements;
|
||||
NOTICE: DDL test: type simple, tag CREATE EXTENSION
|
30
src/test/modules/test_ddl_deparse/expected/create_rule.out
Normal file
30
src/test/modules/test_ddl_deparse/expected/create_rule.out
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
--- CREATE_RULE
|
||||
---
|
||||
CREATE RULE rule_1 AS
|
||||
ON INSERT
|
||||
TO datatype_table
|
||||
DO NOTHING;
|
||||
NOTICE: DDL test: type simple, tag CREATE RULE
|
||||
CREATE RULE rule_2 AS
|
||||
ON UPDATE
|
||||
TO datatype_table
|
||||
DO INSERT INTO unlogged_table (id) VALUES(NEW.id);
|
||||
NOTICE: DDL test: type simple, tag CREATE RULE
|
||||
CREATE RULE rule_3 AS
|
||||
ON DELETE
|
||||
TO datatype_table
|
||||
DO ALSO NOTHING;
|
||||
NOTICE: DDL test: type simple, tag CREATE RULE
|
||||
CREATE RULE "_RETURN" AS
|
||||
ON SELECT
|
||||
TO like_datatype_table
|
||||
DO INSTEAD
|
||||
SELECT * FROM datatype_view;
|
||||
NOTICE: DDL test: type simple, tag CREATE RULE
|
||||
CREATE RULE rule_3 AS
|
||||
ON DELETE
|
||||
TO like_datatype_table
|
||||
WHERE id < 100
|
||||
DO ALSO NOTHING;
|
||||
NOTICE: DDL test: type simple, tag CREATE RULE
|
19
src/test/modules/test_ddl_deparse/expected/create_schema.out
Normal file
19
src/test/modules/test_ddl_deparse/expected/create_schema.out
Normal file
@ -0,0 +1,19 @@
|
||||
--
|
||||
-- CREATE_SCHEMA
|
||||
--
|
||||
CREATE SCHEMA foo;
|
||||
NOTICE: DDL test: type simple, tag CREATE SCHEMA
|
||||
CREATE SCHEMA IF NOT EXISTS bar;
|
||||
NOTICE: DDL test: type simple, tag CREATE SCHEMA
|
||||
CREATE SCHEMA baz;
|
||||
NOTICE: DDL test: type simple, tag CREATE SCHEMA
|
||||
-- Will not be created, and will not be handled by the
|
||||
-- event trigger
|
||||
CREATE SCHEMA IF NOT EXISTS baz;
|
||||
NOTICE: schema "baz" already exists, skipping
|
||||
CREATE SCHEMA element_test
|
||||
CREATE TABLE foo (id int)
|
||||
CREATE VIEW bar AS SELECT * FROM foo;
|
||||
NOTICE: DDL test: type simple, tag CREATE SCHEMA
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE VIEW
|
@ -0,0 +1,11 @@
|
||||
--
|
||||
-- CREATE_SEQUENCE
|
||||
--
|
||||
CREATE SEQUENCE fkey_table_seq
|
||||
INCREMENT BY 1
|
||||
MINVALUE 0
|
||||
MAXVALUE 1000000
|
||||
START 10
|
||||
CACHE 10
|
||||
CYCLE;
|
||||
NOTICE: DDL test: type simple, tag CREATE SEQUENCE
|
160
src/test/modules/test_ddl_deparse/expected/create_table.out
Normal file
160
src/test/modules/test_ddl_deparse/expected/create_table.out
Normal file
@ -0,0 +1,160 @@
|
||||
--
|
||||
-- CREATE_TABLE
|
||||
--
|
||||
-- Datatypes
|
||||
CREATE TABLE datatype_table (
|
||||
id SERIAL,
|
||||
id_big BIGSERIAL,
|
||||
is_small SMALLSERIAL,
|
||||
v_bytea BYTEA,
|
||||
v_smallint SMALLINT,
|
||||
v_int INT,
|
||||
v_bigint BIGINT,
|
||||
v_char CHAR(1),
|
||||
v_varchar VARCHAR(10),
|
||||
v_text TEXT,
|
||||
v_bool BOOLEAN,
|
||||
v_inet INET,
|
||||
v_cidr CIDR,
|
||||
v_macaddr MACADDR,
|
||||
v_numeric NUMERIC(1,0),
|
||||
v_real REAL,
|
||||
v_float FLOAT(1),
|
||||
v_float8 FLOAT8,
|
||||
v_money MONEY,
|
||||
v_tsquery TSQUERY,
|
||||
v_tsvector TSVECTOR,
|
||||
v_date DATE,
|
||||
v_time TIME,
|
||||
v_time_tz TIME WITH TIME ZONE,
|
||||
v_timestamp TIMESTAMP,
|
||||
v_timestamp_tz TIMESTAMP WITH TIME ZONE,
|
||||
v_interval INTERVAL,
|
||||
v_bit BIT,
|
||||
v_bit4 BIT(4),
|
||||
v_varbit VARBIT,
|
||||
v_varbit4 VARBIT(4),
|
||||
v_box BOX,
|
||||
v_circle CIRCLE,
|
||||
v_lseg LSEG,
|
||||
v_path PATH,
|
||||
v_point POINT,
|
||||
v_polygon POLYGON,
|
||||
v_json JSON,
|
||||
v_xml XML,
|
||||
v_uuid UUID,
|
||||
v_txid_snapshot txid_snapshot,
|
||||
v_enum ENUM_TEST,
|
||||
v_postal_code japanese_postal_code,
|
||||
v_int2range int2range,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (id_big)
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE SEQUENCE
|
||||
NOTICE: DDL test: type simple, tag CREATE SEQUENCE
|
||||
NOTICE: DDL test: type simple, tag CREATE SEQUENCE
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
NOTICE: DDL test: type simple, tag ALTER SEQUENCE
|
||||
-- Constraint definitions
|
||||
CREATE TABLE IF NOT EXISTS fkey_table (
|
||||
id INT NOT NULL DEFAULT nextval('fkey_table_seq'::REGCLASS),
|
||||
datatype_id INT NOT NULL REFERENCES datatype_table(id),
|
||||
big_id BIGINT NOT NULL,
|
||||
sometext TEXT COLLATE "POSIX",
|
||||
check_col_1 INT NOT NULL CHECK(check_col_1 < 10),
|
||||
check_col_2 INT NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fkey_big_id
|
||||
FOREIGN KEY (big_id)
|
||||
REFERENCES datatype_table(id_big),
|
||||
EXCLUDE USING btree (check_col_2 WITH =)
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
NOTICE: DDL test: type alter table, tag ALTER TABLE
|
||||
NOTICE: subcommand: ADD CONSTRAINT (and recurse)
|
||||
NOTICE: subcommand: ADD CONSTRAINT (and recurse)
|
||||
-- Typed table
|
||||
CREATE TABLE employees OF employee_type (
|
||||
PRIMARY KEY (name),
|
||||
salary WITH OPTIONS DEFAULT 1000
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
-- Inheritance
|
||||
CREATE TABLE person (
|
||||
id INT NOT NULL PRIMARY KEY,
|
||||
name text,
|
||||
age int4,
|
||||
location point
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
CREATE TABLE emp (
|
||||
salary int4,
|
||||
manager name
|
||||
) INHERITS (person) WITH OIDS;
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
CREATE TABLE student (
|
||||
gpa float8
|
||||
) INHERITS (person);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
CREATE TABLE stud_emp (
|
||||
percent int4
|
||||
) INHERITS (emp, student);
|
||||
NOTICE: merging multiple inherited definitions of column "id"
|
||||
NOTICE: merging multiple inherited definitions of column "name"
|
||||
NOTICE: merging multiple inherited definitions of column "age"
|
||||
NOTICE: merging multiple inherited definitions of column "location"
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
-- Storage parameters
|
||||
CREATE TABLE storage (
|
||||
id INT
|
||||
) WITH (
|
||||
fillfactor = 10,
|
||||
autovacuum_enabled = FALSE
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
-- LIKE
|
||||
CREATE TABLE like_datatype_table (
|
||||
LIKE datatype_table
|
||||
EXCLUDING ALL
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
CREATE TABLE like_fkey_table (
|
||||
LIKE fkey_table
|
||||
INCLUDING DEFAULTS
|
||||
INCLUDING INDEXES
|
||||
INCLUDING STORAGE
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
-- Volatile table types
|
||||
CREATE UNLOGGED TABLE unlogged_table (
|
||||
id INT PRIMARY KEY
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
CREATE TEMP TABLE temp_table (
|
||||
id INT PRIMARY KEY
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
CREATE TEMP TABLE temp_table_commit_delete (
|
||||
id INT PRIMARY KEY
|
||||
)
|
||||
ON COMMIT DELETE ROWS;
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
||||
CREATE TEMP TABLE temp_table_commit_drop (
|
||||
id INT PRIMARY KEY
|
||||
)
|
||||
ON COMMIT DROP;
|
||||
NOTICE: DDL test: type simple, tag CREATE TABLE
|
||||
NOTICE: DDL test: type simple, tag CREATE INDEX
|
@ -0,0 +1,18 @@
|
||||
---
|
||||
--- CREATE_TRIGGER
|
||||
---
|
||||
CREATE FUNCTION plpgsql_function_trigger_1()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
CREATE TRIGGER trigger_1
|
||||
BEFORE INSERT OR UPDATE
|
||||
ON datatype_table
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE plpgsql_function_trigger_1();
|
||||
NOTICE: DDL test: type simple, tag CREATE TRIGGER
|
24
src/test/modules/test_ddl_deparse/expected/create_type.out
Normal file
24
src/test/modules/test_ddl_deparse/expected/create_type.out
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
--- CREATE_TYPE
|
||||
---
|
||||
CREATE FUNCTION text_w_default_in(cstring)
|
||||
RETURNS text_w_default
|
||||
AS 'textin'
|
||||
LANGUAGE internal STABLE STRICT;
|
||||
NOTICE: type "text_w_default" is not yet defined
|
||||
DETAIL: Creating a shell type definition.
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
CREATE FUNCTION text_w_default_out(text_w_default)
|
||||
RETURNS cstring
|
||||
AS 'textout'
|
||||
LANGUAGE internal STABLE STRICT ;
|
||||
NOTICE: argument type text_w_default is only a shell
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
CREATE TYPE employee_type AS (name TEXT, salary NUMERIC);
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
CREATE TYPE enum_test AS ENUM ('foo', 'bar', 'baz');
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
CREATE TYPE int2range AS RANGE (
|
||||
SUBTYPE = int2
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
19
src/test/modules/test_ddl_deparse/expected/create_view.out
Normal file
19
src/test/modules/test_ddl_deparse/expected/create_view.out
Normal file
@ -0,0 +1,19 @@
|
||||
--
|
||||
-- CREATE_VIEW
|
||||
--
|
||||
CREATE VIEW static_view AS
|
||||
SELECT 'foo'::TEXT AS col;
|
||||
NOTICE: DDL test: type simple, tag CREATE VIEW
|
||||
CREATE OR REPLACE VIEW static_view AS
|
||||
SELECT 'bar'::TEXT AS col;
|
||||
NOTICE: DDL test: type simple, tag CREATE VIEW
|
||||
NOTICE: DDL test: type alter table, tag CREATE VIEW
|
||||
NOTICE: subcommand: REPLACE RELOPTIONS
|
||||
CREATE VIEW datatype_view AS
|
||||
SELECT * FROM datatype_table;
|
||||
NOTICE: DDL test: type simple, tag CREATE VIEW
|
||||
CREATE RECURSIVE VIEW nums_1_100 (n) AS
|
||||
VALUES (1)
|
||||
UNION ALL
|
||||
SELECT n+1 FROM nums_1_100 WHERE n < 100;
|
||||
NOTICE: DDL test: type simple, tag CREATE VIEW
|
6
src/test/modules/test_ddl_deparse/expected/defprivs.out
Normal file
6
src/test/modules/test_ddl_deparse/expected/defprivs.out
Normal file
@ -0,0 +1,6 @@
|
||||
--
|
||||
-- ALTER DEFAULT PRIVILEGES
|
||||
--
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
REVOKE ALL PRIVILEGES ON TABLES FROM public;
|
||||
NOTICE: DDL test: type alter default privileges, tag ALTER DEFAULT PRIVILEGES
|
8
src/test/modules/test_ddl_deparse/expected/matviews.out
Normal file
8
src/test/modules/test_ddl_deparse/expected/matviews.out
Normal file
@ -0,0 +1,8 @@
|
||||
--
|
||||
-- Materialized views
|
||||
--
|
||||
CREATE MATERIALIZED VIEW pg_class_mv AS
|
||||
SELECT * FROM pg_class LIMIT 1 WITH NO DATA;
|
||||
NOTICE: DDL test: type simple, tag CREATE MATERIALIZED VIEW
|
||||
REFRESH MATERIALIZED VIEW pg_class_mv;
|
||||
NOTICE: DDL test: type simple, tag REFRESH MATERIALIZED VIEW
|
67
src/test/modules/test_ddl_deparse/expected/opfamily.out
Normal file
67
src/test/modules/test_ddl_deparse/expected/opfamily.out
Normal file
@ -0,0 +1,67 @@
|
||||
-- copied from equivclass.sql
|
||||
create type int8alias1;
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
create function int8alias1in(cstring) returns int8alias1
|
||||
strict immutable language internal as 'int8in';
|
||||
NOTICE: return type int8alias1 is only a shell
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create function int8alias1out(int8alias1) returns cstring
|
||||
strict immutable language internal as 'int8out';
|
||||
NOTICE: argument type int8alias1 is only a shell
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create type int8alias1 (
|
||||
input = int8alias1in,
|
||||
output = int8alias1out,
|
||||
like = int8
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
create type int8alias2;
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
create function int8alias2in(cstring) returns int8alias2
|
||||
strict immutable language internal as 'int8in';
|
||||
NOTICE: return type int8alias2 is only a shell
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create function int8alias2out(int8alias2) returns cstring
|
||||
strict immutable language internal as 'int8out';
|
||||
NOTICE: argument type int8alias2 is only a shell
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create type int8alias2 (
|
||||
input = int8alias2in,
|
||||
output = int8alias2out,
|
||||
like = int8
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
create cast (int8 as int8alias1) without function;
|
||||
NOTICE: DDL test: type simple, tag CREATE CAST
|
||||
create cast (int8 as int8alias2) without function;
|
||||
NOTICE: DDL test: type simple, tag CREATE CAST
|
||||
create cast (int8alias1 as int8) without function;
|
||||
NOTICE: DDL test: type simple, tag CREATE CAST
|
||||
create cast (int8alias2 as int8) without function;
|
||||
NOTICE: DDL test: type simple, tag CREATE CAST
|
||||
create function int8alias1eq(int8alias1, int8alias1) returns bool
|
||||
strict immutable language internal as 'int8eq';
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create operator = (
|
||||
procedure = int8alias1eq,
|
||||
leftarg = int8alias1, rightarg = int8alias1,
|
||||
commutator = =,
|
||||
restrict = eqsel, join = eqjoinsel,
|
||||
merges
|
||||
);
|
||||
NOTICE: DDL test: type simple, tag CREATE OPERATOR
|
||||
alter operator family integer_ops using btree add
|
||||
operator 3 = (int8alias1, int8alias1);
|
||||
NOTICE: DDL test: type alter operator family, tag ALTER OPERATOR FAMILY
|
||||
-- copied from alter_table.sql
|
||||
create type ctype as (f1 int, f2 text);
|
||||
NOTICE: DDL test: type simple, tag CREATE TYPE
|
||||
create function same(ctype, ctype) returns boolean language sql
|
||||
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
|
||||
NOTICE: DDL test: type simple, tag CREATE FUNCTION
|
||||
create operator =(procedure = same, leftarg = ctype, rightarg = ctype);
|
||||
NOTICE: DDL test: type simple, tag CREATE OPERATOR
|
||||
create operator class ctype_hash_ops
|
||||
default for type ctype using hash as
|
||||
operator 1 =(ctype, ctype);
|
||||
NOTICE: DDL test: type create operator class, tag CREATE OPERATOR CLASS
|
@ -0,0 +1,40 @@
|
||||
CREATE EXTENSION test_ddl_deparse;
|
||||
CREATE OR REPLACE FUNCTION test_ddl_deparse()
|
||||
RETURNS event_trigger LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
r record;
|
||||
r2 record;
|
||||
cmdtype text;
|
||||
objtype text;
|
||||
tag text;
|
||||
BEGIN
|
||||
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||
LOOP
|
||||
-- verify that tags match
|
||||
tag = get_command_tag(r.command);
|
||||
IF tag <> r.command_tag THEN
|
||||
RAISE NOTICE 'tag % doesn''t match %', tag, r.command_tag;
|
||||
END IF;
|
||||
|
||||
-- log the operation
|
||||
cmdtype = get_command_type(r.command);
|
||||
IF cmdtype <> 'grant' THEN
|
||||
RAISE NOTICE 'DDL test: type %, tag %', cmdtype, tag;
|
||||
ELSE
|
||||
RAISE NOTICE 'DDL test: type %, object type %', cmdtype, r.object_type;
|
||||
END IF;
|
||||
|
||||
-- if alter table, log more
|
||||
IF cmdtype = 'alter table' THEN
|
||||
FOR r2 IN SELECT *
|
||||
FROM unnest(get_altertable_subcmdtypes(r.command))
|
||||
LOOP
|
||||
RAISE NOTICE ' subcommand: %', r2.unnest;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
CREATE EVENT TRIGGER test_ddl_deparse
|
||||
ON ddl_command_end EXECUTE PROCEDURE test_ddl_deparse();
|
21
src/test/modules/test_ddl_deparse/regress_schedule
Normal file
21
src/test/modules/test_ddl_deparse/regress_schedule
Normal file
@ -0,0 +1,21 @@
|
||||
# must be first
|
||||
test: test_ddl_deparse
|
||||
|
||||
test: create_extension
|
||||
test: create_schema
|
||||
test: create_type
|
||||
test: create_conversion
|
||||
test: create_domain
|
||||
test: create_sequence_1
|
||||
test: create_table
|
||||
test: alter_table
|
||||
test: create_view
|
||||
test: create_trigger
|
||||
test: create_rule
|
||||
test: comment_on
|
||||
test: alter_function
|
||||
test: alter_sequence
|
||||
test: alter_type_enum
|
||||
test: opfamily
|
||||
test: defprivs
|
||||
test: matviews
|
17
src/test/modules/test_ddl_deparse/sql/alter_function.sql
Normal file
17
src/test/modules/test_ddl_deparse/sql/alter_function.sql
Normal file
@ -0,0 +1,17 @@
|
||||
--
|
||||
-- ALTER_FUNCTION
|
||||
--
|
||||
|
||||
ALTER FUNCTION plpgsql_function_trigger_1 ()
|
||||
SET SCHEMA foo;
|
||||
|
||||
ALTER FUNCTION foo.plpgsql_function_trigger_1()
|
||||
COST 10;
|
||||
|
||||
CREATE ROLE tmprole;
|
||||
|
||||
ALTER FUNCTION plpgsql_function_trigger_2()
|
||||
OWNER TO tmprole;
|
||||
|
||||
DROP OWNED BY tmprole;
|
||||
DROP ROLE tmprole;
|
17
src/test/modules/test_ddl_deparse/sql/alter_sequence.sql
Normal file
17
src/test/modules/test_ddl_deparse/sql/alter_sequence.sql
Normal file
@ -0,0 +1,17 @@
|
||||
--
|
||||
-- ALTER_SEQUENCE
|
||||
--
|
||||
|
||||
ALTER SEQUENCE fkey_table_seq
|
||||
MINVALUE 10
|
||||
START 20
|
||||
CACHE 1
|
||||
NO CYCLE;
|
||||
|
||||
ALTER SEQUENCE fkey_table_seq
|
||||
RENAME TO fkey_table_seq_renamed;
|
||||
|
||||
ALTER SEQUENCE fkey_table_seq_renamed
|
||||
SET SCHEMA foo;
|
||||
|
||||
|
13
src/test/modules/test_ddl_deparse/sql/alter_table.sql
Normal file
13
src/test/modules/test_ddl_deparse/sql/alter_table.sql
Normal file
@ -0,0 +1,13 @@
|
||||
CREATE TABLE parent (
|
||||
a int
|
||||
);
|
||||
|
||||
CREATE TABLE child () INHERITS (parent);
|
||||
|
||||
CREATE TABLE grandchild () INHERITS (child);
|
||||
|
||||
ALTER TABLE parent ADD COLUMN b serial;
|
||||
|
||||
ALTER TABLE parent RENAME COLUMN b TO c;
|
||||
|
||||
ALTER TABLE parent ADD CONSTRAINT a_pos CHECK (a > 0);
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
--- ALTER_TYPE_ENUM
|
||||
---
|
||||
|
||||
ALTER TYPE enum_test ADD VALUE 'zzz' AFTER 'baz';
|
||||
ALTER TYPE enum_test ADD VALUE 'aaa' BEFORE 'foo';
|
17
src/test/modules/test_ddl_deparse/sql/comment_on.sql
Normal file
17
src/test/modules/test_ddl_deparse/sql/comment_on.sql
Normal file
@ -0,0 +1,17 @@
|
||||
--
|
||||
-- COMMENT_ON
|
||||
--
|
||||
|
||||
COMMENT ON SCHEMA foo IS 'This is schema foo';
|
||||
COMMENT ON TYPE enum_test IS 'ENUM test';
|
||||
COMMENT ON TYPE int2range IS 'RANGE test';
|
||||
COMMENT ON DOMAIN japanese_postal_code IS 'DOMAIN test';
|
||||
COMMENT ON SEQUENCE fkey_table_seq IS 'SEQUENCE test';
|
||||
COMMENT ON TABLE datatype_table IS 'This table should contain all native datatypes';
|
||||
COMMENT ON VIEW datatype_view IS 'This is a view';
|
||||
COMMENT ON FUNCTION c_function_test() IS 'FUNCTION test';
|
||||
COMMENT ON TRIGGER trigger_1 ON datatype_table IS 'TRIGGER test';
|
||||
COMMENT ON RULE rule_1 IS 'RULE test';
|
||||
|
||||
-- should not fire
|
||||
COMMENT ON DATABASE contrib_regression IS 'contrib regression';
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
--- CREATE_CONVERSION
|
||||
---
|
||||
|
||||
-- Simple test should suffice for this
|
||||
CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
|
10
src/test/modules/test_ddl_deparse/sql/create_domain.sql
Normal file
10
src/test/modules/test_ddl_deparse/sql/create_domain.sql
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
--- CREATE_DOMAIN
|
||||
---
|
||||
CREATE DOMAIN domainvarchar VARCHAR(5);
|
||||
|
||||
CREATE DOMAIN japanese_postal_code AS TEXT
|
||||
CHECK(
|
||||
VALUE ~ '^\d{3}$'
|
||||
OR VALUE ~ '^\d{3}-\d{4}$'
|
||||
);
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
--- CREATE_EXTENSION
|
||||
---
|
||||
|
||||
CREATE EXTENSION pg_stat_statements;
|
||||
|
31
src/test/modules/test_ddl_deparse/sql/create_rule.sql
Normal file
31
src/test/modules/test_ddl_deparse/sql/create_rule.sql
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
--- CREATE_RULE
|
||||
---
|
||||
|
||||
|
||||
CREATE RULE rule_1 AS
|
||||
ON INSERT
|
||||
TO datatype_table
|
||||
DO NOTHING;
|
||||
|
||||
CREATE RULE rule_2 AS
|
||||
ON UPDATE
|
||||
TO datatype_table
|
||||
DO INSERT INTO unlogged_table (id) VALUES(NEW.id);
|
||||
|
||||
CREATE RULE rule_3 AS
|
||||
ON DELETE
|
||||
TO datatype_table
|
||||
DO ALSO NOTHING;
|
||||
|
||||
CREATE RULE "_RETURN" AS
|
||||
ON SELECT
|
||||
TO like_datatype_table
|
||||
DO INSTEAD
|
||||
SELECT * FROM datatype_view;
|
||||
|
||||
CREATE RULE rule_3 AS
|
||||
ON DELETE
|
||||
TO like_datatype_table
|
||||
WHERE id < 100
|
||||
DO ALSO NOTHING;
|
17
src/test/modules/test_ddl_deparse/sql/create_schema.sql
Normal file
17
src/test/modules/test_ddl_deparse/sql/create_schema.sql
Normal file
@ -0,0 +1,17 @@
|
||||
--
|
||||
-- CREATE_SCHEMA
|
||||
--
|
||||
|
||||
CREATE SCHEMA foo;
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS bar;
|
||||
|
||||
CREATE SCHEMA baz;
|
||||
|
||||
-- Will not be created, and will not be handled by the
|
||||
-- event trigger
|
||||
CREATE SCHEMA IF NOT EXISTS baz;
|
||||
|
||||
CREATE SCHEMA element_test
|
||||
CREATE TABLE foo (id int)
|
||||
CREATE VIEW bar AS SELECT * FROM foo;
|
12
src/test/modules/test_ddl_deparse/sql/create_sequence_1.sql
Normal file
12
src/test/modules/test_ddl_deparse/sql/create_sequence_1.sql
Normal file
@ -0,0 +1,12 @@
|
||||
--
|
||||
-- CREATE_SEQUENCE
|
||||
--
|
||||
|
||||
CREATE SEQUENCE fkey_table_seq
|
||||
INCREMENT BY 1
|
||||
MINVALUE 0
|
||||
MAXVALUE 1000000
|
||||
START 10
|
||||
CACHE 10
|
||||
CYCLE;
|
||||
|
142
src/test/modules/test_ddl_deparse/sql/create_table.sql
Normal file
142
src/test/modules/test_ddl_deparse/sql/create_table.sql
Normal file
@ -0,0 +1,142 @@
|
||||
--
|
||||
-- CREATE_TABLE
|
||||
--
|
||||
|
||||
-- Datatypes
|
||||
CREATE TABLE datatype_table (
|
||||
id SERIAL,
|
||||
id_big BIGSERIAL,
|
||||
is_small SMALLSERIAL,
|
||||
v_bytea BYTEA,
|
||||
v_smallint SMALLINT,
|
||||
v_int INT,
|
||||
v_bigint BIGINT,
|
||||
v_char CHAR(1),
|
||||
v_varchar VARCHAR(10),
|
||||
v_text TEXT,
|
||||
v_bool BOOLEAN,
|
||||
v_inet INET,
|
||||
v_cidr CIDR,
|
||||
v_macaddr MACADDR,
|
||||
v_numeric NUMERIC(1,0),
|
||||
v_real REAL,
|
||||
v_float FLOAT(1),
|
||||
v_float8 FLOAT8,
|
||||
v_money MONEY,
|
||||
v_tsquery TSQUERY,
|
||||
v_tsvector TSVECTOR,
|
||||
v_date DATE,
|
||||
v_time TIME,
|
||||
v_time_tz TIME WITH TIME ZONE,
|
||||
v_timestamp TIMESTAMP,
|
||||
v_timestamp_tz TIMESTAMP WITH TIME ZONE,
|
||||
v_interval INTERVAL,
|
||||
v_bit BIT,
|
||||
v_bit4 BIT(4),
|
||||
v_varbit VARBIT,
|
||||
v_varbit4 VARBIT(4),
|
||||
v_box BOX,
|
||||
v_circle CIRCLE,
|
||||
v_lseg LSEG,
|
||||
v_path PATH,
|
||||
v_point POINT,
|
||||
v_polygon POLYGON,
|
||||
v_json JSON,
|
||||
v_xml XML,
|
||||
v_uuid UUID,
|
||||
v_txid_snapshot txid_snapshot,
|
||||
v_enum ENUM_TEST,
|
||||
v_postal_code japanese_postal_code,
|
||||
v_int2range int2range,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (id_big)
|
||||
);
|
||||
|
||||
-- Constraint definitions
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fkey_table (
|
||||
id INT NOT NULL DEFAULT nextval('fkey_table_seq'::REGCLASS),
|
||||
datatype_id INT NOT NULL REFERENCES datatype_table(id),
|
||||
big_id BIGINT NOT NULL,
|
||||
sometext TEXT COLLATE "POSIX",
|
||||
check_col_1 INT NOT NULL CHECK(check_col_1 < 10),
|
||||
check_col_2 INT NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fkey_big_id
|
||||
FOREIGN KEY (big_id)
|
||||
REFERENCES datatype_table(id_big),
|
||||
EXCLUDE USING btree (check_col_2 WITH =)
|
||||
);
|
||||
|
||||
-- Typed table
|
||||
|
||||
CREATE TABLE employees OF employee_type (
|
||||
PRIMARY KEY (name),
|
||||
salary WITH OPTIONS DEFAULT 1000
|
||||
);
|
||||
|
||||
-- Inheritance
|
||||
CREATE TABLE person (
|
||||
id INT NOT NULL PRIMARY KEY,
|
||||
name text,
|
||||
age int4,
|
||||
location point
|
||||
);
|
||||
|
||||
CREATE TABLE emp (
|
||||
salary int4,
|
||||
manager name
|
||||
) INHERITS (person) WITH OIDS;
|
||||
|
||||
|
||||
CREATE TABLE student (
|
||||
gpa float8
|
||||
) INHERITS (person);
|
||||
|
||||
CREATE TABLE stud_emp (
|
||||
percent int4
|
||||
) INHERITS (emp, student);
|
||||
|
||||
|
||||
-- Storage parameters
|
||||
|
||||
CREATE TABLE storage (
|
||||
id INT
|
||||
) WITH (
|
||||
fillfactor = 10,
|
||||
autovacuum_enabled = FALSE
|
||||
);
|
||||
|
||||
-- LIKE
|
||||
|
||||
CREATE TABLE like_datatype_table (
|
||||
LIKE datatype_table
|
||||
EXCLUDING ALL
|
||||
);
|
||||
|
||||
CREATE TABLE like_fkey_table (
|
||||
LIKE fkey_table
|
||||
INCLUDING DEFAULTS
|
||||
INCLUDING INDEXES
|
||||
INCLUDING STORAGE
|
||||
);
|
||||
|
||||
|
||||
-- Volatile table types
|
||||
CREATE UNLOGGED TABLE unlogged_table (
|
||||
id INT PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TEMP TABLE temp_table (
|
||||
id INT PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TEMP TABLE temp_table_commit_delete (
|
||||
id INT PRIMARY KEY
|
||||
)
|
||||
ON COMMIT DELETE ROWS;
|
||||
|
||||
CREATE TEMP TABLE temp_table_commit_drop (
|
||||
id INT PRIMARY KEY
|
||||
)
|
||||
ON COMMIT DROP;
|
18
src/test/modules/test_ddl_deparse/sql/create_trigger.sql
Normal file
18
src/test/modules/test_ddl_deparse/sql/create_trigger.sql
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
--- CREATE_TRIGGER
|
||||
---
|
||||
|
||||
CREATE FUNCTION plpgsql_function_trigger_1()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER trigger_1
|
||||
BEFORE INSERT OR UPDATE
|
||||
ON datatype_table
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE plpgsql_function_trigger_1();
|
21
src/test/modules/test_ddl_deparse/sql/create_type.sql
Normal file
21
src/test/modules/test_ddl_deparse/sql/create_type.sql
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
--- CREATE_TYPE
|
||||
---
|
||||
|
||||
CREATE FUNCTION text_w_default_in(cstring)
|
||||
RETURNS text_w_default
|
||||
AS 'textin'
|
||||
LANGUAGE internal STABLE STRICT;
|
||||
|
||||
CREATE FUNCTION text_w_default_out(text_w_default)
|
||||
RETURNS cstring
|
||||
AS 'textout'
|
||||
LANGUAGE internal STABLE STRICT ;
|
||||
|
||||
CREATE TYPE employee_type AS (name TEXT, salary NUMERIC);
|
||||
|
||||
CREATE TYPE enum_test AS ENUM ('foo', 'bar', 'baz');
|
||||
|
||||
CREATE TYPE int2range AS RANGE (
|
||||
SUBTYPE = int2
|
||||
);
|
17
src/test/modules/test_ddl_deparse/sql/create_view.sql
Normal file
17
src/test/modules/test_ddl_deparse/sql/create_view.sql
Normal file
@ -0,0 +1,17 @@
|
||||
--
|
||||
-- CREATE_VIEW
|
||||
--
|
||||
|
||||
CREATE VIEW static_view AS
|
||||
SELECT 'foo'::TEXT AS col;
|
||||
|
||||
CREATE OR REPLACE VIEW static_view AS
|
||||
SELECT 'bar'::TEXT AS col;
|
||||
|
||||
CREATE VIEW datatype_view AS
|
||||
SELECT * FROM datatype_table;
|
||||
|
||||
CREATE RECURSIVE VIEW nums_1_100 (n) AS
|
||||
VALUES (1)
|
||||
UNION ALL
|
||||
SELECT n+1 FROM nums_1_100 WHERE n < 100;
|
6
src/test/modules/test_ddl_deparse/sql/defprivs.sql
Normal file
6
src/test/modules/test_ddl_deparse/sql/defprivs.sql
Normal file
@ -0,0 +1,6 @@
|
||||
--
|
||||
-- ALTER DEFAULT PRIVILEGES
|
||||
--
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
REVOKE ALL PRIVILEGES ON TABLES FROM public;
|
8
src/test/modules/test_ddl_deparse/sql/matviews.sql
Normal file
8
src/test/modules/test_ddl_deparse/sql/matviews.sql
Normal file
@ -0,0 +1,8 @@
|
||||
--
|
||||
-- Materialized views
|
||||
--
|
||||
|
||||
CREATE MATERIALIZED VIEW pg_class_mv AS
|
||||
SELECT * FROM pg_class LIMIT 1 WITH NO DATA;
|
||||
|
||||
REFRESH MATERIALIZED VIEW pg_class_mv;
|
53
src/test/modules/test_ddl_deparse/sql/opfamily.sql
Normal file
53
src/test/modules/test_ddl_deparse/sql/opfamily.sql
Normal file
@ -0,0 +1,53 @@
|
||||
-- copied from equivclass.sql
|
||||
create type int8alias1;
|
||||
create function int8alias1in(cstring) returns int8alias1
|
||||
strict immutable language internal as 'int8in';
|
||||
create function int8alias1out(int8alias1) returns cstring
|
||||
strict immutable language internal as 'int8out';
|
||||
create type int8alias1 (
|
||||
input = int8alias1in,
|
||||
output = int8alias1out,
|
||||
like = int8
|
||||
);
|
||||
|
||||
create type int8alias2;
|
||||
create function int8alias2in(cstring) returns int8alias2
|
||||
strict immutable language internal as 'int8in';
|
||||
create function int8alias2out(int8alias2) returns cstring
|
||||
strict immutable language internal as 'int8out';
|
||||
create type int8alias2 (
|
||||
input = int8alias2in,
|
||||
output = int8alias2out,
|
||||
like = int8
|
||||
);
|
||||
|
||||
create cast (int8 as int8alias1) without function;
|
||||
create cast (int8 as int8alias2) without function;
|
||||
create cast (int8alias1 as int8) without function;
|
||||
create cast (int8alias2 as int8) without function;
|
||||
|
||||
create function int8alias1eq(int8alias1, int8alias1) returns bool
|
||||
strict immutable language internal as 'int8eq';
|
||||
create operator = (
|
||||
procedure = int8alias1eq,
|
||||
leftarg = int8alias1, rightarg = int8alias1,
|
||||
commutator = =,
|
||||
restrict = eqsel, join = eqjoinsel,
|
||||
merges
|
||||
);
|
||||
alter operator family integer_ops using btree add
|
||||
operator 3 = (int8alias1, int8alias1);
|
||||
|
||||
|
||||
-- copied from alter_table.sql
|
||||
create type ctype as (f1 int, f2 text);
|
||||
|
||||
create function same(ctype, ctype) returns boolean language sql
|
||||
as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
|
||||
|
||||
create operator =(procedure = same, leftarg = ctype, rightarg = ctype);
|
||||
|
||||
create operator class ctype_hash_ops
|
||||
default for type ctype using hash as
|
||||
operator 1 =(ctype, ctype);
|
||||
|
42
src/test/modules/test_ddl_deparse/sql/test_ddl_deparse.sql
Normal file
42
src/test/modules/test_ddl_deparse/sql/test_ddl_deparse.sql
Normal file
@ -0,0 +1,42 @@
|
||||
CREATE EXTENSION test_ddl_deparse;
|
||||
|
||||
CREATE OR REPLACE FUNCTION test_ddl_deparse()
|
||||
RETURNS event_trigger LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
r record;
|
||||
r2 record;
|
||||
cmdtype text;
|
||||
objtype text;
|
||||
tag text;
|
||||
BEGIN
|
||||
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||
LOOP
|
||||
-- verify that tags match
|
||||
tag = get_command_tag(r.command);
|
||||
IF tag <> r.command_tag THEN
|
||||
RAISE NOTICE 'tag % doesn''t match %', tag, r.command_tag;
|
||||
END IF;
|
||||
|
||||
-- log the operation
|
||||
cmdtype = get_command_type(r.command);
|
||||
IF cmdtype <> 'grant' THEN
|
||||
RAISE NOTICE 'DDL test: type %, tag %', cmdtype, tag;
|
||||
ELSE
|
||||
RAISE NOTICE 'DDL test: type %, object type %', cmdtype, r.object_type;
|
||||
END IF;
|
||||
|
||||
-- if alter table, log more
|
||||
IF cmdtype = 'alter table' THEN
|
||||
FOR r2 IN SELECT *
|
||||
FROM unnest(get_altertable_subcmdtypes(r.command))
|
||||
LOOP
|
||||
RAISE NOTICE ' subcommand: %', r2.unnest;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE EVENT TRIGGER test_ddl_deparse
|
||||
ON ddl_command_end EXECUTE PROCEDURE test_ddl_deparse();
|
16
src/test/modules/test_ddl_deparse/test_ddl_deparse--1.0.sql
Normal file
16
src/test/modules/test_ddl_deparse/test_ddl_deparse--1.0.sql
Normal file
@ -0,0 +1,16 @@
|
||||
/* src/test/modules/test_ddl_deparse/test_ddl_deparse--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION test_ddl_deparse" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION get_command_type(pg_ddl_command)
|
||||
RETURNS text IMMUTABLE STRICT
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C;
|
||||
|
||||
CREATE FUNCTION get_command_tag(pg_ddl_command)
|
||||
RETURNS text IMMUTABLE STRICT
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C;
|
||||
|
||||
CREATE FUNCTION get_altertable_subcmdtypes(pg_ddl_command)
|
||||
RETURNS text[] IMMUTABLE STRICT
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C;
|
267
src/test/modules/test_ddl_deparse/test_ddl_deparse.c
Normal file
267
src/test/modules/test_ddl_deparse/test_ddl_deparse.c
Normal file
@ -0,0 +1,267 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "tcop/deparse_utility.h"
|
||||
#include "tcop/utility.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
PG_FUNCTION_INFO_V1(get_command_type);
|
||||
PG_FUNCTION_INFO_V1(get_command_tag);
|
||||
PG_FUNCTION_INFO_V1(get_altertable_subcmdtypes);
|
||||
|
||||
Datum
|
||||
get_command_type(PG_FUNCTION_ARGS)
|
||||
{
|
||||
CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0);
|
||||
const char *type;
|
||||
|
||||
switch (cmd->type)
|
||||
{
|
||||
case SCT_Simple:
|
||||
type = "simple";
|
||||
break;
|
||||
case SCT_AlterTable:
|
||||
type = "alter table";
|
||||
break;
|
||||
case SCT_Grant:
|
||||
type = "grant";
|
||||
break;
|
||||
case SCT_AlterOpFamily:
|
||||
type = "alter operator family";
|
||||
break;
|
||||
case SCT_AlterDefaultPrivileges:
|
||||
type = "alter default privileges";
|
||||
break;
|
||||
case SCT_CreateOpClass:
|
||||
type = "create operator class";
|
||||
break;
|
||||
case SCT_AlterTSConfig:
|
||||
type = "alter text search configuration";
|
||||
break;
|
||||
default:
|
||||
type = "unknown command type";
|
||||
break;
|
||||
}
|
||||
|
||||
PG_RETURN_TEXT_P(cstring_to_text(type));
|
||||
}
|
||||
|
||||
Datum
|
||||
get_command_tag(PG_FUNCTION_ARGS)
|
||||
{
|
||||
CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0);
|
||||
|
||||
if (!cmd->parsetree)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
PG_RETURN_TEXT_P(cstring_to_text(CreateCommandTag(cmd->parsetree)));
|
||||
}
|
||||
|
||||
Datum
|
||||
get_altertable_subcmdtypes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0);
|
||||
ArrayBuildState *astate = NULL;
|
||||
ListCell *cell;
|
||||
|
||||
if (cmd->type != SCT_AlterTable)
|
||||
elog(ERROR, "command is not ALTER TABLE");
|
||||
|
||||
foreach(cell, cmd->d.alterTable.subcmds)
|
||||
{
|
||||
CollectedATSubcmd *sub = lfirst(cell);
|
||||
AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree;
|
||||
const char *strtype;
|
||||
|
||||
Assert(IsA(subcmd, AlterTableCmd));
|
||||
|
||||
switch (subcmd->subtype)
|
||||
{
|
||||
case AT_AddColumn:
|
||||
strtype = "ADD COLUMN";
|
||||
break;
|
||||
case AT_AddColumnRecurse:
|
||||
strtype = "ADD COLUMN (and recurse)";
|
||||
break;
|
||||
case AT_AddColumnToView:
|
||||
strtype = "ADD COLUMN TO VIEW";
|
||||
break;
|
||||
case AT_ColumnDefault:
|
||||
strtype = "ALTER COLUMN SET DEFAULT";
|
||||
break;
|
||||
case AT_DropNotNull:
|
||||
strtype = "DROP NOT NULL";
|
||||
break;
|
||||
case AT_SetNotNull:
|
||||
strtype = "SET NOT NULL";
|
||||
break;
|
||||
case AT_SetStatistics:
|
||||
strtype = "SET STATS";
|
||||
break;
|
||||
case AT_SetOptions:
|
||||
strtype = "SET OPTIONS";
|
||||
break;
|
||||
case AT_ResetOptions:
|
||||
strtype = "RESET OPTIONS";
|
||||
break;
|
||||
case AT_SetStorage:
|
||||
strtype = "SET STORAGE";
|
||||
break;
|
||||
case AT_DropColumn:
|
||||
strtype = "DROP COLUMN";
|
||||
break;
|
||||
case AT_DropColumnRecurse:
|
||||
strtype = "DROP COLUMN (and recurse)";
|
||||
break;
|
||||
case AT_AddIndex:
|
||||
strtype = "ADD INDEX";
|
||||
break;
|
||||
case AT_ReAddIndex:
|
||||
strtype = "(re) ADD INDEX";
|
||||
break;
|
||||
case AT_AddConstraint:
|
||||
strtype = "ADD CONSTRAINT";
|
||||
break;
|
||||
case AT_AddConstraintRecurse:
|
||||
strtype = "ADD CONSTRAINT (and recurse)";
|
||||
break;
|
||||
case AT_ReAddConstraint:
|
||||
strtype = "(re) ADD CONSTRAINT";
|
||||
break;
|
||||
case AT_AlterConstraint:
|
||||
strtype = "ALTER CONSTRAINT";
|
||||
break;
|
||||
case AT_ValidateConstraint:
|
||||
strtype = "VALIDATE CONSTRAINT";
|
||||
break;
|
||||
case AT_ValidateConstraintRecurse:
|
||||
strtype = "VALIDATE CONSTRAINT (and recurse)";
|
||||
break;
|
||||
case AT_ProcessedConstraint:
|
||||
strtype = "ADD (processed) CONSTRAINT";
|
||||
break;
|
||||
case AT_AddIndexConstraint:
|
||||
strtype = "ADD CONSTRAINT (using index)";
|
||||
break;
|
||||
case AT_DropConstraint:
|
||||
strtype = "DROP CONSTRAINT";
|
||||
break;
|
||||
case AT_DropConstraintRecurse:
|
||||
strtype = "DROP CONSTRAINT (and recurse)";
|
||||
break;
|
||||
case AT_AlterColumnType:
|
||||
strtype = "ALTER COLUMN SET TYPE";
|
||||
break;
|
||||
case AT_AlterColumnGenericOptions:
|
||||
strtype = "ALTER COLUMN SET OPTIONS";
|
||||
break;
|
||||
case AT_ChangeOwner:
|
||||
strtype = "CHANGE OWNER";
|
||||
break;
|
||||
case AT_ClusterOn:
|
||||
strtype = "CLUSTER";
|
||||
break;
|
||||
case AT_DropCluster:
|
||||
strtype = "DROP CLUSTER";
|
||||
break;
|
||||
case AT_SetLogged:
|
||||
strtype = "SET LOGGED";
|
||||
break;
|
||||
case AT_SetUnLogged:
|
||||
strtype = "SET UNLOGGED";
|
||||
break;
|
||||
case AT_AddOids:
|
||||
strtype = "ADD OIDS";
|
||||
break;
|
||||
case AT_AddOidsRecurse:
|
||||
strtype = "ADD OIDS (and recurse)";
|
||||
break;
|
||||
case AT_DropOids:
|
||||
strtype = "DROP OIDS";
|
||||
break;
|
||||
case AT_SetTableSpace:
|
||||
strtype = "SET TABLESPACE";
|
||||
break;
|
||||
case AT_SetRelOptions:
|
||||
strtype = "SET RELOPTIONS";
|
||||
break;
|
||||
case AT_ResetRelOptions:
|
||||
strtype = "RESET RELOPTIONS";
|
||||
break;
|
||||
case AT_ReplaceRelOptions:
|
||||
strtype = "REPLACE RELOPTIONS";
|
||||
break;
|
||||
case AT_EnableTrig:
|
||||
strtype = "ENABLE TRIGGER";
|
||||
break;
|
||||
case AT_EnableAlwaysTrig:
|
||||
strtype = "ENABLE TRIGGER (always)";
|
||||
break;
|
||||
case AT_EnableReplicaTrig:
|
||||
strtype = "ENABLE TRIGGER (replica)";
|
||||
break;
|
||||
case AT_DisableTrig:
|
||||
strtype = "DISABLE TRIGGER";
|
||||
break;
|
||||
case AT_EnableTrigAll:
|
||||
strtype = "ENABLE TRIGGER (all)";
|
||||
break;
|
||||
case AT_DisableTrigAll:
|
||||
strtype = "DISABLE TRIGGER (all)";
|
||||
break;
|
||||
case AT_EnableTrigUser:
|
||||
strtype = "ENABLE TRIGGER (user)";
|
||||
break;
|
||||
case AT_DisableTrigUser:
|
||||
strtype = "DISABLE TRIGGER (user)";
|
||||
break;
|
||||
case AT_EnableRule:
|
||||
strtype = "ENABLE RULE";
|
||||
break;
|
||||
case AT_EnableAlwaysRule:
|
||||
strtype = "ENABLE RULE (always)";
|
||||
break;
|
||||
case AT_EnableReplicaRule:
|
||||
strtype = "ENABLE RULE (replica)";
|
||||
break;
|
||||
case AT_DisableRule:
|
||||
strtype = "DISABLE RULE";
|
||||
break;
|
||||
case AT_AddInherit:
|
||||
strtype = "ADD INHERIT";
|
||||
break;
|
||||
case AT_DropInherit:
|
||||
strtype = "DROP INHERIT";
|
||||
break;
|
||||
case AT_AddOf:
|
||||
strtype = "OF";
|
||||
break;
|
||||
case AT_DropOf:
|
||||
strtype = "NOT OF";
|
||||
break;
|
||||
case AT_ReplicaIdentity:
|
||||
strtype = "REPLICA IDENTITY";
|
||||
break;
|
||||
case AT_EnableRowSecurity:
|
||||
strtype = "ENABLE ROW SECURITY";
|
||||
break;
|
||||
case AT_DisableRowSecurity:
|
||||
strtype = "DISABLE ROW SECURITY";
|
||||
break;
|
||||
case AT_GenericOptions:
|
||||
strtype = "SET OPTIONS";
|
||||
break;
|
||||
}
|
||||
|
||||
astate =
|
||||
accumArrayResult(astate, CStringGetTextDatum(strtype),
|
||||
false, TEXTOID, CurrentMemoryContext);
|
||||
}
|
||||
|
||||
if (astate == NULL)
|
||||
elog(ERROR, "empty alter table subcommand list");
|
||||
|
||||
PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext));
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
comment = 'Test code for DDL deparse feature'
|
||||
default_version = '1.0'
|
||||
module_pathname = '$libdir/test_ddl_deparse'
|
||||
relocatable = true
|
Reference in New Issue
Block a user