vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/from.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package planbuilder 18 19 import ( 20 "fmt" 21 "sort" 22 "strings" 23 24 "vitess.io/vitess/go/mysql/collations" 25 "vitess.io/vitess/go/vt/vtgate/evalengine" 26 27 querypb "vitess.io/vitess/go/vt/proto/query" 28 "vitess.io/vitess/go/vt/vterrors" 29 30 "vitess.io/vitess/go/vt/sqlparser" 31 "vitess.io/vitess/go/vt/vtgate/engine" 32 "vitess.io/vitess/go/vt/vtgate/vindexes" 33 ) 34 35 // This file has functions to analyze the FROM clause. 36 37 // processDMLTable analyzes the FROM clause for DMLs and returns a route. 38 func (pb *primitiveBuilder) processDMLTable(tableExprs sqlparser.TableExprs, reservedVars *sqlparser.ReservedVars, where sqlparser.Expr) (*route, error) { 39 if err := pb.processTableExprs(tableExprs, reservedVars, where); err != nil { 40 return nil, err 41 } 42 rb, ok := pb.plan.(*route) 43 if !ok { 44 return nil, vterrors.VT12001("multi-shard or vindex write statement") 45 } 46 for _, sub := range rb.substitutions { 47 *sub.oldExpr = *sub.newExpr 48 } 49 return rb, nil 50 } 51 52 // processTableExprs analyzes the FROM clause. It produces a logicalPlan 53 // with all the routes identified. 54 func (pb *primitiveBuilder) processTableExprs(tableExprs sqlparser.TableExprs, reservedVars *sqlparser.ReservedVars, where sqlparser.Expr) error { 55 if len(tableExprs) == 1 { 56 return pb.processTableExpr(tableExprs[0], reservedVars, where) 57 } 58 59 if err := pb.processTableExpr(tableExprs[0], reservedVars, where); err != nil { 60 return err 61 } 62 rpb := newPrimitiveBuilder(pb.vschema, pb.jt) 63 if err := rpb.processTableExprs(tableExprs[1:], reservedVars, where); err != nil { 64 return err 65 } 66 return pb.join(rpb, nil, reservedVars, where) 67 } 68 69 // processTableExpr produces a logicalPlan subtree for the given TableExpr. 70 func (pb *primitiveBuilder) processTableExpr(tableExpr sqlparser.TableExpr, reservedVars *sqlparser.ReservedVars, where sqlparser.Expr) error { 71 switch tableExpr := tableExpr.(type) { 72 case *sqlparser.AliasedTableExpr: 73 return pb.processAliasedTable(tableExpr, reservedVars) 74 case *sqlparser.ParenTableExpr: 75 err := pb.processTableExprs(tableExpr.Exprs, reservedVars, where) 76 // If it's a route, preserve the parenthesis so things 77 // don't associate differently when more things are pushed 78 // into it. FROM a, (b, c) should not become FROM a, b, c. 79 if rb, ok := pb.plan.(*route); ok { 80 sel, ok := rb.Select.(*sqlparser.Select) 81 if !ok { 82 return vterrors.VT13002(sqlparser.String(rb.Select)) 83 } 84 85 sel.From = sqlparser.TableExprs{&sqlparser.ParenTableExpr{Exprs: sel.From}} 86 } 87 return err 88 case *sqlparser.JoinTableExpr: 89 return pb.processJoin(tableExpr, reservedVars, where) 90 case *sqlparser.JSONTableExpr: 91 return vterrors.VT12001("JSON_TABLE expressions") 92 } 93 return vterrors.VT13001(fmt.Sprintf("unexpected table expression type: %T", tableExpr)) 94 } 95 96 // processAliasedTable produces a logicalPlan subtree for the given AliasedTableExpr. 97 // If the expression is a subquery, then the primitive will create a table 98 // for it in the symtab. If the subquery is a route, then we build a route 99 // primitive with the subquery in the From clause, because a route is more 100 // versatile than a subquery. If a subquery becomes a route, then any result 101 // columns that represent underlying vindex columns are also exposed as 102 // vindex columns. 103 func (pb *primitiveBuilder) processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, reservedVars *sqlparser.ReservedVars) error { 104 if tableExpr.Columns != nil { 105 return vterrors.VT12001("column aliases in derived table") 106 } 107 switch expr := tableExpr.Expr.(type) { 108 case sqlparser.TableName: 109 return pb.buildTablePrimitive(tableExpr, expr) 110 case *sqlparser.DerivedTable: 111 if expr.Lateral { 112 return vterrors.VT12001("lateral derived tables") 113 } 114 spb := newPrimitiveBuilder(pb.vschema, pb.jt) 115 switch stmt := expr.Select.(type) { 116 case *sqlparser.Select: 117 if err := spb.processSelect(stmt, reservedVars, nil, ""); err != nil { 118 return err 119 } 120 case *sqlparser.Union: 121 if err := spb.processUnion(stmt, reservedVars, nil); err != nil { 122 return err 123 } 124 default: 125 return vterrors.VT13001(fmt.Sprintf("unexpected SELECT type: %T", stmt)) 126 } 127 128 subroute, ok := spb.plan.(*route) 129 if !ok { 130 var err error 131 pb.plan, pb.st, err = newSimpleProjection(tableExpr.As, spb.plan) 132 if err != nil { 133 return err 134 } 135 pb.plan.Reorder(0) 136 return nil 137 } 138 139 // Since a route is more versatile than a subquery, we 140 // build a route primitive that has the subquery in its 141 // FROM clause. This allows for other constructs to be 142 // later pushed into it. 143 rb, st := newRoute(&sqlparser.Select{From: []sqlparser.TableExpr{tableExpr}}) 144 rb.substitutions = subroute.substitutions 145 rb.condition = subroute.condition 146 rb.eroute = subroute.eroute 147 subroute.Redirect = rb 148 149 // The subquery needs to be represented as a new logical table in the symtab. 150 // The new route will inherit the routeOptions of the underlying subquery. 151 // For this, we first build new vschema tables based on the columns returned 152 // by the subquery, and re-expose possible vindexes. When added to the symtab, 153 // a new set of column references will be generated against the new tables, 154 // and those vindex maps will be returned. They have to replace the old vindex 155 // maps of the inherited route options. 156 var tableNames []string 157 spbTables, err := spb.st.AllVschemaTableNames() 158 if err != nil { 159 return err 160 } 161 for _, table := range spbTables { 162 tableNames = append(tableNames, table.Name.String()) 163 } 164 sort.Strings(tableNames) 165 vschemaTable := &vindexes.Table{ 166 Keyspace: subroute.eroute.Keyspace, 167 Name: sqlparser.NewIdentifierCS(strings.Join(tableNames, ", ")), 168 } 169 for _, rc := range subroute.ResultColumns() { 170 if rc.column.vindex == nil { 171 continue 172 } 173 // Check if a colvindex of the same name already exists. 174 // Dups are not allowed in subqueries in this situation. 175 for _, colVindex := range vschemaTable.ColumnVindexes { 176 if colVindex.Columns[0].Equal(rc.alias) { 177 return vterrors.VT12001(fmt.Sprintf("duplicate column aliases: %v", rc.alias)) 178 } 179 } 180 vschemaTable.ColumnVindexes = append(vschemaTable.ColumnVindexes, &vindexes.ColumnVindex{ 181 Columns: []sqlparser.IdentifierCI{rc.alias}, 182 Vindex: rc.column.vindex, 183 }) 184 } 185 if err := st.AddVSchemaTable(sqlparser.TableName{Name: tableExpr.As}, vschemaTable, rb); err != nil { 186 return err 187 } 188 189 pb.plan, pb.st = rb, st 190 return nil 191 } 192 return vterrors.VT13001(fmt.Sprintf("unexpected table expression type: %T", tableExpr.Expr)) 193 } 194 195 // buildTablePrimitive builds a primitive based on the table name. 196 func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTableExpr, tableName sqlparser.TableName) error { 197 alias := tableName 198 if !tableExpr.As.IsEmpty() { 199 alias = sqlparser.TableName{Name: tableExpr.As} 200 } 201 sel := &sqlparser.Select{From: sqlparser.TableExprs([]sqlparser.TableExpr{tableExpr})} 202 203 if sqlparser.SystemSchema(tableName.Qualifier.String()) { 204 ks, err := pb.vschema.AnyKeyspace() 205 if err != nil { 206 return err 207 } 208 rb, st := newRoute(sel) 209 rb.eroute = engine.NewSimpleRoute(engine.DBA, ks) 210 rb.eroute.TableName = sqlparser.String(tableName) 211 pb.plan, pb.st = rb, st 212 // Add the table to symtab 213 return st.AddTable(&table{ 214 alias: alias, 215 origin: rb, 216 }) 217 } 218 219 vschemaTable, vindex, _, destTableType, destTarget, err := pb.vschema.FindTableOrVindex(tableName) 220 if err != nil { 221 return err 222 } 223 if vindex != nil { 224 single, ok := vindex.(vindexes.SingleColumn) 225 if !ok { 226 return vterrors.VT12001("multi-column vindexes") 227 } 228 pb.plan, pb.st = newVindexFunc(alias, single) 229 return nil 230 } 231 232 sourceTable, err := pb.tryRedirectGen4InsertToSource(vschemaTable) 233 if err != nil { 234 return err 235 } 236 if sourceTable != nil { 237 vschemaTable = sourceTable 238 } 239 240 rb, st := newRoute(sel) 241 pb.plan, pb.st = rb, st 242 if err := st.AddVSchemaTable(alias, vschemaTable, rb); err != nil { 243 return err 244 } 245 246 sub := &tableSubstitution{ 247 oldExpr: tableExpr, 248 } 249 if tableExpr.As.IsEmpty() { 250 if tableName.Name != vschemaTable.Name { 251 // Table name does not match. Change and alias it to old name. 252 sub.newExpr = &sqlparser.AliasedTableExpr{ 253 Expr: sqlparser.TableName{Name: vschemaTable.Name}, 254 As: tableName.Name, 255 } 256 } 257 } else { 258 // Table is already aliased. 259 if tableName.Name != vschemaTable.Name { 260 // Table name does not match. Change it and reuse existing alias. 261 sub.newExpr = &sqlparser.AliasedTableExpr{ 262 Expr: sqlparser.TableName{Name: vschemaTable.Name}, 263 As: tableExpr.As, 264 } 265 } 266 } 267 if sub != nil && sub.newExpr != nil { 268 rb.substitutions = []*tableSubstitution{sub} 269 } 270 271 var eroute *engine.Route 272 switch { 273 case vschemaTable.Type == vindexes.TypeSequence: 274 eroute = engine.NewSimpleRoute(engine.Next, vschemaTable.Keyspace) 275 case vschemaTable.Type == vindexes.TypeReference: 276 eroute = engine.NewSimpleRoute(engine.Reference, vschemaTable.Keyspace) 277 case !vschemaTable.Keyspace.Sharded: 278 eroute = engine.NewSimpleRoute(engine.Unsharded, vschemaTable.Keyspace) 279 case vschemaTable.Pinned == nil: 280 eroute = engine.NewSimpleRoute(engine.Scatter, vschemaTable.Keyspace) 281 eroute.TargetDestination = destTarget 282 eroute.TargetTabletType = destTableType 283 default: 284 // Pinned tables have their keyspace ids already assigned. 285 // Use the Binary vindex, which is the identity function 286 // for keyspace id. 287 eroute = engine.NewSimpleRoute(engine.EqualUnique, vschemaTable.Keyspace) 288 vindex, _ = vindexes.NewBinary("binary", nil) 289 eroute.Vindex = vindex 290 lit := evalengine.NewLiteralString(vschemaTable.Pinned, collations.TypedCollation{}) 291 eroute.Values = []evalengine.Expr{lit} 292 } 293 eroute.TableName = sqlparser.String(vschemaTable.Name) 294 rb.eroute = eroute 295 296 return nil 297 } 298 299 // processJoin produces a logicalPlan subtree for the given Join. 300 // If the left and right nodes can be part of the same route, 301 // then it's a route. Otherwise, it's a join. 302 func (pb *primitiveBuilder) processJoin(ajoin *sqlparser.JoinTableExpr, reservedVars *sqlparser.ReservedVars, where sqlparser.Expr) error { 303 switch ajoin.Join { 304 case sqlparser.NormalJoinType, sqlparser.StraightJoinType, sqlparser.LeftJoinType: 305 case sqlparser.RightJoinType: 306 convertToLeftJoin(ajoin) 307 default: 308 return vterrors.VT12001(ajoin.Join.ToString()) 309 } 310 if err := pb.processTableExpr(ajoin.LeftExpr, reservedVars, where); err != nil { 311 return err 312 } 313 rpb := newPrimitiveBuilder(pb.vschema, pb.jt) 314 if err := rpb.processTableExpr(ajoin.RightExpr, reservedVars, where); err != nil { 315 return err 316 } 317 return pb.join(rpb, ajoin, reservedVars, where) 318 } 319 320 // If the primitiveBuilder context is a Gen4 planner, the statement is an 321 // INSERT, and the vschema table is a reference with a valid source reference, 322 // then redirect the INSERT back to the source. 323 func (pb *primitiveBuilder) tryRedirectGen4InsertToSource(vschemaTable *vindexes.Table) (*vindexes.Table, error) { 324 if pb.stmt == nil { 325 return nil, nil 326 } 327 if _, ok := pb.stmt.(*sqlparser.Insert); !ok { 328 return nil, nil 329 } 330 if pb.vschema.Planner() == querypb.ExecuteOptions_V3 { 331 return nil, nil 332 } 333 if vschemaTable.Type != vindexes.TypeReference || vschemaTable.Source == nil { 334 return nil, nil 335 } 336 vschemaTable, _, _, _, _, err := pb.vschema.FindTableOrVindex(vschemaTable.Source.TableName) 337 return vschemaTable, err 338 } 339 340 // convertToLeftJoin converts a right join into a left join. 341 func convertToLeftJoin(ajoin *sqlparser.JoinTableExpr) { 342 newRHS := ajoin.LeftExpr 343 // If the LHS is a join, we have to parenthesize it. 344 // Otherwise, it can be used as is. 345 if _, ok := newRHS.(*sqlparser.JoinTableExpr); ok { 346 newRHS = &sqlparser.ParenTableExpr{ 347 Exprs: sqlparser.TableExprs{newRHS}, 348 } 349 } 350 ajoin.LeftExpr, ajoin.RightExpr = ajoin.RightExpr, newRHS 351 ajoin.Join = sqlparser.LeftJoinType 352 } 353 354 func (pb *primitiveBuilder) join(rpb *primitiveBuilder, ajoin *sqlparser.JoinTableExpr, reservedVars *sqlparser.ReservedVars, where sqlparser.Expr) error { 355 // Merge the symbol tables. In the case of a left join, we have to 356 // ideally create new symbols that originate from the join primitive. 357 // However, this is not worth it for now, because the Push functions 358 // verify that only valid constructs are passed through in case of left join. 359 err := pb.st.Merge(rpb.st) 360 if err != nil { 361 return err 362 } 363 364 lRoute, leftIsRoute := pb.plan.(*route) 365 rRoute, rightIsRoute := rpb.plan.(*route) 366 if !leftIsRoute || !rightIsRoute { 367 return newJoin(pb, rpb, ajoin, reservedVars) 368 } 369 370 // Try merging the routes. 371 if !lRoute.JoinCanMerge(pb, rRoute, ajoin, where) { 372 return newJoin(pb, rpb, ajoin, reservedVars) 373 } 374 375 if lRoute.eroute.Opcode == engine.Reference { 376 // Swap the conditions & eroutes, and then merge. 377 lRoute.condition, rRoute.condition = rRoute.condition, lRoute.condition 378 lRoute.eroute, rRoute.eroute = rRoute.eroute, lRoute.eroute 379 } 380 lRoute.substitutions = append(lRoute.substitutions, rRoute.substitutions...) 381 rRoute.Redirect = lRoute 382 383 // Merge the AST. 384 sel, ok := lRoute.Select.(*sqlparser.Select) 385 if !ok { 386 return vterrors.VT13002(sqlparser.String(lRoute.Select)) 387 } 388 if ajoin == nil { 389 rhsSel, ok := rRoute.Select.(*sqlparser.Select) 390 if !ok { 391 return vterrors.VT13002(sqlparser.String(rRoute.Select)) 392 } 393 sel.From = append(sel.From, rhsSel.From...) 394 } else { 395 sel.From = sqlparser.TableExprs{ajoin} 396 } 397 // join table name 398 if lRoute.eroute.TableName != rRoute.eroute.TableName { 399 lRoute.eroute.TableName = strings.Join([]string{lRoute.eroute.TableName, rRoute.eroute.TableName}, ", ") 400 } 401 402 // join sysTableNames 403 for tableName, expr := range rRoute.eroute.SysTableTableName { 404 _, ok := lRoute.eroute.SysTableTableName[tableName] 405 if !ok { 406 lRoute.eroute.SysTableTableName[tableName] = expr 407 } 408 } 409 410 // Since the routes have merged, set st.singleRoute to point at 411 // the merged route. 412 pb.st.singleRoute = lRoute 413 if ajoin == nil { 414 return nil 415 } 416 pullouts, _, expr, err := pb.findOrigin(ajoin.Condition.On, reservedVars) 417 if err != nil { 418 return err 419 } 420 ajoin.Condition.On = expr 421 pb.addPullouts(pullouts) 422 for _, filter := range sqlparser.SplitAndExpression(nil, ajoin.Condition.On) { 423 lRoute.UpdatePlan(pb, filter) 424 } 425 return nil 426 }