Skip to content

Commit 28bca52

Browse files
authored
Merge pull request #939 from dolthub/zachmu/enginetests2
Unskip many InsertInto engine tests
2 parents a790254 + a342b93 commit 28bca52

File tree

8 files changed

+842
-109
lines changed

8 files changed

+842
-109
lines changed

server/analyzer/assign_insert_casts.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package analyzer
1616

1717
import (
1818
"fmt"
19+
"strings"
1920

2021
"github.com/dolthub/go-mysql-server/sql"
2122
"github.com/dolthub/go-mysql-server/sql/analyzer"
@@ -42,12 +43,12 @@ func AssignInsertCasts(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, sc
4243
if !ok {
4344
return nil, transform.NewTree, fmt.Errorf("INSERT: non-Doltgres type found in destination: %s", col.Type.String())
4445
}
45-
destinationNameToType[col.Name] = colType
46+
destinationNameToType[strings.ToLower(col.Name)] = colType
4647
}
4748
// Create the destination type slice that will match each inserted column
4849
destinationTypes := make([]pgtypes.DoltgresType, len(insertInto.ColumnNames))
4950
for i, colName := range insertInto.ColumnNames {
50-
destinationTypes[i], ok = destinationNameToType[colName]
51+
destinationTypes[i], ok = destinationNameToType[strings.ToLower(colName)]
5152
if !ok {
5253
return nil, transform.NewTree, fmt.Errorf("INSERT: cannot find destination column with name `%s`", colName)
5354
}
@@ -72,7 +73,7 @@ func AssignInsertCasts(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, sc
7273
}
7374
}
7475
}
75-
return insertInto.WithSource(plan.NewValues(newValues)), transform.NewTree, nil
76+
insertInto = insertInto.WithSource(plan.NewValues(newValues))
7677
} else {
7778
sourceSchema := insertInto.Source.Schema()
7879
projections := make([]sql.Expression, len(sourceSchema))
@@ -90,6 +91,23 @@ func AssignInsertCasts(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, sc
9091
projections[i] = pgexprs.NewAssignmentCast(getField, fromColType, toColType)
9192
}
9293
}
93-
return insertInto.WithSource(plan.NewProject(projections, insertInto.Source)), transform.NewTree, nil
94+
insertInto = insertInto.WithSource(plan.NewProject(projections, insertInto.Source))
9495
}
96+
97+
// handle on conflict clause if present
98+
if len(insertInto.OnDupExprs) > 0 {
99+
newDupExprs, err := assignUpdateFieldCasts(insertInto.OnDupExprs)
100+
if err != nil {
101+
return nil, false, err
102+
}
103+
// TODO: this relies on a particular implementation detail InsertInto.WithExpressions
104+
newInsertInto, err := insertInto.WithExpressions(append(newDupExprs, insertInto.Checks().ToExpressions()...)...)
105+
if err != nil {
106+
return nil, false, err
107+
}
108+
109+
insertInto = newInsertInto.(*plan.InsertInto)
110+
}
111+
112+
return insertInto, transform.NewTree, nil
95113
}

