func parseAndNormalizeExpr(t *testing.T, sql string) (parser.TypedExpr, qvalMap) { expr, err := parser.ParseExprTraditional(sql) 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) } if expr, err = sel.resolveQNames(expr); err != nil { t.Fatalf("%s: %v", sql, err) } typedExpr, err := parser.TypeCheck(expr, nil, parser.NoTypePreference) if err != nil { t.Fatalf("%s: %v", sql, err) } if typedExpr, err = (parser.EvalContext{}).NormalizeExpr(typedExpr); err != nil { t.Fatalf("%s: %v", sql, err) } return typedExpr, sel.qvals }
// Set sets session variables. // Privileges: None. // Notes: postgres/mysql do not require privileges for session variables (some exceptions). func (p *planner) Set(n *parser.Set) (planNode, error) { if n.Name == nil { // A client has sent the reserved internal syntax SET ROW ... // Reject it. return nil, errors.New("invalid statement: SET ROW") } // By using QualifiedName.String() here any variables that are keywords will // be double quoted. name := strings.ToUpper(n.Name.String()) typedValues := make([]parser.TypedExpr, len(n.Values)) for i, expr := range n.Values { typedValue, err := parser.TypeCheck(expr, nil, parser.TypeString) if err != nil { return nil, err } typedValues[i] = typedValue } switch name { case `DATABASE`: dbName, err := p.getStringVal(name, typedValues) if err != nil { return nil, err } if len(dbName) != 0 { // Verify database descriptor exists. dbDesc, err := p.getDatabaseDesc(dbName) if err != nil { return nil, err } if dbDesc == nil { return nil, sqlbase.NewUndefinedDatabaseError(dbName) } } p.session.Database = dbName case `SYNTAX`: s, err := p.getStringVal(name, typedValues) if err != nil { return nil, err } switch sqlbase.NormalizeName(s) { case sqlbase.NormalizeName(parser.Modern.String()): p.session.Syntax = int32(parser.Modern) case sqlbase.NormalizeName(parser.Traditional.String()): p.session.Syntax = int32(parser.Traditional) default: return nil, fmt.Errorf("%s: \"%s\" is not in (%q, %q)", name, s, parser.Modern, parser.Traditional) } case `EXTRA_FLOAT_DIGITS`: // These settings are sent by the JDBC driver but we silently ignore them. default: return nil, fmt.Errorf("unknown variable: %q", name) } return &emptyNode{}, nil }
func (s *selectNode) addRender(target parser.SelectExpr, desiredType parser.Datum) error { // outputName will be empty if the target is not aliased. outputName := string(target.As) if isStar, cols, typedExprs, err := checkRenderStar(target, &s.table, s.qvals); err != nil { s.err = err return s.err } else if isStar { s.columns = append(s.columns, cols...) s.render = append(s.render, typedExprs...) 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, s.err = s.resolveQNames(target.Expr); s.err != nil { return s.err } if resolved, s.err = s.planner.expandSubqueries(resolved, 1); s.err != nil { return s.err } typedResolved, err := parser.TypeCheck(resolved, s.planner.evalCtx.Args, desiredType) if err != nil { s.err = err return s.err } normalized, err := s.planner.parser.NormalizeExpr(s.planner.evalCtx, typedResolved) if err != nil { s.err = err return s.err } 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: normalized.ReturnType()}) return nil }
// SanitizeVarFreeExpr verifies a default expression is valid, has the // correct type and contains no variable expressions. func SanitizeVarFreeExpr(expr parser.Expr, expectedType parser.Datum, context string) error { if parser.ContainsVars(expr) { return exprContainsVarsError(context, expr) } typedExpr, err := parser.TypeCheck(expr, nil, expectedType) if err != nil { return err } if defaultType := typedExpr.ReturnType(); !expectedType.TypeEqual(defaultType) { return incompatibleExprTypeError(context, expectedType, defaultType) } return nil }
// SanitizeDefaultExpr verifies a default expression is valid and has the // correct type. func SanitizeDefaultExpr(expr parser.Expr, colDatumType parser.Datum) error { typedExpr, err := parser.TypeCheck(expr, nil, colDatumType) if err != nil { return err } if defaultType := typedExpr.ReturnType(); !colDatumType.TypeEqual(defaultType) { return incompatibleColumnDefaultTypeError(colDatumType, defaultType) } if parser.ContainsVars(typedExpr) { return defaultContainsPlaceholdersError(typedExpr) } return nil }
func (p *planner) SetTimeZone(n *parser.SetTimeZone) (planNode, error) { typedValue, err := parser.TypeCheck(n.Value, nil, parser.TypeInt) if err != nil { return nil, err } d, err := typedValue.Eval(&p.evalCtx) if err != nil { return nil, err } var offset int64 switch v := d.(type) { case *parser.DString: location := string(*v) if location == "DEFAULT" || location == "LOCAL" { location = "UTC" } loc, err := time.LoadLocation(location) if err != nil { return nil, fmt.Errorf("cannot find time zone %q: %v", location, err) } p.session.Location = loc case *parser.DInterval: offset, _, _, err = v.Duration.Div(time.Second.Nanoseconds()).Encode() if err != nil { return nil, err } case *parser.DInt: offset = int64(*v) * 60 * 60 case *parser.DFloat: offset = int64(float64(*v) * 60.0 * 60.0) case *parser.DDecimal: sixty := inf.NewDec(60, 0) sixty.Mul(sixty, sixty).Mul(sixty, &v.Dec) sixty.Round(sixty, 0, inf.RoundDown) var ok bool if offset, ok = sixty.Unscaled(); !ok { return nil, fmt.Errorf("time zone value %s would overflow an int64", sixty) } default: return nil, fmt.Errorf("bad time zone value: %v", n.Value) } if offset != 0 { p.session.Location = time.FixedZone("", int(offset)) } return &emptyNode{}, 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)) exprStrings := make([]string, 0, len(cols)) for _, col := range cols { if col.DefaultExpr != nil { exprStrings = append(exprStrings, *col.DefaultExpr) } } exprs, err := parser.ParseExprsTraditional(exprStrings) if err != nil { return nil, err } defExprIdx := 0 for _, col := range cols { if col.DefaultExpr == nil { defaultExprs = append(defaultExprs, parser.DNull) continue } expr := exprs[defExprIdx] 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 } defaultExprs = append(defaultExprs, typedExpr) defExprIdx++ } return defaultExprs, nil }
// analyzeExpr performs semantic analysis of an axpression, including: // - replacing sub-queries by a sql.subquery node; // - resolving qnames (optional); // - type checking (with optional type enforcement); // - normalization. // The parameters tables and qvals, if both are non-nil, indicate // qname resolution should be performed. The qvals map will be filled // as a result. func (p *planner) analyzeExpr( raw parser.Expr, /* arguments for qname resolution */ tables []*tableInfo, qvals qvalMap, /* arguments for type checking */ expectedType parser.Datum, requireType bool, typingContext string, ) (parser.TypedExpr, error) { // Replace the sub-queries. // In all contexts that analyze a single expression, a single value // is expected. Tell this to replaceSubqueries. (See UPDATE for a // counter-example; cases where a subquery is an operand of a // comparison are handled specially in the subqueryVisitor already.) replaced, err := p.replaceSubqueries(raw, 1 /* one value expected */) if err != nil { return nil, err } // Perform optional qname resolution. var resolved parser.Expr if tables == nil || qvals == nil { resolved = replaced } else { resolved, err = resolveQNames(replaced, tables, qvals, &p.qnameVisitor) if err != nil { return nil, err } } // Type check. var typedExpr parser.TypedExpr if requireType { typedExpr, err = parser.TypeCheckAndRequire(resolved, &p.semaCtx, expectedType, typingContext) } else { typedExpr, err = parser.TypeCheck(resolved, &p.semaCtx, expectedType) } if err != nil { return nil, err } // Normalize. return p.parser.NormalizeExpr(&p.evalCtx, typedExpr) }
// TypeCheck ensures that the expressions mentioned in the // returningHelper have the right type. // TODO(knz): this both annotates the type of placeholders // (a task for prepare) and controls that provided values // for placeholders match their context (a task for exec). This // ought to be split into two phases. func (rh *returningHelper) TypeCheck() error { for i, expr := range rh.untypedExprs { desired := parser.NoTypePreference if len(rh.desiredTypes) > i { desired = rh.desiredTypes[i] } typedExpr, err := parser.TypeCheck(expr, rh.p.evalCtx.Args, desired) if err != nil { return err } typedExpr, err = rh.p.parser.NormalizeExpr(rh.p.evalCtx, typedExpr) if err != nil { return err } rh.exprs[i] = typedExpr rh.columns[i].Typ = typedExpr.ReturnType() } return 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 }
// TypeCheck ensures that the expressions mentioned in the // returningHelper have the right type. func (rh *returningHelper) TypeCheck() error { for i, expr := range rh.untypedExprs { baseExpr, bErr := rh.p.replaceSubqueries(expr, 1) if bErr != nil { return bErr } desired := parser.NoTypePreference if len(rh.desiredTypes) > i { desired = rh.desiredTypes[i] } typedExpr, err := parser.TypeCheck(baseExpr, &rh.p.semaCtx, desired) if err != nil { return err } typedExpr, err = rh.p.parser.NormalizeExpr(rh.p.evalCtx, typedExpr) if err != nil { return err } rh.exprs[i] = typedExpr rh.columns[i].Typ = typedExpr.ReturnType() } return 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 }
// Insert inserts rows into the database. // Privileges: INSERT on table. Also requires UPDATE on "ON DUPLICATE KEY UPDATE". // Notes: postgres requires INSERT. No "on duplicate key update" option. // mysql requires INSERT. Also requires UPDATE on "ON DUPLICATE KEY UPDATE". func (p *planner) Insert( n *parser.Insert, desiredTypes []parser.Datum, autoCommit bool, ) (planNode, error) { en, err := p.makeEditNode(n.Table, n.Returning, desiredTypes, autoCommit, privilege.INSERT) if err != nil { return nil, err } if n.OnConflict != nil { if err := p.checkPrivilege(en.tableDesc, privilege.UPDATE); err != nil { return nil, err } // TODO(dan): Support RETURNING in UPSERTs. if n.Returning != nil { return nil, fmt.Errorf("RETURNING is not supported with UPSERT") } } var cols []sqlbase.ColumnDescriptor // Determine which columns we're inserting into. if n.DefaultValues() { cols = en.tableDesc.Columns } else { var err error if cols, err = p.processColumns(en.tableDesc, n.Columns); err != nil { return nil, err } } // Number of columns expecting an input. This doesn't include the // columns receiving a default value. numInputColumns := len(cols) colIDSet := make(map[sqlbase.ColumnID]struct{}, len(cols)) for _, col := range cols { colIDSet[col.ID] = struct{}{} } // Add the column if it has a DEFAULT expression. addIfDefault := func(col sqlbase.ColumnDescriptor) { if col.DefaultExpr != nil { if _, ok := colIDSet[col.ID]; !ok { colIDSet[col.ID] = struct{}{} cols = append(cols, col) } } } // Add any column that has a DEFAULT expression. for _, col := range en.tableDesc.Columns { addIfDefault(col) } // Also add any column in a mutation that is WRITE_ONLY and has // a DEFAULT expression. for _, m := range en.tableDesc.Mutations { if m.State != sqlbase.DescriptorMutation_WRITE_ONLY { continue } if col := m.GetColumn(); col != nil { addIfDefault(*col) } } defaultExprs, err := makeDefaultExprs(cols, &p.parser, p.evalCtx) if err != nil { return nil, err } // Replace any DEFAULT markers with the corresponding default expressions. insertRows, err := p.fillDefaults(defaultExprs, cols, n) if err != nil { return nil, err } // Construct the check expressions. The returned slice will be nil if no // column in the table has a check expression. checkExprs, err := p.makeCheckExprs(cols) if err != nil { return nil, err } // Prepare the check expressions. var qvals qvalMap typedCheckExprs := make([]parser.TypedExpr, 0, len(checkExprs)) if len(checkExprs) > 0 { qvals = make(qvalMap) table := tableInfo{ columns: makeResultColumns(en.tableDesc.Columns), } for i := range checkExprs { expr, err := resolveQNames(checkExprs[i], &table, qvals, &p.qnameVisitor) if err != nil { return nil, err } typedExpr, err := parser.TypeCheck(expr, nil, parser.TypeBool) if err != nil { return nil, err } if typedExpr, err = p.parser.NormalizeExpr(p.evalCtx, typedExpr); err != nil { return nil, err } typedCheckExprs = append(typedCheckExprs, typedExpr) } } // Analyze the expressions for column information and typing. desiredTypesFromSelect := make([]parser.Datum, len(cols)) for i, col := range cols { desiredTypesFromSelect[i] = col.Type.ToDatumType() } rows, err := p.makePlan(insertRows, desiredTypesFromSelect, false) if err != nil { return nil, err } if expressions := len(rows.Columns()); expressions > numInputColumns { return nil, fmt.Errorf("INSERT has more expressions than target columns: %d/%d", expressions, numInputColumns) } // Type check the tuples, if any, to collect placeholder types. if values, ok := n.Rows.Select.(*parser.ValuesClause); ok { for _, tuple := range values.Tuples { for eIdx, val := range tuple.Exprs { if _, ok := val.(parser.DefaultVal); ok { continue } typedExpr, err := parser.TypeCheck(val, p.evalCtx.Args, desiredTypesFromSelect[eIdx]) if err != nil { return nil, err } err = sqlbase.CheckColumnType(cols[eIdx], typedExpr.ReturnType(), p.evalCtx.Args) if err != nil { return nil, err } } } } if err := en.rh.TypeCheck(); err != nil { return nil, err } ri, err := makeRowInserter(en.tableDesc, cols) if err != nil { return nil, err } var tw tableWriter if n.OnConflict == nil { tw = &tableInserter{ri: ri, autoCommit: autoCommit} } else { // TODO(dan): These are both implied by the short form of UPSERT. When the // INSERT INTO ON CONFLICT form is implemented, get these values from // n.OnConfict. upsertConflictIndex := en.tableDesc.PrimaryIndex insertCols := ri.insertCols indexColSet := make(map[sqlbase.ColumnID]struct{}, len(upsertConflictIndex.ColumnIDs)) for _, colID := range upsertConflictIndex.ColumnIDs { indexColSet[colID] = struct{}{} } // updateCols contains the columns that will be updated when a conflict is // found. For the UPSERT short form, it is the set of columns in insertCols // minus any columns in the conflict index. Example: // `UPSERT INTO abc VALUES (1, 2, 3)` is syntactic sugar for // `INSERT INTO abc VALUES (1, 2, 3) ON CONFLICT a DO UPDATE SET b = 2, c = 3`. updateCols := make([]sqlbase.ColumnDescriptor, 0, len(insertCols)) for _, c := range insertCols { if _, ok := indexColSet[c.ID]; !ok { updateCols = append(updateCols, c) } } ru, err := makeRowUpdater(en.tableDesc, updateCols) if err != nil { return nil, err } // TODO(dan): Use ru.fetchCols to compute the fetch selectors. tw = &tableUpserter{ri: ri, ru: ru, autoCommit: autoCommit} } in := &insertNode{ n: n, editNodeBase: en, defaultExprs: defaultExprs, checkExprs: typedCheckExprs, qvals: qvals, insertRows: insertRows, insertCols: ri.insertCols, insertColIDtoRowIndex: ri.insertColIDtoRowIndex, desiredTypes: desiredTypesFromSelect, tw: tw, } return in, nil }
// Update updates columns for a selection of rows from a table. // Privileges: UPDATE and SELECT on table. We currently always use a select statement. // Notes: postgres requires UPDATE. Requires SELECT with WHERE clause with table. // mysql requires UPDATE. Also requires SELECT with WHERE clause with table. // TODO(guanqun): need to support CHECK in UPDATE func (p *planner) Update(n *parser.Update, desiredTypes []parser.Datum, autoCommit bool) (planNode, error) { tracing.AnnotateTrace() en, err := p.makeEditNode(n.Table, n.Returning, desiredTypes, autoCommit, privilege.UPDATE) if err != nil { return nil, err } exprs := make([]*parser.UpdateExpr, len(n.Exprs)) for i, expr := range n.Exprs { // Replace the sub-query nodes. newExpr, err := p.replaceSubqueries(expr.Expr, len(expr.Names)) if err != nil { return nil, err } exprs[i] = &parser.UpdateExpr{Tuple: expr.Tuple, Expr: newExpr, Names: expr.Names} } // Determine which columns we're inserting into. names, err := p.namesForExprs(exprs) if err != nil { return nil, err } updateCols, err := p.processColumns(en.tableDesc, names) if err != nil { return nil, err } defaultExprs, err := makeDefaultExprs(updateCols, &p.parser, p.evalCtx) if err != nil { return nil, err } var requestedCols []sqlbase.ColumnDescriptor if len(en.rh.exprs) > 0 || len(en.tableDesc.Checks) > 0 { // TODO(dan): This could be made tighter, just the rows needed for RETURNING // exprs. requestedCols = en.tableDesc.Columns } ru, err := makeRowUpdater(en.tableDesc, updateCols, requestedCols) if err != nil { return nil, err } tw := tableUpdater{ru: ru, autoCommit: autoCommit} tracing.AnnotateTrace() // Generate the list of select targets. We need to select all of the columns // plus we select all of the update expressions in case those expressions // reference columns (e.g. "UPDATE t SET v = v + 1"). Note that we flatten // expressions for tuple assignments just as we flattened the column names // above. So "UPDATE t SET (a, b) = (1, 2)" translates into select targets of // "*, 1, 2", not "*, (1, 2)". targets := sqlbase.ColumnsSelectors(ru.fetchCols) i := 0 // Remember the index where the targets for exprs start. exprTargetIdx := len(targets) desiredTypesFromSelect := make([]parser.Datum, len(targets), len(targets)+len(exprs)) for _, expr := range exprs { if expr.Tuple { switch t := expr.Expr.(type) { case (*parser.Tuple): for _, e := range t.Exprs { typ := updateCols[i].Type.ToDatumType() e := fillDefault(e, typ, i, defaultExprs) targets = append(targets, parser.SelectExpr{Expr: e}) desiredTypesFromSelect = append(desiredTypesFromSelect, typ) i++ } default: return nil, fmt.Errorf("cannot use this expression to assign multiple columns: %s", expr.Expr) } } else { typ := updateCols[i].Type.ToDatumType() e := fillDefault(expr.Expr, typ, i, defaultExprs) targets = append(targets, parser.SelectExpr{Expr: e}) desiredTypesFromSelect = append(desiredTypesFromSelect, typ) i++ } } rows, err := p.SelectClause(&parser.SelectClause{ Exprs: targets, From: []parser.TableExpr{n.Table}, Where: n.Where, }, nil, nil, desiredTypesFromSelect) if err != nil { return nil, err } // ValArgs have their types populated in the above Select if they are part // of an expression ("SET a = 2 + $1") in the type check step where those // types are inferred. For the simpler case ("SET a = $1"), populate them // using checkColumnType. This step also verifies that the expression // types match the column types. sel := rows.(*selectTopNode).source.(*selectNode) for i, target := range sel.render[exprTargetIdx:] { // DefaultVal doesn't implement TypeCheck if _, ok := target.(parser.DefaultVal); ok { continue } // TODO(nvanbenschoten) isn't this TypeCheck redundant with the call to SelectClause? typedTarget, err := parser.TypeCheck(target, &p.semaCtx, updateCols[i].Type.ToDatumType()) if err != nil { return nil, err } err = sqlbase.CheckColumnType(updateCols[i], typedTarget.ReturnType(), p.semaCtx.Args) if err != nil { return nil, err } } if err := en.rh.TypeCheck(); err != nil { return nil, err } updateColsIdx := make(map[sqlbase.ColumnID]int, len(ru.updateCols)) for i, col := range ru.updateCols { updateColsIdx[col.ID] = i } un := &updateNode{ n: n, editNodeBase: en, updateCols: ru.updateCols, updateColsIdx: updateColsIdx, tw: tw, } if err := un.checkHelper.init(p, en.tableDesc); err != nil { return nil, err } un.run.initEditNode(rows) return un, nil }
// Insert inserts rows into the database. // Privileges: INSERT on table. Also requires UPDATE on "ON DUPLICATE KEY UPDATE". // Notes: postgres requires INSERT. No "on duplicate key update" option. // mysql requires INSERT. Also requires UPDATE on "ON DUPLICATE KEY UPDATE". func (p *planner) Insert( n *parser.Insert, desiredTypes []parser.Datum, autoCommit bool, ) (planNode, error) { en, err := p.makeEditNode(n.Table, n.Returning, desiredTypes, autoCommit, privilege.INSERT) if err != nil { return nil, err } if n.OnConflict != nil { if !n.OnConflict.DoNothing { if err := p.checkPrivilege(en.tableDesc, privilege.UPDATE); err != nil { return nil, err } } // TODO(dan): Support RETURNING in UPSERTs. if n.Returning != nil { return nil, fmt.Errorf("RETURNING is not supported with UPSERT") } } var cols []sqlbase.ColumnDescriptor // Determine which columns we're inserting into. if n.DefaultValues() { cols = en.tableDesc.Columns } else { var err error if cols, err = p.processColumns(en.tableDesc, n.Columns); err != nil { return nil, err } } // Number of columns expecting an input. This doesn't include the // columns receiving a default value. numInputColumns := len(cols) colIDSet := make(map[sqlbase.ColumnID]struct{}, len(cols)) for _, col := range cols { colIDSet[col.ID] = struct{}{} } // Add the column if it has a DEFAULT expression. addIfDefault := func(col sqlbase.ColumnDescriptor) { if col.DefaultExpr != nil { if _, ok := colIDSet[col.ID]; !ok { colIDSet[col.ID] = struct{}{} cols = append(cols, col) } } } // Add any column that has a DEFAULT expression. for _, col := range en.tableDesc.Columns { addIfDefault(col) } // Also add any column in a mutation that is WRITE_ONLY and has // a DEFAULT expression. for _, m := range en.tableDesc.Mutations { if m.State != sqlbase.DescriptorMutation_WRITE_ONLY { continue } if col := m.GetColumn(); col != nil { addIfDefault(*col) } } defaultExprs, err := makeDefaultExprs(cols, &p.parser, p.evalCtx) if err != nil { return nil, err } // Replace any DEFAULT markers with the corresponding default expressions. insertRows, err := p.fillDefaults(defaultExprs, cols, n) if err != nil { return nil, err } // Analyze the expressions for column information and typing. desiredTypesFromSelect := make([]parser.Datum, len(cols)) for i, col := range cols { desiredTypesFromSelect[i] = col.Type.ToDatumType() } rows, err := p.newPlan(insertRows, desiredTypesFromSelect, false) if err != nil { return nil, err } if expressions := len(rows.Columns()); expressions > numInputColumns { return nil, fmt.Errorf("INSERT has more expressions than target columns: %d/%d", expressions, numInputColumns) } // Type check the tuples, if any, to collect placeholder types. if values, ok := n.Rows.Select.(*parser.ValuesClause); ok { for _, tuple := range values.Tuples { for eIdx, val := range tuple.Exprs { if _, ok := val.(parser.DefaultVal); ok { continue } typedExpr, err := parser.TypeCheck(val, &p.semaCtx, desiredTypesFromSelect[eIdx]) if err != nil { return nil, err } err = sqlbase.CheckColumnType(cols[eIdx], typedExpr.ReturnType(), p.semaCtx.Args) if err != nil { return nil, err } } } } if err := en.rh.TypeCheck(); err != nil { return nil, err } ri, err := makeRowInserter(en.tableDesc, cols) if err != nil { return nil, err } var tw tableWriter if n.OnConflict == nil { tw = &tableInserter{ri: ri, autoCommit: autoCommit} } else { updateExprs, conflictIndex, err := upsertExprsAndIndex(en.tableDesc, *n.OnConflict, ri.insertCols) if err != nil { return nil, err } if n.OnConflict.DoNothing { // TODO(dan): Postgres allows ON CONFLICT DO NOTHING without specifying a // conflict index, which means do nothing on any conflict. Support this if // someone needs it. tw = &tableUpserter{ri: ri, conflictIndex: *conflictIndex} } else { names, err := p.namesForExprs(updateExprs) if err != nil { return nil, err } updateCols, err := p.processColumns(en.tableDesc, names) if err != nil { return nil, err } helper, err := p.makeUpsertHelper(en.tableDesc, ri.insertCols, updateCols, updateExprs, conflictIndex) if err != nil { return nil, err } tw = &tableUpserter{ri: ri, updateCols: updateCols, conflictIndex: *conflictIndex, evaler: helper} } } in := &insertNode{ n: n, editNodeBase: en, defaultExprs: defaultExprs, insertRows: insertRows, insertCols: ri.insertCols, insertColIDtoRowIndex: ri.insertColIDtoRowIndex, tw: tw, } if err := in.checkHelper.init(p, en.tableDesc); err != nil { return nil, err } in.run.initEditNode(rows) return in, nil }
// Update updates columns for a selection of rows from a table. // Privileges: UPDATE and SELECT on table. We currently always use a select statement. // Notes: postgres requires UPDATE. Requires SELECT with WHERE clause with table. // mysql requires UPDATE. Also requires SELECT with WHERE clause with table. // TODO(guanqun): need to support CHECK in UPDATE func (p *planner) Update(n *parser.Update, desiredTypes []parser.Datum, autoCommit bool) (planNode, error) { tracing.AnnotateTrace() en, err := p.makeEditNode(n.Table, n.Returning, desiredTypes, autoCommit, privilege.UPDATE) if err != nil { return nil, err } exprs := make([]parser.UpdateExpr, len(n.Exprs)) for i, expr := range n.Exprs { exprs[i] = *expr } // Determine which columns we're inserting into. var names parser.QualifiedNames for _, expr := range n.Exprs { // TODO(knz): We need to (attempt to) expand subqueries here already // so that it retrieves the column names. But then we need to do // it again when the placeholder values are known below. newExpr, eErr := p.expandSubqueries(expr.Expr, len(expr.Names)) if eErr != nil { return nil, eErr } if expr.Tuple { n := 0 switch t := newExpr.(type) { case *parser.Tuple: n = len(t.Exprs) case *parser.DTuple: n = len(*t) default: return nil, util.Errorf("unsupported tuple assignment: %T", newExpr) } if len(expr.Names) != n { return nil, fmt.Errorf("number of columns (%d) does not match number of values (%d)", len(expr.Names), n) } } names = append(names, expr.Names...) } updateCols, err := p.processColumns(en.tableDesc, names) if err != nil { return nil, err } defaultExprs, err := makeDefaultExprs(updateCols, &p.parser, p.evalCtx) if err != nil { return nil, err } ru, err := makeRowUpdater(en.tableDesc, updateCols) if err != nil { return nil, err } // TODO(dan): Use ru.fetchCols to compute the fetch selectors. tw := tableUpdater{ru: ru, autoCommit: autoCommit} tracing.AnnotateTrace() // Generate the list of select targets. We need to select all of the columns // plus we select all of the update expressions in case those expressions // reference columns (e.g. "UPDATE t SET v = v + 1"). Note that we flatten // expressions for tuple assignments just as we flattened the column names // above. So "UPDATE t SET (a, b) = (1, 2)" translates into select targets of // "*, 1, 2", not "*, (1, 2)". // TODO(radu): we only need to select columns necessary to generate primary and // secondary indexes keys, and columns needed by returningHelper. targets := en.tableDesc.AllColumnsSelector() i := 0 // Remember the index where the targets for exprs start. exprTargetIdx := len(targets) desiredTypesFromSelect := make([]parser.Datum, len(targets), len(targets)+len(exprs)) for _, expr := range n.Exprs { if expr.Tuple { if t, ok := expr.Expr.(*parser.Tuple); ok { for _, e := range t.Exprs { typ := updateCols[i].Type.ToDatumType() e := fillDefault(e, typ, i, defaultExprs) targets = append(targets, parser.SelectExpr{Expr: e}) desiredTypesFromSelect = append(desiredTypesFromSelect, typ) i++ } } } else { typ := updateCols[i].Type.ToDatumType() e := fillDefault(expr.Expr, typ, i, defaultExprs) targets = append(targets, parser.SelectExpr{Expr: e}) desiredTypesFromSelect = append(desiredTypesFromSelect, typ) i++ } } // TODO(knz): Until we split the creation of the node from Start() // for the SelectClause too, we cannot cache this. This is because // this node's initSelect() method both does type checking and also // performs index selection. We cannot perform index selection // properly until the placeholder values are known. rows, err := p.SelectClause(&parser.SelectClause{ Exprs: targets, From: []parser.TableExpr{n.Table}, Where: n.Where, }, desiredTypesFromSelect) if err != nil { return nil, err } // ValArgs have their types populated in the above Select if they are part // of an expression ("SET a = 2 + $1") in the type check step where those // types are inferred. For the simpler case ("SET a = $1"), populate them // using checkColumnType. This step also verifies that the expression // types match the column types. for i, target := range rows.(*selectNode).render[exprTargetIdx:] { // DefaultVal doesn't implement TypeCheck if _, ok := target.(parser.DefaultVal); ok { continue } typedTarget, err := parser.TypeCheck(target, p.evalCtx.Args, updateCols[i].Type.ToDatumType()) if err != nil { return nil, err } err = sqlbase.CheckColumnType(updateCols[i], typedTarget.ReturnType(), p.evalCtx.Args) if err != nil { return nil, err } } if err := en.rh.TypeCheck(); err != nil { return nil, err } un := &updateNode{ n: n, editNodeBase: en, desiredTypes: desiredTypesFromSelect, defaultExprs: defaultExprs, updateCols: ru.updateCols, tw: tw, } return un, nil }
func (p *planner) makeUpsertHelper( tableDesc *sqlbase.TableDescriptor, insertCols []sqlbase.ColumnDescriptor, updateCols []sqlbase.ColumnDescriptor, updateExprs parser.UpdateExprs, upsertConflictIndex *sqlbase.IndexDescriptor, ) (*upsertHelper, error) { defaultExprs, err := makeDefaultExprs(updateCols, &p.parser, p.evalCtx) if err != nil { return nil, err } untupledExprs := make(parser.Exprs, 0, len(updateExprs)) i := 0 for _, updateExpr := range updateExprs { if updateExpr.Tuple { if t, ok := updateExpr.Expr.(*parser.Tuple); ok { for _, e := range t.Exprs { typ := updateCols[i].Type.ToDatumType() e := fillDefault(e, typ, i, defaultExprs) untupledExprs = append(untupledExprs, e) i++ } } } else { typ := updateCols[i].Type.ToDatumType() e := fillDefault(updateExpr.Expr, typ, i, defaultExprs) untupledExprs = append(untupledExprs, e) i++ } } allExprsIdentity := true for i, expr := range untupledExprs { qn, ok := expr.(*parser.QualifiedName) if !ok { allExprsIdentity = false break } if err := qn.NormalizeColumnName(); err != nil { return nil, err } if qn.Base != upsertExcludedTable || qn.Column() != updateCols[i].Name { allExprsIdentity = false break } } table := &tableInfo{alias: tableDesc.Name, columns: makeResultColumns(tableDesc.Columns)} excludedAliasTable := &tableInfo{ alias: upsertExcludedTable, columns: makeResultColumns(insertCols), } tables := []*tableInfo{table, excludedAliasTable} var normExprs []parser.TypedExpr qvals := make(qvalMap) for _, expr := range untupledExprs { expandedExpr, err := p.replaceSubqueries(expr, 1) if err != nil { return nil, err } resolvedExpr, err := resolveQNames(expandedExpr, tables, qvals, &p.qnameVisitor) if err != nil { return nil, err } typedExpr, err := parser.TypeCheck(resolvedExpr, &p.semaCtx, parser.NoTypePreference) if err != nil { return nil, err } normExpr, err := p.parser.NormalizeExpr(p.evalCtx, typedExpr) if err != nil { return nil, err } normExprs = append(normExprs, normExpr) } helper := &upsertHelper{ p: p, qvals: qvals, evalExprs: normExprs, table: table, excludedAliasTable: excludedAliasTable, allExprsIdentity: allExprsIdentity, } return helper, nil }