Files
DevToolsAvalonia/常用工具集/Utility/SqlFormat/BasicFormatter.cs
2025-08-26 08:37:44 +08:00

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(" ");
}
}
}
}
}