Skip to content
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
15 changes: 15 additions & 0 deletions data/test/vtgate/dml_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,21 @@
}
}

# update with target destination
"update `user[-]`.user_extra set val = 1"
{
"Original": "update `user[-]`.user_extra set val = 1",
"Instructions": {
"Opcode": "UpdateByDestination",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"Query": "update user_extra set val = 1",
"Table": "user_extra"
}
}

# update with no primary vindex on where clause (scatter update) - multi shard autocommit
"update /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */ user_extra set val = 1"
{
Expand Down
8 changes: 4 additions & 4 deletions data/test/vtgate/unsupported_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
"select * from `user[-]`.user_metadata"
"unsupported: SELECT with a target destination"

# Unsupported UPDATE statement with a target destination
"update `user[-]`.user_metadata set id=2"
"unsupported: UPDATE with a target destination"

# Unsupported INSERT statement with a target destination
"insert into `user[-]`.user_metadata (a, b) values (1,2)"
"unsupported: INSERT with a target destination"
Expand All @@ -51,6 +47,10 @@
"DELETE FROM `user[-]@replica`.user_metadata limit 1"
"unsupported: DELETE statement with a replica target"

# Unsupported UPDATE statement with a replica target destination
"update `user[-]@replica`.user_metadata set id=2"
"unsupported: UPDATE statement with a replica target"

# order by on a cross-shard subquery
"select id from (select user.id, user.col from user join user_extra) as t order by id"
"unsupported: cannot order by on a cross-shard subquery"
Expand Down
5 changes: 5 additions & 0 deletions go/vt/vtgate/engine/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"vitess.io/vitess/go/vt/vtgate/vindexes"

querypb "vitess.io/vitess/go/vt/proto/query"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)

var _ Primitive = (*Route)(nil)
Expand All @@ -50,6 +51,10 @@ type Route struct {
// This bypases the core of the v3 engine.
TargetDestination key.Destination

// TargetTabletType specifies an explicit target destination tablet type
// this is only used in conjunction with TargetDestination
TargetTabletType topodatapb.TabletType

// Query specifies the query to be executed.
Query string

Expand Down
17 changes: 14 additions & 3 deletions go/vt/vtgate/engine/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type Update struct {
// Keyspace specifies the keyspace to send the query to.
Keyspace *vindexes.Keyspace

// TargetDestination specifies the destination to send the query to.
TargetDestination key.Destination

// Query specifies the query to be executed.
Query string

Expand Down Expand Up @@ -115,12 +118,18 @@ const (
// UpdateScatter is for routing a scattered
// update statement.
UpdateScatter
// UpdateByDestination is to route explicitly to a given
// target destination. Is used when the query explicitly sets a target destination:
// in the clause:
// e.g: UPDATE `keyspace[-]`.x1 SET foo=1
UpdateByDestination
)

var updName = map[UpdateOpcode]string{
UpdateUnsharded: "UpdateUnsharded",
UpdateEqual: "UpdateEqual",
UpdateScatter: "UpdateScatter",
UpdateUnsharded: "UpdateUnsharded",
UpdateEqual: "UpdateEqual",
UpdateScatter: "UpdateScatter",
UpdateByDestination: "UpdateByDestination",
}

// MarshalJSON serializes the UpdateOpcode as a JSON string.
Expand All @@ -143,6 +152,8 @@ func (upd *Update) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVar
return upd.execUpdateEqual(vcursor, bindVars)
case UpdateScatter:
return upd.execUpdateByDestination(vcursor, bindVars, key.DestinationAllShards{})
case UpdateByDestination:
return upd.execUpdateByDestination(vcursor, bindVars, upd.TargetDestination)
default:
// Unreachable.
return nil, fmt.Errorf("unsupported opcode: %v", upd)
Expand Down
3 changes: 2 additions & 1 deletion go/vt/vtgate/planbuilder/from.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl
return nil
}

table, vindex, _, _, destTarget, err := pb.vschema.FindTableOrVindex(tableName)
table, vindex, _, destTableType, destTarget, err := pb.vschema.FindTableOrVindex(tableName)
if err != nil {
return err
}
Expand All @@ -183,6 +183,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl
Opcode: engine.SelectScatter,
Keyspace: table.Keyspace,
TargetDestination: destTarget,
TargetTabletType: destTableType,
}
return nil
}
Expand Down
14 changes: 11 additions & 3 deletions go/vt/vtgate/planbuilder/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"vitess.io/vitess/go/vt/vtgate/engine"
"vitess.io/vitess/go/vt/vtgate/vindexes"

topodatapb "vitess.io/vitess/go/vt/proto/topodata"
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)

Expand All @@ -42,9 +43,6 @@ func buildUpdatePlan(upd *sqlparser.Update, vschema ContextVSchema) (*engine.Upd
if !ok {
return nil, errors.New("unsupported: multi-table/vindex update statement in sharded keyspace")
}
if rb.ERoute.TargetDestination != nil {
return nil, errors.New("unsupported: UPDATE with a target destination")
}
eupd.Keyspace = rb.ERoute.Keyspace
if !eupd.Keyspace.Sharded {
// We only validate non-table subexpressions because the previous analysis has already validated them.
Expand Down Expand Up @@ -76,6 +74,16 @@ func buildUpdatePlan(upd *sqlparser.Update, vschema ContextVSchema) (*engine.Upd
return nil, errors.New("internal error: table.vindexTable is mysteriously nil")
}
var err error

if rb.ERoute.TargetDestination != nil {
if rb.ERoute.TargetTabletType != topodatapb.TabletType_MASTER {
return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported: UPDATE statement with a replica target")
}
eupd.Opcode = engine.UpdateByDestination
eupd.TargetDestination = rb.ERoute.TargetDestination
return eupd, nil
}

eupd.Vindex, eupd.Values, err = getDMLRouting(upd.Where, eupd.Table)
if err != nil {
eupd.Opcode = engine.UpdateScatter
Expand Down