Add support for printing/reading MergeAction nodes
Hello, hackers!
When debugging is enabled for server logging, isolation tests fail
because there're no corresponding output functions for InsertStmt /
DeleteStmt / UpdateStmt that are used in the output of the MergeAction
nodes (see the attached regressions diffs and output). I also attached a
try that makes the tests pass. Sorry if I missed that it was already
discussed somewhere.
--
Marina Polyakova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
diff.patchtext/x-diff; name=diff.patchDownload
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c8d9626..2411658 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -409,6 +409,68 @@ _outMergeAction(StringInfo str, const MergeAction *node)
}
static void
+_outInferClause(StringInfo str, const InferClause *node)
+{
+ WRITE_NODE_TYPE("INFERCLAUSE");
+
+ WRITE_NODE_FIELD(indexElems);
+ WRITE_NODE_FIELD(whereClause);
+ WRITE_STRING_FIELD(conname);
+ WRITE_LOCATION_FIELD(location);
+}
+
+static void
+_outOnConflictClause(StringInfo str, const OnConflictClause *node)
+{
+ WRITE_NODE_TYPE("ONCONFLICTCLAUSE");
+
+ WRITE_ENUM_FIELD(action, OnConflictAction);
+ WRITE_NODE_FIELD(infer);
+ WRITE_NODE_FIELD(targetList);
+ WRITE_NODE_FIELD(whereClause);
+ WRITE_LOCATION_FIELD(location);
+}
+
+static void
+_outInsertStmt(StringInfo str, const InsertStmt *node)
+{
+ WRITE_NODE_TYPE("INSERT");
+
+ WRITE_NODE_FIELD(relation);
+ WRITE_NODE_FIELD(cols);
+ WRITE_NODE_FIELD(selectStmt);
+ WRITE_NODE_FIELD(onConflictClause);
+ WRITE_NODE_FIELD(returningList);
+ WRITE_NODE_FIELD(withClause);
+ WRITE_ENUM_FIELD(override, OverridingKind);
+}
+
+static void
+_outDeleteStmt(StringInfo str, const DeleteStmt *node)
+{
+ WRITE_NODE_TYPE("DELETE");
+
+ WRITE_NODE_FIELD(relation);
+ WRITE_NODE_FIELD(usingClause);
+ WRITE_NODE_FIELD(whereClause);
+ WRITE_NODE_FIELD(returningList);
+ WRITE_NODE_FIELD(withClause);
+}
+
+static void
+_outUpdateStmt(StringInfo str, const UpdateStmt *node)
+{
+ WRITE_NODE_TYPE("UPDATE");
+
+ WRITE_NODE_FIELD(relation);
+ WRITE_NODE_FIELD(targetList);
+ WRITE_NODE_FIELD(whereClause);
+ WRITE_NODE_FIELD(fromClause);
+ WRITE_NODE_FIELD(returningList);
+ WRITE_NODE_FIELD(withClause);
+}
+
+static void
_outAppend(StringInfo str, const Append *node)
{
WRITE_NODE_TYPE("APPEND");
@@ -3682,6 +3744,21 @@ outNode(StringInfo str, const void *obj)
case T_MergeAction:
_outMergeAction(str, obj);
break;
+ case T_InferClause:
+ _outInferClause(str, obj);
+ break;
+ case T_OnConflictClause:
+ _outOnConflictClause(str, obj);
+ break;
+ case T_InsertStmt:
+ _outInsertStmt(str, obj);
+ break;
+ case T_DeleteStmt:
+ _outDeleteStmt(str, obj);
+ break;
+ case T_UpdateStmt:
+ _outUpdateStmt(str, obj);
+ break;
case T_Append:
_outAppend(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 4518fa0..13891b1 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1620,6 +1620,93 @@ _readMergeAction(void)
}
/*
+ * _readInferClause
+ */
+static InferClause *
+_readInferClause(void)
+{
+ READ_LOCALS(InferClause);
+
+ READ_NODE_FIELD(indexElems);
+ READ_NODE_FIELD(whereClause);
+ READ_STRING_FIELD(conname);
+ READ_LOCATION_FIELD(location);
+
+ READ_DONE();
+}
+
+/*
+ * _readOnConflictClause
+ */
+static OnConflictClause *
+_readOnConflictClause(void)
+{
+ READ_LOCALS(OnConflictClause);
+
+ READ_ENUM_FIELD(action, OnConflictAction);
+ READ_NODE_FIELD(infer);
+ READ_NODE_FIELD(targetList);
+ READ_NODE_FIELD(whereClause);
+ READ_LOCATION_FIELD(location);
+
+ READ_DONE();
+}
+
+/*
+ * _readInsertStmt
+ */
+static InsertStmt *
+_readInsertStmt(void)
+{
+ READ_LOCALS(InsertStmt);
+
+ READ_NODE_FIELD(relation);
+ READ_NODE_FIELD(cols);
+ READ_NODE_FIELD(selectStmt);
+ READ_NODE_FIELD(onConflictClause);
+ READ_NODE_FIELD(returningList);
+ READ_NODE_FIELD(withClause);
+ READ_ENUM_FIELD(override, OverridingKind);
+
+ READ_DONE();
+}
+
+/*
+ * _readDeleteStmt
+ */
+static DeleteStmt *
+_readDeleteStmt(void)
+{
+ READ_LOCALS(DeleteStmt);
+
+ READ_NODE_FIELD(relation);
+ READ_NODE_FIELD(usingClause);
+ READ_NODE_FIELD(whereClause);
+ READ_NODE_FIELD(returningList);
+ READ_NODE_FIELD(withClause);
+
+ READ_DONE();
+}
+
+/*
+ * _readUpdateStmt
+ */
+static UpdateStmt *
+_readUpdateStmt(void)
+{
+ READ_LOCALS(UpdateStmt);
+
+ READ_NODE_FIELD(relation);
+ READ_NODE_FIELD(targetList);
+ READ_NODE_FIELD(whereClause);
+ READ_NODE_FIELD(fromClause);
+ READ_NODE_FIELD(returningList);
+ READ_NODE_FIELD(withClause);
+
+ READ_DONE();
+}
+
+/*
* _readAppend
*/
static Append *
@@ -2620,6 +2707,16 @@ parseNodeString(void)
return_value = _readModifyTable();
else if (MATCH("MERGEACTION", 11))
return_value = _readMergeAction();
+ else if (MATCH("INFERCLAUSE", 11))
+ return_value = _readInferClause();
+ else if (MATCH("ONCONFLICTCLAUSE", 16))
+ return_value = _readOnConflictClause();
+ else if (MATCH("INSERT", 6))
+ return_value = _readInsertStmt();
+ else if (MATCH("DELETE", 6))
+ return_value = _readDeleteStmt();
+ else if (MATCH("UPDATE", 6))
+ return_value = _readUpdateStmt();
else if (MATCH("APPEND", 6))
return_value = _readAppend();
else if (MATCH("MERGEAPPEND", 11))
regression.diffstext/x-diff; name=regression.diffsDownload
*** C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/expected/merge-insert-update.out Wed Apr 4 14:42:57 2018
--- C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/results/merge-insert-update.out Wed Apr 4 18:16:00 2018
***************
*** 1,6 ****
--- 1,12 ----
Parsed test spec with 2 sessions
starting permutation: merge1 c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1: MERGE INTO target t USING (SELECT 1 as key, 'merge1' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge1';
step c1: COMMIT;
step select2: SELECT * FROM target;
***************
*** 10,17 ****
--- 16,35 ----
step c2: COMMIT;
starting permutation: merge1 c1 merge2 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1: MERGE INTO target t USING (SELECT 1 as key, 'merge1' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge1';
step c1: COMMIT;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2';
step select2: SELECT * FROM target;
key val
***************
*** 21,26 ****
--- 39,50 ----
starting permutation: insert1 merge2 c1 select2 c2
step insert1: INSERT INTO target VALUES (1, 'insert1');
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2'; <waiting ...>
step c1: COMMIT;
step merge2: <... completed>
***************
*** 30,36 ****
--- 54,72 ----
step c2: COMMIT;
starting permutation: merge1 merge2 c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1: MERGE INTO target t USING (SELECT 1 as key, 'merge1' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge1';
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2'; <waiting ...>
step c1: COMMIT;
step merge2: <... completed>
***************
*** 40,46 ****
--- 76,94 ----
step c2: COMMIT;
starting permutation: merge1 merge2 a1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1: MERGE INTO target t USING (SELECT 1 as key, 'merge1' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge1';
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2'; <waiting ...>
step a1: ABORT;
step merge2: <... completed>
***************
*** 54,59 ****
--- 102,113 ----
step delete1: DELETE FROM target WHERE key = 1;
step insert1: INSERT INTO target VALUES (1, 'insert1');
step c1: COMMIT;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2';
step select2: SELECT * FROM target;
key val
***************
*** 64,69 ****
--- 118,129 ----
starting permutation: delete1 insert1 merge2 c1 select2 c2
step delete1: DELETE FROM target WHERE key = 1;
step insert1: INSERT INTO target VALUES (1, 'insert1');
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2'; <waiting ...>
step c1: COMMIT;
step merge2: <... completed>
***************
*** 75,80 ****
--- 135,143 ----
starting permutation: delete1 insert1 merge2i c1 select2 c2
step delete1: DELETE FROM target WHERE key = 1;
step insert1: INSERT INTO target VALUES (1, 'insert1');
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge2i: MERGE INTO target t USING (SELECT 1 as key, 'merge2' as val) s ON s.key = t.key WHEN MATCHED THEN UPDATE set val = t.val || ' updated by merge2';
step c1: COMMIT;
step select2: SELECT * FROM target;
======================================================================
*** C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/expected/merge-delete.out Wed Apr 4 14:42:57 2018
--- C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/results/merge-delete.out Wed Apr 4 18:16:01 2018
***************
*** 9,14 ****
--- 9,17 ----
step c2: COMMIT;
starting permutation: merge_delete c1 select2 c2
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
step merge_delete: MERGE INTO target t USING (SELECT 1 as key) s ON s.key = t.key WHEN MATCHED THEN DELETE;
step c1: COMMIT;
step select2: SELECT * FROM target;
***************
*** 26,31 ****
--- 29,37 ----
step c2: COMMIT;
starting permutation: merge_delete c1 update1 select2 c2
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
step merge_delete: MERGE INTO target t USING (SELECT 1 as key) s ON s.key = t.key WHEN MATCHED THEN DELETE;
step c1: COMMIT;
step update1: UPDATE target t SET val = t.val || ' updated by update1' WHERE t.key = 1;
***************
*** 37,42 ****
--- 43,54 ----
starting permutation: delete c1 merge2 select2 c2
step delete: DELETE FROM target t WHERE t.key = 1;
step c1: COMMIT;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2a' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
step select2: SELECT * FROM target;
key val
***************
*** 45,52 ****
--- 57,73 ----
step c2: COMMIT;
starting permutation: merge_delete c1 merge2 select2 c2
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
step merge_delete: MERGE INTO target t USING (SELECT 1 as key) s ON s.key = t.key WHEN MATCHED THEN DELETE;
step c1: COMMIT;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2a' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
step select2: SELECT * FROM target;
key val
***************
*** 65,70 ****
--- 86,94 ----
step c2: COMMIT;
starting permutation: merge_delete update1 c1 select2 c2
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
step merge_delete: MERGE INTO target t USING (SELECT 1 as key) s ON s.key = t.key WHEN MATCHED THEN DELETE;
step update1: UPDATE target t SET val = t.val || ' updated by update1' WHERE t.key = 1; <waiting ...>
step c1: COMMIT;
***************
*** 76,81 ****
--- 100,111 ----
starting permutation: delete merge2 c1 select2 c2
step delete: DELETE FROM target t WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2a' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val; <waiting ...>
step c1: COMMIT;
step merge2: <... completed>
***************
*** 86,92 ****
--- 116,131 ----
step c2: COMMIT;
starting permutation: merge_delete merge2 c1 select2 c2
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
+ WARNING: could not dump unrecognized node type: 228
step merge_delete: MERGE INTO target t USING (SELECT 1 as key) s ON s.key = t.key WHEN MATCHED THEN DELETE;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2: MERGE INTO target t USING (SELECT 1 as key, 'merge2a' as val) s ON s.key = t.key WHEN NOT MATCHED THEN INSERT VALUES (s.key, s.val) WHEN MATCHED THEN UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val; <waiting ...>
step c1: COMMIT;
step merge2: <... completed>
======================================================================
*** C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/expected/merge-update.out Wed Apr 4 14:42:57 2018
--- C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/results/merge-update.out Wed Apr 4 18:16:03 2018
***************
*** 1,6 ****
--- 1,12 ----
Parsed test spec with 2 sessions
starting permutation: merge1 c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 18,23 ****
--- 24,35 ----
step c2: COMMIT;
starting permutation: merge1 c1 merge2a select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 28,33 ****
--- 40,51 ----
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
step c1: COMMIT;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2a:
MERGE INTO target t
USING (SELECT 1 as key, 'merge2a' as val) s
***************
*** 45,50 ****
--- 63,74 ----
step c2: COMMIT;
starting permutation: merge1 merge2a c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 54,59 ****
--- 78,89 ----
WHEN MATCHED THEN
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2a:
MERGE INTO target t
USING (SELECT 1 as key, 'merge2a' as val) s
***************
*** 73,78 ****
--- 103,114 ----
step c2: COMMIT;
starting permutation: merge1 merge2a a1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 82,87 ****
--- 118,129 ----
WHEN MATCHED THEN
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2a:
MERGE INTO target t
USING (SELECT 1 as key, 'merge2a' as val) s
***************
*** 100,105 ****
--- 142,153 ----
step c2: COMMIT;
starting permutation: merge1 merge2b c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 109,114 ****
--- 157,168 ----
WHEN MATCHED THEN
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2b:
MERGE INTO target t
USING (SELECT 1 as key, 'merge2b' as val) s
***************
*** 128,133 ****
--- 182,193 ----
step c2: COMMIT;
starting permutation: merge1 merge2c c1 select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge1:
MERGE INTO target t
USING (SELECT 1 as key, 'merge1' as val) s
***************
*** 137,142 ****
--- 197,208 ----
WHEN MATCHED THEN
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step merge2c:
MERGE INTO target t
USING (SELECT 1 as key, 'merge2c' as val) s
***************
*** 156,161 ****
--- 222,233 ----
step c2: COMMIT;
starting permutation: pa_merge1 pa_merge2a c1 pa_select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step pa_merge1:
MERGE INTO pa_target t
USING (SELECT 1 as key, 'pa_merge1' as val) s
***************
*** 165,170 ****
--- 237,248 ----
WHEN MATCHED THEN
UPDATE set val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step pa_merge2a:
MERGE INTO pa_target t
USING (SELECT 1 as key, 'pa_merge2a' as val) s
***************
*** 184,189 ****
--- 262,273 ----
step c2: COMMIT;
starting permutation: pa_merge2 pa_merge2a c1 pa_select2 c2
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step pa_merge2:
MERGE INTO pa_target t
USING (SELECT 1 as key, 'pa_merge1' as val) s
***************
*** 193,198 ****
--- 277,288 ----
WHEN MATCHED THEN
UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val;
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 227
+ WARNING: could not dump unrecognized node type: 229
step pa_merge2a:
MERGE INTO pa_target t
USING (SELECT 1 as key, 'pa_merge2a' as val) s
======================================================================
*** C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/expected/merge-match-recheck.out Wed Apr 4 14:42:57 2018
--- C:/Users/buildfarm/mpolyakova/postgresql/src/test/isolation/results/merge-match-recheck.out Wed Apr 4 18:16:04 2018
***************
*** 2,7 ****
--- 2,16 ----
starting permutation: update1 merge_status c2 select1 c1
step update1: UPDATE target t SET balance = balance + 10, val = t.val || ' updated by update1' WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge_status:
MERGE INTO target t
USING (SELECT 1 as key) s
***************
*** 23,28 ****
--- 32,46 ----
starting permutation: update2 merge_status c2 select1 c1
step update2: UPDATE target t SET status = 's2', val = t.val || ' updated by update2' WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge_status:
MERGE INTO target t
USING (SELECT 1 as key) s
***************
*** 44,49 ****
--- 62,76 ----
starting permutation: update3 merge_status c2 select1 c1
step update3: UPDATE target t SET status = 's3', val = t.val || ' updated by update3' WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge_status:
MERGE INTO target t
USING (SELECT 1 as key) s
***************
*** 65,70 ****
--- 92,106 ----
starting permutation: update5 merge_status c2 select1 c1
step update5: UPDATE target t SET status = 's5', val = t.val || ' updated by update5' WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge_status:
MERGE INTO target t
USING (SELECT 1 as key) s
***************
*** 86,91 ****
--- 122,136 ----
starting permutation: update_bal1 merge_bal c2 select1 c1
step update_bal1: UPDATE target t SET balance = 50, val = t.val || ' updated by update_bal1' WHERE t.key = 1;
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
+ WARNING: could not dump unrecognized node type: 229
step merge_bal:
MERGE INTO target t
USING (SELECT 1 as key) s
======================================================================
Marina Polyakova <m.polyakova@postgrespro.ru> writes:
When debugging is enabled for server logging, isolation tests fail
because there're no corresponding output functions for InsertStmt /
DeleteStmt / UpdateStmt that are used in the output of the MergeAction
nodes (see the attached regressions diffs and output). I also attached a
try that makes the tests pass. Sorry if I missed that it was already
discussed somewhere.
Uh ... what?
Those node types are supposed to appear in raw grammar output only;
they should never survive past parse analysis.
If the MERGE patch has broken this, I'm going to push back on that
and push back on it hard, because it probably means there are a
whole bunch of other raw-grammar-output-only node types that can
now get past the parser stage as well, as children of these nodes.
The answer to that is not to add a ton of new infrastructure, it's
"you did MERGE wrong".
BTW, poking around in the grammar, I notice that MergeStmt did not
get added to RuleActionStmt. That seems like a rather serious
omission.
regards, tom lane
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
BTW, poking around in the grammar, I notice that MergeStmt did not
get added to RuleActionStmt. That seems like a rather serious
omission.
MERGE isn't a privilege, a trigger action or a policy action. Why
would it be in RuleActionStmt?
Could you explain what command you think should be supported?
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Marina Polyakova <m.polyakova@postgrespro.ru> writes:
When debugging is enabled for server logging, isolation tests fail
because there're no corresponding output functions for InsertStmt /
DeleteStmt / UpdateStmt that are used in the output of the MergeAction
nodes (see the attached regressions diffs and output). I also attached a
try that makes the tests pass. Sorry if I missed that it was already
discussed somewhere.Uh ... what?
Those node types are supposed to appear in raw grammar output only;
they should never survive past parse analysis.
So if I understand this correctly, it has nothing to do with the
isolation tester, that's just the place where the report was from.
Which debug mode are we talking about, please?
If the MERGE patch has broken this, I'm going to push back on that
and push back on it hard, because it probably means there are a
whole bunch of other raw-grammar-output-only node types that can
now get past the parser stage as well, as children of these nodes.
The answer to that is not to add a ton of new infrastructure, it's
"you did MERGE wrong".
MERGE hasn't broken anything. Marina is saying that the debug output
for MERGE isn't generated correctly.
I accept it shouldn't give spurious messages and I'm sure we can fix.
MERGE contains multiple actions of Insert, Update and Delete and these
could be output in various debug modes. I'm not clear what meaning we
might attach to them if we looked since that differs from normal
INSERTs, UPDATEs, DELETEs, but lets see.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Simon Riggs <simon@2ndquadrant.com> writes:
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
BTW, poking around in the grammar, I notice that MergeStmt did not
get added to RuleActionStmt. That seems like a rather serious
omission.
MERGE isn't a privilege, a trigger action or a policy action. Why
would it be in RuleActionStmt?
Because it seems likely that somebody would want to write a rule along
the lines of "ON UPDATE TO mytable DO INSTEAD MERGE ...".
Looking a little further ahead, one can easily envision somebody
wanting to do "ON MERGE TO mytable DO INSTEAD something". I'd be
prepared to give a pass on that for the present, partly because
it's not very clear what stuff from the original MERGE needs to be
available to the rule. But the other case seems pretty fundamental.
MERGE is not supposed to be a utility command IMO, it's supposed to
be DML, and that means it needs to work anywhere that you could
write e.g. UPDATE.
regards, tom lane
Simon Riggs <simon@2ndquadrant.com> writes:
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If the MERGE patch has broken this, I'm going to push back on that
and push back on it hard, because it probably means there are a
whole bunch of other raw-grammar-output-only node types that can
now get past the parser stage as well, as children of these nodes.
The answer to that is not to add a ton of new infrastructure, it's
"you did MERGE wrong".
MERGE contains multiple actions of Insert, Update and Delete and these
could be output in various debug modes. I'm not clear what meaning we
might attach to them if we looked since that differs from normal
INSERTs, UPDATEs, DELETEs, but lets see.
What I'm complaining about is that that's a very poorly designed parsetree
representation. It may not be the worst one I've ever seen, but it's
got claims in that direction. You're repurposing InsertStmt et al to
do something that's *not* an INSERT statement, but by chance happens
to share some (not all) of the same fields. This is bad because it
invites confusion, and then bugs of commission or omission (eg, assuming
that some particular processing has happened or not happened to subtrees
of that parse node). The most egregious way in which it's a bad idea
is that, as I said, InsertStmt doesn't even exist in post-parse-analysis
trees so far as the normal type of INSERT is concerned. This just opens
a whole batch of ways to screw up. We have some types of raw parse nodes
that are replaced entirely during parse analysis, and we have some others
where it's convenient to use the same node type before and after parse
analysis, but we don't have any that are one way in one context and the
other way in other contexts. And this is not the place to start.
I think you'd have been better off to fold all of those fields into
MergeAction, or perhaps make several variants of MergeAction.
regards, tom lane
On 4 April 2018 at 18:51, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Simon Riggs <simon@2ndquadrant.com> writes:
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If the MERGE patch has broken this, I'm going to push back on that
and push back on it hard, because it probably means there are a
whole bunch of other raw-grammar-output-only node types that can
now get past the parser stage as well, as children of these nodes.
The answer to that is not to add a ton of new infrastructure, it's
"you did MERGE wrong".MERGE contains multiple actions of Insert, Update and Delete and these
could be output in various debug modes. I'm not clear what meaning we
might attach to them if we looked since that differs from normal
INSERTs, UPDATEs, DELETEs, but lets see.What I'm complaining about is that that's a very poorly designed parsetree
representation. It may not be the worst one I've ever seen, but it's
got claims in that direction. You're repurposing InsertStmt et al to
do something that's *not* an INSERT statement, but by chance happens
to share some (not all) of the same fields. This is bad because it
invites confusion, and then bugs of commission or omission (eg, assuming
that some particular processing has happened or not happened to subtrees
of that parse node). The most egregious way in which it's a bad idea
is that, as I said, InsertStmt doesn't even exist in post-parse-analysis
trees so far as the normal type of INSERT is concerned. This just opens
a whole batch of ways to screw up. We have some types of raw parse nodes
that are replaced entirely during parse analysis, and we have some others
where it's convenient to use the same node type before and after parse
analysis, but we don't have any that are one way in one context and the
other way in other contexts. And this is not the place to start.I think you'd have been better off to fold all of those fields into
MergeAction, or perhaps make several variants of MergeAction.
OK, that can be changed, will check and report back tomorrow.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Wed, Apr 4, 2018 at 11:21 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Simon Riggs <simon@2ndquadrant.com> writes:
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If the MERGE patch has broken this, I'm going to push back on that
and push back on it hard, because it probably means there are a
whole bunch of other raw-grammar-output-only node types that can
now get past the parser stage as well, as children of these nodes.
The answer to that is not to add a ton of new infrastructure, it's
"you did MERGE wrong".MERGE contains multiple actions of Insert, Update and Delete and these
could be output in various debug modes. I'm not clear what meaning we
might attach to them if we looked since that differs from normal
INSERTs, UPDATEs, DELETEs, but lets see.What I'm complaining about is that that's a very poorly designed parsetree
representation. It may not be the worst one I've ever seen, but it's
got claims in that direction. You're repurposing InsertStmt et al to
do something that's *not* an INSERT statement, but by chance happens
to share some (not all) of the same fields. This is bad because it
invites confusion, and then bugs of commission or omission (eg, assuming
that some particular processing has happened or not happened to subtrees
of that parse node). The most egregious way in which it's a bad idea
is that, as I said, InsertStmt doesn't even exist in post-parse-analysis
trees so far as the normal type of INSERT is concerned. This just opens
a whole batch of ways to screw up. We have some types of raw parse nodes
that are replaced entirely during parse analysis, and we have some others
where it's convenient to use the same node type before and after parse
analysis, but we don't have any that are one way in one context and the
other way in other contexts. And this is not the place to start.I think you'd have been better off to fold all of those fields into
MergeAction, or perhaps make several variants of MergeAction.
Hi Tom,
Thanks for the review comments.
Attached patch refactors the grammar/parser side per your comments. We no
longer use InsertStmt/UpdateStmt/DeleteStmt/SelectStmt as part of
MergeAction. Instead we only collect the necessary information for running
the INSERT/UPDATE/DELETE actions. Speaking of MergeAction itself, I decided
to use a new parser-only node named MergeWhenClause and removed unnecessary
members from the MergeAction node which now gets to planner/executor.
Regarding the original report by Marina I suspect she may have turned
debug_print_parse=on while running regression. I could reproduce the
failures in the isolation tests by doing same. The attached patch however
passes all tests with the following additional GUCs. So I am more confident
that we should have got the outfuncs.c support ok.
debug_print_parse=on
debug_print_rewritten=on
debug_print_plan=on
Also, I am now running tests with -DCOPY_PARSE_PLAN_TREES
-DRAW_EXPRESSION_COVERAGE_TEST since the buildfarm had earlier uncovered
some issues with those flags. No problem there too.
This now also enforces single VALUES clause in the grammar itself instead
of doing that check at parse-analyse time. So that's a net improvement too.
Thanks,
Pavan
--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
0001-Separate-raw-parse-representation-from-rest.patchapplication/octet-stream; name=0001-Separate-raw-parse-representation-from-rest.patchDownload
From 6cc684498b05e499d17d336fc0e1d664c24b838a Mon Sep 17 00:00:00 2001
From: Pavan Deolasee <pavan.deolasee@gmail.com>
Date: Thu, 5 Apr 2018 09:14:24 +0530
Subject: [PATCH] Separate raw parse representation from rest
Per review comments from Tom Lane
---
src/backend/nodes/copyfuncs.c | 35 ++++++++++----
src/backend/nodes/equalfuncs.c | 28 ++++++++---
src/backend/nodes/nodeFuncs.c | 14 ++++--
src/backend/nodes/outfuncs.c | 27 ++++++++---
src/backend/nodes/readfuncs.c | 35 ++++++++++----
src/backend/parser/gram.y | 92 ++++++++++++++++--------------------
src/backend/parser/parse_merge.c | 86 +++++++++++++--------------------
src/backend/rewrite/rewriteHandler.c | 4 +-
src/include/nodes/nodes.h | 3 +-
src/include/nodes/parsenodes.h | 27 ++++++++---
src/test/regress/expected/merge.out | 4 +-
11 files changed, 207 insertions(+), 148 deletions(-)
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c3efca3c45..d2e4aa3c2f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2136,6 +2136,20 @@ _copyOnConflictExpr(const OnConflictExpr *from)
return newnode;
}
+static MergeAction *
+_copyMergeAction(const MergeAction *from)
+{
+ MergeAction *newnode = makeNode(MergeAction);
+
+ COPY_SCALAR_FIELD(matched);
+ COPY_SCALAR_FIELD(commandType);
+ COPY_SCALAR_FIELD(override);
+ COPY_NODE_FIELD(qual);
+ COPY_NODE_FIELD(targetList);
+
+ return newnode;
+}
+
/* ****************************************************************
* relation.h copy functions
*
@@ -3054,24 +3068,24 @@ _copyMergeStmt(const MergeStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(source_relation);
COPY_NODE_FIELD(join_condition);
- COPY_NODE_FIELD(mergeActionList);
+ COPY_NODE_FIELD(mergeWhenClauses);
COPY_NODE_FIELD(withClause);
return newnode;
}
-static MergeAction *
-_copyMergeAction(const MergeAction *from)
+static MergeWhenClause *
+_copyMergeWhenClause(const MergeWhenClause *from)
{
- MergeAction *newnode = makeNode(MergeAction);
+ MergeWhenClause *newnode = makeNode(MergeWhenClause);
COPY_SCALAR_FIELD(matched);
COPY_SCALAR_FIELD(commandType);
COPY_NODE_FIELD(condition);
- COPY_NODE_FIELD(qual);
- COPY_NODE_FIELD(stmt);
COPY_NODE_FIELD(targetList);
-
+ COPY_NODE_FIELD(cols);
+ COPY_NODE_FIELD(values);
+ COPY_SCALAR_FIELD(override);
return newnode;
}
@@ -5059,6 +5073,9 @@ copyObjectImpl(const void *from)
case T_OnConflictExpr:
retval = _copyOnConflictExpr(from);
break;
+ case T_MergeAction:
+ retval = _copyMergeAction(from);
+ break;
/*
* RELATION NODES
@@ -5140,8 +5157,8 @@ copyObjectImpl(const void *from)
case T_MergeStmt:
retval = _copyMergeStmt(from);
break;
- case T_MergeAction:
- retval = _copyMergeAction(from);
+ case T_MergeWhenClause:
+ retval = _copyMergeWhenClause(from);
break;
case T_SelectStmt:
retval = _copySelectStmt(from);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 45ceba2830..f2dd9035df 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -812,6 +812,18 @@ _equalOnConflictExpr(const OnConflictExpr *a, const OnConflictExpr *b)
return true;
}
+
+static bool
+_equalMergeAction(const MergeAction *a, const MergeAction *b)
+{
+ COMPARE_SCALAR_FIELD(matched);
+ COMPARE_SCALAR_FIELD(commandType);
+ COMPARE_SCALAR_FIELD(override);
+ COMPARE_NODE_FIELD(qual);
+ COMPARE_NODE_FIELD(targetList);
+
+ return true;
+}
/*
* Stuff from relation.h
*/
@@ -1050,21 +1062,22 @@ _equalMergeStmt(const MergeStmt *a, const MergeStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(source_relation);
COMPARE_NODE_FIELD(join_condition);
- COMPARE_NODE_FIELD(mergeActionList);
+ COMPARE_NODE_FIELD(mergeWhenClauses);
COMPARE_NODE_FIELD(withClause);
return true;
}
static bool
-_equalMergeAction(const MergeAction *a, const MergeAction *b)
+_equalMergeWhenClause(const MergeWhenClause *a, const MergeWhenClause *b)
{
COMPARE_SCALAR_FIELD(matched);
COMPARE_SCALAR_FIELD(commandType);
COMPARE_NODE_FIELD(condition);
- COMPARE_NODE_FIELD(qual);
- COMPARE_NODE_FIELD(stmt);
COMPARE_NODE_FIELD(targetList);
+ COMPARE_NODE_FIELD(cols);
+ COMPARE_NODE_FIELD(values);
+ COMPARE_SCALAR_FIELD(override);
return true;
}
@@ -3192,6 +3205,9 @@ equal(const void *a, const void *b)
case T_OnConflictExpr:
retval = _equalOnConflictExpr(a, b);
break;
+ case T_MergeAction:
+ retval = _equalMergeAction(a, b);
+ break;
case T_JoinExpr:
retval = _equalJoinExpr(a, b);
break;
@@ -3263,8 +3279,8 @@ equal(const void *a, const void *b)
case T_MergeStmt:
retval = _equalMergeStmt(a, b);
break;
- case T_MergeAction:
- retval = _equalMergeAction(a, b);
+ case T_MergeWhenClause:
+ retval = _equalMergeWhenClause(a, b);
break;
case T_SelectStmt:
retval = _equalSelectStmt(a, b);
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 4157e7eb9a..f2f8227eb2 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -3444,19 +3444,23 @@ raw_expression_tree_walker(Node *node,
return true;
if (walker(stmt->join_condition, context))
return true;
- if (walker(stmt->mergeActionList, context))
+ if (walker(stmt->mergeWhenClauses, context))
return true;
if (walker(stmt->withClause, context))
return true;
}
break;
- case T_MergeAction:
+ case T_MergeWhenClause:
{
- MergeAction *action = (MergeAction *) node;
+ MergeWhenClause *mergeWhenClause = (MergeWhenClause *) node;
- if (walker(action->targetList, context))
+ if (walker(mergeWhenClause->condition, context))
return true;
- if (walker(action->qual, context))
+ if (walker(mergeWhenClause->targetList, context))
+ return true;
+ if (walker(mergeWhenClause->cols, context))
+ return true;
+ if (walker(mergeWhenClause->values, context))
return true;
}
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c8d962670e..a6a1c16164 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -396,16 +396,17 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
}
static void
-_outMergeAction(StringInfo str, const MergeAction *node)
+_outMergeWhenClause(StringInfo str, const MergeWhenClause *node)
{
- WRITE_NODE_TYPE("MERGEACTION");
+ WRITE_NODE_TYPE("MERGEWHENCLAUSE");
WRITE_BOOL_FIELD(matched);
WRITE_ENUM_FIELD(commandType, CmdType);
WRITE_NODE_FIELD(condition);
- WRITE_NODE_FIELD(qual);
- WRITE_NODE_FIELD(stmt);
WRITE_NODE_FIELD(targetList);
+ WRITE_NODE_FIELD(cols);
+ WRITE_NODE_FIELD(values);
+ WRITE_ENUM_FIELD(override, OverridingKind);
}
static void
@@ -1724,6 +1725,17 @@ _outOnConflictExpr(StringInfo str, const OnConflictExpr *node)
WRITE_NODE_FIELD(exclRelTlist);
}
+static void
+_outMergeAction(StringInfo str, const MergeAction *node)
+{
+ WRITE_NODE_TYPE("MERGEACTION");
+
+ WRITE_BOOL_FIELD(matched);
+ WRITE_ENUM_FIELD(commandType, CmdType);
+ WRITE_NODE_FIELD(qual);
+ WRITE_NODE_FIELD(targetList);
+}
+
/*****************************************************************************
*
* Stuff from relation.h.
@@ -3679,8 +3691,8 @@ outNode(StringInfo str, const void *obj)
case T_ModifyTable:
_outModifyTable(str, obj);
break;
- case T_MergeAction:
- _outMergeAction(str, obj);
+ case T_MergeWhenClause:
+ _outMergeWhenClause(str, obj);
break;
case T_Append:
_outAppend(str, obj);
@@ -3958,6 +3970,9 @@ outNode(StringInfo str, const void *obj)
case T_OnConflictExpr:
_outOnConflictExpr(str, obj);
break;
+ case T_MergeAction:
+ _outMergeAction(str, obj);
+ break;
case T_Path:
_outPath(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 4518fa0cdb..37e3568595 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1331,6 +1331,22 @@ _readOnConflictExpr(void)
READ_DONE();
}
+/*
+ * _readMergeAction
+ */
+static MergeAction *
+_readMergeAction(void)
+{
+ READ_LOCALS(MergeAction);
+
+ READ_BOOL_FIELD(matched);
+ READ_ENUM_FIELD(commandType, CmdType);
+ READ_NODE_FIELD(qual);
+ READ_NODE_FIELD(targetList);
+
+ READ_DONE();
+}
+
/*
* Stuff from parsenodes.h.
*/
@@ -1602,19 +1618,20 @@ _readModifyTable(void)
}
/*
- * _readMergeAction
+ * _readMergeWhenClause
*/
-static MergeAction *
-_readMergeAction(void)
+static MergeWhenClause *
+_readMergeWhenClause(void)
{
- READ_LOCALS(MergeAction);
+ READ_LOCALS(MergeWhenClause);
READ_BOOL_FIELD(matched);
READ_ENUM_FIELD(commandType, CmdType);
READ_NODE_FIELD(condition);
- READ_NODE_FIELD(qual);
- READ_NODE_FIELD(stmt);
READ_NODE_FIELD(targetList);
+ READ_NODE_FIELD(cols);
+ READ_NODE_FIELD(values);
+ READ_ENUM_FIELD(override, OverridingKind);
READ_DONE();
}
@@ -2596,6 +2613,8 @@ parseNodeString(void)
return_value = _readFromExpr();
else if (MATCH("ONCONFLICTEXPR", 14))
return_value = _readOnConflictExpr();
+ else if (MATCH("MERGEACTION", 11))
+ return_value = _readMergeAction();
else if (MATCH("RTE", 3))
return_value = _readRangeTblEntry();
else if (MATCH("RANGETBLFUNCTION", 16))
@@ -2618,8 +2637,8 @@ parseNodeString(void)
return_value = _readProjectSet();
else if (MATCH("MODIFYTABLE", 11))
return_value = _readModifyTable();
- else if (MATCH("MERGEACTION", 11))
- return_value = _readMergeAction();
+ else if (MATCH("MERGEWHENCLAUSE", 15))
+ return_value = _readMergeWhenClause();
else if (MATCH("APPEND", 6))
return_value = _readAppend();
else if (MATCH("MERGEAPPEND", 11))
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1592b58bb4..177906e083 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -241,6 +241,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
PartitionSpec *partspec;
PartitionBoundSpec *partboundspec;
RoleSpec *rolespec;
+ MergeWhenClause *mergewhen;
}
%type <node> stmt schema_stmt
@@ -400,6 +401,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
TriggerTransitions TriggerReferencing
publication_name_list
vacuum_relation_list opt_vacuum_relation_list
+ merge_values_clause
%type <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
@@ -460,6 +462,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <istmt> insert_rest
%type <infer> opt_conf_expr
%type <onconflict> opt_on_conflict
+%type <mergewhen> merge_insert merge_update merge_delete
%type <vsetstmt> generic_set set_rest set_rest_more generic_reset reset_rest
SetResetClause FunctionSetResetClause
@@ -587,7 +590,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> merge_when_clause opt_merge_when_and_condition
%type <list> merge_when_list
-%type <node> merge_update merge_delete merge_insert
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
@@ -11116,7 +11118,7 @@ MergeStmt:
m->relation = $4;
m->source_relation = $6;
m->join_condition = $8;
- m->mergeActionList = $9;
+ m->mergeWhenClauses = $9;
$$ = (Node *)m;
}
@@ -11131,45 +11133,37 @@ merge_when_list:
merge_when_clause:
WHEN MATCHED opt_merge_when_and_condition THEN merge_update
{
- MergeAction *m = makeNode(MergeAction);
+ $5->matched = true;
+ $5->commandType = CMD_UPDATE;
+ $5->condition = $3;
- m->matched = true;
- m->commandType = CMD_UPDATE;
- m->condition = $3;
- m->stmt = $5;
-
- $$ = (Node *)m;
+ $$ = (Node *) $5;
}
| WHEN MATCHED opt_merge_when_and_condition THEN merge_delete
{
- MergeAction *m = makeNode(MergeAction);
+ MergeWhenClause *m = makeNode(MergeWhenClause);
m->matched = true;
m->commandType = CMD_DELETE;
m->condition = $3;
- m->stmt = $5;
$$ = (Node *)m;
}
| WHEN NOT MATCHED opt_merge_when_and_condition THEN merge_insert
{
- MergeAction *m = makeNode(MergeAction);
+ $6->matched = false;
+ $6->commandType = CMD_INSERT;
+ $6->condition = $4;
- m->matched = false;
- m->commandType = CMD_INSERT;
- m->condition = $4;
- m->stmt = $6;
-
- $$ = (Node *)m;
+ $$ = (Node *) $6;
}
| WHEN NOT MATCHED opt_merge_when_and_condition THEN DO NOTHING
{
- MergeAction *m = makeNode(MergeAction);
+ MergeWhenClause *m = makeNode(MergeWhenClause);
m->matched = false;
m->commandType = CMD_NOTHING;
m->condition = $4;
- m->stmt = NULL;
$$ = (Node *)m;
}
@@ -11181,65 +11175,63 @@ opt_merge_when_and_condition:
;
merge_delete:
- DELETE_P
- {
- DeleteStmt *n = makeNode(DeleteStmt);
- $$ = (Node *)n;
- }
+ DELETE_P { $$ = NULL; }
;
merge_update:
UPDATE SET set_clause_list
{
- UpdateStmt *n = makeNode(UpdateStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->targetList = $3;
- $$ = (Node *)n;
+ $$ = n;
}
;
merge_insert:
- INSERT values_clause
+ INSERT merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
- n->selectStmt = $2;
-
- $$ = (Node *)n;
+ n->values = $2;
+ $$ = n;
}
- | INSERT OVERRIDING override_kind VALUE_P values_clause
+ | INSERT OVERRIDING override_kind VALUE_P merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
n->override = $3;
- n->selectStmt = $5;
-
- $$ = (Node *)n;
+ n->values = $5;
+ $$ = n;
}
- | INSERT '(' insert_column_list ')' values_clause
+ | INSERT '(' insert_column_list ')' merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = $3;
- n->selectStmt = $5;
-
- $$ = (Node *)n;
+ n->values = $5;
+ $$ = n;
}
- | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P values_clause
+ | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = $3;
n->override = $6;
- n->selectStmt = $8;
-
- $$ = (Node *)n;
+ n->values = $8;
+ $$ = n;
}
| INSERT DEFAULT VALUES
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
- n->selectStmt = NULL;
+ n->values = NIL;
+ $$ = n;
+ }
+ ;
- $$ = (Node *)n;
+merge_values_clause:
+ VALUES '(' expr_list ')'
+ {
+ $$ = $3;
}
;
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index eb4c615ce1..722cb23b86 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -33,8 +33,8 @@
static int transformMergeJoinClause(ParseState *pstate, Node *merge,
List **mergeSourceTargetList);
-static void setNamespaceForMergeAction(ParseState *pstate,
- MergeAction *action);
+static void setNamespaceForMergeWhen(ParseState *pstate,
+ MergeWhenClause *mergeWhenClause);
static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte,
bool rel_visible,
bool cols_visible);
@@ -138,7 +138,7 @@ transformMergeJoinClause(ParseState *pstate, Node *merge,
* that columns can be referenced unqualified from these relations.
*/
static void
-setNamespaceForMergeAction(ParseState *pstate, MergeAction *action)
+setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause)
{
RangeTblEntry *targetRelRTE,
*sourceRelRTE;
@@ -152,7 +152,7 @@ setNamespaceForMergeAction(ParseState *pstate, MergeAction *action)
*/
sourceRelRTE = rt_fetch(list_length(pstate->p_rtable) - 1, pstate->p_rtable);
- switch (action->commandType)
+ switch (mergeWhenClause->commandType)
{
case CMD_INSERT:
@@ -198,6 +198,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
bool is_terminal[2];
JoinExpr *joinexpr;
RangeTblEntry *resultRelRTE, *mergeRelRTE;
+ List *mergeActionList;
/* There can't be any outer WITH to worry about */
Assert(pstate->p_ctenamespace == NIL);
@@ -222,43 +223,18 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
*/
is_terminal[0] = false;
is_terminal[1] = false;
- foreach(l, stmt->mergeActionList)
+ foreach(l, stmt->mergeWhenClauses)
{
- MergeAction *action = (MergeAction *) lfirst(l);
- int when_type = (action->matched ? 0 : 1);
+ MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
+ int when_type = (mergeWhenClause->matched ? 0 : 1);
/*
* Collect action types so we can check Target permissions
*/
- switch (action->commandType)
+ switch (mergeWhenClause->commandType)
{
case CMD_INSERT:
- {
- InsertStmt *istmt = (InsertStmt *) action->stmt;
- SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt;
-
- /*
- * The grammar allows attaching ORDER BY, LIMIT, FOR
- * UPDATE, or WITH to a VALUES clause and also multiple
- * VALUES clauses. If we have any of those, ERROR.
- */
- if (selectStmt && (selectStmt->valuesLists == NIL ||
- selectStmt->sortClause != NIL ||
- selectStmt->limitOffset != NULL ||
- selectStmt->limitCount != NULL ||
- selectStmt->lockingClause != NIL ||
- selectStmt->withClause != NULL))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("SELECT not allowed in MERGE INSERT statement")));
-
- if (selectStmt && list_length(selectStmt->valuesLists) > 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("Multiple VALUES clauses not allowed in MERGE INSERT statement")));
-
- targetPerms |= ACL_INSERT;
- }
+ targetPerms |= ACL_INSERT;
break;
case CMD_UPDATE:
targetPerms |= ACL_UPDATE;
@@ -275,7 +251,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
/*
* Check for unreachable WHEN clauses
*/
- if (action->condition == NULL)
+ if (mergeWhenClause->condition == NULL)
is_terminal[when_type] = true;
else if (is_terminal[when_type])
ereport(ERROR,
@@ -461,15 +437,20 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* both of those already have RTEs. There is nothing like the EXCLUDED
* pseudo-relation for INSERT ON CONFLICT.
*/
- foreach(l, stmt->mergeActionList)
+ mergeActionList = NIL;
+ foreach(l, stmt->mergeWhenClauses)
{
- MergeAction *action = (MergeAction *) lfirst(l);
+ MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
+ MergeAction *action = makeNode(MergeAction);
+
+ action->commandType = mergeWhenClause->commandType;
+ action->matched = mergeWhenClause->matched;
/*
* Set namespace for the specific action. This must be done before
* analyzing the WHEN quals and the action targetlisst.
*/
- setNamespaceForMergeAction(pstate, action);
+ setNamespaceForMergeWhen(pstate, mergeWhenClause);
/*
* Transform the when condition.
@@ -478,7 +459,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* are evaluated separately during execution to decide which of the
* WHEN MATCHED or WHEN NOT MATCHED actions to execute.
*/
- action->qual = transformWhereClause(pstate, action->condition,
+ action->qual = transformWhereClause(pstate, mergeWhenClause->condition,
EXPR_KIND_MERGE_WHEN_AND, "WHEN");
/*
@@ -488,8 +469,6 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
{
case CMD_INSERT:
{
- InsertStmt *istmt = (InsertStmt *) action->stmt;
- SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt;
List *exprList = NIL;
ListCell *lc;
RangeTblEntry *rte;
@@ -500,13 +479,17 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
pstate->p_is_insert = true;
- icolumns = checkInsertTargets(pstate, istmt->cols, &attrnos);
+ icolumns = checkInsertTargets(pstate,
+ mergeWhenClause->cols,
+ &attrnos);
Assert(list_length(icolumns) == list_length(attrnos));
+ action->override = mergeWhenClause->override;
+
/*
* Handle INSERT much like in transformInsertStmt
*/
- if (selectStmt == NULL)
+ if (mergeWhenClause->values == NIL)
{
/*
* We have INSERT ... DEFAULT VALUES. We can handle
@@ -525,23 +508,19 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* as the Query's targetlist, with no VALUES RTE. So
* it works just like a SELECT without any FROM.
*/
- List *valuesLists = selectStmt->valuesLists;
-
- Assert(list_length(valuesLists) == 1);
- Assert(selectStmt->intoClause == NULL);
/*
* Do basic expression transformation (same as a ROW()
* expr, but allow SetToDefault at top level)
*/
exprList = transformExpressionList(pstate,
- (List *) linitial(valuesLists),
+ mergeWhenClause->values,
EXPR_KIND_VALUES_SINGLE,
true);
/* Prepare row for assignment to target table */
exprList = transformInsertRow(pstate, exprList,
- istmt->cols,
+ mergeWhenClause->cols,
icolumns, attrnos,
false);
}
@@ -580,10 +559,9 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
break;
case CMD_UPDATE:
{
- UpdateStmt *ustmt = (UpdateStmt *) action->stmt;
-
pstate->p_is_insert = false;
- action->targetList = transformUpdateTargetList(pstate, ustmt->targetList);
+ action->targetList = transformUpdateTargetList(pstate,
+ mergeWhenClause->targetList);
}
break;
case CMD_DELETE:
@@ -595,9 +573,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
default:
elog(ERROR, "unknown action in MERGE WHEN clause");
}
+
+ mergeActionList = lappend(mergeActionList, action);
}
- qry->mergeActionList = stmt->mergeActionList;
+ qry->mergeActionList = mergeActionList;
/* XXX maybe later */
qry->returningList = NULL;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 98239f569a..cb4bcd58d1 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -3417,12 +3417,10 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
break;
case CMD_INSERT:
{
- InsertStmt *istmt = (InsertStmt *) action->stmt;
-
action->targetList =
rewriteTargetListIU(action->targetList,
action->commandType,
- istmt->override,
+ action->override,
rt_entry_relation,
parsetree->resultRelation,
NULL);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fce48026b6..b1e3d53f78 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -269,6 +269,7 @@ typedef enum NodeTag
T_RollupData,
T_GroupingSetData,
T_StatisticExtInfo,
+ T_MergeAction,
/*
* TAGS FOR MEMORY NODES (memnodes.h)
@@ -310,7 +311,6 @@ typedef enum NodeTag
T_DeleteStmt,
T_UpdateStmt,
T_MergeStmt,
- T_MergeAction,
T_SelectStmt,
T_AlterTableStmt,
T_AlterTableCmd,
@@ -475,6 +475,7 @@ typedef enum NodeTag
T_PartitionRangeDatum,
T_PartitionCmd,
T_VacuumRelation,
+ T_MergeWhenClause,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 699fa77bc7..06abb70e94 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1518,19 +1518,34 @@ typedef struct MergeStmt
RangeVar *relation; /* target relation to merge into */
Node *source_relation; /* source relation */
Node *join_condition; /* join condition between source and target */
- List *mergeActionList; /* list of MergeAction(s) */
+ List *mergeWhenClauses; /* list of MergeWhenClause(es) */
WithClause *withClause; /* WITH clause */
} MergeStmt;
-typedef struct MergeAction
+typedef struct MergeWhenClause
{
NodeTag type;
bool matched; /* true=MATCHED, false=NOT MATCHED */
- Node *condition; /* WHEN AND conditions (raw parser) */
- Node *qual; /* transformed WHEN AND conditions */
CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */
- Node *stmt; /* T_UpdateStmt etc */
- List *targetList; /* the target list (of ResTarget) */
+ Node *condition; /* WHEN AND conditions (raw parser) */
+ List *targetList; /* INSERT/UPDATE targetlist */
+ /* the following members are only useful for INSERT action */
+ List *cols; /* optional: names of the target columns */
+ List *values; /* VALUES to INSERT, or NULL */
+ OverridingKind override; /* OVERRIDING clause */
+} MergeWhenClause;
+
+/*
+ * WHEN [NOT] MATCHED THEN action info
+ */
+typedef struct MergeAction
+{
+ NodeTag type;
+ bool matched; /* true=MATCHED, false=NOT MATCHED */
+ OverridingKind override; /* OVERRIDING clause */
+ Node *qual; /* transformed WHEN AND conditions */
+ CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */
+ List *targetList; /* the target list (of ResTarget) */
} MergeAction;
/* ----------------------
diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out
index 389eeedf28..03e30ef559 100644
--- a/src/test/regress/expected/merge.out
+++ b/src/test/regress/expected/merge.out
@@ -90,7 +90,9 @@ USING source AS s
ON t.tid = s.sid
WHEN NOT MATCHED THEN
INSERT VALUES (1,1), (2,2);
-ERROR: Multiple VALUES clauses not allowed in MERGE INSERT statement
+ERROR: syntax error at or near ","
+LINE 5: INSERT VALUES (1,1), (2,2);
+ ^
;
-- SELECT query for INSERT
MERGE INTO target t
--
2.14.3 (Apple Git-98)
On 5 April 2018 at 11:31, Pavan Deolasee <pavan.deolasee@gmail.com> wrote:
Attached patch refactors the grammar/parser side per your comments. We no
longer use InsertStmt/UpdateStmt/DeleteStmt/SelectStmt as part of
MergeAction. Instead we only collect the necessary information for running
the INSERT/UPDATE/DELETE actions. Speaking of MergeAction itself, I decided
to use a new parser-only node named MergeWhenClause and removed unnecessary
members from the MergeAction node which now gets to planner/executor.
That looks good to me. Simply separation of duty.
Regarding the original report by Marina I suspect she may have turned
debug_print_parse=on while running regression. I could reproduce the
failures in the isolation tests by doing same. The attached patch however
passes all tests with the following additional GUCs. So I am more confident
that we should have got the outfuncs.c support ok.debug_print_parse=on
debug_print_rewritten=on
debug_print_plan=onAlso, I am now running tests with -DCOPY_PARSE_PLAN_TREES
-DRAW_EXPRESSION_COVERAGE_TEST since the buildfarm had earlier uncovered
some issues with those flags. No problem there too.
OK, so $OP fixed.
This now also enforces single VALUES clause in the grammar itself instead of
doing that check at parse-analyse time. So that's a net improvement too.
OK, that's good. I've updated the docs to show this restriction correctly.
I'll commit this tomorrow morning unless further comments or edits.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 4 April 2018 at 18:08, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Simon Riggs <simon@2ndquadrant.com> writes:
On 4 April 2018 at 17:19, Tom Lane <tgl@sss.pgh.pa.us> wrote:
BTW, poking around in the grammar, I notice that MergeStmt did not
get added to RuleActionStmt. That seems like a rather serious
omission.MERGE isn't a privilege, a trigger action or a policy action. Why
would it be in RuleActionStmt?Because it seems likely that somebody would want to write a rule along
the lines of "ON UPDATE TO mytable DO INSTEAD MERGE ...".Looking a little further ahead, one can easily envision somebody
wanting to do "ON MERGE TO mytable DO INSTEAD something". I'd be
prepared to give a pass on that for the present, partly because
it's not very clear what stuff from the original MERGE needs to be
available to the rule. But the other case seems pretty fundamental.
MERGE is not supposed to be a utility command IMO, it's supposed to
be DML, and that means it needs to work anywhere that you could
write e.g. UPDATE.
MERGE is important because it is implemented by other databases,
making it an application portability issue and an important feature
for PostgreSQL adoption with real users.
Enhancing Rules to allow interoperation with MERGE doesn't fall into
that same category, so I don't see it needs to work anywhere you can
write UPDATE - that certainly isn't the case with triggers, row level
security policies or privileges.
With that said, we can still discuss it to see if it's possible.
... ON UPDATE TO foo DO INSTEAD MERGE...
would look like this
MERGE INTO foo USING (what?) ON (join condition) WHEN MATCHED THEN UPDATE
which if we managed to achieve that is simply a much poorer version of
UPDATE, since MERGE with a single WHEN clause is semantically similar
but higher overhead than a single DML operation. So if we implemented
it you wouldn't ever use it.
Achieving the marriage between rules and merge is made complex in the
source and join condition. MERGE is different from other DML in that
it always has two tables, so is hard to see how that work with rules
on just one table.
So that leaves the thought of could we do a more complex version with
some kind of exploitation of multi-DML features? Well possibly, but I
think its months of work. Adding this requested feature doesn't
enhance the original goal of application portability and standards
compliance, so there's no way to know when you've got it right.
Without a scope or a spec it would be difficult to see where that
would go.
I would be most glad to be proved wrong to allow us to implement
something here and I have no objection to others adding that, though
it seems clear that can't happen in this release.
For this release, in discussion with Stephen and others at the Dev
Meeting in Brussels the addition of features for RLS and partitioning
were decided as the priorities for MERGE ahead of other items. This
item wasn't mentioned by anyone before and not at all by any users
I've spoken to.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
I'm sorry I was very busy with the patch for pgbench..
On 04-04-2018 19:19, Tom Lane wrote:
...
BTW, poking around in the grammar, I notice that MergeStmt did not
get added to RuleActionStmt. That seems like a rather serious
omission.
Thank you very much! I will try to do this, if you do not mind, of
course..
--
Marina Polyakova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Sorry for this late reply, I was very busy with the patch for pgbench..
On 04-04-2018 20:07, Simon Riggs wrote:
...
Which debug mode are we talking about, please?
-d 5
--
Marina Polyakova
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company