Skip to content

Commit

Permalink
optbuilder: try harder to propagate types in UNION
Browse files Browse the repository at this point in the history
Release note: None
  • Loading branch information
jordanlewis committed Jul 19, 2019
1 parent e86e27a commit 0180907
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 58 deletions.
25 changes: 14 additions & 11 deletions pkg/sql/logictest/testdata/logic_test/union
Original file line number Diff line number Diff line change
Expand Up @@ -209,21 +209,24 @@ SELECT 1, 2 INTERSECT SELECT 3
query error pgcode 42601 each EXCEPT query must have the same number of columns: 2 vs 1
SELECT 1, 2 EXCEPT SELECT 3

query error pgcode 42804 UNION types int and string cannot be matched
SELECT 1 UNION SELECT '3'

query error pgcode 42804 INTERSECT types int and string cannot be matched
SELECT 1 INTERSECT SELECT '3'

query error pgcode 42804 EXCEPT types int and string cannot be matched
SELECT 1 EXCEPT SELECT '3'
# These work with the optimizer on, but not with it off. Skip for now.
# TODO(jordan,radu): re-enable when optimizer=off goes away.

# query error pgcode 42804 UNION types int and string cannot be matched
# SELECT 1 UNION SELECT '3'
#
# query error pgcode 42804 INTERSECT types int and string cannot be matched
# SELECT 1 INTERSECT SELECT '3'
#
# query error pgcode 42804 EXCEPT types int and string cannot be matched
# SELECT 1 EXCEPT SELECT '3'
#
# query error UNION types int\[] and string\[] cannot be matched
# SELECT ARRAY[1] UNION ALL SELECT ARRAY['foo']

query error pgcode 42703 column \"z\" does not exist
SELECT 1 UNION SELECT 3 ORDER BY z

query error UNION types int\[] and string\[] cannot be matched
SELECT ARRAY[1] UNION ALL SELECT ARRAY['foo']

# Check that UNION permits columns of different visible types

statement ok
Expand Down
16 changes: 8 additions & 8 deletions pkg/sql/opt/memo/testdata/stats/set
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ WHERE a IS NULL and b
except
├── columns: a:5(int) b:2(bool!null)
├── left columns: column1:5(int) column2:2(bool!null)
├── right columns: column1:3(int) column2:6(bool)
├── right columns: column1:3(int) column2:4(bool)
├── cardinality: [1 - 1]
├── stats: [rows=1, distinct(2,5)=1, null(2,5)=1]
├── key: (2,5)
Expand All @@ -859,11 +859,11 @@ except
│ ├── fd: ()-->(2,5)
│ └── (true, NULL) [type=tuple{bool, int}]
└── values
├── columns: column1:3(int!null) column2:6(bool!null)
├── columns: column1:3(int!null) column2:4(bool!null)
├── cardinality: [0 - 0]
├── stats: [rows=0, distinct(3,6)=0, null(3,6)=0]
├── stats: [rows=0, distinct(3,4)=0, null(3,4)=0]
├── key: ()
└── fd: ()-->(3,6)
└── fd: ()-->(3,4)

