Skip to content

Commit

Permalink
opt: add optimizer support for numeric references
Browse files Browse the repository at this point in the history
This commit adds support in the optimizer for the following
type of query:

`SELECT * FROM [53 as t]`

Release note: None
  • Loading branch information
madhavsuresh committed Aug 6, 2018
1 parent 6e2bcfe commit 2aca2b1
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 8 deletions.
5 changes: 5 additions & 0 deletions pkg/sql/opt/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ type Table interface {
// position within the table, where i < ColumnCount.
Column(i int) Column

// LookupColumnOrdinal returns the ordinal of the column with the given ID. A
// cache makes the lookup O(1).
LookupColumnOrdinal(colID uint32) (int, error)

// IndexCount returns the number of indexes defined on this table. This
// includes the primary index, so the count is always >= 1.
IndexCount() int
Expand All @@ -219,6 +223,7 @@ type Catalog interface {
// FindTable returns a Table interface for the database table matching the
// given table name. Returns an error if the table does not exist.
FindTable(ctx context.Context, name *tree.TableName) (Table, error)
FindTableByTableRef(ctx context.Context, tableID int64) (Table, error)
}

// FormatCatalogTable nicely formats a catalog table using a treeprinter for
Expand Down
202 changes: 202 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/select
Original file line number Diff line number Diff line change
@@ -1,5 +1,207 @@
# LogicTest: local-opt


# ------------------------------------------------------------------------------
# Numeric References Tests.
# These are put at the beginning of the file to ensure the numeric table
# reference is 53 (the numeric reference of the first table).
# If the numbering scheme in cockroach changes, this test will break.
# TODO(madhavsuresh): get the numeric reference ID in a less brittle fashion
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE num_ref (a INT PRIMARY KEY, xx INT, b INT, c INT, INDEX bc (b,c))

statement ok
ALTER TABLE num_ref RENAME COLUMN b TO d

statement ok
ALTER TABLE num_ref RENAME COLUMN a TO p

statement ok
ALTER TABLE num_ref DROP COLUMN xx

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53 AS num_ref_alias]
----
scan · · (p, d, c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]
----
scan · · (c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1,4) AS num_ref_alias]
----
scan · · (p, c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1,3,4) AS num_ref_alias]
----
scan · · (p, d, c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias]
----
render · · (c, d, p) ·
│ render 0 c · ·
│ render 1 d · ·
│ render 2 p · ·
└── scan · · (p, d, c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias(col1,col2,col3)]
----
render · · (col1, col2, col3) ·
│ render 0 c · ·
│ render 1 d · ·
│ render 2 p · ·
└── scan · · (p, d, c) ·
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias]@bc
----
scan · · (c, d, p) p!=NULL; weak-key(c,d,p)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@bc
----
render · · (c) ·
│ render 0 num_ref_alias.c · ·
└── scan · · (c, p[hidden,omitted], d[hidden,omitted]) p!=NULL; weak-key(c,p,d)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@bc
----
render · · (d) ·
│ render 0 num_ref_alias.d · ·
└── scan · · (d, p[hidden,omitted], c[hidden,omitted]) p!=NULL; weak-key(d,p,c)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@bc
----
render · · (p) p!=NULL
│ render 0 num_ref_alias.p · ·
└── scan · · (p, d[hidden,omitted], c[hidden,omitted]) p!=NULL; weak-key(p,d,c)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@[1]
----
render · · (p) p!=NULL; key(p)
│ render 0 num_ref_alias.p · ·
└── scan · · (p, d[hidden,omitted], c[hidden,omitted]) p!=NULL; key(p)
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@[2]
----
render · · (p) p!=NULL
│ render 0 num_ref_alias.p · ·
└── scan · · (p, d[hidden,omitted], c[hidden,omitted]) p!=NULL; weak-key(p,d,c)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@[1]
----
render · · (d) ·
│ render 0 num_ref_alias.d · ·
└── scan · · (d, p[hidden,omitted], c[hidden,omitted]) p!=NULL; key(p)
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@[2]
----
render · · (d) ·
│ render 0 num_ref_alias.d · ·
└── scan · · (d, p[hidden,omitted], c[hidden,omitted]) p!=NULL; weak-key(d,p,c)
· table num_ref@bc · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@[1]
----
render · · (c) ·
│ render 0 num_ref_alias.c · ·
└── scan · · (c, p[hidden,omitted], d[hidden,omitted]) p!=NULL; key(p)
· table num_ref@primary · ·
· spans ALL · ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@[2]
----
render · · (c) ·
│ render 0 num_ref_alias.c · ·
└── scan · · (c, p[hidden,omitted], d[hidden,omitted]) p!=NULL; weak-key(c,p,d)
· table num_ref@bc · ·
· spans ALL · ·

query error pq: descriptor not found
EXPLAIN (VERBOSE) SELECT * FROM [666(1) AS num_ref_alias]

query error pq: column \[666\] does not exist
EXPLAIN (VERBOSE) SELECT * FROM [53(666) AS num_ref_alias]

query error pq: column \[2\] does not exist
EXPLAIN (VERBOSE) SELECT * FROM [53(2) AS num_ref_alias]

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

query error pq: cannot use "\*" without a FROM clause
SELECT * FROM [53() AS num_ref_alias]

query III
SELECT * FROM [53(4,3,1) AS num_ref_alias]
----
100 10 1
200 20 2
300 30 3

query I
SELECT * FROM [53(4) AS num_ref_alias]@[2]
----
100
200
300

query I
SELECT * FROM [53(1) AS num_ref_alias]@[1]
----
1
2
3

query III
SELECT * FROM [53(1,3,4) AS num_ref_alias(col1,col2,col3)]
----
1 10 100
2 20 200
3 30 300


