// Test that we can resolve the qnames in an expression that has already been // resolved. func TestRetryResolveQNames(t *testing.T) { defer leaktest.AfterTest(t)() expr, err := parser.ParseExprTraditional(`COUNT(a)`) if err != nil { t.Fatal(err) } for i := 0; i < 2; i++ { desc := testTableDesc() s := testInitDummySelectNode(desc) if err := desc.AllocateIDs(); err != nil { t.Fatal(err) } _, err := s.resolveQNames(expr) if err != nil { t.Fatal(err) } if len(s.qvals) != 1 { t.Fatalf("%d: expected 1 qvalue, but found %d", i, len(s.qvals)) } if _, ok := s.qvals[columnRef{&s.source.info, 0}]; !ok { t.Fatalf("%d: unable to find qvalue for column 0 (a)", i) } } }
func parseAndNormalizeExpr(t *testing.T, sql string) (parser.Expr, qvalMap) { expr, err := parser.ParseExprTraditional(sql) if err != nil { t.Fatalf("%s: %v", sql, err) } expr, err = (parser.EvalContext{}).NormalizeExpr(expr) if err != nil { t.Fatalf("%s: %v", sql, err) } // Perform qualified name resolution because {analyze,simplify}Expr want // expressions containing qvalues. s := &scanNode{} s.desc = testTableDesc() s.visibleCols = s.desc.Columns if err := s.desc.AllocateIDs(); err != nil { t.Fatal(err) } expr, err = s.resolveQNames(expr) if err != nil { t.Fatalf("%s: %v", sql, err) } if _, err := expr.TypeCheck(); err != nil { t.Fatalf("%s: %v", sql, err) } return expr, s.qvals }
func (p *planner) makeCheckExprs(cols []sqlbase.ColumnDescriptor) ([]parser.Expr, error) { // Check to see if any of the columns have CHECK expressions. If there are // no CHECK expressions, we don't bother with constructing it. numCheck := 0 for _, col := range cols { if col.CheckExpr != nil { numCheck++ break } } if numCheck == 0 { return nil, nil } checkExprs := make([]parser.Expr, 0, numCheck) for _, col := range cols { if col.CheckExpr == nil { continue } expr, err := parser.ParseExprTraditional(*col.CheckExpr) if err != nil { return nil, err } checkExprs = append(checkExprs, expr) } return checkExprs, nil }
func parseAndNormalizeExpr(t *testing.T, sql string) (parser.Expr, qvalMap) { expr, err := parser.ParseExprTraditional(sql) if err != nil { t.Fatalf("%s: %v", sql, err) } expr, err = (parser.EvalContext{}).NormalizeExpr(expr) if err != nil { t.Fatalf("%s: %v", sql, err) } // Perform qualified name resolution because {analyze,simplify}Expr want // expressions containing qvalues. desc := testTableDesc() sel := testInitDummySelectNode(desc) if err := desc.AllocateIDs(); err != nil { t.Fatal(err) } expr, nErr := sel.resolveQNames(expr) if nErr != nil { t.Fatalf("%s: %v", sql, nErr) } if _, err := expr.TypeCheck(nil); err != nil { t.Fatalf("%s: %v", sql, err) } return expr, sel.qvals }
// Test that we can resolve the qnames in an expression that has already been // resolved. func TestRetryResolveQNames(t *testing.T) { defer leaktest.AfterTest(t) expr, err := parser.ParseExprTraditional(`COUNT(a)`) if err != nil { t.Fatal(err) } for i := 0; i < 2; i++ { s := &scanNode{} s.desc = testTableDesc() s.visibleCols = s.desc.Columns if err := s.desc.AllocateIDs(); err != nil { t.Fatal(err) } _, pErr := s.resolveQNames(expr) if pErr != nil { t.Fatal(pErr) } if len(s.qvals) != 1 { t.Fatalf("%d: expected 1 qvalue, but found %d", i, len(s.qvals)) } if _, ok := s.qvals[ColumnID(1)]; !ok { t.Fatalf("%d: unable to find qvalue for column ID 1", i) } } }
func (c *checkHelper) init(p *planner, tableDesc *sqlbase.TableDescriptor) error { if len(tableDesc.Checks) == 0 { return nil } c.qvals = make(qvalMap) c.cols = tableDesc.Columns table := tableInfo{ columns: makeResultColumns(tableDesc.Columns), } c.exprs = make([]parser.TypedExpr, len(tableDesc.Checks)) for i, check := range tableDesc.Checks { raw, err := parser.ParseExprTraditional(check.Expr) if err != nil { return err } typedExpr, err := p.analyzeExpr(raw, []*tableInfo{&table}, c.qvals, parser.TypeBool, false, "") if err != nil { return err } c.exprs[i] = typedExpr } return nil }
func makeDefaultExprs( cols []sqlbase.ColumnDescriptor, parse *parser.Parser, evalCtx parser.EvalContext, ) ([]parser.TypedExpr, error) { // Check to see if any of the columns have DEFAULT expressions. If there // are no DEFAULT expressions, we don't bother with constructing the // defaults map as the defaults are all NULL. haveDefaults := false for _, col := range cols { if col.DefaultExpr != nil { haveDefaults = true break } } if !haveDefaults { return nil, nil } // Build the default expressions map from the parsed SELECT statement. defaultExprs := make([]parser.TypedExpr, 0, len(cols)) for _, col := range cols { if col.DefaultExpr == nil { defaultExprs = append(defaultExprs, parser.DNull) continue } expr, err := parser.ParseExprTraditional(*col.DefaultExpr) if err != nil { return nil, err } typedExpr, err := parser.TypeCheck(expr, nil, col.Type.ToDatumType()) if err != nil { return nil, err } if typedExpr, err = parse.NormalizeExpr(evalCtx, typedExpr); err != nil { return nil, err } if parser.ContainsVars(typedExpr) { return nil, util.Errorf("default expression contains variables") } defaultExprs = append(defaultExprs, typedExpr) } return defaultExprs, nil }
// processExpression parses the string expression inside an Expression, // interpreting $0, $1, etc as indexed variables. func processExpression(exprSpec Expression, h *parser.IndexedVarHelper) (parser.TypedExpr, error) { expr, err := parser.ParseExprTraditional(exprSpec.Expr) if err != nil { return nil, err } // Convert ValArgs to IndexedVars v := valArgsConvert{h: h, err: nil} expr, _ = parser.WalkExpr(&v, expr) if v.err != nil { return nil, v.err } // Convert to a fully typed expression. typedExpr, err := parser.TypeCheck(expr, nil, nil) if err != nil { return nil, err } return typedExpr, nil }
func (p *planner) makeDefaultExprs(cols []ColumnDescriptor) ([]parser.Expr, error) { // Check to see if any of the columns have DEFAULT expressions. If there are // no DEFAULT expressions, we don't bother with constructing the defaults map // as the defaults are all NULL. haveDefaults := false for _, col := range cols { if col.DefaultExpr != nil { haveDefaults = true break } } if !haveDefaults { return nil, nil } // Build the default expressions map from the parsed SELECT statement. defaultExprs := make([]parser.Expr, 0, len(cols)) for _, col := range cols { if col.DefaultExpr == nil { defaultExprs = append(defaultExprs, parser.DNull) continue } expr, err := parser.ParseExprTraditional(*col.DefaultExpr) if err != nil { return nil, err } expr, err = p.parser.NormalizeExpr(p.evalCtx, expr) if err != nil { return nil, err } if parser.ContainsVars(expr) { return nil, util.Errorf("default expression contains variables") } defaultExprs = append(defaultExprs, expr) } return defaultExprs, nil }
func parseZoneName(s string) ([]string, error) { if strings.ToLower(s) == ".default" { return nil, nil } expr, err := parser.ParseExprTraditional(s) if err != nil { return nil, fmt.Errorf("malformed name: %s", s) } qname, ok := expr.(*parser.QualifiedName) if !ok { return nil, fmt.Errorf("malformed name: %s", s) } // This is a bit of a hack: "." is not a valid database name which we use as // a placeholder in order to normalize the qualified name. if err := qname.NormalizeTableName("."); err != nil { return nil, err } var names []string if n := qname.Database(); n != "." { names = append(names, n) } names = append(names, qname.Table()) return names, nil }
func (c *checkHelper) init(p *planner, tableDesc *sqlbase.TableDescriptor) error { if len(tableDesc.Checks) == 0 { return nil } c.qvals = make(qvalMap) c.cols = tableDesc.Columns table := tableInfo{ columns: makeResultColumns(tableDesc.Columns), } c.exprs = make([]parser.TypedExpr, len(tableDesc.Checks)) for i, check := range tableDesc.Checks { raw, err := parser.ParseExprTraditional(check.Expr) if err != nil { return err } replaced, err := p.replaceSubqueries(raw, 1) if err != nil { return nil } resolved, err := resolveQNames(replaced, []*tableInfo{&table}, c.qvals, &p.qnameVisitor) if err != nil { return err } typedExpr, err := parser.TypeCheck(resolved, nil, parser.TypeBool) if err != nil { return err } if typedExpr, err = p.parser.NormalizeExpr(p.evalCtx, typedExpr); err != nil { return err } c.exprs[i] = typedExpr } return nil }