mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 14:19:28 +02:00
* fcl-db: sql parser:
- fix parsing scripts containing SET AUTODDL and SET TERM statements - SET TERM/SET AUTODDL will be output as SQL comments when regenerating SQL so thethe commands work with e.g. sqldb git-svn-id: trunk@27923 -
This commit is contained in:
parent
1b11541c90
commit
81548f0e9c
@ -101,6 +101,7 @@ 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;
|
||||
@ -158,7 +159,9 @@ Type
|
||||
Function ParseConnectStatement(AParent : TSQLElement) : TSQLConnectStatement;
|
||||
Function ParseGrantStatement(AParent: TSQLElement): TSQLGrantStatement;
|
||||
Function ParseRevokeStatement(AParent: TSQLElement): TSQLGrantStatement;
|
||||
// Parse single element
|
||||
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
|
||||
@ -2965,11 +2968,11 @@ begin
|
||||
Consume(tsqlGenerator) ;
|
||||
try
|
||||
Result:=TSQLSetGeneratorStatement(CreateElement(TSQLSetGeneratorStatement,AParent));
|
||||
expect(tsqlidentifier);
|
||||
Expect(tsqlidentifier);
|
||||
Result.ObjectName:=CreateIdentifier(Result,CurrentTokenString);
|
||||
GetNextToken;
|
||||
consume(tsqlto);
|
||||
expect(tsqlIntegerNumber);
|
||||
Consume(tsqlto);
|
||||
Expect(tsqlIntegerNumber);
|
||||
Result.NewValue:=StrToInt(CurrentTokenString);
|
||||
GetNextToken;
|
||||
except
|
||||
@ -2978,6 +2981,37 @@ 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
|
||||
@ -2987,23 +3021,29 @@ begin
|
||||
Consume(tsqlTerm) ;
|
||||
try
|
||||
Result:=TSQLSetTermStatement(CreateElement(TSQLSetTermStatement,AParent));
|
||||
expect([tsqlSemiColon,tsqlStatementTerminator,tsqlSymbolString,tsqlString]);
|
||||
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.NewValue:=TokenInfos[CurrentToken];
|
||||
tsqlSymbolString, tsqlString: Result.NewValue:=CurrentTokenString;
|
||||
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
|
||||
Expect(tsqlSEMICOLON)
|
||||
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.NewValue; //process new terminator value
|
||||
TokenInfos[tsqlStatementTerminator]:=Result.NewTerminator; //process new terminator value
|
||||
except
|
||||
FreeAndNil(Result);
|
||||
Raise;
|
||||
@ -3414,20 +3454,7 @@ begin
|
||||
Case CurrentToken of
|
||||
tsqlGenerator : Result:=ParseSetGeneratorStatement(AParent); //SET GENERATOR
|
||||
tsqlTerm : Result:=ParseSetTermStatement(AParent); //SET TERM
|
||||
tsqlAutoDDL : //SET AUTODDL: ignore these isql commands for now
|
||||
begin
|
||||
// SET AUTODDL ON, SET AUTODDL OFF; optional arguments
|
||||
if (PeekNextToken in [tsqlOn, tsqlOff]) then
|
||||
begin
|
||||
GetNextToken;
|
||||
Consume([tsqlOn,tsqlOff]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Consume(tsqlAutoDDL);
|
||||
end;
|
||||
Result:=nil; //ignore
|
||||
end;
|
||||
tsqlAutoDDL : Result:=ParseSetISQLStatement(AParent); //SET AUTODDL
|
||||
else
|
||||
// For the time being
|
||||
UnexpectedToken;
|
||||
|
@ -26,7 +26,7 @@ Type
|
||||
TSQLFormatOption = (sfoDoubleQuotes, // Use double quote character for string literals
|
||||
sfoBackslashEscape, // Backslash escapes in string literals
|
||||
sfoSingleQuoteIdentifier, // quote Identifiers using '
|
||||
sfoDoubleQuoteIdentifier, // quote Identifiers using "
|
||||
sfoDoubleQuoteIdentifier, // quote Identifiers using " (e.g. as in Firebird)
|
||||
sfoBackQuoteIdentifier, // quote Identifiers using `
|
||||
sfoLowercaseKeyword, // Lowercase SQL keywords
|
||||
sfoOneFieldPerLine, // One field per line in SELECT, Update, Insert
|
||||
@ -901,13 +901,29 @@ Type
|
||||
Property NewValue : Integer Read FNewValue Write FNewValue;
|
||||
end;
|
||||
|
||||
{ TSQLSetISQLStatement }
|
||||
// SET statements as used by the isql Firebird command line utility
|
||||
TSQLSetISQLStatement = Class(TSQLStatement)
|
||||
private
|
||||
FArgument: string;
|
||||
Public
|
||||
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
|
||||
// The test of the SET statement excluding the SET command
|
||||
Property Arguments : string Read FArgument Write FArgument;
|
||||
end;
|
||||
|
||||
{ TSQLSetTermStatement }
|
||||
|
||||
TSQLSetTermStatement = Class(TSQLStatement)
|
||||
private
|
||||
FNewValue: string;
|
||||
FOldValue: string;
|
||||
Public
|
||||
Property NewValue : string Read FNewValue Write FNewValue;
|
||||
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 }
|
||||
@ -1864,6 +1880,26 @@ begin
|
||||
Sep:=', ';
|
||||
end;
|
||||
|
||||
{ TSQLSetISQLStatement }
|
||||
|
||||
function TSQLSetISQLStatement.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 '+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]);
|
||||
|
@ -872,21 +872,39 @@ uses typinfo;
|
||||
{ TTestSetParser }
|
||||
|
||||
procedure TTestSetParser.TestSetAutoDDL;
|
||||
Const
|
||||
Desired='-- SET AUTODDL ON';
|
||||
Var
|
||||
I: TSQLSetISQLStatement;
|
||||
begin
|
||||
CreateParser('SET AUTODDL;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
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;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
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;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
FToFree:=Parser.Parse;
|
||||
I:=TSQLSetISQLStatement(CheckClass(FToFree,TSQLSetISQLStatement));
|
||||
AssertEquals('GetAsSQL',I.GetAsSQL([]),Desired);
|
||||
end;
|
||||
|
||||
procedure TTestSetParser.TestSetAutoDDLCreateProcedure;
|
||||
@ -913,7 +931,7 @@ begin
|
||||
CreateParser('SET TERM ^ ;');
|
||||
FToFree:=Parser.Parse;
|
||||
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
||||
AssertEquals('New value','^',S.NewValue);
|
||||
AssertEquals('New terminator','^',S.NewTerminator);
|
||||
AssertEquals('Closing semicolon',tsqlSEMICOLON,Parser.CurrentToken);
|
||||
Parser.GetNextToken;
|
||||
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
|
||||
@ -929,7 +947,7 @@ begin
|
||||
AssertEquals('Closing statement terminator should match ^','^',Parser.GetStatementTerminator);
|
||||
FToFree:=Parser.Parse;
|
||||
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
||||
AssertEquals('New value',';',S.NewValue);
|
||||
AssertEquals('New terminator',';',S.NewTerminator);
|
||||
AssertEquals('Closing terminator',tsqlStatementTerminator,Parser.CurrentToken);
|
||||
AssertEquals('Closing ^','^',Parser.CurrentTokenString);
|
||||
Parser.GetNextToken;
|
||||
|
Loading…
Reference in New Issue
Block a user