Skip to content

Commit

Permalink
opt: Add execbuilder support for Insert operator
Browse files Browse the repository at this point in the history
Add handling for the Insert operator in execbuilder and in the exec
factory. This is mostly code copied over from sql/insert.go.

Release note: None
  • Loading branch information
andy-kimball committed Nov 29, 2018
1 parent 209f49a commit b3eaf62
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 209 deletions.
2 changes: 1 addition & 1 deletion pkg/sql/logictest/testdata/logic_test/computed
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ CREATE TABLE error_check (k INT PRIMARY KEY, s STRING, i INT AS (s::INT) STORED)
statement ok
INSERT INTO error_check VALUES(1, '1')

statement error computed column i:
statement error could not parse "foo" as type int: strconv.ParseInt
INSERT INTO error_check VALUES(2, 'foo')

statement error computed column i:
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/logictest/testdata/logic_test/optimizer
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ CREATE SEQUENCE seq
statement ok
SET OPTIMIZER = ALWAYS

query error pq: unsupported statement: \*tree\.Insert
INSERT INTO test (k, v) VALUES (5, 50)
query error pq: unsupported statement: \*tree\.Delete
DELETE FROM test WHERE k=5

# Don't fall back to heuristic planner in ALWAYS mode.
query error pq: aggregates with FILTER are not supported yet
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/logictest/testdata/logic_test/statement_statistics
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ SELECT key,flags
WHERE application_name = 'valuetest' ORDER BY key, flags
----
key flags
INSERT INTO test VALUES (_, _, __more1__), (__more1__) -
INSERT INTO test VALUES (_, _, __more1__), (__more1__) ·
SELECT (_, _, __more3__) FROM test WHERE _ ·
SELECT key FROM test.crdb_internal.node_statement_statistics ·
SELECT sin(_) ·
Expand Down
10 changes: 5 additions & 5 deletions pkg/sql/logictest/testdata/logic_test/txn
Original file line number Diff line number Diff line change
Expand Up @@ -931,19 +931,19 @@ statement ok
COMMIT

statement error cannot execute CREATE TABLE in a read-only transaction
CREATE TABLE a (a int)
CREATE TABLE tab (a int)

statement error cannot execute INSERT in a read-only transaction
INSERT INTO a VALUES(1)
INSERT INTO kv VALUES('foo')

statement error cannot execute UPDATE in a read-only transaction
UPDATE a SET a = 1
UPDATE kv SET v = 'foo'

statement error cannot execute INSERT in a read-only transaction
UPSERT INTO a VALUES(2)
UPSERT INTO kv VALUES('foo')

statement error cannot execute DELETE in a read-only transaction
DELETE FROM a
DELETE FROM kv

