diff --git a/go/vt/vtgate/planbuilder/operators/rewriters.go b/go/vt/vtgate/planbuilder/operators/rewriters.go index 1864eb952e1..e7e131ada57 100644 --- a/go/vt/vtgate/planbuilder/operators/rewriters.go +++ b/go/vt/vtgate/planbuilder/operators/rewriters.go @@ -50,9 +50,7 @@ type ( VisitRule bool ) -var ( - NoRewrite *ApplyResult = nil -) +var NoRewrite *ApplyResult = nil const ( VisitChildren VisitRule = true diff --git a/go/vt/vtgate/planbuilder/operators/route.go b/go/vt/vtgate/planbuilder/operators/route.go index 13da54e9b03..47bfbbf462f 100644 --- a/go/vt/vtgate/planbuilder/operators/route.go +++ b/go/vt/vtgate/planbuilder/operators/route.go @@ -361,7 +361,19 @@ func findVSchemaTableAndCreateRoute( tableName sqlparser.TableName, planAlternates bool, ) *Route { - vschemaTable, _, _, tabletType, target, err := ctx.VSchema.FindTableOrVindex(tableName) + var ( + vschemaTable *vindexes.BaseTable + tabletType topodatapb.TabletType + target key.ShardDestination + err error + ) + + if ctx.IsMirrored() { + vschemaTable, _, tabletType, target, err = ctx.VSchema.FindTable(tableName) + } else { + vschemaTable, _, _, tabletType, target, err = ctx.VSchema.FindTableOrVindex(tableName) + } + if err != nil { panic(err) } diff --git a/go/vt/vtgate/planbuilder/operators/route_planning.go b/go/vt/vtgate/planbuilder/operators/route_planning.go index 10b36515c42..7fc730f677d 100644 --- a/go/vt/vtgate/planbuilder/operators/route_planning.go +++ b/go/vt/vtgate/planbuilder/operators/route_planning.go @@ -60,7 +60,6 @@ func optimizeJoin(ctx *plancontext.PlanningContext, op *Join) (Operator, *ApplyR } func optimizeQueryGraph(ctx *plancontext.PlanningContext, op *QueryGraph) (result Operator, changed *ApplyResult) { - switch { case ctx.PlannerVersion == querypb.ExecuteOptions_Gen4Left2Right: result = leftToRightSolve(ctx, op) diff --git a/go/vt/vtgate/planbuilder/testdata/mirror_cases.json b/go/vt/vtgate/planbuilder/testdata/mirror_cases.json index 1edbec3d1a6..be292b7cb72 100644 --- a/go/vt/vtgate/planbuilder/testdata/mirror_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/mirror_cases.json @@ -41,6 +41,132 @@ ] } }, + { + "comment": "select from source of unsharded, unqualified, table mirrored to unsharded table with routing rules", + "query": "select t4.id from t4 where t4.id = 1", + "plan": { + "Type": "Complex", + "QueryType": "SELECT", + "Original": "select t4.id from t4 where t4.id = 1", + "Instructions": { + "OperatorType": "Mirror", + "Variant": "PercentBased", + "Percent": 10, + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_src1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + }, + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_dst1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + } + ] + }, + "TablesUsed": [ + "unsharded_dst1.t4", + "unsharded_src1.t4" + ] + } + }, + { + "comment": "select from source of unsharded, qualified, table mirrored to unsharded table with routing rules", + "query": "select t4.id from unsharded_src1.t4 where t4.id = 1", + "plan": { + "Type": "Complex", + "QueryType": "SELECT", + "Original": "select t4.id from unsharded_src1.t4 where t4.id = 1", + "Instructions": { + "OperatorType": "Mirror", + "Variant": "PercentBased", + "Percent": 10, + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_src1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + }, + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_dst1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + } + ] + }, + "TablesUsed": [ + "unsharded_dst1.t4", + "unsharded_src1.t4" + ] + } + }, + { + "comment": "select from destination of unsharded, qualified, table mirrored to unsharded table with routing rules", + "query": "select t4.id from unsharded_dst1.t4 where t4.id = 1", + "plan": { + "Type": "Complex", + "QueryType": "SELECT", + "Original": "select t4.id from unsharded_dst1.t4 where t4.id = 1", + "Instructions": { + "OperatorType": "Mirror", + "Variant": "PercentBased", + "Percent": 10, + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_src1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + }, + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "unsharded_dst1", + "Sharded": false + }, + "FieldQuery": "select t4.id from t4 where 1 != 1", + "Query": "select t4.id from t4 where t4.id = 1", + "Table": "t4" + } + ] + }, + "TablesUsed": [ + "unsharded_dst1.t4", + "unsharded_src1.t4" + ] + } + }, { "comment": "select unsharded, qualified, table mirrored to unsharded table with zero percentage", "query": "select t3.id from unsharded_src1.t3 where t3.id = 1", diff --git a/go/vt/vtgate/planbuilder/testdata/vschemas/mirror_schema.json b/go/vt/vtgate/planbuilder/testdata/vschemas/mirror_schema.json index 4feaa09c126..0beb9c33f52 100644 --- a/go/vt/vtgate/planbuilder/testdata/vschemas/mirror_schema.json +++ b/go/vt/vtgate/planbuilder/testdata/vschemas/mirror_schema.json @@ -45,6 +45,69 @@ "from_table": "unsharded_src1.t3", "to_table": "unsharded_dst1.t2", "percent": 0 + }, + { + "from_table": "unsharded_src1.t4", + "to_table": "unsharded_dst1.t4", + "percent": 10 + } + ] + }, + "routing_rules": { + "rules": [ + { + "from_table": "t4", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "t4@replica", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "t4@rdonly", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_src1.t4", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_src1.t4@replica", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_src1.t4@rdonly", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_dst1.t4", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_dst1.t4@replica", + "to_tables": [ + "unsharded_src1.t4" + ] + }, + { + "from_table": "unsharded_dst1.t4@rdonly", + "to_tables": [ + "unsharded_src1.t4" + ] } ] }, diff --git a/go/vt/vtgate/semantics/table_collector.go b/go/vt/vtgate/semantics/table_collector.go index d2740afaee9..4eed6f4eb93 100644 --- a/go/vt/vtgate/semantics/table_collector.go +++ b/go/vt/vtgate/semantics/table_collector.go @@ -554,7 +554,11 @@ func (etc *earlyTableCollector) createTable( return nil, err } - mr, err := etc.si.FindMirrorRule(t) + tblName := t + if tbl != nil && tbl.Keyspace != nil { + tblName = tbl.GetTableName() + } + mr, err := etc.si.FindMirrorRule(tblName) if err != nil { // Mirroring is best effort. If we get an error while mirroring, keep going // as if mirroring was disabled. We don't want to interrupt production work