mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 09:09:47 +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 ParseCreateViewStatement(AParent: TSQLElement; IsAlter: Boolean): TSQLCreateOrAlterStatement;
|
||||||
function ParseCreateTriggerStatement(AParent: TSQLElement; IsAlter: Boolean): TSQLCreateOrAlterStatement;
|
function ParseCreateTriggerStatement(AParent: TSQLElement; IsAlter: Boolean): TSQLCreateOrAlterStatement;
|
||||||
function ParseSetGeneratorStatement(AParent: TSQLElement) : TSQLSetGeneratorStatement;
|
function ParseSetGeneratorStatement(AParent: TSQLElement) : TSQLSetGeneratorStatement;
|
||||||
|
function ParseSetISQLStatement(AParent: TSQLElement) : TSQLSetISQLStatement;
|
||||||
function ParseSetTermStatement(AParent: TSQLElement) : TSQLSetTermStatement;
|
function ParseSetTermStatement(AParent: TSQLElement) : TSQLSetTermStatement;
|
||||||
function ParseCreateDatabaseStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateDatabaseStatement;
|
function ParseCreateDatabaseStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateDatabaseStatement;
|
||||||
function ParseCreateShadowStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateShadowStatement;
|
function ParseCreateShadowStatement(AParent: TSQLElement; IsAlter: Boolean ): TSQLCreateShadowStatement;
|
||||||
@ -158,7 +159,9 @@ Type
|
|||||||
Function ParseConnectStatement(AParent : TSQLElement) : TSQLConnectStatement;
|
Function ParseConnectStatement(AParent : TSQLElement) : TSQLConnectStatement;
|
||||||
Function ParseGrantStatement(AParent: TSQLElement): TSQLGrantStatement;
|
Function ParseGrantStatement(AParent: TSQLElement): TSQLGrantStatement;
|
||||||
Function ParseRevokeStatement(AParent: TSQLElement): TSQLGrantStatement;
|
Function ParseRevokeStatement(AParent: TSQLElement): TSQLGrantStatement;
|
||||||
|
// Parse single element
|
||||||
Function Parse : TSQLElement;
|
Function Parse : TSQLElement;
|
||||||
|
// Parse script containing 1 or more elements
|
||||||
Function ParseScript(AllowPartial : Boolean = False) : TSQLElementList;
|
Function ParseScript(AllowPartial : Boolean = False) : TSQLElementList;
|
||||||
// Gets statement terminator (as e.g. used in SET TERM) so statements like
|
// Gets statement terminator (as e.g. used in SET TERM) so statements like
|
||||||
// EXECUTE BLOCK or CREATE PROCEDURE that contain semicolons can be parsed
|
// EXECUTE BLOCK or CREATE PROCEDURE that contain semicolons can be parsed
|
||||||
@ -2965,11 +2968,11 @@ begin
|
|||||||
Consume(tsqlGenerator) ;
|
Consume(tsqlGenerator) ;
|
||||||
try
|
try
|
||||||
Result:=TSQLSetGeneratorStatement(CreateElement(TSQLSetGeneratorStatement,AParent));
|
Result:=TSQLSetGeneratorStatement(CreateElement(TSQLSetGeneratorStatement,AParent));
|
||||||
expect(tsqlidentifier);
|
Expect(tsqlidentifier);
|
||||||
Result.ObjectName:=CreateIdentifier(Result,CurrentTokenString);
|
Result.ObjectName:=CreateIdentifier(Result,CurrentTokenString);
|
||||||
GetNextToken;
|
GetNextToken;
|
||||||
consume(tsqlto);
|
Consume(tsqlto);
|
||||||
expect(tsqlIntegerNumber);
|
Expect(tsqlIntegerNumber);
|
||||||
Result.NewValue:=StrToInt(CurrentTokenString);
|
Result.NewValue:=StrToInt(CurrentTokenString);
|
||||||
GetNextToken;
|
GetNextToken;
|
||||||
except
|
except
|
||||||
@ -2978,6 +2981,37 @@ begin
|
|||||||
end;
|
end;
|
||||||
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
|
function TSQLParser.ParseSetTermStatement(AParent: TSQLElement
|
||||||
): TSQLSetTermStatement;
|
): TSQLSetTermStatement;
|
||||||
var
|
var
|
||||||
@ -2987,23 +3021,29 @@ begin
|
|||||||
Consume(tsqlTerm) ;
|
Consume(tsqlTerm) ;
|
||||||
try
|
try
|
||||||
Result:=TSQLSetTermStatement(CreateElement(TSQLSetTermStatement,AParent));
|
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
|
// Already set the expression's new value to the new terminator, but do not
|
||||||
// change tSQLStatementTerminator as GetNextToken etc need the old one to
|
// change tSQLStatementTerminator as GetNextToken etc need the old one to
|
||||||
// detect the closing terminator
|
// detect the closing terminator
|
||||||
case CurrentToken of
|
case CurrentToken of
|
||||||
tsqlSemiColon, tsqlStatementTerminator: Result.NewValue:=TokenInfos[CurrentToken];
|
tsqlSemiColon, tsqlStatementTerminator: Result.NewTerminator:=TokenInfos[CurrentToken];
|
||||||
tsqlSymbolString, tsqlString: Result.NewValue:=CurrentTokenString;
|
tsqlSymbolString, tsqlString: Result.NewTerminator:=CurrentTokenString;
|
||||||
end;
|
end;
|
||||||
// Expect the old terminator...
|
// Expect the old terminator...
|
||||||
GetNextToken;
|
GetNextToken;
|
||||||
// Parser will give tsqlSemicolon rather than tsqlStatementTerminator:
|
// Parser will give tsqlSemicolon rather than tsqlStatementTerminator:
|
||||||
if TokenInfos[tsqlStatementTerminator]=TokenInfos[tsqlSEMICOLON] then
|
if TokenInfos[tsqlStatementTerminator]=TokenInfos[tsqlSEMICOLON] then
|
||||||
Expect(tsqlSEMICOLON)
|
begin
|
||||||
|
Expect(tsqlSEMICOLON);
|
||||||
|
Result.OldTerminator:=TokenInfos[tsqlSEMICOLON];
|
||||||
|
end
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
Expect(tsqlStatementTerminator);
|
Expect(tsqlStatementTerminator);
|
||||||
|
Result.OldTerminator:=TokenInfos[tsqlStatementTerminator];
|
||||||
|
end;
|
||||||
//... and now set the new terminator:
|
//... and now set the new terminator:
|
||||||
TokenInfos[tsqlStatementTerminator]:=Result.NewValue; //process new terminator value
|
TokenInfos[tsqlStatementTerminator]:=Result.NewTerminator; //process new terminator value
|
||||||
except
|
except
|
||||||
FreeAndNil(Result);
|
FreeAndNil(Result);
|
||||||
Raise;
|
Raise;
|
||||||
@ -3414,20 +3454,7 @@ begin
|
|||||||
Case CurrentToken of
|
Case CurrentToken of
|
||||||
tsqlGenerator : Result:=ParseSetGeneratorStatement(AParent); //SET GENERATOR
|
tsqlGenerator : Result:=ParseSetGeneratorStatement(AParent); //SET GENERATOR
|
||||||
tsqlTerm : Result:=ParseSetTermStatement(AParent); //SET TERM
|
tsqlTerm : Result:=ParseSetTermStatement(AParent); //SET TERM
|
||||||
tsqlAutoDDL : //SET AUTODDL: ignore these isql commands for now
|
tsqlAutoDDL : Result:=ParseSetISQLStatement(AParent); //SET AUTODDL
|
||||||
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;
|
|
||||||
else
|
else
|
||||||
// For the time being
|
// For the time being
|
||||||
UnexpectedToken;
|
UnexpectedToken;
|
||||||
|
@ -26,7 +26,7 @@ Type
|
|||||||
TSQLFormatOption = (sfoDoubleQuotes, // Use double quote character for string literals
|
TSQLFormatOption = (sfoDoubleQuotes, // Use double quote character for string literals
|
||||||
sfoBackslashEscape, // Backslash escapes in string literals
|
sfoBackslashEscape, // Backslash escapes in string literals
|
||||||
sfoSingleQuoteIdentifier, // quote Identifiers using '
|
sfoSingleQuoteIdentifier, // quote Identifiers using '
|
||||||
sfoDoubleQuoteIdentifier, // quote Identifiers using "
|
sfoDoubleQuoteIdentifier, // quote Identifiers using " (e.g. as in Firebird)
|
||||||
sfoBackQuoteIdentifier, // quote Identifiers using `
|
sfoBackQuoteIdentifier, // quote Identifiers using `
|
||||||
sfoLowercaseKeyword, // Lowercase SQL keywords
|
sfoLowercaseKeyword, // Lowercase SQL keywords
|
||||||
sfoOneFieldPerLine, // One field per line in SELECT, Update, Insert
|
sfoOneFieldPerLine, // One field per line in SELECT, Update, Insert
|
||||||
@ -901,13 +901,29 @@ Type
|
|||||||
Property NewValue : Integer Read FNewValue Write FNewValue;
|
Property NewValue : Integer Read FNewValue Write FNewValue;
|
||||||
end;
|
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 }
|
||||||
|
|
||||||
TSQLSetTermStatement = Class(TSQLStatement)
|
TSQLSetTermStatement = Class(TSQLStatement)
|
||||||
private
|
private
|
||||||
FNewValue: string;
|
FNewValue: string;
|
||||||
|
FOldValue: string;
|
||||||
Public
|
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;
|
end;
|
||||||
|
|
||||||
{ TSQLCreateRoleStatement }
|
{ TSQLCreateRoleStatement }
|
||||||
@ -1864,6 +1880,26 @@ begin
|
|||||||
Sep:=', ';
|
Sep:=', ';
|
||||||
end;
|
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;
|
function TSQLElementList.GetE(AIndex : Integer): TSQLElement;
|
||||||
begin
|
begin
|
||||||
Result:=TSQLElement(Items[AIndex]);
|
Result:=TSQLElement(Items[AIndex]);
|
||||||
|
@ -872,21 +872,39 @@ uses typinfo;
|
|||||||
{ TTestSetParser }
|
{ TTestSetParser }
|
||||||
|
|
||||||
procedure TTestSetParser.TestSetAutoDDL;
|
procedure TTestSetParser.TestSetAutoDDL;
|
||||||
|
Const
|
||||||
|
Desired='-- SET AUTODDL ON';
|
||||||
|
Var
|
||||||
|
I: TSQLSetISQLStatement;
|
||||||
begin
|
begin
|
||||||
CreateParser('SET AUTODDL;');
|
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;
|
end;
|
||||||
|
|
||||||
procedure TTestSetParser.TestSetAutoDDLOn;
|
procedure TTestSetParser.TestSetAutoDDLOn;
|
||||||
|
Const
|
||||||
|
Desired='-- SET AUTODDL ON';
|
||||||
|
Var
|
||||||
|
I: TSQLSetISQLStatement;
|
||||||
begin
|
begin
|
||||||
CreateParser('SET AUTODDL ON;');
|
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;
|
end;
|
||||||
|
|
||||||
procedure TTestSetParser.TestSetAutoDDLOff;
|
procedure TTestSetParser.TestSetAutoDDLOff;
|
||||||
|
Const
|
||||||
|
Desired='-- SET AUTODDL OFF';
|
||||||
|
Var
|
||||||
|
I: TSQLSetISQLStatement;
|
||||||
begin
|
begin
|
||||||
CreateParser('SET AUTODDL OFF;');
|
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;
|
end;
|
||||||
|
|
||||||
procedure TTestSetParser.TestSetAutoDDLCreateProcedure;
|
procedure TTestSetParser.TestSetAutoDDLCreateProcedure;
|
||||||
@ -913,7 +931,7 @@ begin
|
|||||||
CreateParser('SET TERM ^ ;');
|
CreateParser('SET TERM ^ ;');
|
||||||
FToFree:=Parser.Parse;
|
FToFree:=Parser.Parse;
|
||||||
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
||||||
AssertEquals('New value','^',S.NewValue);
|
AssertEquals('New terminator','^',S.NewTerminator);
|
||||||
AssertEquals('Closing semicolon',tsqlSEMICOLON,Parser.CurrentToken);
|
AssertEquals('Closing semicolon',tsqlSEMICOLON,Parser.CurrentToken);
|
||||||
Parser.GetNextToken;
|
Parser.GetNextToken;
|
||||||
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
|
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
|
||||||
@ -929,7 +947,7 @@ begin
|
|||||||
AssertEquals('Closing statement terminator should match ^','^',Parser.GetStatementTerminator);
|
AssertEquals('Closing statement terminator should match ^','^',Parser.GetStatementTerminator);
|
||||||
FToFree:=Parser.Parse;
|
FToFree:=Parser.Parse;
|
||||||
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
S:=TSQLSetTermStatement(CheckClass(FToFree,TSQLSetTermStatement));
|
||||||
AssertEquals('New value',';',S.NewValue);
|
AssertEquals('New terminator',';',S.NewTerminator);
|
||||||
AssertEquals('Closing terminator',tsqlStatementTerminator,Parser.CurrentToken);
|
AssertEquals('Closing terminator',tsqlStatementTerminator,Parser.CurrentToken);
|
||||||
AssertEquals('Closing ^','^',Parser.CurrentTokenString);
|
AssertEquals('Closing ^','^',Parser.CurrentTokenString);
|
||||||
Parser.GetNextToken;
|
Parser.GetNextToken;
|
||||||
|
Loading…
Reference in New Issue
Block a user