Esempio n. 1
0
/*生成一个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
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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
}
Esempio n. 4
0
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
}
Esempio n. 5
0
/*获得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")
}
Esempio n. 6
0
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
}
Esempio n. 7
0
/*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"))
		}
	}
}
Esempio n. 8
0
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
}
Esempio n. 9
0
/*从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
	}
}