| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 | using LJLib.Method;using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;using System.Text.RegularExpressions;namespace LJLib.DAL.SQL{    internal static class SqlStrHelper    {        /// <summary>        /// 从查询语句中分离出字段部分与表部分        /// </summary>        /// <param name="selectstr">查询语句ie:select...from...</param>        /// <returns>两项分别是字段部分、表部分</returns>        private static string[] SpliteSelectStr(string selectstr)        {            Regex regex = new Regex(@"\bselect\s+(distinct\s+)?(.+?)\s+from\s+(.*)", RegexOptions.IgnoreCase | RegexOptions.Singleline);            Match match = regex.Match(selectstr);            string outCmdStr = string.Empty;            if (match.Success)            {                return new[] {match.Groups[2].Value.Trim(), match.Groups[3].Value.Trim(), match.Groups[1].Value.Trim()};            }            else            {                throw new Exception("selectstr分析失败,ie:select...from...");            }        }        /// <summary>        /// 分析字段部分        /// </summary>        /// <param name="orgFieldStr">字段部分</param>        /// <param name="orgFields">字段名对字段表达式</param>        /// <param name="orgOrderFields">字段名对排序表达式</param>        private static void AnalyseFields(string orgFieldStr, Dictionary<string, string> orgFields, Dictionary<string, string> orgOrderFields)        {            string[] selectFieldArr = SplitFields(orgFieldStr);            string[] pattens = new string[] { @"^\s*(?<sort>(?<key>\w+))\s*=.+$", @"^.+\s+as\s+(?<sort>(?<key>\w+))\s*$", @"^.+\s+(?<sort>(?<key>\w+))\s*$", @"^(?<sort>.*\.\s*(?<key>\w+)\s*)$", @"^\s*(?<sort>(?<key>\w+))\s*$" };            foreach (string orgField in selectFieldArr)            {                var find = false;                foreach (string patten in pattens)                {                    Match fiMatch = Regex.Match(orgField, patten, RegexOptions.IgnoreCase | RegexOptions.Singleline);                    if (fiMatch.Success)                    {                        find = true;                        string key = fiMatch.Groups["key"].Value.Trim().ToLower();                        if (orgFields.ContainsKey(key))                        {                            throw new Exception(string.Format("查询字段名重复:[{0}] = [{1}]", orgFields[key], orgField));                        }                        orgFields[key] = fiMatch.Value.Trim();                        orgOrderFields[key] = fiMatch.Groups["sort"].Value.Trim();                        break;                    }                }                if (!find)                {                    throw  new Exception(string.Format("字段表达式分析失败:{0}", orgField));                }            }        }        /// <summary>        /// 将字段部分拆分        /// </summary>        /// <param name="orgFieldStr">字段部分</param>        /// <returns>各字段</returns>        private static string[] SplitFields(string orgFieldStr)        {            List<string> rslt = new List<string>();            string builder = string.Empty;            Stack<char> states = new Stack<char>();            for (int i = 0; i < orgFieldStr.Length; i++)            {                char cur = orgFieldStr[i];                if (states.Count == 0)                {                    if (cur == ',')                    {                        rslt.Add(builder);                        builder = string.Empty;                    }                    else                    {                        builder += cur;                        if (cur == '(' || cur == '\'')                        {                            states.Push(cur);                        }                    }                }                else                {                    builder += cur;                    char curstate = states.Peek();                    if (curstate == '\'')                    {                        if (cur == '\'')                        {                            states.Pop();                        }                    }                    else                    {                        if (cur == '(' || cur == '\'')                        {                            states.Push(cur);                        }                        else if (cur == ')')                        {                            states.Pop();                        }                    }                }            }            rslt.Add(builder.Trim());            return rslt.ToArray();        }        /// <summary>        /// 生成新的字段语句        /// </summary>        /// <param name="orgFields">字段名-字段表达式</param>        /// <param name="preOutFieldStr">输出字段名ie:mtrlid,mtrlname,如果与原始字段完全不匹配就输出全部字段,最终会变成与输出字段一至</param>        /// <returns>新的字段语句</returns>        private static string BuildSelectFields(Dictionary<string, string> orgFields, ref string preOutFieldStr, string orderFieldStr = null)        {            string outFieldStr = string.Empty;            Dictionary<string, string> outFields = new Dictionary<string, string>();            if (!string.IsNullOrEmpty(preOutFieldStr))            {                string[] fields = preOutFieldStr.Split(',');                foreach (string field in fields)                {                    string key = field.Trim().ToLower();                    if (orgFields.ContainsKey(key) && !outFields.ContainsKey(key))                    {                        outFields[key] = orgFields[key];                    }                }            }            if (!string.IsNullOrEmpty(orderFieldStr))            {                string[] fields = orderFieldStr.Split(',');                foreach (string field in fields)                {                    string key = field.Trim().ToLower();                    if (orgFields.ContainsKey(key) && !outFields.ContainsKey(key))                    {                        outFields[key] = orgFields[key];                    }                }            }            preOutFieldStr = string.Empty;            if (outFields.Count == 0)            {                outFields = orgFields;            }            foreach (KeyValuePair<string, string> kvp in outFields)            {                if (string.IsNullOrEmpty(outFieldStr))                {                    outFieldStr = kvp.Value;                }                else                {                    outFieldStr += "," + kvp.Value;                }                if (string.IsNullOrEmpty(preOutFieldStr))                {                    preOutFieldStr = kvp.Key;                }                else                {                    preOutFieldStr += "," + kvp.Key;                }            }            return outFieldStr;        }        /// <summary>        /// 生成新的排序语名        /// </summary>        /// <param name="orgOrderFields">字段名-字段表达式</param>        /// <param name="preOrderStr">输出字段名ie:mtrlid asc,mtrlname desc</param>        /// <returns>可为空</returns>        private static string BuildOrderFields(Dictionary<string, string> orgOrderFields, string preOrderStr)        {            string outOrderStr = string.Empty;            Dictionary<string, string> outOrderFields = new Dictionary<string, string>();            if (!string.IsNullOrEmpty(preOrderStr))            {                string[] fields = preOrderStr.Split(',');                foreach (string field in fields)                {                    string key = field.Trim().ToLower();                    string[] arr = key.Split(' ');                    if (arr.Length > 1)                    {                        key = arr[0];                        string sort = arr[arr.Length - 1];                        if (orgOrderFields.ContainsKey(key) && !outOrderFields.ContainsKey(key) && (sort == "asc" || sort == "desc"))                        {                            outOrderFields[key] = orgOrderFields[key] + " " + sort;                        }                    }                    else                    {                        if (orgOrderFields.ContainsKey(key) && !outOrderFields.ContainsKey(key))                        {                            outOrderFields[key] = orgOrderFields[key];                        }                    }                }            }            foreach (KeyValuePair<string, string> kvp in outOrderFields)            {                if (string.IsNullOrEmpty(outOrderStr))                {                    outOrderStr = kvp.Value;                }                else                {                    outOrderStr += "," + kvp.Value;                }            }            return outOrderStr;        }        /// <summary>        /// 生成新的查询语句        /// </summary>        /// <param name="orgSelectStr">原始查询语名,select...from...</param>        /// <param name="preOutFieldStr">输出字段</param>        /// <param name="orgWhereStr">条件语句</param>        /// <param name="preOrderStr">排序语句</param>        /// <param name="pageindex">页数</param>        /// <param name="pagesize">每页项数</param>        /// <returns>新的查询语句</returns>        public static string BuildSelectStr(string orgSelectStr, ref string preOutFieldStr, string orgWhereStr,    string preOrderStr, int pageindex, int pagesize)        {            var parts = SpliteSelectStr(orgSelectStr);            var orgFieldStr = parts[0];            var orgFromStr = parts[1];            var distinctStr = parts[2];            Dictionary<string, string> orgFields = new Dictionary<string, string>();            Dictionary<string, string> orgOrderFields = new Dictionary<string, string>();            AnalyseFields(orgFieldStr, orgFields, orgOrderFields);            string outFieldStr = BuildSelectFields(orgFields, ref preOutFieldStr, preOrderStr);            string outOrderStr = BuildOrderFields(orgOrderFields, preOrderStr);            var outCmdStr = outFieldStr + " FROM " + orgFromStr;            if (!string.IsNullOrEmpty(orgWhereStr))            {                outCmdStr += " WHERE " + orgWhereStr;            }            if (!string.IsNullOrEmpty(outOrderStr))            {                outCmdStr += " ORDER BY " + outOrderStr;            }            if (pageindex > 0 && pagesize > 0)            {                outCmdStr = "SELECT " + distinctStr + " TOP " + (pageindex * pagesize).ToString() + " " + outCmdStr;                outCmdStr = "SELECT RowNumber = IDENTITY(INT,1, 1)," + preOutFieldStr + " INTO #tmp_sorttable FROM (" +                            outCmdStr + @") aSELECT TOP " + pagesize.ToString() + " " + preOutFieldStr + @" FROM #tmp_sorttable WHERE RowNumber > " +                            (pagesize * (pageindex - 1)).ToString() + @" ORDER BY RowNumberDROP TABLE #tmp_sorttable";            }            else if (pageindex <= 0 && pagesize > 0)            {                outCmdStr = "SELECT " + distinctStr + " TOP " + pagesize + " " + outCmdStr;            }            else            {                outCmdStr = "SELECT " + distinctStr + " " + outCmdStr;            }            return outCmdStr;        }        public static string BuildSelectStrL1(ParseResult sqlInfo, string preOutFieldStr, string orgWhereStr,    string preOrderStr, int pageindex, int pagesize)        {            var fromStr = sqlInfo.fromStr;            var outCmdStr = string.Format("{0} {1}", string.Join(",", sqlInfo.selectFieldsDic.Values), fromStr);            var whereStr = sqlInfo.whereStr;            if (!string.IsNullOrEmpty(orgWhereStr))            {                if (!string.IsNullOrEmpty(whereStr))                {                    var rawWhereitem = whereStr.Substring(whereStr.IndexOf("WHERE", StringComparison.OrdinalIgnoreCase) + 6);                    whereStr = "WHERE (" + rawWhereitem + ") AND ";                }                else                {                    whereStr = "WHERE ";                }                whereStr += orgWhereStr;            }            outCmdStr += whereStr;            outCmdStr += " " + sqlInfo.groupStr;            outCmdStr += " " + sqlInfo.orderStr;            if (!string.IsNullOrEmpty(preOrderStr))            {                outCmdStr += " ORDER BY " + preOrderStr;            }            if (pageindex > 0 && pagesize > 0)            {                outCmdStr = sqlInfo.selectStr + " TOP " + (pageindex * pagesize).ToString() + " " + outCmdStr;                outCmdStr = "SELECT RowNumber = IDENTITY(INT,1, 1)," + preOutFieldStr + " INTO #tmp_sorttable FROM (" +                            outCmdStr + @") aSELECT TOP " + pagesize.ToString() + " " + preOutFieldStr + @" FROM #tmp_sorttable WHERE RowNumber > " +                            (pagesize * (pageindex - 1)).ToString() + @" ORDER BY RowNumberDROP TABLE #tmp_sorttable";            }            else if (pageindex <= 0 && pagesize > 0)            {                outCmdStr = sqlInfo.selectStr + " TOP " + pagesize + " " + outCmdStr;            }            else            {                outCmdStr = sqlInfo.selectStr + " " + outCmdStr;            }            return outCmdStr;        }        public static string RemoveComment(string source)        {            var sb = new StringBuilder();            using (StringReader reader = new StringReader(source))            {                string line;                while ((line = reader.ReadLine()) != null)                {                    if (line.Contains("--"))                    {                        int commentstart = -1;                        var instr = false;                        for (var i = 0; i < line.Length; i++)                        {                            var curchar = line[i];                            if (curchar == '\'')                            {                                instr = !instr;                            }                            else if (!instr)                            {                                if (curchar == '-')                                {                                    if (i + 1 < line.Length)                                    {                                        if (line[i + 1] == '-')                                        {                                            commentstart = i;                                            break;                                        }                                    }                                }                            }                        }                        if (commentstart >= 0)                        {                            line = line.Substring(0, commentstart);                        }                    }                    sb.AppendLine(line);                }            }            return sb.ToString().TrimEnd('\n').TrimEnd('\r');        }        public static ParseResult ParseSelectStr(string orgSelectStr)        {            var rslt = new ParseResult();            orgSelectStr = RemoveComment(orgSelectStr);            var indexchars = GetIndexChar(orgSelectStr);            var regex = new Regex(@"\bselect\s+(distinct\s+)?(top\b)?", RegexOptions.IgnoreCase | RegexOptions.Singleline);            #region 查找select关键字            var selectMatch = regex.Match(orgSelectStr);            if (!selectMatch.Success)            {                throw new Exception(string.Format("查找select关键字失败,表达式[{0}],请检查:{1}", regex, orgSelectStr));            }            var stateIndex = indexchars.Keys.GetFirstIndexBefore(selectMatch.Index);            if (stateIndex >= 0)            {                throw new Exception(string.Format("第{0}个字符的select关键字前面不允许存在括号或字符串,表达式[{1}],请检查:{2}", selectMatch.Index, regex,                    orgSelectStr));            }            if (!string.IsNullOrEmpty(selectMatch.Groups[2].Value))            {                throw new Exception(string.Format("第{0}位,不应该包含TOP关键字,请使用分页参数,请检查:{1}", selectMatch.Groups[2].Index,                    orgSelectStr));            }            rslt.selectStr = orgSelectStr.Substring(0, selectMatch.Index + selectMatch.Length);            #endregion            regex = new Regex(@"\bfrom\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);            #region 查找from关键字            var match = regex.Match(orgSelectStr);            int fromIndex = -1;            while (match.Success)            {                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')                {                    fromIndex = match.Index;                    break;                }                match = match.NextMatch();            }            if (fromIndex < 0)            {                throw new Exception(string.Format("最外层查找from字句失败,请检查:{0}", orgSelectStr));            }            #endregion            #region 分析返回字段            Dictionary<string, string> orgFields = new Dictionary<string, string>();            Dictionary<string, string> orgOrderFields = new Dictionary<string, string>();            var parts = SpliteSelectStr(orgSelectStr);            var orgFieldStr = parts[0];            AnalyseFields(orgFieldStr, orgFields, orgOrderFields);            rslt.selectFieldsDic = orgFields;            #endregion            regex = new Regex(@"\where\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);            #region 查找where关键字            int whereIndex = -1;            match = regex.Match(orgSelectStr, fromIndex);            while (match.Success)            {                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')                {                    whereIndex = match.Index;                    break;                }                match = match.NextMatch();            }            #endregion            regex = new Regex(@"\bgroup\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);            #region 查找group关键字            int groupIndex = -1;            match = regex.Match(orgSelectStr, fromIndex);            while (match.Success)            {                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')                {                    groupIndex = match.Index;                    break;                }                match = match.NextMatch();            }            #endregion            regex = new Regex(@"\border\b", RegexOptions.IgnoreCase | RegexOptions.Singleline);            #region 查找order关键字            int orderindex = -1;            match = regex.Match(orgSelectStr, fromIndex);            while (match.Success)            {                stateIndex = indexchars.Keys.GetFirstIndexBefore(match.Index);                if (stateIndex < 0 || indexchars.Values[stateIndex] == ' ')                {                    orderindex = match.Index;                    break;                }                match = match.NextMatch();            }            #endregion            rslt.fromStr = string.Empty;            var fromStopIndexs = new List<int> { whereIndex, groupIndex, orderindex }.Where(x => x > 0);            if (fromStopIndexs.Any())            {                rslt.fromStr = orgSelectStr.Substring(fromIndex, fromStopIndexs.Min() - fromIndex);            }            else            {                rslt.fromStr = orgSelectStr.Substring(fromIndex);            }            rslt.whereStr = string.Empty;            if (whereIndex > 0)            {                var whereStopIndexs = new List<int> { groupIndex, orderindex }.Where(x => x > 0);                if (whereStopIndexs.Any())                {                    rslt.whereStr = orgSelectStr.Substring(whereIndex, whereStopIndexs.Min() - whereIndex);                }                else                {                    rslt.whereStr = orgSelectStr.Substring(whereIndex);                }            }            rslt.orderStr = string.Empty;            if (orderindex > 0)            {                rslt.orderStr = orgSelectStr.Substring(orderindex);            }            rslt.groupStr = string.Empty;            if (groupIndex > 0)            {                if (orderindex > 0)                {                    rslt.groupStr = orgSelectStr.Substring(groupIndex, orderindex - groupIndex);                }                else                {                    rslt.groupStr = orgSelectStr.Substring(groupIndex);                }            }            return rslt;        }        /// <summary>        /// 获取SQL中括号与字符串的转换位置        /// </summary>        /// <param name="sqlStr"></param>        /// <returns></returns>        public static SortedList<int, char> GetIndexChar(string sqlStr)        {            var rslt = new SortedList<int, char>();            Stack<char> states = new Stack<char>();            char curstate = ' ';            for (int i = 0; i < sqlStr.Length; i++)            {                char cur = sqlStr[i];                if (curstate == '\'')                {                    if (cur == '\'')                    {                        states.Pop();                        curstate = states.Count > 0 ? states.Peek() : ' ';                        rslt[i] = curstate;                    }                    continue;                }                if (curstate == '(')                {                    if (cur == ')')                    {                        states.Pop();                        curstate = states.Count > 0 ? states.Peek() : ' ';                        rslt[i] = curstate;                        continue;                    }                }                if (curstate == '[')                {                    if (cur == ']')                    {                        states.Pop();                        curstate = states.Count > 0 ? states.Peek() : ' ';                        rslt[i] = curstate;                        continue;                    }                }                if (cur == '(' || cur == '\'' || cur == '[')                {                    states.Push(cur);                    curstate = cur;                    rslt[i] = curstate;                    continue;                }                if (cur == ')')                {                    throw new Exception(string.Format("第{0}位\")\"没有找到对应的\"(\",请检查:{1}", i, sqlStr));                }                if (cur == ']')                {                    throw new Exception(string.Format("第{0}位\"]\"没有找到对应的\"[\",请检查:{1}", i, sqlStr));                }            }            if (states.Count > 0)            {                throw new Exception(string.Format("第{0}位\"{1}\"没有找到对应的结束符,请检查:{2}", rslt.Keys[rslt.Count - 1], rslt.Values[rslt.Count - 1], sqlStr));            }            return rslt;        }        public class ParseResult        {            public string selectStr { get; set; }            //public List<string> selectFields { get; set; }            //public List<string> selectTitles { get; set; }            public Dictionary<string, string> selectFieldsDic { get; set; }            public string fromStr { get; set; }            public string whereStr { get; set; }            public string groupStr { get; set; }            public string orderStr { get; set; }        }    }}
 |