diff --git a/sql/mysql/Oracle/Antlr4ng/MySQLLexerBase.ts b/sql/mysql/Oracle/Antlr4ng/MySQLLexerBase.ts index 036674d09e..3a418acefb 100644 --- a/sql/mysql/Oracle/Antlr4ng/MySQLLexerBase.ts +++ b/sql/mysql/Oracle/Antlr4ng/MySQLLexerBase.ts @@ -5,7 +5,7 @@ /* eslint-disable no-underscore-dangle */ /* cspell: ignore antlr, longlong, ULONGLONG, MAXDB */ -import { Lexer, Token } from "antlr4ng"; +import { CharStream, Lexer, Token } from "antlr4ng"; import { MySQLLexer } from "./MySQLLexer.js"; /** SQL modes that control parsing behavior. */ @@ -41,6 +41,12 @@ export abstract class MySQLLexerBase extends Lexer { static #unsignedLongLongString = "18446744073709551615"; static #unsignedLongLongLength = 20; + constructor(input: CharStream) { + super(input); + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); + } + /** * Determines if the given SQL mode is currently active in the lexer. * @@ -313,226 +319,226 @@ export abstract class MySQLLexerBase extends Lexer { public doLogicalOr(): void { - this.type = this.isSqlModeActive(SqlMode.PipesAsConcat) ? MySQLLexer.CONCAT_PIPES_SYMBOL : MySQLLexer.LOGICAL_OR_OPERATOR; + this.type = this.isSqlModeActive(SqlMode.PipesAsConcat) ? MySQLLexer.CONCAT_PIPES_SYMBOL : MySQLLexer.LOGICAL_OR_OPERATOR; } public doIntNumber(): void { - this.type = this.determineNumericType(this.text); + this.type = this.determineNumericType(this.text); } public doAdddate(): void { - this.type = this.determineFunction(MySQLLexer.ADDDATE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.ADDDATE_SYMBOL); } public doBitAnd(): void { - this.type = this.determineFunction(MySQLLexer.BIT_AND_SYMBOL); + this.type = this.determineFunction(MySQLLexer.BIT_AND_SYMBOL); } public doBitOr(): void { - this.type = this.determineFunction(MySQLLexer.BIT_OR_SYMBOL); + this.type = this.determineFunction(MySQLLexer.BIT_OR_SYMBOL); } public doBitXor(): void { - this.type = this.determineFunction(MySQLLexer.BIT_XOR_SYMBOL); + this.type = this.determineFunction(MySQLLexer.BIT_XOR_SYMBOL); } public doCast(): void { - this.type = this.determineFunction(MySQLLexer.CAST_SYMBOL); + this.type = this.determineFunction(MySQLLexer.CAST_SYMBOL); } public doCount(): void { - this.type = this.determineFunction(MySQLLexer.COUNT_SYMBOL); + this.type = this.determineFunction(MySQLLexer.COUNT_SYMBOL); } public doCurdate(): void { - this.type = this.determineFunction(MySQLLexer.CURDATE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.CURDATE_SYMBOL); } public doCurrentDate(): void { - this.type = this.determineFunction(MySQLLexer.CURDATE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.CURDATE_SYMBOL); } public doCurrentTime(): void { - this.type = this.determineFunction(MySQLLexer.CURTIME_SYMBOL); + this.type = this.determineFunction(MySQLLexer.CURTIME_SYMBOL); } public doCurtime(): void { - this.type = this.determineFunction(MySQLLexer.CURTIME_SYMBOL); + this.type = this.determineFunction(MySQLLexer.CURTIME_SYMBOL); } public doDateAdd(): void { - this.type = this.determineFunction(MySQLLexer.DATE_ADD_SYMBOL); + this.type = this.determineFunction(MySQLLexer.DATE_ADD_SYMBOL); } public doDateSub(): void { - this.type = this.determineFunction(MySQLLexer.DATE_SUB_SYMBOL); + this.type = this.determineFunction(MySQLLexer.DATE_SUB_SYMBOL); } public doExtract(): void { - this.type = this.determineFunction(MySQLLexer.EXTRACT_SYMBOL); + this.type = this.determineFunction(MySQLLexer.EXTRACT_SYMBOL); } public doGroupConcat(): void { - this.type = this.determineFunction(MySQLLexer.GROUP_CONCAT_SYMBOL); + this.type = this.determineFunction(MySQLLexer.GROUP_CONCAT_SYMBOL); } public doMax(): void { - this.type = this.determineFunction(MySQLLexer.MAX_SYMBOL); + this.type = this.determineFunction(MySQLLexer.MAX_SYMBOL); } public doMid(): void { - this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); } public doMin(): void { - this.type = this.determineFunction(MySQLLexer.MIN_SYMBOL); + this.type = this.determineFunction(MySQLLexer.MIN_SYMBOL); } public doNot(): void { - this.type = this.isSqlModeActive(SqlMode.HighNotPrecedence) ? MySQLLexer.NOT2_SYMBOL: MySQLLexer.NOT_SYMBOL; + this.type = this.isSqlModeActive(SqlMode.HighNotPrecedence) ? MySQLLexer.NOT2_SYMBOL: MySQLLexer.NOT_SYMBOL; } public doNow(): void { - this.type = this.determineFunction(MySQLLexer.NOW_SYMBOL); + this.type = this.determineFunction(MySQLLexer.NOW_SYMBOL); } public doPosition(): void { - this.type = this.determineFunction(MySQLLexer.POSITION_SYMBOL); + this.type = this.determineFunction(MySQLLexer.POSITION_SYMBOL); } public doSessionUser(): void { - this.type = this.determineFunction(MySQLLexer.USER_SYMBOL); + this.type = this.determineFunction(MySQLLexer.USER_SYMBOL); } public doStddevSamp(): void { - this.type = this.determineFunction(MySQLLexer.STDDEV_SAMP_SYMBOL); + this.type = this.determineFunction(MySQLLexer.STDDEV_SAMP_SYMBOL); } public doStddev(): void { - this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); + this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); } public doStddevPop(): void { - this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); + this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); } public doStd(): void { - this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); + this.type = this.determineFunction(MySQLLexer.STD_SYMBOL); } public doSubdate(): void { - this.type = this.determineFunction(MySQLLexer.SUBDATE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SUBDATE_SYMBOL); } public doSubstr(): void { - this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); } public doSubstring(): void { - this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SUBSTRING_SYMBOL); } public doSum(): void { - this.type = this.determineFunction(MySQLLexer.SUM_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SUM_SYMBOL); } public doSysdate(): void { - this.type = this.determineFunction(MySQLLexer.SYSDATE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.SYSDATE_SYMBOL); } public doSystemUser(): void { - this.type = this.determineFunction(MySQLLexer.USER_SYMBOL); + this.type = this.determineFunction(MySQLLexer.USER_SYMBOL); } public doTrim(): void { - this.type = this.determineFunction(MySQLLexer.TRIM_SYMBOL); + this.type = this.determineFunction(MySQLLexer.TRIM_SYMBOL); } public doVariance(): void { - this.type = this.determineFunction(MySQLLexer.VARIANCE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.VARIANCE_SYMBOL); } public doVarPop(): void { - this.type = this.determineFunction(MySQLLexer.VARIANCE_SYMBOL); + this.type = this.determineFunction(MySQLLexer.VARIANCE_SYMBOL); } public doVarSamp(): void { - this.type = this.determineFunction(MySQLLexer.VAR_SAMP_SYMBOL); + this.type = this.determineFunction(MySQLLexer.VAR_SAMP_SYMBOL); } public doUnderscoreCharset(): void { - this.type = this.checkCharset(this.text); + this.type = this.checkCharset(this.text); } public isVersionComment(): boolean { - return this.checkMySQLVersion(this.text); + return this.checkMySQLVersion(this.text); } public isBackTickQuotedId(): boolean { - return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); + return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); } public isDoubleQuotedText(): boolean { - return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); + return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); } public isSingleQuotedText(): boolean { - return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); + return !this.isSqlModeActive(SqlMode.NoBackslashEscapes); } public startInVersionComment(): void { - this.inVersionComment = true; + this.inVersionComment = true; } public endInVersionComment(): void { - this.inVersionComment = false; + this.inVersionComment = false; } public isInVersionComment(): boolean { - return this.inVersionComment; + return this.inVersionComment; } } diff --git a/sql/mysql/Oracle/Antlr4ng/MySQLParserBase.ts b/sql/mysql/Oracle/Antlr4ng/MySQLParserBase.ts index 3c80d99e1c..cbe88f5bf5 100644 --- a/sql/mysql/Oracle/Antlr4ng/MySQLParserBase.ts +++ b/sql/mysql/Oracle/Antlr4ng/MySQLParserBase.ts @@ -2,8 +2,7 @@ * Copyright © 2024, Oracle and/or its affiliates */ -import { Parser } from "antlr4ng"; - +import { Parser, TokenStream } from "antlr4ng"; import { SqlMode } from "./MySQLLexerBase.js"; export abstract class MySQLParserBase extends Parser { @@ -15,6 +14,12 @@ export abstract class MySQLParserBase extends Parser { /** Enable Multi Language Extension support. */ public supportMle = true; + constructor(input: TokenStream) { + super(input); + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); + } + /** * Determines if the given SQL mode is currently active in the lexer. * @@ -28,21 +33,48 @@ export abstract class MySQLParserBase extends Parser { public isPureIdentifier(): boolean { - return this.isSqlModeActive(SqlMode.AnsiQuotes); + return this.isSqlModeActive(SqlMode.AnsiQuotes); } public isTextStringLiteral(): boolean { - return !this.isSqlModeActive(SqlMode.AnsiQuotes); + return !this.isSqlModeActive(SqlMode.AnsiQuotes); } public isStoredRoutineBody(): boolean { - return this.serverVersion >= 80032 && this.supportMle; + return this.serverVersion >= 80032 && this.supportMle; } public isSelectStatementWithInto(): boolean { - return this.serverVersion >= 80024 && this.serverVersion < 80031; + return this.serverVersion >= 80024 && this.serverVersion < 80031; + } + + /** + * Converts a mode string into individual mode flags. + * + * @param modes The input string to parse. + */ + public sqlModeFromString(modes: string): void { + this.sqlModes = new Set(); + + const parts = modes.toUpperCase().split(","); + parts.forEach((mode: string) => { + if (mode === "ANSI" || mode === "DB2" || mode === "MAXDB" || mode === "MSSQL" || mode === "ORACLE" || + mode === "POSTGRESQL") { + this.sqlModes.add(SqlMode.AnsiQuotes).add(SqlMode.PipesAsConcat).add(SqlMode.IgnoreSpace); + } else if (mode === "ANSI_QUOTES") { + this.sqlModes.add(SqlMode.AnsiQuotes); + } else if (mode === "PIPES_AS_CONCAT") { + this.sqlModes.add(SqlMode.PipesAsConcat); + } else if (mode === "NO_BACKSLASH_ESCAPES") { + this.sqlModes.add(SqlMode.NoBackslashEscapes); + } else if (mode === "IGNORE_SPACE") { + this.sqlModes.add(SqlMode.IgnoreSpace); + } else if (mode === "HIGH_NOT_PRECEDENCE" || mode === "MYSQL323" || mode === "MYSQL40") { + this.sqlModes.add(SqlMode.HighNotPrecedence); + } + }); } } diff --git a/sql/mysql/Oracle/Antlr4ng/Test.ts b/sql/mysql/Oracle/Antlr4ng/Test.ts deleted file mode 100644 index b6384b4645..0000000000 --- a/sql/mysql/Oracle/Antlr4ng/Test.ts +++ /dev/null @@ -1,289 +0,0 @@ -// Generated from trgen 0.23.7 - -import { ATNSimulator } from 'antlr4ng'; -import { BaseErrorListener } from 'antlr4ng'; -import { CharStream } from 'antlr4ng'; -import { CommonTokenStream } from 'antlr4ng'; -import { ConsoleErrorListener } from 'antlr4ng'; -import { ErrorNode } from 'antlr4ng'; -//import { InputStream } from 'antlr4ng'; -import { Parser } from 'antlr4ng'; -import { ParserRuleContext } from 'antlr4ng'; -import { ParseTree } from 'antlr4ng'; -import { Recognizer } from 'antlr4ng'; -import { RecognitionException } from 'antlr4ng'; -import { TerminalNode } from 'antlr4ng'; -import { Token } from 'antlr4ng'; -import { Trees } from 'antlr4ng'; -import { escapeWhitespace } from 'antlr4ng'; -import { readFileSync } from 'fs'; -import { writeFileSync } from 'fs'; -import { openSync } from 'fs'; -import { readSync } from 'fs'; -import { writeSync } from 'fs'; -import { closeSync } from 'fs'; -import { readFile } from 'fs/promises' -import { isToken } from 'antlr4ng'; - -import { MySQLLexer } from './MySQLLexer.js'; -import { MySQLParser } from './MySQLParser.js'; - -import { StringBuilder, emptyString, joinString, formatString, isNullOrWhiteSpace } from 'typescript-string-operations'; -import { Timer, Time, TimerOptions } from 'timer-node'; - - -function getChar() { - let buffer = Buffer.alloc(1); - var xx = 0; - try { - xx = readSync(0, buffer, 0, 1, null); - } catch (err) { - } - if (xx === 0) { - return ''; - } - return buffer.toString('utf8'); -} - - -class MyErrorListener extends ConsoleErrorListener { - _quiet: boolean; - _tee: boolean; - _output: any; - had_error: boolean; - - constructor(quiet: boolean, tee: boolean, output: any) { - super(); - this._quiet = quiet; - this._tee = tee; - this._output = output; - this.had_error = false; - } - - syntaxError(recognizer: Recognizer | null, offendingSymbol: unknown, line: number, column: number, msg: string | null, e: RecognitionException | null): void { - this.had_error = true; - if (this._tee) { - writeSync(this._output, `line ${line}:${column} ${msg}\n`); - } - if (!this._quiet) { - console.error(`line ${line}:${column} ${msg}`); - } - } -} - -var tee = false; -var show_profile = false; -var show_tree = false; -var show_tokens = false; -var show_trace = false; -var error_code = 0; -var quiet = false; -var enc = 'utf8'; -var string_instance = 0; -var prefix = ''; -var inputs: string[] = []; -var is_fns: boolean[] = []; - -function splitLines(t: string) { return t.split(/\r\n|\r|\n/); } - -function main() { - for (let i = 2; i charSets = new HashSet(); // Used to check repertoires. protected bool inVersionComment = false; - private StackQueue pendingTokens = new StackQueue(); + private Queue pendingTokens = new Queue(); static string longString = "2147483647"; static int longLength = 10; @@ -55,13 +55,17 @@ public class MySQLLexerBase : Lexer { protected MySQLLexerBase(ICharStream input, TextWriter output, TextWriter errorOutput) - : base(input, output, errorOutput) + : base(input, output, errorOutput) { + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); } public MySQLLexerBase(ICharStream input) : base(input) { + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); } /** @@ -125,8 +129,9 @@ public override void Reset() public override IToken NextToken() { // First respond with pending tokens to the next token request, if there are any. - var pending = this.pendingTokens.DequeueBottom(); - if (pending != null) { + IToken pending; + var not_empty = this.pendingTokens.TryDequeue(out pending); + if (not_empty) { return pending; } @@ -134,10 +139,9 @@ public override IToken NextToken() // This might create additional tokens again. var next = base.NextToken(); - pending = this.pendingTokens.DequeueBottom(); - if (pending != null) { - this.pendingTokens.Push(next); - + not_empty = this.pendingTokens.TryDequeue(out pending); + if (not_empty) { + this.pendingTokens.Enqueue(next); return pending; } @@ -293,7 +297,7 @@ protected int checkCharset(string text) */ protected void emitDot() { - this.pendingTokens.Push(this.TokenFactory.Create(new Tuple(this, (ICharStream)this.InputStream), MySQLLexer.DOT_SYMBOL, + this.pendingTokens.Enqueue(this.TokenFactory.Create(new Tuple(this, (ICharStream)this.InputStream), MySQLLexer.DOT_SYMBOL, this.Text, this.Channel, this.TokenStartCharIndex, this.TokenStartCharIndex, this.Line, this.Column )); diff --git a/sql/mysql/Oracle/CSharp/MySQLParserBase.cs b/sql/mysql/Oracle/CSharp/MySQLParserBase.cs index 25233e7520..7c7274eb11 100644 --- a/sql/mysql/Oracle/CSharp/MySQLParserBase.cs +++ b/sql/mysql/Oracle/CSharp/MySQLParserBase.cs @@ -17,6 +17,8 @@ public abstract class MySQLParserBase : Parser { protected MySQLParserBase(ITokenStream input, TextWriter output, TextWriter errorOutput) : base(input, output, errorOutput) { + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); } /** @@ -49,4 +51,35 @@ public bool isSelectStatementWithInto() { return serverVersion >= 80024 && serverVersion < 80031; } + + /** + * Converts a mode string into individual mode flags. + * + * @param modes The input string to parse. + */ + public void sqlModeFromString(string modes) + { + this.sqlModes = new HashSet(); + + var parts = modes.ToUpper().Split(","); + foreach (var mode in parts) + { + if (mode == "ANSI" || mode == "DB2" || mode == "MAXDB" || mode == "MSSQL" || mode == "ORACLE" || + mode == "POSTGRESQL") { + this.sqlModes.Add(SqlMode.AnsiQuotes); + this.sqlModes.Add(SqlMode.PipesAsConcat); + this.sqlModes.Add(SqlMode.IgnoreSpace); + } else if (mode == "ANSI_QUOTES") { + this.sqlModes.Add(SqlMode.AnsiQuotes); + } else if (mode == "PIPES_AS_CONCAT") { + this.sqlModes.Add(SqlMode.PipesAsConcat); + } else if (mode == "NO_BACKSLASH_ESCAPES") { + this.sqlModes.Add(SqlMode.NoBackslashEscapes); + } else if (mode == "IGNORE_SPACE") { + this.sqlModes.Add(SqlMode.IgnoreSpace); + } else if (mode == "HIGH_NOT_PRECEDENCE" || mode == "MYSQL323" || mode == "MYSQL40") { + this.sqlModes.Add(SqlMode.HighNotPrecedence); + } + } + } } diff --git a/sql/mysql/Oracle/CSharp/StackQueue.cs b/sql/mysql/Oracle/CSharp/StackQueue.cs deleted file mode 100644 index 6bc4e296dd..0000000000 --- a/sql/mysql/Oracle/CSharp/StackQueue.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Collections; -using System.Collections.Generic; - -public class StackQueue : IEnumerable -{ - private readonly List _items; - - public StackQueue() - { - _items = new List(); - } - - public StackQueue(T value) - { - _items = new List(); - _items.Add(value); - } - - public StackQueue(StackQueue other) - { - _items = new List(); - _items.AddRange(other._items); - } - - public virtual int Size() - { - return _items.Count; - } - - public virtual int Count => _items.Count; - - public virtual T Pop() - { - if (_items.Count > 0) - { - var result = _items[_items.Count - 1]; - _items.RemoveAt(_items.Count - 1); - return result; - } - else return default; - } - - public virtual T this[int n] - { - get => PeekBottom(n); - set => _items[n] = value; - } - - public virtual T Peek() - { - return PeekTop(0); - } - - public bool Any() - { - return _items.Count > 0; - } - - public virtual T PeekTop(int n = 0) - { - if (_items.Count - n > 0) - { - int index = _items.Count - n - 1; - var result = _items[index]; - return result; - } - else return default; - } - - public virtual T PeekBottom(int n) - { - if (n >= 0 && n < _items.Count - 1) - { - var result = _items[n]; - return result; - } - else return default; - } - - public virtual void Push(T value) - { - _items.Add(value); - } - - public virtual void Push(IEnumerable collection) - { - foreach (T t in collection) - { - _items.Add(t); - } - } - - public virtual void PushMultiple(params T[] values) - { - int count = values.Length; - for (int i = 0; i < count; i++) _items.Add(values[i]); - } - - public virtual void EnqueueTop(T value) - { - Push(value); - } - - public virtual void EnqueueBottom(T value) - { - _items.Insert(0, value); - } - - public virtual T DequeueTop() - { - return Pop(); - } - - public virtual T DequeueBottom() - { - if (_items.Count > 0) - { - var result = _items[0]; - _items.RemoveAt(0); - return result; - } - else return default; - } - - public virtual bool Contains(T item) - { - return _items.Contains(item); - } - - public virtual System.Collections.Generic.IEnumerator GetEnumerator() - { - for (int i = _items.Count - 1; i >= 0; i--) - yield return _items[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (int i = _items.Count - 1; i >= 0; i--) - yield return _items[i]; - } -} diff --git a/sql/mysql/Oracle/CSharp/Test.cs b/sql/mysql/Oracle/CSharp/Test.cs deleted file mode 100644 index 5c4636221c..0000000000 --- a/sql/mysql/Oracle/CSharp/Test.cs +++ /dev/null @@ -1,483 +0,0 @@ -// Generated from trgen 0.23.7 - -using Antlr4.Runtime; -using Antlr4.Runtime.Atn; -using Antlr4.Runtime.Tree; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -public class Program -{ - public static MySQLParser Parser { get; set; } - public static ErrorListener ParserErrorListener { get; set; } - public static MySQLLexer Lexer { get; set; } - public static ErrorListener LexerErrorListener { get; set; } - public static ITokenStream TokenStream { get; set; } - public static ICharStream CharStream { get; set; } - public static IParseTree Tree { get; set; } - public static List Trees { get; set; } - public static string StartSymbol { get; set; } = "queries"; - public static string Input { get; set; } - public static bool HeatMap { get; set; } = false; - public static void SetupParse2(string input, bool quiet = false) - { - ICharStream str = new AntlrInputStream(input); - CharStream = str; - var lexer = new MySQLLexer(str); - lexer.serverVersion = 80200; - lexer.sqlModeFromString("ANSI_QUOTES"); - Lexer = lexer; - CommonTokenStream tokens = null; - if (HeatMap) { - tokens = new ProfilingCommonTokenStream(lexer); - } - else { - tokens = new CommonTokenStream(lexer); - } - TokenStream = tokens; - var parser = new MyParser(tokens); - parser.serverVersion = lexer.serverVersion; - parser.sqlModes = lexer.sqlModes; - Parser = parser; - var listener_lexer = new ErrorListener(false, false, System.Console.Error); - var listener_parser = new ErrorListener(false, false, System.Console.Error); - LexerErrorListener = listener_lexer; - ParserErrorListener = listener_parser; - lexer.RemoveErrorListeners(); - parser.RemoveErrorListeners(); - lexer.AddErrorListener(listener_lexer); - parser.AddErrorListener(listener_parser); - } - - public static IParseTree Parse2() - { - var tree = Parser.queries(); - Input = Lexer.InputStream.ToString(); - TokenStream = Parser.TokenStream; - Tree = tree; - return tree; - } - - public static List>> Parse3() - { - Parser.Profile = true; - var tree = Parser.queries(); - var decisions = Parser.ParseInfo.getDecisionInfo().Where(d => d.ambiguities.Any()).ToList(); - var result = new List>>(); - foreach (var decision in decisions) - { - var am = decision.ambiguities; - var trees = new List(); - foreach (AmbiguityInfo ai in am) - { - var parser_decision = ai.decision; - var parser_alts = ai.ambigAlts; - var parser_startIndex = ai.startIndex; - var parser_stopIndex = ai.stopIndex; - var p = Parser.RuleNames.Select((value, index) => new { value, index }) - .Where(pair => (pair.value == "queries")) - .Select(pair => pair.index).First(); - var parser_startRuleIndex = p; - var parser_trees = ((MyParser)Parser).getAllPossibleParseTrees( - parser_decision, - parser_alts, - parser_startIndex, - parser_stopIndex, - parser_startRuleIndex); - trees.AddRange(parser_trees); - } - result.Add(new Tuple>(decision.decision, trees)); - } - Input = Lexer.InputStream.ToString(); - TokenStream = Parser.TokenStream; - return result; - } - - public static bool AnyErrors() - { - return ParserErrorListener.had_error || LexerErrorListener.had_error; - } - - public static IParseTree Parse(string input) - { - ICharStream str = new AntlrInputStream(input); - CharStream = str; - var lexer = new MySQLLexer(str); - lexer.serverVersion = 80200; - lexer.sqlModeFromString("ANSI_QUOTES"); - Lexer = lexer; - CommonTokenStream tokens = null; - if (show_hit) { - tokens = new ProfilingCommonTokenStream(lexer); - } - else { - tokens = new CommonTokenStream(lexer); - } - TokenStream = tokens; - var parser = new MySQLParser(tokens); - parser.serverVersion = lexer.serverVersion; - parser.sqlModes = lexer.sqlModes; - Parser = parser; - var listener_lexer = new ErrorListener(false, false, System.Console.Error); - var listener_parser = new ErrorListener(false, false, System.Console.Error); - lexer.RemoveErrorListeners(); - parser.RemoveErrorListeners(); - lexer.AddErrorListener(listener_lexer); - parser.AddErrorListener(listener_parser); - var tree = parser.queries(); - Input = lexer.InputStream.ToString(); - TokenStream = parser.TokenStream; - Tree = tree; - return tree; - } - - static bool tee = false; - static bool show_diagnostic = false; - static bool show_hit = false; - static bool show_ambig = false; - static bool show_profile = false; - static bool show_tokens = false; - static bool show_trace = false; - static bool show_tree = false; - static bool old = false; - static bool two_byte = false; - static int exit_code = 0; - static Encoding encoding = null; - static int string_instance = 0; - static string prefix = ""; - static bool quiet = false; - - static void Main(string[] args) - { - List is_fns = new List(); - List inputs = new List(); - for (int i = 0; i < args.Length; ++i) - { - if (args[i] == "-d") - { - show_diagnostic = true; - } - else if (args[i] == "-ambig") - { - show_ambig = true; - } - else if (args[i] == "-profile") - { - show_profile = true; - } - else if (args[i] == "-tokens") - { - show_tokens = true; - } - else if (args[i] == "-two-byte") - { - two_byte = true; - } - else if (args[i] == "-old") - { - old = true; - } - else if (args[i] == "-tree") - { - show_tree = true; - } - else if (args[i] == "-prefix") - { - prefix = args[++i] + " "; - } - else if (args[i] == "-input") - { - inputs.Add(args[++i]); - is_fns.Add(false); - } - else if (args[i] == "-tee") - { - tee = true; - } - else if (args[i] == "-encoding") - { - ++i; - encoding = Encoding.GetEncoding( - args[i], - new EncoderReplacementFallback("(unknown)"), - new DecoderReplacementFallback("(error)")); - if (encoding == null) - throw new Exception(@"Unknown encoding. Must be an Internet Assigned Numbers Authority (IANA) code page name. https://www.iana.org/assignments/character-sets/character-sets.xhtml"); - } - else if (args[i] == "-x") - { - for (; ; ) - { - var line = System.Console.In.ReadLine(); - line = line?.Trim(); - if (line == null || line == "") - { - break; - } - inputs.Add(line); - is_fns.Add(true); - } - } - else if (args[i] == "-q") - { - quiet = true; - } - else if (args[i] == "-trace") - { - show_trace = true; - } - else - { - inputs.Add(args[i]); - is_fns.Add(true); - } - } - if (inputs.Count() == 0) - { - ParseStdin(); - } - else - { - DateTime before = DateTime.Now; - for (int f = 0; f < inputs.Count(); ++f) - { - if (is_fns[f]) - ParseFilename(inputs[f], f); - else - ParseString(inputs[f], f); - } - DateTime after = DateTime.Now; - if (!quiet) System.Console.Error.WriteLine("Total Time: " + (after - before).TotalSeconds); - } - Environment.ExitCode = exit_code; - } - - static void ParseStdin() - { - ICharStream str = null; - str = CharStreams.fromStream(System.Console.OpenStandardInput()); - DoParse(str, "stdin", 0); - } - - static void ParseString(string input, int row_number) - { - ICharStream str = null; - str = CharStreams.fromString(input); - DoParse(str, "string" + string_instance++, row_number); - } - - static void ParseFilename(string input, int row_number) - { - ICharStream str = null; - if (two_byte) - str = new TwoByteCharStream(input); - else if (old) - { - FileStream fs = new FileStream(input, FileMode.Open); - str = new Antlr4.Runtime.AntlrInputStream(fs); - } - else if (encoding == null) - str = CharStreams.fromPath(input); - else - str = CharStreams.fromPath(input, encoding); - DoParse(str, input, row_number); - } - - static void DoParse(ICharStream str, string input_name, int row_number) - { - var lexer = new MySQLLexer(str); - lexer.serverVersion = 80200; - lexer.sqlModeFromString("ANSI_QUOTES"); - if (show_tokens) - { - StringBuilder new_s = new StringBuilder(); - for (int i = 0; ; ++i) - { - var ro_token = lexer.NextToken(); - var token = (CommonToken)ro_token; - token.TokenIndex = i; - new_s.AppendLine(token.ToString()); - if (token.Type == Antlr4.Runtime.TokenConstants.EOF) - break; - } - System.Console.Error.WriteLine(new_s.ToString()); - lexer.Reset(); - } - CommonTokenStream tokens = null; - if (show_hit) { - tokens = new ProfilingCommonTokenStream(lexer); - } - else { - tokens = new CommonTokenStream(lexer); - } - var parser = new MyParser(tokens); - parser.serverVersion = lexer.serverVersion; - parser.sqlModes = lexer.sqlModes; - var output = tee ? new StreamWriter(input_name + ".errors") : System.Console.Error; - var listener_lexer = new ErrorListener(quiet, tee, output); - var listener_parser = new ErrorListener(quiet, tee, output); - lexer.RemoveErrorListeners(); - parser.RemoveErrorListeners(); - lexer.AddErrorListener(listener_lexer); - parser.AddErrorListener(listener_parser); - if (show_diagnostic) - { - parser.AddErrorListener(new MyDiagnosticErrorListener()); - } - if (show_profile || show_ambig) - { - parser.Profile = true; - } - if (show_trace) - { - parser.Trace = true; -// ParserATNSimulator.trace_atn_sim = true; - } - DateTime before = DateTime.Now; - var tree = parser.queries(); - DateTime after = DateTime.Now; - var result = ""; - if (listener_lexer.had_error || listener_parser.had_error) - { - result = "fail"; - exit_code = 1; - } - else - { - result = "success"; - } - if (show_tree) - { - if (tee) - { - System.IO.File.WriteAllText(input_name + ".tree", tree.ToStringTree(parser)); - } else { - System.Console.Error.WriteLine(tree.ToStringTree(parser)); - } - } - if (show_profile) - { - System.Console.Error.WriteLine(String.Join(",\n\r", parser.ParseInfo.getDecisionInfo().Select(d => d.ToString()))); - } - if (show_ambig) - { - var decs = parser.ParseInfo.getDecisionInfo().Where(d => - d.ambiguities.Any()).Select(d => d.ambiguities).ToList(); - foreach (var decision in decs) - { - foreach (var ai in decision) - { - var parser_decision = ai.decision; - var parser_alts = ai.ambigAlts; - var parser_startIndex = ai.startIndex; - var parser_stopIndex = ai.stopIndex; - var nfa_state = parser.Atn.states.Where(s => - { - if (s is BasicBlockStartState s2) return s2.decision == parser_decision; - else return false; - }).ToList(); - var p = parser.RuleNames.Select((value, index) => new { value, index }) - .Where(pair => (pair.value == "queries")) - .Select(pair => pair.index).First(); - var parser_startRuleIndex = p; - var parser_trees = parser.getAllPossibleParseTrees( - parser_decision, - parser_alts, - parser_startIndex, - parser_stopIndex, - parser_startRuleIndex); - foreach (var parser_tree in parser_trees) - { - System.Console.WriteLine(parser_tree.ToStringTree(parser)); - System.Console.WriteLine(); - } - } - } - } - if (!quiet) - { - System.Console.Error.WriteLine(prefix + "CSharp " + row_number + " " + input_name + " " + result + " " + (after - before).TotalSeconds); - } - if (tee) output.Close(); - } - - public static string ToStringTree(ITree tree, Parser recog) - { - StringBuilder sb = new StringBuilder(); - string[] ruleNames = recog != null ? recog.RuleNames : null; - IList ruleNamesList = ruleNames != null ? ruleNames.ToList() : null; - ToStringTree(sb, tree, 0, ruleNamesList); - return sb.ToString(); - } - - public static void ToStringTree(StringBuilder sb, ITree t, int indent, IList ruleNames) - { - string s = Antlr4.Runtime.Misc.Utils.EscapeWhitespace(GetNodeText(t, ruleNames), false); - if (t.ChildCount == 0) - { - for (int i = 0; i < indent; ++i) sb.Append(" "); - sb.AppendLine(s); - return; - } - s = Antlr4.Runtime.Misc.Utils.EscapeWhitespace(GetNodeText(t, ruleNames), false); - for (int i = 0; i < indent; ++i) sb.Append(' '); - sb.AppendLine(s); - for (int i = 0; i < t.ChildCount; i++) - { - ToStringTree(sb, t.GetChild(i), indent+1, ruleNames); - } - } - - public static string GetNodeText(ITree t, Parser recog) - { - string[] ruleNames = recog != null ? recog.RuleNames : null; - IList ruleNamesList = ruleNames != null ? ruleNames.ToList() : null; - return GetNodeText(t, ruleNamesList); - } - - public static string GetNodeText(ITree t, IList ruleNames) - { - if (ruleNames != null) - { - if (t is RuleContext) - { - int ruleIndex = ((RuleContext)t).RuleIndex; - string ruleName = ruleNames[ruleIndex]; - int altNumber = ((RuleContext)t).getAltNumber(); - if ( altNumber!= Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { - return ruleName+":"+altNumber; - } - return ruleName; - } - else - { - if (t is IErrorNode) - { - return t.ToString(); - } - else - { - if (t is ITerminalNode) - { - IToken symbol = ((ITerminalNode)t).Symbol; - if (symbol != null) - { - string s = symbol.Text; - return s; - } - } - } - } - } - // no recog for rule names - object payload = t.Payload; - if (payload is IToken) - { - return ((IToken)payload).Text; - } - return t.Payload.ToString(); - } -} - diff --git a/sql/mysql/Oracle/Dart/MySQLLexerBase.dart b/sql/mysql/Oracle/Dart/MySQLLexerBase.dart new file mode 100644 index 0000000000..7544f31ab0 --- /dev/null +++ b/sql/mysql/Oracle/Dart/MySQLLexerBase.dart @@ -0,0 +1,387 @@ +import 'package:antlr4/antlr4.dart'; +import 'dart:io'; +import 'dart:core'; +import 'dart:convert'; +import 'dart:collection'; +import 'MySQLLexer.dart'; +import 'MySQLParser.dart'; + +/** SQL modes that control parsing behavior. */ +enum SqlMode { + noMode, + ansiQuotes, + highNotPrecedence, + pipesAsConcat, + ignoreSpace, + noBackslashEscapes, +} + +/** Base lexer class providing functions needed in actions. */ +abstract class MySQLLexerBase extends Lexer +{ + int serverVersion = 0; + Set sqlModes = {}; + bool supportMle = true; + Set charSets = {}; + bool inVersionComment = false; + Queue pendingTokens = Queue(); + + static const String longString = "2147483647"; + static const int longLength = 10; + static const String signedLongString = "-2147483648"; + static const String longLongString = "9223372036854775807"; + static const int longLongLength = 19; + static const String signedLongLongString = "-9223372036854775808"; + static const int signedLongLongLength = 19; + static const String unsignedLongLongString = "18446744073709551615"; + static const int unsignedLongLongLength = 20; + + bool justEmitedDot = false; + + MySQLLexerBase(CharStream input) : super(input) + { + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); + } + + bool isSqlModeActive(SqlMode mode) { + return sqlModes.contains(mode); + } + + void sqlModeFromString(String modes) { + sqlModes.clear(); + List parts = modes.toUpperCase().split(','); + + for (String mode in parts) { + if (['ANSI', 'DB2', 'MAXDB', 'MSSQL', 'ORACLE', 'POSTGRESQL'] + .contains(mode)) { + sqlModes.add(SqlMode.ansiQuotes); + sqlModes.add(SqlMode.pipesAsConcat); + sqlModes.add(SqlMode.ignoreSpace); + } else if (mode == 'ANSI_QUOTES') { + sqlModes.add(SqlMode.ansiQuotes); + } else if (mode == 'PIPES_AS_CONCAT') { + sqlModes.add(SqlMode.pipesAsConcat); + } else if (mode == 'NO_BACKSLASH_ESCAPES') { + sqlModes.add(SqlMode.noBackslashEscapes); + } else if (mode == 'IGNORE_SPACE') { + sqlModes.add(SqlMode.ignoreSpace); + } else if (['HIGH_NOT_PRECEDENCE', 'MYSQL323', 'MYSQL40'] + .contains(mode)) { + sqlModes.add(SqlMode.highNotPrecedence); + } + } + } + + /** + * Resets the lexer by setting initial values to transient member, resetting the input stream position etc. + */ + @override void reset([bool resetInput = false]) + { + inVersionComment = false; + super.reset(true); // reset() needs to follow the semantics in other targets! + } + + /** + * Implements the multi token feature required in our lexer. + * A lexer rule can emit more than a single token, if needed. + * + * @returns The next token in the token stream. + */ + @override Token nextToken() + { + // First respond with pending tokens to the next token request, if there are any. + if (! this.pendingTokens.isEmpty) { + var pending = this.pendingTokens.removeFirst(); + return pending; + } + + // Let the main lexer class run the next token recognition. + // This might create additional tokens again. + var next = super.nextToken(); + + if (! this.pendingTokens.isEmpty) { + var pending = this.pendingTokens.removeFirst(); + this.pendingTokens.add(next); + return pending; + } + + return next; + } + + /** + * Checks if the version number in the token text is less than or equal to the current server version. + * + * @param text The text from a matched token. + * @returns True if so the number matches, otherwise false. + */ + bool checkMySQLVersion(String text) { + if (text.length < 8) { + return false; + } + + int version = int.parse(text.substring(3)); + if (version <= serverVersion) { + inVersionComment = true; + return true; + } + + return false; + } + + /** + * Called when a keyword was consumed that represents an internal MySQL function and checks if that keyword is + * followed by an open parenthesis. If not then it is not considered a keyword but treated like a normal identifier. + * + * @param proposed The token type to use if the check succeeds. + * + * @returns If a function call is found then return the proposed token type, otherwise just IDENTIFIER. + */ + int determineFunction(int proposed) { + var input = this.inputStream.LA(1) ?? 0; + if (isSqlModeActive(SqlMode.ignoreSpace)) { + while ([' ', '\t', '\r', '\n'].contains(String.fromCharCode(input))) { + // Consume logic based on InputStream equivalent. + this.interpreter?.consume(this.inputStream); + this.channel = Lexer.HIDDEN; + this.type = MySQLLexer.TOKEN_WHITESPACE; + var c = this.inputStream.LA(1); + input = c ?? 0; + } + } + var r = input == '('.codeUnitAt(0) ? proposed : MySQLLexer.TOKEN_IDENTIFIER; + return r; + } + + /** + * Checks the given text and determines the smallest number type from it. Code has been taken from sql_lex.cc. + * + * @param text The text to parse (which must be a number). + * + * @returns The token type for that text. + */ + int determineNumericType(String text) + { + // The original code checks for leading +/- but actually that can never happen, neither in the + // server parser (as a digit is used to trigger processing in the lexer) nor in our parser + // as our rules are defined without signs. But we do it anyway for maximum compatibility. + var length = text.length - 1; + if (length < MySQLLexerBase.longLength) { // quick normal case + return MySQLLexer.TOKEN_INT_NUMBER; + } + + var negative = false; + var index = 0; + if (text[index] == '+') { // Remove sign and pre-zeros + ++index; + --length; + } else if (text[index] == '-') { + ++index; + --length; + negative = true; + } + + while (text[index] == '0' && length > 0) { + ++index; + --length; + } + + if (length < MySQLLexerBase.longLength) { + return MySQLLexer.TOKEN_INT_NUMBER; + } + + int smaller; + int bigger; + String cmp; + if (negative) { + if (length == MySQLLexerBase.longLength) { + cmp = MySQLLexerBase.signedLongString.substring(1); + smaller = MySQLLexer.TOKEN_INT_NUMBER; // If <= signed_long_str + bigger = MySQLLexer.TOKEN_LONG_NUMBER; // If >= signed_long_str + } else if (length < MySQLLexerBase.signedLongLongLength) { + return MySQLLexer.TOKEN_LONG_NUMBER; + } else if (length > MySQLLexerBase.signedLongLongLength) { + return MySQLLexer.TOKEN_DECIMAL_NUMBER; + } else { + cmp = MySQLLexerBase.signedLongLongString.substring(1); + smaller = MySQLLexer.TOKEN_LONG_NUMBER; // If <= signed_longlong_str + bigger = MySQLLexer.TOKEN_DECIMAL_NUMBER; + } + } else { + if (length == MySQLLexerBase.longLength) { + cmp = MySQLLexerBase.longString; + smaller = MySQLLexer.TOKEN_INT_NUMBER; + bigger = MySQLLexer.TOKEN_LONG_NUMBER; + } else if (length < MySQLLexerBase.longLongLength) { + return MySQLLexer.TOKEN_LONG_NUMBER; + } else if (length > MySQLLexerBase.longLongLength) { + if (length > MySQLLexerBase.unsignedLongLongLength) { + return MySQLLexer.TOKEN_DECIMAL_NUMBER; + } + cmp = MySQLLexerBase.unsignedLongLongString; + smaller = MySQLLexer.TOKEN_ULONGLONG_NUMBER; + bigger = MySQLLexer.TOKEN_DECIMAL_NUMBER; + } else { + cmp = MySQLLexerBase.longLongString; + smaller = MySQLLexer.TOKEN_LONG_NUMBER; + bigger = MySQLLexer.TOKEN_ULONGLONG_NUMBER; + } + } + + var otherIndex = 0; + while (index < text.length && cmp[otherIndex++] == text[index++]) { + // + } + + var i = text[index - 1].compareTo(cmp[otherIndex - 1]); + return i <= 0 ? smaller : bigger; + } + + /** + * Checks if the given text corresponds to a charset defined in the server (text is preceded by an underscore). + * + * @param text The text to check. + * + * @returns UNDERSCORE_CHARSET if so, otherwise IDENTIFIER. + */ + int checkCharset(String text) + { + var z = this.charSets.contains(text); + var r = z ? MySQLLexer.TOKEN_UNDERSCORE_CHARSET : MySQLLexer.TOKEN_IDENTIFIER; + return r; + } + + /** + * Creates a DOT token in the token stream. + */ + void emitDot() + { + var ctf = this.tokenFactory; + Token t = ctf.create( + MySQLLexer.TOKEN_DOT_SYMBOL, + this.text, + Pair(this, this.inputStream), + this.channel, + this.tokenStartCharIndex, + this.tokenStartCharIndex, + this.line, + this.charPositionInLine); + this.pendingTokens.add(t); + ++this.charPositionInLine; + ++this.tokenStartCharIndex; + this.justEmitedDot = true; + } + + // Version-related methods + bool isServerVersionLt80024() => serverVersion < 80024; + bool isServerVersionGe80024() => serverVersion >= 80024; + bool isServerVersionGe80011() => serverVersion >= 80011; + bool isServerVersionGe80013() => serverVersion >= 80013; + bool isServerVersionLt80014() => serverVersion < 80014; + bool isServerVersionGe80014() => serverVersion >= 80014; + bool isServerVersionGe80017() => serverVersion >= 80017; + bool isServerVersionGe80018() => serverVersion >= 80018; + + bool isMasterCompressionAlgorithm() => serverVersion >= 80018 && isServerVersionLt80024(); + + bool isServerVersionLt80031() => serverVersion < 80031; + + // Functions for specific token types + void doLogicalOr() + { + this.type = isSqlModeActive(SqlMode.pipesAsConcat) ? MySQLLexer.TOKEN_CONCAT_PIPES_SYMBOL : MySQLLexer.TOKEN_LOGICAL_OR_OPERATOR; + } + + void doIntNumber() + { + this.type = determineNumericType(this.text); + } + + void doAdddate() => this.type = determineFunction(MySQLLexer.TOKEN_ADDDATE_SYMBOL); + void doBitAnd() => this.type = determineFunction(MySQLLexer.TOKEN_BIT_AND_SYMBOL); + void doBitOr() => this.type = determineFunction(MySQLLexer.TOKEN_BIT_OR_SYMBOL); + void doBitXor() => this.type = determineFunction(MySQLLexer.TOKEN_BIT_XOR_SYMBOL); + void doCast() => this.type = determineFunction(MySQLLexer.TOKEN_CAST_SYMBOL); + void doCount() => this.type = determineFunction(MySQLLexer.TOKEN_COUNT_SYMBOL); + void doCurdate() => this.type = determineFunction(MySQLLexer.TOKEN_CURDATE_SYMBOL); + void doCurrentDate() => this.type = determineFunction(MySQLLexer.TOKEN_CURDATE_SYMBOL); + void doCurrentTime() => this.type = determineFunction(MySQLLexer.TOKEN_CURTIME_SYMBOL); + void doCurtime() => this.type = determineFunction(MySQLLexer.TOKEN_CURTIME_SYMBOL); + void doDateAdd() => this.type = determineFunction(MySQLLexer.TOKEN_DATE_ADD_SYMBOL); + void doDateSub() => this.type = determineFunction(MySQLLexer.TOKEN_DATE_SUB_SYMBOL); + void doExtract() => this.type = determineFunction(MySQLLexer.TOKEN_EXTRACT_SYMBOL); + void doGroupConcat() => this.type = determineFunction(MySQLLexer.TOKEN_GROUP_CONCAT_SYMBOL); + void doMax() => this.type = determineFunction(MySQLLexer.TOKEN_MAX_SYMBOL); + void doMid() => this.type = determineFunction(MySQLLexer.TOKEN_SUBSTRING_SYMBOL); + void doMin() => this.type = determineFunction(MySQLLexer.TOKEN_MIN_SYMBOL); + void doNot() => this.type = isSqlModeActive(SqlMode.highNotPrecedence) ? MySQLLexer.TOKEN_NOT2_SYMBOL : MySQLLexer.TOKEN_NOT_SYMBOL; + void doNow() => this.type = determineFunction(MySQLLexer.TOKEN_NOW_SYMBOL); + void doPosition() => this.type = determineFunction(MySQLLexer.TOKEN_POSITION_SYMBOL); + void doSessionUser() => this.type = determineFunction(MySQLLexer.TOKEN_USER_SYMBOL); + void doStddevSamp() => this.type = determineFunction(MySQLLexer.TOKEN_STDDEV_SAMP_SYMBOL); + void doStddev() => this.type = determineFunction(MySQLLexer.TOKEN_STD_SYMBOL); + void doStddevPop() => this.type = determineFunction(MySQLLexer.TOKEN_STD_SYMBOL); + void doStd() => this.type = determineFunction(MySQLLexer.TOKEN_STD_SYMBOL); + void doSubdate() => this.type = determineFunction(MySQLLexer.TOKEN_SUBDATE_SYMBOL); + void doSubstr() => this.type = determineFunction(MySQLLexer.TOKEN_SUBSTRING_SYMBOL); + void doSubstring() => this.type = determineFunction(MySQLLexer.TOKEN_SUBSTRING_SYMBOL); + void doSum() => this.type = determineFunction(MySQLLexer.TOKEN_SUM_SYMBOL); + void doSysdate() => this.type = determineFunction(MySQLLexer.TOKEN_SYSDATE_SYMBOL); + void doSystemUser() => this.type = determineFunction(MySQLLexer.TOKEN_USER_SYMBOL); + void doTrim() => this.type = determineFunction(MySQLLexer.TOKEN_TRIM_SYMBOL); + void doVariance() => this.type = determineFunction(MySQLLexer.TOKEN_VARIANCE_SYMBOL); + void doVarPop() => this.type = determineFunction(MySQLLexer.TOKEN_VARIANCE_SYMBOL); + void doVarSamp() => this.type = determineFunction(MySQLLexer.TOKEN_VAR_SAMP_SYMBOL); + void doUnderscoreCharset() => this.type = checkCharset(this.text); + + bool isVersionComment() => checkMySQLVersion(this.text); + + bool isBackTickQuotedId() + { + return !this.isSqlModeActive(SqlMode.noBackslashEscapes); + } + + bool isDoubleQuotedText() + { + return !this.isSqlModeActive(SqlMode.noBackslashEscapes); + } + + bool isSingleQuotedText() + { + return !this.isSqlModeActive(SqlMode.noBackslashEscapes); + } + +/* + @override Token emit() + { + var ctf = this.tokenFactory; + Token t = ctf.create( + this.type, + (this.text!=null?(this.justEmitedDot?this.text.substring(1):this.text):null), + Pair(this, this.inputStream), + this.channel, + this.tokenStartCharIndex + (this.justEmitedDot?1:0), + CharIndex - 1, + this.line, + this.charPositionInLine); + this.justEmitedDot = false; + super.emit(t); + return t; + } +*/ + + void startInVersionComment() + { + inVersionComment = true; + } + + void endInVersionComment() + { + inVersionComment = false; + } + + bool isInVersionComment() + { + return inVersionComment; + } +} diff --git a/sql/mysql/Oracle/Dart/MySQLParserBase.dart b/sql/mysql/Oracle/Dart/MySQLParserBase.dart new file mode 100644 index 0000000000..47f1c61b8f --- /dev/null +++ b/sql/mysql/Oracle/Dart/MySQLParserBase.dart @@ -0,0 +1,82 @@ +import 'package:antlr4/antlr4.dart'; +import 'dart:io'; +import 'dart:core'; +import 'dart:convert'; +import 'dart:collection'; +import 'MySQLLexer.dart'; +import 'MySQLParser.dart'; + +/** SQL modes that control parsing behavior. */ +enum SqlMode { + noMode, + ansiQuotes, + highNotPrecedence, + pipesAsConcat, + ignoreSpace, + noBackslashEscapes, +} + +/** Base parser class for MySQL parsing. */ +abstract class MySQLParserBase extends Parser { + + // To parameterize the parsing process. + int serverVersion = 0; + Set sqlModes = {}; + bool supportMle = true; + + MySQLParserBase(TokenStream input) : super(input) + { + this.serverVersion = 80200; + this.sqlModeFromString("ANSI_QUOTES"); + } + + /// Determines if the given SQL mode is currently active. + bool isSqlModeActive(SqlMode mode) { + return sqlModes.contains(mode); + } + + /// Checks if the parser is in pure identifier mode. + bool isPureIdentifier() { + return isSqlModeActive(SqlMode.ansiQuotes); + } + + /// Checks if the parser is in text string literal mode. + bool isTextStringLiteral() { + return !isSqlModeActive(SqlMode.ansiQuotes); + } + + /// Checks if the parser is handling a stored routine body. + bool isStoredRoutineBody() { + return serverVersion >= 80032 && supportMle; + } + + /// Checks if the parser is handling a SELECT statement with INTO clause. + bool isSelectStatementWithInto() { + return serverVersion >= 80024 && serverVersion < 80031; + } + + void sqlModeFromString(String modes) { + sqlModes.clear(); + List parts = modes.toUpperCase().split(','); + + for (String mode in parts) { + if (['ANSI', 'DB2', 'MAXDB', 'MSSQL', 'ORACLE', 'POSTGRESQL'] + .contains(mode)) { + sqlModes.add(SqlMode.ansiQuotes); + sqlModes.add(SqlMode.pipesAsConcat); + sqlModes.add(SqlMode.ignoreSpace); + } else if (mode == 'ANSI_QUOTES') { + sqlModes.add(SqlMode.ansiQuotes); + } else if (mode == 'PIPES_AS_CONCAT') { + sqlModes.add(SqlMode.pipesAsConcat); + } else if (mode == 'NO_BACKSLASH_ESCAPES') { + sqlModes.add(SqlMode.noBackslashEscapes); + } else if (mode == 'IGNORE_SPACE') { + sqlModes.add(SqlMode.ignoreSpace); + } else if (['HIGH_NOT_PRECEDENCE', 'MYSQL323', 'MYSQL40'] + .contains(mode)) { + sqlModes.add(SqlMode.highNotPrecedence); + } + } + } +} diff --git a/sql/mysql/Oracle/Java/MySQLLexerBase.java b/sql/mysql/Oracle/Java/MySQLLexerBase.java index c020d4a162..fc6f7ae4a3 100644 --- a/sql/mysql/Oracle/Java/MySQLLexerBase.java +++ b/sql/mysql/Oracle/Java/MySQLLexerBase.java @@ -25,7 +25,7 @@ public MySQLLexerBase(CharStream input) { public Set charSets = new HashSet<>(); // Used to check repertoires. protected boolean inVersionComment = false; - private Deque pendingTokens = new ArrayDeque<>(); + private Queue pendingTokens = new LinkedList<>(); static String longString = "2147483647"; static int longLength = 10; @@ -100,16 +100,16 @@ public void reset() { @Override public Token nextToken() { - Token pending = pendingTokens.pollLast(); + Token pending = pendingTokens.poll(); if (pending != null) { return pending; } Token next = super.nextToken(); - pending = pendingTokens.pollLast(); + pending = pendingTokens.poll(); if (pending != null) { - pendingTokens.push(next); + pendingTokens.add(next); return pending; } @@ -218,7 +218,7 @@ protected int checkCharset(String text) { } protected void emitDot() { - pendingTokens.push(this._factory.create(this._tokenFactorySourcePair, MySQLLexer.DOT_SYMBOL, + pendingTokens.add(this._factory.create(this._tokenFactorySourcePair, MySQLLexer.DOT_SYMBOL, this.getText(), this._channel, this._tokenStartCharIndex, this._tokenStartCharIndex, this.getLine(), this.getCharPositionInLine())); ++this._tokenStartCharPositionInLine; this.justEmitedDot = true; diff --git a/sql/mysql/Oracle/desc.xml b/sql/mysql/Oracle/desc.xml index 5819861f41..78656ebb33 100644 --- a/sql/mysql/Oracle/desc.xml +++ b/sql/mysql/Oracle/desc.xml @@ -1,5 +1,5 @@ - Antlr4ng;CSharp;Java;Python3;TypeScript + Antlr4ng;CSharp;Dart;Java;Python3;TypeScript examples/**/*.sql