-- keep these tests aligned with generated_stored.sql
CREATESCHEMA generated_virtual_tests; GRANTUSAGEONSCHEMA generated_virtual_tests TO PUBLIC; SET search_path = generated_virtual_tests;
CREATETABLE gtest0 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (55) VIRTUAL); CREATETABLE gtest1 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL);
SELECT table_name, column_name, column_default, is_nullable, is_generated, generation_expression FROM information_schema.columns WHERE table_schema = 'generated_virtual_tests'ORDERBY1, 2;
SELECT table_name, column_name, dependent_column FROM information_schema.column_column_usage WHERE table_schema = 'generated_virtual_tests'ORDERBY1, 2, 3;
\d gtest1
-- duplicate generated CREATETABLE gtest_err_1 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL GENERATED ALWAYS AS (a * 3) VIRTUAL);
-- references to other generated columns, including self-references CREATETABLE gtest_err_2a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (b * 2) VIRTUAL); CREATETABLE gtest_err_2b (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL, c int GENERATED ALWAYS AS (b * 3) VIRTUAL); -- a whole-row var is a self-reference on steroids, so disallow that too CREATETABLE gtest_err_2c (a intPRIMARYKEY,
b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) VIRTUAL);
-- invalid reference CREATETABLE gtest_err_3 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (c * 2) VIRTUAL);
-- generation expression must be immutable CREATETABLE gtest_err_4 (a intPRIMARYKEY, b doubleprecision GENERATED ALWAYS AS (random()) VIRTUAL); -- ... but be sure that the immutability test is accurate CREATETABLE gtest2 (a int, b text GENERATED ALWAYS AS (a || ' sec') VIRTUAL); DROPTABLE gtest2;
-- cannot have default/identity and generated CREATETABLE gtest_err_5a (a intPRIMARYKEY, b intDEFAULT5 GENERATED ALWAYS AS (a * 2) VIRTUAL); CREATETABLE gtest_err_5b (a intPRIMARYKEY, b int GENERATED ALWAYS AS identity GENERATED ALWAYS AS (a * 2) VIRTUAL);
-- reference to system column not allowed in generated column -- (except tableoid, which we test below) CREATETABLE gtest_err_6a (a intPRIMARYKEY, b bool GENERATED ALWAYS AS (xmin <> 37) VIRTUAL);
-- various prohibited constructs CREATETABLE gtest_err_7a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (avg(a)) VIRTUAL); CREATETABLE gtest_err_7b (a intPRIMARYKEY, b int GENERATED ALWAYS AS (row_number() OVER (ORDERBY a)) VIRTUAL); CREATETABLE gtest_err_7c (a intPRIMARYKEY, b int GENERATED ALWAYS AS ((SELECT a)) VIRTUAL); CREATETABLE gtest_err_7d (a intPRIMARYKEY, b int GENERATED ALWAYS AS (generate_series(1, a)) VIRTUAL);
-- GENERATED BY DEFAULT not allowed CREATETABLE gtest_err_8 (a intPRIMARYKEY, b int GENERATED BYDEFAULTAS (a * 2) VIRTUAL);
SELECT * FROM gtest1 ORDERBY a; SELECT gtest1 FROM gtest1 ORDERBY a; -- whole-row reference SELECT a, (SELECT gtest1.b) FROM gtest1 ORDERBY a; -- sublink DELETEFROM gtest1 WHERE a >= 3;
UPDATE gtest1 SET b = DEFAULTWHERE a = 1; UPDATE gtest1 SET b = 11WHERE a = 1; -- error
SELECT * FROM gtest1 ORDERBY a;
SELECT a, b, b * 2AS b2 FROM gtest1 ORDERBY a; SELECT a, b FROM gtest1 WHERE b = 4ORDERBY a;
-- test that overflow error happens on read INSERTINTO gtest1 VALUES (2000000000); SELECT * FROM gtest1; DELETEFROM gtest1 WHERE a = 2000000000;
-- test with joins CREATETABLE gtestx (x int, y int); INSERTINTO gtestx VALUES (11, 1), (22, 2), (33, 3); SELECT * FROM gtestx, gtest1 WHERE gtestx.y = gtest1.a; DROPTABLE gtestx;
-- test UPDATE/DELETE quals SELECT * FROM gtest1 ORDERBY a; UPDATE gtest1 SET a = 3WHERE b = 4 RETURNING old.*, new.*; SELECT * FROM gtest1 ORDERBY a; DELETEFROM gtest1 WHERE b = 2; SELECT * FROM gtest1 ORDERBY a;
-- test MERGE CREATETABLE gtestm (
id intPRIMARYKEY,
f1 int,
f2 int,
f3 int GENERATED ALWAYS AS (f1 * 2) VIRTUAL,
f4 int GENERATED ALWAYS AS (f2 * 2) VIRTUAL
); INSERTINTO gtestm VALUES (1, 5, 100);
MERGE INTO gtestm t USING (VALUES (1, 10), (2, 20)) v(id, f1) ON t.id = v.id WHEN MATCHED THENUPDATESET f1 = v.f1 WHENNOT MATCHED THENINSERTVALUES (v.id, v.f1, 200)
RETURNING merge_action(), old.*, new.*; SELECT * FROM gtestm ORDERBY id; DROPTABLE gtestm;
CREATETABLE gtestm (
a intPRIMARYKEY,
b int GENERATED ALWAYS AS (a * 2) VIRTUAL
); INSERTINTO gtestm (a) SELECT g FROM generate_series(1, 10) g;
MERGE INTO gtestm t USING gtestm AS s ON2 * t.a = s.b WHEN MATCHED THENDELETE RETURNING *; DROPTABLE gtestm;
SELECT * FROM gtest1v; DELETEFROM gtest1v WHERE a >= 5; DROP VIEW gtest1v;
-- CTEs WITH foo AS (SELECT * FROM gtest1) SELECT * FROM foo;
-- inheritance CREATETABLE gtest1_1 () INHERITS (gtest1); SELECT * FROM gtest1_1;
\d gtest1_1 INSERTINTO gtest1_1 VALUES (4); SELECT * FROM gtest1_1; SELECT * FROM gtest1;
-- can't have generated column that is a child of normal column CREATETABLE gtest_normal (a int, b int); CREATETABLE gtest_normal_child (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL) INHERITS (gtest_normal); -- error CREATETABLE gtest_normal_child (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); ALTERTABLE gtest_normal_child INHERIT gtest_normal; -- error DROPTABLE gtest_normal, gtest_normal_child;
-- test inheritance mismatches between parent and child CREATETABLE gtestx (x int, b intDEFAULT10) INHERITS (gtest1); -- error CREATETABLE gtestx (x int, b int GENERATED ALWAYS AS IDENTITY) INHERITS (gtest1); -- error CREATETABLE gtestx (x int, b int GENERATED ALWAYS AS (a * 22) STORED) INHERITS (gtest1); -- error CREATETABLE gtestx (x int, b int GENERATED ALWAYS AS (a * 22) VIRTUAL) INHERITS (gtest1); -- ok, overrides parent
\d+ gtestx INSERTINTO gtestx (a, x) VALUES (11, 22); SELECT * FROM gtest1; SELECT * FROM gtestx;
CREATETABLE gtestxx_1 (a intNOTNULL, b int); ALTERTABLE gtestxx_1 INHERIT gtest1; -- error CREATETABLE gtestxx_3 (a intNOTNULL, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); ALTERTABLE gtestxx_3 INHERIT gtest1; -- ok CREATETABLE gtestxx_4 (b int GENERATED ALWAYS AS (a * 2) VIRTUAL, a intNOTNULL); ALTERTABLE gtestxx_4 INHERIT gtest1; -- ok
CREATETABLE gtesty (x int, b int GENERATED ALWAYS AS (x * 22) VIRTUAL); CREATETABLE gtest1_y () INHERITS (gtest1, gtesty); -- error CREATETABLE gtest1_y (b int GENERATED ALWAYS AS (x + 1) VIRTUAL) INHERITS (gtest1, gtesty); -- ok
\d gtest1_y
-- test correct handling of GENERATED column that's only in child CREATETABLE gtestp (f1 int); CREATETABLE gtestc (f2 int GENERATED ALWAYS AS (f1+1) VIRTUAL) INHERITS(gtestp); INSERTINTO gtestc values(42); TABLE gtestc; UPDATE gtestp SET f1 = f1 * 10; TABLE gtestc; DROPTABLE gtestp CASCADE;
-- test update CREATETABLE gtest3 (a int, b int GENERATED ALWAYS AS (a * 3) VIRTUAL); INSERTINTO gtest3 (a) VALUES (1), (2), (3), (NULL); SELECT * FROM gtest3 ORDERBY a; UPDATE gtest3 SET a = 22WHERE a = 2; SELECT * FROM gtest3 ORDERBY a;
CREATETABLE gtest3a (a text, b text GENERATED ALWAYS AS (a || '+' || a) VIRTUAL); INSERTINTO gtest3a (a) VALUES ('a'), ('b'), ('c'), (NULL); SELECT * FROM gtest3a ORDERBY a; UPDATE gtest3a SET a = 'bb'WHERE a = 'b'; SELECT * FROM gtest3a ORDERBY a;
-- null values CREATETABLE gtest2 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (NULL) VIRTUAL); INSERTINTO gtest2 VALUES (1); SELECT * FROM gtest2;
-- simple column reference for varlena types CREATETABLE gtest_varlena (a varchar, b varchar GENERATED ALWAYS AS (a) VIRTUAL); INSERTINTO gtest_varlena (a) VALUES('01234567890123456789'); INSERTINTO gtest_varlena (a) VALUES(NULL); SELECT * FROM gtest_varlena ORDERBY a; DROPTABLE gtest_varlena;
-- composite types CREATE TYPE double_int as (a int, b int); CREATETABLE gtest4 (
a int,
b double_int GENERATED ALWAYS AS ((a * 2, a * 3)) VIRTUAL
); --INSERT INTO gtest4 VALUES (1), (6); --SELECT * FROM gtest4;
--DROP TABLE gtest4; DROP TYPE double_int;
-- using tableoid is allowed CREATETABLE gtest_tableoid (
a intPRIMARYKEY,
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) VIRTUAL
); INSERTINTO gtest_tableoid VALUES (1), (2); ALTERTABLE gtest_tableoid ADDCOLUMN
c regclass GENERATED ALWAYS AS (tableoid) VIRTUAL; SELECT * FROM gtest_tableoid;
-- drop column behavior CREATETABLE gtest10 (a intPRIMARYKEY, b int, c int GENERATED ALWAYS AS (b * 2) VIRTUAL); ALTERTABLE gtest10 DROPCOLUMN b; -- fails ALTERTABLE gtest10 DROPCOLUMN b CASCADE; -- drops c too
\d gtest10
CREATETABLE gtest10a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); ALTERTABLE gtest10a DROPCOLUMN b; INSERTINTO gtest10a (a) VALUES (1);
-- privileges CREATE USER regress_user11;
CREATETABLE gtest11 (a intPRIMARYKEY, b int, c int GENERATED ALWAYS AS (b * 2) VIRTUAL); INSERTINTO gtest11 VALUES (1, 10), (2, 20); GRANTSELECT (a, c) ON gtest11 TO regress_user11;
CREATE FUNCTION gf1(a int) RETURNS intAS $$ SELECT a * 3 $$ IMMUTABLE LANGUAGE SQL; REVOKEALLON FUNCTION gf1(int) FROM PUBLIC;
CREATETABLE gtest12 (a intPRIMARYKEY, b int, c int GENERATED ALWAYS AS (gf1(b)) VIRTUAL); -- fails, user-defined function --INSERT INTO gtest12 VALUES (1, 10), (2, 20); --GRANT SELECT (a, c), INSERT ON gtest12 TO regress_user11;
SET ROLE regress_user11; SELECT a, b FROM gtest11; -- not allowed SELECT a, c FROM gtest11; -- allowed SELECT gf1(10); -- not allowed --INSERT INTO gtest12 VALUES (3, 30), (4, 40); -- allowed (does not actually invoke the function) --SELECT a, c FROM gtest12; -- currently not allowed because of function permissions, should arguably be allowed
RESET ROLE;
--DROP FUNCTION gf1(int); -- fail DROPTABLE gtest11; --DROP TABLE gtest12; DROP FUNCTION gf1(int); DROP USER regress_user11;
-- check constraints CREATETABLE gtest20 (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL CHECK (b < 50)); INSERTINTO gtest20 (a) VALUES (10); -- ok INSERTINTO gtest20 (a) VALUES (30); -- violates constraint
ALTERTABLE gtest20 ALTERCOLUMN b SET EXPRESSION AS (a * 100); -- violates constraint (currently not supported) ALTERTABLE gtest20 ALTERCOLUMN b SET EXPRESSION AS (a * 3); -- ok (currently not supported)
CREATETABLE gtest20a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); INSERTINTO gtest20a (a) VALUES (10); INSERTINTO gtest20a (a) VALUES (30); ALTERTABLE gtest20a ADDCHECK (b < 50); -- fails on existing row -- table rewrite cases ALTERTABLE gtest20a ADDCOLUMN c float8DEFAULT random() CHECK (b < 50); -- fails on existing row ALTERTABLE gtest20a ADDCOLUMN c float8DEFAULT random() CHECK (b < 61); -- ok
CREATETABLE gtest20b (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); INSERTINTO gtest20b (a) VALUES (10); INSERTINTO gtest20b (a) VALUES (30); ALTERTABLE gtest20b ADDCONSTRAINT chk CHECK (b < 50) NOT VALID; ALTERTABLE gtest20b VALIDATE CONSTRAINT chk; -- fails on existing row
-- check with whole-row reference CREATETABLE gtest20c (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); ALTERTABLE gtest20c ADDCONSTRAINT whole_row_check CHECK (gtest20c ISNOTNULL); INSERTINTO gtest20c VALUES (1); -- ok INSERTINTO gtest20c VALUES (NULL); -- fails
-- not-null constraints CREATETABLE gtest21a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (nullif(a, 0)) VIRTUAL NOTNULL); INSERTINTO gtest21a (a) VALUES (1); -- ok INSERTINTO gtest21a (a) VALUES (0); -- violates constraint
-- also check with table constraint syntax CREATETABLE gtest21ax (a intPRIMARYKEY, b int GENERATED ALWAYS AS (nullif(a, 0)) VIRTUAL, CONSTRAINT cc NOTNULL b); INSERTINTO gtest21ax (a) VALUES (0); -- violates constraint INSERTINTO gtest21ax (a) VALUES (1); --ok -- SET EXPRESSION supports not null constraint ALTERTABLE gtest21ax ALTERCOLUMN b SET EXPRESSION AS (nullif(a, 1)); --error DROPTABLE gtest21ax;
CREATETABLE gtest21ax (a intPRIMARYKEY, b int GENERATED ALWAYS AS (nullif(a, 0)) VIRTUAL); ALTERTABLE gtest21ax ADDCONSTRAINT cc NOTNULL b; INSERTINTO gtest21ax (a) VALUES (0); -- violates constraint DROPTABLE gtest21ax;
CREATETABLE gtest21b (a int, b int GENERATED ALWAYS AS (nullif(a, 0)) VIRTUAL); ALTERTABLE gtest21b ALTERCOLUMN b SETNOTNULL; INSERTINTO gtest21b (a) VALUES (1); -- ok INSERTINTO gtest21b (a) VALUES (2), (0); -- violates constraint INSERTINTO gtest21b (a) VALUES (NULL); -- error ALTERTABLE gtest21b ALTERCOLUMN b DROPNOTNULL; INSERTINTO gtest21b (a) VALUES (0); -- ok now
-- not-null constraint with partitioned table CREATETABLE gtestnn_parent (
f1 int,
f2 bigint,
f3 bigint GENERATED ALWAYS AS (nullif(f1, 1) + nullif(f2, 10)) VIRTUAL NOTNULL
) PARTITION BY RANGE (f1); CREATETABLE gtestnn_child PARTITION OF gtestnn_parent FORVALUESFROM (1) TO (5); CREATETABLE gtestnn_childdef PARTITION OF gtestnn_parent default; -- check the error messages INSERTINTO gtestnn_parent VALUES (2, 2, default), (3, 5, default), (14, 12, default); -- ok INSERTINTO gtestnn_parent VALUES (1, 2, default); -- error INSERTINTO gtestnn_parent VALUES (2, 10, default); -- error ALTERTABLE gtestnn_parent ALTERCOLUMN f3 SET EXPRESSION AS (nullif(f1, 2) + nullif(f2, 11)); -- error INSERTINTO gtestnn_parent VALUES (10, 11, default); -- ok SELECT * FROM gtestnn_parent ORDERBY f1, f2, f3; -- test ALTER TABLE ADD COLUMN ALTERTABLE gtestnn_parent ADDCOLUMN c intNOTNULL GENERATED ALWAYS AS (nullif(f1, 14) + nullif(f2, 10)) VIRTUAL; -- error ALTERTABLE gtestnn_parent ADDCOLUMN c intNOTNULL GENERATED ALWAYS AS (nullif(f1, 13) + nullif(f2, 5)) VIRTUAL; -- error ALTERTABLE gtestnn_parent ADDCOLUMN c intNOTNULL GENERATED ALWAYS AS (nullif(f1, 4) + nullif(f2, 6)) VIRTUAL; -- ok
-- index constraints CREATETABLE gtest22a (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a / 2) VIRTUAL UNIQUE); --INSERT INTO gtest22a VALUES (2); --INSERT INTO gtest22a VALUES (3); --INSERT INTO gtest22a VALUES (4); CREATETABLE gtest22b (a int, b int GENERATED ALWAYS AS (a / 2) VIRTUAL, PRIMARYKEY (a, b)); --INSERT INTO gtest22b VALUES (2); --INSERT INTO gtest22b VALUES (2);
-- indexes CREATETABLE gtest22c (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); --CREATE INDEX gtest22c_b_idx ON gtest22c (b); --CREATE INDEX gtest22c_expr_idx ON gtest22c ((b * 3)); --CREATE INDEX gtest22c_pred_idx ON gtest22c (a) WHERE b > 0; --\d gtest22c
--INSERT INTO gtest22c VALUES (1), (2), (3); --SET enable_seqscan TO off; --SET enable_bitmapscan TO off; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b = 4; --SELECT * FROM gtest22c WHERE b = 4; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b * 3 = 6; --SELECT * FROM gtest22c WHERE b * 3 = 6; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE a = 1 AND b > 0; --SELECT * FROM gtest22c WHERE a = 1 AND b > 0;
--ALTER TABLE gtest22c ALTER COLUMN b SET EXPRESSION AS (a * 4); --ANALYZE gtest22c; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b = 8; --SELECT * FROM gtest22c WHERE b = 8; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE b * 3 = 12; --SELECT * FROM gtest22c WHERE b * 3 = 12; --EXPLAIN (COSTS OFF) SELECT * FROM gtest22c WHERE a = 1 AND b > 0; --SELECT * FROM gtest22c WHERE a = 1 AND b > 0; --RESET enable_seqscan; --RESET enable_bitmapscan;
-- foreign keys CREATETABLE gtest23a (x intPRIMARYKEY, y int); --INSERT INTO gtest23a VALUES (1, 11), (2, 22), (3, 33);
CREATETABLE gtest23x (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x) ONUPDATECASCADE); -- error CREATETABLE gtest23x (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x) ONDELETESETNULL); -- error
CREATETABLE gtest23b (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x)); --\d gtest23b
--INSERT INTO gtest23b VALUES (1); -- ok --INSERT INTO gtest23b VALUES (5); -- error --ALTER TABLE gtest23b ALTER COLUMN b SET EXPRESSION AS (a * 5); -- error --ALTER TABLE gtest23b ALTER COLUMN b SET EXPRESSION AS (a * 1); -- ok
--DROP TABLE gtest23b; --DROP TABLE gtest23a;
CREATETABLE gtest23p (x int, y int GENERATED ALWAYS AS (x * 2) VIRTUAL, PRIMARYKEY (y)); --INSERT INTO gtest23p VALUES (1), (2), (3);
CREATETABLE gtest23q (a intPRIMARYKEY, b intREFERENCES gtest23p (y)); --INSERT INTO gtest23q VALUES (1, 2); -- ok --INSERT INTO gtest23q VALUES (2, 5); -- error
-- domains CREATE DOMAIN gtestdomain1 ASintCHECK (VALUE < 10); CREATETABLE gtest24 (a intPRIMARYKEY, b gtestdomain1 GENERATED ALWAYS AS (a * 2) VIRTUAL); --INSERT INTO gtest24 (a) VALUES (4); -- ok --INSERT INTO gtest24 (a) VALUES (6); -- error CREATE TYPE gtestdomain1range AS range (subtype = gtestdomain1); CREATETABLE gtest24r (a intPRIMARYKEY, b gtestdomain1range GENERATED ALWAYS AS (gtestdomain1range(a, a + 5)) VIRTUAL); --INSERT INTO gtest24r (a) VALUES (4); -- ok --INSERT INTO gtest24r (a) VALUES (6); -- error
CREATETABLE gtest24at (a intPRIMARYKEY); ALTERTABLE gtest24at ADDCOLUMN b gtestdomain1 GENERATED ALWAYS AS (a * 2) VIRTUAL; -- error CREATETABLE gtest24ata (a intPRIMARYKEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); ALTERTABLE gtest24ata ALTERCOLUMN b TYPE gtestdomain1; -- error
CREATE DOMAIN gtestdomainnn ASintCHECK (VALUE ISNOTNULL); CREATETABLE gtest24nn (a int, b gtestdomainnn GENERATED ALWAYS AS (a * 2) VIRTUAL); --INSERT INTO gtest24nn (a) VALUES (4); -- ok --INSERT INTO gtest24nn (a) VALUES (NULL); -- error
-- using user-defined type not yet supported CREATETABLE gtest24xxx (a gtestdomain1, b gtestdomain1, c int GENERATED ALWAYS AS (greatest(a, b)) VIRTUAL); -- error
-- typed tables (currently not supported) CREATE TYPE gtest_type AS (f1 integer, f2 text, f3 bigint); CREATETABLE gtest28 OF gtest_type (f1 WITH OPTIONS GENERATED ALWAYS AS (f2 *2) VIRTUAL); DROP TYPE gtest_type CASCADE;
-- partitioning cases CREATETABLE gtest_parent (f1 date NOTNULL, f2 bigint, f3 bigint) PARTITION BY RANGE (f1); CREATETABLE gtest_child PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS (f2 * 2) VIRTUAL
) FORVALUESFROM ('2016-07-01') TO ('2016-08-01'); -- error CREATETABLE gtest_child (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child FORVALUESFROM ('2016-07-01') TO ('2016-08-01'); -- error DROPTABLE gtest_parent, gtest_child;
CREATETABLE gtest_parent (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE (f1); CREATETABLE gtest_child PARTITION OF gtest_parent FORVALUESFROM ('2016-07-01') TO ('2016-08-01'); -- inherits gen expr CREATETABLE gtest_child2 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS (f2 * 22) VIRTUAL -- overrides gen expr
) FORVALUESFROM ('2016-08-01') TO ('2016-09-01'); CREATETABLE gtest_child3 PARTITION OF gtest_parent (
f3 DEFAULT42-- error
) FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); CREATETABLE gtest_child3 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS IDENTITY -- error
) FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); CREATETABLE gtest_child3 PARTITION OF gtest_parent (
f3 GENERATED ALWAYS AS (f2 * 2) STORED -- error
) FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); CREATETABLE gtest_child3 (f1 date NOTNULL, f2 bigint, f3 bigint); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child3 FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); -- error DROPTABLE gtest_child3; CREATETABLE gtest_child3 (f1 date NOTNULL, f2 bigint, f3 bigintDEFAULT42); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child3 FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); -- error DROPTABLE gtest_child3; CREATETABLE gtest_child3 (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS IDENTITY); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child3 FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); -- error DROPTABLE gtest_child3; CREATETABLE gtest_child3 (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 33) STORED); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child3 FORVALUESFROM ('2016-09-01') TO ('2016-10-01'); -- error DROPTABLE gtest_child3; CREATETABLE gtest_child3 (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 33) VIRTUAL); ALTERTABLE gtest_parent ATTACH PARTITION gtest_child3 FORVALUESFROM ('2016-09-01') TO ('2016-10-01');
\d gtest_child
\d gtest_child2
\d gtest_child3 INSERTINTO gtest_parent (f1, f2) VALUES ('2016-07-15', 1); INSERTINTO gtest_parent (f1, f2) VALUES ('2016-07-15', 2); INSERTINTO gtest_parent (f1, f2) VALUES ('2016-08-15', 3); SELECT tableoid::regclass, * FROM gtest_parent ORDERBY1, 2, 3; SELECT tableoid::regclass, * FROM gtest_child ORDERBY1, 2, 3; SELECT tableoid::regclass, * FROM gtest_child2 ORDERBY1, 2, 3; -- uses child's generation expression, not parent's SELECT tableoid::regclass, * FROM gtest_child3 ORDERBY1, 2, 3; UPDATE gtest_parent SET f1 = f1 + 60WHERE f2 = 1; SELECT tableoid::regclass, * FROM gtest_parent ORDERBY1, 2, 3;
-- alter only parent's and one child's generation expression ALTERTABLE ONLY gtest_parent ALTERCOLUMN f3 SET EXPRESSION AS (f2 * 4); ALTERTABLE gtest_child ALTERCOLUMN f3 SET EXPRESSION AS (f2 * 10);
\d gtest_parent
\d gtest_child
\d gtest_child2
\d gtest_child3 SELECT tableoid::regclass, * FROM gtest_parent ORDERBY1, 2, 3;
-- alter generation expression of parent and all its children altogether ALTERTABLE gtest_parent ALTERCOLUMN f3 SET EXPRESSION AS (f2 * 2);
\d gtest_parent
\d gtest_child
\d gtest_child2
\d gtest_child3 SELECT tableoid::regclass, * FROM gtest_parent ORDERBY1, 2, 3; -- we leave these tables around for purposes of testing dump/reload/upgrade
-- generated columns in partition key (not allowed) CREATETABLE gtest_part_key (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE (f3); CREATETABLE gtest_part_key (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((f3)); CREATETABLE gtest_part_key (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((f3 * 3)); CREATETABLE gtest_part_key (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((gtest_part_key)); CREATETABLE gtest_part_key (f1 date NOTNULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 2) VIRTUAL) PARTITION BY RANGE ((gtest_part_key isnotnull));
-- ALTER TABLE ... ADD COLUMN CREATETABLE gtest25 (a intPRIMARYKEY); INSERTINTO gtest25 VALUES (3), (4); ALTERTABLE gtest25 ADDCOLUMN b int GENERATED ALWAYS AS (a * 2) VIRTUAL, ALTERCOLUMN b SET EXPRESSION AS (a * 3); SELECT * FROM gtest25 ORDERBY a; ALTERTABLE gtest25 ADDCOLUMN x int GENERATED ALWAYS AS (b * 4) VIRTUAL; -- error ALTERTABLE gtest25 ADDCOLUMN x int GENERATED ALWAYS AS (z * 4) VIRTUAL; -- error ALTERTABLE gtest25 ADDCOLUMN c intDEFAULT42, ADDCOLUMN x int GENERATED ALWAYS AS (c * 4) VIRTUAL; ALTERTABLE gtest25 ADDCOLUMN d intDEFAULT101; ALTERTABLE gtest25 ALTERCOLUMN d SET DATA TYPE float8, ADDCOLUMN y float8 GENERATED ALWAYS AS (d * 4) VIRTUAL; SELECT * FROM gtest25 ORDERBY a;
\d gtest25
-- ALTER TABLE ... ALTER COLUMN CREATETABLE gtest27 (
a int,
b int,
x int GENERATED ALWAYS AS ((a + b) * 2) VIRTUAL
); INSERTINTO gtest27 (a, b) VALUES (3, 7), (4, 11); ALTERTABLE gtest27 ALTERCOLUMN a TYPE text; -- error ALTERTABLE gtest27 ALTERCOLUMN x TYPE numeric;
\d gtest27 SELECT * FROM gtest27; ALTERTABLE gtest27 ALTERCOLUMN x TYPE boolean USING x <> 0; -- error ALTERTABLE gtest27 ALTERCOLUMN x DROPDEFAULT; -- error -- test not-null checking during table rewrite INSERTINTO gtest27 (a, b) VALUES (NULL, NULL); ALTERTABLE gtest27 DROPCOLUMN x, ALTERCOLUMN a TYPE bigint, ALTERCOLUMN b TYPE bigint, ADDCOLUMN x bigint GENERATED ALWAYS AS ((a + b) * 2) VIRTUAL NOTNULL; -- error DELETEFROM gtest27 WHERE a ISNULLAND b ISNULL; -- It's possible to alter the column types this way: ALTERTABLE gtest27 DROPCOLUMN x, ALTERCOLUMN a TYPE bigint, ALTERCOLUMN b TYPE bigint, ADDCOLUMN x bigint GENERATED ALWAYS AS ((a + b) * 2) VIRTUAL;
\d gtest27 -- Ideally you could just do this, but not today (and should x change type?): ALTERTABLE gtest27 ALTERCOLUMN a TYPE float8, ALTERCOLUMN b TYPE float8; -- error
\d gtest27 SELECT * FROM gtest27;
-- ALTER TABLE ... ALTER COLUMN ... DROP EXPRESSION CREATETABLE gtest29 (
a int,
b int GENERATED ALWAYS AS (a * 2) VIRTUAL
); INSERTINTO gtest29 (a) VALUES (3), (4); SELECT * FROM gtest29;
\d gtest29 ALTERTABLE gtest29 ALTERCOLUMN a SET EXPRESSION AS (a * 3); -- error ALTERTABLE gtest29 ALTERCOLUMN a DROP EXPRESSION; -- error ALTERTABLE gtest29 ALTERCOLUMN a DROP EXPRESSION IFEXISTS; -- notice
-- Change the expression ALTERTABLE gtest29 ALTERCOLUMN b SET EXPRESSION AS (a * 3); SELECT * FROM gtest29;
\d gtest29
ALTERTABLE gtest29 ALTERCOLUMN b DROP EXPRESSION; -- not supported INSERTINTO gtest29 (a) VALUES (5); INSERTINTO gtest29 (a, b) VALUES (6, 66); SELECT * FROM gtest29;
\d gtest29
-- check that dependencies between columns have also been removed --ALTER TABLE gtest29 DROP COLUMN a; -- should not drop b --\d gtest29
-- with inheritance CREATETABLE gtest30 (
a int,
b int GENERATED ALWAYS AS (a * 2) VIRTUAL
); CREATETABLE gtest30_1 () INHERITS (gtest30); ALTERTABLE gtest30 ALTERCOLUMN b DROP EXPRESSION;
\d gtest30
\d gtest30_1 DROPTABLE gtest30 CASCADE; CREATETABLE gtest30 (
a int,
b int GENERATED ALWAYS AS (a * 2) VIRTUAL
); CREATETABLE gtest30_1 () INHERITS (gtest30); ALTERTABLE ONLY gtest30 ALTERCOLUMN b DROP EXPRESSION; -- error
\d gtest30
\d gtest30_1 ALTERTABLE gtest30_1 ALTERCOLUMN b DROP EXPRESSION; -- error
-- composite type dependencies CREATETABLE gtest31_1 (a int, b text GENERATED ALWAYS AS ('hello') VIRTUAL, c text); CREATETABLE gtest31_2 (x int, y gtest31_1); ALTERTABLE gtest31_1 ALTERCOLUMN b TYPE varchar; -- fails
-- bug #18970 ALTERTABLE gtest31_2 ADDCONSTRAINT cc CHECK ((y).b ISNOTNULL); ALTERTABLE gtest31_1 ALTERCOLUMN b SET EXPRESSION AS ('hello1'); ALTERTABLE gtest31_2 DROPCONSTRAINT cc;
CREATE STATISTICS gtest31_2_stat ON ((y).b isnotnull) FROM gtest31_2; ALTERTABLE gtest31_1 ALTERCOLUMN b SET EXPRESSION AS ('hello2'); DROP STATISTICS gtest31_2_stat;
CREATEINDEX gtest31_2_y_idx ON gtest31_2(((y).b)); ALTERTABLE gtest31_1 ALTERCOLUMN b SET EXPRESSION AS ('hello3');
DROPTABLE gtest31_1, gtest31_2;
-- Check it for a partitioned table, too CREATETABLE gtest31_1 (a int, b text GENERATED ALWAYS AS ('hello') VIRTUAL, c text) PARTITION BY LIST (a); CREATETABLE gtest31_2 (x int, y gtest31_1); ALTERTABLE gtest31_1 ALTERCOLUMN b TYPE varchar; -- fails DROPTABLE gtest31_1, gtest31_2;
-- triggers CREATETABLE gtest26 (
a intPRIMARYKEY,
b int GENERATED ALWAYS AS (a * 2) VIRTUAL
);
CREATE FUNCTION gtest_trigger_func() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN IF tg_op IN ('DELETE', 'UPDATE') THEN
RAISE INFO '%: %: old = %', TG_NAME, TG_WHEN, OLD;
END IF; IF tg_op IN ('INSERT', 'UPDATE') THEN
RAISE INFO '%: %: new = %', TG_NAME, TG_WHEN, NEW;
END IF; IF tg_op = 'DELETE'THEN RETURN OLD; ELSE RETURN NEW;
END IF;
END
$$;
CREATETRIGGER gtest1 BEFOREDELETEORUPDATEON gtest26 FOREACH ROW WHEN (OLD.b < 0) -- ok
EXECUTE PROCEDURE gtest_trigger_func();
CREATETRIGGER gtest3 AFTER DELETEORUPDATEON gtest26 FOREACH ROW WHEN (OLD.b < 0) -- ok
EXECUTE PROCEDURE gtest_trigger_func();
CREATETRIGGER gtest4 AFTER INSERTORUPDATEON gtest26 FOREACH ROW WHEN (NEW.b < 0) -- ok
EXECUTE PROCEDURE gtest_trigger_func();
INSERTINTO gtest26 (a) VALUES (-2), (0), (3); SELECT * FROM gtest26 ORDERBY a; UPDATE gtest26 SET a = a * -2; SELECT * FROM gtest26 ORDERBY a; DELETEFROM gtest26 WHERE a = -6; SELECT * FROM gtest26 ORDERBY a;
DROPTRIGGER gtest1 ON gtest26; DROPTRIGGER gtest2 ON gtest26; DROPTRIGGER gtest3 ON gtest26;
-- Check that an UPDATE of "a" fires the trigger for UPDATE OF b, per -- SQL standard. CREATE FUNCTION gtest_trigger_func3() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'OK'; RETURN NEW;
END
$$;
CREATETRIGGER gtest11 BEFOREUPDATE OF b ON gtest26 FOREACH ROW
EXECUTE PROCEDURE gtest_trigger_func3();
UPDATE gtest26 SET a = 1WHERE a = 0;
DROPTRIGGER gtest11 ON gtest26;
TRUNCATE gtest26;
-- check that modifications of generated columns in triggers do -- not get propagated CREATE FUNCTION gtest_trigger_func4() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
NEW.a = 10;
NEW.b = 300; RETURN NEW;
END;
$$;
INSERTINTO gtest26 (a) VALUES (1); SELECT * FROM gtest26 ORDERBY a; UPDATE gtest26 SET a = 11WHERE a = 10; SELECT * FROM gtest26 ORDERBY a;
-- LIKE INCLUDING GENERATED and dropped column handling CREATETABLE gtest28a (
a int,
b int,
c int,
x int GENERATED ALWAYS AS (b * 2) VIRTUAL
);
ALTERTABLE gtest28a DROPCOLUMN a;
CREATETABLE gtest28b (LIKE gtest28a INCLUDING GENERATED);
\d gtest28*
-- rule actions referring to generated columns: -- NEW.b in a rule action should reflect the generated column's new value CREATETABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); CREATETABLE gtest_rule_log (op text, old_b int, new_b int); CREATE RULE gtest_rule_upd ASONUPDATETO gtest_rule
DO ALSO INSERTINTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); CREATE RULE gtest_rule_ins ASONINSERTTO gtest_rule
DO ALSO INSERTINTO gtest_rule_log VALUES ('INS', NULL, NEW.b); INSERTINTO gtest_rule (a) VALUES (1); UPDATE gtest_rule SET a = 10; UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); SELECT * FROM gtest_rule_log; DROP RULE gtest_rule_upd ON gtest_rule; DROP RULE gtest_rule_ins ON gtest_rule; DROPTABLE gtest_rule_log;
-- rule quals referring to generated columns: -- NEW.b in the rule qual should reflect the generated column's new value CREATE RULE gtest_rule_qual ASONUPDATETO gtest_rule WHERE NEW.b > 100
DO INSTEAD NOTHING; UPDATE gtest_rule SET a = 100; SELECT * FROM gtest_rule; DROPTABLE gtest_rule;
-- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOTIN ('', 's', 'v');
-- -- test the expansion of virtual generated columns -- -- these tests are specific to generated_virtual.sql --
createtable gtest32 (
a intprimarykey,
b int generated always as (a * 2),
c int generated always as (10 + 10),
d int generated always as (coalesce(a, 100)),
e int
);
-- Ensure that nullingrel bits are propagated into the generation expressions explain (costs off) select sum(t2.b) over (partition by t2.a),
sum(t2.c) over (partition by t2.a),
sum(t2.d) over (partition by t2.a) from gtest32 as t1 leftjoin gtest32 as t2 on (t1.a = t2.a) orderby t1.a;
select sum(t2.b) over (partition by t2.a),
sum(t2.c) over (partition by t2.a),
sum(t2.d) over (partition by t2.a) from gtest32 as t1 leftjoin gtest32 as t2 on (t1.a = t2.a) orderby t1.a;
-- Ensure that outer-join removal functions correctly after the propagation of nullingrel bits explain (costs off) select t1.a from gtest32 t1 leftjoin gtest32 t2 on t1.a = t2.a where coalesce(t2.b, 1) = 2;
select t1.a from gtest32 t1 leftjoin gtest32 t2 on t1.a = t2.a where coalesce(t2.b, 1) = 2;
explain (costs off) select t1.a from gtest32 t1 leftjoin gtest32 t2 on t1.a = t2.a where coalesce(t2.b, 1) = 2or t1.a isnull;
select t1.a from gtest32 t1 leftjoin gtest32 t2 on t1.a = t2.a where coalesce(t2.b, 1) = 2or t1.a isnull;
-- Ensure that the generation expressions are wrapped into PHVs if needed explain (verbose, costs off) select t2.* from gtest32 t1 leftjoin gtest32 t2 onfalse; select t2.* from gtest32 t1 leftjoin gtest32 t2 onfalse;
explain (verbose, costs off) select * from gtest32 t groupby grouping sets (a, b, c, d, e) having c = 20; select * from gtest32 t groupby grouping sets (a, b, c, d, e) having c = 20;
-- Ensure that the virtual generated columns in ALTER COLUMN TYPE USING expression are expanded altertable gtest32 altercolumn e type bigintusing b;
droptable gtest32;
-- Ensure that virtual generated columns in constraint expressions are expanded createtable gtest33 (a int, b int generated always as (a * 2) virtual notnull, check (b > 10)); set constraint_exclusion toon;
-- should get a dummy Result, not a seq scan explain (costs off) select * from gtest33 where b < 10;
-- should get a dummy Result, not a seq scan explain (costs off) select * from gtest33 where b isnull;
reset constraint_exclusion; droptable gtest33;
-- Ensure that EXCLUDED.<virtual-generated-column> in INSERT ... ON CONFLICT -- DO UPDATE is expanded to the generation expression, both for plain and -- partitioned target relations. createtable gtest34 (id intprimarykey, a int,
c int generated always as (a * 10) virtual); insertinto gtest34 values (1, 5); insertinto gtest34 values (1, 7) on conflict (id) do updateset a = excluded.c returning *; insertinto gtest34 values (1, 2) on conflict (id) do updateset a = gtest34.c + excluded.c returning *; insertinto gtest34 values (1, 3) on conflict (id) do updateset a = 999where excluded.c > 20 returning *; droptable gtest34;
createtable gtest34p (id intprimarykey, a int,
c int generated always as (a * 10) virtual)
partition by range (id); createtable gtest34p_1 partition of gtest34p forvaluesfrom (1) to (100); insertinto gtest34p values (1, 5); insertinto gtest34p values (1, 7) on conflict (id) do updateset a = excluded.c returning *; insertinto gtest34p values (1, 2) on conflict (id) do updateset a = gtest34p.c + excluded.c returning *; droptable gtest34p;
-- Ensure that virtual generated columns work with WHERE CURRENT OF createtable gtest_cursor (id intprimarykey, a int, b int generated always as (a * 2) virtual); insertinto gtest_cursor values (1, 10), (2, 20), (3, 30);
begin; declare curs cursorforselect * from gtest_cursor orderby id forupdate; fetch1from curs; update gtest_cursor set a = 99where current of curs; select * from gtest_cursor orderby id; deletefrom gtest_cursor where current of curs; select * from gtest_cursor orderby id; commit;
droptable gtest_cursor;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.36 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.