123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- 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 + @") a
- SELECT TOP " + pagesize.ToString() + " " + preOutFieldStr + @" FROM #tmp_sorttable WHERE RowNumber > " +
- (pagesize * (pageindex - 1)).ToString() + @" ORDER BY RowNumber
- DROP 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 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; }
- }
- }
- }
|