server/analyzer/assign_update_casts.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,21 @@ func AssignUpdateCasts(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, sc
6969

7070
// assignUpdateCastsHandleSource handles the *plan.UpdateSource portion of AssignUpdateCasts.
7171
func assignUpdateCastsHandleSource(updateSource *plan.UpdateSource) (*plan.UpdateSource, error) {
72-
newUpdateExprs := make([]sql.Expression, len(updateSource.UpdateExprs))
73-
for i, updateExpr := range updateSource.UpdateExprs {
72+
updateExprs := updateSource.UpdateExprs
73+
newUpdateExprs, err := assignUpdateFieldCasts(updateExprs)
74+
if err != nil {
75+
return nil, err
76+
}
77+
newUpdateSource, err := updateSource.WithExpressions(newUpdateExprs...)
78+
if err != nil {
79+
return nil, err
80+
}
81+
return newUpdateSource.(*plan.UpdateSource), nil
82+
}
83+
84+
func assignUpdateFieldCasts(updateExprs []sql.Expression) ([]sql.Expression, error) {
85+
newUpdateExprs := make([]sql.Expression, len(updateExprs))
86+
for i, updateExpr := range updateExprs {
7487
setField, ok := updateExpr.(*expression.SetField)
7588
if !ok {
7689
return nil, fmt.Errorf("UPDATE: assumption that expression is always SetField is incorrect: %T", updateExpr)
@@ -94,9 +107,5 @@ func assignUpdateCastsHandleSource(updateSource *plan.UpdateSource) (*plan.Updat
94107
newUpdateExprs[i] = newSetField
95108
}
96109
}
97-
newUpdateSource, err := updateSource.WithExpressions(newUpdateExprs...)
98-
if err != nil {
99-
return nil, err
100-
}
101-
return newUpdateSource.(*plan.UpdateSource), nil
110+
return newUpdateExprs, nil
102111
}

server/ast/insert.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,23 @@ func nodeInsert(ctx *Context, node *tree.Insert) (*vitess.Insert, error) {
3535
return nil, fmt.Errorf("RETURNING is not yet supported")
3636
}
3737
var ignore string
38+
var onDuplicate vitess.OnDup
39+
3840
if node.OnConflict != nil {
39-
// Currently, only ON CONFLICT DO NOTHING is supported, which is equivalent to INSERT IGNORE in GMS
40-
if node.OnConflict.Columns != nil ||
41-
node.OnConflict.ArbiterPredicate != nil ||
42-
node.OnConflict.Exprs != nil ||
43-
node.OnConflict.Where != nil ||
44-
!node.OnConflict.DoNothing {
41+
if isIgnore(node.OnConflict) {
42+
ignore = vitess.IgnoreStr
43+
} else if supportedOnConflictClause(node.OnConflict) {
44+
// TODO: we are ignoring the column names, which are used to infer which index under conflict is to be checked
45+
updateExprs, err := nodeUpdateExprs(ctx, node.OnConflict.Exprs)
46+
if err != nil {
47+
return nil, err
48+
}
49+
for _, updateExpr := range updateExprs {
50+
onDuplicate = append(onDuplicate, updateExpr)
51+
}
52+
} else {
4553
return nil, fmt.Errorf("the ON CONFLICT clause provided is not yet supported")
4654
}
47-
ignore = vitess.IgnoreStr
4855
}
4956
var tableName vitess.TableName
5057
switch node := node.Table.(type) {
@@ -78,7 +85,7 @@ func nodeInsert(ctx *Context, node *tree.Insert) (*vitess.Insert, error) {
7885
return nil, err
7986
}
8087

81-
// GMS For a ValuesStatement with simple rows, GMS expects AliasedValues
88+
// For a ValuesStatement with simple rows, GMS expects AliasedValues
8289
if vSelect, ok := rows.(*vitess.Select); ok && len(vSelect.From) == 1 {
8390
if valsStmt, ok := vSelect.From[0].(*vitess.ValuesStatement); ok {
8491
rows = &vitess.AliasedValues{
@@ -93,10 +100,31 @@ func nodeInsert(ctx *Context, node *tree.Insert) (*vitess.Insert, error) {
93100
With: with,
94101
Columns: columns,
95102
Rows: rows,
103+
OnDup: onDuplicate,
96104
Auth: vitess.AuthInformation{
97105
AuthType: auth.AuthType_INSERT,
98106
TargetType: auth.AuthTargetType_SingleTableIdentifier,
99107
TargetNames: []string{tableName.SchemaQualifier.String(), tableName.Name.String()},
100108
},
101109
}, nil
102110
}
111+
112+
// isIgnore returns true if the ON CONFLICT clause provided is equivalent to INSERT IGNORE in GMS
113+
func isIgnore(conflict *tree.OnConflict) bool {
114+
return conflict.ArbiterPredicate == nil &&
115+
conflict.Exprs == nil &&
116+
conflict.Where == nil &&
117+
conflict.DoNothing
118+
}
119+
120+
// supportedOnConflictClause returns true if the ON CONFLICT clause given can be represented as
121+
// an ON DUPLICATE KEY UPDATE clause in GMS
122+
func supportedOnConflictClause(conflict *tree.OnConflict) bool {
123+
if conflict.ArbiterPredicate != nil {
124+
return false
125+
}
126+
if conflict.Where != nil {
127+
return false
128+
}
129+
return true
130+
}

server/ast/select.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func nodeSelect(ctx *Context, node *tree.Select) (vitess.SelectStatement, error)
5555

5656
switch selectStmt := selectStmt.(type) {
5757
case *vitess.ParenSelect:
58-
//TODO: figure out if this is even correct, not sure what statement would produce this AST
58+
// TODO: figure out if this is even correct, not sure what statement would produce this AST
5959
// perhaps we should use the inner select statement, but maybe it has its own order by, limit, etc.
6060
return &vitess.Select{
6161
SelectExprs: vitess.SelectExprs{
@@ -144,13 +144,15 @@ func nodeSelectExpr(ctx *Context, node tree.SelectExpr) (vitess.SelectExpr, erro
144144
if expr.NumParts == 2 {
145145
tableName.Name = vitess.NewTableIdent(expr.Parts[1])
146146
}
147+
// We don't set the InputExpression for ColName expressions. This matches the behavior in vitess's
148+
// post-processing found in ast.go. Input expressions are load bearing for some parts of plan building
149+
// so we need to match the behavior exactly.
147150
return &vitess.AliasedExpr{
148151
Expr: &vitess.ColName{
149152
Name: vitess.NewColIdent(expr.Parts[0]),
150153
Qualifier: tableName,
151154
},
152-
As: vitess.NewColIdent(string(node.As)),
153-
InputExpression: tree.AsString(&node),
155+
As: vitess.NewColIdent(string(node.As)),
154156
}, nil
155157
}
156158
default:

testing/go/enginetest/doltgres_engine_test.go

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/dolthub/go-mysql-server/enginetest/queries"
2626
"github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup"
2727
"github.com/dolthub/go-mysql-server/sql"
28+
"github.com/dolthub/go-mysql-server/sql/types"
2829
"github.com/stretchr/testify/require"
2930

3031
"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
@@ -59,6 +60,28 @@ func TestQueries(t *testing.T) {
5960
enginetest.TestQueries(t, h)
6061
}
6162

63+
func TestSingleWriteQuery(t *testing.T) {
64+
t.Skip()
65+
h := newDoltgresServerHarness(t)
66+
defer h.Close()
67+
68+
h.Setup(setup.MydbData, setup.MytableData, setup.Mytable_del_idxData, setup.KeylessData, setup.Keyless_idxData, setup.NiltableData, setup.TypestableData, setup.EmptytableData, setup.AutoincrementData, setup.OthertableData, setup.Othertable_del_idxData)
69+
70+
test := queries.WriteQueryTest{
71+
WriteQuery: `INSERT INTO emptytable (s,i) SELECT s,i from mytable where i = 1
72+
union select s,i from mytable where i = 3
73+
union select s,i from mytable where i > 2`,
74+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(2)}},
75+
SelectQuery: "SELECT * FROM emptytable ORDER BY i,s",
76+
ExpectedSelect: []sql.Row{
77+
{int64(1), "first row"},
78+
{int64(3), "third row"},
79+
},
80+
}
81+
82+
enginetest.RunWriteQueryTest(t, h, test)
83+
}
84+
6285
func TestSingleQuery(t *testing.T) {
6386
t.Skip()
6487

@@ -148,34 +171,35 @@ func TestSingleScript(t *testing.T) {
148171

149172
var scripts = []queries.ScriptTest{
150173
{
151-
Name: "Group by BINARY: https://github.com/dolthub/dolt/issues/6179",
174+
Name: "Insert throws primary key violations",
152175
SetUpScript: []string{
153-
"create table t (s varchar(100));",
154-
"insert into t values ('abc'), ('def');",
155-
"create table t1 (b binary(3));",
156-
"insert into t1 values ('abc'), ('abc'), ('def'), ('abc'), ('def');",
176+
"CREATE TABLE t (pk int PRIMARY key);",
177+
"CREATE TABLE t2 (pk1 int, pk2 int, PRIMARY KEY (pk1, pk2));",
157178
},
158179
Assertions: []queries.ScriptTestAssertion{
159180
{
160-
Query: "select binary s from t group by binary s order by binary s",
161-
Expected: []sql.Row{
162-
{[]uint8("abc")},
163-
{[]uint8("def")},
164-
},
181+
Query: "INSERT INTO t VALUES (1), (2);",
182+
Expected: []sql.Row{{types.NewOkResult(2)}},
165183
},
166184
{
167-
Query: "select count(b), b from t1 group by b order by b",
168-
Expected: []sql.Row{
169-
{3, []uint8("abc")},
170-
{2, []uint8("def")},
171-
},
185+
Query: "INSERT into t VALUES (1);",
186+
ExpectedErr: sql.ErrPrimaryKeyViolation,
172187
},
173188
{
174-
Query: "select binary s from t group by binary s order by s",
175-
Expected: []sql.Row{
176-
{[]uint8("abc")},
177-
{[]uint8("def")},
178-
},
189+
Query: "SELECT * from t;",
190+
Expected: []sql.Row{{1}, {2}},
191+
},
192+
{
193+
Query: "INSERT into t2 VALUES (1, 1), (2, 2);",
194+
Expected: []sql.Row{{types.NewOkResult(2)}},
195+
},
196+
{
197+
Query: "INSERT into t2 VALUES (1, 1);",
198+
ExpectedErr: sql.ErrPrimaryKeyViolation,
199+
},
200+
{
201+
Query: "SELECT * from t2;",
202+
Expected: []sql.Row{{1, 1}, {2, 2}},
179203
},
180204
},
181205
},
@@ -286,15 +310,46 @@ func TestOrderByGroupBy(t *testing.T) {
286310
}
287311

288312
func TestAmbiguousColumnResolution(t *testing.T) {
289-
t.Skip()
290313
h := newDoltgresServerHarness(t)
291314
defer h.Close()
292315
enginetest.TestAmbiguousColumnResolution(t, h)
293316
}
294317

295318
func TestInsertInto(t *testing.T) {
296-
t.Skip()
297-
h := newDoltgresServerHarness(t)
319+
h := newDoltgresServerHarness(t).WithSkippedQueries([]string{
320+
"INSERT INTO keyless VALUES ();", // unsupported syntax
321+
"INSERT INTO keyless () VALUES ();", // unsupported syntax
322+
"INSERT INTO mytable (s, i) VALUES ('x', '10.0');", // type mismatch
323+
"INSERT INTO mytable (s, i) VALUES ('x', '64.6');", // type mismatch
324+
"INSERT INTO mytable SET s = 'x', i = 999;", // unsupported syntax
325+
"INSERT INTO mytable SET i = 999, s = 'x';", // unsupported syntax
326+
`INSERT INTO mytable (i,s) SELECT i * 2, concat(s,s) from mytable order by 1 desc limit 1`, // type error
327+
"INSERT INTO mytable VALUES (999, _binary 'x');", // unsupported syntax
328+
"INSERT INTO mytable SET i = 999, s = _binary 'x';", // unsupported syntax
329+
"INSERT INTO mytable (i,s) values (1,'hi') ON DUPLICATE KEY UPDATE s=VALUES(s)", // unsupported syntax
330+
"INSERT INTO mytable (s,i) values ('dup',1) ON DUPLICATE KEY UPDATE s=CONCAT(VALUES(s), 'licate')", // unsupported syntax
331+
"INSERT INTO mytable (i,s) values (1,'mar'), (2,'par') ON DUPLICATE KEY UPDATE s=CONCAT(VALUES(s), 'tial')", // bad translation
332+
"INSERT INTO mytable (i,s) values (1,'maybe') ON DUPLICATE KEY UPDATE i=VALUES(i)+8000, s=VALUES(s)", // unsupported syntax
333+
`insert into keyless (c0, c1) select a.c0, a.c1 from (select 1, 1) as a(c0, c1) join keyless on a.c0 = keyless.c0`, // missing result element, needs investigation
334+
"with t (i,f) as (select 4,'fourth row' from dual) insert into mytable select i,f from t", // WITH unsupported syntax
335+
"with recursive t (i,f) as (select 4,4 from dual union all select i + 1, i + 1 from t where i < 5) insert into mytable select i,f from t", // WITH unsupported syntax
336+
"issue 6675: on duplicate rearranged getfield indexes from select source", // panic
337+
"issue 4857: insert cte column alias with table alias qualify panic", // WITH unsupported syntax
338+
"sql_mode=NO_auto_value_ON_ZERO", // unsupported
339+
"explicit DEFAULT", // enum type unsupported
340+
// "Try INSERT IGNORE with primary key, non null, and single row violations", // insert ignore not supported
341+
"Insert on duplicate key references table in subquery", // bad translation?
342+
"Insert on duplicate key references table in aliased subquery", // bad translation?
343+
"Insert on duplicate key references table in cte", // CTE not supported
344+
"insert on duplicate key with incorrect row alias", // column "c" could not be found in any table in scope
345+
"insert on duplicate key update errors", // failing
346+
"Insert on duplicate key references table in subquery with join", // untranslated
347+
"INSERT INTO ... SELECT works properly with ENUM", // enum unsupported
348+
"INSERT INTO ... SELECT works properly with SET", // set unsupported
349+
"INSERT INTO ... SELECT with TEXT types", // typecasts needed
350+
"check IN TUPLE constraint with duplicate key update", // error not being thrown
351+
"INSERT IGNORE works with FK Violations", // ignore not supported
352+
})
298353
defer h.Close()
299354
enginetest.TestInsertInto(t, h)
300355
}

testing/go/enginetest/doltgres_harness_test.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,6 @@ var skippedSetupWords = []string{
217217
}
218218

219219
var commentClause = regexp.MustCompile(`(?i)comment '.*?'`)
220-
var createIndexStatement = regexp.MustCompile(`(?i)create( unique)? index`)
221-
var alterTableStatement = regexp.MustCompile(`(?i)alter table`)
222220

223221
// sanitizeQuery strips the query string given of any unsupported constructs without attempting to actually convert
224222
// to Postgres syntax.
@@ -229,13 +227,6 @@ func sanitizeQuery(s string) (bool, string) {
229227
}
230228
}
231229

232-
if createIndexStatement.MatchString(s) {
233-
return false, ""
234-
}
235-
if alterTableStatement.MatchString(s) {
236-
return false, ""
237-
}
238-
239230
s = commentClause.ReplaceAllString(s, "")
240231
return true, s
241232
}

0 commit comments

Comments
 (0)