vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/horizon_planning.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  
    22  	"vitess.io/vitess/go/sqltypes"
    23  	"vitess.io/vitess/go/vt/vtgate/planbuilder/operators"
    24  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    25  
    26  	"vitess.io/vitess/go/vt/vtgate/semantics"
    27  
    28  	"vitess.io/vitess/go/vt/vterrors"
    29  
    30  	"vitess.io/vitess/go/vt/sqlparser"
    31  	"vitess.io/vitess/go/vt/vtgate/engine"
    32  )
    33  
    34  type horizonPlanning struct {
    35  	sel *sqlparser.Select
    36  	qp  *operators.QueryProjection
    37  }
    38  
    39  func (hp *horizonPlanning) planHorizon(ctx *plancontext.PlanningContext, plan logicalPlan, truncateColumns bool) (logicalPlan, error) {
    40  	rb, isRoute := plan.(*routeGen4)
    41  	if !isRoute && ctx.SemTable.NotSingleRouteErr != nil {
    42  		// If we got here, we don't have a single shard plan
    43  		return nil, ctx.SemTable.NotSingleRouteErr
    44  	}
    45  
    46  	if isRoute && rb.isSingleShard() {
    47  		err := planSingleShardRoutePlan(hp.sel, rb)
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  		return plan, nil
    52  	}
    53  
    54  	// If the current plan is a simpleProjection, we want to rewrite derived expression.
    55  	// In transformDerivedPlan (operator_transformers.go), derived tables that are not
    56  	// a simple route are put behind a simpleProjection. In this simple projection,
    57  	// every Route will represent the original derived table. Thus, pushing new expressions
    58  	// to those Routes require us to rewrite them.
    59  	// On the other hand, when a derived table is a simple Route, we do not put it under
    60  	// a simpleProjection. We create a new Route that contains the derived table in the
    61  	// FROM clause. Meaning that, when we push expressions to the select list of this
    62  	// new Route, we do not want them to rewrite them.
    63  	sp, derivedTable := plan.(*simpleProjection)
    64  	if derivedTable {
    65  		oldRewriteDerivedExpr := ctx.RewriteDerivedExpr
    66  		defer func() {
    67  			ctx.RewriteDerivedExpr = oldRewriteDerivedExpr
    68  		}()
    69  		ctx.RewriteDerivedExpr = true
    70  	}
    71  
    72  	var err error
    73  	hp.qp, err = operators.CreateQPFromSelect(ctx, hp.sel)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	needsOrdering := len(hp.qp.OrderExprs) > 0
    79  
    80  	// If we still have a HAVING clause, it's because it could not be pushed to the WHERE,
    81  	// so it probably has aggregations
    82  	canShortcut := isRoute && hp.sel.Having == nil && !needsOrdering
    83  
    84  	switch {
    85  	case hp.qp.NeedsAggregation() || hp.sel.Having != nil:
    86  		plan, err = hp.planAggregations(ctx, plan)
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  		// if we already did sorting, we don't need to do it again
    91  		needsOrdering = needsOrdering && !hp.qp.CanPushDownSorting
    92  	case canShortcut:
    93  		err = planSingleShardRoutePlan(hp.sel, rb)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  	case derivedTable:
    98  		pusher := func(ae *sqlparser.AliasedExpr) (int, error) {
    99  			offset, _, err := pushProjection(ctx, ae, sp.input, true, true, false)
   100  			return offset, err
   101  		}
   102  		needsVtGate, projections, colNames, err := hp.qp.NeedsProjecting(ctx, pusher)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		if !needsVtGate {
   107  			break
   108  		}
   109  
   110  		// there were some expressions we could not push down entirely,
   111  		// so replace the simpleProjection with a real projection
   112  		plan = &projection{
   113  			source:      sp.input,
   114  			columns:     projections,
   115  			columnNames: colNames,
   116  		}
   117  	default:
   118  		err = pushProjections(ctx, plan, hp.qp.SelectExprs)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  	}
   123  
   124  	// If we didn't already take care of ORDER BY during aggregation planning, we need to handle it now
   125  	if needsOrdering {
   126  		plan, err = hp.planOrderBy(ctx, hp.qp.OrderExprs, plan)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  	}
   131  
   132  	plan, err = hp.planDistinct(ctx, plan)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	if !truncateColumns {
   138  		return plan, nil
   139  	}
   140  
   141  	plan, err = hp.truncateColumnsIfNeeded(ctx, plan)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	return plan, nil
   147  }
   148  
   149  func pushProjections(ctx *plancontext.PlanningContext, plan logicalPlan, selectExprs []operators.SelectExpr) error {
   150  	for _, e := range selectExprs {
   151  		aliasExpr, err := e.GetAliasedExpr()
   152  		if err != nil {
   153  			return err
   154  		}
   155  		if _, _, err := pushProjection(ctx, aliasExpr, plan, true, false, false); err != nil {
   156  			return err
   157  		}
   158  	}
   159  	return nil
   160  }
   161  
   162  func (hp *horizonPlanning) truncateColumnsIfNeeded(ctx *plancontext.PlanningContext, plan logicalPlan) (logicalPlan, error) {
   163  	if len(plan.OutputColumns()) == hp.qp.GetColumnCount() {
   164  		return plan, nil
   165  	}
   166  	switch p := plan.(type) {
   167  	case *routeGen4:
   168  		p.eroute.SetTruncateColumnCount(hp.qp.GetColumnCount())
   169  	case *joinGen4, *semiJoin, *hashJoin:
   170  		// since this is a join, we can safely add extra columns and not need to truncate them
   171  	case *orderedAggregate:
   172  		p.truncateColumnCount = hp.qp.GetColumnCount()
   173  	case *memorySort:
   174  		p.truncater.SetTruncateColumnCount(hp.qp.GetColumnCount())
   175  	case *pulloutSubquery:
   176  		newUnderlyingPlan, err := hp.truncateColumnsIfNeeded(ctx, p.underlying)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  		p.underlying = newUnderlyingPlan
   181  	default:
   182  		plan = &simpleProjection{
   183  			logicalPlanCommon: newBuilderCommon(plan),
   184  			eSimpleProj:       &engine.SimpleProjection{},
   185  		}
   186  
   187  		exprs := hp.qp.SelectExprs[0:hp.qp.GetColumnCount()]
   188  		err := pushProjections(ctx, plan, exprs)
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  	}
   193  	return plan, nil
   194  }
   195  
   196  func checkIfAlreadyExists(expr *sqlparser.AliasedExpr, node sqlparser.SelectStatement, semTable *semantics.SemTable) int {
   197  	// Here to find if the expr already exists in the SelectStatement, we have 3 cases
   198  	// input is a Select -> In this case we want to search in the select
   199  	// input is a Union -> In this case we want to search in the First Select of the Union
   200  	// input is a Parenthesised Select -> In this case we want to search in the select
   201  	// all these three cases are handled by the call to GetFirstSelect.
   202  	sel := sqlparser.GetFirstSelect(node)
   203  
   204  	exprCol, isExprCol := expr.Expr.(*sqlparser.ColName)
   205  
   206  	// first pass - search for aliased expressions
   207  	for i, selectExpr := range sel.SelectExprs {
   208  		if !isExprCol {
   209  			break
   210  		}
   211  
   212  		selectExpr, ok := selectExpr.(*sqlparser.AliasedExpr)
   213  		if ok && selectExpr.As.Equal(exprCol.Name) {
   214  			return i
   215  		}
   216  	}
   217  
   218  	// next pass - we are searching the actual expressions and not the aliases
   219  	for i, selectExpr := range sel.SelectExprs {
   220  		selectExpr, ok := selectExpr.(*sqlparser.AliasedExpr)
   221  		if !ok {
   222  			continue
   223  		}
   224  
   225  		if semTable.EqualsExpr(expr.Expr, selectExpr.Expr) {
   226  			return i
   227  		}
   228  	}
   229  	return -1
   230  }
   231  
   232  func (hp *horizonPlanning) planAggregations(ctx *plancontext.PlanningContext, plan logicalPlan) (logicalPlan, error) {
   233  	isPushable := !isJoin(plan)
   234  	grouping := hp.qp.GetGrouping()
   235  	vindexOverlapWithGrouping := hasUniqueVindex(ctx.SemTable, grouping)
   236  	if isPushable && vindexOverlapWithGrouping {
   237  		// If we have a plan that we can push the group by and aggregation through, we don't need to do aggregation
   238  		// at the vtgate level at all
   239  		err := hp.planAggregationWithoutOA(ctx, plan)
   240  		if err != nil {
   241  			return nil, err
   242  		}
   243  		resultPlan, err := hp.planOrderBy(ctx, hp.qp.OrderExprs, plan)
   244  		if err != nil {
   245  			return nil, err
   246  		}
   247  
   248  		newPlan, err := hp.planHaving(ctx, resultPlan)
   249  		if err != nil {
   250  			return nil, err
   251  		}
   252  
   253  		return newPlan, nil
   254  	}
   255  
   256  	return hp.planAggrUsingOA(ctx, plan, grouping)
   257  }
   258  
   259  func (hp *horizonPlanning) planAggrUsingOA(
   260  	ctx *plancontext.PlanningContext,
   261  	plan logicalPlan,
   262  	grouping []operators.GroupBy,
   263  ) (logicalPlan, error) {
   264  	oa := &orderedAggregate{
   265  		groupByKeys: make([]*engine.GroupByParams, 0, len(grouping)),
   266  	}
   267  
   268  	var order []operators.OrderBy
   269  	if hp.qp.CanPushDownSorting {
   270  		hp.qp.AlignGroupByAndOrderBy(ctx)
   271  		// the grouping order might have changed, so we reload the grouping expressions
   272  		grouping = hp.qp.GetGrouping()
   273  		order = hp.qp.OrderExprs
   274  	} else {
   275  		for _, expr := range grouping {
   276  			order = append(order, expr.AsOrderBy())
   277  		}
   278  	}
   279  
   280  	// here we are building up the grouping keys for the OA,
   281  	// but they are lacking the input offsets because we have yet to push the columns down
   282  	for _, expr := range grouping {
   283  		oa.groupByKeys = append(oa.groupByKeys, &engine.GroupByParams{
   284  			Expr:        expr.Inner,
   285  			FromGroupBy: true,
   286  			CollationID: ctx.SemTable.CollationForExpr(expr.Inner),
   287  		})
   288  	}
   289  
   290  	if hp.sel.Having != nil {
   291  		rewriter := hp.qp.AggrRewriter(ctx)
   292  		sqlparser.SafeRewrite(hp.sel.Having.Expr, rewriter.RewriteDown(), rewriter.RewriteUp())
   293  		if rewriter.Err != nil {
   294  			return nil, rewriter.Err
   295  		}
   296  	}
   297  
   298  	aggregationExprs, err := hp.qp.AggregationExpressions(ctx)
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  	// If we have a distinct aggregating expression,
   304  	// we handle it by pushing it down to the underlying input as a grouping column
   305  	distinctGroupBy, distinctOffsets, aggrs, err := hp.handleDistinctAggr(ctx, aggregationExprs)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  
   310  	if len(distinctGroupBy) > 0 {
   311  		grouping = append(grouping, distinctGroupBy...)
   312  		// all the distinct grouping aggregates use the same expression, so it should be OK to just add it once
   313  		order = append(order, distinctGroupBy[0].AsOrderBy())
   314  		oa.preProcess = true
   315  	}
   316  
   317  	newPlan, groupingOffsets, aggrParamOffsets, pushed, err := hp.pushAggregation(ctx, plan, grouping, aggrs, false)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  	if !pushed {
   322  		oa.preProcess = true
   323  		oa.aggrOnEngine = true
   324  	}
   325  
   326  	plan = newPlan
   327  
   328  	_, isRoute := plan.(*routeGen4)
   329  	needsProj := !isRoute
   330  	var aggPlan = plan
   331  	var proj *projection
   332  	if needsProj {
   333  		length := getLengthOfProjection(groupingOffsets, aggrs)
   334  		proj = &projection{
   335  			source:      plan,
   336  			columns:     make([]sqlparser.Expr, length),
   337  			columnNames: make([]string, length),
   338  		}
   339  		aggPlan = proj
   340  	}
   341  
   342  	aggrParams, err := generateAggregateParams(aggrs, aggrParamOffsets, proj, pushed)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  
   347  	if proj != nil {
   348  		groupingOffsets, err = passGroupingColumns(proj, groupingOffsets, grouping)
   349  		if err != nil {
   350  			return nil, err
   351  		}
   352  	}
   353  
   354  	// Next we add the aggregation expressions and grouping offsets to the OA
   355  	addColumnsToOA(ctx, oa, distinctGroupBy, aggrParams, distinctOffsets, groupingOffsets, aggregationExprs)
   356  
   357  	aggPlan, err = hp.planOrderBy(ctx, order, aggPlan)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  
   362  	oa.resultsBuilder = resultsBuilder{
   363  		logicalPlanCommon: newBuilderCommon(aggPlan),
   364  		weightStrings:     make(map[*resultColumn]int),
   365  	}
   366  
   367  	return hp.planHaving(ctx, oa)
   368  }
   369  
   370  func passGroupingColumns(proj *projection, groupings []offsets, grouping []operators.GroupBy) (projGrpOffsets []offsets, err error) {
   371  	for idx, grp := range groupings {
   372  		origGrp := grouping[idx]
   373  		var offs offsets
   374  		expr := origGrp.AsAliasedExpr()
   375  		offs.col, err = proj.addColumn(origGrp.InnerIndex, sqlparser.NewOffset(grp.col, expr.Expr), expr.ColumnName())
   376  		if err != nil {
   377  			return nil, err
   378  		}
   379  		if grp.wsCol != -1 {
   380  			offs.wsCol, err = proj.addColumn(nil, sqlparser.NewOffset(grp.wsCol, weightStringFor(expr.Expr)), "")
   381  			if err != nil {
   382  				return nil, err
   383  			}
   384  		}
   385  		projGrpOffsets = append(projGrpOffsets, offs)
   386  	}
   387  	return projGrpOffsets, nil
   388  }
   389  
   390  func generateAggregateParams(aggrs []operators.Aggr, aggrParamOffsets [][]offsets, proj *projection, pushed bool) ([]*engine.AggregateParams, error) {
   391  	aggrParams := make([]*engine.AggregateParams, len(aggrs))
   392  	for idx, paramOffset := range aggrParamOffsets {
   393  		aggr := aggrs[idx]
   394  		incomingOffset := paramOffset[0].col
   395  		var offset int
   396  		if proj != nil {
   397  			var aggrExpr sqlparser.Expr
   398  			for _, ofs := range paramOffset {
   399  				curr := &sqlparser.Offset{V: ofs.col}
   400  				if aggrExpr == nil {
   401  					aggrExpr = curr
   402  				} else {
   403  					aggrExpr = &sqlparser.BinaryExpr{
   404  						Operator: sqlparser.MultOp,
   405  						Left:     aggrExpr,
   406  						Right: &sqlparser.FuncExpr{
   407  							Name: sqlparser.NewIdentifierCI("coalesce"),
   408  							Exprs: sqlparser.SelectExprs{
   409  								&sqlparser.AliasedExpr{Expr: curr},
   410  								&sqlparser.AliasedExpr{Expr: sqlparser.NewIntLiteral("1")},
   411  							},
   412  						},
   413  					}
   414  				}
   415  			}
   416  
   417  			pos, err := proj.addColumn(aggr.Index, aggrExpr, aggr.Alias)
   418  			if err != nil {
   419  				return nil, err
   420  			}
   421  			offset = pos
   422  		} else {
   423  			offset = incomingOffset
   424  		}
   425  
   426  		opcode := engine.AggregateSum
   427  		switch aggr.OpCode {
   428  		case engine.AggregateMin, engine.AggregateMax, engine.AggregateRandom:
   429  			opcode = aggr.OpCode
   430  		case engine.AggregateCount, engine.AggregateCountStar, engine.AggregateCountDistinct, engine.AggregateSumDistinct:
   431  			if !pushed {
   432  				opcode = aggr.OpCode
   433  			}
   434  		}
   435  
   436  		aggrParams[idx] = &engine.AggregateParams{
   437  			Opcode:     opcode,
   438  			Col:        offset,
   439  			Alias:      aggr.Alias,
   440  			Expr:       aggr.Original.Expr,
   441  			Original:   aggr.Original,
   442  			OrigOpcode: aggr.OpCode,
   443  		}
   444  	}
   445  	return aggrParams, nil
   446  }
   447  
   448  func addColumnsToOA(
   449  	ctx *plancontext.PlanningContext,
   450  	oa *orderedAggregate,
   451  	// these are the group by expressions that where added because we have unique aggregations
   452  	distinctGroupBy []operators.GroupBy,
   453  	// these are the aggregate params we already have for non-distinct aggregations
   454  	aggrParams []*engine.AggregateParams,
   455  	// distinctOffsets mark out where we need to use the distinctGroupBy offsets
   456  	// to create *engine.AggregateParams for the distinct aggregations
   457  	distinctOffsets []int,
   458  	// these are the offsets for the group by params
   459  	groupings []offsets,
   460  	// aggregationExprs are all the original aggregation expressions the query requested
   461  	aggregationExprs []operators.Aggr,
   462  ) {
   463  	if len(distinctGroupBy) == 0 {
   464  		// no distinct aggregations
   465  		oa.aggregates = aggrParams
   466  	} else {
   467  		count := len(groupings) - len(distinctOffsets)
   468  		addDistinctAggr := func(offset int) {
   469  			// the last grouping we pushed is the one we added for the distinct aggregation
   470  			o := groupings[count]
   471  			count++
   472  			a := aggregationExprs[offset]
   473  			collID := ctx.SemTable.CollationForExpr(a.Func.GetArg())
   474  			oa.aggregates = append(oa.aggregates, &engine.AggregateParams{
   475  				Opcode:      a.OpCode,
   476  				Col:         o.col,
   477  				KeyCol:      o.col,
   478  				WAssigned:   o.wsCol >= 0,
   479  				WCol:        o.wsCol,
   480  				Alias:       a.Alias,
   481  				Original:    a.Original,
   482  				CollationID: collID,
   483  			})
   484  		}
   485  		lastOffset := distinctOffsets[len(distinctOffsets)-1]
   486  		distinctIdx := 0
   487  		for i := 0; i <= lastOffset || i <= len(aggrParams); i++ {
   488  			for distinctIdx < len(distinctOffsets) && i == distinctOffsets[distinctIdx] {
   489  				// we loop here since we could be dealing with multiple distinct aggregations after each other
   490  				addDistinctAggr(i)
   491  				distinctIdx++
   492  			}
   493  			if i < len(aggrParams) {
   494  				oa.aggregates = append(oa.aggregates, aggrParams[i])
   495  			}
   496  		}
   497  
   498  		// we have to remove the tail of the grouping offsets, so we only have the offsets for the GROUP BY in the query
   499  		groupings = groupings[:len(groupings)-len(distinctOffsets)]
   500  	}
   501  
   502  	for i, grouping := range groupings {
   503  		oa.groupByKeys[i].KeyCol = grouping.col
   504  		oa.groupByKeys[i].WeightStringCol = grouping.wsCol
   505  	}
   506  }
   507  
   508  // handleDistinctAggr takes in a slice of aggregations and returns GroupBy elements that replace
   509  // the distinct aggregations in the input, along with a slice of offsets and the non-distinct aggregations left,
   510  // so we can later reify the original aggregations
   511  func (hp *horizonPlanning) handleDistinctAggr(ctx *plancontext.PlanningContext, exprs []operators.Aggr) (
   512  	distincts []operators.GroupBy, offsets []int, aggrs []operators.Aggr, err error) {
   513  	var distinctExpr sqlparser.Expr
   514  	for i, expr := range exprs {
   515  		if !expr.Distinct {
   516  			aggrs = append(aggrs, expr)
   517  			continue
   518  		}
   519  
   520  		inner, innerWS, err := hp.qp.GetSimplifiedExpr(expr.Func.GetArg())
   521  		if err != nil {
   522  			return nil, nil, nil, err
   523  		}
   524  		if exprHasVindex(ctx.SemTable, innerWS, false) {
   525  			aggrs = append(aggrs, expr)
   526  			continue
   527  		}
   528  		if distinctExpr == nil {
   529  			distinctExpr = innerWS
   530  		} else {
   531  			if !ctx.SemTable.EqualsExpr(distinctExpr, innerWS) {
   532  				err = vterrors.VT12001(fmt.Sprintf("only one DISTINCT aggregation is allowed in a SELECT: %s", sqlparser.String(expr.Original)))
   533  				return nil, nil, nil, err
   534  			}
   535  		}
   536  		distincts = append(distincts, operators.GroupBy{
   537  			Inner:         inner,
   538  			WeightStrExpr: innerWS,
   539  			InnerIndex:    expr.Index,
   540  		})
   541  		offsets = append(offsets, i)
   542  	}
   543  	return
   544  }
   545  
   546  func (hp *horizonPlanning) planAggregationWithoutOA(ctx *plancontext.PlanningContext, plan logicalPlan) error {
   547  	for _, expr := range hp.qp.SelectExprs {
   548  		aliasedExpr, err := expr.GetAliasedExpr()
   549  		if err != nil {
   550  			return err
   551  		}
   552  		_, _, err = pushProjection(ctx, aliasedExpr, plan, true, false, false)
   553  		if err != nil {
   554  			return err
   555  		}
   556  	}
   557  	for _, expr := range hp.qp.GetGrouping() {
   558  		// since all the grouping will be done at the mysql level,
   559  		// we know that we won't need any weight_string() calls
   560  		err := planGroupByGen4(ctx, expr, plan /*weighString*/, false)
   561  		if err != nil {
   562  			return err
   563  		}
   564  	}
   565  	return nil
   566  }
   567  
   568  type offsets struct {
   569  	col, wsCol int
   570  }
   571  
   572  func newOffset(col int) offsets {
   573  	return offsets{col: col, wsCol: -1}
   574  }
   575  
   576  func (hp *horizonPlanning) createGroupingsForColumns(columns []*sqlparser.ColName) ([]operators.GroupBy, error) {
   577  	var lhsGrouping []operators.GroupBy
   578  	for _, lhsColumn := range columns {
   579  		expr, wsExpr, err := hp.qp.GetSimplifiedExpr(lhsColumn)
   580  		if err != nil {
   581  			return nil, err
   582  		}
   583  
   584  		lhsGrouping = append(lhsGrouping, operators.GroupBy{
   585  			Inner:         expr,
   586  			WeightStrExpr: wsExpr,
   587  		})
   588  	}
   589  	return lhsGrouping, nil
   590  }
   591  
   592  func hasUniqueVindex(semTable *semantics.SemTable, groupByExprs []operators.GroupBy) bool {
   593  	for _, groupByExpr := range groupByExprs {
   594  		if exprHasUniqueVindex(semTable, groupByExpr.WeightStrExpr) {
   595  			return true
   596  		}
   597  	}
   598  	return false
   599  }
   600  
   601  func (hp *horizonPlanning) planOrderBy(ctx *plancontext.PlanningContext, orderExprs []operators.OrderBy, plan logicalPlan) (logicalPlan, error) {
   602  	switch plan := plan.(type) {
   603  	case *routeGen4:
   604  		newPlan, err := planOrderByForRoute(ctx, orderExprs, plan, hp.qp.HasStar)
   605  		if err != nil {
   606  			return nil, err
   607  		}
   608  		return newPlan, nil
   609  	case *joinGen4:
   610  		newPlan, err := hp.planOrderByForJoin(ctx, orderExprs, plan)
   611  		if err != nil {
   612  			return nil, err
   613  		}
   614  
   615  		return newPlan, nil
   616  	case *hashJoin:
   617  		newPlan, err := hp.planOrderByForHashJoin(ctx, orderExprs, plan)
   618  		if err != nil {
   619  			return nil, err
   620  		}
   621  
   622  		return newPlan, nil
   623  	case *orderedAggregate:
   624  		// remove ORDER BY NULL from the list of order by expressions since we will be doing the ordering on vtgate level so NULL is not useful
   625  		var orderExprsWithoutNils []operators.OrderBy
   626  		for _, expr := range orderExprs {
   627  			if sqlparser.IsNull(expr.Inner.Expr) {
   628  				continue
   629  			}
   630  			orderExprsWithoutNils = append(orderExprsWithoutNils, expr)
   631  		}
   632  		orderExprs = orderExprsWithoutNils
   633  
   634  		for _, order := range orderExprs {
   635  			if sqlparser.ContainsAggregation(order.WeightStrExpr) {
   636  				ms, err := createMemorySortPlanOnAggregation(ctx, plan, orderExprs)
   637  				if err != nil {
   638  					return nil, err
   639  				}
   640  				return ms, nil
   641  			}
   642  		}
   643  		newInput, err := hp.planOrderBy(ctx, orderExprs, plan.input)
   644  		if err != nil {
   645  			return nil, err
   646  		}
   647  		plan.input = newInput
   648  		return plan, nil
   649  	case *memorySort:
   650  		return plan, nil
   651  	case *simpleProjection:
   652  		return hp.createMemorySortPlan(ctx, plan, orderExprs, true)
   653  	case *vindexFunc:
   654  		// This is evaluated at VTGate only, so weight_string function cannot be used.
   655  		return hp.createMemorySortPlan(ctx, plan, orderExprs /* useWeightStr */, false)
   656  	case *limit, *semiJoin, *filter, *pulloutSubquery, *projection:
   657  		inputs := plan.Inputs()
   658  		if len(inputs) == 0 {
   659  			break
   660  		}
   661  		newFirstInput, err := hp.planOrderBy(ctx, orderExprs, inputs[0])
   662  		if err != nil {
   663  			return nil, err
   664  		}
   665  		inputs[0] = newFirstInput
   666  		err = plan.Rewrite(inputs...)
   667  		if err != nil {
   668  			return nil, err
   669  		}
   670  		return plan, nil
   671  	}
   672  	return nil, vterrors.VT13001(fmt.Sprintf("ORDER BY in complex query %T", plan))
   673  }
   674  
   675  func isSpecialOrderBy(o operators.OrderBy) bool {
   676  	if sqlparser.IsNull(o.Inner.Expr) {
   677  		return true
   678  	}
   679  	f, isFunction := o.Inner.Expr.(*sqlparser.FuncExpr)
   680  	return isFunction && f.Name.Lowered() == "rand"
   681  }
   682  
   683  func planOrderByForRoute(ctx *plancontext.PlanningContext, orderExprs []operators.OrderBy, plan *routeGen4, hasStar bool) (logicalPlan, error) {
   684  	for _, order := range orderExprs {
   685  		err := checkOrderExprCanBePlannedInScatter(ctx, plan, order, hasStar)
   686  		if err != nil {
   687  			return nil, err
   688  		}
   689  		plan.Select.AddOrder(order.Inner)
   690  		if isSpecialOrderBy(order) {
   691  			continue
   692  		}
   693  		var wsExpr sqlparser.Expr
   694  		if ctx.SemTable.NeedsWeightString(order.Inner.Expr) {
   695  			wsExpr = order.WeightStrExpr
   696  		}
   697  
   698  		offset, weightStringOffset, err := wrapAndPushExpr(ctx, order.Inner.Expr, wsExpr, plan)
   699  		if err != nil {
   700  			return nil, err
   701  		}
   702  		plan.eroute.OrderBy = append(plan.eroute.OrderBy, engine.OrderByParams{
   703  			Col:             offset,
   704  			WeightStringCol: weightStringOffset,
   705  			Desc:            order.Inner.Direction == sqlparser.DescOrder,
   706  			CollationID:     ctx.SemTable.CollationForExpr(order.Inner.Expr),
   707  		})
   708  	}
   709  	return plan, nil
   710  }
   711  
   712  // checkOrderExprCanBePlannedInScatter verifies that the given order by expression can be planned.
   713  // It checks if the expression exists in the plan's select list when the query is a scatter.
   714  func checkOrderExprCanBePlannedInScatter(ctx *plancontext.PlanningContext, plan *routeGen4, order operators.OrderBy, hasStar bool) error {
   715  	if !hasStar {
   716  		return nil
   717  	}
   718  	sel := sqlparser.GetFirstSelect(plan.Select)
   719  	found := false
   720  	for _, expr := range sel.SelectExprs {
   721  		aliasedExpr, isAliasedExpr := expr.(*sqlparser.AliasedExpr)
   722  		if isAliasedExpr && ctx.SemTable.EqualsExpr(aliasedExpr.Expr, order.Inner.Expr) {
   723  			found = true
   724  			break
   725  		}
   726  	}
   727  	if !found {
   728  		return vterrors.VT12001(fmt.Sprintf("in scatter query: ORDER BY must reference a column in the SELECT list: %s", sqlparser.String(order.Inner)))
   729  	}
   730  	return nil
   731  }
   732  
   733  // wrapAndPushExpr pushes the expression and weighted_string function to the plan using semantics.SemTable
   734  // It returns (expr offset, weight_string offset, error)
   735  func wrapAndPushExpr(ctx *plancontext.PlanningContext, expr sqlparser.Expr, weightStrExpr sqlparser.Expr, plan logicalPlan) (int, int, error) {
   736  	offset, _, err := pushProjection(ctx, &sqlparser.AliasedExpr{Expr: expr}, plan, true, true, false)
   737  	if err != nil {
   738  		return 0, 0, err
   739  	}
   740  	if weightStrExpr == nil {
   741  		return offset, -1, nil
   742  	}
   743  	if !sqlparser.IsColName(expr) {
   744  		switch unary := expr.(type) {
   745  		case *sqlparser.CastExpr:
   746  			expr = unary.Expr
   747  		case *sqlparser.ConvertExpr:
   748  			expr = unary.Expr
   749  		}
   750  		if !sqlparser.IsColName(expr) {
   751  			return 0, 0, vterrors.VT13001(fmt.Sprintf("in scatter query: complex ORDER BY expression: %s", sqlparser.String(expr)))
   752  		}
   753  	}
   754  	qt := ctx.SemTable.TypeFor(expr)
   755  	wsNeeded := true
   756  	if qt != nil && sqltypes.IsNumber(*qt) {
   757  		wsNeeded = false
   758  	}
   759  
   760  	weightStringOffset := -1
   761  	if wsNeeded {
   762  		aliasedExpr := &sqlparser.AliasedExpr{Expr: weightStringFor(weightStrExpr)}
   763  		weightStringOffset, _, err = pushProjection(ctx, aliasedExpr, plan, true, true, false)
   764  		if err != nil {
   765  			return 0, 0, err
   766  		}
   767  	}
   768  	return offset, weightStringOffset, nil
   769  }
   770  
   771  func weightStringFor(expr sqlparser.Expr) sqlparser.Expr {
   772  	return &sqlparser.WeightStringFuncExpr{Expr: expr}
   773  }
   774  
   775  func (hp *horizonPlanning) planOrderByForHashJoin(ctx *plancontext.PlanningContext, orderExprs []operators.OrderBy, plan *hashJoin) (logicalPlan, error) {
   776  	if len(orderExprs) == 1 && isSpecialOrderBy(orderExprs[0]) {
   777  		rhs, err := hp.planOrderBy(ctx, orderExprs, plan.Right)
   778  		if err != nil {
   779  			return nil, err
   780  		}
   781  		plan.Right = rhs
   782  		return plan, nil
   783  	}
   784  	if orderExprsDependsOnTableSet(orderExprs, ctx.SemTable, plan.Right.ContainsTables()) {
   785  		newRight, err := hp.planOrderBy(ctx, orderExprs, plan.Right)
   786  		if err != nil {
   787  			return nil, err
   788  		}
   789  		plan.Right = newRight
   790  		return plan, nil
   791  	}
   792  	sortPlan, err := hp.createMemorySortPlan(ctx, plan, orderExprs, true)
   793  	if err != nil {
   794  		return nil, err
   795  	}
   796  	return sortPlan, nil
   797  }
   798  
   799  func (hp *horizonPlanning) planOrderByForJoin(ctx *plancontext.PlanningContext, orderExprs []operators.OrderBy, plan *joinGen4) (logicalPlan, error) {
   800  	if len(orderExprs) == 1 && isSpecialOrderBy(orderExprs[0]) {
   801  		lhs, err := hp.planOrderBy(ctx, orderExprs, plan.Left)
   802  		if err != nil {
   803  			return nil, err
   804  		}
   805  		rhs, err := hp.planOrderBy(ctx, orderExprs, plan.Right)
   806  		if err != nil {
   807  			return nil, err
   808  		}
   809  		plan.Left = lhs
   810  		plan.Right = rhs
   811  		return plan, nil
   812  	}
   813  	// We can only push down sorting on the LHS of the join.
   814  	// If the order is on the RHS, we need to do the sorting on the vtgate
   815  	if orderExprsDependsOnTableSet(orderExprs, ctx.SemTable, plan.Left.ContainsTables()) {
   816  		newLeft, err := hp.planOrderBy(ctx, orderExprs, plan.Left)
   817  		if err != nil {
   818  			return nil, err
   819  		}
   820  		plan.Left = newLeft
   821  		return plan, nil
   822  	}
   823  	sortPlan, err := hp.createMemorySortPlan(ctx, plan, orderExprs, true)
   824  	if err != nil {
   825  		return nil, err
   826  	}
   827  	return sortPlan, nil
   828  }
   829  
   830  func createMemorySortPlanOnAggregation(ctx *plancontext.PlanningContext, plan *orderedAggregate, orderExprs []operators.OrderBy) (logicalPlan, error) {
   831  	primitive := &engine.MemorySort{}
   832  	ms := &memorySort{
   833  		resultsBuilder: resultsBuilder{
   834  			logicalPlanCommon: newBuilderCommon(plan),
   835  			weightStrings:     make(map[*resultColumn]int),
   836  			truncater:         primitive,
   837  		},
   838  		eMemorySort: primitive,
   839  	}
   840  
   841  	for _, order := range orderExprs {
   842  		offset, woffset, found := findExprInOrderedAggr(ctx, plan, order)
   843  		if !found {
   844  			return nil, vterrors.VT13001(fmt.Sprintf("expected to find ORDER BY expression (%s) in orderedAggregate", sqlparser.String(order.Inner)))
   845  		}
   846  
   847  		collationID := ctx.SemTable.CollationForExpr(order.WeightStrExpr)
   848  		ms.eMemorySort.OrderBy = append(ms.eMemorySort.OrderBy, engine.OrderByParams{
   849  			Col:               offset,
   850  			WeightStringCol:   woffset,
   851  			Desc:              order.Inner.Direction == sqlparser.DescOrder,
   852  			StarColFixedIndex: offset,
   853  			CollationID:       collationID,
   854  		})
   855  	}
   856  	return ms, nil
   857  }
   858  
   859  func findExprInOrderedAggr(ctx *plancontext.PlanningContext, plan *orderedAggregate, order operators.OrderBy) (keyCol int, weightStringCol int, found bool) {
   860  	for _, key := range plan.groupByKeys {
   861  		if ctx.SemTable.EqualsExpr(order.WeightStrExpr, key.Expr) ||
   862  			ctx.SemTable.EqualsExpr(order.Inner.Expr, key.Expr) {
   863  			return key.KeyCol, key.WeightStringCol, true
   864  		}
   865  	}
   866  	for _, aggregate := range plan.aggregates {
   867  		if ctx.SemTable.EqualsExpr(order.WeightStrExpr, aggregate.Original.Expr) ||
   868  			ctx.SemTable.EqualsExpr(order.Inner.Expr, aggregate.Original.Expr) {
   869  			return aggregate.Col, -1, true
   870  		}
   871  	}
   872  	return 0, 0, false
   873  }
   874  
   875  func (hp *horizonPlanning) createMemorySortPlan(ctx *plancontext.PlanningContext, plan logicalPlan, orderExprs []operators.OrderBy, useWeightStr bool) (logicalPlan, error) {
   876  	primitive := &engine.MemorySort{}
   877  	ms := &memorySort{
   878  		resultsBuilder: resultsBuilder{
   879  			logicalPlanCommon: newBuilderCommon(plan),
   880  			weightStrings:     make(map[*resultColumn]int),
   881  			truncater:         primitive,
   882  		},
   883  		eMemorySort: primitive,
   884  	}
   885  
   886  	for _, order := range orderExprs {
   887  		wsExpr := order.WeightStrExpr
   888  		if !useWeightStr {
   889  			wsExpr = nil
   890  		}
   891  		offset, weightStringOffset, err := wrapAndPushExpr(ctx, order.Inner.Expr, wsExpr, plan)
   892  		if err != nil {
   893  			return nil, err
   894  		}
   895  		ms.eMemorySort.OrderBy = append(ms.eMemorySort.OrderBy, engine.OrderByParams{
   896  			Col:               offset,
   897  			WeightStringCol:   weightStringOffset,
   898  			Desc:              order.Inner.Direction == sqlparser.DescOrder,
   899  			StarColFixedIndex: offset,
   900  			CollationID:       ctx.SemTable.CollationForExpr(order.Inner.Expr),
   901  		})
   902  	}
   903  	return ms, nil
   904  }
   905  
   906  func orderExprsDependsOnTableSet(orderExprs []operators.OrderBy, semTable *semantics.SemTable, ts semantics.TableSet) bool {
   907  	for _, expr := range orderExprs {
   908  		exprDependencies := semTable.RecursiveDeps(expr.Inner.Expr)
   909  		if !exprDependencies.IsSolvedBy(ts) {
   910  			return false
   911  		}
   912  	}
   913  	return true
   914  }
   915  
   916  func (hp *horizonPlanning) planDistinct(ctx *plancontext.PlanningContext, plan logicalPlan) (logicalPlan, error) {
   917  	if !hp.qp.NeedsDistinct() {
   918  		return plan, nil
   919  	}
   920  	switch p := plan.(type) {
   921  	case *routeGen4:
   922  		// we always make the underlying query distinct,
   923  		// and then we might also add a distinct operator on top if it is needed
   924  		p.Select.MakeDistinct()
   925  		if p.isSingleShard() || selectHasUniqueVindex(ctx.SemTable, hp.qp.SelectExprs) {
   926  			return plan, nil
   927  		}
   928  
   929  		return hp.addDistinct(ctx, plan)
   930  	case *joinGen4, *pulloutSubquery:
   931  		return hp.addDistinct(ctx, plan)
   932  	case *orderedAggregate:
   933  		return hp.planDistinctOA(ctx.SemTable, p)
   934  	default:
   935  		return nil, vterrors.VT13001(fmt.Sprintf("unknown plan type for DISTINCT %T", plan))
   936  	}
   937  }
   938  
   939  func (hp *horizonPlanning) planDistinctOA(semTable *semantics.SemTable, currPlan *orderedAggregate) (logicalPlan, error) {
   940  	oa := &orderedAggregate{
   941  		resultsBuilder: resultsBuilder{
   942  			logicalPlanCommon: newBuilderCommon(currPlan),
   943  			weightStrings:     make(map[*resultColumn]int),
   944  		},
   945  	}
   946  	for _, sExpr := range hp.qp.SelectExprs {
   947  		expr, err := sExpr.GetExpr()
   948  		if err != nil {
   949  			return nil, err
   950  		}
   951  		found := false
   952  		for _, grpParam := range currPlan.groupByKeys {
   953  			if semTable.EqualsExpr(expr, grpParam.Expr) {
   954  				found = true
   955  				oa.groupByKeys = append(oa.groupByKeys, grpParam)
   956  				break
   957  			}
   958  		}
   959  		if found {
   960  			continue
   961  		}
   962  		for _, aggrParam := range currPlan.aggregates {
   963  			if semTable.EqualsExpr(expr, aggrParam.Expr) {
   964  				found = true
   965  				oa.groupByKeys = append(oa.groupByKeys, &engine.GroupByParams{KeyCol: aggrParam.Col, WeightStringCol: -1, CollationID: semTable.CollationForExpr(expr)})
   966  				break
   967  			}
   968  		}
   969  		if !found {
   970  			return nil, vterrors.VT13001(fmt.Sprintf("unable to plan DISTINCT query as the column is not projected: %s", sqlparser.String(sExpr.Col)))
   971  		}
   972  	}
   973  	return oa, nil
   974  }
   975  
   976  func (hp *horizonPlanning) addDistinct(ctx *plancontext.PlanningContext, plan logicalPlan) (logicalPlan, error) {
   977  	var orderExprs []operators.OrderBy
   978  	var groupByKeys []*engine.GroupByParams
   979  	for index, sExpr := range hp.qp.SelectExprs {
   980  		aliasExpr, err := sExpr.GetAliasedExpr()
   981  		if err != nil {
   982  			return nil, err
   983  		}
   984  		if isAmbiguousOrderBy(index, aliasExpr.As, hp.qp.SelectExprs) {
   985  			return nil, vterrors.VT13001(fmt.Sprintf("generating ORDER BY clause: ambiguous symbol reference: %s", sqlparser.String(aliasExpr.As)))
   986  		}
   987  		var inner sqlparser.Expr
   988  		if aliasExpr.As.IsEmpty() {
   989  			inner = aliasExpr.Expr
   990  		} else {
   991  			// If we have an alias, we need to use the alias and not the original expression
   992  			// to make sure dependencies work correctly,
   993  			// we simply copy the dependencies of the original expression here
   994  			inner = sqlparser.NewColName(aliasExpr.As.String())
   995  			ctx.SemTable.CopyDependencies(aliasExpr.Expr, inner)
   996  		}
   997  		grpParam := &engine.GroupByParams{KeyCol: index, WeightStringCol: -1, CollationID: ctx.SemTable.CollationForExpr(inner), Expr: inner}
   998  		_, wOffset, err := wrapAndPushExpr(ctx, aliasExpr.Expr, aliasExpr.Expr, plan)
   999  		if err != nil {
  1000  			return nil, err
  1001  		}
  1002  		grpParam.WeightStringCol = wOffset
  1003  		groupByKeys = append(groupByKeys, grpParam)
  1004  
  1005  		orderExprs = append(orderExprs, operators.OrderBy{
  1006  			Inner:         &sqlparser.Order{Expr: inner},
  1007  			WeightStrExpr: aliasExpr.Expr},
  1008  		)
  1009  	}
  1010  	innerPlan, err := hp.planOrderBy(ctx, orderExprs, plan)
  1011  	if err != nil {
  1012  		return nil, err
  1013  	}
  1014  	oa := &orderedAggregate{
  1015  		resultsBuilder: resultsBuilder{
  1016  			logicalPlanCommon: newBuilderCommon(innerPlan),
  1017  			weightStrings:     make(map[*resultColumn]int),
  1018  		},
  1019  		groupByKeys: groupByKeys,
  1020  	}
  1021  	return oa, nil
  1022  }
  1023  
  1024  func isAmbiguousOrderBy(index int, col sqlparser.IdentifierCI, exprs []operators.SelectExpr) bool {
  1025  	if col.String() == "" {
  1026  		return false
  1027  	}
  1028  	for i, expr := range exprs {
  1029  		if i == index {
  1030  			continue
  1031  		}
  1032  		aliasExpr, isAlias := expr.Col.(*sqlparser.AliasedExpr)
  1033  		if !isAlias {
  1034  			// TODO: handle star expression error
  1035  			return true
  1036  		}
  1037  		alias := aliasExpr.As
  1038  		if alias.IsEmpty() {
  1039  			if col, ok := aliasExpr.Expr.(*sqlparser.ColName); ok {
  1040  				alias = col.Name
  1041  			}
  1042  		}
  1043  		if col.Equal(alias) {
  1044  			return true
  1045  		}
  1046  	}
  1047  	return false
  1048  }
  1049  
  1050  func selectHasUniqueVindex(semTable *semantics.SemTable, sel []operators.SelectExpr) bool {
  1051  	for _, expr := range sel {
  1052  		exp, err := expr.GetExpr()
  1053  		if err != nil {
  1054  			// TODO: handle star expression error
  1055  			return false
  1056  		}
  1057  		if exprHasUniqueVindex(semTable, exp) {
  1058  			return true
  1059  		}
  1060  	}
  1061  	return false
  1062  }
  1063  
  1064  func (hp *horizonPlanning) planHaving(ctx *plancontext.PlanningContext, plan logicalPlan) (logicalPlan, error) {
  1065  	if hp.sel.Having == nil {
  1066  		return plan, nil
  1067  	}
  1068  	return pushHaving(ctx, hp.sel.Having.Expr, plan)
  1069  }
  1070  
  1071  func pushHaving(ctx *plancontext.PlanningContext, expr sqlparser.Expr, plan logicalPlan) (logicalPlan, error) {
  1072  	switch node := plan.(type) {
  1073  	case *routeGen4:
  1074  		sel := sqlparser.GetFirstSelect(node.Select)
  1075  		sel.AddHaving(expr)
  1076  		return plan, nil
  1077  	case *pulloutSubquery:
  1078  		return pushHaving(ctx, expr, node.underlying)
  1079  	case *simpleProjection:
  1080  		return nil, vterrors.VT13001("filtering on results of cross-shard derived table")
  1081  	case *orderedAggregate:
  1082  		return newFilter(ctx, plan, expr)
  1083  	}
  1084  	return nil, vterrors.VT13001(fmt.Sprintf("unreachable %T.filtering", plan))
  1085  }
  1086  
  1087  func isJoin(plan logicalPlan) bool {
  1088  	switch plan.(type) {
  1089  	case *joinGen4, *hashJoin:
  1090  		return true
  1091  	default:
  1092  		return false
  1093  	}
  1094  }
  1095  
  1096  func exprHasUniqueVindex(semTable *semantics.SemTable, expr sqlparser.Expr) bool {
  1097  	return exprHasVindex(semTable, expr, true)
  1098  }
  1099  
  1100  func exprHasVindex(semTable *semantics.SemTable, expr sqlparser.Expr, hasToBeUnique bool) bool {
  1101  	col, isCol := expr.(*sqlparser.ColName)
  1102  	if !isCol {
  1103  		return false
  1104  	}
  1105  	ts := semTable.RecursiveDeps(expr)
  1106  	tableInfo, err := semTable.TableInfoFor(ts)
  1107  	if err != nil {
  1108  		return false
  1109  	}
  1110  	vschemaTable := tableInfo.GetVindexTable()
  1111  	for _, vindex := range vschemaTable.ColumnVindexes {
  1112  		if len(vindex.Columns) > 1 || hasToBeUnique && !vindex.IsUnique() {
  1113  			return false
  1114  		}
  1115  		if col.Name.Equal(vindex.Columns[0]) {
  1116  			return true
  1117  		}
  1118  	}
  1119  	return false
  1120  }
  1121  
  1122  func planSingleShardRoutePlan(sel sqlparser.SelectStatement, rb *routeGen4) error {
  1123  	err := stripDownQuery(sel, rb.Select)
  1124  	if err != nil {
  1125  		return err
  1126  	}
  1127  	return sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  1128  		if aliasedExpr, ok := node.(sqlparser.SelectExpr); ok {
  1129  			removeKeyspaceFromSelectExpr(aliasedExpr)
  1130  		}
  1131  		return true, nil
  1132  	}, rb.Select)
  1133  
  1134  }
  1135  
  1136  func removeKeyspaceFromSelectExpr(expr sqlparser.SelectExpr) {
  1137  	switch expr := expr.(type) {
  1138  	case *sqlparser.AliasedExpr:
  1139  		sqlparser.RemoveKeyspaceFromColName(expr.Expr)
  1140  	case *sqlparser.StarExpr:
  1141  		expr.TableName.Qualifier = sqlparser.NewIdentifierCS("")
  1142  	}
  1143  }
  1144  
  1145  func stripDownQuery(from, to sqlparser.SelectStatement) error {
  1146  	var err error
  1147  
  1148  	switch node := from.(type) {
  1149  	case *sqlparser.Select:
  1150  		toNode, ok := to.(*sqlparser.Select)
  1151  		if !ok {
  1152  			return vterrors.VT13001("AST did not match")
  1153  		}
  1154  		toNode.Distinct = node.Distinct
  1155  		toNode.GroupBy = node.GroupBy
  1156  		toNode.Having = node.Having
  1157  		toNode.OrderBy = node.OrderBy
  1158  		toNode.Comments = node.Comments
  1159  		toNode.SelectExprs = node.SelectExprs
  1160  		for _, expr := range toNode.SelectExprs {
  1161  			removeKeyspaceFromSelectExpr(expr)
  1162  		}
  1163  	case *sqlparser.Union:
  1164  		toNode, ok := to.(*sqlparser.Union)
  1165  		if !ok {
  1166  			return vterrors.VT13001("AST did not match")
  1167  		}
  1168  		err = stripDownQuery(node.Left, toNode.Left)
  1169  		if err != nil {
  1170  			return err
  1171  		}
  1172  		err = stripDownQuery(node.Right, toNode.Right)
  1173  		if err != nil {
  1174  			return err
  1175  		}
  1176  		toNode.OrderBy = node.OrderBy
  1177  	default:
  1178  		return vterrors.VT13001(fmt.Sprintf("this should not happen - we have covered all implementations of SelectStatement %T", from))
  1179  	}
  1180  	return nil
  1181  }
  1182  
  1183  func planGroupByGen4(ctx *plancontext.PlanningContext, groupExpr operators.GroupBy, plan logicalPlan, wsAdded bool) error {
  1184  	switch node := plan.(type) {
  1185  	case *routeGen4:
  1186  		sel := node.Select.(*sqlparser.Select)
  1187  		sel.AddGroupBy(groupExpr.Inner)
  1188  		// If a weight_string function is added to the select list,
  1189  		// then we need to add that to the group by clause otherwise the query will fail on mysql with full_group_by error
  1190  		// as the weight_string function might not be functionally dependent on the group by.
  1191  		if wsAdded {
  1192  			sel.AddGroupBy(weightStringFor(groupExpr.WeightStrExpr))
  1193  		}
  1194  		return nil
  1195  	case *pulloutSubquery:
  1196  		return planGroupByGen4(ctx, groupExpr, node.underlying, wsAdded)
  1197  	case *semiJoin:
  1198  		return vterrors.VT13001("GROUP BY in a query having a correlated subquery")
  1199  	default:
  1200  		return vterrors.VT13001(fmt.Sprintf("GROUP BY on: %T", plan))
  1201  	}
  1202  }
  1203  
  1204  func getLengthOfProjection(groupingOffsets []offsets, aggregations []operators.Aggr) int {
  1205  	length := 0
  1206  	for _, groupBy := range groupingOffsets {
  1207  		if groupBy.wsCol != -1 {
  1208  			length++
  1209  		}
  1210  		length++
  1211  	}
  1212  	length += len(aggregations)
  1213  	return length
  1214  }