Skip to content

Commit d6f6de2

Browse files
craig[bot]mgartner
andcommitted
108188: sql: refactor semantic analysis and fix some bugs r=mgartner a=mgartner #### sql/sem/tree: simplify SemaCtx reject flag checks Release note: None #### sql/sem/tree: split derived SemaContext properties from contextual info Properties derived about expressions during semantic analysis are communicated to callers via ScalarProperties. Prior to this commit, this type was also used to provide contextual information while traversing sub-expressions during semantic analysis. For example, it would indicate whether the current expression is a descendent of a window function expression. These two types of information, derived and contextual, are fundamentally different. Derived properties bubble up from the bottom of the tree to the top, while context propagates downward into sub-expressions. This difference made it difficult to maintaining them correctly in a single type and difficult to reason about. This commit introduces the ScalarScene type which is used for providing internal contextual information during semantic analysis. Release note: None #### sql/sem/tree: do not Restore SemaRejectFlags during semantic analysis This commit fixes a bug introduced in cockroachdb#105582 that caused SemaRejectFlags to be restored during semantic analysis, preventing the analysis from detecting some forms of invalid expressions. Fixes cockroachdb#108166 There is no release note because the related bug does not exist in any releases. Release note: None #### sql: do not allow subqueries to be cast to enums in views and UDFs This commit is a follow-up to cockroachdb#106868 after additional reproductions of the original bug were found. For now, we disallow any CAST expressions that contain a subquery in the input and the target type is an ENUM. I've created cockroachdb#108184 to track this limitation. Fixes cockroachdb#107654 There is no release note because the release note from cockroachdb#106868 should be sufficient. Release note: None #### sql/randgen: fix typo in comment Release note: None Co-authored-by: Marcus Gartner <[email protected]>
2 parents cdf6d15 + 25c344c commit d6f6de2

File tree

14 files changed

+165
-138
lines changed

14 files changed

+165
-138
lines changed

