// limit func (p *Plan) rewriteLimit(stmt *sqlparser.Select) (err error) { origin := stmt.Limit // get offset and count if origin == nil { return } var offset, count int64 if origin.Offset == nil { offset = 0 } else { o, ok := origin.Offset.(sqlparser.NumVal) if !ok { err = fmt.Errorf("invalid select limit %s", sqlparser.String(stmt.Limit)) return } if offset, err = strconv.ParseInt(string([]byte(o)), 10, 64); err != nil { return } } o, ok := origin.Rowcount.(sqlparser.NumVal) if !ok { err = fmt.Errorf("invalid limit %s", sqlparser.String(stmt.Limit)) return } if count, err = strconv.ParseInt(string([]byte(o)), 10, 64); err != nil { return } if count < 0 { err = fmt.Errorf("invalid limit %s", sqlparser.String(stmt.Limit)) return } // rewrite limit stmt stmt.Limit.Offset = sqlparser.NumVal([]byte("0")) stmt.Limit.Rowcount = sqlparser.NumVal([]byte(strconv.FormatInt(count+offset, 10))) p.offset = offset p.count = count return }
func (sei *session) buildInsertPlan(stmt *sqlparser.Insert) (*Plan, error) { plan := &Plan{} isNoCol := false isNeedInitCol := true colLen := len(stmt.Columns) // get table table, err := sei.getMeta().GetTable(sei.user, sei.db, string(stmt.Table.Name)) if err != nil { return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, err.Error()) } plan.Table = table if colLen == 0 { isNoCol = true } // get sqls values, ok := stmt.Rows.(sqlparser.Values) if !ok { return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unsupport") } for row, value := range values { tuple, ok := value.(sqlparser.ValTuple) if !ok { return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unsupport") } if (isNoCol && len(tuple) != table.Table.ColsLen) || !isNoCol && len(tuple) != colLen { return nil, mysql.NewDefaultError(mysql.ER_WRONG_VALUE_COUNT_ON_ROW, row+1) } // rewrite auto key if isNoCol { // rewrite by index for _, autokey := range table.Table.AutoKeys { id, err := table.GetKey(autokey.Name, config.Config.Proxy.AutoKeyInterval, sei.server.info) if err != nil { glog.Warningf("Get autokey(%v) get error(%v)", autokey.Name, err) return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, err.Error()) } if autokey.Type == meta.TypeKeyInt { tuple[autokey.Index] = sqlparser.NumVal(id) } else { tuple[autokey.Index] = sqlparser.StrVal(id) } } } else { for _, autokey := range table.Table.AutoKeys { isExist := false id, err := table.GetKey(autokey.Name, config.Config.Proxy.AutoKeyInterval, sei.server.info) if err != nil { glog.Warningf("Get autokey(%v) get error(%v)", autokey.Name, err) return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, err.Error()) } for n, column := range stmt.Columns { col, ok := column.(*sqlparser.NonStarExpr) if !ok { return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unsupport") } colName, ok := col.Expr.(*sqlparser.ColName) if !ok { return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unsupport") } if autokey.Name == string(colName.Name) && n < len(tuple) { isExist = true if autokey.Type == meta.TypeKeyInt { tuple[n] = sqlparser.NumVal(id) } else { tuple[n] = sqlparser.StrVal(id) } } } if !isExist { if isNeedInitCol { stmt.Columns = append(stmt.Columns, &sqlparser.NonStarExpr{ Expr: &sqlparser.ColName{ Name: sqlparser.SQLName(autokey.Name), }, }) } if autokey.Type == meta.TypeKeyInt { tuple = append(tuple, sqlparser.NumVal(id)) } else { tuple = append(tuple, sqlparser.StrVal(id)) } } } } values[row] = tuple isNeedInitCol = false } stmt.Rows = values sqls := make(map[int]sqlparser.InsertRows) // split stmt for row, value := range values { tuple := value.(sqlparser.ValTuple) var value string if isNoCol { // get hash key switch v := tuple[table.Table.PartitionKey.Index].(type) { case sqlparser.NumVal: value = string(v) case sqlparser.StrVal: value = string(v) default: return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unknow partition key type") } } else { for col, column := range stmt.Columns { name := string(column.(*sqlparser.NonStarExpr).Expr.(*sqlparser.ColName).Name) if name == table.Table.PartitionKey.Name { switch v := tuple[col].(type) { case sqlparser.NumVal: value = string(v) case sqlparser.StrVal: value = string(v) default: return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unknow partition key type") } } } } if value == "" { glog.Warning("Get partition key error value is null") return nil, mysql.NewError(mysql.ER_UNKNOWN_ERROR, "unknow partition key type") } index := FindForKey(value, len(table.Backends)) s, ok := sqls[index] if !ok { sqls[index] = sqlparser.Values{values[row]} } else { sqls[index] = append(s.(sqlparser.Values), values[row]) } } var lastIDs []uint64 if len(table.Table.AutoIns) > 0 { index := 0 if isNoCol { // range column index = table.Table.AutoIns[0].Index } else { // get index index = sort.Search(len(stmt.Columns), func(i int) bool { return string(stmt.Columns[i].(*sqlparser.NonStarExpr).Expr.(*sqlparser.ColName).Name) == table.Table.AutoIns[0].Name }) } lastIDs = make([]uint64, len(sqls)) n := 0 for _, sql := range sqls { switch v := sql.(sqlparser.Values)[0].(sqlparser.ValTuple)[index].(type) { case sqlparser.NumVal: glog.Info(n, len(lastIDs)) lastIDs[n], _ = strconv.ParseUint(string(v), 10, 64) case sqlparser.StrVal: lastIDs[n], _ = strconv.ParseUint(string(v), 10, 64) } n++ } } for k, v := range sqls { stmt.Rows = v plan.generateOneSQL(stmt, k) } return plan, nil }