func (c *ClientConn) handleSetNames(ch, ci sqlparser.ValExpr) error { var cid mysql.CollationId var ok bool value := sqlparser.String(ch) value = strings.Trim(value, "'`\"") charset := strings.ToLower(value) if charset == "null" { return c.writeOK(nil) } if ci == nil { cid, ok = mysql.CharsetIds[charset] if !ok { return fmt.Errorf("invalid charset %s", charset) } } else { collate := sqlparser.String(ci) collate = strings.Trim(value, "'`\"") cid, ok = mysql.CollationNames[collate] if !ok { return fmt.Errorf("invalid charset %s", charset) } } c.charset = charset c.collation = cid return c.writeOK(nil) }
func (r *Router) buildReplacePlan(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(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 }
func (r *Router) buildDeletePlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where var err error stmt := statement.(*sqlparser.Delete) plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) where = stmt.Where if where != nil { plan.Criteria = where.Expr //路由条件 err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildUpdatePlan", err.Error(), 0) return nil, err } } else { //if shard delete without where,send to all nodes and all tables plan.RouteTableIndexs = plan.Rule.SubTableIndexs plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes)) } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildDeletePlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateDeleteSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (r *Router) buildSelectPlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where var err error var tableName string stmt := statement.(*sqlparser.Select) switch v := (stmt.From[0]).(type) { case *sqlparser.AliasedTableExpr: tableName = sqlparser.String(v.Expr) case *sqlparser.JoinTableExpr: if ate, ok := (v.LeftExpr).(*sqlparser.AliasedTableExpr); ok { tableName = sqlparser.String(ate.Expr) } else { tableName = sqlparser.String(v) } default: tableName = sqlparser.String(v) } plan.Rule = r.GetRule(tableName) //根据表名获得分表规则 where = stmt.Where if where != nil { plan.Criteria = where.Expr //路由条件 err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildSelectPlan", err.Error(), 0) return nil, err } } else { //if shard select without where,send to all nodes and all tables plan.RouteTableIndexs = plan.Rule.SubTableIndexs plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes)) } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildSelectPlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateSelectSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (r *Router) buildInsertPlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} plan.Rows = make(map[int]sqlparser.Values) stmt := statement.(*sqlparser.Insert) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { return nil, errors.ErrSelectInInsert } if stmt.Columns == nil { return nil, errors.ErrIRNoColumns } //根据sql语句的表,获得对应的分片规则 plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) err := plan.GetIRKeyIndex(stmt.Columns) if err != nil { return nil, err } if stmt.OnDup != nil { err := plan.Rule.checkUpdateExprs(sqlparser.UpdateExprs(stmt.OnDup)) if err != nil { return nil, err } } plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildInsertPlan", err.Error(), 0) return nil, err } err = r.generateInsertSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (c *ClientConn) handleUseDB(stmt *sqlparser.UseDB) error { if len(stmt.DB) == 0 { return fmt.Errorf("must have database, not %s", sqlparser.String(stmt)) } if c.schema == nil { return mysql.NewDefaultError(mysql.ER_NO_DB_ERROR) } nodeName := c.schema.rule.DefaultRule.Nodes[0] n := c.proxy.GetNode(nodeName) co, err := n.GetMasterConn() defer c.closeConn(co, false) if err != nil { return err } if err = co.UseDB(string(stmt.DB)); err != nil { return err } c.db = string(stmt.DB) return c.writeOK(nil) }
//rewrite select sql func (r *Router) rewriteSelectSql(plan *Plan, node *sqlparser.Select, tableIndex int) string { buf := sqlparser.NewTrackedBuffer(nil) buf.Fprintf("select %v%s%v", node.Comments, node.Distinct, node.SelectExprs, ) //insert the group columns in the first of select cloumns if len(node.GroupBy) != 0 { prefix := "," for _, n := range node.GroupBy { buf.Fprintf("%s%v", prefix, n) } } buf.Fprintf(" from ") switch v := (node.From[0]).(type) { case *sqlparser.AliasedTableExpr: if len(v.As) != 0 { fmt.Fprintf(buf, "%s_%04d as %s", sqlparser.String(v.Expr), tableIndex, string(v.As), ) } else { fmt.Fprintf(buf, "%s_%04d", sqlparser.String(v.Expr), tableIndex, ) } case *sqlparser.JoinTableExpr: if ate, ok := (v.LeftExpr).(*sqlparser.AliasedTableExpr); ok { if len(ate.As) != 0 { fmt.Fprintf(buf, "%s_%04d as %s", sqlparser.String(ate.Expr), tableIndex, string(ate.As), ) } else { fmt.Fprintf(buf, "%s_%04d", sqlparser.String(ate.Expr), tableIndex, ) } } else { fmt.Fprintf(buf, "%s_%04d", sqlparser.String(v.LeftExpr), tableIndex, ) } buf.Fprintf(" %s %v", v.Join, v.RightExpr) if v.On != nil { buf.Fprintf(" on %v", v.On) } default: fmt.Fprintf(buf, "%s_%04d", sqlparser.String(node.From[0]), tableIndex, ) } //append other tables prefix := ", " for i := 1; i < len(node.From); i++ { buf.Fprintf("%s%v", prefix, node.From[i]) } buf.Fprintf("%v%v%v%v%s", node.Where, node.GroupBy, node.Having, node.OrderBy, node.Lock, ) return buf.String() }