pkg/sql/create_function.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ func setFuncOptions(
443443
return err
444444
}
445445
typeReplacedFuncBody, err := serializeUserDefinedTypes(
446-
params.ctx, params.p.SemaCtx(), seqReplacedFuncBody, true, /* multiStmt */
446+
params.ctx, params.p.SemaCtx(), seqReplacedFuncBody, true /* multiStmt */, "UDFs",
447447
)
448448
if err != nil {
449449
return err

pkg/sql/create_view.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ func makeViewTableDesc(
411411
desc.ViewQuery = sequenceReplacedQuery
412412
}
413413

414-
typeReplacedQuery, err := serializeUserDefinedTypes(ctx, semaCtx, desc.ViewQuery, false /* multiStmt */)
414+
typeReplacedQuery, err := serializeUserDefinedTypes(ctx, semaCtx, desc.ViewQuery,
415+
false /* multiStmt */, "view queries")
415416
if err != nil {
416417
return tabledesc.Mutable{}, err
417418
}
@@ -490,7 +491,7 @@ func replaceSeqNamesWithIDs(
490491
// and serialize any user defined types, so that renaming the type
491492
// does not corrupt the view.
492493
func serializeUserDefinedTypes(
493-
ctx context.Context, semaCtx *tree.SemaContext, queries string, multiStmt bool,
494+
ctx context.Context, semaCtx *tree.SemaContext, queries string, multiStmt bool, parentType string,
494495
) (string, error) {
495496
replaceFunc := func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) {
496497
var innerExpr tree.Expr
@@ -505,20 +506,6 @@ func serializeUserDefinedTypes(
505506
default:
506507
return true, expr, nil
507508
}
508-
// We cannot type-check subqueries without using optbuilder, and there
509-
// is no need to because we only need to rewrite string values that are
510-
// directly cast to enums. For example, we must rewrite the 'foo' in:
511-
//
512-
// SELECT 'foo'::myenum
513-
//
514-
// We don't need to rewrite the 'foo' in the query below, which can be
515-
// corrupted by renaming the 'foo' value in the myenum type.
516-
//
517-
// SELECT (SELECT 'foo')::myenum
518-
//
519-
if _, ok := innerExpr.(*tree.Subquery); ok {
520-
return true, expr, nil
521-
}
522509
// semaCtx may be nil if this is a virtual view being created at
523510
// init time.
524511
var typeResolver tree.TypeReferenceResolver
@@ -533,6 +520,14 @@ func serializeUserDefinedTypes(
533520
if !typ.UserDefined() {
534521
return true, expr, nil
535522
}
523+
{
524+
// We cannot type-check subqueries without using optbuilder, so we
525+
// currently do not support casting expressions with subqueries to
526+
// UDTs.
527+
context := "casts to enums within " + parentType
528+
defer semaCtx.Properties.Restore(semaCtx.Properties)
529+
semaCtx.Properties.Require(context, tree.RejectSubqueries)
530+
}
536531
texpr, err := innerExpr.TypeCheck(ctx, semaCtx, typ)
537532
if err != nil {
538533
return false, expr, err
@@ -603,7 +598,8 @@ func (p *planner) replaceViewDesc(
603598
toReplace.ViewQuery = updatedQuery
604599
}
605600

606-
typeReplacedQuery, err := serializeUserDefinedTypes(ctx, p.SemaCtx(), toReplace.ViewQuery, false /* multiStmt */)
601+
typeReplacedQuery, err := serializeUserDefinedTypes(ctx, p.SemaCtx(), toReplace.ViewQuery,
602+
false /* multiStmt */, "view queries")
607603
if err != nil {
608604
return nil, err
609605
}

pkg/sql/logictest/testdata/logic_test/delete

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,15 @@ statement error pgcode 42803 sum\(\): aggregate functions are not allowed in ORD
576576
DELETE FROM t107634 ORDER BY sum(a) LIMIT 1;
577577

578578
subtest end
579+
580+
# Regression test for #108166. Do not allow aggregate functions in ORDER BY when
581+
# the function is wrapped by a conditional expression.
582+
subtest regression_108166
583+
584+
statement ok
585+
CREATE TABLE t108166 (a INT)
586+
587+
statement error pgcode 42803 sum\(\): aggregate functions are not allowed in ORDER BY in DELETE
588+
DELETE FROM t108166 ORDER BY COALESCE(sum(a), 1) LIMIT 1;
589+
590+
subtest end

pkg/sql/logictest/testdata/logic_test/srfs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,16 +1322,16 @@ subtest generator-syntax
13221322

13231323
# Regression test for #97119 and #94890 - return syntax error when CASE or
13241324
# COALESCE is used with a set-generating function as argument.
1325-
statement error pq: set-returning functions are not allowed in CASE
1325+
statement error pq: set-returning functions are not allowed in conditional expressions
13261326
SELECT CASE generate_series(1, 3) WHEN 3 THEN 0 ELSE 1 END;
13271327

1328-
statement error pq: set-returning functions are not allowed in CASE
1328+
statement error pq: set-returning functions are not allowed in conditional expressions
13291329
SELECT CASE WHEN true THEN generate_series(1, 3) ELSE 1 END;
13301330

1331-
statement error pq: set-returning functions are not allowed in CASE
1331+
statement error pq: set-returning functions are not allowed in conditional expressions
13321332
SELECT CASE WHEN false THEN 1 ELSE generate_series(1, 3) END;
13331333

1334-
statement error pq: set-returning functions are not allowed in COALESCE
1334+
statement error pq: set-returning functions are not allowed in conditional expressions
13351335
SELECT COALESCE(generate_series(1, 10));
13361336

13371337
# A subquery with a generator function is allowed within CASE and COALESCE.
@@ -1376,12 +1376,12 @@ SELECT COALESCE(sum(x) OVER ()) FROM xy;
13761376
15
13771377

13781378
# IF does not allow generator functions.
1379-
statement error pq: set-returning functions are not allowed in IF
1379+
statement error pq: set-returning functions are not allowed in conditional expressions
13801380
SELECT IF(x > y, generate_series(1, 3), 0) FROM xy;
13811381

13821382
# IFNULL does not allow generator functions. Note that the error mentions
13831383
# COALESCE because IFNULL is parsed directly as a COALESCE expression.
1384-
statement error pq: set-returning functions are not allowed in COALESCE
1384+
statement error pq: set-returning functions are not allowed in conditional expressions
13851385
SELECT IFNULL(1, generate_series(1, 2));
13861386

13871387
# NULLIF allows generator functions.

pkg/sql/logictest/testdata/logic_test/udf_regressions

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -554,29 +554,25 @@ $$
554554
subtest end
555555

556556

557-
# Regression test for #105259. Do not type-check subqueries in UDFs outside
558-
# optbuilder. Doing so can cause internal errors.
557+
# Regression tests for #105259 and #107654. Do not type-check subqueries in UDFs
558+
# outside optbuilder. Doing so can cause internal errors.
559559
subtest regression_105259
560560

561561
statement ok
562562
CREATE TYPE e105259 AS ENUM ('foo');
563563

564-
statement ok
564+
statement error pgcode 0A000 subqueries are not allowed in casts to enums within UDFs
565565
CREATE FUNCTION f() RETURNS VOID LANGUAGE SQL AS $$
566566
SELECT (SELECT 'foo')::e105259;
567567
SELECT NULL;
568568
$$
569569

570-
query T
571-
SELECT f()
572-
----
573-
NULL
574-
575-
statement ok
576-
ALTER TYPE e105259 RENAME VALUE 'foo' TO 'bar'
577-
578-
# Renaming the enum value corrupts the UDF. This is expected behavior.
579-
statement error pgcode 22P02 invalid input value for enum e105259: "foo"
580-
SELECT f()
570+
statement error pgcode 0A000 subqueries are not allowed in casts to enums within UDFs
571+
CREATE FUNCTION f() RETURNS VOID LANGUAGE SQL AS $$
572+
SELECT (
573+
CASE WHEN true THEN (SELECT 'foo') ELSE NULL END
574+
)::e105259;
575+
SELECT NULL;
576+
$$
581577

582578
subtest end

pkg/sql/logictest/testdata/logic_test/udf_unsupported

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,3 @@ statement error pgcode 0A000 unimplemented: cannot create UDFs under a temporary
183183
CREATE FUNCTION $temp_schema_102964.f_102964 () RETURNS INT AS 'SELECT 1' LANGUAGE sql;
184184

185185
subtest end
186-

pkg/sql/logictest/testdata/logic_test/update

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,3 +672,15 @@ statement error pgcode 42803 sum\(\): aggregate functions are not allowed in ORD
672672
UPDATE t107634 SET a = 1 ORDER BY sum(a) LIMIT 1;
673673

674674
subtest end
675+
676+
# Regression test for #108166. Do not allow aggregate functions in ORDER BY when
677+
# the function is wrapped by a conditional expression.
678+
subtest regression_108166
679+
680+
statement ok
681+
CREATE TABLE t108166 (a INT)
682+
683+
statement error pgcode 42803 sum\(\): aggregate functions are not allowed in ORDER BY in UPDATE
684+
UPDATE t108166 SET a = 1 ORDER BY COALESCE(sum(a), 1) LIMIT 1;
685+
686+
subtest end

pkg/sql/logictest/testdata/logic_test/views

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,28 +1900,22 @@ SELECT * FROM v104927
19001900

19011901
subtest end
19021902

1903-
# Regression test for #105259. Do not type-check subqueries in views outside
1904-
# optbuilder. Doing so can cause internal errors.
1905-
subtest regression_105259
1903+
# Regression tests for #105259 and #107654. Do not type-check subqueries in
1904+
# views outside optbuilder. Doing so can cause internal errors.
1905+
subtest regression_105259_107654
19061906

19071907
statement ok
19081908
CREATE TYPE e105259 AS ENUM ('foo');
19091909

1910-
statement ok
1911-
CREATE VIEW v105259 AS
1910+
statement error pgcode 0A000 subqueries are not allowed in casts to enums within view queries
1911+
CREATE VIEW v AS
19121912
SELECT (SELECT 'foo')::e105259
19131913

1914-
query T
1915-
SELECT * FROM v105259
1916-
----
1917-
foo
1918-
1919-
statement ok
1920-
ALTER TYPE e105259 RENAME VALUE 'foo' TO 'bar'
1921-
1922-
# Renaming the enum value corrupts the view. This is expected behavior.
1923-
statement error pgcode 22P02 invalid input value for enum e105259: "foo"
1924-
SELECT * FROM v105259
1914+
statement error pgcode 0A000 subqueries are not allowed in casts to enums within view queries
1915+
CREATE VIEW v AS
1916+
SELECT (
1917+
CASE WHEN true THEN (SELECT 'foo') ELSE NULL END
1918+
)::e105259
19251919

19261920
subtest end
19271921

pkg/sql/opt/optbuilder/scope.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,15 +1358,10 @@ func (s *scope) replaceWindowFn(f *tree.FuncExpr, def *tree.ResolvedFunctionDefi
13581358
// We will be performing type checking on expressions from PARTITION BY and
13591359
// ORDER BY clauses below, and we need the semantic context to know that we
13601360
// are in a window function. InWindowFunc is updated when type checking
1361-
// FuncExpr above, but it is reset upon returning from that, so we need to do
1362-
// this update manually.
1363-
defer func(ctx *tree.SemaContext, prevWindow bool) {
1364-
ctx.Properties.Derived.InWindowFunc = prevWindow
1365-
}(
1366-
s.builder.semaCtx,
1367-
s.builder.semaCtx.Properties.Derived.InWindowFunc,
1368-
)
1369-
s.builder.semaCtx.Properties.Derived.InWindowFunc = true
1361+
// FuncExpr above, but it is reset upon returning from that, so we need to
1362+
// do this update manually.
1363+
defer s.builder.semaCtx.Properties.Ancestors.PopTo(s.builder.semaCtx.Properties.Ancestors)
1364+
s.builder.semaCtx.Properties.Ancestors.Push(tree.WindowFuncAncestor)
13701365

13711366
oldPartitions := f.WindowDef.Partitions
13721367
f.WindowDef.Partitions = make(tree.Exprs, len(oldPartitions))

pkg/sql/opt/optbuilder/srfs.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ func (s *srf) TypeCheck(
5050
// invalid usage here.
5151
return nil, tree.NewInvalidFunctionUsageError(tree.GeneratorClass, ctx.TypeCheckContext())
5252
}
53+
if ctx.Properties.Ancestors.Has(tree.ConditionalAncestor) {
54+
return nil, tree.NewInvalidFunctionUsageError(tree.GeneratorClass, "conditional expressions")
55+
}
5356
if ctx.Properties.Derived.SeenGenerator {
5457
// This error happens if this srf struct is nested inside a raw srf that
5558
// has not yet been replaced. This is possible since scope.replaceSRF first

0 commit comments

Comments
 (0)