mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 14:19:28 +02:00
* fcl-db: sql parser:
- support reading (and ignoring) SET AUTODDL statements generated by isql. This allows the parser to read isql-generated metadata extraction scripts from Firebird databases - tests git-svn-id: trunk@27921 -
This commit is contained in:
parent
041b4681e9
commit
0782f4f853
@ -2,6 +2,8 @@ SQL scanner/parser/Abstract Syntax Tree units
|
||||
|
||||
This can parse the complete Firebird dialect 3 SQL syntax (which should come pretty close to SQL-92) and builds a syntax tree from it. The Abstract Syntax Tree can re-create the SQL with limited formatting support.
|
||||
|
||||
Additionally, the parser has limited support for SET commands used by the Firebird isql tool, enough to read DDL dumps from databases generated by isql.
|
||||
|
||||
It comes with extensive test suite (over 830 test cases; see the fcl-db\tests directory). It has been tested on almost 400,000 SQL statements. Nevertheless bugs may remain, so any test results you may produce are welcome. Especially the GRANT/REVOKE statements are tested only theoretically.
|
||||
|
||||
The scanner/parser have been designed so they should be able to cope with other SQL dialects (using a set of flags) such as MySQL, but this support is currently not implemented.
|
||||
|
@ -3412,8 +3412,22 @@ begin
|
||||
// On Entry, we're on the SET statement
|
||||
Consume(tsqlSet);
|
||||
Case CurrentToken of
|
||||
tsqlGenerator : Result:=ParseSetGeneratorStatement(AParent);
|
||||
tsqlTerm : Result:=ParseSetTermStatement(AParent);
|
||||
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;
|
||||
else
|
||||
// For the time being
|
||||
UnexpectedToken;
|
||||
|
@ -50,7 +50,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,tsqlAfter,tsqlAdmin,
|
||||
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,
|
||||
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,
|
||||
@ -64,11 +64,11 @@ type
|
||||
tsqlLEFT, tsqlLIKE, tsqlLength,
|
||||
tsqlMAX, tsqlMIN, tsqlMERGE, tsqlManual, tsqlModuleName,
|
||||
tsqlNOT, tsqlNULL, tsqlNUMERIC , tsqlNChar, tsqlNATIONAL,tsqlNO, tsqlNatural,
|
||||
tsqlON, tsqlOR, tsqlORDER, tsqlOUTER, tsqlOption,
|
||||
tsqlOFF {not an FB reserved word; used in isql scripts}, tsqlON, tsqlOR, tsqlORDER, tsqlOUTER, tsqlOption,
|
||||
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, tsqlTrigger, tsqlTime, tsqlTimeStamp, tsqlType, tsqlTo, tsqlTransaction, tsqlThen,
|
||||
tSQLTABLE, tsqlText, tsqlTerm {not an FB reserved word, used in isql scripts}, tsqlTrigger, tsqlTime, tsqlTimeStamp, tsqlType, tsqlTo, tsqlTransaction, tsqlThen,
|
||||
tsqlUNION, tsqlUPDATE, tsqlUPPER, tsqlUNIQUE, tsqlUSER,
|
||||
tsqlValue, tsqlVALUES, tsqlVARIABLE, tsqlVIEW, tsqlVARCHAR,TSQLVARYING,
|
||||
tsqlWHERE, tsqlWITH, tsqlWHILE, tsqlWork, tsqlWhen
|
||||
@ -96,7 +96,7 @@ const
|
||||
'+','-','*','/','||',
|
||||
'=','>=','<=','<>',
|
||||
// Identifiers last:
|
||||
'ALL', 'AND', 'ANY', 'ASC', 'ASCENDING', 'AVG', 'ALTER', 'ADD','ACTIVE','ACTION', 'AS', 'AT', 'AUTO', 'AFTER', 'ADMIN',
|
||||
'ALL', 'AND', 'ANY', 'ASC', 'ASCENDING', 'AVG', 'ALTER', 'ADD','ACTIVE','ACTION', 'AS', 'AT', 'AUTO', 'AUTODDL', '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',
|
||||
@ -110,7 +110,7 @@ const
|
||||
'LEFT', 'LIKE', 'LENGTH',
|
||||
'MAX', 'MIN', 'MERGE', 'MANUAL', 'MODULE_NAME',
|
||||
'NOT', 'NULL', 'NUMERIC','NCHAR','NATIONAL', 'NO', 'NATURAL',
|
||||
'ON', 'OR', 'ORDER', 'OUTER', 'OPTION',
|
||||
'OFF', 'ON', 'OR', 'ORDER', 'OUTER', 'OPTION',
|
||||
'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',
|
||||
|
@ -2014,14 +2014,14 @@ begin
|
||||
AssertSQL(S,'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('A');
|
||||
P.ParamType:=CreatetypeDefinition(sdtInteger,0);
|
||||
P.ParamType:=CreateTypeDefinition(sdtInteger,0);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
AssertSQL(S,'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('B');
|
||||
P.ParamType:=CreatetypeDefinition(sdtChar,5);
|
||||
P.ParamType:=CreateTypeDefinition(sdtChar,5);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,'DECLARE VARIABLE A INT;'+sLineBreak+'DECLARE VARIABLE B CHAR(5);'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
@ -2046,7 +2046,7 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('I');
|
||||
P.ParamType:=CreatetypeDefinition(sdtInteger,0);
|
||||
P.ParamType:=CreateTypeDefinition(sdtInteger,0);
|
||||
FToFree:=S;
|
||||
S.InputVariables.Add(P);
|
||||
H:=PHEAD+' (I INT)'+sLineBreak+'AS'+sLineBreak;
|
||||
@ -2054,7 +2054,7 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('J');
|
||||
P.ParamType:=CreatetypeDefinition(sdtChar,5);
|
||||
P.ParamType:=CreateTypeDefinition(sdtChar,5);
|
||||
FToFree:=S;
|
||||
S.InputVariables.Add(P);
|
||||
H:=PHEAD+' (I INT , J CHAR(5))'+sLineBreak+'AS'+sLineBreak;
|
||||
@ -2062,7 +2062,7 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('R');
|
||||
P.ParamType:=CreatetypeDefinition(sdtInteger,0);
|
||||
P.ParamType:=CreateTypeDefinition(sdtInteger,0);
|
||||
FToFree:=S;
|
||||
S.OutputVariables.Add(P);
|
||||
H:=PHEAD+' (I INT , J CHAR(5))'+sLineBreak+'RETURNS (R INT)'+sLineBreak+'AS'+sLineBreak;
|
||||
@ -2070,7 +2070,7 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('S');
|
||||
P.ParamType:=CreatetypeDefinition(sdtChar,5);
|
||||
P.ParamType:=CreateTypeDefinition(sdtChar,5);
|
||||
FToFree:=S;
|
||||
S.OutputVariables.Add(P);
|
||||
H:=PHEAD+' (I INT , J CHAR(5))'+sLineBreak+'RETURNS (R INT , S CHAR(5))'+sLineBreak+'AS'+sLineBreak;
|
||||
@ -2078,14 +2078,14 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('A');
|
||||
P.ParamType:=CreatetypeDefinition(sdtInteger,0);
|
||||
P.ParamType:=CreateTypeDefinition(sdtInteger,0);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('B');
|
||||
P.ParamType:=CreatetypeDefinition(sdtChar,5);
|
||||
P.ParamType:=CreateTypeDefinition(sdtChar,5);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'DECLARE VARIABLE B CHAR(5);'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
@ -2141,14 +2141,14 @@ begin
|
||||
AssertSQL(S,H+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('A');
|
||||
P.ParamType:=CreatetypeDefinition(sdtInteger,0);
|
||||
P.ParamType:=CreateTypeDefinition(sdtInteger,0);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'BEGIN'+sLineBreak+' EXIT;'+sLineBreak+'END',[sfoIndentProcedureBlock]);
|
||||
P:=TSQLProcedureParamDef.Create(Nil);
|
||||
P.ParamName:=CreateIdentifier('B');
|
||||
P.ParamType:=CreatetypeDefinition(sdtChar,5);
|
||||
P.ParamType:=CreateTypeDefinition(sdtChar,5);
|
||||
FToFree:=S;
|
||||
S.LocalVariables.Add(P);
|
||||
AssertSQL(S,H+'DECLARE VARIABLE A INT;'+sLineBreak+'DECLARE VARIABLE B CHAR(5);'+sLineBreak+'BEGIN'+sLineBreak+'EXIT;'+sLineBreak+'END');
|
||||
|
@ -844,10 +844,14 @@ type
|
||||
procedure Test2RolesToUser;
|
||||
end;
|
||||
|
||||
{ TTestTermParser }
|
||||
{ TTestSetParser }
|
||||
|
||||
TTestTermParser = Class(TTestSQLParser)
|
||||
TTestSetParser = Class(TTestSQLParser)
|
||||
published
|
||||
procedure TestSetAutoDDL;
|
||||
procedure TestSetAutoDDLOn;
|
||||
procedure TestSetAutoDDLOff;
|
||||
procedure TestSetAutoDDLCreateProcedure;
|
||||
procedure TestSetTerm;
|
||||
procedure TestSetTermSemicolon;
|
||||
procedure TestSetTermCreateProcedure;
|
||||
@ -865,9 +869,43 @@ implementation
|
||||
|
||||
uses typinfo;
|
||||
|
||||
{ TTestTermParser }
|
||||
{ TTestSetParser }
|
||||
|
||||
procedure TTestTermParser.TestSetTerm;
|
||||
procedure TTestSetParser.TestSetAutoDDL;
|
||||
begin
|
||||
CreateParser('SET AUTODDL;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
end;
|
||||
|
||||
procedure TTestSetParser.TestSetAutoDDLOn;
|
||||
begin
|
||||
CreateParser('SET AUTODDL ON;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
end;
|
||||
|
||||
procedure TTestSetParser.TestSetAutoDDLOff;
|
||||
begin
|
||||
CreateParser('SET AUTODDL OFF;');
|
||||
AssertNull('SET AUTODDL should be ignored and give nil result',Parser.Parse);
|
||||
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;
|
||||
|
||||
@ -881,7 +919,7 @@ begin
|
||||
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
|
||||
end;
|
||||
|
||||
procedure TTestTermParser.TestSetTermSemicolon;
|
||||
procedure TTestSetParser.TestSetTermSemicolon;
|
||||
Var
|
||||
S : TSQLSetTermStatement;
|
||||
|
||||
@ -898,48 +936,50 @@ begin
|
||||
AssertEquals('End of stream reached',tsqlEOF,Parser.CurrentToken);
|
||||
end;
|
||||
|
||||
procedure TTestTermParser.TestSetTermCreateProcedure;
|
||||
procedure TTestSetParser.TestSetTermCreateProcedure;
|
||||
Const
|
||||
SQL =
|
||||
'SET TERM ^ ;'+#13+#10+
|
||||
''+#13+#10+
|
||||
'CREATE PROCEDURE PROCNAME'+#13+#10+
|
||||
'AS'+#13+#10+
|
||||
'BEGIN'+#13+#10+
|
||||
' /* Empty procedure */'+#13+#10+
|
||||
'END^'+#13+#10+
|
||||
''+#13+#10+
|
||||
'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 TTestTermParser.TestSetTermCreateProcedureVar;
|
||||
procedure TTestSetParser.TestSetTermCreateProcedureVar;
|
||||
// Procedure with variable
|
||||
Const
|
||||
SQL =
|
||||
'SET TERM ^ ;'+#13+#10+
|
||||
'CREATE PROCEDURE PROCWITHVAR'+#13+#10+
|
||||
'RETURNS (LANGUAGES VARCHAR(15) CHARACTER SET NONE)'+#13+#10+
|
||||
'AS'+#13+#10+
|
||||
'DECLARE VARIABLE i INTEGER;'+#13+#10+
|
||||
'BEGIN'+#13+#10+
|
||||
' i = 1;'+#13+#10+
|
||||
' WHILE (i <= 5) DO'+#13+#10+
|
||||
' BEGIN'+#13+#10+
|
||||
' SELECT language_req[:i] FROM job'+#13+#10+
|
||||
' INTO :languages;'+#13+#10+
|
||||
' i = i +1;'+#13+#10+
|
||||
' SUSPEND;'+#13+#10+
|
||||
' END'+#13+#10+
|
||||
'END ^'+#13+#10+
|
||||
'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;
|
||||
|
||||
|
||||
@ -8259,7 +8299,7 @@ initialization
|
||||
TTestDeclareExternalFunctionParser,
|
||||
TTestGrantParser,
|
||||
TTestRevokeParser,
|
||||
TTestTermParser,
|
||||
TTestSetParser,
|
||||
TTestGlobalParser]);
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user