func analyzeInsert(ins *sqlparser.Insert, getTable TableGetter) (plan *ExecPlan, err error) { plan = &ExecPlan{ PlanID: PlanPassDML, FullQuery: GenerateFullQuery(ins), } tableName := sqlparser.GetTableName(ins.Table) if tableName == "" { plan.Reason = ReasonTable return plan, nil } tableInfo, err := plan.setTableInfo(tableName, getTable) if err != nil { return nil, err } if len(tableInfo.Indexes) == 0 || tableInfo.Indexes[0].Name.Lowered() != "primary" { log.Warningf("no primary key for table %s", tableName) plan.Reason = ReasonTableNoIndex return plan, nil } pkColumnNumbers := getInsertPKColumns(ins.Columns, tableInfo) if sel, ok := ins.Rows.(sqlparser.SelectStatement); ok { if ins.OnDup != nil { // Upserts not allowed for subqueries. // http://bugs.mysql.com/bug.php?id=58637 plan.Reason = ReasonUpsert return plan, nil } plan.PlanID = PlanInsertSubquery plan.OuterQuery = GenerateInsertOuterQuery(ins) plan.Subquery = GenerateSelectLimitQuery(sel) if len(ins.Columns) != 0 { for _, col := range ins.Columns { colIndex := tableInfo.FindColumn(col.Original()) if colIndex == -1 { return nil, fmt.Errorf("column %v not found in table %s", col, tableInfo.Name) } plan.ColumnNumbers = append(plan.ColumnNumbers, colIndex) } } else { // Add all columns. for colIndex := range tableInfo.Columns { plan.ColumnNumbers = append(plan.ColumnNumbers, colIndex) } } plan.SubqueryPKColumns = pkColumnNumbers return plan, nil } // If it's not a sqlparser.SelectStatement, it's Values. rowList := ins.Rows.(sqlparser.Values) pkValues, err := getInsertPKValues(pkColumnNumbers, rowList, tableInfo) if err != nil { return nil, err } if pkValues == nil { plan.Reason = ReasonComplexExpr return plan, nil } plan.PKValues = pkValues if ins.OnDup == nil { plan.PlanID = PlanInsertPK plan.OuterQuery = sqlparser.GenerateParsedQuery(ins) return plan, nil } if len(rowList) > 1 { // Upsert supported only for single row inserts. plan.Reason = ReasonUpsert return plan, nil } plan.SecondaryPKValues, err = analyzeUpdateExpressions(sqlparser.UpdateExprs(ins.OnDup), tableInfo.Indexes[0]) if err != nil { plan.Reason = ReasonPKChange return plan, nil } plan.PlanID = PlanUpsertPK newins := *ins newins.Ignore = "" newins.OnDup = nil plan.OuterQuery = sqlparser.GenerateParsedQuery(&newins) upd := &sqlparser.Update{ Comments: ins.Comments, Table: ins.Table, Exprs: sqlparser.UpdateExprs(ins.OnDup), } plan.UpsertQuery = GenerateUpdateOuterQuery(upd) return plan, nil }
func analyzeInsert(ins *sqlparser.Insert, getTable TableGetter) (plan *ExecPlan, err error) { plan = &ExecPlan{ PlanID: PlanPassDML, FullQuery: GenerateFullQuery(ins), } tableName := sqlparser.GetTableName(ins.Table) if tableName == "" { plan.Reason = ReasonTable return plan, nil } tableInfo, err := plan.setTableInfo(tableName, getTable) if err != nil { return nil, err } if len(tableInfo.Indexes) == 0 || tableInfo.Indexes[0].Name != "PRIMARY" { log.Warningf("no primary key for table %s", tableName) plan.Reason = ReasonTableNoIndex return plan, nil } pkColumnNumbers := getInsertPKColumns(ins.Columns, tableInfo) if sel, ok := ins.Rows.(sqlparser.SelectStatement); ok { if ins.OnDup != nil { // Upserts not allowed for subqueries. // http://bugs.mysql.com/bug.php?id=58637 plan.Reason = ReasonUpsert return plan, nil } plan.PlanID = PlanInsertSubquery plan.OuterQuery = GenerateInsertOuterQuery(ins) plan.Subquery = GenerateSelectLimitQuery(sqlparser.ForUpdate(sel)) if len(ins.Columns) != 0 { plan.ColumnNumbers, err = analyzeSelectExprs(sqlparser.SelectExprs(ins.Columns), tableInfo) if err != nil { return nil, err } } else { // StarExpr node will expand into all columns n := sqlparser.SelectExprs{&sqlparser.StarExpr{}} plan.ColumnNumbers, err = analyzeSelectExprs(n, tableInfo) if err != nil { return nil, err } } plan.SubqueryPKColumns = pkColumnNumbers return plan, nil } // If it's not a sqlparser.SelectStatement, it's Values. rowList := ins.Rows.(sqlparser.Values) pkValues, err := getInsertPKValues(pkColumnNumbers, rowList, tableInfo) if err != nil { return nil, err } if pkValues == nil { plan.Reason = ReasonComplexExpr return plan, nil } plan.PKValues = pkValues if ins.OnDup == nil { plan.PlanID = PlanInsertPK plan.OuterQuery = sqlparser.GenerateParsedQuery(ins) return plan, nil } if len(rowList) > 1 { // Upsert supported only for single row inserts. plan.Reason = ReasonUpsert return plan, nil } plan.SecondaryPKValues, err = analyzeUpdateExpressions(sqlparser.UpdateExprs(ins.OnDup), tableInfo.Indexes[0]) if err != nil { if err == ErrTooComplex { plan.Reason = ReasonPKChange return plan, nil } return nil, err } plan.PlanID = PlanUpsertPK newins := *ins newins.Ignore = "" newins.OnDup = nil plan.OuterQuery = sqlparser.GenerateParsedQuery(&newins) upd := &sqlparser.Update{ Comments: ins.Comments, Table: ins.Table, Exprs: sqlparser.UpdateExprs(ins.OnDup), } plan.UpsertQuery = GenerateUpdateOuterQuery(upd) return plan, nil }