AIMS/AIMSEntity/ObjectQuery/SyntaxAnalyzer.cs
2022-08-23 21:12:59 +08:00

464 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 }
}