func (p *planner) fillDefaults(defaultExprs []parser.Expr, cols []ColumnDescriptor, n *parser.Insert) parser.SelectStatement { if n.DefaultValues() { row := make(parser.Tuple, 0, len(cols)) for i := range cols { if defaultExprs == nil { row = append(row, parser.DNull) continue } row = append(row, defaultExprs[i]) } return parser.Values{row} } switch values := n.Rows.(type) { case parser.Values: for _, tuple := range values { for i, val := range tuple { switch val.(type) { case parser.DefaultVal: if defaultExprs == nil { tuple[i] = parser.DNull continue } tuple[i] = defaultExprs[i] } } } } return n.Rows }
func (p *planner) fillDefaults(defaultExprs []parser.TypedExpr, cols []sqlbase.ColumnDescriptor, n *parser.Insert) (parser.SelectStatement, error) { if n.DefaultValues() { row := make(parser.Exprs, 0, len(cols)) for i := range cols { if defaultExprs == nil { row = append(row, parser.DNull) continue } row = append(row, defaultExprs[i]) } return &parser.ValuesClause{Tuples: []*parser.Tuple{{Exprs: row}}}, nil } values, ok := n.Rows.Select.(*parser.ValuesClause) if !ok { return n.Rows.Select, nil } ret := values for tIdx, tuple := range values.Tuples { tupleCopied := false for eIdx, val := range tuple.Exprs { switch val.(type) { case parser.DefaultVal: if !tupleCopied { if ret == values { ret = &parser.ValuesClause{Tuples: append([]*parser.Tuple(nil), values.Tuples...)} } ret.Tuples[tIdx] = &parser.Tuple{Exprs: append([]parser.Expr(nil), tuple.Exprs...)} tupleCopied = true } if defaultExprs == nil || eIdx >= len(defaultExprs) { // The case where eIdx is too large for defaultExprs will be // transformed into an error by the check on the number of // columns in Insert(). ret.Tuples[tIdx].Exprs[eIdx] = parser.DNull } else { ret.Tuples[tIdx].Exprs[eIdx] = defaultExprs[eIdx] } } } } return ret, nil }
func (p *planner) fillDefaults(defaultExprs []parser.Expr, cols []ColumnDescriptor, n *parser.Insert) parser.SelectStatement { if n.DefaultValues() { row := make(parser.Exprs, 0, len(cols)) for i := range cols { if defaultExprs == nil { row = append(row, parser.DNull) continue } row = append(row, defaultExprs[i]) } return &parser.Values{Tuples: []*parser.Tuple{{Exprs: row}}} } values, ok := n.Rows.(*parser.Values) if !ok { return n.Rows } ret := values for tIdx, tuple := range values.Tuples { tupleCopied := false for eIdx, val := range tuple.Exprs { switch val.(type) { case parser.DefaultVal: if !tupleCopied { if ret == values { ret = &parser.Values{Tuples: append([]*parser.Tuple(nil), values.Tuples...)} } ret.Tuples[tIdx] = &parser.Tuple{Exprs: append([]parser.Expr(nil), tuple.Exprs...)} tupleCopied = true } if defaultExprs == nil { ret.Tuples[tIdx].Exprs[eIdx] = parser.DNull } else { ret.Tuples[tIdx].Exprs[eIdx] = defaultExprs[eIdx] } } } } return ret }
// 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 }
// 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) { tn, err := p.getAliasedTableName(n.Table) if err != nil { return nil, err } en, err := p.makeEditNode(tn, 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() } // Create the plan for the data source. // This performs type checking on source expressions, collecting // types for placeholders in the process. 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 error: table %s has %d columns but %d values were supplied", n.Table, numInputColumns, expressions) } fkTables := tablesNeededForFKs(*en.tableDesc, CheckInserts) if err := p.fillFKTableMap(fkTables); err != nil { return nil, err } ri, err := makeRowInserter(p.txn, en.tableDesc, fkTables, cols, checkFKs) 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(tn, en.tableDesc, ri.insertCols, updateCols, updateExprs, conflictIndex) if err != nil { return nil, err } fkTables := tablesNeededForFKs(*en.tableDesc, CheckUpdates) if err := p.fillFKTableMap(fkTables); err != nil { return nil, err } tw = &tableUpserter{ri: ri, fkTables: fkTables, 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, tn, en.tableDesc); err != nil { return nil, err } if err := in.run.initEditNode(&in.editNodeBase, rows, n.Returning, desiredTypes); err != nil { return nil, err } return in, nil }
// Insert inserts rows into the database. // Privileges: INSERT on table // 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, autoCommit bool) (planNode, *roachpb.Error) { // TODO(marcb): We can't use the cached descriptor here because a recent // update of the schema (e.g. the addition of an index) might not be // reflected in the cached version (yet). Perhaps schema modification // routines such as CREATE INDEX should not return until the schema change // has been pushed everywhere. tableDesc, pErr := p.getTableLease(n.Table) if pErr != nil { return nil, pErr } if err := p.checkPrivilege(&tableDesc, privilege.INSERT); err != nil { return nil, roachpb.NewError(err) } var cols []ColumnDescriptor // Determine which columns we're inserting into. if n.DefaultValues() { cols = tableDesc.Columns } else { var err error if cols, err = p.processColumns(&tableDesc, n.Columns); err != nil { return nil, roachpb.NewError(err) } } // Number of columns expecting an input. This doesn't include the // columns receiving a default value. numInputColumns := len(cols) // Construct a map from column ID to the index the value appears at within a // row. colIDtoRowIndex := map[ColumnID]int{} for i, c := range cols { colIDtoRowIndex[c.ID] = i } // Add the column if it has a DEFAULT expression. addIfDefault := func(col ColumnDescriptor) { if col.DefaultExpr != nil { if _, ok := colIDtoRowIndex[col.ID]; !ok { colIDtoRowIndex[col.ID] = len(cols) cols = append(cols, col) } } } // Add any column that has a DEFAULT expression. for _, col := range tableDesc.Columns { addIfDefault(col) } // Also add any column in a mutation that is WRITE_ONLY and has // a DEFAULT expression. for _, m := range tableDesc.Mutations { if m.State != DescriptorMutation_WRITE_ONLY { continue } if col := m.GetColumn(); col != nil { addIfDefault(*col) } } // Verify we have at least the columns that are part of the primary key. primaryKeyCols := map[ColumnID]struct{}{} for i, id := range tableDesc.PrimaryIndex.ColumnIDs { if _, ok := colIDtoRowIndex[id]; !ok { return nil, roachpb.NewUErrorf("missing %q primary key column", tableDesc.PrimaryIndex.ColumnNames[i]) } primaryKeyCols[id] = struct{}{} } // Construct the default expressions. The returned slice will be nil if no // column in the table has a default expression. defaultExprs, err := p.makeDefaultExprs(cols) if err != nil { return nil, roachpb.NewError(err) } // Replace any DEFAULT markers with the corresponding default expressions. insertRows := p.fillDefaults(defaultExprs, cols, n) // Transform the values into a rows object. This expands SELECT statements or // generates rows from the values contained within the query. rows, pErr := p.makePlan(insertRows, false) if pErr != nil { return nil, pErr } if expressions := len(rows.Columns()); expressions > numInputColumns { return nil, roachpb.NewUErrorf("INSERT has more expressions than target columns: %d/%d", expressions, numInputColumns) } primaryIndex := tableDesc.PrimaryIndex primaryIndexKeyPrefix := MakeIndexKeyPrefix(tableDesc.ID, primaryIndex.ID) marshalled := make([]interface{}, len(cols)) b := p.txn.NewBatch() rh, err := makeReturningHelper(p, n.Returning, tableDesc.Name, cols) if err != nil { return nil, roachpb.NewError(err) } for rows.Next() { rowVals := rows.Values() // The values for the row may be shorter than the number of columns being // inserted into. Generate default values for those columns using the // default expressions. for i := len(rowVals); i < len(cols); i++ { if defaultExprs == nil { rowVals = append(rowVals, parser.DNull) continue } d, err := defaultExprs[i].Eval(p.evalCtx) if err != nil { return nil, roachpb.NewError(err) } rowVals = append(rowVals, d) } // Check to see if NULL is being inserted into any non-nullable column. for _, col := range tableDesc.Columns { if !col.Nullable { if i, ok := colIDtoRowIndex[col.ID]; !ok || rowVals[i] == parser.DNull { return nil, roachpb.NewUErrorf("null value in column %q violates not-null constraint", col.Name) } } } // Check that the row value types match the column types. This needs to // happen before index encoding because certain datum types (i.e. tuple) // cannot be used as index values. for i, val := range rowVals { // Make sure the value can be written to the column before proceeding. var mErr error if marshalled[i], mErr = marshalColumnValue(cols[i], val, p.evalCtx.Args); mErr != nil { return nil, roachpb.NewError(mErr) } } if p.prepareOnly { continue } primaryIndexKey, _, eErr := encodeIndexKey( &primaryIndex, colIDtoRowIndex, rowVals, primaryIndexKeyPrefix) if eErr != nil { return nil, roachpb.NewError(eErr) } // Write the secondary indexes. indexes := tableDesc.Indexes // Also include the secondary indexes in mutation state WRITE_ONLY. for _, m := range tableDesc.Mutations { if m.State == DescriptorMutation_WRITE_ONLY { if index := m.GetIndex(); index != nil { indexes = append(indexes, *index) } } } secondaryIndexEntries, eErr := encodeSecondaryIndexes( tableDesc.ID, indexes, colIDtoRowIndex, rowVals) if eErr != nil { return nil, roachpb.NewError(eErr) } for _, secondaryIndexEntry := range secondaryIndexEntries { if log.V(2) { log.Infof("CPut %s -> %v", secondaryIndexEntry.key, secondaryIndexEntry.value) } b.CPut(secondaryIndexEntry.key, secondaryIndexEntry.value, nil) } // Write the row sentinel. sentinelKey := keys.MakeNonColumnKey(primaryIndexKey) if log.V(2) { log.Infof("CPut %s -> NULL", roachpb.Key(sentinelKey)) } // This is subtle: An interface{}(nil) deletes the value, so we pass in // []byte{} as a non-nil value. b.CPut(sentinelKey, []byte{}, nil) // Write the row columns. for i, val := range rowVals { col := cols[i] if _, ok := primaryKeyCols[col.ID]; ok { // Skip primary key columns as their values are encoded in the row // sentinel key which is guaranteed to exist for as long as the row // exists. continue } if marshalled[i] != nil { // We only output non-NULL values. Non-existent column keys are // considered NULL during scanning and the row sentinel ensures we know // the row exists. key := keys.MakeColumnKey(primaryIndexKey, uint32(col.ID)) if log.V(2) { log.Infof("CPut %s -> %v", roachpb.Key(key), val) } b.CPut(key, marshalled[i], nil) } } if err := rh.append(rowVals); err != nil { return nil, roachpb.NewError(err) } } if pErr := rows.PErr(); pErr != nil { return nil, pErr } if p.prepareOnly { // Return the result column types. return rh.getResults(), nil } if isSystemConfigID(tableDesc.GetID()) { // Mark transaction as operating on the system DB. p.txn.SetSystemConfigTrigger() } if autoCommit { // An auto-txn can commit the transaction with the batch. This is an // optimization to avoid an extra round-trip to the transaction // coordinator. pErr = p.txn.CommitInBatch(b) } else { pErr = p.txn.Run(b) } if pErr != nil { return nil, convertBatchError(&tableDesc, *b, pErr) } return rh.getResults(), 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 }