# Regression test for #36147.
opt
Expand Down Expand Up @@ -920,7 +920,7 @@ sort
└── intersect
├── columns: column1:1(int)
├── left columns: column1:1(int)
├── right columns: column1:3(int)
├── right columns: column1:2(int)
├── cardinality: [0 - 1]
├── stats: [rows=1, distinct(1)=1, null(1)=0]
├── key: (1)
Expand All @@ -932,9 +932,9 @@ sort
│ ├── fd: ()-->(1)
│ └── (1,) [type=tuple{int}]
└── values
├── columns: column1:3(int)
├── columns: column1:2(int)
├── cardinality: [1 - 1]
├── stats: [rows=1, distinct(3)=1, null(3)=1]
├── stats: [rows=1, distinct(2)=1, null(2)=1]
├── key: ()
├── fd: ()-->(3)
├── fd: ()-->(2)
└── (NULL,) [type=tuple{int}]
123 changes: 84 additions & 39 deletions pkg/sql/opt/optbuilder/testdata/union
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,11 @@ build
SELECT x, pg_typeof(y) FROM (SELECT 1 AS a, 3 AS b UNION ALL SELECT 2 AS a, NULL AS b) AS t(x, y)
----
project
├── columns: x:5(int!null) pg_typeof:8(string)
├── columns: x:5(int!null) pg_typeof:7(string)
├── union-all
│ ├── columns: a:5(int!null) b:6(int)
│ ├── left columns: a:1(int) b:2(int)
│ ├── right columns: a:3(int) b:7(int)
│ ├── right columns: a:3(int) b:4(int)
│ ├── project
│ │ ├── columns: a:1(int!null) b:2(int!null)
│ │ ├── values
Expand All @@ -367,17 +367,13 @@ project
│ │ ├── const: 1 [type=int]
│ │ └── const: 3 [type=int]
│ └── project
│ ├── columns: b:7(int) a:3(int!null)
│ ├── project
│ │ ├── columns: a:3(int!null) b:4(unknown)
│ │ ├── values
│ │ │ └── tuple [type=tuple]
│ │ └── projections
│ │ ├── const: 2 [type=int]
│ │ └── null [type=unknown]
│ ├── columns: a:3(int!null) b:4(int)
│ ├── values
│ │ └── tuple [type=tuple]
│ └── projections
│ ├── const: 2 [type=int]
│ └── cast: INT8 [type=int]
│ └── variable: b [type=unknown]
│ └── null [type=unknown]
└── projections
└── function: pg_typeof [type=string]
└── variable: b [type=int]
Expand Down Expand Up @@ -732,17 +728,62 @@ error (42601): each EXCEPT query must have the same number of columns: 2 vs 1
build
SELECT 1 UNION SELECT '3'
----
error (42804): UNION types int and string cannot be matched
union
├── columns: "?column?":3(int!null)
├── left columns: "?column?":1(int)
├── right columns: "?column?":2(int)
├── project
│ ├── columns: "?column?":1(int!null)
│ ├── values
│ │ └── tuple [type=tuple]
│ └── projections
│ └── const: 1 [type=int]
└── project
├── columns: "?column?":2(int!null)
├── values
│ └── tuple [type=tuple]
└── projections
└── const: 3 [type=int]

build
SELECT 1 INTERSECT SELECT '3'
----
error (42804): INTERSECT types int and string cannot be matched
intersect
├── columns: "?column?":1(int!null)
├── left columns: "?column?":1(int!null)
├── right columns: "?column?":2(int)
├── project
│ ├── columns: "?column?":1(int!null)
│ ├── values
│ │ └── tuple [type=tuple]
│ └── projections
│ └── const: 1 [type=int]
└── project
├── columns: "?column?":2(int!null)
├── values
│ └── tuple [type=tuple]
└── projections
└── const: 3 [type=int]

build
SELECT 1 EXCEPT SELECT '3'
----
error (42804): EXCEPT types int and string cannot be matched
except
├── columns: "?column?":1(int!null)
├── left columns: "?column?":1(int!null)
├── right columns: "?column?":2(int)
├── project
│ ├── columns: "?column?":1(int!null)
│ ├── values
│ │ └── tuple [type=tuple]
│ └── projections
│ └── const: 1 [type=int]
└── project
├── columns: "?column?":2(int!null)
├── values
│ └── tuple [type=tuple]
└── projections
└── const: 3 [type=int]

build
SELECT 1 UNION SELECT 3 ORDER BY z
Expand All @@ -752,7 +793,17 @@ error (42703): column "z" does not exist
build
SELECT ARRAY[1] UNION ALL SELECT ARRAY['foo']
----
error (42804): UNION types int[] and string[] cannot be matched
error (22P02): could not parse "foo" as type int: strconv.ParseInt: parsing "foo": invalid syntax

build
SELECT ARRAY['foo'] UNION ALL SELECT ARRAY[1]
----
error (42804): UNION types string[] and int[] cannot be matched

