Пример #1
0
            public static void RouteForTableMeta(RouteResultset rrs,
                                                 SchemaConfig schema,
                                                 ISqlStatement ast,
                                                 PartitionKeyVisitor visitor,
                                                 string stmt)
            {
                var sql = stmt;

                if (visitor.IsSchemaTrimmed())
                {
                    sql = GenSql(ast, stmt);
                }

                var tables = visitor.GetMetaReadTable();

                if (tables == null)
                {
                    throw new ArgumentException(string.Format("route err: tables[] is null for meta read table: {0}",
                                                              stmt));
                }

                string[] dataNodes;
                if (tables.Length <= 0)
                {
                    dataNodes = schema.MetaDataNodes;
                }
                else
                {
                    if (tables.Length == 1)
                    {
                        dataNodes    = new string[1];
                        dataNodes[0] = GetMetaReadDataNode(schema, tables[0]);
                    }
                    else
                    {
                        ICollection <string> dataNodeSet = new HashSet <string>();
                        foreach (var table in tables)
                        {
                            var dataNode = GetMetaReadDataNode(schema, table);
                            dataNodeSet.Add(dataNode);
                        }
                        dataNodes = dataNodeSet.ToArray();
                        //dataNodes = new string[dataNodeSet.Count];
                        //IEnumerator<string> iter = dataNodeSet.GetEnumerator();
                        //for (int i = 0; i < dataNodes.Length; ++i)
                        //{
                        //    dataNodes[i] = iter.Current;
                        //}
                    }
                }

                var nodes = new RouteResultsetNode[dataNodes.Length];

                rrs.Nodes = nodes;
                for (var i1 = 0; i1 < dataNodes.Length; ++i1)
                {
                    nodes[i1] = new RouteResultsetNode(dataNodes[i1], sql);
                }
            }
Пример #2
0
 /// <exception cref="System.Exception" />
 public override void Route(SchemaConfig schema, int loop, string sql)
 {
     for (var i = 0; i < loop; ++i)
     {
         var lexer   = new MySqlLexer(sql);
         var select  = new MySqlDmlSelectParser(lexer, new MySqlExprParser(lexer)).Select();
         var visitor = new PartitionKeyVisitor(schema.Tables);
         select.Accept(visitor);
     }
 }
Пример #3
0
        /// <summary>
        /// </summary>
        /// <param name="ast"></param>
        /// <param name="tc"></param>
        /// <param name="rule"></param>
        /// <param name="visitor"></param>
        private static void ValidateAst(ISqlStatement ast,
                                        TableConfig tc,
                                        RuleConfig rule,
                                        PartitionKeyVisitor visitor)
        {
            if (!(ast is DmlUpdateStatement))
            {
                return;
            }

            IList <Identifier> columns = null;
            var ruleCols = rule.Columns;
            var update   = (DmlUpdateStatement)ast;

            foreach (var pair in update.Values)
            {
                foreach (var ruleCol in ruleCols)
                {
                    if (pair.Key.IdTextUpUnescape == ruleCol)
                    {
                        if (columns == null)
                        {
                            columns = new List <Identifier>(ruleCols.Count);
                        }
                        columns.Add(pair.Key);
                    }
                }
            }

            if (columns == null)
            {
                return;
            }

            var alias = visitor.GetTableAlias();

            foreach (var column in columns)
            {
                var table = column.GetLevelUnescapeUpName(2);
                table = alias.GetValue(table);
                if (table != null && table.Equals(tc.Name))
                {
                    throw new NotSupportedException("partition key cannot be changed");
                }
            }
        }
Пример #4
0
        // [perf tag] 22.0965 us: sharding multivalue
        private static void ReplacePartitionKeyOperand(IDictionary <string, ColumnValueType> index, IList <string> cols)
        {
            if (cols == null)
            {
                return;
            }

            foreach (var col in cols)
            {
                var map = index.GetValue(col);
                if (map == null)
                {
                    continue;
                }

                foreach (var set in map.Values)
                {
                    if (set == null)
                    {
                        continue;
                    }

                    foreach (var p in set)
                    {
                        var expr   = p.Key;
                        var parent = p.Value;
                        if (PartitionKeyVisitor.IsPartitionKeyOperandSingle(expr, parent))
                        {
                            ((IReplacableExpression)expr).ReplaceExpr = ReplacableExpressionConstants.BoolFalse;
                        }
                        else if (PartitionKeyVisitor.IsPartitionKeyOperandIn(expr, parent))
                        {
                            ((IReplacableExpression)parent).ReplaceExpr = ReplacableExpressionConstants.BoolFalse;
                        }
                    }
                }
            }
        }
