- fcl-db: sql parser

- remove support for SET TERM/SET AUTODDL as it does not fall within Firebird SQL

git-svn-id: trunk@27961 -
This commit is contained in:
reiniero 2014-06-15 09:10:24 +00:00
parent d7f9265eba
commit 951d128042
4 changed files with 8 additions and 277 deletions

View File

@ -101,8 +101,6 @@ Type
function ParseCreateViewStatement(AParent: TSQLElement; IsAlter: Boolean): TSQLCreateOrAlterStatement;
function ParseCreateTriggerStatement(AParent: TSQLElement; IsAlter: Boolean): TSQLCreateOrAlterStatement;
function ParseSetGeneratorStatement(AParent: TSQLElement) : TSQLSetGeneratorStatement;
function ParseSetISQLStatement(AParent: TSQLElement) : TSQLSetISQLStatement;
function ParseSetTermStatement(AParent: TSQLElement) : TSQLSetTermStatement;
function ParseCreateDatabaseStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateDatabaseStatement;
function ParseCreateShadowStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateShadowStatement;
function ParseAlterDatabaseStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLAlterDatabaseStatement;
@ -163,12 +161,6 @@ Type
Function Parse : TSQLElement;
// Parse script containing 1 or more elements
Function ParseScript(AllowPartial : Boolean = False) : TSQLElementList;
// Gets statement terminator (as e.g. used in SET TERM) so statements like
// EXECUTE BLOCK or CREATE PROCEDURE that contain semicolons can be parsed
function GetStatementTerminator: string;
// Sets statement terminator (as e.g. used in SET TERM) so statements like
// EXECUTE BLOCK or CREATE PROCEDURE that contain semicolons can be parsed
procedure SetStatementTerminator(AValue: string);
// Auxiliary stuff
Function CurrentToken : TSQLToken;
Function CurrentTokenString : String;
@ -1522,7 +1514,7 @@ begin
S:=ParseProcedureStatement(AParent);
Statements.Add(S);
if not (PreviousToken=tsqlEnd) then
Consume([tsqlSemicolon,tsqlStatementTerminator]);
Consume([tsqlSemicolon]);
end;
Consume(tsqlEnd);
end;
@ -2981,74 +2973,6 @@ begin
end;
end;
function TSQLParser.ParseSetISQLStatement(AParent: TSQLElement
): TSQLSetISQLStatement;
begin
// On entry, we're on the first argument e.g. AUTODDL in SET AUTODDL
// for now, only support AutoDDL
//SET AUTODDL: ignore these isql commands for now
case CurrentToken of
tsqlAutoDDL:
begin
Result:=TSQLSetISQLStatement(CreateElement(TSQLSetISQLStatement,AParent));
// SET AUTODDL ON, SET AUTODDL OFF; optional arguments
if (PeekNextToken in [tsqlOn, tsqlOff]) then
begin
GetNextToken;
if CurrentToken=tsqlOFF then
Result.Arguments:='AUTODDL OFF'
else
Result.Arguments:='AUTODDL ON';
Consume([tsqlOn,tsqlOff]);
end
else
begin
Result.Arguments:='AUTODDL ON';
Consume(tsqlAutoDDL);
end;
end
else
UnexpectedToken;
end;
end;
function TSQLParser.ParseSetTermStatement(AParent: TSQLElement
): TSQLSetTermStatement;
var
ExistingStatTerm: string;
begin
// On entry, we're on the 'TERM' token
Consume(tsqlTerm) ;
try
Result:=TSQLSetTermStatement(CreateElement(TSQLSetTermStatement,AParent));
Expect([tsqlSemiColon,tsqlStatementTerminator,tsqlSymbolString,tsqlString]);
// Already set the expression's new value to the new terminator, but do not
// change tSQLStatementTerminator as GetNextToken etc need the old one to
// detect the closing terminator
case CurrentToken of
tsqlSemiColon, tsqlStatementTerminator: Result.NewTerminator:=TokenInfos[CurrentToken];
tsqlSymbolString, tsqlString: Result.NewTerminator:=CurrentTokenString;
end;
// Expect the old terminator...
GetNextToken;
// Parser will give tsqlSemicolon rather than tsqlStatementTerminator:
if TokenInfos[tsqlStatementTerminator]=TokenInfos[tsqlSEMICOLON] then
begin
Expect(tsqlSEMICOLON);
Result.OldTerminator:=TokenInfos[tsqlSEMICOLON];
end
else
begin
Expect(tsqlStatementTerminator);
Result.OldTerminator:=TokenInfos[tsqlStatementTerminator];
end;
//... and now set the new terminator:
TokenInfos[tsqlStatementTerminator]:=Result.NewTerminator; //process new terminator value
except
FreeAndNil(Result);
Raise;
end;
end;
function TSQLParser.ParseSecondaryFile(AParent: TSQLElement) : TSQLDatabaseFileInfo;
@ -3453,8 +3377,6 @@ begin
Consume(tsqlSet);
Case CurrentToken of
tsqlGenerator : Result:=ParseSetGeneratorStatement(AParent); //SET GENERATOR
tsqlTerm : Result:=ParseSetTermStatement(AParent); //SET TERM
tsqlAutoDDL : Result:=ParseSetISQLStatement(AParent); //SET AUTODDL
else
// For the time being
UnexpectedToken;
@ -3971,7 +3893,7 @@ begin
else
UnexpectedToken;
end;
if Not (CurrentToken in [tsqlEOF,tsqlSemicolon,tsqlStatementTerminator]) then
if Not (CurrentToken in [tsqlEOF,tsqlSemicolon]) then
begin
FreeAndNil(Result);
if (CurrentToken=tsqlBraceClose) then
@ -4003,16 +3925,6 @@ begin
end;
end;
function TSQLParser.GetStatementTerminator: string;
begin
result:=TokenInfos[tsqlStatementTerminator];
end;
procedure TSQLParser.SetStatementTerminator(AValue: string);
begin
TokenInfos[tsqlStatementTerminator]:=AValue;;
end;
function TSQLParser.CurrentToken: TSQLToken;
begin
Result:=FCurrent;

