vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/logical.go (about)

     1  /*
     2  Copyright 2022 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 operators
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"vitess.io/vitess/go/vt/sqlparser"
    23  	"vitess.io/vitess/go/vt/vterrors"
    24  	"vitess.io/vitess/go/vt/vtgate/engine"
    25  	"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops"
    26  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    27  	"vitess.io/vitess/go/vt/vtgate/semantics"
    28  )
    29  
    30  // createLogicalOperatorFromAST creates an operator tree that represents the input SELECT or UNION query
    31  func createLogicalOperatorFromAST(ctx *plancontext.PlanningContext, selStmt sqlparser.Statement) (op ops.Operator, err error) {
    32  	switch node := selStmt.(type) {
    33  	case *sqlparser.Select:
    34  		op, err = createOperatorFromSelect(ctx, node)
    35  	case *sqlparser.Union:
    36  		op, err = createOperatorFromUnion(ctx, node)
    37  	case *sqlparser.Update:
    38  		op, err = createOperatorFromUpdate(ctx, node)
    39  	case *sqlparser.Delete:
    40  		op, err = createOperatorFromDelete(ctx, node)
    41  	default:
    42  		err = vterrors.VT12001(fmt.Sprintf("operator: %T", selStmt))
    43  	}
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	return op, nil
    49  }
    50  
    51  // createOperatorFromSelect creates an operator tree that represents the input SELECT query
    52  func createOperatorFromSelect(ctx *plancontext.PlanningContext, sel *sqlparser.Select) (ops.Operator, error) {
    53  	subq, err := createSubqueryFromStatement(ctx, sel)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	op, err := crossJoin(ctx, sel.From)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	if sel.Where != nil {
    62  		exprs := sqlparser.SplitAndExpression(nil, sel.Where.Expr)
    63  		for _, expr := range exprs {
    64  			sqlparser.RemoveKeyspaceFromColName(expr)
    65  			op, err = op.AddPredicate(ctx, expr)
    66  			if err != nil {
    67  				return nil, err
    68  			}
    69  			addColumnEquality(ctx, expr)
    70  		}
    71  	}
    72  	if subq == nil {
    73  		return &Horizon{
    74  			Source: op,
    75  			Select: sel,
    76  		}, nil
    77  	}
    78  	subq.Outer = op
    79  	return &Horizon{
    80  		Source: subq,
    81  		Select: sel,
    82  	}, nil
    83  }
    84  
    85  func createOperatorFromUnion(ctx *plancontext.PlanningContext, node *sqlparser.Union) (ops.Operator, error) {
    86  	opLHS, err := createLogicalOperatorFromAST(ctx, node.Left)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	_, isRHSUnion := node.Right.(*sqlparser.Union)
    92  	if isRHSUnion {
    93  		return nil, vterrors.VT12001("nesting of UNIONs on the right-hand side")
    94  	}
    95  	opRHS, err := createLogicalOperatorFromAST(ctx, node.Right)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	union := &Union{
   101  		Distinct: node.Distinct,
   102  		Sources:  []ops.Operator{opLHS, opRHS},
   103  		Ordering: node.OrderBy,
   104  	}
   105  	return &Horizon{Source: union, Select: node}, nil
   106  }
   107  
   108  func createOperatorFromUpdate(ctx *plancontext.PlanningContext, updStmt *sqlparser.Update) (ops.Operator, error) {
   109  	tableInfo, qt, err := createQueryTableForDML(ctx, updStmt.TableExprs[0], updStmt.Where)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	assignments := make(map[string]sqlparser.Expr)
   115  	for _, set := range updStmt.Exprs {
   116  		assignments[set.Name.Name.String()] = set.Expr
   117  	}
   118  
   119  	vindexTable, opCode, dest, err := buildVindexTableForDML(ctx, tableInfo, qt, "update")
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	vp, cvv, ovq, err := getUpdateVindexInformation(updStmt, vindexTable, qt.ID, qt.Predicates)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	r := &Route{
   130  		Source: &Update{
   131  			QTable:              qt,
   132  			VTable:              vindexTable,
   133  			Assignments:         assignments,
   134  			ChangedVindexValues: cvv,
   135  			OwnedVindexQuery:    ovq,
   136  			AST:                 updStmt,
   137  		},
   138  		RouteOpCode:       opCode,
   139  		Keyspace:          vindexTable.Keyspace,
   140  		VindexPreds:       vp,
   141  		TargetDestination: dest,
   142  	}
   143  
   144  	for _, predicate := range qt.Predicates {
   145  		err := r.UpdateRoutingLogic(ctx, predicate)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  	}
   150  
   151  	if r.RouteOpCode == engine.Scatter && updStmt.Limit != nil {
   152  		// TODO systay: we should probably check for other op code types - IN could also hit multiple shards (2022-04-07)
   153  		return nil, vterrors.VT12001("multi shard UPDATE with LIMIT")
   154  	}
   155  
   156  	subq, err := createSubqueryFromStatement(ctx, updStmt)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	if subq == nil {
   161  		return r, nil
   162  	}
   163  	subq.Outer = r
   164  	return subq, nil
   165  }
   166  
   167  func createOperatorFromDelete(ctx *plancontext.PlanningContext, deleteStmt *sqlparser.Delete) (ops.Operator, error) {
   168  	tableInfo, qt, err := createQueryTableForDML(ctx, deleteStmt.TableExprs[0], deleteStmt.Where)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	vindexTable, opCode, dest, err := buildVindexTableForDML(ctx, tableInfo, qt, "delete")
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  
   178  	del := &Delete{
   179  		QTable: qt,
   180  		VTable: vindexTable,
   181  		AST:    deleteStmt,
   182  	}
   183  	route := &Route{
   184  		Source:            del,
   185  		RouteOpCode:       opCode,
   186  		Keyspace:          vindexTable.Keyspace,
   187  		TargetDestination: dest,
   188  	}
   189  
   190  	if !vindexTable.Keyspace.Sharded {
   191  		return route, nil
   192  	}
   193  
   194  	primaryVindex, vindexAndPredicates, err := getVindexInformation(qt.ID, qt.Predicates, vindexTable)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	route.VindexPreds = vindexAndPredicates
   200  
   201  	var ovq string
   202  	if len(vindexTable.Owned) > 0 {
   203  		tblExpr := &sqlparser.AliasedTableExpr{Expr: sqlparser.TableName{Name: vindexTable.Name}, As: qt.Alias.As}
   204  		ovq = generateOwnedVindexQuery(tblExpr, deleteStmt, vindexTable, primaryVindex.Columns)
   205  	}
   206  
   207  	del.OwnedVindexQuery = ovq
   208  
   209  	for _, predicate := range qt.Predicates {
   210  		err := route.UpdateRoutingLogic(ctx, predicate)
   211  		if err != nil {
   212  			return nil, err
   213  		}
   214  	}
   215  
   216  	if route.RouteOpCode == engine.Scatter && deleteStmt.Limit != nil {
   217  		// TODO systay: we should probably check for other op code types - IN could also hit multiple shards (2022-04-07)
   218  		return nil, vterrors.VT12001("multi shard DELETE with LIMIT")
   219  	}
   220  
   221  	subq, err := createSubqueryFromStatement(ctx, deleteStmt)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  	if subq == nil {
   226  		return route, nil
   227  	}
   228  	subq.Outer = route
   229  	return subq, nil
   230  }
   231  
   232  func getOperatorFromTableExpr(ctx *plancontext.PlanningContext, tableExpr sqlparser.TableExpr) (ops.Operator, error) {
   233  	switch tableExpr := tableExpr.(type) {
   234  	case *sqlparser.AliasedTableExpr:
   235  		return getOperatorFromAliasedTableExpr(ctx, tableExpr)
   236  	case *sqlparser.JoinTableExpr:
   237  		return getOperatorFromJoinTableExpr(ctx, tableExpr)
   238  	case *sqlparser.ParenTableExpr:
   239  		return crossJoin(ctx, tableExpr.Exprs)
   240  	default:
   241  		return nil, vterrors.VT13001(fmt.Sprintf("unable to use: %T table type", tableExpr))
   242  	}
   243  }
   244  
   245  func getOperatorFromJoinTableExpr(ctx *plancontext.PlanningContext, tableExpr *sqlparser.JoinTableExpr) (ops.Operator, error) {
   246  	lhs, err := getOperatorFromTableExpr(ctx, tableExpr.LeftExpr)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	rhs, err := getOperatorFromTableExpr(ctx, tableExpr.RightExpr)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	switch tableExpr.Join {
   256  	case sqlparser.NormalJoinType:
   257  		return createInnerJoin(ctx, tableExpr, lhs, rhs)
   258  	case sqlparser.LeftJoinType, sqlparser.RightJoinType:
   259  		return createOuterJoin(tableExpr, lhs, rhs)
   260  	default:
   261  		return nil, vterrors.VT13001("unsupported: %s", tableExpr.Join.ToString())
   262  	}
   263  }
   264  
   265  func getOperatorFromAliasedTableExpr(ctx *plancontext.PlanningContext, tableExpr *sqlparser.AliasedTableExpr) (ops.Operator, error) {
   266  	switch tbl := tableExpr.Expr.(type) {
   267  	case sqlparser.TableName:
   268  		tableID := ctx.SemTable.TableSetFor(tableExpr)
   269  		tableInfo, err := ctx.SemTable.TableInfoFor(tableID)
   270  		if err != nil {
   271  			return nil, err
   272  		}
   273  
   274  		if vt, isVindex := tableInfo.(*semantics.VindexTable); isVindex {
   275  			solves := ctx.SemTable.TableSetFor(tableExpr)
   276  			return &Vindex{
   277  				Table: VindexTable{
   278  					TableID: tableID,
   279  					Alias:   tableExpr,
   280  					Table:   tbl,
   281  					VTable:  vt.Table.GetVindexTable(),
   282  				},
   283  				Vindex: vt.Vindex,
   284  				Solved: solves,
   285  			}, nil
   286  		}
   287  		qg := newQueryGraph()
   288  		isInfSchema := tableInfo.IsInfSchema()
   289  		qt := &QueryTable{Alias: tableExpr, Table: tbl, ID: tableID, IsInfSchema: isInfSchema}
   290  		qg.Tables = append(qg.Tables, qt)
   291  		return qg, nil
   292  	case *sqlparser.DerivedTable:
   293  		inner, err := createLogicalOperatorFromAST(ctx, tbl.Select)
   294  		if err != nil {
   295  			return nil, err
   296  		}
   297  		if horizon, ok := inner.(*Horizon); ok {
   298  			inner = horizon.Source
   299  		}
   300  
   301  		return &Derived{Alias: tableExpr.As.String(), Source: inner, Query: tbl.Select, ColumnAliases: tableExpr.Columns}, nil
   302  	default:
   303  		return nil, vterrors.VT13001(fmt.Sprintf("unable to use: %T", tbl))
   304  	}
   305  }
   306  
   307  func crossJoin(ctx *plancontext.PlanningContext, exprs sqlparser.TableExprs) (ops.Operator, error) {
   308  	var output ops.Operator
   309  	for _, tableExpr := range exprs {
   310  		op, err := getOperatorFromTableExpr(ctx, tableExpr)
   311  		if err != nil {
   312  			return nil, err
   313  		}
   314  		if output == nil {
   315  			output = op
   316  		} else {
   317  			output = createJoin(ctx, output, op)
   318  		}
   319  	}
   320  	return output, nil
   321  }
   322  
   323  func createQueryTableForDML(ctx *plancontext.PlanningContext, tableExpr sqlparser.TableExpr, whereClause *sqlparser.Where) (semantics.TableInfo, *QueryTable, error) {
   324  	alTbl, ok := tableExpr.(*sqlparser.AliasedTableExpr)
   325  	if !ok {
   326  		return nil, nil, vterrors.VT13001("expected AliasedTableExpr")
   327  	}
   328  	tblName, ok := alTbl.Expr.(sqlparser.TableName)
   329  	if !ok {
   330  		return nil, nil, vterrors.VT13001("expected TableName")
   331  	}
   332  
   333  	tableID := ctx.SemTable.TableSetFor(alTbl)
   334  	tableInfo, err := ctx.SemTable.TableInfoFor(tableID)
   335  	if err != nil {
   336  		return nil, nil, err
   337  	}
   338  
   339  	if tableInfo.IsInfSchema() {
   340  		return nil, nil, vterrors.VT12001("update information schema tables")
   341  	}
   342  
   343  	var predicates []sqlparser.Expr
   344  	if whereClause != nil {
   345  		predicates = sqlparser.SplitAndExpression(nil, whereClause.Expr)
   346  	}
   347  	qt := &QueryTable{
   348  		ID:          tableID,
   349  		Alias:       alTbl,
   350  		Table:       tblName,
   351  		Predicates:  predicates,
   352  		IsInfSchema: false,
   353  	}
   354  	return tableInfo, qt, nil
   355  }
   356  
   357  func addColumnEquality(ctx *plancontext.PlanningContext, expr sqlparser.Expr) {
   358  	switch expr := expr.(type) {
   359  	case *sqlparser.ComparisonExpr:
   360  		if expr.Operator != sqlparser.EqualOp {
   361  			return
   362  		}
   363  
   364  		if left, isCol := expr.Left.(*sqlparser.ColName); isCol {
   365  			ctx.SemTable.AddColumnEquality(left, expr.Right)
   366  		}
   367  		if right, isCol := expr.Right.(*sqlparser.ColName); isCol {
   368  			ctx.SemTable.AddColumnEquality(right, expr.Left)
   369  		}
   370  	}
   371  }