464 lines
18 KiB
C#
464 lines
18 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace AIMSObjectQuery
|
||
{
|
||
internal class SyntaxAnalyzer
|
||
{
|
||
/// <summary>
|
||
/// 由对象查询语句解析为Sql语句
|
||
/// </summary>
|
||
/// <param name="oql"></param>
|
||
/// <param name="sql"></param>
|
||
/// <param name="parameters"></param>
|
||
public static string ParseSql(string oql,IMap map)
|
||
{
|
||
if(oql==string.Empty)
|
||
return string.Empty;
|
||
SyntaxNode syntaxNode=new SyntaxNode();
|
||
syntaxNode.Sentence = oql;
|
||
if (syntaxNode.Map == null)
|
||
syntaxNode.Map = map;
|
||
string sql = syntaxNode.GetSql();
|
||
return sql;
|
||
}
|
||
}
|
||
class SyntaxNode
|
||
{
|
||
private static List<string> keywords=new List<string>();
|
||
private static List<string> funKeywords = new List<string>();
|
||
/// <summary>
|
||
/// 关键字列表
|
||
/// </summary>
|
||
static SyntaxNode()
|
||
{
|
||
keywords.Add("in");
|
||
keywords.Add("and");
|
||
keywords.Add("or");
|
||
keywords.Add("like");
|
||
keywords.Add("not");
|
||
keywords.Add("between");
|
||
keywords.Add("to");
|
||
keywords.Add("as");
|
||
keywords.Add("is");
|
||
keywords.Add("null");
|
||
keywords.Add("tinyint");
|
||
keywords.Add("smallint");
|
||
keywords.Add("int");
|
||
keywords.Add("bigint");
|
||
keywords.Add("decimal");
|
||
keywords.Add("numeric");
|
||
keywords.Add("smallmoney");
|
||
keywords.Add("money");
|
||
keywords.Add("float");
|
||
keywords.Add("real");
|
||
keywords.Add("char");
|
||
keywords.Add("text");
|
||
keywords.Add("varchar");
|
||
keywords.Add("nchar");
|
||
keywords.Add("ntext");
|
||
keywords.Add("nvarchar");
|
||
keywords.Add("desc");
|
||
keywords.Add("asc");
|
||
funKeywords.Add("dateadd");
|
||
funKeywords.Add("datediff");
|
||
funKeywords.Add("datename");
|
||
funKeywords.Add("datepart");
|
||
}
|
||
private IMap map;
|
||
/// <summary>
|
||
/// 属性和字段间的映射
|
||
/// </summary>
|
||
public IMap Map
|
||
{
|
||
get { return map; }
|
||
set { map = value; }
|
||
}
|
||
private string sentence;
|
||
public string Sentence
|
||
{
|
||
get { return sentence; }
|
||
set
|
||
{
|
||
sentence = value;
|
||
if (this.sentenceType == SentenceType.Segment || this.sentenceType == SentenceType.InBracket)
|
||
Parse();
|
||
}
|
||
}
|
||
private SentenceType sentenceType=SentenceType.Segment;
|
||
/// <summary>
|
||
/// 语句类型
|
||
/// </summary>
|
||
public SentenceType SentenceType
|
||
{
|
||
get { return sentenceType; }
|
||
set
|
||
{
|
||
sentenceType = value;
|
||
}
|
||
}
|
||
private SyntaxNode parentNode;
|
||
/// <summary>
|
||
/// 父节点
|
||
/// </summary>
|
||
public SyntaxNode ParentNode
|
||
{
|
||
get { return parentNode; }
|
||
set { parentNode = value; }
|
||
}
|
||
|
||
private List<SyntaxNode> nodes=new List<SyntaxNode>();
|
||
/// <summary>
|
||
/// 子节点集合
|
||
/// </summary>
|
||
public List<SyntaxNode> Nodes
|
||
{
|
||
get { return nodes; }
|
||
set { nodes = value; }
|
||
}
|
||
/// <summary>
|
||
/// 在碰到“(”后,取出与之对应的“)”之间的内容
|
||
/// </summary>
|
||
/// <param name="charArray">字符数组</param>
|
||
/// <param name="index">当前字符位置</param>
|
||
private void ParseInBracket(ref Char[] charArray, ref int index)
|
||
{
|
||
int bracketDepth=1;//括号深度,“(”加1,“)”减1
|
||
bool inQuotation = false;//是否在引号内
|
||
string inBracketString=string.Empty;
|
||
index++;
|
||
//遍历当前字符串到倒数第二个字符
|
||
for (; index < charArray.Length - 1; index++)
|
||
{
|
||
char c = charArray[index];
|
||
if (inQuotation) //如果在引号内,后面有两个连续的“'”则当成普通字符,一个“'”则结束字符串
|
||
{
|
||
if (c == '\'') //出现一个引号后再出现了另一个引号
|
||
{
|
||
if (charArray[index + 1] == '\'')//如果“'”后面的还是“'”,SQL解析为一个“'”
|
||
{
|
||
inBracketString += "''";
|
||
index++; //跳过第二个“'”
|
||
}
|
||
else
|
||
{
|
||
inQuotation = false;
|
||
inBracketString += "'";
|
||
}
|
||
}
|
||
else //除“'”号之外的其它字符则加到字符串中
|
||
{
|
||
inBracketString += c.ToString();
|
||
}
|
||
}
|
||
else //不在引号内
|
||
{
|
||
if (c == '\'') //出现了第一个引号,设置inQuotation为true
|
||
{
|
||
inQuotation = true;
|
||
inBracketString += "'";
|
||
}
|
||
else if (c == '(') //出现了“(”则括号计数加1
|
||
{
|
||
inBracketString += "(";
|
||
bracketDepth++;
|
||
}
|
||
else if (c == ')') //出现了“)”则括号计数减1,如果计数为0则表示此次整个括号的内容结束
|
||
{
|
||
bracketDepth--;
|
||
if (bracketDepth == 0)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.SentenceType = SentenceType.InBracket;
|
||
node.Sentence = inBracketString;
|
||
node.parentNode = this;
|
||
nodes.Add(node);
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
inBracketString += ")";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
inBracketString += c.ToString();
|
||
}
|
||
}
|
||
}
|
||
//处理最后一个字符
|
||
char lastChar = charArray[charArray.Length - 1];
|
||
if (lastChar == ')' && bracketDepth==1)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.parentNode = this;
|
||
node.SentenceType = SentenceType.InBracket;
|
||
node.Sentence = inBracketString;
|
||
nodes.Add(node);
|
||
}
|
||
else
|
||
{
|
||
throw new Exception("缺少“)”");
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 在碰到“'”后,取出整个字符串的内容
|
||
/// </summary>
|
||
/// <param name="charArray">字符数组</param>
|
||
/// <param name="index">当前字符位置</param>
|
||
private void ParseInQuotation(ref Char[] charArray, ref int index)
|
||
{
|
||
string inQuotationString = "'";
|
||
index++;
|
||
//遍历当前字符串到倒数第二个字符
|
||
for (; index < charArray.Length - 1; index++)
|
||
{
|
||
char c = charArray[index];
|
||
if (c == '\'')
|
||
{
|
||
if (charArray[index + 1] == '\'') //如果“'”后面的还是“'”,SQL解析为一个“'”
|
||
{
|
||
inQuotationString += "''";
|
||
index++; //跳过第二个“'”
|
||
}
|
||
else //出现了另一个“'”号,记录整个字符串
|
||
{
|
||
inQuotationString += "'";
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.ParentNode = this;
|
||
node.SentenceType = SentenceType.String;
|
||
node.sentence = inQuotationString;
|
||
nodes.Add(node);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
inQuotationString += c.ToString();
|
||
}
|
||
}
|
||
//处理最后一个字符
|
||
char lastChar = charArray[charArray.Length - 1];
|
||
if (lastChar == '\'')
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.ParentNode = this;
|
||
node.SentenceType = SentenceType.String;
|
||
node.sentence = inQuotationString+"'";
|
||
nodes.Add(node);
|
||
}
|
||
else
|
||
{
|
||
throw new Exception("缺少“'”");
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 解析整条语句,生成树型结构
|
||
/// </summary>
|
||
public void Parse()
|
||
{
|
||
string s = string.Empty;
|
||
Char[] charArray = sentence.ToCharArray();
|
||
for (int i = 0; i < charArray.Length; i++)
|
||
{
|
||
char c=charArray[i];
|
||
if (c == '\'') //如果碰见一个“'”,调用ParseInQuotation记录从该处开始其后的字符串
|
||
{
|
||
if (s != string.Empty)
|
||
{
|
||
throw new Exception("“'”附近有语法错误");
|
||
}
|
||
ParseInQuotation(ref charArray, ref i);
|
||
}
|
||
else if (c == '(') //如果碰见一个“(”,调用ParseInBracket记录从该处开始到与之对应的“)”之间的内容
|
||
{
|
||
string funName = string.Empty;
|
||
if (s != string.Empty)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.ParentNode = this;
|
||
node.sentence = s;
|
||
node.SentenceType = SentenceType.Function;
|
||
this.nodes.Add(node);
|
||
funName = s.ToLower();
|
||
s = string.Empty;
|
||
}
|
||
ParseInBracket(ref charArray, ref i);
|
||
if (funKeywords.Contains(funName) && this.nodes[this.nodes.Count - 1].nodes.Count > 0)
|
||
this.nodes[this.nodes.Count - 1].nodes[0].SentenceType = SentenceType.Keyword;
|
||
}
|
||
else if (c == ' ') //如果碰见一个空格,记录空格前的内容
|
||
{
|
||
if (s != string.Empty)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.ParentNode = this;
|
||
if (nodes.Count > 0 && nodes[nodes.Count - 1].sentenceType == SentenceType.From)
|
||
{
|
||
node.sentenceType = SentenceType.Entity;
|
||
EntityInfo entityInfo = EntityMap.GetEntityInfo(GetName(s));
|
||
if (entityInfo == null)
|
||
throw new Exception("from后有语法错误,使用了一个不存在的实体名");
|
||
this.map = entityInfo.PropertyMap;
|
||
}
|
||
else
|
||
node.SentenceType = GetSentenceType(s);
|
||
node.sentence = GetName(s) + " ";
|
||
this.nodes.Add(node);
|
||
s = string.Empty;
|
||
}
|
||
}
|
||
else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '!' || c == '<' || c == '>' || c == ',')//如果碰见一个符号,记录符号前的内容及符号本身
|
||
{
|
||
if (s != string.Empty)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.ParentNode = this;
|
||
node.SentenceType = GetSentenceType(s);
|
||
node.sentence = s;
|
||
this.nodes.Add(node);
|
||
}
|
||
SyntaxNode operatorNode = new SyntaxNode();
|
||
operatorNode.ParentNode = this;
|
||
operatorNode.SentenceType = SentenceType.Symbol;
|
||
operatorNode.sentence = c.ToString();
|
||
this.nodes.Add(operatorNode);
|
||
s = string.Empty;
|
||
}
|
||
else
|
||
{
|
||
s += c.ToString();
|
||
}
|
||
}
|
||
//记录最后的内容
|
||
if (s != string.Empty)
|
||
{
|
||
SyntaxNode node = new SyntaxNode();
|
||
node.parentNode = this;
|
||
if (nodes.Count > 0 && nodes[nodes.Count - 1].sentenceType == SentenceType.From)
|
||
{
|
||
node.sentenceType = SentenceType.Entity;
|
||
EntityInfo entityInfo = EntityMap.GetEntityInfo(GetName(s));
|
||
if (entityInfo == null)
|
||
throw new Exception("from后有语法错误,使用了一个不存在的实体名");
|
||
this.map = entityInfo.PropertyMap;
|
||
}
|
||
else
|
||
node.SentenceType = GetSentenceType(s);
|
||
node.sentence = GetName(s);
|
||
this.nodes.Add(node);
|
||
}
|
||
}
|
||
private string GetName(string str)
|
||
{
|
||
string s = str.ToLower().Trim();
|
||
if (s.IndexOf('[') == 0 && s.LastIndexOf(']') == s.Length - 1)
|
||
s = s.Substring(1, s.Length - 2);
|
||
return s;
|
||
}
|
||
/// <summary>
|
||
/// 获取语句的类型
|
||
/// </summary>
|
||
/// <param name="sentence">语句</param>
|
||
/// <returns>语句类型</returns>
|
||
public SentenceType GetSentenceType(string sentence)
|
||
{
|
||
if (IsNumeric(sentence))
|
||
return SentenceType.Numeric;
|
||
if (sentence.Substring(0, 1) == "@")
|
||
return SentenceType.Parameter;
|
||
string s = sentence.ToLower();
|
||
if (keywords.Contains(sentence))
|
||
return SentenceType.Keyword;
|
||
switch (s)
|
||
{
|
||
case "select":return SentenceType.Select;
|
||
case "from": return SentenceType.From;
|
||
case "where": return SentenceType.Where;
|
||
case "group": return SentenceType.Group;
|
||
case "order": return SentenceType.Order;
|
||
case "by": return SentenceType.By;
|
||
default: return SentenceType.Property;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 判断字符串是否是数值格式
|
||
/// </summary>
|
||
/// <param name="str">字符串</param>
|
||
/// <returns>true:是数值格式 false:不是数值格式</returns>
|
||
private bool IsNumeric(string str)
|
||
{
|
||
Regex regex = new Regex("^(-?[0-9]*[.]*[0-9]{0,3})$");
|
||
return regex.IsMatch(str);
|
||
}
|
||
/// <summary>
|
||
/// 获取解析后的Sql语句
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetSql()
|
||
{
|
||
if (this.map == null)
|
||
this.map = this.parentNode.map;
|
||
string sql = "";
|
||
if (this.SentenceType == SentenceType.Segment)
|
||
{
|
||
foreach (SyntaxNode node in nodes)
|
||
{
|
||
sql += node.GetSql();
|
||
}
|
||
}
|
||
else if (this.SentenceType == SentenceType.InBracket)
|
||
{
|
||
foreach (SyntaxNode node in nodes)
|
||
{
|
||
sql += node.GetSql();
|
||
}
|
||
sql = "(" + sql + ")";
|
||
}
|
||
else if(this.SentenceType==SentenceType.Property)
|
||
{
|
||
sql += this.sentence.Replace(this.sentence.Trim(), "["+this.map[this.sentence.Trim()]+"]");
|
||
}
|
||
else if (this.SentenceType == SentenceType.Entity)
|
||
{
|
||
sql += this.sentence.Replace(this.sentence.Trim(), "["+EntityMap.GetEntityInfo(this.sentence.Trim()).TableName+"]");
|
||
}
|
||
else if (this.SentenceType == SentenceType.String)
|
||
{
|
||
sql = this.sentence+" ";
|
||
}
|
||
else
|
||
{
|
||
sql = this.sentence;
|
||
}
|
||
return sql;
|
||
}
|
||
/// <summary>
|
||
/// 获取语句中包含的参数列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public List<string> GetParameters()
|
||
{
|
||
List<string> parameters = new List<string>();
|
||
if (this.SentenceType == SentenceType.Parameter)
|
||
{
|
||
parameters.Add(this.sentence.Trim());
|
||
}
|
||
else if (this.SentenceType == SentenceType.InBracket)
|
||
{
|
||
foreach (SyntaxNode node in nodes)
|
||
{
|
||
List<string> childParameters = node.GetParameters();
|
||
foreach (string para in childParameters)
|
||
{
|
||
parameters.Add(para);
|
||
}
|
||
}
|
||
}
|
||
return parameters;
|
||
}
|
||
}
|
||
enum SentenceType { Segment, InBracket, String, Numeric, Parameter, Entity, Property, Symbol, Keyword, Function, Select, From, Where, Group, By, Order }
|
||
} |