Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand subqueries in VALUES statements. #2633

Merged
merged 1 commit into from
Sep 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are two more test cases we need here:

  • INSERT INTO abc VALUES ((SELECT (7,8,9))); in postgres, this doesn't type check
  • INSERT INTO abc VALUES ((SELECT 7,8,9)); in postgres, this errors out with subquery must return only one column

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. And there are corresponding cases for UPDATE. These found bugs in insert/update which are now fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.


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