Skip to content

Commit 5373cfc

Browse files
authored
Merge pull request #151160 from yuzefovich/backport25.3-151093
release-25.3: colexec: fix column type when ConstNullOp is used
2 parents 8cd431d + 3042bae commit 5373cfc

File tree

7 files changed

+46
-17
lines changed

7 files changed

+46
-17
lines changed

pkg/sql/colexec/colbuilder/execplan.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,7 +2384,7 @@ func planProjectionOperators(
23842384
if datumType.Family() == types.UnknownFamily {
23852385
// We handle Unknown type by planning a special constant null
23862386
// operator.
2387-
return colexecbase.NewConstNullOp(allocator, input, resultIdx), nil
2387+
return colexecbase.NewConstNullOp(allocator, datumType, input, resultIdx), nil
23882388
}
23892389
constVal := colconv.GetDatumToPhysicalFn(datumType)(datum)
23902390
return colexecbase.NewConstOp(allocator, input, datumType, constVal, resultIdx)
@@ -2864,7 +2864,7 @@ func planProjectionExpr(
28642864
if !calledOnNullInput && right == tree.DNull {
28652865
// If the right is NULL and the operator is not called on NULL,
28662866
// simply project NULL.
2867-
op = colexecbase.NewConstNullOp(allocator, input, resultIdx)
2867+
op = colexecbase.NewConstNullOp(allocator, outputType, input, resultIdx)
28682868
} else if isCmpProjOp {
28692869
// Use optimized operators for special cases.
28702870
switch cmpProjOp.Symbol {

pkg/sql/colexec/colexecbase/const.eg.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/colexec/colexecbase/const_tmpl.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,12 @@ func (c const_TYPEOp) Next() coldata.Batch {
127127
// {{end}}
128128
// {{end}}
129129

130-
// NewConstNullOp creates a new operator that produces a constant (untyped) NULL
131-
// value at index outputIdx.
130+
// NewConstNullOp creates a new operator that produces a constant NULL value at
131+
// index outputIdx. The column will be typed according to the passed in 't'.
132132
func NewConstNullOp(
133-
allocator *colmem.Allocator, input colexecop.Operator, outputIdx int,
133+
allocator *colmem.Allocator, t *types.T, input colexecop.Operator, outputIdx int,
134134
) colexecop.Operator {
135-
input = colexecutils.NewVectorTypeEnforcer(allocator, input, types.Unknown, outputIdx)
135+
input = colexecutils.NewVectorTypeEnforcer(allocator, input, t, outputIdx)
136136
return &constNullOp{
137137
OneInputHelper: colexecop.MakeOneInputHelper(input),
138138
outputIdx: outputIdx,

pkg/sql/sem/eval/eval_test/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ go_test(
3434
"//pkg/util/log",
3535
"//pkg/util/randutil",
3636
"@com_github_cockroachdb_datadriven//:datadriven",
37+
"@com_github_cockroachdb_errors//:errors",
3738
"@com_github_stretchr_testify//require",
3839
],
3940
)

pkg/sql/sem/eval/eval_test/eval_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/cockroachdb/cockroach/pkg/util/log"
3535
"github.com/cockroachdb/cockroach/pkg/util/randutil"
3636
"github.com/cockroachdb/datadriven"
37+
"github.com/cockroachdb/errors"
3738
"github.com/stretchr/testify/require"
3839
)
3940

@@ -156,6 +157,8 @@ func TestEval(t *testing.T) {
156157
return strings.TrimSpace(d.Expected)
157158
}
158159
semaCtx := tree.MakeSemaContext(nil /* resolver */)
160+
// In 50% cases, disable "always null" short-circuiting.
161+
semaCtx.TestingKnobs.DisallowAlwaysNullShortCut = rng.Intn(2) == 1
159162
typedExpr, err := expr.TypeCheck(ctx, &semaCtx, types.AnyElement)
160163
if err != nil {
161164
// Skip this test as it's testing an expected error which would be
@@ -221,6 +224,9 @@ func TestEval(t *testing.T) {
221224
row, meta := mat.Next()
222225
if meta != nil {
223226
if meta.Err != nil {
227+
if errors.IsAssertionFailure(meta.Err) {
228+
t.Fatalf("%+v", meta.Err)
229+
}
224230
return fmt.Sprint(meta.Err)
225231
}
226232
t.Fatalf("unexpected metadata: %+v", meta)

pkg/sql/sem/eval/testdata/eval/boolean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,10 @@ eval
114114
true OR (3 = 1)
115115
----
116116
true
117+
118+
# Regression test for incorrect typing of NULL column in the vectorized engine
119+
# (#151020).
120+
eval
121+
('foo' LIKE NULL) OR true
122+
----
123+
true

pkg/sql/sem/tree/type_check.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree/treecmp"
1717
"github.com/cockroachdb/cockroach/pkg/sql/sem/volatility"
1818
"github.com/cockroachdb/cockroach/pkg/sql/types"
19+
"github.com/cockroachdb/cockroach/pkg/util/buildutil"
1920
"github.com/cockroachdb/cockroach/pkg/util/collatedstring"
2021
"github.com/cockroachdb/cockroach/pkg/util/duration"
2122
"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
@@ -78,6 +79,13 @@ type SemaContext struct {
7879
// UsePre_25_2VariadicBuiltins is set to true when we should use the pre-25.2
7980
// variadic builtins behavior.
8081
UsePre_25_2VariadicBuiltins bool
82+
83+
// TestingKnobs only has effect under buildutil.CrdbTestBuild.
84+
TestingKnobs struct {
85+
// DisallowAlwaysNullShortCut, if set, disables short-circuiting logic
86+
// for "always NULL" case during type checking.
87+
DisallowAlwaysNullShortCut bool
88+
}
8189
}
8290

8391
// SemaProperties is a holder for required and derived properties
@@ -2370,9 +2378,12 @@ func typeCheckComparisonOpWithSubOperator(
23702378
rightTyped = array
23712379
cmpTypeRight = retType
23722380

2373-
// Return early without looking up a CmpOp if the comparison type is types.Null.
2374-
if leftTyped.ResolvedType().Family() == types.UnknownFamily || retType.Family() == types.UnknownFamily {
2375-
return leftTyped, rightTyped, nil, true /* alwaysNull */, nil
2381+
// Return early without looking up a CmpOp if the comparison type is types.Null
2382+
// (unless the short-cut is disabled in tests).
2383+
if !buildutil.CrdbTestBuild || semaCtx == nil || !semaCtx.TestingKnobs.DisallowAlwaysNullShortCut {
2384+
if leftTyped.ResolvedType().Family() == types.UnknownFamily || retType.Family() == types.UnknownFamily {
2385+
return leftTyped, rightTyped, nil, true /* alwaysNull */, nil
2386+
}
23762387
}
23772388
} else {
23782389
// If the right expression is not an array constructor, we type the left
@@ -2403,8 +2414,10 @@ func typeCheckComparisonOpWithSubOperator(
24032414
}
24042415

24052416
rightReturn := rightTyped.ResolvedType()
2406-
if rightReturn.Family() == types.UnknownFamily {
2407-
return leftTyped, rightTyped, nil, true /* alwaysNull */, nil
2417+
if !buildutil.CrdbTestBuild || semaCtx == nil || !semaCtx.TestingKnobs.DisallowAlwaysNullShortCut {
2418+
if rightReturn.Family() == types.UnknownFamily {
2419+
return leftTyped, rightTyped, nil, true /* alwaysNull */, nil
2420+
}
24082421
}
24092422

24102423
switch rightReturn.Family() {
@@ -2739,8 +2752,10 @@ func typeCheckComparisonOp(
27392752
break
27402753
}
27412754
}
2742-
if noneAcceptNull {
2743-
return leftExpr, rightExpr, nil, true /* alwaysNull */, nil
2755+
if !buildutil.CrdbTestBuild || semaCtx == nil || !semaCtx.TestingKnobs.DisallowAlwaysNullShortCut {
2756+
if noneAcceptNull {
2757+
return leftExpr, rightExpr, nil, true /* alwaysNull */, nil
2758+
}
27442759
}
27452760
}
27462761
}

0 commit comments

Comments
 (0)