Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c2da1a5

Browse files
author
Álvaro Herrera
committed
Make query jumbling also squash PARAM_EXTERN params
Commit 62d712e made query jumbling squash lists of Consts as a single element, but there's no reason not to treat PARAM_EXTERN parameters the same. For these purposes, these values are indeed constants for any particular execution of a query. In particular, this should make list squashing more useful for applications using extended query protocol, which would use parameters extensively. A complication arises: if a query has both external parameters and squashable lists, then the parameter number used as placeholder for the squashed list might be inconsistent with regards to the parameter numbers used by the query literal. To reduce the surprise factor, all parameters are renumbered starting from 1 in that case. Author: Sami Imseih <[email protected]> Author: Dmitry Dolgov <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Discussion: https://postgr.es/m/CAA5RZ0tRXoPG2y6bMgBCWNDt0Tn=unRerbzYM=oW0syi1=C1OA@mail.gmail.com
1 parent debad29 commit c2da1a5

File tree

8 files changed

+198
-98
lines changed

8 files changed

+198
-98
lines changed

contrib/pg_stat_statements/expected/extended.out

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
6969
(4 rows)
7070

7171
-- Various parameter numbering patterns
72+
-- Unique query IDs with parameter numbers switched.
7273
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
7374
t
7475
---
7576
t
7677
(1 row)
7778

78-
-- Unique query IDs with parameter numbers switched.
7979
SELECT WHERE ($1::int, 7) IN ((8, $2::int), ($3::int, 9)) \bind '1' '2' '3' \g
8080
--
8181
(0 rows)
@@ -96,7 +96,24 @@ SELECT WHERE $3::int IN ($1::int, $2::int) \bind '1' '2' '3' \g
9696
--
9797
(0 rows)
9898

99+
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
100+
query | calls
101+
--------------------------------------------------------------+-------
102+
SELECT WHERE $1::int IN ($2 /*, ... */) | 1
103+
SELECT WHERE $1::int IN ($2 /*, ... */) | 1
104+
SELECT WHERE $1::int IN ($2 /*, ... */) | 1
105+
SELECT WHERE ($1::int, $4) IN (($5, $2::int), ($3::int, $6)) | 1
106+
SELECT WHERE ($2::int, $4) IN (($5, $3::int), ($1::int, $6)) | 1
107+
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
108+
(6 rows)
109+
99110
-- Two groups of two queries with the same query ID.
111+
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
112+
t
113+
---
114+
t
115+
(1 row)
116+
100117
SELECT WHERE '1'::int IN ($1::int, '2'::int) \bind '1' \g
101118
--
102119
(1 row)
@@ -114,15 +131,34 @@ SELECT WHERE $2::int IN ($1::int, '2'::int) \bind '3' '4' \g
114131
(0 rows)
115132

116133
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
117-
query | calls
118-
--------------------------------------------------------------+-------
119-
SELECT WHERE $1::int IN ($2::int, $3::int) | 1
120-
SELECT WHERE $2::int IN ($1::int, $3::int) | 2
121-
SELECT WHERE $2::int IN ($1::int, $3::int) | 2
122-
SELECT WHERE $2::int IN ($3::int, $1::int) | 1
123-
SELECT WHERE $3::int IN ($1::int, $2::int) | 1
124-
SELECT WHERE ($1::int, $4) IN (($5, $2::int), ($3::int, $6)) | 1
125-
SELECT WHERE ($2::int, $4) IN (($5, $3::int), ($1::int, $6)) | 1
126-
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
127-
(8 rows)
134+
query | calls
135+
----------------------------------------------------+-------
136+
SELECT WHERE $1::int IN ($2 /*, ... */) | 2
137+
SELECT WHERE $1::int IN ($2 /*, ... */) | 2
138+
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
139+
(3 rows)
140+
141+
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
142+
t
143+
---
144+
t
145+
(1 row)
146+
147+
-- no squashable list, the parameters id's are kept as-is
148+
SELECT WHERE $3 = $1 AND $2 = $4 \bind 1 2 1 2 \g
149+
--
150+
(1 row)
151+
152+
-- squashable list, so the parameter IDs will be re-assigned
153+
SELECT WHERE 1 IN (1, 2, 3) AND $3 = $1 AND $2 = $4 \bind 1 2 1 2 \g
154+
--
155+
(1 row)
156+
157+
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
158+
query | calls
159+
------------------------------------------------------------+-------
160+
SELECT WHERE $1 IN ($2 /*, ... */) AND $3 = $4 AND $5 = $6 | 1
161+
SELECT WHERE $3 = $1 AND $2 = $4 | 1
162+
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
163+
(3 rows)
128164

contrib/pg_stat_statements/expected/squashing.out

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
103103
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
104104
(2 rows)
105105

