diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c new file mode 100644 index b6464d4..2c9d8ae --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -96,7 +96,8 @@ static List *matchLocks(CmdType event, R int varno, Query *parsetree, bool *hasUpdate); static Query *fireRIRrules(Query *parsetree, List *activeRIRs); static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist); -static Node *expand_generated_columns_internal(Node *node, Relation rel, int rt_index, RangeTblEntry *rte); +static Node *expand_generated_columns_internal(Node *node, Relation rel, int rt_index, + RangeTblEntry *rte, int result_relation); /* @@ -2326,8 +2327,10 @@ fireRIRrules(Query *parsetree, List *act * Note that subqueries in virtual generated column expressions are * not currently supported, so this cannot add any more sublinks. */ - parsetree = (Query *) expand_generated_columns_internal((Node *) parsetree, - rel, rt_index, rte); + parsetree = (Query *) + expand_generated_columns_internal((Node *) parsetree, + rel, rt_index, rte, + parsetree->resultRelation); table_close(rel, NoLock); } @@ -4449,9 +4452,18 @@ RewriteQuery(Query *parsetree, List *rew * If the table contains virtual generated columns, build a target list * containing the expanded expressions and use ReplaceVarsFromTargetList() to * do the replacements. + * + * Vars matching rt_index at the current query level are replaced by the + * virtual generated column expressions from rel, if there are any. + * + * The caller must also provide rte, the RTE describing the target relation, + * in order to handle any whole-row Vars referencing the target, and + * result_relation, the index of the result relation, if this is part of an + * INSERT/UPDATE/DELETE/MERGE query. */ static Node * -expand_generated_columns_internal(Node *node, Relation rel, int rt_index, RangeTblEntry *rte) +expand_generated_columns_internal(Node *node, Relation rel, int rt_index, + RangeTblEntry *rte, int result_relation) { TupleDesc tupdesc; @@ -4502,7 +4514,10 @@ expand_generated_columns_internal(Node * Assert(list_length(tlist) > 0); - node = ReplaceVarsFromTargetList(node, rt_index, 0, rte, tlist, REPLACEVARS_CHANGE_VARNO, rt_index, NULL); + node = ReplaceVarsFromTargetList(node, rt_index, 0, rte, tlist, + result_relation, + REPLACEVARS_CHANGE_VARNO, rt_index, + NULL); } return node; @@ -4529,7 +4544,7 @@ expand_generated_columns_in_expr(Node *n rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel); - node = expand_generated_columns_internal(node, rel, rt_index, rte); + node = expand_generated_columns_internal(node, rel, rt_index, rte, 0); } return node; diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out new file mode 100644 index 5a74c0a..367605d --- a/src/test/regress/expected/generated_virtual.out +++ b/src/test/regress/expected/generated_virtual.out @@ -190,7 +190,12 @@ SELECT * FROM gtest1 ORDER BY a; 2 | 4 (2 rows) -UPDATE gtest1 SET a = 3 WHERE b = 4; +UPDATE gtest1 SET a = 3 WHERE b = 4 RETURNING old.*, new.*; + a | b | a | b +---+---+---+--- + 2 | 4 | 3 | 6 +(1 row) + SELECT * FROM gtest1 ORDER BY a; a | b ---+--- @@ -216,7 +221,14 @@ CREATE TABLE gtestm ( INSERT INTO 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 THEN UPDATE SET f1 = v.f1 - WHEN NOT MATCHED THEN INSERT VALUES (v.id, v.f1, 200); + WHEN NOT MATCHED THEN INSERT VALUES (v.id, v.f1, 200) + RETURNING merge_action(), old.*, new.*; + merge_action | id | f1 | f2 | f3 | f4 | id | f1 | f2 | f3 | f4 +--------------+----+----+-----+----+-----+----+----+-----+----+----- + UPDATE | 1 | 5 | 100 | 10 | 200 | 1 | 10 | 100 | 20 | 200 + INSERT | | | | | | 2 | 20 | 200 | 40 | 400 +(2 rows) + SELECT * FROM gtestm ORDER BY id; id | f1 | f2 | f3 | f4 ----+----+-----+----+----- diff --git a/src/test/regress/sql/generated_virtual.sql b/src/test/regress/sql/generated_virtual.sql new file mode 100644 index f855898..91aec4e --- a/src/test/regress/sql/generated_virtual.sql +++ b/src/test/regress/sql/generated_virtual.sql @@ -84,7 +84,7 @@ DROP TABLE gtestx; -- test UPDATE/DELETE quals SELECT * FROM gtest1 ORDER BY a; -UPDATE gtest1 SET a = 3 WHERE b = 4; +UPDATE gtest1 SET a = 3 WHERE b = 4 RETURNING old.*, new.*; SELECT * FROM gtest1 ORDER BY a; DELETE FROM gtest1 WHERE b = 2; SELECT * FROM gtest1 ORDER BY a; @@ -100,7 +100,8 @@ CREATE TABLE gtestm ( INSERT INTO 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 THEN UPDATE SET f1 = v.f1 - WHEN NOT MATCHED THEN INSERT VALUES (v.id, v.f1, 200); + WHEN NOT MATCHED THEN INSERT VALUES (v.id, v.f1, 200) + RETURNING merge_action(), old.*, new.*; SELECT * FROM gtestm ORDER BY id; DROP TABLE gtestm;