diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2022-09-27 10:44:42 +0200 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2022-09-27 10:44:42 +0200 |
commit | 72abf03b6491a8df880e1fea45798797bcc86c47 (patch) | |
tree | 92cd81d3c7ad1ceb657ff69f23811d4634649333 | |
parent | d1f95fa2476bcf427a3e3677f67ceee26552e23e (diff) | |
download | postgresql-72abf03b6491a8df880e1fea45798797bcc86c47.tar.gz postgresql-72abf03b6491a8df880e1fea45798797bcc86c47.zip |
Fix pg_stat_statements for MERGE
We weren't jumbling the merge action list, so wildly different commands
would be considered to use the same query ID. Add that, mention it in
the docs, and some test lines.
Backpatch to 15.
Author: Tatsu <bt22nakamorit@oss.nttdata.com>
Reviewed-by: Julien Rouhaud <rjuju123@gmail.com>
Discussion: https://postgr.es/m/d87e391694db75a038abc3b2597828e8@oss.nttdata.com
-rw-r--r-- | contrib/pg_stat_statements/expected/pg_stat_statements.out | 41 | ||||
-rw-r--r-- | contrib/pg_stat_statements/sql/pg_stat_statements.sql | 22 | ||||
-rw-r--r-- | doc/src/sgml/pgstatstatements.sgml | 4 | ||||
-rw-r--r-- | src/backend/nodes/nodeFuncs.c | 4 | ||||
-rw-r--r-- | src/backend/utils/misc/queryjumble.c | 11 |
5 files changed, 77 insertions, 5 deletions
diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out index 8f7f93172a2..49deebdfcac 100644 --- a/contrib/pg_stat_statements/expected/pg_stat_statements.out +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -222,12 +222,51 @@ SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5); 3 | c (8 rows) +-- MERGE +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = test.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL); +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0); +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (a) VALUES (0); +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN DELETE; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN DO NOTHING; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN NOT MATCHED THEN DO NOTHING; SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; query | calls | rows ------------------------------------------------------------------------------+-------+------ DELETE FROM test WHERE a > $1 | 1 | 1 INSERT INTO test (a, b) VALUES ($1, $2), ($3, $4), ($5, $6) | 1 | 3 INSERT INTO test VALUES(generate_series($1, $2), $3) | 1 | 10 + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6 + WHEN MATCHED AND length(st.b) > $2 THEN UPDATE SET b = test.b || st.a::text | | + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6 + WHEN MATCHED THEN DELETE | | + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 0 + WHEN MATCHED THEN DO NOTHING | | + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6 + WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text | | + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 6 + WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text | | + MERGE INTO test USING test st ON (st.a = test.a AND st.a >= $1) +| 1 | 0 + WHEN NOT MATCHED THEN DO NOTHING | | + MERGE INTO test USING test st ON (st.a = test.a) +| 1 | 0 + WHEN NOT MATCHED THEN INSERT (a) VALUES ($1) | | + MERGE INTO test USING test st ON (st.a = test.a) +| 2 | 0 + WHEN NOT MATCHED THEN INSERT (a, b) VALUES ($1, $2) | | + MERGE INTO test USING test st ON (st.a = test.a) +| 1 | 0 + WHEN NOT MATCHED THEN INSERT (b, a) VALUES ($1, $2) | | SELECT * FROM test ORDER BY a | 1 | 12 SELECT * FROM test WHERE a > $1 ORDER BY a | 2 | 4 SELECT * FROM test WHERE a IN ($1, $2, $3, $4, $5) | 1 | 8 @@ -235,7 +274,7 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" | 0 | 0 UPDATE test SET b = $1 WHERE a = $2 | 6 | 6 UPDATE test SET b = $1 WHERE a > $2 | 1 | 3 -(10 rows) +(19 rows) -- -- INSERT, UPDATE, DELETE on test table to validate WAL generation metrics diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql index dffd2c8c187..8828e74e894 100644 --- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -100,6 +100,28 @@ SELECT * FROM test ORDER BY a; -- SELECT with IN clause SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5); +-- MERGE +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN UPDATE SET b = st.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN UPDATE SET b = test.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED AND length(st.b) > 1 THEN UPDATE SET b = test.b || st.a::text; +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, NULL); +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT VALUES (0, NULL); -- same as above +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (b, a) VALUES (NULL, 0); +MERGE INTO test USING test st ON (st.a = test.a) + WHEN NOT MATCHED THEN INSERT (a) VALUES (0); +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN DELETE; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN MATCHED THEN DO NOTHING; +MERGE INTO test USING test st ON (st.a = test.a AND st.a >= 4) + WHEN NOT MATCHED THEN DO NOTHING; + SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; -- diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml index ecf6cd6bf3e..ea90365c7f2 100644 --- a/doc/src/sgml/pgstatstatements.sgml +++ b/doc/src/sgml/pgstatstatements.sgml @@ -487,7 +487,7 @@ <para> Plannable queries (that is, <command>SELECT</command>, <command>INSERT</command>, - <command>UPDATE</command>, and <command>DELETE</command>) are combined into a single + <command>UPDATE</command>, <command>DELETE</command>, and <command>MERGE</command>) are combined into a single <structname>pg_stat_statements</structname> entry whenever they have identical query structures according to an internal hash calculation. Typically, two queries will be considered the same for this purpose if they are @@ -783,7 +783,7 @@ <varname>pg_stat_statements.track_utility</varname> controls whether utility commands are tracked by the module. Utility commands are all those other than <command>SELECT</command>, <command>INSERT</command>, - <command>UPDATE</command> and <command>DELETE</command>. + <command>UPDATE</command>, <command>DELETE</command>, and <command>MERGE</command>. The default value is <literal>on</literal>. Only superusers can change this setting. </para> diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 3bac350bf50..6029da3ee1f 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -2266,10 +2266,10 @@ expression_tree_walker(Node *node, { MergeAction *action = (MergeAction *) node; - if (walker(action->targetList, context)) - return true; if (walker(action->qual, context)) return true; + if (walker(action->targetList, context)) + return true; } break; case T_PartitionPruneStepOp: diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c index a67487e5fe8..1224bb6c660 100644 --- a/src/backend/utils/misc/queryjumble.c +++ b/src/backend/utils/misc/queryjumble.c @@ -247,6 +247,7 @@ JumbleQueryInternal(JumbleState *jstate, Query *query) JumbleExpr(jstate, (Node *) query->cteList); JumbleRangeTable(jstate, query->rtable); JumbleExpr(jstate, (Node *) query->jointree); + JumbleExpr(jstate, (Node *) query->mergeActionList); JumbleExpr(jstate, (Node *) query->targetList); JumbleExpr(jstate, (Node *) query->onConflict); JumbleExpr(jstate, (Node *) query->returningList); @@ -737,6 +738,16 @@ JumbleExpr(JumbleState *jstate, Node *node) JumbleExpr(jstate, (Node *) conf->exclRelTlist); } break; + case T_MergeAction: + { + MergeAction *mergeaction = (MergeAction *) node; + + APP_JUMB(mergeaction->matched); + APP_JUMB(mergeaction->commandType); + JumbleExpr(jstate, mergeaction->qual); + JumbleExpr(jstate, (Node *) mergeaction->targetList); + } + break; case T_List: foreach(temp, (List *) node) { |