Skip to content

Commit

Permalink
opt: add support for ALTER TABLE/INDEX SPLIT AT
Browse files Browse the repository at this point in the history
Adding optimizer support for `tree.Split`. This statement has a
relational input, so it can't be implemented as an "opaque".

Note that as part of this change, we move all the "fixed" planNode
column definitions to `sqlbase` and we add an `Ordinal()` method to
`cat.Index`.

Release note: None
  • Loading branch information
RaduBerinde committed Jul 2, 2019
1 parent d9964c0 commit 521f24f
Show file tree
Hide file tree
Showing 32 changed files with 465 additions and 231 deletions.
2 changes: 1 addition & 1 deletion pkg/sql/data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ func (p *planner) getSequenceSource(
}
return planDataSource{
plan: node,
info: sqlbase.NewSourceInfoForSingleTable(tn, sequenceSelectColumns),
info: sqlbase.NewSourceInfoForSingleTable(tn, sqlbase.SequenceSelectColumns),
}, nil
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/sql/opt/bench/stub_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,9 @@ func (f *stubFactory) ConstructErrorIfRows(
func (f *stubFactory) ConstructOpaque(metadata opt.OpaqueMetadata) (exec.Node, error) {
return struct{}{}, nil
}

func (f *stubFactory) ConstructAlterTableSplit(
index cat.Index, input exec.Node, expiration tree.TypedExpr,
) (exec.Node, error) {
return struct{}{}, nil
}
4 changes: 4 additions & 0 deletions pkg/sql/opt/cat/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type Index interface {
// Table returns a reference to the table this index is based on.
Table() Table

// Ordinal returns the ordinal of this index within the context of its Table.
// Specifically idx = Table().Index(idx.Ordinal).
Ordinal() int

// IsUnique returns true if this index is declared as UNIQUE in the schema.
IsUnique() bool

Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/opt/exec/execbuilder/relational.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ func (b *Builder) buildRelational(e memo.RelExpr) (execPlan, error) {
case *memo.OpaqueRelExpr:
ep, err = b.buildOpaque(t)

case *memo.AlterTableSplitExpr:
ep, err = b.buildAlterTableSplit(t)

default:
if opt.IsSetOp(e) {
ep, err = b.buildSetOp(e)
Expand Down
36 changes: 30 additions & 6 deletions pkg/sql/opt/exec/execbuilder/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ func (b *Builder) buildExplain(explain *memo.ExplainExpr) (execPlan, error) {
}

ep := execPlan{root: node}
for i := range explain.ColList {
ep.outputCols.Set(int(explain.ColList[i]), i)
for i, c := range explain.ColList {
ep.outputCols.Set(int(c), i)
}
// The subqueries are now owned by the explain node; remove them so they don't
// also show up in the final plan.
Expand All @@ -110,10 +110,34 @@ func (b *Builder) buildShowTrace(show *memo.ShowTraceForSessionExpr) (execPlan,
return execPlan{}, err
}
ep := execPlan{root: node}
for i := range show.ColList {
ep.outputCols.Set(int(show.ColList[i]), i)
for i, c := range show.ColList {
ep.outputCols.Set(int(c), i)
}
return ep, nil
}

func (b *Builder) buildAlterTableSplit(split *memo.AlterTableSplitExpr) (execPlan, error) {
input, err := b.buildRelational(split.Input)
if err != nil {
return execPlan{}, err
}
scalarCtx := buildScalarCtx{}
expiration, err := b.buildScalar(&scalarCtx, split.Expiration)
if err != nil {
return execPlan{}, err
}
table := b.mem.Metadata().Table(split.Table)
node, err := b.factory.ConstructAlterTableSplit(
table.Index(split.Index),
input.root,
expiration,
)
if err != nil {
return execPlan{}, err
}
ep := execPlan{root: node}
for i, c := range split.Columns {
ep.outputCols.Set(int(c), i)
}
// The subqueries are now owned by the explain node; remove them so they don't
// also show up in the final plan.
return ep, nil
}
17 changes: 6 additions & 11 deletions pkg/sql/opt/exec/execbuilder/testdata/ddl
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,12 @@ CREATE TABLE s (k1 INT, k2 INT, v INT, PRIMARY KEY (k1,k2))
query TTTTT colnames
EXPLAIN (VERBOSE) ALTER TABLE s SPLIT AT SELECT k1,k2 FROM s ORDER BY k1 LIMIT 3
----
tree field description columns ordering
split · · (key, pretty, split_enforced_until) ·
└── limit · · (k1, k2) k1!=NULL; k2!=NULL; key(k1,k2); +k1
│ count 3 · ·
└── render · · (k1, k2) k1!=NULL; k2!=NULL; key(k1,k2); +k1
│ render 0 test.public.s.k1 · ·
│ render 1 test.public.s.k2 · ·
└── scan · · (k1, k2, v[omitted]) k1!=NULL; k2!=NULL; key(k1,k2); +k1
· table s@primary · ·
· spans ALL · ·
· limit 3 · ·
tree field description columns ordering
split · · (key, pretty, split_enforced_until) ·
└── scan · · (k1, k2) +k1
· table s@primary · ·
· spans ALL · ·
· limit 3 · ·

statement ok
DROP TABLE t; DROP TABLE other
Expand Down
23 changes: 10 additions & 13 deletions pkg/sql/opt/exec/execbuilder/testdata/subquery
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,16 @@ CREATE TABLE abc (a INT PRIMARY KEY, b INT, c INT)
query TTT
EXPLAIN ALTER TABLE abc SPLIT AT VALUES ((SELECT 42))
----
root · ·
├── split · ·
│ └── values · ·
│ size 1 column, 1 row
└── subquery · ·
│ id @S1
│ original sql (SELECT 42)
│ exec mode one row
└── max1row · ·
└── limit · ·
│ count 2
└── render · ·
└── emptyrow · ·
root · ·
├── split · ·
│ └── values · ·
│ size 1 column, 1 row
└── subquery · ·
│ id @S1
│ original sql (SELECT 42)
│ exec mode one row
└── values · ·
· size 1 column, 1 row

statement ok
ALTER TABLE abc SPLIT AT VALUES ((SELECT 1))
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/opt/exec/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,10 @@ type Factory interface {

// ConstructOpaque creates a node for an opaque operator.
ConstructOpaque(metadata opt.OpaqueMetadata) (Node, error)

// ConstructAlterTableSplit creates a node that implements ALTER TABLE/INDEX
// SPLIT AT.
ConstructAlterTableSplit(index cat.Index, input Node, expiration tree.TypedExpr) (Node, error)
}

// OutputOrdering indicates the required output ordering on a Node that is being
Expand Down
8 changes: 8 additions & 0 deletions pkg/sql/opt/memo/expr_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,14 @@ func FormatPrivate(f *ExprFmtCtx, private interface{}, physProps *physical.Requi
f.Buffer.WriteByte(' ')
f.Buffer.WriteString(t.Metadata.String())

case *AlterTableSplitPrivate:
tab := f.Memo.metadata.Table(t.Table)
if t.Index == cat.PrimaryIndex {
fmt.Fprintf(f.Buffer, " %s", tableAlias(f, t.Table))
} else {
fmt.Fprintf(f.Buffer, " %s@%s", tableAlias(f, t.Table), tab.Index(t.Index).Name())
}

case *JoinPrivate:
// Nothing to show; flags are shown separately.

Expand Down
89 changes: 22 additions & 67 deletions pkg/sql/opt/memo/logical_props_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,25 +684,24 @@ func (b *logicalPropsBuilder) buildValuesProps(values *ValuesExpr, rel *props.Re
}
}

func (b *logicalPropsBuilder) buildExplainProps(explain *ExplainExpr, rel *props.Relational) {
BuildSharedProps(b.mem, explain, &rel.Shared)
func (b *logicalPropsBuilder) buildBasicProps(e opt.Expr, cols opt.ColList, rel *props.Relational) {
BuildSharedProps(b.mem, e, &rel.Shared)

// Output Columns
// --------------
// Output columns are stored in the definition.
rel.OutputCols = explain.ColList.ToSet()
rel.OutputCols = cols.ToSet()

// Not Null Columns
// ----------------
// All columns are assumed to be nullable.

// Outer Columns
// -------------
// EXPLAIN doesn't allow outer columns.
// No outer columns.

// Functional Dependencies
// -----------------------
// Explain operator has an empty FD set.
// Empty FD set.

// Cardinality
// -----------
Expand All @@ -716,39 +715,28 @@ func (b *logicalPropsBuilder) buildExplainProps(explain *ExplainExpr, rel *props
}
}

func (b *logicalPropsBuilder) buildExplainProps(explain *ExplainExpr, rel *props.Relational) {
b.buildBasicProps(explain, explain.ColList, rel)
}

func (b *logicalPropsBuilder) buildShowTraceForSessionProps(
showTrace *ShowTraceForSessionExpr, rel *props.Relational,
) {
BuildSharedProps(b.mem, showTrace, &rel.Shared)

// Output Columns
// --------------
// Output columns are stored in the definition.
rel.OutputCols = showTrace.ColList.ToSet()

// Not Null Columns
// ----------------
// All columns are assumed to be nullable.

// Outer Columns
// -------------
// SHOW TRACE doesn't allow outer columns.

// Functional Dependencies
// -----------------------
// ShowTrace operator has an empty FD set.

// Cardinality
// -----------
// Don't make any assumptions about cardinality of output.
rel.Cardinality = props.AnyCardinality
b.buildBasicProps(showTrace, showTrace.ColList, rel)
}

// Statistics
// ----------
if !b.disableStats {
b.sb.buildUnknown(rel)
}
func (b *logicalPropsBuilder) buildOpaqueRelProps(op *OpaqueRelExpr, rel *props.Relational) {
b.buildBasicProps(op, op.Columns, rel)
rel.CanHaveSideEffects = true
rel.CanMutate = true
}

func (b *logicalPropsBuilder) buildAlterTableSplitProps(
split *AlterTableSplitExpr, rel *props.Relational,
) {
b.buildBasicProps(split, split.Columns, rel)
rel.CanHaveSideEffects = true
rel.CanMutate = true
}

func (b *logicalPropsBuilder) buildLimitProps(limit *LimitExpr, rel *props.Relational) {
Expand Down Expand Up @@ -1785,39 +1773,6 @@ func (h *joinPropsHelper) cardinality() props.Cardinality {
}
}

func (b *logicalPropsBuilder) buildOpaqueRelProps(op *OpaqueRelExpr, rel *props.Relational) {
BuildSharedProps(b.mem, op, &rel.Shared)
rel.CanHaveSideEffects = true
rel.CanMutate = true

// Output Columns
// --------------
rel.OutputCols = op.Columns.ToSet()

// Not Null Columns
// ----------------
// All columns are assumed to be nullable.

// Outer Columns
// -------------
// No outer columns.

// Functional Dependencies
// -----------------------
// None.

// Cardinality
// -----------
// Any.
rel.Cardinality = props.AnyCardinality

// Statistics
// ----------
if !b.disableStats {
b.sb.buildUnknown(rel)
}
}

func (b *logicalPropsBuilder) buildFakeRelProps(fake *FakeRelExpr, rel *props.Relational) {
*rel = *fake.Props
}
33 changes: 33 additions & 0 deletions pkg/sql/opt/ops/statement.opt
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,36 @@ define OpaqueRelPrivate {
Columns ColList
Metadata OpaqueMetadata
}

# AlterTableSplit represents an `ALTER TABLE/INDEX .. SPLIT AT ..` statement.
[Relational, DDL]
define AlterTableSplit {
# The input expression provides values for the index columns (or a prefix of
# them).
Input RelExpr

# Expiration is a string scalar that indicates a timestamp after which the
# ranges are eligible for automatic merging (or Null if there is no
# expiration).
Expiration ScalarExpr

_ AlterTableSplitPrivate
}

[Private]
define AlterTableSplitPrivate {
# Table identifies the table to alter. It is an id that can be passed to
# the Metadata.Table method in order to fetch cat.Table metadata.
Table TableID

# Index identifies the index to scan (whether primary or secondary). It
# can be passed to the cat.Table.Index(i int) method in order to fetch the
# cat.Index metadata.
Index int

# Props stores the required physical properties for the enclosed expression.
Props PhysProps

# Columns stores the column IDs for the statement result columns.
Columns ColList
}
Loading

0 comments on commit 521f24f

Please sign in to comment.