View File

@ -42,8 +42,6 @@ type
tsqlIdentifier {a table etc name},
tsqlSymbolString {a string containing symbols/punctuation marks; only rarely used - e.g. in SET TERM ^ ;},
tsqlIntegerNumber,tsqlFloatNumber,tsqlComment,
tsqlStatementTerminator {statement separator, usually semicolon but may be changed by code. For now, limited to semicolon and symbol literals not already defined like tsqlCOMMA.}
{todo: move this out of fpsqlscanner into fpsqlparser with an option to disable},
tsqlBraceOpen,tsqlBraceClose,tsqlSquareBraceOpen,tsqlSquareBraceClose,
tsqlPlaceHolder {question mark},
tsqlCOMMA,tsqlCOLON,tsqlDOT,tsqlSEMICOLON,
@ -51,7 +49,7 @@ type
tsqlEQ,tsqlGE,tsqlLE,tsqlNE,
{ Reserved words/keywords start here. They must be last }
{ Note: if adding before tsqlALL or after tsqlWHEN please update FirstKeyword/LastKeyword }
tsqlALL, tsqlAND, tsqlANY, tsqlASC, tsqlASCENDING, tsqlAVG, tsqlALTER, tsqlAdd, tsqlActive, tsqlAction, tsqlAs,tsqlAt, tsqlAuto, tsqlAutoDDL {not an FB reserved word but used in isql scripts}, tsqlAfter,tsqlAdmin,
tsqlALL, tsqlAND, tsqlANY, tsqlASC, tsqlASCENDING, tsqlAVG, tsqlALTER, tsqlAdd, tsqlActive, tsqlAction, tsqlAs,tsqlAt, tsqlAuto, tsqlAfter,tsqlAdmin,
tsqlBETWEEN, tsqlBinary, tsqlBY, tsqlBLOB, tsqlBegin, tsqlBefore,
tsqlCOLLATE, tsqlCONTAINING, tsqlCOUNT, tsqlCREATE, tsqlCOLUMN, tsqlCONSTRAINT, tsqlChar,tsqlCHARACTER, tsqlCHECK, tsqlComputed,tsqlCASCADE, tsqlCast, tsqlCommit,tsqlConnect,tsqlCache,tsqlConditional,tsqlCString,
tsqlDESC, tsqlDESCENDING, tsqlDISTINCT, tsqlDEFAULT, tsqlDELETE, tsqlDO, tsqlDouble, tsqlDECLARE, tsqlDROP, tsqlDomain, tsqlDecimal, tsqlDate,tsqlDatabase,
@ -69,7 +67,7 @@ type
tsqlPrecision, tsqlPRIMARY, tsqlProcedure, tsqlPosition, tsqlPlan, tsqlPassword, tsqlPage,tsqlPages,tsqlPageSize,tsqlPostEvent,tsqlPrivileges,tsqlPublic,
tsqlRIGHT, tsqlROLE, tsqlReferences, tsqlRollBack, tsqlRelease, tsqlretain, tsqlReturningValues,tsqlReturns, tsqlrevoke,
tsqlSELECT, tsqlSET, tsqlSINGULAR, tsqlSOME, tsqlSTARTING, tsqlSUM, tsqlSKIP,tsqlSUBTYPE,tsqlSize,tsqlSegment, tsqlSORT, tsqlSnapShot,tsqlSchema,tsqlShadow,tsqlSuspend,tsqlSQLCode,tsqlSmallint,
tSQLTABLE, tsqlText, tsqlTerm {not an FB reserved word, used in isql scripts}, tsqlTrigger, tsqlTime, tsqlTimeStamp, tsqlType, tsqlTo, tsqlTransaction, tsqlThen,
tSQLTABLE, tsqlText, tsqlTrigger, tsqlTime, tsqlTimeStamp, tsqlType, tsqlTo, tsqlTransaction, tsqlThen,
tsqlUNION, tsqlUPDATE, tsqlUPPER, tsqlUNIQUE, tsqlUSER,
tsqlValue, tsqlVALUES, tsqlVARIABLE, tsqlVIEW, tsqlVARCHAR,TSQLVARYING,
tsqlWHERE, tsqlWITH, tsqlWHILE, tsqlWork, tsqlWhen
@ -89,15 +87,14 @@ const
'EOF','whitespace',
'String',
'identifier',
'symbol literal',
'symbol string',
'integer number','float number', 'comment',
';' {value may be changed at run time to any symbol or set of symbols},
'(',')', '[',']',
'?',',',':','.',';','>','<',
'+','-','*','/','||',
'=','>=','<=','<>',
// Identifiers last:
'ALL', 'AND', 'ANY', 'ASC', 'ASCENDING', 'AVG', 'ALTER', 'ADD','ACTIVE','ACTION', 'AS', 'AT', 'AUTO', 'AUTODDL', 'AFTER', 'ADMIN',
'ALL', 'AND', 'ANY', 'ASC', 'ASCENDING', 'AVG', 'ALTER', 'ADD','ACTIVE','ACTION', 'AS', 'AT', 'AUTO', 'AFTER', 'ADMIN',
'BETWEEN', 'BINARY', 'BY', 'BLOB','BEGIN', 'BEFORE',
'COLLATE', 'CONTAINING', 'COUNT', 'CREATE', 'COLUMN', 'CONSTRAINT', 'CHAR','CHARACTER','CHECK', 'COMPUTED','CASCADE','CAST', 'COMMIT', 'CONNECT', 'CACHE','CONDITIONAL', 'CSTRING',
'DESC', 'DESCENDING', 'DISTINCT', 'DEFAULT', 'DELETE', 'DO', 'DOUBLE', 'DECLARE', 'DROP', 'DOMAIN', 'DECIMAL', 'DATE','DATABASE',
@ -115,7 +112,7 @@ const
'PRECISION', 'PRIMARY', 'PROCEDURE','POSITION','PLAN', 'PASSWORD','PAGE','PAGES','PAGE_SIZE','POST_EVENT','PRIVILEGES','PUBLIC',
'RIGHT', 'ROLE', 'REFERENCES', 'ROLLBACK','RELEASE', 'RETAIN', 'RETURNING_VALUES', 'RETURNS','REVOKE',
'SELECT', 'SET', 'SINGULAR', 'SOME', 'STARTING', 'SUM', 'SKIP','SUB_TYPE', 'SIZE', 'SEGMENT', 'SORT', 'SNAPSHOT','SCHEMA','SHADOW','SUSPEND','SQLCODE','SMALLINT',
'TABLE', 'TEXT', 'TERM', 'TRIGGER', 'TIME', 'TIMESTAMP', 'TYPE', 'TO', 'TRANSACTION', 'THEN',
'TABLE', 'TEXT', 'TRIGGER', 'TIME', 'TIMESTAMP', 'TYPE', 'TO', 'TRANSACTION', 'THEN',
'UNION', 'UPDATE', 'UPPER', 'UNIQUE', 'USER',
'VALUE','VALUES','VARIABLE', 'VIEW','VARCHAR','VARYING',
'WHERE', 'WITH', 'WHILE','WORK','WHEN'
@ -187,7 +184,6 @@ Type
// Used to parse out an identifier/name and store it in the list of identifiers
function DoIdentifier : TSQLToken;
// Used to parse out a string containing symbols
// Also looks for tsqlStatementTerminator
function DoSymbolString : TSQLToken;
function DoMultiLineComment: TSQLToken;
function DoNumericLiteral: TSQLToken;
@ -692,12 +688,6 @@ begin
SetLength(FCurTokenString,Len);
Move(TokenStart^,FCurTokenString[1],Len);
// Check if it is the statement terminator
if FCurTokenString=TokenInfos[tsqlStatementTerminator] then
begin
exit(tsqlStatementTerminator);
end;
// Check if this is a keyword or identifier/literal
// Probably not (due to naming rules) but it doesn't hurt
If FKeyWords.Count=0 then

