Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opt: Add execbuilder support for ANY operator #26134

Merged
merged 1 commit into from
May 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -301,6 +302,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