From 908fe7b48c963c7bc71d3ab7c7cbd651bbcac486 Mon Sep 17 00:00:00 2001 From: Solon Gordon Date: Thu, 11 Jul 2019 11:24:19 -0400 Subject: [PATCH] exec: bail out on mixed type expressions Since our vectorized projection and selection operators currently only handle homogeneous types, I added logic to the planner which detects mixed types and errors out. Fixes #38798 Release note: None --- pkg/sql/distsqlrun/column_exec_setup.go | 44 ++++++++++++++----- .../logictest/testdata/logic_test/vectorize | 12 +++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/pkg/sql/distsqlrun/column_exec_setup.go b/pkg/sql/distsqlrun/column_exec_setup.go index d32515291462..42dafa232665 100644 --- a/pkg/sql/distsqlrun/column_exec_setup.go +++ b/pkg/sql/distsqlrun/column_exec_setup.go @@ -543,6 +543,9 @@ func newColOperator( func planSelectionOperators( ctx *tree.EvalContext, expr tree.TypedExpr, columnTypes []semtypes.T, input exec.Operator, ) (op exec.Operator, resultIdx int, ct []semtypes.T, err error) { + if err := assertHomogeneousTypes(expr); err != nil { + return op, resultIdx, ct, err + } switch t := expr.(type) { case *tree.IndexedVar: return exec.NewBoolVecToSelOp(input, t.Idx), -1, columnTypes, nil @@ -583,12 +586,6 @@ func planSelectionOperators( if err != nil { return nil, resultIdx, ct, err } - if !ct[leftIdx].Identical(&ct[rightIdx]) { - err = errors.Errorf( - "comparison between %s and %s is unhandled", ct[leftIdx].Family(), - ct[rightIdx].Family()) - return nil, resultIdx, ct, err - } op, err := exec.GetSelectionOperator(typ, cmpOp, rightOp, leftIdx, rightIdx) return op, resultIdx, ct, err default: @@ -603,6 +600,9 @@ func planSelectionOperators( func planProjectionOperators( ctx *tree.EvalContext, expr tree.TypedExpr, columnTypes []semtypes.T, input exec.Operator, ) (op exec.Operator, resultIdx int, ct []semtypes.T, err error) { + if err := assertHomogeneousTypes(expr); err != nil { + return op, resultIdx, ct, err + } resultIdx = -1 switch t := expr.(type) { case *tree.IndexedVar: @@ -693,18 +693,38 @@ func planProjectionExpr( if err != nil { return nil, resultIdx, nil, err } - if !ct[leftIdx].Identical(&ct[rightIdx]) { - err = errors.Errorf( - "projection on %s and %s is unhandled", ct[leftIdx].Family(), - ct[rightIdx].Family()) - return nil, resultIdx, ct, err - } resultIdx = len(ct) op, err = exec.GetProjectionOperator(typ, binOp, rightOp, leftIdx, rightIdx, resultIdx) ct = append(ct, *typ) return op, resultIdx, ct, err } +// assertHomogeneousTypes checks that the left and right sides of an expression +// have identical types. (Vectorized execution does not yet handle mixed types.) +// For BinaryExprs, it also checks that the result type matches, since this is +// not the case for certain operations like integer division. +func assertHomogeneousTypes(expr tree.TypedExpr) error { + switch t := expr.(type) { + case *tree.BinaryExpr: + left := t.TypedLeft().ResolvedType() + right := t.TypedRight().ResolvedType() + result := t.ResolvedType() + if !left.Identical(right) { + return errors.Errorf("BinaryExpr on %s and %s is unhandled", left, right) + } + if !left.Identical(result) { + return errors.Errorf("BinaryExpr on %s with %s result is unhandled", left, result) + } + case *tree.ComparisonExpr: + left := t.TypedLeft().ResolvedType() + right := t.TypedRight().ResolvedType() + if !left.Identical(right) { + return errors.Errorf("ComparisonExpr on %s and %s is unhandled", left, right) + } + } + return nil +} + // wrapWithVectorizedStatsCollector creates a new exec.VectorizedStatsCollector // that wraps op and connects the newly created wrapper with those // corresponding to operators in inputs (the latter must have already been diff --git a/pkg/sql/logictest/testdata/logic_test/vectorize b/pkg/sql/logictest/testdata/logic_test/vectorize index 5c4609c2aeaf..da6f900becaa 100644 --- a/pkg/sql/logictest/testdata/logic_test/vectorize +++ b/pkg/sql/logictest/testdata/logic_test/vectorize @@ -400,3 +400,15 @@ query O SELECT * FROM t38754 ---- 1 + +# Test integer division. (Should fall back due to decimal result.) +query T +SELECT a/b FROM a WHERE b = 2 +---- +0.5 + +# Test mixed types comparison. (Should also fall back.) +query I +SELECT b FROM a WHERE b < 0.5 +---- +0