View File

@ -912,20 +912,6 @@ Type
Property Arguments : string Read FArgument Write FArgument;
end;
{ TSQLSetTermStatement }
TSQLSetTermStatement = Class(TSQLStatement)
private
FNewValue: string;
FOldValue: string;
Public
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
// The first, new terminator in the SET TERM statement
Property NewTerminator : string Read FNewValue Write FNewValue;
// The second, old terminator in the SET TERM statement
Property OldTerminator : string Read FOldValue Write FOldValue;
end;
{ TSQLCreateRoleStatement }
TSQLCreateRoleStatement = Class(TSQLCreateOrAlterStatement)
@ -1890,16 +1876,6 @@ begin
Result:='-- SET '+Arguments;
end;
{ TSQLSetTermStatement }
function TSQLSetTermStatement.GetAsSQL(Options: TSQLFormatOptions;
AIndent: Integer): TSQLStringType;
begin
// Note: we generate this as a comment as this is ISQL-specific and will generate
// errors when passed as SQL to servers
Result:='-- SET TERM '+NewTerminator+' '+OldTerminator;
end;
function TSQLElementList.GetE(AIndex : Integer): TSQLElement;
begin
Result:=TSQLElement(Items[AIndex]);

View File

@ -844,20 +844,6 @@ type
procedure Test2RolesToUser;
end;
{ TTestSetParser }
TTestSetParser = Class(TTestSQLParser)
published
procedure TestSetAutoDDL;
procedure TestSetAutoDDLOn;
procedure TestSetAutoDDLOff;
procedure TestSetAutoDDLCreateProcedure;
procedure TestSetTerm;
procedure TestSetTermSemicolon;
procedure TestSetTermCreateProcedure;
procedure TestSetTermCreateProcedureVar;
end;
{ TTestGlobalParser }
TTestGlobalParser = Class(TTestSQLParser)
@ -869,138 +855,6 @@ implementation
uses typinfo;
{ TTestSetParser }
procedure TTestSetParser.TestSetAutoDDL;
Const
Desired='-- SET AUTODDL ON';
Var
I: TSQLSetISQLStatement;
begin
CreateParser('SET AUTODDL;');
FToFree:=Parser.Parse;
I:=TSQLSetISQLStatement(CheckClass(FToFree,TSQLSetISQLStatement));
AssertEquals('GetAsSQL',I.GetAsSQL([]),Desired);
end;
procedure TTestSetParser.TestSetAutoDDLOn;
Const
Desired='-- SET AUTODDL ON';
Var
I: TSQLSetISQLStatement;
begin
CreateParser('SET AUTODDL ON;');
FToFree:=Parser.Parse;
I:=TSQLSetISQLStatement(CheckClass(FToFree,TSQLSetISQLStatement));
AssertEquals('GetAsSQL',I.GetAsSQL([]),Desired);
end;
procedure TTestSetParser.TestSetAutoDDLOff;
Const
Desired='-- SET AUTODDL OFF';
Var
I: TSQLSetISQLStatement;
begin
CreateParser('SET AUTODDL OFF;');
FToFree:=Parser.Parse;
I:=TSQLSetISQLStatement(CheckClass(FToFree,TSQLSetISQLStatement));
AssertEquals('GetAsSQL',I.GetAsSQL([]),Desired);
end;
procedure TTestSetParser.TestSetAutoDDLCreateProcedure;
Const
SQL =
'SET AUTODDL ;'+LineEnding+
''+LineEnding+
'CREATE PROCEDURE PROCNAME'+LineEnding+
'AS'+LineEnding+
'BEGIN'+LineEnding+
' /* Empty procedure */'+LineEnding+
'END;';
begin
CreateParser(SQL);
Parser.ParseScript;
//todo: test name etc of procedure
end;
procedure TTestSetParser.TestSetTerm;
Var
S : TSQLSetTermStatement;
begin
CreateParser('SET TERM ^ ;');
FToFree:=Parser.Parse;
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
AssertEquals('New terminator','^',S.NewTerminator);
AssertEquals('Closing semicolon',tsqlSEMICOLON,Parser.CurrentToken);
Parser.GetNextToken;
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
end;
procedure TTestSetParser.TestSetTermSemicolon;
Var
S : TSQLSetTermStatement;
begin
CreateParser('SET TERM ; ^');
FParser.SetStatementTerminator('^'); // emulate a previous SET TERM ^ ;
AssertEquals('Closing statement terminator should match ^','^',Parser.GetStatementTerminator);
FToFree:=Parser.Parse;
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
AssertEquals('New terminator',';',S.NewTerminator);
AssertEquals('Closing terminator',tsqlStatementTerminator,Parser.CurrentToken);
AssertEquals('Closing ^','^',Parser.CurrentTokenString);
Parser.GetNextToken;
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
end;
procedure TTestSetParser.TestSetTermCreateProcedure;
Const
SQL =
'SET TERM ^ ;'+LineEnding+
''+LineEnding+
'CREATE PROCEDURE PROCNAME'+LineEnding+
'AS'+LineEnding+
'BEGIN'+LineEnding+
' /* Empty procedure */'+LineEnding+
'END^'+LineEnding+
''+LineEnding+
'SET TERM ; ^';
begin
CreateParser(SQL);
Parser.ParseScript;
//todo: test name etc of procedure
end;
procedure TTestSetParser.TestSetTermCreateProcedureVar;
// Procedure with variable
Const
SQL =
'SET TERM ^ ;'+LineEnding+
'CREATE PROCEDURE PROCWITHVAR'+LineEnding+
'RETURNS (LANGUAGES VARCHAR(15) CHARACTER SET NONE)'+LineEnding+
'AS'+LineEnding+
'DECLARE VARIABLE i INTEGER;'+LineEnding+
'BEGIN'+LineEnding+
' i = 1;'+LineEnding+
' WHILE (i <= 5) DO'+LineEnding+
' BEGIN'+LineEnding+
' SELECT language_req[:i] FROM job'+LineEnding+
' INTO :languages;'+LineEnding+
' i = i +1;'+LineEnding+
' SUSPEND;'+LineEnding+
' END'+LineEnding+
'END ^'+LineEnding+
'SET TERM ; ^';
begin
CreateParser(SQL);
Parser.ParseScript;
//todo: test name etc of procedure
end;
{ TTestGlobalParser }
procedure TTestGlobalParser.TestEmpty;
@ -1040,7 +894,7 @@ end;
procedure TTestSQLParser.SetUp;
begin
FParser.SetStatementTerminator(';');
// nothing yet
end;
procedure TTestSQLParser.TearDown;
@ -8317,7 +8171,6 @@ initialization
TTestDeclareExternalFunctionParser,
TTestGrantParser,
TTestRevokeParser,
TTestSetParser,
TTestGlobalParser]);
end.