vitess.io/vitess@v0.16.2/go/vt/vtgate/semantics/analyzer.go (about) 1 /* 2 Copyright 2020 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 semantics 18 19 import ( 20 "vitess.io/vitess/go/mysql/collations" 21 "vitess.io/vitess/go/vt/vterrors" 22 "vitess.io/vitess/go/vt/vtgate/vindexes" 23 24 "vitess.io/vitess/go/vt/sqlparser" 25 ) 26 27 // analyzer controls the flow of the analysis. 28 // It starts the tree walking and controls which part of the analysis sees which parts of the tree 29 type analyzer struct { 30 scoper *scoper 31 tables *tableCollector 32 binder *binder 33 typer *typer 34 rewriter *earlyRewriter 35 36 err error 37 inProjection int 38 39 projErr error 40 unshardedErr error 41 warning string 42 } 43 44 // newAnalyzer create the semantic analyzer 45 func newAnalyzer(dbName string, si SchemaInformation) *analyzer { 46 // TODO dependencies between these components are a little tangled. We should try to clean up 47 s := newScoper() 48 a := &analyzer{ 49 scoper: s, 50 tables: newTableCollector(s, si, dbName), 51 typer: newTyper(), 52 } 53 s.org = a 54 a.tables.org = a 55 56 b := newBinder(s, a, a.tables, a.typer) 57 a.binder = b 58 a.rewriter = &earlyRewriter{ 59 scoper: s, 60 binder: b, 61 expandedColumns: map[sqlparser.TableName][]*sqlparser.ColName{}, 62 } 63 s.binder = b 64 return a 65 } 66 67 // Analyze analyzes the parsed query. 68 func Analyze(statement sqlparser.Statement, currentDb string, si SchemaInformation) (*SemTable, error) { 69 analyzer := newAnalyzer(currentDb, newSchemaInfo(si)) 70 71 // Analysis for initial scope 72 err := analyzer.analyze(statement) 73 if err != nil { 74 return nil, err 75 } 76 77 // Creation of the semantic table 78 semTable := analyzer.newSemTable(statement, si.ConnCollation()) 79 80 return semTable, nil 81 } 82 83 func (a *analyzer) newSemTable(statement sqlparser.Statement, coll collations.ID) *SemTable { 84 var comments *sqlparser.ParsedComments 85 commentedStmt, isCommented := statement.(sqlparser.Commented) 86 if isCommented { 87 comments = commentedStmt.GetParsedComments() 88 } 89 90 return &SemTable{ 91 Recursive: a.binder.recursive, 92 Direct: a.binder.direct, 93 ExprTypes: a.typer.exprTypes, 94 Tables: a.tables.Tables, 95 selectScope: a.scoper.rScope, 96 NotSingleRouteErr: a.projErr, 97 NotUnshardedErr: a.unshardedErr, 98 Warning: a.warning, 99 Comments: comments, 100 SubqueryMap: a.binder.subqueryMap, 101 SubqueryRef: a.binder.subqueryRef, 102 ColumnEqualities: map[columnName][]sqlparser.Expr{}, 103 Collation: coll, 104 ExpandedColumns: a.rewriter.expandedColumns, 105 } 106 } 107 108 func (a *analyzer) setError(err error) { 109 switch err := err.(type) { 110 case ProjError: 111 a.projErr = err.Inner 112 case ShardedError: 113 a.unshardedErr = err.Inner 114 default: 115 if a.inProjection > 0 && vterrors.ErrState(err) == vterrors.NonUniqError { 116 a.projErr = err 117 } else { 118 a.err = err 119 } 120 } 121 } 122 123 func (a *analyzer) analyzeDown(cursor *sqlparser.Cursor) bool { 124 // If we have an error we keep on going down the tree without checking for anything else 125 // this way we can abort when we come back up. 126 if !a.shouldContinue() { 127 return true 128 } 129 130 if err := a.scoper.down(cursor); err != nil { 131 a.setError(err) 132 return true 133 } 134 if err := a.checkForInvalidConstructs(cursor); err != nil { 135 a.setError(err) 136 return true 137 } 138 if err := a.rewriter.down(cursor); err != nil { 139 a.setError(err) 140 return true 141 } 142 // log any warn in rewriting. 143 a.warning = a.rewriter.warning 144 145 a.enterProjection(cursor) 146 // this is the visitor going down the tree. Returning false here would just not visit the children 147 // to the current node, but that is not what we want if we have encountered an error. 148 // In order to abort the whole visitation, we have to return true here and then return false in the `analyzeUp` method 149 return true 150 } 151 152 func (a *analyzer) analyzeUp(cursor *sqlparser.Cursor) bool { 153 if !a.shouldContinue() { 154 return false 155 } 156 157 if err := a.binder.up(cursor); err != nil { 158 a.setError(err) 159 return true 160 } 161 162 if err := a.scoper.up(cursor); err != nil { 163 a.setError(err) 164 return false 165 } 166 if err := a.tables.up(cursor); err != nil { 167 a.setError(err) 168 return false 169 } 170 if err := a.typer.up(cursor); err != nil { 171 a.setError(err) 172 return false 173 } 174 175 a.leaveProjection(cursor) 176 return a.shouldContinue() 177 } 178 179 func containsStar(s sqlparser.SelectExprs) bool { 180 for _, expr := range s { 181 _, isStar := expr.(*sqlparser.StarExpr) 182 if isStar { 183 return true 184 } 185 } 186 return false 187 } 188 189 func checkUnionColumns(union *sqlparser.Union) error { 190 firstProj := sqlparser.GetFirstSelect(union).SelectExprs 191 if containsStar(firstProj) { 192 // if we still have *, we can't figure out if the query is invalid or not 193 // we'll fail it at run time instead 194 return nil 195 } 196 count := len(firstProj) 197 198 secondProj := sqlparser.GetFirstSelect(union.Right).SelectExprs 199 if containsStar(secondProj) { 200 return nil 201 } 202 203 if len(secondProj) != count { 204 return NewError(UnionColumnsDoNotMatch) 205 } 206 207 return nil 208 } 209 210 /* 211 errors that happen when we are evaluating SELECT expressions are saved until we know 212 if we can merge everything into a single route or not 213 */ 214 func (a *analyzer) enterProjection(cursor *sqlparser.Cursor) { 215 _, ok := cursor.Node().(sqlparser.SelectExprs) 216 if ok && isParentSelect(cursor) { 217 a.inProjection++ 218 } 219 } 220 221 func (a *analyzer) leaveProjection(cursor *sqlparser.Cursor) { 222 _, ok := cursor.Node().(sqlparser.SelectExprs) 223 if ok && isParentSelect(cursor) { 224 a.inProjection-- 225 } 226 } 227 228 func isParentSelect(cursor *sqlparser.Cursor) bool { 229 _, isSelect := cursor.Parent().(*sqlparser.Select) 230 return isSelect 231 } 232 233 func isParentSelectStatement(cursor *sqlparser.Cursor) bool { 234 _, isSelect := cursor.Parent().(sqlparser.SelectStatement) 235 return isSelect 236 } 237 238 type originable interface { 239 tableSetFor(t *sqlparser.AliasedTableExpr) TableSet 240 depsForExpr(expr sqlparser.Expr) (direct, recursive TableSet, typ *Type) 241 } 242 243 func (a *analyzer) depsForExpr(expr sqlparser.Expr) (direct, recursive TableSet, typ *Type) { 244 recursive = a.binder.recursive.dependencies(expr) 245 direct = a.binder.direct.dependencies(expr) 246 qt, isFound := a.typer.exprTypes[expr] 247 if !isFound { 248 return 249 } 250 typ = &qt 251 return 252 } 253 254 func (a *analyzer) analyze(statement sqlparser.Statement) error { 255 _ = sqlparser.Rewrite(statement, a.analyzeDown, a.analyzeUp) 256 return a.err 257 } 258 259 func (a *analyzer) checkForInvalidConstructs(cursor *sqlparser.Cursor) error { 260 switch node := cursor.Node().(type) { 261 case *sqlparser.Update: 262 if len(node.TableExprs) != 1 { 263 return ShardedError{Inner: NewError(UnsupportedMultiTablesInUpdate)} 264 } 265 alias, isAlias := node.TableExprs[0].(*sqlparser.AliasedTableExpr) 266 if !isAlias { 267 return ShardedError{Inner: NewError(UnsupportedMultiTablesInUpdate)} 268 } 269 _, isDerived := alias.Expr.(*sqlparser.DerivedTable) 270 if isDerived { 271 return NewError(TableNotUpdatable, alias.As.String()) 272 } 273 case *sqlparser.Select: 274 parent := cursor.Parent() 275 if _, isUnion := parent.(*sqlparser.Union); isUnion && node.SQLCalcFoundRows { 276 return NewError(UnionWithSQLCalcFoundRows) 277 } 278 if _, isRoot := parent.(*sqlparser.RootNode); !isRoot && node.SQLCalcFoundRows { 279 return NewError(SQLCalcFoundRowsUsage) 280 } 281 errMsg := "INTO" 282 nextVal := false 283 if len(node.SelectExprs) == 1 { 284 if _, isNextVal := node.SelectExprs[0].(*sqlparser.Nextval); isNextVal { 285 nextVal = true 286 errMsg = "NEXT" 287 } 288 } 289 if !nextVal && node.Into == nil { 290 return nil 291 } 292 if a.scoper.currentScope().parent != nil { 293 return NewError(CantUseOptionHere, errMsg) 294 } 295 case *sqlparser.Nextval: 296 currScope := a.scoper.currentScope() 297 if currScope.parent != nil { 298 return NewError(CantUseOptionHere, "Incorrect usage/placement of 'INTO'") 299 } 300 if len(currScope.tables) != 1 { 301 return NewError(NextWithMultipleTables) 302 } 303 vindexTbl := currScope.tables[0].GetVindexTable() 304 if vindexTbl == nil { 305 return NewError(MissingInVSchema) 306 } 307 if vindexTbl.Type != vindexes.TypeSequence { 308 return NewError(NotSequenceTable) 309 } 310 case *sqlparser.JoinTableExpr: 311 if node.Join == sqlparser.NaturalJoinType || node.Join == sqlparser.NaturalRightJoinType || node.Join == sqlparser.NaturalLeftJoinType { 312 return NewError(UnsupportedNaturalJoin, node.Join.ToString()) 313 } 314 case *sqlparser.LockingFunc: 315 return NewError(LockOnlyWithDual, node) 316 case *sqlparser.Union: 317 err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { 318 switch node := node.(type) { 319 case *sqlparser.ColName: 320 if !node.Qualifier.IsEmpty() { 321 return false, NewError(QualifiedOrderInUnion, node.Qualifier.Name) 322 } 323 case *sqlparser.Subquery: 324 return false, nil 325 } 326 return true, nil 327 }, node.OrderBy) 328 if err != nil { 329 return err 330 } 331 err = checkUnionColumns(node) 332 if err != nil { 333 return err 334 } 335 case *sqlparser.JSONTableExpr: 336 return NewError(JSONTables) 337 } 338 339 return nil 340 } 341 342 func (a *analyzer) shouldContinue() bool { 343 return a.err == nil 344 } 345 346 func (a *analyzer) tableSetFor(t *sqlparser.AliasedTableExpr) TableSet { 347 return a.tables.tableSetFor(t) 348 } 349 350 // ProjError is used to mark an error as something that should only be returned 351 // if the planner fails to merge everything down to a single route 352 type ProjError struct { 353 Inner error 354 } 355 356 func (p ProjError) Error() string { 357 return p.Inner.Error() 358 } 359 360 // ShardedError is used to mark an error as something that should only be returned 361 // if the query is not unsharded 362 type ShardedError struct { 363 Inner error 364 } 365 366 func (p ShardedError) Error() string { 367 return p.Inner.Error() 368 }