/*生成一个route plan*/ func (r *Router) GetPlan(statement sqlparser.Statement) (plan *Plan) { plan = &Plan{} var where *sqlparser.Where //因为实现Statement接口的方法都是指针类型,所以type对应类型也是指针类型 switch stmt := statement.(type) { case *sqlparser.Insert: if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in insert not allowed")) } /*根据sql语句的表,获得对应的分片规则*/ plan.rule = r.GetRule(sqlparser.String(stmt.Table)) if stmt.OnDup != nil { plan.rule.checkUpdateExprs(sqlparser.UpdateExprs(stmt.OnDup)) } plan.criteria = plan.routingAnalyzeValues(stmt.Rows.(sqlparser.Values)) plan.fullList = makeList(0, len(plan.rule.Nodes)) return plan case *sqlparser.Replace: if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in replace not allowed")) } plan.rule = r.GetRule(sqlparser.String(stmt.Table)) plan.criteria = plan.routingAnalyzeValues(stmt.Rows.(sqlparser.Values)) plan.fullList = makeList(0, len(plan.rule.Nodes)) return plan case *sqlparser.Select: plan.rule = r.GetRule(sqlparser.String(stmt.From[0])) //根据表名获得分表规则 where = stmt.Where case *sqlparser.Update: plan.rule = r.GetRule(sqlparser.String(stmt.Table)) plan.rule.checkUpdateExprs(stmt.Exprs) where = stmt.Where case *sqlparser.Delete: plan.rule = r.GetRule(sqlparser.String(stmt.Table)) where = stmt.Where } if where != nil { plan.criteria = where.Expr /*路由条件*/ } else { plan.rule = r.DefaultRule } plan.fullList = makeList(0, len(plan.rule.Nodes)) return plan }
func (plan *Plan) checkValuesType(vals sqlparser.Values) sqlparser.Values { // Analyze first value of every item in the list for i := 0; i < len(vals); i++ { switch tuple := vals[i].(type) { case sqlparser.ValTuple: result := plan.getValueType(tuple[0]) if result != VALUE_NODE { panic(sqlparser.NewParserError("insert is too complex")) } default: panic(sqlparser.NewParserError("insert is too complex")) } } return vals }
func (r *Router) buildReplacePlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} stmt := statement.(*sqlparser.Replace) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in replace not allowed")) } plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) err := plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildReplacePlan", err.Error(), 0) return nil, err } err = r.generateReplaceSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (r *Router) buildReplacePlan(db string, statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} plan.Rows = make(map[int]sqlparser.Values) stmt := statement.(*sqlparser.Replace) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in replace not allowed")) } if stmt.Columns == nil { return nil, errors.ErrIRNoColumns } plan.Rule = r.GetRule(db, sqlparser.String(stmt.Table)) err := plan.GetIRKeyIndex(stmt.Columns) if err != nil { return nil, err } plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildReplacePlan", err.Error(), 0) return nil, err } err = r.generateReplaceSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
/*获得valExpr对应的值*/ func (plan *Plan) getBoundValue(valExpr sqlparser.ValExpr) interface{} { switch node := valExpr.(type) { case sqlparser.ValTuple: //ValTuple可以是一个slice if len(node) != 1 { panic(sqlparser.NewParserError("tuples not allowed as insert values")) } // TODO: Change parser to create single value tuples into non-tuples. return plan.getBoundValue(node[0]) case sqlparser.StrVal: return string(node) case sqlparser.NumVal: val, err := strconv.ParseInt(string(node), 10, 64) if err != nil { panic(sqlparser.NewParserError("%s", err.Error())) } return val case sqlparser.ValArg: panic("Unexpected token") } panic("Unexpected token") }
func (plan *Plan) getInsertTableIndex(vals sqlparser.Values) int { index := -1 for i := 0; i < len(vals); i++ { first_value_expression := vals[i].(sqlparser.ValTuple)[0] newIndex := plan.getTableIndexByValue(first_value_expression) if index == -1 { index = newIndex } else if index != newIndex { panic(sqlparser.NewParserError("insert or replace has multiple shard targets")) } } return index }
/*UpdateExprs对应set后面的表达式*/ func (r *Rule) checkUpdateExprs(exprs sqlparser.UpdateExprs) { if r.Type == DefaultRuleType { return } else if len(r.Nodes) == 1 { return } for _, e := range exprs { if string(e.Name.Name) == r.Key { panic(sqlparser.NewParserError("routing key can not in update expression")) } } }
func (plan *Plan) adjustShardIndex(valExpr sqlparser.ValExpr, index int) int { value := plan.getBoundValue(valExpr) //生成一个范围的接口,[100,120) s, ok := plan.Rule.Shard.(RangeShard) if !ok { return index } //value是否和shard[index].Start相等 if s.EqualStart(value, index) { index-- if index < 0 { panic(sqlparser.NewParserError("invalid range sharding")) } } return index }
/*从plan中得到shard list*/ func (plan *Plan) shardListFromPlan() (shardList []int) { if plan.criteria == nil { //如果没有分表条件,则是全表扫描 return plan.fullList } //default rule will route all sql to one node //if rule has one node, we also can route directly if plan.rule.Type == DefaultRuleType || len(plan.rule.Nodes) == 1 { if len(plan.fullList) != 1 { panic(sqlparser.NewParserError("invalid rule nodes num %d, must 1", plan.fullList)) } return plan.fullList } switch criteria := plan.criteria.(type) { case sqlparser.Values: //代表insert中values index := plan.findInsertShard(criteria) return []int{index} case sqlparser.BoolExpr: return plan.routingAnalyzeBoolean(criteria) default: return plan.fullList } }