From cd4c0bf03310c77d1069fe05d185bb74fa5c0295 Mon Sep 17 00:00:00 2001
From: "zhaotinghai.zth" <zhaotinghai.zth@alibaba-inc.com>
Date: Thu, 16 Jan 2025 10:15:53 +0800
Subject: [PATCH] limit length of queries

---
 contrib/pg_stat_statements/Makefile           |  2 +-
 .../expected/max_length.out                   | 57 +++++++++++++++++++
 .../pg_stat_statements/pg_stat_statements.c   | 19 +++++++
 contrib/pg_stat_statements/sql/max_length.sql | 29 ++++++++++
 4 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 contrib/pg_stat_statements/expected/max_length.out
 create mode 100644 contrib/pg_stat_statements/sql/max_length.sql

diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index 31e4fdeeb9..a40267a9ac 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -18,7 +18,7 @@ LDFLAGS_SL += $(filter -lm, $(LIBS))
 
 REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_statements/pg_stat_statements.conf
 REGRESS = select dml cursors utility level_tracking planning \
-	user_activity wal extended cleanup oldextversions
+	user_activity wal extended cleanup oldextversions max_length
 # Disabled because these tests require "shared_preload_libraries=pg_stat_statements",
 # which typical installcheck users do not have (e.g. buildfarm clients).
 NO_INSTALLCHECK = 1
diff --git a/contrib/pg_stat_statements/expected/max_length.out b/contrib/pg_stat_statements/expected/max_length.out
new file mode 100644
index 0000000000..d1007ee004
--- /dev/null
+++ b/contrib/pg_stat_statements/expected/max_length.out
@@ -0,0 +1,57 @@
+CREATE EXTENSION pg_stat_statements;
+CREATE TABLE pg_stat_statement_tmp (query text);
+INSERT INTO pg_stat_statement_tmp
+(SELECT substring(query, 1, 64) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%');
+SET pg_stat_statements.max_query_length=64;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+-- check correctness
+SELECT (
+  SELECT (
+    SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
+  ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+ grouping 
+----------
+        0
+        0
+        0
+(3 rows)
+
+SELECT (
+  SELECT (
+    SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
+  ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+ grouping 
+----------
+        3
+        0
+        1
+(3 rows)
+
+SELECT COUNT(a.query) FROM pg_stat_statement_tmp a
+INNER JOIN pg_stat_statements b on a.query=b.query;
+ count 
+-------
+     0
+(1 row)
+
+SELECT a.query FROM pg_stat_statement_tmp a
+INNER JOIN pg_stat_statements b on a.query=b.query;
+ query 
+-------
+(0 rows)
+
+-- check length
+SELECT EXISTS (SELECT * FROM pg_stat_statements WHERE length(query) > 64);
+ exists 
+--------
+ f
+(1 row)
+
+DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 55b957d251..bbb6cf7b87 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -289,6 +289,7 @@ static bool pgss_track_utility = true;	/* whether to track utility commands */
 static bool pgss_track_planning = false;	/* whether to track planning
 											 * duration */
 static bool pgss_save = true;	/* whether to save stats across shutdown */
+static int 	pgss_max_query_length = 0;
 
 
 #define pgss_enabled(level) \
@@ -450,6 +451,19 @@ _PG_init(void)
 							 NULL,
 							 NULL);
 
+	DefineCustomIntVariable("pg_stat_statements.max_query_length",
+							"Max length of query which store in pgss_query_texts.stat",
+							NULL,
+							&pgss_max_query_length,
+							0,
+							0,
+							PG_INT32_MAX,
+							PGC_USERSET,
+							GUC_UNIT_BYTE,
+							NULL,
+							NULL,
+							NULL);
+
 	MarkGUCPrefixReserved("pg_stat_statements");
 
 	/*
@@ -1294,6 +1308,11 @@ pgss_store(const char *query, uint64 queryId,
 			LWLockAcquire(pgss->lock, LW_SHARED);
 		}
 
+		if (pgss_max_query_length > 0)
+		{
+			query_len = Min(query_len, pgss_max_query_length);
+		}
+
 		/* Append new query text to file with only shared lock held */
 		stored = qtext_store(norm_query ? norm_query : query, query_len,
 							 &query_offset, &gc_count);
diff --git a/contrib/pg_stat_statements/sql/max_length.sql b/contrib/pg_stat_statements/sql/max_length.sql
new file mode 100644
index 0000000000..24dff60dde
--- /dev/null
+++ b/contrib/pg_stat_statements/sql/max_length.sql
@@ -0,0 +1,29 @@
+CREATE EXTENSION pg_stat_statements;
+CREATE TABLE pg_stat_statement_tmp (query text);
+INSERT INTO pg_stat_statement_tmp
+(SELECT substring(query, 1, 64) FROM pg_stat_statements WHERE query LIKE '%SELECT GROUPING%');
+
+SET pg_stat_statements.max_query_length=64;
+SELECT pg_stat_statements_reset();
+
+-- check correctness
+SELECT (
+  SELECT (
+    SELECT GROUPING(a,b) FROM (VALUES (1)) v2(c)
+  ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+SELECT (
+  SELECT (
+    SELECT GROUPING(e,f) FROM (VALUES (1)) v2(c)
+  ) FROM (VALUES (1,2)) v1(a,b) GROUP BY (a,b)
+) FROM (VALUES(6,7)) v3(e,f) GROUP BY ROLLUP(e,f);
+
+SELECT COUNT(a.query) FROM pg_stat_statement_tmp a
+INNER JOIN pg_stat_statements b on a.query=b.query;
+
+SELECT a.query FROM pg_stat_statement_tmp a
+INNER JOIN pg_stat_statements b on a.query=b.query;
+
+-- check length
+SELECT EXISTS (SELECT * FROM pg_stat_statements WHERE length(query) > 64);
+DROP EXTENSION pg_stat_statements;
\ No newline at end of file
-- 
2.39.3