Пример #5
0
        private static void SetGroupFlagAndLimit(RouteResultset rrs, PartitionKeyVisitor visitor)
        {
            rrs.LimitSize = visitor.GetLimitSize();
            switch (visitor.GetGroupFuncType())
            {
            case PartitionKeyVisitor.GroupSum:
            {
                rrs.Flag = RouteResultset.SumFlag;
                break;
            }

            case PartitionKeyVisitor.GroupMax:
            {
                rrs.Flag = RouteResultset.MaxFlag;
                break;
            }

            case PartitionKeyVisitor.GroupMin:
            {
                rrs.Flag = RouteResultset.MinFlag;
                break;
            }
            }
        }
Пример #6
0
        private static void DispatchInsertReplace(RouteResultsetNode[] rn,
                                                  DmlInsertReplaceStatement stmt,
                                                  IList <string> ruleColumns,
                                                  IDictionary <int, IList <object[]> > dataNodeMap,
                                                  TableConfig matchedTable,
                                                  string originalSql,
                                                  PartitionKeyVisitor visitor)
        {
            if (stmt.Select != null)
            {
                DispatchWhereBasedStmt(rn, stmt, ruleColumns, dataNodeMap, matchedTable, originalSql, visitor);
                return;
            }

            var colsIndex = visitor.GetColumnIndex(stmt.Table.IdTextUpUnescape);

            if (colsIndex == null || colsIndex.IsEmpty())
            {
                throw new ArgumentException("columns index is empty: " + originalSql);
            }

            var colsIndexList = new List <ColumnValueType>(ruleColumns.Count);

            for (int i = 0, len = ruleColumns.Count; i < len; ++i)
            {
                colsIndexList.Add(colsIndex[ruleColumns[i]]);
            }

            var dataNodeId = -1;

            foreach (var en in dataNodeMap)
            {
                var tuples         = en.Value;
                var replaceRowList = new HashSet <RowExpression>();
                foreach (var tuple in tuples)
                {
                    ICollection <Pair <IExpression, IAstNode> > tupleExprs = null;
                    for (var i1 = 0; i1 < tuple.Length; ++i1)
                    {
                        var valueMap = colsIndexList[i1];
                        var value    = tuple[i1];
                        var set      = GetExpressionSet(valueMap, value);
                        tupleExprs = CollectionUtil.IntersectSet(tupleExprs, set);
                    }

                    if (tupleExprs == null || tupleExprs.IsEmpty())
                    {
                        throw new ArgumentException(
                                  string.Format("route: empty expression list for insertReplace stmt: {0}", originalSql));
                    }

                    foreach (var p in tupleExprs)
                    {
                        if (p.Value == stmt && p.Key is RowExpression)
                        {
                            replaceRowList.Add((RowExpression)p.Key);
                        }
                    }
                }

                stmt.ReplaceRowList = new List <RowExpression>(replaceRowList);
                var sql = GenSql(stmt, originalSql);
                stmt.ClearReplaceRowList();

                var dataNodeName = matchedTable.DataNodes[en.Key];
                rn[++dataNodeId] = new RouteResultsetNode(dataNodeName, sql);
            }
        }
