Skip to content

Commit

Permalink
Merge #26134
Browse files Browse the repository at this point in the history
26134: opt: Add execbuilder support for ANY operator r=andy-kimball a=andy-kimball

The optbuilder maps the SQL ANY, ALL, and IN operators that use
a subquery into the opt.Any operator. This commit adds execution
support for this operator.

Release note: None

Co-authored-by: Andrew Kimball <[email protected]>
  • Loading branch information
craig[bot] and andy-kimball committed May 28, 2018
2 parents 0530ad4 + 698d8c5 commit 83e98d9
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pkg/sql/opt/exec/execbuilder/scalar_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func init() {
opt.CastOp: (*Builder).buildCast,
opt.CoalesceOp: (*Builder).buildCoalesce,
opt.ArrayOp: (*Builder).buildArray,
opt.AnyOp: (*Builder).buildAny,
opt.UnsupportedExprOp: (*Builder).buildUnsupportedExpr,

// Subquery operators.
Expand Down Expand Up @@ -300,6 +301,31 @@ func (b *Builder) buildArray(ctx *buildScalarCtx, ev memo.ExprView) (tree.TypedE
return tree.NewTypedArray(exprs, ev.Logical().Scalar.Type), nil
}

func (b *Builder) buildAny(ctx *buildScalarCtx, ev memo.ExprView) (tree.TypedExpr, error) {
// Build the execution plan for the input subquery.
plan, err := b.buildRelational(ev.Child(0))
if err != nil {
return nil, err
}

// Construct tuple type of columns in the row.
types := types.TTuple{Types: make([]types.T, plan.outputCols.Len())}
plan.outputCols.ForEach(func(key, val int) {
types.Types[val] = ev.Metadata().ColumnType(opt.ColumnID(key))
})

input := b.addSubquery(exec.SubqueryAnyRows, types, plan.root)

// Build the scalar value that is compared against each row.
scalar, err := b.buildScalar(ctx, ev.Child(1))
if err != nil {
return nil, err
}

cmp := opt.ComparisonOpReverseMap[ev.Private().(opt.Operator)]
return tree.NewTypedComparisonExprWithSubOp(tree.Any, cmp, scalar, input), nil
}

func (b *Builder) buildUnsupportedExpr(
ctx *buildScalarCtx, ev memo.ExprView,
) (tree.TypedExpr, error) {
Expand Down
186 changes: 186 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/select
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,189 @@ filter · · (f float) ·
└── scan · · (f float) ·
· table flt@primary · ·
· spans ALL · ·

# ------------------------------------------------------------------------------
# ANY, ALL tests.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE abc (a INT, b INT, C INT)

statement ok
INSERT INTO abc VALUES (1, 10, 100), (2, 20, 200), (3, 30, 300)

query III
SELECT * FROM abc WHERE a = ANY(SELECT a FROM abc WHERE b = 10)
----
1 10 100

query III
SELECT * FROM abc WHERE a < ANY(SELECT a FROM abc WHERE b = 30) ORDER BY a
----
1 10 100
2 20 200

query III
SELECT * FROM abc WHERE a > ANY(SELECT a FROM abc WHERE b = 30)
----

query III
SELECT * FROM abc WHERE a < ALL(SELECT b FROM abc) ORDER BY a
----
1 10 100
2 20 200
3 30 300

query III
SELECT * FROM abc WHERE a < ALL(SELECT a FROM abc WHERE a >= 2)
----
1 10 100

query III
SELECT * FROM abc WHERE a < ALL(SELECT a FROM abc)
----

# ------------------------------------------------------------------------------
# IN tests.
# ------------------------------------------------------------------------------
# Regression tests for #22670.
query B
SELECT 1 IN (1, 2)
----
true

query B
SELECT NULL IN (1, 2)
----
NULL

query B
SELECT 1 IN (1, NULL)
----
true

query B
SELECT 1 IN (NULL, 2)
----
NULL

query B
SELECT (1, NULL) IN ((1, 1))
----
NULL

query B
SELECT (2, NULL) IN ((1, 1))
----
false

query B
SELECT (1, 1) IN ((1, NULL))
----
NULL

query B
SELECT (1, 1) IN ((2, NULL))
----
false

# Tests with a tuple coming from a subquery.
query B
SELECT NULL::int IN (SELECT * FROM (VALUES (1)) AS t(a))
----
NULL

query B
SELECT (1, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (2, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
false

query B
SELECT (NULL::int, 1) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (NULL::int, 2) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
false

query B
SELECT (NULL::int, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT NULL::int NOT IN (SELECT * FROM (VALUES (1)) AS t(a))
----
NULL

query B
SELECT (1, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (2, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
true

query B
SELECT (NULL::int, 1) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (NULL::int, 2) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
true

query B
SELECT (NULL::int, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

# Tests with an empty IN tuple.
query B
SELECT NULL::int IN (SELECT * FROM (VALUES (1)) AS t(a) WHERE a > 1)
----
false

query B
SELECT (1, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT (NULL::int, 1) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT (NULL::int, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT NULL::int NOT IN (SELECT * FROM (VALUES (1)) AS t(a) WHERE a > 1)
----
true

query B
SELECT (1, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true

query B
SELECT (NULL::int, 1) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true

query B
SELECT (NULL::int, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true
5 changes: 5 additions & 0 deletions pkg/sql/opt/exec/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ const (
// SubqueryOneRow - the subquery expects at most one row; the result is that
// row (as a single value or a tuple), or NULL if there were no rows.
SubqueryOneRow
// SubqueryAnyRows - the subquery is an argument to ANY. Any number of rows
// expected; the result is a sorted, distinct tuple of rows (i.e. it has been
// normalized). As a special case, if there is only one column selected, the
// result is a tuple of the selected values (instead of a tuple of 1-tuples).
SubqueryAnyRows
)

// ColumnOrdinal is the 0-based ordinal index of a column produced by a Node.
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/opt_exec_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ func (ef *execFactory) ConstructPlan(
out.execMode = execModeExists
case exec.SubqueryOneRow:
out.execMode = execModeOneRow
case exec.SubqueryAnyRows:
out.execMode = execModeAllRowsNormalized
default:
return nil, errors.Errorf("invalid SubqueryMode %d", in.Mode)
}
Expand Down

0 comments on commit 83e98d9

Please sign in to comment.