# ------------------------------------------------------------------------------
# Basic filter combinations.
# ------------------------------------------------------------------------------
Expand Down
57 changes: 56 additions & 1 deletion pkg/sql/opt/optbuilder/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ func (b *Builder) buildTable(texpr tree.TableExpr, inScope *scope) (outScope *sc
outScope = b.buildStmt(source.Statement, inScope)
return outScope

case *tree.TableRef:
tab := b.resolveTableRef(source)
outScope = b.buildScanWithTableRef(tab, tab.TabName(), inScope, source)
b.renameSource(source.As, outScope)
return outScope

default:
panic(unimplementedf("not yet implemented: table expr: %T", texpr))
}
Expand Down Expand Up @@ -139,6 +145,56 @@ func (b *Builder) renameSource(as tree.AliasClause, scope *scope) {
}
}

func (b *Builder) buildScanWithTableRef(tab opt.Table, tn *tree.TableName, inScope *scope,
ref *tree.TableRef) (outScope *scope) {

tabName := tree.AsStringWithFlags(tn, b.FmtFlags)
tabID := b.factory.Metadata().AddTableWithName(tab, tabName)

var colsToAdd []int
// See tree.TableRef: "Note that a nil [Columns] array means 'unspecified' (all columns)."
// whereas an array of length 0 means 'zero columns'.
if ref.Columns == nil {
for i := 0; i < tab.ColumnCount(); i++ {
colsToAdd = append(colsToAdd, i)
}
} else {
for _, c := range ref.Columns {
ordinalCol, error := tab.LookupColumnOrdinal(uint32(c))
if error != nil {
panic(builderError{error})
}
colsToAdd = append(colsToAdd, ordinalCol)
}
}
var tabCols opt.ColSet
outScope = inScope.push()
for _, i := range colsToAdd {
col := tab.Column(i)
colID := b.factory.Metadata().TableColumn(tabID, i)
name := tree.Name(col.ColName())
colProps := scopeColumn{
id: colID,
origName: name,
name: name,
table: *tn,
typ: col.DatumType(),
hidden: col.IsHidden(),
}
tabCols.Add(int(colID))
b.colMap = append(b.colMap, colProps)
outScope.cols = append(outScope.cols, colProps)
}
if tab.IsVirtualTable() {
def := memo.VirtualScanOpDef{Table: tabID, Cols: tabCols}
outScope.group = b.factory.ConstructVirtualScan(b.factory.InternVirtualScanOpDef(&def))
} else {
def := memo.ScanOpDef{Table: tabID, Cols: tabCols}
outScope.group = b.factory.ConstructScan(b.factory.InternScanOpDef(&def))
}
return outScope
}

// buildScan builds a memo group for a ScanOp or VirtualScanOp expression on the
// given table with the given table name.
//
Expand All @@ -162,7 +218,6 @@ func (b *Builder) buildScan(tab opt.Table, tn *tree.TableName, inScope *scope) (
typ: col.DatumType(),
hidden: col.IsHidden(),
}

tabCols.Add(int(colID))
b.colMap = append(b.colMap, colProps)
outScope.cols = append(outScope.cols, colProps)
Expand Down
67 changes: 67 additions & 0 deletions pkg/sql/opt/optbuilder/testdata/select
Original file line number Diff line number Diff line change
Expand Up @@ -1094,3 +1094,70 @@ project
├── columns: x:1(int!null)
└── scan a
└── columns: x:1(int!null) y:2(float)

exec-ddl
CREATE TABLE t (a INT PRIMARY KEY, xx INT, b INT, c INT, INDEX bc (b,c))
----
TABLE t
├── a int not null
├── xx int
├── b int
├── c int
├── INDEX primary
│ └── a int not null
└── INDEX bc
├── b int
├── c int
└── a int not null

# Numeric Reference Test (1/7)
build
SELECT * FROM [1 AS t]
----
scan t
└── columns: a:1(int!null) xx:2(int) b:3(int) c:4(int)

# Numeric Reference Test (2/7)
# These columns are off by one from what
# the logictests will run. This is due
# to the implementation of the test_catalog
build
SELECT * FROM [1(0) AS t]
----
scan t
└── columns: a:1(int!null)

# Numeric Reference Test (3/7)
build
SELECT * FROM [1(0,1) AS t]
----
scan t
└── columns: a:1(int!null) xx:2(int)

# Numeric Reference Test (4/7)
build
SELECT * FROM [1(3) AS t]
----
scan t
└── columns: c:4(int)

# Numeric Reference Test (5/7)
build
SELECT * FROM [1(4) AS t]
----
error: column [4] does not exist

# Numeric Reference Test (6/7)
build
SELECT * FROM [1(1,3) AS t]
----
scan t
└── columns: xx:2(int) c:4(int)

# Numeric Reference Test (7/7)
build
SELECT * FROM [1(1,2) AS t(col1,col2)]
----
scan t
└── columns: col1:2(int) col2:3(int)

8 changes: 8 additions & 0 deletions pkg/sql/opt/optbuilder/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ func (b *Builder) assertNoAggregationOrWindowing(expr tree.Expr, op string) {
}
}

func (b *Builder) resolveTableRef(ref *tree.TableRef) opt.Table {
tab, err := b.catalog.FindTableByTableRef(b.ctx, ref.TableID)
if err != nil {
panic(builderError{err})
}
return tab
}

// resolveTable returns the table in the catalog with the given name.
func (b *Builder) resolveTable(tn *tree.TableName) opt.Table {
tab, err := b.catalog.FindTable(b.ctx, tn)
Expand Down
Loading

0 comments on commit 2aca2b1

Please sign in to comment.