106-
-- external parameters will not be squashed
106+
-- external parameters will be squashed
107107
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
108108
t
109109
---
@@ -123,14 +123,14 @@ SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) \bind
123123
(0 rows)
124124

125125
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
126-
query | calls
127-
---------------------------------------------------------------------------+-------
128-
SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5) | 1
129-
SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) | 1
130-
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
126+
query | calls
127+
----------------------------------------------------------------------+-------
128+
SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) | 1
129+
SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1 /*, ... */]) | 1
130+
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
131131
(3 rows)
132132

133-
-- neither are prepared statements
133+
-- prepared statements will also be squashed
134134
-- the IN and ARRAY forms of this statement will have the same queryId
135135
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
136136
t
@@ -155,12 +155,12 @@ EXECUTE p1(1, 2, 3, 4, 5);
155155

156156
DEALLOCATE p1;
157157
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
158-
query | calls
159-
------------------------------------------------------------+-------
160-
DEALLOCATE $1 | 2
161-
PREPARE p1(int, int, int, int, int) AS +| 2
162-
SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5) |
163-
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
158+
query | calls
159+
-------------------------------------------------------+-------
160+
DEALLOCATE $1 | 2
161+
PREPARE p1(int, int, int, int, int) AS +| 2
162+
SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) |
163+
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
164164
(3 rows)
165165

166166
-- More conditions in the query

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,6 +2841,16 @@ generate_normalized_query(JumbleState *jstate, const char *query,
28412841
int off, /* Offset from start for cur tok */
28422842
tok_len; /* Length (in bytes) of that tok */
28432843

2844+
/*
2845+
* If we have an external param at this location, but no lists are
2846+
* being squashed across the query, then we skip here; this will make
2847+
* us print print the characters found in the original query that
2848+
* represent the parameter in the next iteration (or after the loop is
2849+
* done), which is a bit odd but seems to work okay in most cases.
2850+
*/
2851+
if (jstate->clocations[i].extern_param && !jstate->has_squashed_lists)
2852+
continue;
2853+
28442854
off = jstate->clocations[i].location;
28452855

28462856
/* Adjust recorded location if we're dealing with partial string */

contrib/pg_stat_statements/sql/extended.sql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,26 @@ SELECT $1 \bind 'unnamed_val1' \g
2121
SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
2222

2323
-- Various parameter numbering patterns
24-
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
2524
-- Unique query IDs with parameter numbers switched.
25+
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
2626
SELECT WHERE ($1::int, 7) IN ((8, $2::int), ($3::int, 9)) \bind '1' '2' '3' \g
2727
SELECT WHERE ($2::int, 10) IN ((11, $3::int), ($1::int, 12)) \bind '1' '2' '3' \g
2828
SELECT WHERE $1::int IN ($2::int, $3::int) \bind '1' '2' '3' \g
2929
SELECT WHERE $2::int IN ($3::int, $1::int) \bind '1' '2' '3' \g
3030
SELECT WHERE $3::int IN ($1::int, $2::int) \bind '1' '2' '3' \g
31+
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
3132
-- Two groups of two queries with the same query ID.
33+
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
3234
SELECT WHERE '1'::int IN ($1::int, '2'::int) \bind '1' \g
3335
SELECT WHERE '4'::int IN ($1::int, '5'::int) \bind '2' \g
3436
SELECT WHERE $2::int IN ($1::int, '1'::int) \bind '1' '2' \g
3537
SELECT WHERE $2::int IN ($1::int, '2'::int) \bind '3' '4' \g
38+
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
39+
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
40+
41+
-- no squashable list, the parameters id's are kept as-is
42+
SELECT WHERE $3 = $1 AND $2 = $4 \bind 1 2 1 2 \g
43+
-- squashable list, so the parameter IDs will be re-assigned
44+
SELECT WHERE 1 IN (1, 2, 3) AND $3 = $1 AND $2 = $4 \bind 1 2 1 2 \g
3645

3746
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";

contrib/pg_stat_statements/sql/squashing.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ SELECT WHERE 1 IN (1, int4(1), int4(2), 2);
3232
SELECT WHERE 1 = ANY (ARRAY[1, int4(1), int4(2), 2]);
3333
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
3434

35-
-- external parameters will not be squashed
35+
-- external parameters will be squashed
3636
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
3737
SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5) \bind 1 2 3 4 5
3838
;
3939
SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) \bind 1 2 3 4 5
4040
;
4141
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
4242

43-
-- neither are prepared statements
43+
-- prepared statements will also be squashed
4444
-- the IN and ARRAY forms of this statement will have the same queryId
4545
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
4646
PREPARE p1(int, int, int, int, int) AS

0 commit comments

Comments
 (0)