diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out index c759763be2..6787ec1efd 100644 --- a/contrib/pg_stat_statements/expected/pg_stat_statements.out +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -354,6 +354,93 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; SELECT pg_stat_statements_reset() | 1 | 1 (5 rows) +-- +-- queries with locking clauses +-- +CREATE TABLE pgss_a (id integer PRIMARY KEY); +CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a); +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +-- control query +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id; + id | id | a_id +----+----+------ +(0 rows) + +-- test range tables +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE" + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a; + id | id | a_id +----+----+------ +(0 rows) + +-- test strengths +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE; + id | id | a_id +----+----+------ +(0 rows) + +-- test wait policies +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT; + id | id | a_id +----+----+------ +(0 rows) + +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED; + id | id | a_id +----+----+------ +(0 rows) + +SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"; + calls | query +-------+------------------------------------------------------------------------------------------ + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE + 2 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a + 1 | SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED + 1 | SELECT pg_stat_statements_reset() +(11 rows) + +DROP TABLE pgss_a, pgss_b CASCADE; -- -- utility commands -- diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 00cae04eea..ba57628f6f 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -333,6 +333,7 @@ static void AppendJumble(pgssJumbleState *jstate, const unsigned char *item, Size size); static void JumbleQuery(pgssJumbleState *jstate, Query *query); static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable); +static void JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks); static void JumbleExpr(pgssJumbleState *jstate, Node *node); static void RecordConstLocation(pgssJumbleState *jstate, int location); static char *generate_normalized_query(pgssJumbleState *jstate, const char *query, @@ -2430,7 +2431,7 @@ JumbleQuery(pgssJumbleState *jstate, Query *query) JumbleExpr(jstate, (Node *) query->sortClause); JumbleExpr(jstate, query->limitOffset); JumbleExpr(jstate, query->limitCount); - /* we ignore rowMarks */ + JumbleRowMarks(jstate, query->rowMarks); JumbleExpr(jstate, query->setOperations); } @@ -2489,6 +2490,26 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable) } } +/* + * Jumble a rowMarks list + */ +static void +JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks) +{ + ListCell *lc; + + foreach(lc, rowMarks) + { + RowMarkClause *rowmark = lfirst_node(RowMarkClause, lc); + if (!rowmark->pushedDown) + { + APP_JUMB(rowmark->rti); + APP_JUMB(rowmark->strength); + APP_JUMB(rowmark->waitPolicy); + } + } +} + /* * Jumble an expression tree * diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql index aef890d893..8b527070d4 100644 --- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -177,6 +177,37 @@ SELECT PLUS_ONE(1); SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C"; +-- +-- queries with locking clauses +-- +CREATE TABLE pgss_a (id integer PRIMARY KEY); +CREATE TABLE pgss_b (id integer PRIMARY KEY, a_id integer REFERENCES pgss_a); + +SELECT pg_stat_statements_reset(); + +-- control query +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id; + +-- test range tables +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_a, pgss_b; -- matches plain "FOR UPDATE" +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE OF pgss_b, pgss_a; + +-- test strengths +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR NO KEY UPDATE; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR SHARE; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR KEY SHARE; + +-- test wait policies +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE NOWAIT; +SELECT * FROM pgss_a JOIN pgss_b ON pgss_b.a_id = pgss_a.id FOR UPDATE SKIP LOCKED; + +SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C"; + +DROP TABLE pgss_a, pgss_b CASCADE; + -- -- utility commands --