func (s *selectNode) addRender(target parser.SelectExpr) *roachpb.Error { // outputName will be empty if the target is not aliased. outputName := string(target.As) if isStar, cols, exprs, err := checkRenderStar(target, &s.table, s.qvals); err != nil { s.pErr = roachpb.NewError(err) return s.pErr } else if isStar { s.columns = append(s.columns, cols...) s.render = append(s.render, exprs...) return nil } // When generating an output column name it should exactly match the original // expression, so determine the output column name before we perform any // manipulations to the expression. outputName = getRenderColName(target) // Resolve qualified names. This has the side-effect of normalizing any // qualified name found. var resolved parser.Expr var err error if resolved, err = s.resolveQNames(target.Expr); err != nil { s.pErr = roachpb.NewError(err) return s.pErr } if resolved, s.pErr = s.planner.expandSubqueries(resolved, 1); s.pErr != nil { return s.pErr } var typ parser.Datum typ, err = resolved.TypeCheck(s.planner.evalCtx.Args) s.pErr = roachpb.NewError(err) if s.pErr != nil { return s.pErr } var normalized parser.Expr normalized, err = s.planner.parser.NormalizeExpr(s.planner.evalCtx, resolved) s.pErr = roachpb.NewError(err) if s.pErr != nil { return s.pErr } s.render = append(s.render, normalized) if target.As == "" { switch t := target.Expr.(type) { case *parser.QualifiedName: // If the expression is a qualified name, use the column name, not the // full qualification as the column name to return. outputName = t.Column() } } s.columns = append(s.columns, ResultColumn{Name: outputName, Typ: typ}) return nil }
func sameTypeExprs(left, right parser.Expr) (bool, error) { dummyLeft, err := left.TypeCheck(nil) if err != nil || dummyLeft == parser.DNull { return false, err } dummyRight, err := right.TypeCheck(nil) if err != nil || dummyRight == parser.DNull { return false, err } return !dummyLeft.TypeEqual(dummyRight), nil }
func (n *scanNode) addRender(target parser.SelectExpr) *roachpb.Error { // When generating an output column name it should exactly match the original // expression, so determine the output column name before we perform any // manipulations to the expression (such as star expansion). var outputName string if target.As != "" { outputName = string(target.As) } else { outputName = target.Expr.String() } // If a QualifiedName has a StarIndirection suffix we need to match the // prefix of the qualified name to one of the tables in the query and // then expand the "*" into a list of columns. if qname, ok := target.Expr.(*parser.QualifiedName); ok { if n.pErr = roachpb.NewError(qname.NormalizeColumnName()); n.pErr != nil { return n.pErr } if qname.IsStar() { if n.desc == nil { return roachpb.NewUErrorf("\"%s\" with no tables specified is not valid", qname) } if target.As != "" { return roachpb.NewUErrorf("\"%s\" cannot be aliased", qname) } tableName := qname.Table() if tableName != "" && !equalName(n.desc.Alias, tableName) { return roachpb.NewUErrorf("table \"%s\" not found", tableName) } if n.isSecondaryIndex { for _, id := range n.index.ColumnIDs { var col *ColumnDescriptor if col, n.pErr = n.desc.FindColumnByID(id); n.pErr != nil { return n.pErr } qval := n.getQVal(*col) n.columns = append(n.columns, resultColumn{name: col.Name, typ: qval.datum}) n.render = append(n.render, qval) } } else { for _, col := range n.desc.VisibleColumns() { qval := n.getQVal(col) n.columns = append(n.columns, resultColumn{name: col.Name, typ: qval.datum}) n.render = append(n.render, qval) } } return nil } } // Resolve qualified names. This has the side-effect of normalizing any // qualified name found. var resolved parser.Expr if resolved, n.pErr = n.resolveQNames(target.Expr); n.pErr != nil { return n.pErr } if resolved, n.pErr = n.planner.expandSubqueries(resolved, 1); n.pErr != nil { return n.pErr } var typ parser.Datum var err error typ, err = resolved.TypeCheck(n.planner.evalCtx.Args) n.pErr = roachpb.NewError(err) if n.pErr != nil { return n.pErr } var normalized parser.Expr normalized, err = n.planner.parser.NormalizeExpr(n.planner.evalCtx, resolved) n.pErr = roachpb.NewError(err) if n.pErr != nil { return n.pErr } n.render = append(n.render, normalized) if target.As == "" { switch t := target.Expr.(type) { case *parser.QualifiedName: // If the expression is a qualified name, use the column name, not the // full qualification as the column name to return. outputName = t.Column() } } n.columns = append(n.columns, resultColumn{name: outputName, typ: typ}) return nil }