Exemplo n.º 1
0
// processAliasedTable produces a builder subtree for the given AliasedTableExpr.
// If the expression is a subquery, then the the route built for it will contain
// the entire subquery tree in the from clause, as if it was a table.
// The symtab entry for the query will be a tabsym where the columns
// will be built from the select expressions of the subquery.
// Since the table aliases only contain vindex columns, we'll follow
// the same rule: only columns from the subquery that are identified as
// vindex columns will be added to the tabsym.
// A symtab symbol can only point to a route. This means that we canoot
// support complex joins in subqueries yet.
func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema VSchema) (builder, error) {
	switch expr := tableExpr.Expr.(type) {
	case *sqlparser.TableName:
		eroute, table, err := getTablePlan(expr, vschema)
		if err != nil {
			return nil, err
		}
		alias := sqlparser.TableIdent(sqlparser.String(expr))
		astName := expr.Name
		if tableExpr.As != "" {
			alias = tableExpr.As
			astName = alias
		}
		return newRoute(
			sqlparser.TableExprs([]sqlparser.TableExpr{tableExpr}),
			eroute,
			table,
			vschema,
			alias,
			astName,
		), nil
	case *sqlparser.Subquery:
		sel, ok := expr.Select.(*sqlparser.Select)
		if !ok {
			return nil, errors.New("unsupported: union operator in subqueries")
		}
		subplan, err := processSelect(sel, vschema, nil)
		if err != nil {
			return nil, err
		}
		subroute, ok := subplan.(*route)
		if !ok {
			return nil, errors.New("unsupported: complex join in subqueries")
		}
		table := &vindexes.Table{
			Keyspace: subroute.ERoute.Keyspace,
		}
		for _, colsyms := range subroute.Colsyms {
			if colsyms.Vindex == nil {
				continue
			}
			table.ColumnVindexes = append(table.ColumnVindexes, &vindexes.ColumnVindex{
				Column: cistring.CIString(colsyms.Alias),
				Vindex: colsyms.Vindex,
			})
		}
		rtb := newRoute(
			sqlparser.TableExprs([]sqlparser.TableExpr{tableExpr}),
			subroute.ERoute,
			table,
			vschema,
			tableExpr.As,
			tableExpr.As,
		)
		subroute.Redirect = rtb
		return rtb, nil
	}
	panic("unreachable")
}
Exemplo n.º 2
0
// Find returns the route for the symbol referenced by col.
// If a reference is found, the column's Metadata is set to point
// it. Subsequent searches will reuse this meatadata.
// If autoResolve is true, and there is only one table in the symbol table,
// then an unqualified reference is assumed to be implicitly against
// that table. The table info doesn't contain the full list of columns.
// So, any column reference is presumed valid. If a Colsyms scope is
// present, then the table scope is not searched. If a symbol is found
// in the current symtab, then isLocal is set to true. Otherwise, the
// search is continued in the outer symtab. If so, isLocal will be set
// to false. If the symbol was not found, an error is returned.
// isLocal must be checked before you can push-down (or pull-out)
// a construct.
// If a symbol was found in an outer scope, then the column reference
// is added to the Externs field.
func (st *symtab) Find(col *sqlparser.ColName, autoResolve bool) (rb *route, isLocal bool, err error) {
	if m, ok := col.Metadata.(sym); ok {
		return m.Route(), m.Symtab() == st, nil
	}
	if len(st.Colsyms) != 0 {
		name := sqlparser.String(col)
		starname := sqlparser.String(&sqlparser.ColName{
			Name:      sqlparser.NewColIdent("*"),
			Qualifier: col.Qualifier,
		})
		for _, colsym := range st.Colsyms {
			if colsym.Alias.EqualString(name) || colsym.Alias.EqualString(starname) || colsym.Alias.EqualString("*") {
				col.Metadata = colsym
				return colsym.Route(), true, nil
			}
		}
		if st.Outer != nil {
			// autoResolve only allowed for innermost scope.
			rb, _, err = st.Outer.Find(col, false)
			if err == nil {
				st.Externs = append(st.Externs, col)
			}
			return rb, false, err
		}
		return nil, false, fmt.Errorf("symbol %s not found", sqlparser.String(col))
	}
	qualifier := sqlparser.TableIdent(sqlparser.String(col.Qualifier))
	if qualifier == "" && autoResolve && len(st.tables) == 1 {
		for _, t := range st.tables {
			qualifier = t.Alias
			break
		}
	}
	alias := st.findTable(qualifier)
	if alias == nil {
		if st.Outer != nil {
			// autoResolve only allowed for innermost scope.
			rb, _, err = st.Outer.Find(col, false)
			if err == nil {
				st.Externs = append(st.Externs, col)
			}
			return rb, false, err
		}
		return nil, false, fmt.Errorf("symbol %s not found", sqlparser.String(col))
	}
	col.Metadata = alias
	return alias.Route(), true, nil
}