statement error cannot execute nextval\(\) in a read-only transaction
SELECT nextval('a')
Expand Down
45 changes: 44 additions & 1 deletion pkg/sql/opt/exec/execbuilder/relational_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
"github.com/cockroachdb/cockroach/pkg/sql/opt/ordering"
"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
"github.com/cockroachdb/cockroach/pkg/util/encoding"
Expand Down Expand Up @@ -118,6 +119,14 @@ func (ep *execPlan) sqlOrdering(ordering opt.Ordering) sqlbase.ColumnOrdering {
func (b *Builder) buildRelational(e memo.RelExpr) (execPlan, error) {
var ep execPlan
var err error

// Raise error if a mutation op is part of a read-only transaction.
if opt.IsMutationOp(e) && b.evalCtx.TxnReadOnly {
return execPlan{}, pgerror.NewErrorf(pgerror.CodeReadOnlySQLTransactionError,
"cannot execute %s in a read-only transaction", e.Op().SyntaxTag())
}

// Handle read-only operators which never write data or modify schema.
switch t := e.(type) {
case *memo.ValuesExpr:
ep, err = b.buildValues(t)
Expand Down Expand Up @@ -167,6 +176,9 @@ func (b *Builder) buildRelational(e memo.RelExpr) (execPlan, error) {
case *memo.ProjectSetExpr:
ep, err = b.buildProjectSet(t)

case *memo.InsertExpr:
ep, err = b.buildInsert(t)

default:
if opt.IsSetOp(e) {
ep, err = b.buildSetOp(e)
Expand All @@ -179,11 +191,12 @@ func (b *Builder) buildRelational(e memo.RelExpr) (execPlan, error) {
if opt.IsJoinApplyOp(e) {
return execPlan{}, b.decorrelationError()
}
return execPlan{}, errors.Errorf("unsupported relational op %s", e.Op())
}
if err != nil {
return execPlan{}, err
}

// Wrap the expression in a render expression if presentation requires it.
if p := e.RequiredPhysical(); !p.Presentation.Any() {
ep, err = b.applyPresentation(ep, p)
}
Expand Down Expand Up @@ -937,6 +950,36 @@ func (b *Builder) buildProjectSet(projectSet *memo.ProjectSetExpr) (execPlan, er
return ep, nil
}

func (b *Builder) buildInsert(ins *memo.InsertExpr) (execPlan, error) {
// Build the input query and ensure that the input columns that correspond to
// the table columns are projected.
input, err := b.buildRelational(ins.Input)
if err != nil {
return execPlan{}, err
}
input, err = b.ensureColumns(input, ins.InputCols, nil, ins.ProvidedPhysical().Ordering)
if err != nil {
return execPlan{}, err
}

// Construct the Insert node.
tab := b.mem.Metadata().Table(ins.Table)
node, err := b.factory.ConstructInsert(input.root, tab, ins.NeedResults)
if err != nil {
return execPlan{}, err
}

// If INSERT returns rows, they contain all non-mutation columns from the
// table, in the same order they're defined in the table.
ep := execPlan{root: node}
if ins.NeedResults {
for i, n := 0, tab.ColumnCount(); i < n; i++ {
ep.outputCols.Set(int(ins.InputCols[i]), i)
}
}
return ep, nil
}

// needProjection figures out what projection is needed on top of the input plan
// to produce the given list of columns. If the input plan already produces
// the columns (in the same order), returns needProj=false.
Expand Down
155 changes: 89 additions & 66 deletions pkg/sql/opt/exec/execbuilder/testdata/insert
Original file line number Diff line number Diff line change
Expand Up @@ -298,93 +298,116 @@ SELECT tree, field, description FROM [
EXPLAIN (VERBOSE) INSERT INTO insert_t TABLE select_t ORDER BY v DESC
]
----
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
│ default 0 NULL
│ default 1 NULL
│ default 2 unique_rowid()
└── sort · ·
│ order -v
└── render · ·
│ render 0 test.public.select_t.x
│ render 1 test.public.select_t.v
└── scan · ·
· table select_t@primary
· spans ALL
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── render · ·
│ render 0 x
│ render 1 v
│ render 2 column7
└── sort · ·
│ order -v
└── render · ·
│ render 0 unique_rowid()
│ render 1 x
│ render 2 v
└── scan · ·
· table select_t@primary
· spans ALL

# Check that INSERT supports LIMIT (MySQL extension)
query TTT
SELECT tree, field, description FROM [
EXPLAIN (VERBOSE) INSERT INTO insert_t SELECT * FROM select_t LIMIT 1
]
----
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
│ default 0 NULL
│ default 1 NULL
│ default 2 unique_rowid()
└── limit · ·
│ count 1
└── render · ·
│ render 0 test.public.select_t.x
│ render 1 test.public.select_t.v
└── scan · ·
· table select_t@primary
· spans ALL
· limit 1
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── render · ·
│ render 0 x
│ render 1 v
│ render 2 unique_rowid()
└── scan · ·
· table select_t@primary
· spans ALL
· limit 1

# Check the grouping of LIMIT and ORDER BY
query TTT
EXPLAIN (PLAN) INSERT INTO insert_t VALUES (1,1), (2,2) LIMIT 1
----
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── limit · ·
│ count 1
└── values · ·
· size 2 columns, 2 rows
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── render · ·
└── limit · ·
│ count 1
└── values · ·
· size 2 columns, 2 rows

query TTT
EXPLAIN (PLAN) INSERT INTO insert_t VALUES (1,1), (2,2) ORDER BY 2 LIMIT 1
----
count · ·
└── insert · ·
into insert_t(x, v, rowid)
└── limit · ·
count 1
└── sort · ·
order +column2
strategy top 1
└── values · ·
· size 2 columns, 2 rows
count · ·
└── insert · ·
into insert_t(x, v, rowid)
└── render · ·
└── limit · ·
count 1
└── sort · ·
order +column2
└── values · ·
· size 2 columns, 2 rows

query TTT
EXPLAIN (PLAN) INSERT INTO insert_t (VALUES (1,1), (2,2) ORDER BY 2) LIMIT 1
----
count · ·
└── insert · ·
into insert_t(x, v, rowid)
└── limit · ·
count 1
└── sort · ·
order +column2
strategy top 1
└── values · ·
· size 2 columns, 2 rows
count · ·
└── insert · ·
into insert_t(x, v, rowid)
└── render · ·
└── limit · ·
count 1
└── sort · ·
order +column2
└── values · ·
· size 2 columns, 2 rows

query TTT
EXPLAIN (PLAN) INSERT INTO insert_t (VALUES (1,1), (2,2) ORDER BY 2 LIMIT 1)
----
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── limit · ·
│ count 1
└── sort · ·
│ order +column2
│ strategy top 1
└── values · ·
· size 2 columns, 2 rows
count · ·
└── insert · ·
│ into insert_t(x, v, rowid)
└── render · ·
└── limit · ·
│ count 1
└── sort · ·
│ order +column2
└── values · ·
· size 2 columns, 2 rows

# ORDER BY expression that's not inserted into table.
query TTTTT
EXPLAIN (VERBOSE) INSERT INTO insert_t (SELECT length(k), 2 FROM kv ORDER BY k || v) RETURNING x+v
----
render · · ("?column?") ·
│ render 0 x + v · ·
└── run · · (x, v, rowid[hidden]) ·
└── insert · · (x, v, rowid[hidden]) ·
│ into insert_t(x, v, rowid) · ·
└── render · · (length, "?column?", column9) ·
│ render 0 length · ·
│ render 1 "?column?" · ·
│ render 2 column9 · ·
└── sort · · (column9, length, "?column?", column8) +column8
│ order +column8 · ·
└── render · · (column9, length, "?column?", column8) ·
│ render 0 unique_rowid() · ·
│ render 1 length(k) · ·
│ render 2 2 · ·
│ render 3 k || v · ·
└── scan · · (k, v) ·
· table kv@primary · ·
· spans ALL · ·
19 changes: 10 additions & 9 deletions pkg/sql/opt/exec/execbuilder/testdata/orderby
Original file line number Diff line number Diff line change
Expand Up @@ -482,15 +482,16 @@ ordinality · · (x, "ordinality") ·
query TTTTT
EXPLAIN (VERBOSE) INSERT INTO t(a, b) SELECT * FROM (SELECT 1 AS x, 2 AS y) ORDER BY x RETURNING b
----
render · · (b) ·
│ render 0 test.public.t.b · ·
└── run · · (a, b, c) ·
└── insert · · (a, b, c) ·
│ into t(a, b) · ·
└── render · · (x, y) x=CONST; y=CONST
│ render 0 1 · ·
│ render 1 2 · ·
└── emptyrow · · () ·
render · · (b) ·
│ render 0 b · ·
└── run · · (a, b, c) ·
└── insert · · (a, b, c) ·
│ into t(a, b, c) · ·
└── values · · (x, y, column6) ·
· size 3 columns, 1 row · ·
· row 0, expr 0 1 · ·
· row 0, expr 1 2 · ·
· row 0, expr 2 NULL · ·

query TTTTT
EXPLAIN (VERBOSE) DELETE FROM t WHERE a = 3 RETURNING b
Expand Down
Loading

0 comments on commit b3eaf62

Please sign in to comment.