vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/select.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/vt/log"
    23  
    24  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    25  
    26  	"vitess.io/vitess/go/vt/key"
    27  
    28  	"vitess.io/vitess/go/vt/vterrors"
    29  
    30  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    31  
    32  	"vitess.io/vitess/go/vt/sqlparser"
    33  	"vitess.io/vitess/go/vt/vtgate/engine"
    34  )
    35  
    36  func buildSelectPlan(query string) stmtPlanner {
    37  	return func(stmt sqlparser.Statement, reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema) (*planResult, error) {
    38  		sel := stmt.(*sqlparser.Select)
    39  		if sel.With != nil {
    40  			return nil, vterrors.VT12001("WITH expression in SELECT statement")
    41  		}
    42  
    43  		p, err := handleDualSelects(sel, vschema)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		if p != nil {
    48  			return newPlanResult(p), nil
    49  		}
    50  
    51  		getPlan := func(sel *sqlparser.Select) (logicalPlan, error) {
    52  			pb := newPrimitiveBuilder(vschema, newJointab(reservedVars))
    53  			if err := pb.processSelect(sel, reservedVars, nil, query); err != nil {
    54  				return nil, err
    55  			}
    56  			if err := pb.plan.Wireup(pb.plan, pb.jt); err != nil {
    57  				return nil, err
    58  			}
    59  			return pb.plan, nil
    60  		}
    61  
    62  		plan, err := getPlan(sel)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  
    67  		if shouldRetryAfterPredicateRewriting(plan) {
    68  			// by transforming the predicates to CNF, the planner will sometimes find better plans
    69  			primitive := rewriteToCNFAndReplan(stmt, getPlan)
    70  			if primitive != nil {
    71  				return newPlanResult(primitive), nil
    72  			}
    73  		}
    74  		primitive := plan.Primitive()
    75  		if rb, ok := primitive.(*engine.Route); ok {
    76  			// this is done because engine.Route doesn't handle the empty result well
    77  			// if it doesn't find a shard to send the query to.
    78  			// All other engine primitives can handle this, so we only need it when
    79  			// Route is the last (and only) instruction before the user sees a result
    80  			if isOnlyDual(sel) || (len(sel.GroupBy) == 0 && sel.SelectExprs.AllAggregation()) {
    81  				rb.NoRoutesSpecialHandling = true
    82  			}
    83  		}
    84  
    85  		return newPlanResult(primitive), nil
    86  	}
    87  }
    88  
    89  func rewriteToCNFAndReplan(stmt sqlparser.Statement, getPlan func(sel *sqlparser.Select) (logicalPlan, error)) engine.Primitive {
    90  	rewritten := sqlparser.RewritePredicate(stmt)
    91  	sel2, isSelect := rewritten.(*sqlparser.Select)
    92  	if isSelect {
    93  		log.Infof("retrying plan after cnf: %s", sqlparser.String(sel2))
    94  		plan2, err := getPlan(sel2)
    95  		if err == nil && !shouldRetryAfterPredicateRewriting(plan2) {
    96  			// we only use this new plan if it's better than the old one we got
    97  			return plan2.Primitive()
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  func shouldRetryAfterPredicateRewriting(plan logicalPlan) bool {
   104  	// if we have a I_S query, but have not found table_schema or table_name, let's try CNF
   105  	var opcode engine.Opcode
   106  	var sysTableTableName map[string]evalengine.Expr
   107  	var sysTableTableSchema []evalengine.Expr
   108  
   109  	switch routePlan := plan.(type) {
   110  	case *routeGen4:
   111  		opcode = routePlan.eroute.Opcode
   112  		sysTableTableName = routePlan.eroute.SysTableTableName
   113  		sysTableTableSchema = routePlan.eroute.SysTableTableSchema
   114  	case *route:
   115  		opcode = routePlan.eroute.Opcode
   116  		sysTableTableName = routePlan.eroute.SysTableTableName
   117  		sysTableTableSchema = routePlan.eroute.SysTableTableSchema
   118  	default:
   119  		return false
   120  	}
   121  
   122  	return opcode == engine.DBA &&
   123  		len(sysTableTableName) == 0 &&
   124  		len(sysTableTableSchema) == 0
   125  }
   126  
   127  // processSelect builds a primitive tree for the given query or subquery.
   128  // The tree built by this function has the following general structure:
   129  //
   130  // The leaf nodes can be a route, vindexFunc or subquery. In the symtab,
   131  // the tables map has columns that point to these leaf nodes. A subquery
   132  // itself contains a logicalPlan tree, but it's opaque and is made to look
   133  // like a table for the analysis of the current tree.
   134  //
   135  // The leaf nodes are usually tied together by join nodes. While the join
   136  // nodes are built, they have ON clauses. Those are analyzed and pushed
   137  // down into the leaf nodes as the tree is formed. Join nodes are formed
   138  // during analysis of the FROM clause.
   139  //
   140  // During the WHERE clause analysis, the target leaf node is identified
   141  // for each part, and the PushFilter function is used to push the condition
   142  // down. The same strategy is used for the other clauses.
   143  //
   144  // So, a typical plan would either be a simple leaf node, or may consist
   145  // of leaf nodes tied together by join nodes.
   146  //
   147  // If a query has aggregates that cannot be pushed down, an aggregator
   148  // primitive is built. The current orderedAggregate primitive can only
   149  // be built on top of a route. The orderedAggregate expects the rows
   150  // to be ordered as they are returned. This work is performed by the
   151  // underlying route. This means that a compatible ORDER BY clause
   152  // can also be handled by this combination of primitives. In this case,
   153  // the tree would consist of an orderedAggregate whose input is a route.
   154  //
   155  // If a query has an ORDER BY, but the route is a scatter, then the
   156  // ordering is pushed down into the route itself. This results in a simple
   157  // route primitive.
   158  //
   159  // The LIMIT clause is the last construct of a query. If it cannot be
   160  // pushed into a route, then a primitive is created on top of any
   161  // of the above trees to make it discard unwanted rows.
   162  func (pb *primitiveBuilder) processSelect(sel *sqlparser.Select, reservedVars *sqlparser.ReservedVars, outer *symtab, query string) error {
   163  	// Check and error if there is any locking function present in select expression.
   164  	for _, expr := range sel.SelectExprs {
   165  		if aExpr, ok := expr.(*sqlparser.AliasedExpr); ok && sqlparser.IsLockingFunc(aExpr.Expr) {
   166  			return vterrors.VT12001(fmt.Sprintf("%v is allowed only with dual", sqlparser.String(aExpr)))
   167  		}
   168  	}
   169  	if sel.SQLCalcFoundRows {
   170  		if outer != nil || query == "" {
   171  			return vterrors.VT03008("SQL_CALC_FOUND_ROWS")
   172  		}
   173  		sel.SQLCalcFoundRows = false
   174  		if sel.Limit != nil {
   175  			plan, _, err := buildSQLCalcFoundRowsPlan(query, sel, reservedVars, pb.vschema, planSelectV3)
   176  			if err != nil {
   177  				return err
   178  			}
   179  			pb.plan = plan
   180  			return nil
   181  		}
   182  	}
   183  
   184  	// Into is not supported in subquery.
   185  	if sel.Into != nil && (outer != nil || query == "") {
   186  		return vterrors.VT03008("INTO")
   187  	}
   188  
   189  	var where sqlparser.Expr
   190  	if sel.Where != nil {
   191  		where = sel.Where.Expr
   192  	}
   193  	if err := pb.processTableExprs(sel.From, reservedVars, where); err != nil {
   194  		return err
   195  	}
   196  
   197  	if rb, ok := pb.plan.(*route); ok {
   198  		// TODO(sougou): this can probably be improved.
   199  		directives := sel.Comments.Directives()
   200  		rb.eroute.QueryTimeout = queryTimeout(directives)
   201  		if rb.eroute.TargetDestination != nil {
   202  			return vterrors.VT12001("SELECT with a target destination")
   203  		}
   204  		if directives.IsSet(sqlparser.DirectiveScatterErrorsAsWarnings) {
   205  			rb.eroute.ScatterErrorsAsWarnings = true
   206  		}
   207  	}
   208  
   209  	// Set the outer symtab after processing of FROM clause.
   210  	// This is because correlation is not allowed there.
   211  	pb.st.Outer = outer
   212  	if sel.Where != nil {
   213  		if err := pb.pushFilter(sel.Where.Expr, sqlparser.WhereStr, reservedVars); err != nil {
   214  			return err
   215  		}
   216  	}
   217  	if err := pb.checkAggregates(sel); err != nil {
   218  		return err
   219  	}
   220  	if err := pb.pushSelectExprs(sel, reservedVars); err != nil {
   221  		return err
   222  	}
   223  	if sel.Having != nil {
   224  		if err := pb.pushFilter(sel.Having.Expr, sqlparser.HavingStr, reservedVars); err != nil {
   225  			return err
   226  		}
   227  	}
   228  	if err := pb.pushOrderBy(sel.OrderBy); err != nil {
   229  		return err
   230  	}
   231  	if err := pb.pushLimit(sel.Limit); err != nil {
   232  		return err
   233  	}
   234  
   235  	return setMiscFunc(pb.plan, sel)
   236  }
   237  
   238  func setMiscFunc(in logicalPlan, sel *sqlparser.Select) error {
   239  	_, err := visit(in, func(plan logicalPlan) (bool, logicalPlan, error) {
   240  		switch node := plan.(type) {
   241  		case *route:
   242  			err := copyCommentsAndLocks(node.Select, sel, node.eroute.Opcode)
   243  			if err != nil {
   244  				return false, nil, err
   245  			}
   246  			return true, node, nil
   247  		case *routeGen4:
   248  			err := copyCommentsAndLocks(node.Select, sel, node.eroute.Opcode)
   249  			if err != nil {
   250  				return false, nil, err
   251  			}
   252  			return true, node, nil
   253  		}
   254  		return true, plan, nil
   255  	})
   256  
   257  	if err != nil {
   258  		return err
   259  	}
   260  	return nil
   261  }
   262  
   263  func copyCommentsAndLocks(statement sqlparser.SelectStatement, sel *sqlparser.Select, opcode engine.Opcode) error {
   264  	query := sqlparser.GetFirstSelect(statement)
   265  	query.Comments = sel.Comments
   266  	query.Lock = sel.Lock
   267  	if sel.Into != nil {
   268  		if opcode != engine.Unsharded {
   269  			return vterrors.VT12001("INTO on sharded keyspace")
   270  		}
   271  		query.Into = sel.Into
   272  	}
   273  	return nil
   274  }
   275  
   276  func buildSQLCalcFoundRowsPlan(
   277  	originalQuery string,
   278  	sel *sqlparser.Select,
   279  	reservedVars *sqlparser.ReservedVars,
   280  	vschema plancontext.VSchema,
   281  	planSelect func(reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema, sel *sqlparser.Select) (*jointab, logicalPlan, []string, error),
   282  ) (logicalPlan, []string, error) {
   283  	ljt, limitPlan, _, err := planSelect(reservedVars, vschema, sel)
   284  	if err != nil {
   285  		return nil, nil, err
   286  	}
   287  
   288  	statement2, reserved2, err := sqlparser.Parse2(originalQuery)
   289  	if err != nil {
   290  		return nil, nil, err
   291  	}
   292  	sel2 := statement2.(*sqlparser.Select)
   293  
   294  	sel2.SQLCalcFoundRows = false
   295  	sel2.OrderBy = nil
   296  	sel2.Limit = nil
   297  
   298  	countStartExpr := []sqlparser.SelectExpr{&sqlparser.AliasedExpr{
   299  		Expr: &sqlparser.CountStar{},
   300  	}}
   301  	if sel2.GroupBy == nil && sel2.Having == nil {
   302  		// if there is no grouping, we can use the same query and
   303  		// just replace the SELECT sub-clause to have a single count(*)
   304  		sel2.SelectExprs = countStartExpr
   305  	} else {
   306  		// when there is grouping, we have to move the original query into a derived table.
   307  		//                       select id, sum(12) from user group by id =>
   308  		// select count(*) from (select id, sum(12) from user group by id) t
   309  		sel3 := &sqlparser.Select{
   310  			SelectExprs: countStartExpr,
   311  			From: []sqlparser.TableExpr{
   312  				&sqlparser.AliasedTableExpr{
   313  					Expr: &sqlparser.DerivedTable{Select: sel2},
   314  					As:   sqlparser.NewIdentifierCS("t"),
   315  				},
   316  			},
   317  		}
   318  		sel2 = sel3
   319  	}
   320  
   321  	reservedVars2 := sqlparser.NewReservedVars("vtg", reserved2)
   322  
   323  	cjt, countPlan, tablesUsed, err := planSelect(reservedVars2, vschema, sel2)
   324  	if err != nil {
   325  		return nil, nil, err
   326  	}
   327  	return &sqlCalcFoundRows{LimitQuery: limitPlan, CountQuery: countPlan, ljt: ljt, cjt: cjt}, tablesUsed, nil
   328  }
   329  
   330  func planSelectV3(reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema, sel *sqlparser.Select) (*jointab, logicalPlan, []string, error) {
   331  	ljt := newJointab(reservedVars)
   332  	frpb := newPrimitiveBuilder(vschema, ljt)
   333  	err := frpb.processSelect(sel, reservedVars, nil, "")
   334  	return ljt, frpb.plan, nil, err
   335  }
   336  
   337  func handleDualSelects(sel *sqlparser.Select, vschema plancontext.VSchema) (engine.Primitive, error) {
   338  	if !isOnlyDual(sel) {
   339  		return nil, nil
   340  	}
   341  
   342  	exprs := make([]evalengine.Expr, len(sel.SelectExprs))
   343  	cols := make([]string, len(sel.SelectExprs))
   344  	var lockFunctions []*engine.LockFunc
   345  	for i, e := range sel.SelectExprs {
   346  		expr, ok := e.(*sqlparser.AliasedExpr)
   347  		if !ok {
   348  			return nil, nil
   349  		}
   350  		var err error
   351  		lFunc, isLFunc := expr.Expr.(*sqlparser.LockingFunc)
   352  		if isLFunc {
   353  			elem := &engine.LockFunc{Typ: expr.Expr.(*sqlparser.LockingFunc)}
   354  			if lFunc.Name != nil {
   355  				n, err := evalengine.Translate(lFunc.Name, nil)
   356  				if err != nil {
   357  					return nil, err
   358  				}
   359  				elem.Name = n
   360  			}
   361  			lockFunctions = append(lockFunctions, elem)
   362  			continue
   363  		}
   364  		if len(lockFunctions) > 0 {
   365  			return nil, vterrors.VT12001(fmt.Sprintf("LOCK function and other expression: [%s] in same select query", sqlparser.String(expr)))
   366  		}
   367  		exprs[i], err = evalengine.Translate(expr.Expr, evalengine.LookupDefaultCollation(vschema.ConnCollation()))
   368  		if err != nil {
   369  			return nil, nil
   370  		}
   371  		cols[i] = expr.As.String()
   372  		if cols[i] == "" {
   373  			cols[i] = sqlparser.String(expr.Expr)
   374  		}
   375  	}
   376  	if len(lockFunctions) > 0 {
   377  		return buildLockingPrimitive(sel, vschema, lockFunctions)
   378  	}
   379  	return &engine.Projection{
   380  		Exprs: exprs,
   381  		Cols:  cols,
   382  		Input: &engine.SingleRow{},
   383  	}, nil
   384  }
   385  
   386  func buildLockingPrimitive(sel *sqlparser.Select, vschema plancontext.VSchema, lockFunctions []*engine.LockFunc) (engine.Primitive, error) {
   387  	ks, err := vschema.FirstSortedKeyspace()
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  	buf := sqlparser.NewTrackedBuffer(sqlparser.FormatImpossibleQuery).WriteNode(sel)
   392  	return &engine.Lock{
   393  		Keyspace:          ks,
   394  		TargetDestination: key.DestinationKeyspaceID{0},
   395  		FieldQuery:        buf.String(),
   396  		LockFunctions:     lockFunctions,
   397  	}, nil
   398  }
   399  
   400  func isOnlyDual(sel *sqlparser.Select) bool {
   401  	if sel.Where != nil || sel.GroupBy != nil || sel.Having != nil || sel.Limit != nil || sel.OrderBy != nil {
   402  		// we can only deal with queries without any other subclauses - just SELECT and FROM, nothing else is allowed
   403  		return false
   404  	}
   405  
   406  	if len(sel.From) > 1 {
   407  		return false
   408  	}
   409  	table, ok := sel.From[0].(*sqlparser.AliasedTableExpr)
   410  	if !ok {
   411  		return false
   412  	}
   413  	tableName, ok := table.Expr.(sqlparser.TableName)
   414  
   415  	return ok && tableName.Name.String() == "dual" && tableName.Qualifier.IsEmpty()
   416  }
   417  
   418  // pushFilter identifies the target route for the specified bool expr,
   419  // pushes it down, and updates the route info if the new constraint improves
   420  // the primitive. This function can push to a WHERE or HAVING clause.
   421  func (pb *primitiveBuilder) pushFilter(in sqlparser.Expr, whereType string, reservedVars *sqlparser.ReservedVars) error {
   422  	filters := sqlparser.SplitAndExpression(nil, in)
   423  	reorderBySubquery(filters)
   424  	for _, filter := range filters {
   425  		pullouts, origin, expr, err := pb.findOrigin(filter, reservedVars)
   426  		if err != nil {
   427  			return err
   428  		}
   429  		rut, isRoute := origin.(*route)
   430  		if isRoute && rut.eroute.Opcode == engine.DBA {
   431  			err := pb.findSysInfoRoutingPredicates(expr, rut, reservedVars)
   432  			if err != nil {
   433  				return err
   434  			}
   435  		}
   436  		// The returned expression may be complex. Resplit before pushing.
   437  		for _, subexpr := range sqlparser.SplitAndExpression(nil, expr) {
   438  			pb.plan, err = planFilter(pb, pb.plan, subexpr, whereType, origin)
   439  			if err != nil {
   440  				return err
   441  			}
   442  		}
   443  		pb.addPullouts(pullouts)
   444  	}
   445  	return nil
   446  }
   447  
   448  // reorderBySubquery reorders the filters by pushing subqueries
   449  // to the end. This allows the non-subquery filters to be
   450  // pushed first because they can potentially improve the routing
   451  // plan, which can later allow a filter containing a subquery
   452  // to successfully merge with the corresponding route.
   453  func reorderBySubquery(filters []sqlparser.Expr) {
   454  	max := len(filters)
   455  	for i := 0; i < max; i++ {
   456  		if !hasSubquery(filters[i]) {
   457  			continue
   458  		}
   459  		saved := filters[i]
   460  		for j := i; j < len(filters)-1; j++ {
   461  			filters[j] = filters[j+1]
   462  		}
   463  		filters[len(filters)-1] = saved
   464  		max--
   465  	}
   466  }
   467  
   468  // addPullouts adds the pullout subqueries to the primitiveBuilder.
   469  func (pb *primitiveBuilder) addPullouts(pullouts []*pulloutSubquery) {
   470  	for _, pullout := range pullouts {
   471  		pullout.setUnderlying(pb.plan)
   472  		pb.plan = pullout
   473  		pb.plan.Reorder(0)
   474  	}
   475  }
   476  
   477  // pushSelectExprs identifies the target route for the
   478  // select expressions and pushes them down.
   479  func (pb *primitiveBuilder) pushSelectExprs(sel *sqlparser.Select, reservedVars *sqlparser.ReservedVars) error {
   480  	resultColumns, err := pb.pushSelectRoutes(sel.SelectExprs, reservedVars)
   481  	if err != nil {
   482  		return err
   483  	}
   484  	pb.st.SetResultColumns(resultColumns)
   485  	return pb.pushGroupBy(sel)
   486  }
   487  
   488  // pushSelectRoutes is a convenience function that pushes all the select
   489  // expressions and returns the list of resultColumns generated for it.
   490  func (pb *primitiveBuilder) pushSelectRoutes(selectExprs sqlparser.SelectExprs, reservedVars *sqlparser.ReservedVars) ([]*resultColumn, error) {
   491  	resultColumns := make([]*resultColumn, 0, len(selectExprs))
   492  	for _, node := range selectExprs {
   493  		switch node := node.(type) {
   494  		case *sqlparser.AliasedExpr:
   495  			pullouts, origin, expr, err := pb.findOrigin(node.Expr, reservedVars)
   496  			if err != nil {
   497  				return nil, err
   498  			}
   499  			node.Expr = expr
   500  			newBuilder, rc, _, err := planProjection(pb, pb.plan, node, origin)
   501  			if err != nil {
   502  				return nil, err
   503  			}
   504  			pb.plan = newBuilder
   505  			resultColumns = append(resultColumns, rc)
   506  			pb.addPullouts(pullouts)
   507  		case *sqlparser.StarExpr:
   508  			var expanded bool
   509  			var err error
   510  			resultColumns, expanded, err = pb.expandStar(resultColumns, node)
   511  			if err != nil {
   512  				return nil, err
   513  			}
   514  			if expanded {
   515  				continue
   516  			}
   517  			// We'll allow select * for simple routes.
   518  			rb, ok := pb.plan.(*route)
   519  			if !ok {
   520  				return nil, vterrors.VT12001("'*' expression in cross-shard query")
   521  			}
   522  			// Validate keyspace reference if any.
   523  			if !node.TableName.IsEmpty() {
   524  				if _, err := pb.st.FindTable(node.TableName); err != nil {
   525  					return nil, err
   526  				}
   527  			}
   528  			resultColumns = append(resultColumns, rb.PushAnonymous(node))
   529  		case *sqlparser.Nextval:
   530  			rb, ok := pb.plan.(*route)
   531  			if !ok {
   532  				// This code is unreachable because the parser doesn't allow joins for next val statements.
   533  				return nil, vterrors.VT12001("SELECT NEXT query in cross-shard query")
   534  			}
   535  			if rb.eroute.Opcode != engine.Next {
   536  				return nil, vterrors.VT03018()
   537  			}
   538  			rb.eroute.Opcode = engine.Next
   539  			resultColumns = append(resultColumns, rb.PushAnonymous(node))
   540  		default:
   541  			return nil, vterrors.VT13001(fmt.Sprintf("unexpected SELECT expression type: %T", node))
   542  		}
   543  	}
   544  	return resultColumns, nil
   545  }
   546  
   547  // expandStar expands a StarExpr and pushes the expanded
   548  // expressions down if the tables have authoritative column lists.
   549  // If not, it returns false.
   550  // This function breaks the abstraction a bit: it directly sets the
   551  // the Metadata for newly created expressions. In all other cases,
   552  // the Metadata is set through a symtab Find.
   553  func (pb *primitiveBuilder) expandStar(inrcs []*resultColumn, expr *sqlparser.StarExpr) (outrcs []*resultColumn, expanded bool, err error) {
   554  	tables := pb.st.AllTables()
   555  	if tables == nil {
   556  		// no table metadata available.
   557  		return inrcs, false, nil
   558  	}
   559  	if expr.TableName.IsEmpty() {
   560  		for _, t := range tables {
   561  			// All tables must have authoritative column lists.
   562  			if !t.isAuthoritative {
   563  				return inrcs, false, nil
   564  			}
   565  		}
   566  		singleTable := false
   567  		if len(tables) == 1 {
   568  			singleTable = true
   569  		}
   570  		for _, t := range tables {
   571  			for _, col := range t.columnNames {
   572  				var expr *sqlparser.AliasedExpr
   573  				if singleTable {
   574  					// If there's only one table, we use unqualified column names.
   575  					expr = &sqlparser.AliasedExpr{
   576  						Expr: &sqlparser.ColName{
   577  							Metadata: t.columns[col.Lowered()],
   578  							Name:     col,
   579  						},
   580  					}
   581  				} else {
   582  					// If a and b have id as their column, then
   583  					// select * from a join b should result in
   584  					// select a.id as id, b.id as id from a join b.
   585  					expr = &sqlparser.AliasedExpr{
   586  						Expr: &sqlparser.ColName{
   587  							Metadata:  t.columns[col.Lowered()],
   588  							Name:      col,
   589  							Qualifier: t.alias,
   590  						},
   591  						As: col,
   592  					}
   593  				}
   594  				newBuilder, rc, _, err := planProjection(pb, pb.plan, expr, t.Origin())
   595  				if err != nil {
   596  					// Unreachable because PushSelect won't fail on ColName.
   597  					return inrcs, false, err
   598  				}
   599  				pb.plan = newBuilder
   600  				inrcs = append(inrcs, rc)
   601  			}
   602  		}
   603  		return inrcs, true, nil
   604  	}
   605  
   606  	// Expression qualified with table name.
   607  	t, err := pb.st.FindTable(expr.TableName)
   608  	if err != nil {
   609  		return inrcs, false, err
   610  	}
   611  	if !t.isAuthoritative {
   612  		return inrcs, false, nil
   613  	}
   614  	for _, col := range t.columnNames {
   615  		expr := &sqlparser.AliasedExpr{
   616  			Expr: &sqlparser.ColName{
   617  				Metadata:  t.columns[col.Lowered()],
   618  				Name:      col,
   619  				Qualifier: expr.TableName,
   620  			},
   621  		}
   622  		newBuilder, rc, _, err := planProjection(pb, pb.plan, expr, t.Origin())
   623  		if err != nil {
   624  			// Unreachable because PushSelect won't fail on ColName.
   625  			return inrcs, false, err
   626  		}
   627  		pb.plan = newBuilder
   628  		inrcs = append(inrcs, rc)
   629  	}
   630  	return inrcs, true, nil
   631  }