diff --git a/go/vt/sqlparser/ast_funcs.go b/go/vt/sqlparser/ast_funcs.go index 201a0b8315c..af57e02ee88 100644 --- a/go/vt/sqlparser/ast_funcs.go +++ b/go/vt/sqlparser/ast_funcs.go @@ -2145,6 +2145,18 @@ func RemoveKeyspace(in SQLNode) { }, in) } +// RemoveKeyspaceInTables removes the database qualifier for all table names in the AST +func RemoveKeyspaceInTables(in SQLNode) { + Rewrite(in, nil, func(cursor *Cursor) bool { + if tbl, ok := cursor.Node().(TableName); ok && !tbl.Qualifier.IsEmpty() { + tbl.Qualifier = NewIdentifierCS("") + cursor.Replace(tbl) + } + + return true + }) +} + func convertStringToInt(integer string) int { val, _ := strconv.Atoi(integer) return val diff --git a/go/vt/vtgate/planbuilder/operators/merging.go b/go/vt/vtgate/planbuilder/operators/merging.go index ef8da1ef280..6055eb4354d 100644 --- a/go/vt/vtgate/planbuilder/operators/merging.go +++ b/go/vt/vtgate/planbuilder/operators/merging.go @@ -274,6 +274,8 @@ func (s *subQueryMerger) markPredicateInOuterRouting(outer *ShardedRouting, inne func (s *subQueryMerger) mergeTables(outer, inner *ShardedRouting, op1, op2 *Route) (*Route, error) { s.subq.ExtractedSubquery.Merged = true + // we need to make sure that table qualifiers are removed before sending the query to MySQL + sqlparser.RemoveKeyspaceInTables(s.subq.ExtractedSubquery) routing, err := s.markPredicateInOuterRouting(outer, inner) if err != nil { diff --git a/go/vt/vtgate/planbuilder/testdata/expected/onecase.json b/go/vt/vtgate/planbuilder/testdata/expected/onecase.json new file mode 100644 index 00000000000..401ed4e9d43 --- /dev/null +++ b/go/vt/vtgate/planbuilder/testdata/expected/onecase.json @@ -0,0 +1,85 @@ +[ + { + "comment": "Add your test case here for debugging and run go test -run=One.", + "query": "select (select count(*) from user_extra) x from user order by x", + "plan": { + "QueryType": "SELECT", + "Original": "select (select count(*) from user_extra) x from user order by x", + "Instructions": { + "OperatorType": "UncorrelatedSubquery", + "Variant": "PulloutValue", + "PulloutVars": [ + "__sq1" + ], + "Inputs": [ + { + "InputName": "SubQuery", + "OperatorType": "Aggregate", + "Variant": "Scalar", + "Aggregates": "sum_count_star(0) AS count(*)", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select count(*) from user_extra where 1 != 1", + "Query": "select count(*) from user_extra", + "Table": "user_extra" + } + ] + }, + { + "InputName": "Outer", + "OperatorType": "UncorrelatedSubquery", + "Variant": "PulloutValue", + "PulloutVars": [ + "__sq1" + ], + "Inputs": [ + { + "InputName": "SubQuery", + "OperatorType": "Aggregate", + "Variant": "Scalar", + "Aggregates": "sum_count_star(0) AS count(*)", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select count(*) from user_extra where 1 != 1", + "Query": "select count(*) from user_extra", + "Table": "user_extra" + } + ] + }, + { + "InputName": "Outer", + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select :__sq1 as x, __sq1, weight_string(__sq1) from `user` where 1 != 1", + "OrderBy": "(1|2) ASC", + "Query": "select :__sq1 as x, __sq1, weight_string(__sq1) from `user` order by __sq1 asc", + "ResultColumns": 1, + "Table": "`user`" + } + ] + } + ] + }, + "TablesUsed": [ + "user.user", + "user.user_extra" + ] + } + } +] diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.json b/go/vt/vtgate/planbuilder/testdata/filter_cases.json index c596875f2df..f693d9a089a 100644 --- a/go/vt/vtgate/planbuilder/testdata/filter_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.json @@ -846,6 +846,64 @@ ] } }, + { + "comment": "Merging subqueries should remove keyspace from query", + "query": "select u.id from user.user as u where not exists (select 1 from user.user_extra as ue where u.id = ue.user_id)", + "v3-plan": { + "QueryType": "SELECT", + "Original": "select u.id from user.user as u where not exists (select 1 from user.user_extra as ue where u.id = ue.user_id)", + "Instructions": { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select u.id from `user` as u where 1 != 1", + "Query": "select u.id from `user` as u where not exists (select 1 from user_extra as ue where u.id = ue.user_id limit 1)", + "Table": "`user`" + } + }, + "gen4-plan": { + "QueryType": "SELECT", + "Original": "select u.id from user.user as u where not exists (select 1 from user.user_extra as ue where u.id = ue.user_id)", + "Instructions": { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select u.id from `user` as u where 1 != 1", + "Query": "select u.id from `user` as u where not exists (select 1 from user_extra as ue where u.id = ue.user_id limit 1)", + "Table": "`user`" + }, + "TablesUsed": [ + "user.user", + "user.user_extra" + ] + } + }, + { + "comment": "Check that we don't remove information_schema qualifier", + "query": "select 1 from information_schema.tables where exists(select 1 from information_schema.tables where table_name = 'tables')", + "plan": { + "QueryType": "SELECT", + "Original": "select 1 from information_schema.tables where exists(select 1 from information_schema.tables where table_name = 'tables')", + "Instructions": { + "OperatorType": "Route", + "Variant": "DBA", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select 1 from information_schema.`tables` where 1 != 1", + "Query": "select 1 from information_schema.`tables` where exists (select 1 from information_schema.`tables` where table_name = :table_name /* VARCHAR */ limit 1)", + "SysTableTableName": "[table_name:VARCHAR(\"tables\")]", + "Table": "information_schema.`tables`" + } + }}, + { "comment": "Composite IN: tuple inside tuple", "query": "select id from user where ((col1, name), col2) in ((('aa', 'bb'), 'cc'), (('dd', 'ee'), 'ff'))",