Skip to content

Fix 8193 err on empty insert vals #3055

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

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
1 change: 0 additions & 1 deletion enginetest/enginetests.go
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,6 @@ func TestInsertIntoErrors(t *testing.T, harness Harness) {

func TestBrokenInsertScripts(t *testing.T, harness Harness) {
for _, script := range queries.InsertBrokenScripts {
t.Skip()
Copy link
Contributor

Choose a reason for hiding this comment

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

If these are all fixed now, move the queries to InsertScripts and and delete the TestBrokenInsertScripts test functions.

TestScript(t, harness, script)
}
}
Expand Down
54 changes: 52 additions & 2 deletions enginetest/queries/insert_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -2988,7 +2988,7 @@ var InsertBrokenScripts = []ScriptTest{
{
Query: "SELECT * FROM x",
Expected: []sql.Row{
{1, "one"}, {2, 1}, {3, "three"},
{1, "one"}, {2, "1"}, {3, "three"},
},
},
{
Expand Down Expand Up @@ -3123,9 +3123,59 @@ var InsertBrokenScripts = []ScriptTest{
Expected: []sql.Row{{types.NewOkResult(1)}},
},
{
Query: "select * from t2;",
Query: "select * from test;",
Expected: []sql.Row{{1, "a"}},
},
},
},
{
Name: "column count mismatch in insert",
SetUpScript: []string{
"create table t(i int, j int)",
},
Assertions: []ScriptTestAssertion{
{
Query: "insert into t(i, j) values (1, 2, 3)",
ExpectedErr: sql.ErrColValCountMismatch,
},
{
Query: "insert into t(i, j) values (1)",
ExpectedErr: sql.ErrColValCountMismatch,
},
{
Query: "insert into t(i, j) values (1, 2), ()",
ExpectedErr: sql.ErrColValCountMismatch,
},
},
},
{
Name: "no cols empty val insert",
SetUpScript: []string{
"create table t_auto (id int auto_increment primary key, name varchar(10) default null)",
"create table t_default_null (id int default null, name varchar(10) default null)",
"create table t_not_null (id int not null, name varchar(10) not null)",
},
Assertions: []ScriptTestAssertion{
{
Query: "insert into t_auto values ()",
Expected: []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 1}}},
},
{
Query: "select * from t_auto",
Expected: []sql.Row{{1, nil}},
},
{
Query: "insert into t_default_null values ()",
Expected: []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 0}}},
},
{
Query: "select * from t_default_null",
Expected: []sql.Row{{nil, nil}},
},
{
Query: "insert into t_not_null values ()",
ExpectedErr: sql.ErrInsertIntoNonNullableDefaultNullColumn,
},
},
},
}
14 changes: 7 additions & 7 deletions enginetest/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -10462,28 +10462,28 @@ var KeylessQueries = []QueryTest{
{
Query: "DESCRIBE keyless",
Expected: []sql.Row{
{"c0", "bigint", "YES", "", nil, ""},
{"c1", "bigint", "YES", "", nil, ""},
{"c0", "bigint", "YES", "", "NULL", ""},
{"c1", "bigint", "YES", "", "NULL", ""},
},
},
{
Query: "SHOW COLUMNS FROM keyless",
Expected: []sql.Row{
{"c0", "bigint", "YES", "", nil, ""},
{"c1", "bigint", "YES", "", nil, ""},
{"c0", "bigint", "YES", "", "NULL", ""},
{"c1", "bigint", "YES", "", "NULL", ""},
},
},
{
Query: "SHOW FULL COLUMNS FROM keyless",
Expected: []sql.Row{
{"c0", "bigint", nil, "YES", "", nil, "", "", ""},
{"c1", "bigint", nil, "YES", "", nil, "", "", ""},
{"c0", "bigint", nil, "YES", "", "NULL", "", "", ""},
{"c1", "bigint", nil, "YES", "", "NULL", "", "", ""},
},
},
{
Query: "SHOW CREATE TABLE keyless",
Expected: []sql.Row{
{"keyless", "CREATE TABLE `keyless` (\n `c0` bigint,\n `c1` bigint\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
{"keyless", "CREATE TABLE `keyless` (\n `c0` bigint DEFAULT NULL,\n `c1` bigint DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
},
},
}
Expand Down
6 changes: 3 additions & 3 deletions enginetest/queries/trigger_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -2574,7 +2574,7 @@ end;`,
{
Name: "insert into common sequence table (https://github.com/dolthub/dolt/issues/2534)",
SetUpScript: []string{
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text);",
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text DEFAULT NULL);",
"create table sequence_table (max_id integer PRIMARY KEY);",
"create trigger update_position_id before insert on mytable for each row begin set new.id = (select coalesce(max(max_id),1) from sequence_table); update sequence_table set max_id = max_id + 1; end;",
"insert into sequence_table values (1);",
Expand Down Expand Up @@ -2605,7 +2605,7 @@ end;`,
{
Name: "insert into common sequence table workaround",
SetUpScript: []string{
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text);",
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text DEFAULT NULL);",
"create table sequence_table (max_id integer PRIMARY KEY);",
`create trigger update_position_id before insert on mytable for each row
begin
Expand Down Expand Up @@ -4500,7 +4500,7 @@ var BrokenTriggerQueries = []ScriptTest{
{
Name: "update common table multiple times in single insert",
SetUpScript: []string{
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text);",
"create table mytable (id integer PRIMARY KEY DEFAULT 0, sometext text DEFAULT NULL);",
"create table sequence_table (max_id integer PRIMARY KEY);",
"create trigger update_position_id before insert on mytable for each row begin set new.id = (select coalesce(max(max_id),1) from sequence_table); update sequence_table set max_id = max_id + 1; end;",
"insert into sequence_table values (1);",
Expand Down
8 changes: 4 additions & 4 deletions enginetest/scriptgen/setup/scripts/keyless
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

exec
CREATE TABLE `unique_keyless` (
`c0` bigint,
Copy link
Contributor

Choose a reason for hiding this comment

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

DEFAULT NULL shouldn't be necessary here

`c1` bigint
`c0` bigint DEFAULT NULL,
`c1` bigint DEFAULT NULL
)
----

Expand All @@ -15,8 +15,8 @@ insert into unique_keyless values

exec
CREATE TABLE `keyless` (
`c0` bigint,
Copy link
Contributor

Choose a reason for hiding this comment

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

Same

`c1` bigint
`c0` bigint DEFAULT NULL,
`c1` bigint DEFAULT NULL
)
----

Expand Down
4 changes: 2 additions & 2 deletions enginetest/scriptgen/setup/setup_data.sg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 24 additions & 7 deletions sql/planbuilder/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,25 @@ func (b *Builder) buildInsert(inScope *scope, i *ast.Insert) (outScope *scope) {
if len(columns) == 0 && len(destScope.cols) > 0 && rt != nil {
schema := rt.Schema()
columns = make([]string, len(schema))
for i, col := range schema {
columns[i] = col.Name
for index, col := range schema {
columns[index] = col.Name
}
if ir, ok := i.Rows.(*ast.AliasedValues); ok {
// Handle any empty VALUES() tuples when no column list was specified
for valueIdx, valueRow := range ir.Values {
if len(valueRow) == 0 {
// VALUES() clause is empty in conjunction with empty column list, so we need to
// insert default val for respective columns.
ir.Values[valueIdx] = make([]ast.Expr, len(schema))
for j, col := range schema {
if col.Default == nil && !col.AutoIncrement {
b.handleErr(sql.ErrInsertIntoNonNullableDefaultNullColumn.New(col.Name))
}

ir.Values[valueIdx][j] = &ast.Default{}
}
}
}
}
}
}
Expand Down Expand Up @@ -210,20 +227,20 @@ func (b *Builder) buildInsertValues(inScope *scope, v *ast.AliasedValues, column
literalOnly = true
exprTuples := make([][]sql.Expression, len(v.Values))
for i, vt := range v.Values {
// noExprs is an edge case where we fill VALUES with nil expressions
noExprs := len(vt) == 0
// triggerUnknownTable is an edge case where we ignored an unresolved
// table error and do not have a schema for resolving defaults
triggerUnknownTable := (len(columnNames) == 0 && len(vt) > 0) && (len(b.TriggerCtx().UnresolvedTables) > 0)

if len(vt) != len(columnNames) && !noExprs && !triggerUnknownTable {
err := sql.ErrInsertIntoMismatchValueCount.New()
// For empty VALUES with explicit column list, this is an error
// For empty VALUES without column list, it was handled above by filling with defaults
if len(vt) != len(columnNames) && !triggerUnknownTable {
err := sql.ErrColValCountMismatch.New(i + 1)
b.handleErr(err)
}
exprs := make([]sql.Expression, len(columnNames))
exprTuples[i] = exprs
for j := range columnNames {
if noExprs || triggerUnknownTable {
if triggerUnknownTable {
exprs[j] = expression.WrapExpression(columnDefaultValues[j])
continue
}
Expand Down
Loading