Skip to content

Commit 33fd37d

Browse files
craig[bot]ZhouXing19
andcommitted
151983: sqlsmith: add support for DO block r=ZhouXing19 a=ZhouXing19 informs #106368 A `DO` block can be either a top-level sql statement or be part of the plpgsql function body. In this commit we introduce the DO block for both of these 2 usages. We also introduced `DisableDoBlocks` which disables both usages of a DO block. Release note: None 154783: sql/jsonpath: validate JSON column in jsonb_path_exists for inverted index acceleration r=ZhouXing19 a=ZhouXing19 Informs: #154729 Previously, the `jsonb_path_exists` function would attempt inverted index acceleration even when the JSON parameter referenced a column that was not the source column of the inverted index, or when it was a constant JSON value. This resulted in incorrect query plans and potentially wrong results. This commit adds proper validation to ensure that inverted index acceleration is only used when the JSON parameter is a variable expression that references the actual source column of the inverted index. For all other cases, the query will fall back to a full table scan with post-filtering. We also don't allow index acceleration for jsonb_path_exists filter if it takes a variable list in its parameters. For example, `jsonb_path_exists(b, '$.a ? (`@.b` == $x)', '{"x": "c"}')` (where `'{"x": "c"}'` is the variable list) is not allowed. Release note: None Co-authored-by: ZhouXing19 <[email protected]>
3 parents e5415f7 + 4938792 + 664452a commit 33fd37d

File tree

7 files changed

+101
-11
lines changed

7 files changed

+101
-11
lines changed

