431 lines
14 KiB
C#
431 lines
14 KiB
C#
namespace NHibernate.AdoNet.Util
|
|
{
|
|
using NHibernate.Util;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
public class BasicFormatter : IFormatter
|
|
{
|
|
protected static readonly HashSet<string> beginClauses = new HashSet<string>();
|
|
protected static readonly HashSet<string> dml = new HashSet<string>();
|
|
protected static readonly HashSet<string> endClauses = new HashSet<string>();
|
|
protected const string IndentString = " ";
|
|
protected const string Initial = "\n ";
|
|
protected static readonly HashSet<string> logical = new HashSet<string>();
|
|
protected static readonly HashSet<string> misc = new HashSet<string>();
|
|
protected static readonly HashSet<string> quantifiers = new HashSet<string>();
|
|
|
|
static BasicFormatter()
|
|
{
|
|
beginClauses.Add("left");
|
|
beginClauses.Add("right");
|
|
beginClauses.Add("inner");
|
|
beginClauses.Add("outer");
|
|
beginClauses.Add("group");
|
|
beginClauses.Add("order");
|
|
endClauses.Add("where");
|
|
endClauses.Add("set");
|
|
endClauses.Add("having");
|
|
endClauses.Add("join");
|
|
endClauses.Add("from");
|
|
endClauses.Add("by");
|
|
endClauses.Add("join");
|
|
endClauses.Add("into");
|
|
endClauses.Add("union");
|
|
logical.Add("and");
|
|
logical.Add("or");
|
|
logical.Add("when");
|
|
logical.Add("else");
|
|
logical.Add("end");
|
|
quantifiers.Add("in");
|
|
quantifiers.Add("all");
|
|
quantifiers.Add("exists");
|
|
quantifiers.Add("some");
|
|
quantifiers.Add("any");
|
|
dml.Add("insert");
|
|
dml.Add("update");
|
|
dml.Add("delete");
|
|
misc.Add("select");
|
|
misc.Add("on");
|
|
}
|
|
|
|
public virtual string Format(string source)
|
|
{
|
|
return new FormatProcess(source).Perform();
|
|
}
|
|
|
|
private class FormatProcess
|
|
{
|
|
private bool afterBeginBeforeEnd;
|
|
private bool afterBetween;
|
|
private readonly List<bool> afterByOrFromOrSelects = new List<bool>();
|
|
private bool afterByOrSetOrFromOrSelect;
|
|
private bool afterInsert;
|
|
private bool afterOn;
|
|
private bool beginLine = true;
|
|
private bool endCommandFound;
|
|
private int indent = 1;
|
|
private int inFunction;
|
|
private string lastToken;
|
|
private string lcToken;
|
|
private readonly List<int> parenCounts = new List<int>();
|
|
private int parensSinceSelect;
|
|
private readonly StringBuilder result = new StringBuilder();
|
|
private string token;
|
|
private readonly IEnumerator<string> tokens;
|
|
|
|
public FormatProcess(string sql)
|
|
{
|
|
this.tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[],; \n\r\f\t", true).GetEnumerator();
|
|
}
|
|
|
|
private void BeginNewClause()
|
|
{
|
|
if (!this.afterBeginBeforeEnd)
|
|
{
|
|
if (this.afterOn)
|
|
{
|
|
this.indent--;
|
|
this.afterOn = false;
|
|
}
|
|
this.indent--;
|
|
this.Newline();
|
|
}
|
|
this.Out();
|
|
this.beginLine = false;
|
|
this.afterBeginBeforeEnd = true;
|
|
}
|
|
|
|
private void CloseParen()
|
|
{
|
|
if (this.endCommandFound)
|
|
{
|
|
this.Out();
|
|
}
|
|
else
|
|
{
|
|
this.parensSinceSelect--;
|
|
if (this.parensSinceSelect < 0)
|
|
{
|
|
this.indent--;
|
|
int num = this.parenCounts[this.parenCounts.Count - 1];
|
|
this.parenCounts.RemoveAt(this.parenCounts.Count - 1);
|
|
this.parensSinceSelect = num;
|
|
bool flag = this.afterByOrFromOrSelects[this.afterByOrFromOrSelects.Count - 1];
|
|
this.afterByOrFromOrSelects.RemoveAt(this.afterByOrFromOrSelects.Count - 1);
|
|
this.afterByOrSetOrFromOrSelect = flag;
|
|
}
|
|
if (this.inFunction > 0)
|
|
{
|
|
this.inFunction--;
|
|
this.Out();
|
|
}
|
|
else
|
|
{
|
|
if (!this.afterByOrSetOrFromOrSelect)
|
|
{
|
|
this.indent--;
|
|
this.Newline();
|
|
}
|
|
this.Out();
|
|
}
|
|
this.beginLine = false;
|
|
}
|
|
}
|
|
|
|
private void CommaAfterByOrFromOrSelect()
|
|
{
|
|
this.Out();
|
|
this.Newline();
|
|
}
|
|
|
|
private void CommaAfterOn()
|
|
{
|
|
this.Out();
|
|
this.indent--;
|
|
this.Newline();
|
|
this.afterOn = false;
|
|
this.afterByOrSetOrFromOrSelect = true;
|
|
}
|
|
|
|
private void EndNewClause()
|
|
{
|
|
if (!this.afterBeginBeforeEnd)
|
|
{
|
|
this.indent--;
|
|
if (this.afterOn)
|
|
{
|
|
this.indent--;
|
|
this.afterOn = false;
|
|
}
|
|
this.Newline();
|
|
}
|
|
this.Out();
|
|
if (!"union".Equals(this.lcToken))
|
|
{
|
|
this.indent++;
|
|
}
|
|
this.Newline();
|
|
this.afterBeginBeforeEnd = false;
|
|
this.afterByOrSetOrFromOrSelect = ("by".Equals(this.lcToken) || "set".Equals(this.lcToken)) || "from".Equals(this.lcToken);
|
|
}
|
|
|
|
private void ExtractStringEnclosedBy(string stringDelimiter)
|
|
{
|
|
while (this.tokens.MoveNext())
|
|
{
|
|
string current = this.tokens.Current;
|
|
this.token = this.token + current;
|
|
if (stringDelimiter.Equals(current))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool IsFunctionName(string tok)
|
|
{
|
|
char c = tok[0];
|
|
return (((((((char.IsLetter(c) || (c.CompareTo('$') == 0)) || (c.CompareTo('_') == 0)) || ('"' == c)) && !BasicFormatter.logical.Contains(tok)) && (!BasicFormatter.endClauses.Contains(tok) && !BasicFormatter.quantifiers.Contains(tok))) && !BasicFormatter.dml.Contains(tok)) && !BasicFormatter.misc.Contains(tok));
|
|
}
|
|
|
|
private bool IsMultiQueryDelimiter(string delimiter)
|
|
{
|
|
return ";".Equals(delimiter);
|
|
}
|
|
|
|
private static bool IsWhitespace(string token)
|
|
{
|
|
return (" \n\r\f\t".IndexOf(token) >= 0);
|
|
}
|
|
|
|
private void Logical()
|
|
{
|
|
if ("end".Equals(this.lcToken))
|
|
{
|
|
this.indent--;
|
|
}
|
|
this.Newline();
|
|
this.Out();
|
|
this.beginLine = false;
|
|
}
|
|
|
|
private void Misc()
|
|
{
|
|
this.Out();
|
|
if ("between".Equals(this.lcToken))
|
|
{
|
|
this.afterBetween = true;
|
|
}
|
|
if (this.afterInsert)
|
|
{
|
|
this.Newline();
|
|
this.afterInsert = false;
|
|
}
|
|
else
|
|
{
|
|
this.beginLine = false;
|
|
if ("case".Equals(this.lcToken))
|
|
{
|
|
this.indent++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Newline()
|
|
{
|
|
this.result.Append("\n");
|
|
for (int i = 0; i < this.indent; i++)
|
|
{
|
|
this.result.Append(" ");
|
|
}
|
|
this.beginLine = true;
|
|
}
|
|
|
|
private void On()
|
|
{
|
|
this.indent++;
|
|
this.afterOn = true;
|
|
this.Newline();
|
|
this.Out();
|
|
this.beginLine = false;
|
|
}
|
|
|
|
private void OpenParen()
|
|
{
|
|
if (this.endCommandFound)
|
|
{
|
|
this.Out();
|
|
}
|
|
else
|
|
{
|
|
if (IsFunctionName(this.lastToken) || (this.inFunction > 0))
|
|
{
|
|
this.inFunction++;
|
|
}
|
|
this.beginLine = false;
|
|
if (this.inFunction > 0)
|
|
{
|
|
this.Out();
|
|
}
|
|
else
|
|
{
|
|
this.Out();
|
|
if (!this.afterByOrSetOrFromOrSelect)
|
|
{
|
|
this.indent++;
|
|
this.Newline();
|
|
this.beginLine = true;
|
|
}
|
|
}
|
|
this.parensSinceSelect++;
|
|
}
|
|
}
|
|
|
|
private void Out()
|
|
{
|
|
this.result.Append(this.token);
|
|
}
|
|
|
|
public string Perform()
|
|
{
|
|
this.result.Append("\n ");
|
|
while (this.tokens.MoveNext())
|
|
{
|
|
this.token = this.tokens.Current;
|
|
this.lcToken = this.token.ToLowerInvariant();
|
|
if ("'".Equals(this.token))
|
|
{
|
|
this.ExtractStringEnclosedBy("'");
|
|
}
|
|
else if ("\"".Equals(this.token))
|
|
{
|
|
this.ExtractStringEnclosedBy("\"");
|
|
}
|
|
if (this.IsMultiQueryDelimiter(this.token))
|
|
{
|
|
this.StartingNewQuery();
|
|
}
|
|
else if (this.afterByOrSetOrFromOrSelect && ",".Equals(this.token))
|
|
{
|
|
this.CommaAfterByOrFromOrSelect();
|
|
}
|
|
else if (this.afterOn && ",".Equals(this.token))
|
|
{
|
|
this.CommaAfterOn();
|
|
}
|
|
else if ("(".Equals(this.token))
|
|
{
|
|
this.OpenParen();
|
|
}
|
|
else if (")".Equals(this.token))
|
|
{
|
|
this.CloseParen();
|
|
}
|
|
else if (BasicFormatter.beginClauses.Contains(this.lcToken))
|
|
{
|
|
this.BeginNewClause();
|
|
}
|
|
else if (BasicFormatter.endClauses.Contains(this.lcToken))
|
|
{
|
|
this.EndNewClause();
|
|
}
|
|
else if ("select".Equals(this.lcToken))
|
|
{
|
|
this.Select();
|
|
}
|
|
else if (BasicFormatter.dml.Contains(this.lcToken))
|
|
{
|
|
this.UpdateOrInsertOrDelete();
|
|
}
|
|
else if ("values".Equals(this.lcToken))
|
|
{
|
|
this.Values();
|
|
}
|
|
else if ("on".Equals(this.lcToken))
|
|
{
|
|
this.On();
|
|
}
|
|
else if (this.afterBetween && this.lcToken.Equals("and"))
|
|
{
|
|
this.Misc();
|
|
this.afterBetween = false;
|
|
}
|
|
else if (BasicFormatter.logical.Contains(this.lcToken))
|
|
{
|
|
this.Logical();
|
|
}
|
|
else if (IsWhitespace(this.token))
|
|
{
|
|
this.White();
|
|
}
|
|
else
|
|
{
|
|
this.Misc();
|
|
}
|
|
if (!IsWhitespace(this.token))
|
|
{
|
|
this.lastToken = this.lcToken;
|
|
}
|
|
}
|
|
return this.result.ToString();
|
|
}
|
|
|
|
private void Select()
|
|
{
|
|
this.Out();
|
|
this.indent++;
|
|
this.Newline();
|
|
this.parenCounts.Insert(this.parenCounts.Count, this.parensSinceSelect);
|
|
this.afterByOrFromOrSelects.Insert(this.afterByOrFromOrSelects.Count, this.afterByOrSetOrFromOrSelect);
|
|
this.parensSinceSelect = 0;
|
|
this.afterByOrSetOrFromOrSelect = true;
|
|
this.endCommandFound = false;
|
|
}
|
|
|
|
private void StartingNewQuery()
|
|
{
|
|
this.Out();
|
|
this.indent = 1;
|
|
this.endCommandFound = true;
|
|
this.Newline();
|
|
}
|
|
|
|
private void UpdateOrInsertOrDelete()
|
|
{
|
|
this.Out();
|
|
this.indent++;
|
|
this.beginLine = false;
|
|
if ("update".Equals(this.lcToken))
|
|
{
|
|
this.Newline();
|
|
}
|
|
if ("insert".Equals(this.lcToken))
|
|
{
|
|
this.afterInsert = true;
|
|
}
|
|
this.endCommandFound = false;
|
|
}
|
|
|
|
private void Values()
|
|
{
|
|
this.indent--;
|
|
this.Newline();
|
|
this.Out();
|
|
this.indent++;
|
|
this.Newline();
|
|
}
|
|
|
|
private void White()
|
|
{
|
|
if (!this.beginLine)
|
|
{
|
|
this.result.Append(" ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|