Skip to content

Commit

Permalink
sql: simplify the subquery typing rules
Browse files Browse the repository at this point in the history
The simplification allows Cockroach to support a strict superset of the
queries Postgres supports.

Release note: None
  • Loading branch information
petermattis committed Dec 28, 2017
1 parent ad26b2d commit 8fe1e91
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 43 deletions.
14 changes: 10 additions & 4 deletions pkg/sql/logictest/testdata/logic_test/subquery
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,19 @@ SELECT (SELECT (1, 2)) IN ((1, 2))
----
true

query error unsupported comparison operator: <tuple{int, int}> IN <tuple{tuple{tuple{int, int}}}>
# Postgres cannot handle this query, even though it seems sensical:
# ERROR: subquery must return only one column
# LINE 1: select (select 1, 2) in (select (1, 2));
# ^
query B
SELECT (SELECT 1, 2) IN (SELECT (1, 2))
----
true

# Postgres successfully handles this query (returning true), even
# though doing so seems at odds with other rules.
query error unsupported comparison operator: <tuple{int, int}> IN <tuple{tuple{tuple{int, int}}}>
query B
SELECT (SELECT (1, 2)) IN (SELECT (1, 2))
----
true

query B
SELECT 1 = ANY(SELECT 1)
Expand Down
6 changes: 4 additions & 2 deletions pkg/sql/logictest/testdata/logic_test/typing
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,15 @@ true
statement error unsupported comparison operator: <int> IN <tuple{string}>
SELECT 1 IN (SELECT 'a')

statement error unsupported comparison operator: <int> IN <tuple{tuple{tuple{int, int}}}>
statement error unsupported comparison operator: <int> IN <tuple{tuple{int, int}}>
SELECT 1 IN (SELECT (1, 2))

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

statement error unsupported comparison operator: <tuple{int, int}> IN <tuple{tuple{tuple{int, int}}}>
query B
SELECT (1, 2) IN (SELECT (1, 2))
----
true
60 changes: 23 additions & 37 deletions pkg/sql/subquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,44 +378,30 @@ func (v *subqueryVisitor) replaceSubquery(

result := &subquery{subquery: sub, plan: plan}

wrap := true
if len(cols) == 1 {
if !multiRow {
// The subquery has only a single column and is not in a multi-row
// context, we don't want to wrap the type in a tuple. For example:
//
// SELECT (SELECT 1)
//
// and
//
// SELECT (SELECT (1, 2))
//
// This will result in the types "int" and "tuple{int,int}" respectively.
wrap = false
} else if !types.FamTuple.FamilyEqual(cols[0].Typ) {
// The subquery has only a single column and is in a multi-row
// context. We only wrap if the type of the result column is not a
// tuple. For example:
//
// SELECT 1 IN (SELECT 1)
//
// The type of the subquery will be "tuple{int}". Now consider this
// invalid query:
//
// SELECT (1, 2) IN (SELECT (1, 2))
//
// We want the type of the subquery to be "tuple{tuple{tuple{int,int}}}"
// in order to distinguish it from this semantically valid query:
//
// SELECT (1, 2) IN (SELECT 1, 2)
//
// In this query, the subquery has the type "tuple{tuple{int,int}}"
// making the IN expression valid.
wrap = false
}
}

if !wrap {
// Whenever the subquery returns a single column we don't wrap the type in
// a tuple. This differs from Postgres's behavior. For example:
//
// SELECT (1, 2) IN (SELECT (1, 2))
//
// Postgres thinks this query is not valid, but Cockroach does and treats
// it the same as:
//
// SELECT (1, 2) IN (SELECT 1, 2)
//
// And:
//
// SELECT (1, 2) IN ((1, 2))
//
// The Postgres rules are somewhat complex. The following works in both
// Postgres and Cockroach:
//
// SELECT (SELECT (1, 2)) IN (SELECT (1, 2))
//
// What rule allows that to work in Postgres, but not the first query
// above? The Cockroach rule is simple: if the subquery returns on a single
// column, use the type of that column as the type for the subquery. If the
// subquery returns multiple rows, wrap the type in a tuple.
result.typ = cols[0].Typ
} else {
colTypes := make(types.TTuple, len(cols))
Expand Down

0 comments on commit 8fe1e91

Please sign in to comment.