Skip to content

Commit f123352

Browse files
committed
[WIP] sqlstats: data driven tests
Epic: None Release note: None
1 parent de08acb commit f123352

File tree

7 files changed

+299
-1
lines changed

7 files changed

+299
-1
lines changed

pkg/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ ALL_TESTS = [
667667
"//pkg/sql/sqlstats/sslocal:sslocal_test",
668668
"//pkg/sql/sqlstats/ssmemstorage:ssmemstorage_test",
669669
"//pkg/sql/sqlstats/ssremote:ssremote_test",
670+
"//pkg/sql/sqlstats:sqlstats_test",
670671
"//pkg/sql/sqltestutils:sqltestutils_test",
671672
"//pkg/sql/stats:stats_test",
672673
"//pkg/sql/stmtdiagnostics:stmtdiagnostics_test",
@@ -2424,6 +2425,7 @@ GO_TARGETS = [
24242425
"//pkg/sql/sqlstats/ssremote:ssremote",
24252426
"//pkg/sql/sqlstats/ssremote:ssremote_test",
24262427
"//pkg/sql/sqlstats:sqlstats",
2428+
"//pkg/sql/sqlstats:sqlstats_test",
24272429
"//pkg/sql/sqltelemetry:sqltelemetry",
24282430
"//pkg/sql/sqltestutils:sqltestutils",
24292431
"//pkg/sql/sqltestutils:sqltestutils_test",

pkg/sql/sqlstats/BUILD.bazel

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("@io_bazel_rules_go//go:def.bzl", "go_library")
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
22

33
go_library(
44
name = "sqlstats",
@@ -33,3 +33,26 @@ go_library(
3333
"@com_github_cockroachdb_redact//:redact",
3434
],
3535
)
36+
37+
go_test(
38+
name = "sqlstats_test",
39+
srcs = [
40+
"main_test.go",
41+
"sqlstats_test.go",
42+
],
43+
data = glob(["testdata/**"]),
44+
deps = [
45+
":sqlstats",
46+
"//pkg/base",
47+
"//pkg/security/securityassets",
48+
"//pkg/security/securitytest",
49+
"//pkg/server",
50+
"//pkg/testutils/datapathutils",
51+
"//pkg/testutils/serverutils",
52+
"//pkg/testutils/sqlutils",
53+
"//pkg/testutils/testcluster",
54+
"//pkg/util/leaktest",
55+
"//pkg/util/log",
56+
"@com_github_cockroachdb_datadriven//:datadriven",
57+
],
58+
)

pkg/sql/sqlstats/main_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package sqlstats_test
7+
8+
import (
9+
"os"
10+
"testing"
11+
12+
"github.com/cockroachdb/cockroach/pkg/security/securityassets"
13+
"github.com/cockroachdb/cockroach/pkg/security/securitytest"
14+
"github.com/cockroachdb/cockroach/pkg/server"
15+
"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
16+
"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
17+
)
18+
19+
func TestMain(m *testing.M) {
20+
securityassets.SetLoader(securitytest.EmbeddedAssets)
21+
serverutils.InitTestServerFactory(server.TestServerFactory)
22+
serverutils.InitTestClusterFactory(testcluster.TestClusterFactory)
23+
os.Exit(m.Run())
24+
}

pkg/sql/sqlstats/sqlstats_test.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package sqlstats_test
7+
8+
import (
9+
"context"
10+
"fmt"
11+
"strings"
12+
"testing"
13+
14+
"github.com/cockroachdb/cockroach/pkg/base"
15+
"github.com/cockroachdb/cockroach/pkg/sql/sqlstats"
16+
"github.com/cockroachdb/cockroach/pkg/testutils/datapathutils"
17+
"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
18+
"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
19+
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
20+
"github.com/cockroachdb/cockroach/pkg/util/log"
21+
"github.com/cockroachdb/datadriven"
22+
)
23+
24+
func TestDataDrivenTest(t *testing.T) {
25+
defer leaktest.AfterTest(t)()
26+
defer log.Scope(t).Close(t)
27+
28+
datadriven.Walk(t, datapathutils.TestDataPath(t), func(t *testing.T, path string) {
29+
s, conn, _ := serverutils.StartServer(t, base.TestServerArgs{
30+
Knobs: base.TestingKnobs{
31+
SQLStatsKnobs: &sqlstats.TestingKnobs{
32+
SynchronousSQLStats: true,
33+
},
34+
},
35+
})
36+
37+
defer s.Stopper().Stop(context.Background())
38+
statsRunner := sqlutils.MakeSQLRunner(conn)
39+
datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string {
40+
switch d.Cmd {
41+
case "exec-sql":
42+
sqlConn := s.SQLConn(t)
43+
defer sqlConn.Close()
44+
execSqlRunner := sqlutils.MakeSQLRunner(sqlConn)
45+
var appName, dbName string
46+
if d.HasArg("db") {
47+
d.ScanArgs(t, "db", &dbName)
48+
execSqlRunner.Exec(t, fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
49+
execSqlRunner.Exec(t, fmt.Sprintf("USE %s", dbName))
50+
} else {
51+
t.Fatalf("db arg is required")
52+
}
53+
if d.HasArg("app-name") {
54+
d.ScanArgs(t, "app-name", &appName)
55+
execSqlRunner.Exec(t, "SET APPLICATION_NAME = $1", appName)
56+
}
57+
execSqlRunner.Exec(t, d.Input)
58+
return ""
59+
case "show-stats":
60+
var appName, dbName string
61+
if d.HasArg("app-name") {
62+
d.ScanArgs(t, "app-name", &appName)
63+
}
64+
if d.HasArg("db") {
65+
d.ScanArgs(t, "db", &dbName)
66+
}
67+
return GetStats(t, statsRunner, appName, dbName)
68+
case "show-txn-stats":
69+
var appName, dbName string
70+
if d.HasArg("app-name") {
71+
d.ScanArgs(t, "app-name", &appName)
72+
}
73+
if d.HasArg("db") {
74+
d.ScanArgs(t, "db", &dbName)
75+
}
76+
return GetTxnStats(t, statsRunner, appName, dbName)
77+
default:
78+
t.Fatalf("unexpected cmd %s", d.Cmd)
79+
}
80+
return ""
81+
})
82+
})
83+
}
84+
85+
func GetStats(t *testing.T, conn *sqlutils.SQLRunner, appName string, dbName string) string {
86+
t.Helper()
87+
query := ` SELECT row_to_json(s) FROM (
88+
SELECT
89+
encode(fingerprint_id, 'hex') AS fingerprint_id,
90+
encode(transaction_fingerprint_id, 'hex') AS transaction_fingerprint_id,
91+
(plan_hash != '\x'::BYTES) AS plan_hash_set,
92+
metadata ->> 'query' AS query,
93+
metadata ->> 'querySummary' AS summary,
94+
metadata -> 'distsql' AS plan_distributed,
95+
metadata -> 'implicitTxn' AS plan_implicit_txn,
96+
metadata -> 'vec' AS plan_vectorized,
97+
metadata -> 'fullScan' AS plan_full_scan,
98+
statistics -> 'statistics'->> 'cnt' AS count,
99+
statistics -> 'statistics'-> 'nodes' AS nodes,
100+
statistics -> 'statistics' -> 'sqlType' AS sql_type,
101+
(statistics -> 'statistics' -> 'parseLat' -> 'mean')::FLOAT > 0 AS parse_lat_not_zero,
102+
(statistics -> 'statistics' -> 'planLat' -> 'mean')::FLOAT > 0 AS plan_lat_not_zero,
103+
(statistics -> 'statistics' -> 'runLat' -> 'mean')::FLOAT > 0 AS run_lat_not_zero,
104+
(statistics -> 'statistics' -> 'svcLat' -> 'mean')::FLOAT > 0 AS svc_lat_not_zero,
105+
(((statistics->'execution_statistics':::STRING)->'cpuSQLNanos':::STRING)->'mean':::STRING)::FLOAT8 > 0 AS cpu_sql_nanos_not_zero
106+
FROM crdb_internal.statement_statistics
107+
WHERE 1=1
108+
AND app_name = $1
109+
AND metadata->>'db' = $2
110+
ORDER BY fingerprint_id) s
111+
`
112+
res := conn.QueryStr(t, query, appName, dbName)
113+
rows := make([]string, len(res))
114+
for rowIdx := range res {
115+
rows[rowIdx] = strings.Join(res[rowIdx], ",")
116+
}
117+
return strings.Join(rows, "\n")
118+
}
119+
120+
func GetTxnStats(t *testing.T, conn *sqlutils.SQLRunner, appName string, dbName string) string {
121+
query := ` SELECT row_to_json(s) FROM (
122+
SELECT
123+
encode(ts.fingerprint_id, 'hex') AS txn_fingerprint_id,
124+
max(ts.metadata->'stmtFingerprintIDs') AS statement_fingerprint_ids
125+
FROM crdb_internal.transaction_statistics ts
126+
JOIN crdb_internal.statement_statistics ss ON ss.transaction_fingerprint_id = ts.fingerprint_id
127+
WHERE 1=1
128+
AND ss.app_name = $1
129+
AND ss.metadata->>'db' = $2
130+
GROUP BY txn_fingerprint_id
131+
ORDER BY txn_fingerprint_id) s
132+
`
133+
res := conn.QueryStr(t, query, appName, dbName)
134+
rows := make([]string, len(res))
135+
for rowIdx := range res {
136+
rows[rowIdx] = strings.Join(res[rowIdx], ",")
137+
}
138+
return strings.Join(rows, "\n")
139+
}

pkg/sql/sqlstats/testdata/example

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
exec-sql db=random_db
2+
CREATE TABLE users (id INT PRIMARY KEY, name STRING);
3+
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
4+
SELECT * FROM users;
5+
----
6+
7+
# Sanity check shouldn't return anything
8+
show-stats app-name=random db=random_db
9+
----
10+
11+
show-stats db=random_db
12+
----
13+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "269c5d2c33dec958", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "INSERT INTO users VALUES (_, __more__), (__more__)", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "INSERT INTO users", "svc_lat_not_zero": true, "transaction_fingerprint_id": "205354584637cfcb"}
14+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "2cdc86177e8b242b", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "SET database = random_db", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "SET database = random_db", "svc_lat_not_zero": true, "transaction_fingerprint_id": "83bf3b5bf88a93f4"}
15+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "e6733d9c37147d22", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": true, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "SELECT * FROM users", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "SELECT * FROM users", "svc_lat_not_zero": true, "transaction_fingerprint_id": "205354584637cfcb"}
16+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "ec1bc23e5d2925f6", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "CREATE TABLE users (id INT8 PRIMARY KEY, name STRING)", "run_lat_not_zero": true, "sql_type": "TypeDDL", "summary": "CREATE TABLE users (id INT8 PRIMARY KEY, name STRING)", "svc_lat_not_zero": true, "transaction_fingerprint_id": "205354584637cfcb"}
17+
18+
exec-sql db=random_db app-name=transactions
19+
BEGIN;
20+
INSERT INTO users VALUES (3, 'Charlie');
21+
INSERT INTO users VALUES (4, 'Diana');
22+
COMMIT;
23+
----
24+
25+
exec-sql db=random_db app-name=transactions
26+
BEGIN;
27+
INSERT INTO users VALUES (5, 'Eve');
28+
INSERT INTO users VALUES (6, 'Frank');
29+
COMMIT;
30+
----
31+
32+
show-stats db=random_db app-name=transactions
33+
----
34+
{"count": "4", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "5fe99858726d3688", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": false, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "INSERT INTO users VALUES (_, __more__)", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "INSERT INTO users", "svc_lat_not_zero": true, "transaction_fingerprint_id": "78d7c1c32632f05d"}
35+
36+
show-txn-stats db=random_db app-name=transactions
37+
----
38+
{"statement_fingerprint_ids": ["5fe99858726d3688", "5fe99858726d3688"], "txn_fingerprint_id": "78d7c1c32632f05d"}

pkg/sql/sqlstats/testdata/plpgsql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
exec-sql db=udf_test app-name=plpgsql
2+
CREATE TABLE IF NOT EXISTS test(a int);
3+
CREATE OR REPLACE PROCEDURE insert_incremental(n INT)
4+
LANGUAGE plpgsql
5+
AS $$
6+
DECLARE
7+
i INT := 0;
8+
next_val INT;
9+
BEGIN
10+
WHILE i < n LOOP
11+
SELECT COALESCE(MAX(a), 0) + 1 INTO next_val FROM test;
12+
INSERT INTO test(a) VALUES (next_val);
13+
i := i + 1;
14+
END LOOP;
15+
END;
16+
$$;
17+
CALL insert_incremental(5);
18+
----
19+
20+
show-stats db=udf_test app-name=plpgsql
21+
----
22+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "11c4e5400aa05722", "nodes": [], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "CREATE OR REPLACE PROCEDURE insert_incremental(n INT8)\n\tLANGUAGE plpgsql\n\tAS $$_$$", "run_lat_not_zero": true, "sql_type": "TypeDDL", "summary": "CREATE OR REPLACE PROCEDURE insert_incremental(n INT8)\n\tLANGUAGE plpgsql\n\tAS $$_$$", "svc_lat_not_zero": true, "transaction_fingerprint_id": "3013cc07fc915da5"}
23+
{"count": "5", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "12d44a85acad2974", "nodes": [], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": true, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "SELECT COALESCE(max(a), _) + _ FROM udf_test.public.test", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "SELECT COALESCE(max(a)...)... FROM udf_test.public.test", "svc_lat_not_zero": true, "transaction_fingerprint_id": "3013cc07fc915da5"}
24+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "a82856550b801042", "nodes": [], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "CALL insert_incremental(_)", "run_lat_not_zero": true, "sql_type": "TypeTCL", "summary": "CALL insert_incremental(_)", "svc_lat_not_zero": true, "transaction_fingerprint_id": "3013cc07fc915da5"}
25+
{"count": "5", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "a8eed74b07b66674", "nodes": [], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "INSERT INTO udf_test.public.test(a) VALUES (next_val)", "run_lat_not_zero": true, "sql_type": "TypeDML", "summary": "INSERT INTO udf_test.public.test(a)", "svc_lat_not_zero": true, "transaction_fingerprint_id": "3013cc07fc915da5"}
26+
{"count": "1", "cpu_sql_nanos_not_zero": false, "fingerprint_id": "f592c1a0850da0bf", "nodes": [1], "parse_lat_not_zero": true, "plan_distributed": false, "plan_full_scan": false, "plan_hash_set": true, "plan_implicit_txn": true, "plan_lat_not_zero": true, "plan_vectorized": true, "query": "CREATE TABLE IF NOT EXISTS test (a INT8)", "run_lat_not_zero": true, "sql_type": "TypeDDL", "summary": "CREATE TABLE IF NOT EXISTS test (a INT8)", "svc_lat_not_zero": true, "transaction_fingerprint_id": "5af17cec030c1760"}

0 commit comments

Comments
 (0)