diff --git a/go/test/endtoend/preparestmt/stmt_methods_test.go b/go/test/endtoend/preparestmt/stmt_methods_test.go index bcb9e70bd44..9a52ef0f409 100644 --- a/go/test/endtoend/preparestmt/stmt_methods_test.go +++ b/go/test/endtoend/preparestmt/stmt_methods_test.go @@ -31,6 +31,33 @@ import ( "vitess.io/vitess/go/vt/vtgate/engine" ) +// TestDMLNone tests that impossible query run without an error. +func TestDMLNone(t *testing.T) { + dbo := Connect(t) + defer dbo.Close() + + t.Run("delete none", func(t *testing.T) { + dmlquery(t, dbo, "delete from sks.t1 where 1 = 0") + }) + t.Run("update none", func(t *testing.T) { + dmlquery(t, dbo, "update sks.t1 set age = 5 where 1 = 0") + }) +} + +func dmlquery(t *testing.T, dbo *sql.DB, query string) { + stmt, err := dbo.Prepare(query) + require.NoError(t, err) + defer stmt.Close() + + qr, err := stmt.Exec() + require.NoError(t, err) + + ra, err := qr.RowsAffected() + require.NoError(t, err) + + require.Zero(t, ra) +} + // TestSelect simple select the data without any condition. func TestSelect(t *testing.T) { dbo := Connect(t) diff --git a/go/test/endtoend/vtgate/queries/timeout/timeout_test.go b/go/test/endtoend/vtgate/queries/timeout/timeout_test.go index dd922d023db..858c6c80c74 100644 --- a/go/test/endtoend/vtgate/queries/timeout/timeout_test.go +++ b/go/test/endtoend/vtgate/queries/timeout/timeout_test.go @@ -99,7 +99,7 @@ func TestQueryTimeoutWithTables(t *testing.T) { utils.Exec(t, mcmp.VtConn, "select /*vt+ QUERY_TIMEOUT_MS=500 */ sleep(0.1) from t1 where id1 = 1") _, err = utils.ExecAllowError(t, mcmp.VtConn, "select /*vt+ QUERY_TIMEOUT_MS=20 */ sleep(0.1) from t1 where id1 = 1") require.Error(t, err) - assert.ErrorContains(t, err, "context deadline exceeded") + assert.ErrorContains(t, err, "DeadlineExceeded") assert.ErrorContains(t, err, "(errno 1317) (sqlstate 70100)") } diff --git a/go/vt/vtgate/engine/delete.go b/go/vt/vtgate/engine/delete.go index f20f70ba187..5ff18809c4c 100644 --- a/go/vt/vtgate/engine/delete.go +++ b/go/vt/vtgate/engine/delete.go @@ -51,6 +51,8 @@ func (del *Delete) TryExecute(ctx context.Context, vcursor VCursor, bindVars map } switch del.Opcode { + case None: + return &sqltypes.Result{}, nil case Unsharded: return del.execUnsharded(ctx, del, vcursor, bindVars, rss) case Equal, IN, Scatter, ByDestination, SubShard, EqualUnique, MultiEqual: diff --git a/go/vt/vtgate/engine/update.go b/go/vt/vtgate/engine/update.go index 9e878ffce20..07c36428295 100644 --- a/go/vt/vtgate/engine/update.go +++ b/go/vt/vtgate/engine/update.go @@ -61,6 +61,8 @@ func (upd *Update) TryExecute(ctx context.Context, vcursor VCursor, bindVars map } switch upd.Opcode { + case None: + return &sqltypes.Result{}, nil case Unsharded: return upd.execUnsharded(ctx, upd, vcursor, bindVars, rss) case Equal, EqualUnique, IN, Scatter, ByDestination, SubShard, MultiEqual: diff --git a/go/vt/vtgate/planbuilder/operator_transformers.go b/go/vt/vtgate/planbuilder/operator_transformers.go index fcd4f64fc2f..2a26f114a1d 100644 --- a/go/vt/vtgate/planbuilder/operator_transformers.go +++ b/go/vt/vtgate/planbuilder/operator_transformers.go @@ -761,6 +761,10 @@ func buildUpdatePrimitive( upd := dmlOp.(*operators.Update) var vindexes []*vindexes.ColumnVindex vQuery := "" + if rb.Routing.OpCode() == engine.None { + // reset as no modification will happen for an impossible query. + upd.ChangedVindexValues = nil + } if len(upd.ChangedVindexValues) > 0 { upd.OwnedVindexQuery.From = stmt.GetFrom() upd.OwnedVindexQuery.Where = stmt.Where @@ -811,7 +815,12 @@ func createDMLPrimitive(ctx *plancontext.PlanningContext, rb *operators.Route, h FetchLastInsertID: ctx.SemTable.ShouldFetchLastInsertID(), } - if rb.Routing.OpCode() != engine.Unsharded && vindexQuery != "" { + if rb.Routing.OpCode() == engine.None { + // reset as no modification will happen for an impossible query. + edml.OwnedVindexQuery = "" + edml.Vindex = nil + edml.Values = nil + } else if rb.Routing.OpCode() != engine.Unsharded && vindexQuery != "" { primary := vTbl.ColumnVindexes[0] edml.KsidVindex = primary.Vindex edml.KsidLength = len(primary.Columns) diff --git a/go/vt/vtgate/planbuilder/testdata/dml_cases.json b/go/vt/vtgate/planbuilder/testdata/dml_cases.json index cf70ff8216b..370d24af4f3 100644 --- a/go/vt/vtgate/planbuilder/testdata/dml_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/dml_cases.json @@ -11,6 +11,50 @@ "plan": "table nouser not found", "skip_e2e": true }, + { + "comment": "delete none", + "query": "delete from user where 1 = 0", + "plan": { + "Type": "Local", + "QueryType": "DELETE", + "Original": "delete from user where 1 = 0", + "Instructions": { + "OperatorType": "Delete", + "Variant": "None", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "delete from `user` where 0", + "Table": "user" + }, + "TablesUsed": [ + "user.user" + ] + } + }, + { + "comment": "update none", + "query": "update user set name = 'xyz' where 1 = 0", + "plan": { + "Type": "Local", + "QueryType": "UPDATE", + "Original": "update user set name = 'xyz' where 1 = 0", + "Instructions": { + "OperatorType": "Update", + "Variant": "None", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "update `user` set `name` = 'xyz' where 0", + "Table": "user" + }, + "TablesUsed": [ + "user.user" + ] + } + }, { "comment": "explicit keyspace reference", "query": "update main.m1 set val = 1",