Пример #7
0
        //private static readonly Logger Logger = Logger.GetLogger(typeof(ServerRouter));

        public static RouteResultset Route(SchemaConfig schema,
                                           string stmt,
                                           string charset,
                                           object info)
        {
            var rrs = new RouteResultset(stmt);
            // 检查是否含有cobar hint
            var prefixIndex = HintRouter.IndexOfPrefix(stmt);

            if (prefixIndex >= 0)
            {
                HintRouter.RouteFromHint(info, schema, rrs, prefixIndex, stmt);
                return(rrs);
            }

            // 检查schema是否含有拆分库
            if (schema.IsNoSharding)
            {
                if (schema.IsKeepSqlSchema)
                {
                    var ast     = SqlParserDelegate.Parse(stmt, charset ?? MySqlParser.DefaultCharset);
                    var visitor = new PartitionKeyVisitor(schema.Tables);
                    visitor.SetTrimSchema(schema.Name);
                    ast.Accept(visitor);
                    if (visitor.IsSchemaTrimmed())
                    {
                        stmt = GenSql(ast, stmt);
                    }
                }
                var nodes = new RouteResultsetNode[1];
                nodes[0]  = new RouteResultsetNode(schema.DataNode, stmt);
                rrs.Nodes = nodes;
                return(rrs);
            }

            // 生成和展开AST
            var ast1     = SqlParserDelegate.Parse(stmt, charset ?? MySqlParser.DefaultCharset);
            var visitor1 = new PartitionKeyVisitor(schema.Tables);

            visitor1.SetTrimSchema(schema.IsKeepSqlSchema ? schema.Name : null);
            ast1.Accept(visitor1);
            // 如果sql包含用户自定义的schema,则路由到default节点
            if (schema.IsKeepSqlSchema && visitor1.IsCustomedSchema())
            {
                if (visitor1.IsSchemaTrimmed())
                {
                    stmt = GenSql(ast1, stmt);
                }
                var nodes = new RouteResultsetNode[1];
                nodes[0]  = new RouteResultsetNode(schema.DataNode, stmt);
                rrs.Nodes = nodes;
                return(rrs);
            }

            // 元数据语句路由
            if (visitor1.IsTableMetaRead())
            {
                MetaRouter.RouteForTableMeta(rrs, schema, ast1, visitor1, stmt);
                if (visitor1.IsNeedRewriteField())
                {
                    rrs.Flag = RouteResultset.RewriteField;
                }
                return(rrs);
            }

            // 匹配规则
            TableConfig matchedTable = null;
            RuleConfig  rule         = null;
            IDictionary <string, IList <object> > columnValues = null;
            var astExt = visitor1.GetColumnValue();
            var tables = schema.Tables;

            foreach (var e in astExt)
            {
                var col2Val = e.Value;
                var tc      = tables.GetValue(e.Key);
                if (tc == null)
                {
                    continue;
                }
                if (matchedTable == null)
                {
                    matchedTable = tc;
                }
                if (col2Val == null || col2Val.IsEmpty())
                {
                    continue;
                }
                var tr = tc.Rule;
                if (tr != null)
                {
                    foreach (var rc in tr.Rules)
                    {
                        var match = true;
                        foreach (var ruleColumn in rc.Columns)
                        {
                            match &= col2Val.ContainsKey(ruleColumn);
                        }

                        if (match)
                        {
                            columnValues = col2Val;
                            rule         = rc;
                            matchedTable = tc;
                            goto ft_break;
                        }
                    }
                }
            }
ft_break:
            ;

            // 规则匹配处理,表级别和列级别。
            if (matchedTable == null)
            {
                var sql = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt;
                var rn  = new RouteResultsetNode[1];
                if (string.Empty.Equals(schema.DataNode) && IsSystemReadSql(ast1))
                {
                    rn[0] = new RouteResultsetNode(schema.RandomDataNode, sql);
                }
                else
                {
                    rn[0] = new RouteResultsetNode(schema.DataNode, sql);
                }
                rrs.Nodes = rn;
                return(rrs);
            }
            if (rule == null)
            {
                if (matchedTable.IsRuleRequired)
                {
                    throw new ArgumentException(string.Format("route rule for table {0} is required: {1}",
                                                              matchedTable.Name, stmt));
                }
                var dataNodes = matchedTable.DataNodes;
                var sql       = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt;
                var rn        = new RouteResultsetNode[dataNodes.Length];
                for (var i = 0; i < dataNodes.Length; ++i)
                {
                    rn[i] = new RouteResultsetNode(dataNodes[i], sql);
                }
                rrs.Nodes = rn;
                SetGroupFlagAndLimit(rrs, visitor1);
                return(rrs);
            }

            // 规则计算
            ValidateAst(ast1, matchedTable, rule, visitor1);
            var dnMap = RuleCalculate(matchedTable, rule, columnValues);

            if (dnMap == null || dnMap.IsEmpty())
            {
                throw new ArgumentException("No target dataNode for rule " + rule);
            }

            // 判断路由结果是单库还是多库
            if (dnMap.Count == 1)
            {
                var dataNode = matchedTable.DataNodes[dnMap.Keys.FirstOrDefault()];
                //string dataNode = matchedTable.GetDataNodes()[dnMap.Keys.GetEnumerator().Current];
                var sql = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt;
                var rn  = new RouteResultsetNode[1];
                rn[0]     = new RouteResultsetNode(dataNode, sql);
                rrs.Nodes = rn;
            }
            else
            {
                var rn = new RouteResultsetNode[dnMap.Count];
                if (ast1 is DmlInsertReplaceStatement)
                {
                    var ir = (DmlInsertReplaceStatement)ast1;
                    DispatchInsertReplace(rn, ir, rule.Columns, dnMap, matchedTable, stmt, visitor1);
                }
                else
                {
                    DispatchWhereBasedStmt(rn, ast1, rule.Columns, dnMap, matchedTable, stmt, visitor1);
                }
                rrs.Nodes = rn;
                SetGroupFlagAndLimit(rrs, visitor1);
            }
            return(rrs);
        }