pkg/ccl/changefeedccl/changefeed_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ func TestChangefeedRandomExpressions(t *testing.T) {
16921692
sqlsmith.DisableWith(),
16931693
sqlsmith.DisableMutations(),
16941694
sqlsmith.DisableLimits(),
1695+
sqlsmith.DisableDoBlocks(),
16951696
sqlsmith.DisableAggregateFuncs(),
16961697
sqlsmith.DisableWindowFuncs(),
16971698
sqlsmith.DisableJoins(),

pkg/cmd/smith/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ var (
6666
"DisableCrossJoins": sqlsmith.DisableCrossJoins(),
6767
"DisableDDLs": sqlsmith.DisableDDLs(),
6868
"DisableDecimals": sqlsmith.DisableDecimals(),
69+
"DisableDoBlocks": sqlsmith.DisableDoBlocks(),
6970
"DisableEverything": sqlsmith.DisableEverything(),
7071
"DisableIndexHints": sqlsmith.DisableIndexHints(),
7172
"DisableInsertSelect": sqlsmith.DisableInsertSelect(),

pkg/internal/sqlsmith/plpgsql.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ var (
141141
{2, makePLpgSQLReturn},
142142
{2, makePLpgSQLIf},
143143
{2, makePLpgSQLWhile},
144+
{2, makeDoBlockWithinScope},
144145
{2, makePLpgSQLForLoop},
145146
{5, makePLpgSQLNull},
146147
{10, makePLpgSQLAssign},
@@ -395,3 +396,20 @@ func (s *plpgsqlBlockScope) addVariable(name string, typ *types.T, constant bool
395396
s.constants[name] = struct{}{}
396397
}
397398
}
399+
400+
func (s *Smither) makeDoBlockTreeStmt() (*tree.DoBlock, bool) {
401+
scope := makeBlockScope(0, types.Unknown, tree.RoutineVolatile)
402+
doBlock, ok := makeDoBlockWithinScope(s, scope)
403+
if !ok {
404+
return nil, false
405+
}
406+
return &tree.DoBlock{Code: doBlock.(*ast.DoBlock)}, true
407+
}
408+
409+
func makeDoBlockWithinScope(s *Smither, scope plpgsqlBlockScope) (ast.Statement, bool) {
410+
if s.disableDoBlock {
411+
return nil, false
412+
}
413+
block := s.makePLpgSQLBlock(scope)
414+
return &ast.DoBlock{Block: block}, true
415+
}

pkg/internal/sqlsmith/relational.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ var (
110110
{1, makeImport},
111111
{1, makeCreateStats},
112112
{1, makeSetSessionCharacteristics},
113+
{1, makeDoBlock},
113114
}
114115
nonMutatingStatements = []statementWeight{
115116
{10, makeSelect},
117+
{1, makeDoBlock},
116118
}
117119
allStatements = append(mutatingStatements, nonMutatingStatements...)
118120

@@ -928,6 +930,10 @@ func makeCreateFunc(s *Smither) (tree.Statement, bool) {
928930
return s.makeCreateFunc()
929931
}
930932

933+
func makeDoBlock(s *Smither) (tree.Statement, bool) {
934+
return s.makeDoBlockTreeStmt()
935+
}
936+
931937
func makeDropFunc(s *Smither) (tree.Statement, bool) {
932938
if s.disableUDFCreation {
933939
return nil, false

pkg/internal/sqlsmith/sqlsmith.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ type Smither struct {
118118
// disableUDFCreation indicates whether we're not allowed to create UDFs.
119119
// It follows that if we haven't created any UDFs, we have no UDFs to invoke
120120
// too.
121-
disableUDFCreation bool
121+
disableUDFCreation bool
122+
// disableDoBlock indicates whether we're not allowed to create DO blocks,
123+
// both as top level statements and inside plpgsql function body
124+
// definition.
125+
disableDoBlock bool
122126
disableIsolationChange bool
123127

124128
bulkSrv *httptest.Server
@@ -612,6 +616,11 @@ var DisableUDFs = simpleOption("disable udfs", func(s *Smither) {
612616
s.disableUDFCreation = true
613617
})
614618

619+
// DisableDoBlocks causes the Smither to disable DO blocks.
620+
var DisableDoBlocks = simpleOption("disable do block", func(s *Smither) {
621+
s.disableDoBlock = true
622+
})
623+
615624
// DisableIsolationChange causes the Smither to disable stmts that modify the
616625
// txn isolation level.
617626
var DisableIsolationChange = simpleOption("disable isolation change", func(s *Smither) {

pkg/sql/logictest/testdata/logic_test/jsonb_path_exists_index_acceleration

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
statement ok
55
CREATE TABLE json_tab (
66
a INT PRIMARY KEY,
7-
b JSONB
7+
b JSONB,
8+
c JSONB
89
)
910

1011
statement ok
@@ -25,7 +26,7 @@ INSERT INTO json_tab VALUES
2526

2627
# To confirm which rows contain the specified path.
2728
query IT
28-
SELECT * FROM json_tab@primary WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a;
29+
SELECT a, b FROM json_tab@primary WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a, b;
2930
----
3031
3 {"a": {"b": "c", "d": "e"}}
3132
4 {"a": {"b": [1, 2, 3, 4]}}
@@ -35,7 +36,7 @@ SELECT * FROM json_tab@primary WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a;
3536
9 {"a": {"b": "c"}}
3637

3738
query IT
38-
SELECT * FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a;
39+
SELECT a, b FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a.b') ORDER BY a, b;
3940
----
4041
3 {"a": {"b": "c", "d": "e"}}
4142
4 {"a": {"b": [1, 2, 3, 4]}}
@@ -505,3 +506,53 @@ SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a[*][*] ? (@.b == 1
505506
16
506507
17
507508
18
509+
510+
# If json parameter is not part of the inverted index, the filter should
511+
# not be index accelerated.
512+
statement ok
513+
INSERT INTO json_tab VALUES (19, '{"a": {"b": "c"}}', '{"a": {"b": "c"}}')
514+
515+
query I
516+
SELECT a FROM json_tab@primary WHERE jsonb_path_exists(c, '$.a.b') ORDER BY a;
517+
----
518+
19
519+
520+
statement error index "foo_inv" is inverted and cannot be used for this query
521+
SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(c, '$.a.b') ORDER BY a;
522+
523+
query I
524+
SELECT a FROM json_tab@primary WHERE jsonb_path_exists('{"a": {"b": "c"}}', '$.a.b') ORDER BY a;
525+
----
526+
1
527+
2
528+
3
529+
4
530+
5
531+
6
532+
7
533+
8
534+
9
535+
10
536+
11
537+
12
538+
13
539+
14
540+
15
541+
16
542+
17
543+
18
544+
19
545+
546+
statement error index "foo_inv" is inverted and cannot be used for this query
547+
SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists('{"a": {"b": "c"}}', '$.a.b') ORDER BY a;
548+
549+
# We don't index accelerate jsonb_path_exists clause with variables.
550+
query I
551+
SELECT a FROM json_tab@primary WHERE jsonb_path_exists(b, '$.a ? (@.b == $x)', '{"x": "c"}') ORDER BY a;
552+
----
553+
3
554+
9
555+
19
556+
557+
statement error index "foo_inv" is inverted and cannot be used for this query
558+
SELECT a FROM json_tab@foo_inv WHERE jsonb_path_exists(b, '$.a ? (@.b == $x)', '{"x": "c"}') ORDER BY a;

pkg/sql/opt/invertedidx/json_array.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,16 +416,20 @@ func (j *jsonOrArrayFilterPlanner) extractInvertedFilterConditionFromLeaf(
416416
invertedExpr = j.extractArrayOverlapsCondition(ctx, evalCtx, t.Left, t.Right)
417417
case *memo.FunctionExpr:
418418
if t.Properties.Category == builtinconstants.CategoryJsonpath && t.Name == "jsonb_path_exists" {
419-
if len(t.Args) > 1 {
420-
if ce, ok := t.Args[1].(*memo.ConstExpr); ok {
421-
if dJsonPath, ok := ce.Value.(*tree.DJsonpath); ok {
422-
if dJsonPath.Strict {
423-
return inverted.NonInvertedColExpression{}, expr, nil
419+
if len(t.Args) == 2 {
420+
// The first parameter has to be a column reference.
421+
if isIndexColumn(j.tabID, j.index, t.Args[0], j.computedColumns) {
422+
if ce, ok := t.Args[1].(*memo.ConstExpr); ok {
423+
if dJsonPath, ok := ce.Value.(*tree.DJsonpath); ok {
424+
if dJsonPath.Strict {
425+
return inverted.NonInvertedColExpression{}, expr, nil
426+
}
427+
jp := dJsonPath.Path
428+
invertedExpr = j.extractJSONPathCondition(ctx, evalCtx, jp)
424429
}
425-
jp := dJsonPath.Path
426-
invertedExpr = j.extractJSONPathCondition(ctx, evalCtx, jp)
427430
}
428431
}
432+
429433
}
430434
}
431435
}

0 commit comments

Comments
 (0)