build
SELECT ARRAY[1] UNION ALL SELECT ARRAY[1.2]
----
error (42804): UNION types int[] and decimal[] cannot be matched

exec-ddl
CREATE TABLE t.xy (x STRING NOT NULL, y STRING NOT NULL)
Expand Down Expand Up @@ -874,7 +925,7 @@ VALUES (3, NULL), (NULL, 'x') INTERSECT VALUES (1, NULL), (2, NULL)
intersect
├── columns: column1:1(int) column2:2(string)
├── left columns: column1:1(int) column2:2(string)
├── right columns: column1:3(int) column2:5(string)
├── right columns: column1:3(int) column2:4(string)
├── values
│ ├── columns: column1:1(int) column2:2(string)
│ ├── tuple [type=tuple{int, string}]
Expand All @@ -885,27 +936,24 @@ intersect
│ ├── cast: INT8 [type=int]
│ │ └── null [type=unknown]
│ └── const: 'x' [type=string]
└── project
├── columns: column2:5(string) column1:3(int!null)
├── values
│ ├── columns: column1:3(int!null) column2:4(unknown)
│ ├── tuple [type=tuple{int, unknown}]
│ │ ├── const: 1 [type=int]
│ │ └── null [type=unknown]
│ └── tuple [type=tuple{int, unknown}]
│ ├── const: 2 [type=int]
└── values
├── columns: column1:3(int!null) column2:4(string)
├── tuple [type=tuple{int, string}]
│ ├── const: 1 [type=int]
│ └── cast: STRING [type=string]
│ └── null [type=unknown]
└── projections
└── tuple [type=tuple{int, string}]
├── const: 2 [type=int]
└── cast: STRING [type=string]
└── variable: column2 [type=unknown]
└── null [type=unknown]

build
VALUES (NULL, NULL), (NULL, 'x') UNION ALL VALUES (1, NULL), (2, NULL)
----
union-all
├── columns: column1:5(int) column2:6(string)
├── left columns: column1:7(int) column2:2(string)
├── right columns: column1:3(int) column2:8(string)
├── right columns: column1:3(int) column2:4(string)
├── project
│ ├── columns: column1:7(int) column2:2(string)
│ ├── values
Expand All @@ -920,19 +968,16 @@ union-all
│ └── projections
│ └── cast: INT8 [type=int]
│ └── variable: column1 [type=unknown]
└── project
├── columns: column2:8(string) column1:3(int!null)
├── values
│ ├── columns: column1:3(int!null) column2:4(unknown)
│ ├── tuple [type=tuple{int, unknown}]
│ │ ├── const: 1 [type=int]
│ │ └── null [type=unknown]
│ └── tuple [type=tuple{int, unknown}]
│ ├── const: 2 [type=int]
└── values
├── columns: column1:3(int!null) column2:4(string)
├── tuple [type=tuple{int, string}]
│ ├── const: 1 [type=int]
│ └── cast: STRING [type=string]
│ └── null [type=unknown]
└── projections
└── tuple [type=tuple{int, string}]
├── const: 2 [type=int]
└── cast: STRING [type=string]
└── variable: column2 [type=unknown]
└── null [type=unknown]

build
VALUES (NULL, NULL), (NULL, NULL) UNION ALL VALUES (NULL, NULL), (NULL, NULL)
Expand Down
8 changes: 8 additions & 0 deletions pkg/sql/opt/optbuilder/union.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ func (b *Builder) buildUnion(
clause *tree.UnionClause, desiredTypes []*types.T, inScope *scope,
) (outScope *scope) {
leftScope := b.buildSelect(clause.Left, desiredTypes, inScope)
// Try to propagate types left-to-right, if we didn't already have desired
// types.
if len(desiredTypes) == 0 {
desiredTypes = make([]*types.T, len(leftScope.cols))
for i := range leftScope.cols {
desiredTypes[i] = leftScope.cols[i].typ
}
}
rightScope := b.buildSelect(clause.Right, desiredTypes, inScope)

// Remove any hidden columns, as they are not included in the Union.
Expand Down

0 comments on commit 0180907

Please sign in to comment.