Пример #8
0
        private static void DispatchWhereBasedStmt(RouteResultsetNode[] rn,
                                                   ISqlStatement stmtAST,
                                                   IList <string> ruleColumns,
                                                   IDictionary <int, IList <object[]> > dataNodeMap,
                                                   TableConfig matchedTable,
                                                   string originalSQL,
                                                   PartitionKeyVisitor visitor)
        {
            // [perf tag] 11.617 us: sharding multivalue
            if (ruleColumns.Count > 1)
            {
                string sql;
                if (visitor.IsSchemaTrimmed())
                {
                    sql = GenSql(stmtAST, originalSQL);
                }
                else
                {
                    sql = originalSQL;
                }

                var i = -1;
                foreach (var dataNodeId in dataNodeMap.Keys)
                {
                    var dataNode = matchedTable.DataNodes[dataNodeId];
                    rn[++i] = new RouteResultsetNode(dataNode, sql);
                }
                return;
            }

            var table       = matchedTable.Name;
            var columnIndex = visitor.GetColumnIndex(table);
            var valueMap    = columnIndex.GetValue(ruleColumns[0]);

            ReplacePartitionKeyOperand(columnIndex, ruleColumns);
            var unreplacedInExpr      = new Dictionary <InExpression, ICollection <IExpression> >(1);
            var unreplacedSingleExprs = new HashSet <IReplacableExpression>();
            // [perf tag] 12.2755 us: sharding multivalue
            var nodeId = -1;

            foreach (var en in dataNodeMap)
            {
                var tuples = en.Value;
                unreplacedSingleExprs.Clear();
                unreplacedInExpr.Clear();

                foreach (var tuple in tuples)
                {
                    var value = tuple[0];
                    var indexedExpressionPair = GetExpressionSet(valueMap, value);
                    foreach (var pair in indexedExpressionPair)
                    {
                        var expr   = pair.Key;
                        var parent = (InExpression)pair.Value;
                        if (PartitionKeyVisitor.IsPartitionKeyOperandSingle(expr, parent))
                        {
                            unreplacedSingleExprs.Add((IReplacableExpression)expr);
                        }
                        else if (PartitionKeyVisitor.IsPartitionKeyOperandIn(expr, parent))
                        {
                            var newInSet = unreplacedInExpr.GetValue(parent);
                            if (newInSet == null)
                            {
                                newInSet = new HashSet <IExpression>();
                                unreplacedInExpr[parent] = newInSet;
                            }
                            newInSet.Add(expr);
                        }
                    }
                }
                // [perf tag] 15.3745 us: sharding multivalue
                foreach (var expr1 in unreplacedSingleExprs)
                {
                    expr1.ClearReplaceExpr();
                }

                foreach (var entemp in unreplacedInExpr)
                {
                    var @in = entemp.Key;
                    var set = entemp.Value;
                    if (set == null || set.IsEmpty())
                    {
                        @in.ReplaceExpr = ReplacableExpressionConstants.BoolFalse;
                    }
                    else
                    {
                        @in.ClearReplaceExpr();
                        var inlist = @in.GetInExpressionList();
                        if (inlist != null)
                        {
                            inlist.ReplaceExpr = new List <IExpression>(set);
                        }
                    }
                }

                // [perf tag] 16.506 us: sharding multivalue
                var sql = GenSql(stmtAST, originalSQL);
                // [perf tag] 21.3425 us: sharding multivalue
                var dataNodeName = matchedTable.DataNodes[en.Key];
                rn[++nodeId] = new RouteResultsetNode(dataNodeName, sql);
                foreach (var expr2 in unreplacedSingleExprs)
                {
                    expr2.ReplaceExpr = ReplacableExpressionConstants.BoolFalse;
                }

                foreach (var in1 in unreplacedInExpr.Keys)
                {
                    in1.ReplaceExpr = ReplacableExpressionConstants.BoolFalse;
                    var list = in1.GetInExpressionList();
                    if (list != null)
                    {
                        list.ClearReplaceExpr();
                    }
                }
            }
        }
 /// <exception cref="System.Exception" />
 public override void Route(SchemaConfig schema, int loop, string sql)
 {
     for (var i = 0; i < loop; ++i)
     {
         var lexer = new MySqlLexer(sql);
         var select = new MySqlDmlSelectParser(lexer, new MySqlExprParser(lexer)).Select();
         var visitor = new PartitionKeyVisitor(schema.Tables);
         select.Accept(visitor);
     }
 }