Skip to content

Commit

Permalink
Expand subqueries in VALUES statements.
Browse files Browse the repository at this point in the history
Fixes #2621.
  • Loading branch information
petermattis committed Sep 23, 2015
1 parent 12ce178 commit 60197e7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 16 deletions.
24 changes: 15 additions & 9 deletions sql/insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ func (p *planner) Insert(n *parser.Insert) (planNode, error) {
primaryIndex := tableDesc.PrimaryIndex
primaryIndexKeyPrefix := MakeIndexKeyPrefix(tableDesc.ID, primaryIndex.ID)

marshalled := make([]interface{}, len(cols))

var b client.Batch
for rows.Next() {
rowVals := rows.Values()
Expand Down Expand Up @@ -124,6 +126,17 @@ func (p *planner) Insert(n *parser.Insert) (planNode, error) {
}
}

// Check that the row value types match the column types. This needs to
// happen before index encoding because certain datum types (i.e. tuple)
// cannot be used as index values.
for i, val := range rowVals {
// Make sure the value can be written to the column before proceeding.
var err error
if marshalled[i], err = marshalColumnValue(cols[i], val); err != nil {
return nil, err
}
}

primaryIndexKey, _, err := encodeIndexKey(
primaryIndex.ColumnIDs, colIDtoRowIndex, rowVals, primaryIndexKeyPrefix)
if err != nil {
Expand Down Expand Up @@ -153,21 +166,14 @@ func (p *planner) Insert(n *parser.Insert) (planNode, error) {
// Write the row columns.
for i, val := range rowVals {
col := cols[i]

// Make sure the value can be written to the column before proceeding.
marshalled, err := marshalColumnValue(col, val)
if err != nil {
return nil, err
}

if _, ok := primaryKeyCols[col.ID]; ok {
// Skip primary key columns as their values are encoded in the row
// sentinel key which is guaranteed to exist for as long as the row
// exists.
continue
}

if marshalled != nil {
if marshalled[i] != nil {
// We only output non-NULL values. Non-existent column keys are
// considered NULL during scanning and the row sentinel ensures we know
// the row exists.
Expand All @@ -177,7 +183,7 @@ func (p *planner) Insert(n *parser.Insert) (planNode, error) {
log.Infof("CPut %q -> %v", key, val)
}

b.CPut(key, marshalled, nil)
b.CPut(key, marshalled[i], nil)
}
}
}
Expand Down
59 changes: 59 additions & 0 deletions sql/testdata/subquery
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,62 @@ query I
SELECT (SELECT a FROM abc WHERE false)
----
NULL

query I
VALUES (1, (SELECT (2)))
----
1 2

statement ok
INSERT INTO abc VALUES ((SELECT 7), (SELECT 8), (SELECT 9))

query III
SELECT * FROM abc WHERE a = 7
----
7 8 9

statement error value type tuple doesn't match type INT of column "a"
INSERT INTO abc VALUES ((SELECT (10, 11, 12)))

statement error subquery must return only one column, found 3
INSERT INTO abc VALUES ((SELECT 10, 11, 12))

statement ok
CREATE TABLE xyz (x INT PRIMARY KEY, y INT, z INT)

statement ok
INSERT INTO xyz SELECT * FROM abc

query III
SELECT * FROM xyz
----
1 2 3
4 5 6
7 8 9

statement ok
UPDATE xyz SET z = (SELECT 10) WHERE x = 7

query III
SELECT * FROM xyz
----
1 2 3
4 5 6
7 8 10

statement error value type tuple doesn't match type INT of column "z"
UPDATE xyz SET z = (SELECT (10, 11)) WHERE x = 7

statement error subquery must return 2 columns, found 1
UPDATE xyz SET (y, z) = (SELECT (11, 12)) WHERE x = 7

statement ok
UPDATE xyz SET (y, z) = (SELECT 11, 12) WHERE x = 7

query III
SELECT * FROM xyz
----
1 2 3
4 5 6
7 11 12

23 changes: 16 additions & 7 deletions sql/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ func (p *planner) Update(n *parser.Update) (planNode, error) {
}
}

marshalled := make([]interface{}, len(cols))

// Update all the rows.
var b client.Batch
for rows.Next() {
Expand Down Expand Up @@ -184,12 +186,24 @@ func (p *planner) Update(n *parser.Update) (planNode, error) {
}
rowVals[colIDtoRowIndex[col.ID]] = val
}

// Check that the new value types match the column types. This needs to
// happen before index encoding because certain datum types (i.e. tuple)
// cannot be used as index values.
for i, val := range newVals {
var err error
if marshalled[i], err = marshalColumnValue(cols[i], val); err != nil {
return nil, err
}
}

// Compute the new secondary index key:value pairs for this row.
newSecondaryIndexEntries, err := encodeSecondaryIndexes(
tableDesc.ID, indexes, colIDtoRowIndex, rowVals)
if err != nil {
return nil, err
}

// Update secondary indexes.
for i, newSecondaryIndexEntry := range newSecondaryIndexEntries {
secondaryIndexEntry := secondaryIndexEntries[i]
Expand All @@ -209,21 +223,16 @@ func (p *planner) Update(n *parser.Update) (planNode, error) {
for i, val := range newVals {
col := cols[i]

marshalled, err := marshalColumnValue(col, val)
if err != nil {
return nil, err
}

key := MakeColumnKey(col.ID, primaryIndexKey)
if marshalled != nil {
if marshalled[i] != nil {
// We only output non-NULL values. Non-existent column keys are
// considered NULL during scanning and the row sentinel ensures we know
// the row exists.
if log.V(2) {
log.Infof("Put %q -> %v", key, val)
}

b.Put(key, marshalled)
b.Put(key, marshalled[i])
} else {
// The column might have already existed but is being set to NULL, so
// delete it.
Expand Down
11 changes: 11 additions & 0 deletions sql/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ func (p *planner) Values(n parser.Values) (planNode, error) {

nCols := 0
for _, tuple := range n {
for i := range tuple {
var err error
tuple[i], err = p.evalCtx.NormalizeAndTypeCheckExpr(tuple[i])
if err != nil {
return nil, err
}
tuple[i], err = p.expandSubqueries(tuple[i], 1)
if err != nil {
return nil, err
}
}
data, err := p.evalCtx.EvalExpr(tuple)
if err != nil {
return nil, err
Expand Down

0 comments on commit 60197e7

Please sign in to comment.