* fcl-db: sql parser: Allow:

- double precision datatype
- blob subtype text and blob subtype binary (instead of only blob subtype 0 and 1)
- Associated tests

git-svn-id: trunk@27887 -
This commit is contained in:
reiniero 2014-06-07 09:31:12 +00:00
parent 9898474fa7
commit e1d9a068c0
4 changed files with 70 additions and 24 deletions

View File

@ -49,19 +49,20 @@ Type
FPeekTokenString: String; FPeekTokenString: String;
Procedure CheckEOF; Procedure CheckEOF;
protected protected
Procedure UnexpectedToken; overload; procedure UnexpectedToken; overload;
Procedure UnexpectedToken(AExpected : TSQLTokens); overload; procedure UnexpectedToken(AExpected : TSQLTokens); overload;
// All elements must be created with this factory function // All elements must be created with this factory function
Function CreateElement(AElementClass : TSQLElementClass; APArent : TSQLElement) : TSQLElement; virtual; function CreateElement(AElementClass : TSQLElementClass; APArent : TSQLElement) : TSQLElement; virtual;
function CreateLiteral(AParent: TSQLElement): TSQLLiteral; function CreateLiteral(AParent: TSQLElement): TSQLLiteral;
Function CreateIdentifier(AParent : TSQLElement; Const AName : TSQLStringType) : TSQLIdentifierName; function CreateIdentifier(AParent : TSQLElement; Const AName : TSQLStringType) : TSQLIdentifierName;
// Verify that current token is the expect token; raise error if not // Verify that current token is the expected token; raise error if not
procedure Expect(aToken: TSQLToken); procedure Expect(aToken: TSQLToken);
// Verify that current token is one of the expected tokens; raise error if not
procedure Expect(aTokens: TSQLTokens); procedure Expect(aTokens: TSQLTokens);
// Expects aToken and eats it // Expects aToken as current token and eats it
procedure Consume(aToken: TSQLToken); procedure Consume(aToken: TSQLToken);
procedure Error(Msg : String); procedure Error(Msg : String);
Procedure Error(Fmt : String; Args : Array of const); procedure Error(Fmt : String; Args : Array of const);
// Expression support // Expression support
function ParseExprLevel1(AParent: TSQLElement; EO : TExpressionOptions): TSQLExpression; function ParseExprLevel1(AParent: TSQLElement; EO : TExpressionOptions): TSQLExpression;
function ParseExprLevel2(AParent: TSQLElement; EO : TExpressionOptions): TSQLExpression; function ParseExprLevel2(AParent: TSQLElement; EO : TExpressionOptions): TSQLExpression;
@ -195,7 +196,7 @@ Resourcestring
SErrUnexpectedTokenOf = 'Unexpected token: %s, expected one of %s'; SErrUnexpectedTokenOf = 'Unexpected token: %s, expected one of %s';
SErrTokenMismatch = 'Unexpected token: ''%s'', expected: ''%s'''; SErrTokenMismatch = 'Unexpected token: ''%s'', expected: ''%s''';
SErrExpectedDBObject = 'Expected database object type. Got: ''%s'''; SErrExpectedDBObject = 'Expected database object type. Got: ''%s''';
SErrDomainNotAllowed = 'Domain name not allowed in typ definition.'; SErrDomainNotAllowed = 'Domain name not allowed in type definition.';
SErrExpectedChar = 'Expected CHAR or CHARACTER, got "%s"'; SErrExpectedChar = 'Expected CHAR or CHARACTER, got "%s"';
SERRVaryingNotAllowed = 'VARYING not allowed at this point.'; SERRVaryingNotAllowed = 'VARYING not allowed at this point.';
SErrUnknownBooleanOp = 'Unknown boolean operation'; SErrUnknownBooleanOp = 'Unknown boolean operation';
@ -804,7 +805,7 @@ begin
Result.ComputedBy:=ParseExprLevel1(Result,[eoComputedBy]); Result.ComputedBy:=ParseExprLevel1(Result,[eoComputedBy]);
Consume(tsqlBraceClose); Consume(tsqlBraceClose);
end end
else else //not computed, regular field
Result.FieldType:=ParseTypeDefinition(Result,[ptfAllowDomainName,ptfAllowConstraint,ptfTableFieldDef]); Result.FieldType:=ParseTypeDefinition(Result,[ptfAllowDomainName,ptfAllowConstraint,ptfTableFieldDef]);
except except
FreeAndNil(Result); FreeAndNil(Result);
@ -1618,8 +1619,13 @@ begin
If CurrentToken=tsqlSubtype then // SUB_TYPE T If CurrentToken=tsqlSubtype then // SUB_TYPE T
begin begin
GetNextToken; GetNextToken;
Expect(tsqlIntegerNumber); Expect([tsqlIntegerNumber,tsqlBinary,tsqlText]);
ABlobType:=StrtoInt(CurrentTokenString); case CurrentToken of
tsqlBinary: ABlobType:=0; //FB2.0+ see Language Reference Update
tsqlText: ABlobType:=1;
tsqlIntegerNumber: ABlobType:=StrtoInt(CurrentTokenString);
else Error('ParseBlobDefinition: internal error: unknown token type.');
end;
GetNextToken; GetNextToken;
end; end;
If (CurrentToken=tsqlSegment) then // SEGMENT SIZE S If (CurrentToken=tsqlSegment) then // SEGMENT SIZE S
@ -1837,6 +1843,12 @@ begin
dt:=sdtDate; dt:=sdtDate;
tsqlTimeStamp: tsqlTimeStamp:
dt:=sdtDateTime; dt:=sdtDateTime;
tsqlDouble:
begin
GetNextToken;
Consume(tsqlPrecision); //DOUBLE PRECISION
dt:=sdtDoublePrecision;
end;
tsqlFloat: tsqlFloat:
dt:=sdtFloat; dt:=sdtFloat;
tsqlTime: tsqlTime:

View File

@ -42,11 +42,12 @@ type
tsqlPlaceHolder,tsqlCOMMA,tsqlCOLON,tsqlDOT,tsqlSEMICOLON,tsqlGT,tsqlLT, tsqlPlaceHolder,tsqlCOMMA,tsqlCOLON,tsqlDOT,tsqlSEMICOLON,tsqlGT,tsqlLT,
tsqlPLUS,tsqlMINUS,tsqlMUL,tsqlDIV,tsqlConcatenate, tsqlPLUS,tsqlMINUS,tsqlMUL,tsqlDIV,tsqlConcatenate,
tsqlEQ,tsqlGE,tsqlLE,tsqlNE, tsqlEQ,tsqlGE,tsqlLE,tsqlNE,
{ Reserved words start here. They must be last } { 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,tsqlAfter,tsqlAdmin,
tsqlBETWEEN, tsqlBY, tsqlBLOB,tsqlBegin, tsqlBefore, tsqlBETWEEN, tsqlBinary, tsqlBY, tsqlBLOB, tsqlBegin, tsqlBefore,
tsqlCOLLATE, tsqlCONTAINING, tsqlCOUNT, tsqlCREATE, tsqlCOLUMN, tsqlCONSTRAINT, tsqlChar,tsqlCHARACTER, tsqlCHECK, tsqlComputed,tsqlCASCADE, tsqlCast, tsqlCommit,tsqlConnect,tsqlCache,tsqlConditional,tsqlCString, tsqlCOLLATE, tsqlCONTAINING, tsqlCOUNT, tsqlCREATE, tsqlCOLUMN, tsqlCONSTRAINT, tsqlChar,tsqlCHARACTER, tsqlCHECK, tsqlComputed,tsqlCASCADE, tsqlCast, tsqlCommit,tsqlConnect,tsqlCache,tsqlConditional,tsqlCString,
tsqlDESC, tsqlDESCENDING, tsqlDISTINCT, tsqlDEFAULT, tsqlDELETE, tsqlDO, tsqlDECLARE, tsqlDROP, tsqlDomain, tsqlDecimal, tsqlDate,tsqlDatabase, tsqlDESC, tsqlDESCENDING, tsqlDISTINCT, tsqlDEFAULT, tsqlDELETE, tsqlDO, tsqlDouble, tsqlDECLARE, tsqlDROP, tsqlDomain, tsqlDecimal, tsqlDate,tsqlDatabase,
tsqlESCAPE, tsqlEXISTS, tsqlELSE, tsqlException, tsqlExternal, tsqlExecute, tsqlEnd,tsqlExit,tsqlEntrypoint,tsqlExtract, tsqlESCAPE, tsqlEXISTS, tsqlELSE, tsqlException, tsqlExternal, tsqlExecute, tsqlEnd,tsqlExit,tsqlEntrypoint,tsqlExtract,
tsqlFROM, tsqlFULL, tsqlFOREIGN, tsqlFOR, tsqlFUNCTION, tsqlFLOAT, tsqlFile,tsqlFreeIt, tsqlFROM, tsqlFULL, tsqlFOREIGN, tsqlFOR, tsqlFUNCTION, tsqlFLOAT, tsqlFile,tsqlFreeIt,
tsqlGenerator, tsqlGROUP, tsqlGenID,tsqlGDSCODE,tsqlGrant, tsqlGenerator, tsqlGROUP, tsqlGenID,tsqlGDSCODE,tsqlGrant,
@ -58,10 +59,10 @@ type
tsqlMAX, tsqlMIN, tsqlMERGE, tsqlManual, tsqlModuleName, tsqlMAX, tsqlMIN, tsqlMERGE, tsqlManual, tsqlModuleName,
tsqlNOT, tsqlNULL, tsqlNUMERIC , tsqlNChar, tsqlNATIONAL,tsqlNO, tsqlNatural, tsqlNOT, tsqlNULL, tsqlNUMERIC , tsqlNChar, tsqlNATIONAL,tsqlNO, tsqlNatural,
tsqlON, tsqlOR, tsqlORDER, tsqlOUTER, tsqlOption, tsqlON, tsqlOR, tsqlORDER, tsqlOUTER, tsqlOption,
tsqlPRIMARY, tsqlProcedure, tsqlPosition, tsqlPlan, tsqlPassword, tsqlPage,tsqlPages,tsqlPageSize,tsqlPostEvent,tsqlPrivileges,tsqlPublic, tsqlPrecision, tsqlPRIMARY, tsqlProcedure, tsqlPosition, tsqlPlan, tsqlPassword, tsqlPage,tsqlPages,tsqlPageSize,tsqlPostEvent,tsqlPrivileges,tsqlPublic,
tsqlRIGHT, tsqlROLE, tsqlReferences, tsqlRollBack, tsqlRelease, tsqlretain, tsqlReturningValues,tsqlReturns, tsqlrevoke, 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, tsqlSELECT, tsqlSET, tsqlSINGULAR, tsqlSOME, tsqlSTARTING, tsqlSUM, tsqlSKIP,tsqlSUBTYPE,tsqlSize,tsqlSegment, tsqlSORT, tsqlSnapShot,tsqlSchema,tsqlShadow,tsqlSuspend,tsqlSQLCode,tsqlSmallint,
tSQLTABLE, tsqlTrigger,tsqlTime,tsqlTimeStamp,tsqlType, tsqlTo, tsqlTransaction,tsqlThen, tSQLTABLE, tsqlText, tsqlTrigger, tsqlTime, tsqlTimeStamp, tsqlType, tsqlTo, tsqlTransaction, tsqlThen,
tsqlUNION, tsqlUPDATE, tsqlUPPER, tsqlUNIQUE, tsqlUSER, tsqlUNION, tsqlUPDATE, tsqlUPPER, tsqlUNIQUE, tsqlUSER,
tsqlValue, tsqlVALUES, tsqlVARIABLE, tsqlVIEW, tsqlVARCHAR,TSQLVARYING, tsqlValue, tsqlVALUES, tsqlVARIABLE, tsqlVIEW, tsqlVARCHAR,TSQLVARYING,
tsqlWHERE, tsqlWITH, tsqlWHILE, tsqlWork, tsqlWhen tsqlWHERE, tsqlWITH, tsqlWHILE, tsqlWork, tsqlWhen
@ -83,11 +84,11 @@ const
'?',',',':','.',';','>','<', '?',',',':','.',';','>','<',
'+','-','*','/','||', '+','-','*','/','||',
'=','>=','<=','<>', '=','>=','<=','<>',
// Identifiers last // 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', 'AFTER', 'ADMIN',
'BETWEEN', 'BY', 'BLOB','BEGIN', 'BEFORE', 'BETWEEN', 'BINARY', 'BY', 'BLOB','BEGIN', 'BEFORE',
'COLLATE', 'CONTAINING', 'COUNT', 'CREATE', 'COLUMN', 'CONSTRAINT', 'CHAR','CHARACTER','CHECK', 'COMPUTED','CASCADE','CAST', 'COMMIT', 'CONNECT', 'CACHE','CONDITIONAL', 'CSTRING', 'COLLATE', 'CONTAINING', 'COUNT', 'CREATE', 'COLUMN', 'CONSTRAINT', 'CHAR','CHARACTER','CHECK', 'COMPUTED','CASCADE','CAST', 'COMMIT', 'CONNECT', 'CACHE','CONDITIONAL', 'CSTRING',
'DESC', 'DESCENDING', 'DISTINCT', 'DEFAULT', 'DELETE', 'DO', 'DECLARE', 'DROP', 'DOMAIN', 'DECIMAL', 'DATE','DATABASE', 'DESC', 'DESCENDING', 'DISTINCT', 'DEFAULT', 'DELETE', 'DO', 'DOUBLE', 'DECLARE', 'DROP', 'DOMAIN', 'DECIMAL', 'DATE','DATABASE',
'ESCAPE', 'EXISTS', 'ELSE', 'EXCEPTION', 'EXTERNAL','EXECUTE', 'END','EXIT','ENTRY_POINT','EXTRACT', 'ESCAPE', 'EXISTS', 'ELSE', 'EXCEPTION', 'EXTERNAL','EXECUTE', 'END','EXIT','ENTRY_POINT','EXTRACT',
'FROM', 'FULL','FOREIGN', 'FOR', 'FUNCTION', 'FLOAT','FILE', 'FREE_IT', 'FROM', 'FULL','FOREIGN', 'FOR', 'FUNCTION', 'FLOAT','FILE', 'FREE_IT',
'GENERATOR', 'GROUP', 'GEN_ID','GDSCODE','GRANT', 'GENERATOR', 'GROUP', 'GEN_ID','GDSCODE','GRANT',
@ -99,10 +100,10 @@ const
'MAX', 'MIN', 'MERGE', 'MANUAL', 'MODULE_NAME', 'MAX', 'MIN', 'MERGE', 'MANUAL', 'MODULE_NAME',
'NOT', 'NULL', 'NUMERIC','NCHAR','NATIONAL', 'NO', 'NATURAL', 'NOT', 'NULL', 'NUMERIC','NCHAR','NATIONAL', 'NO', 'NATURAL',
'ON', 'OR', 'ORDER', 'OUTER', 'OPTION', 'ON', 'OR', 'ORDER', 'OUTER', 'OPTION',
'PRIMARY', 'PROCEDURE','POSITION','PLAN', 'PASSWORD','PAGE','PAGES','PAGE_SIZE','POST_EVENT','PRIVILEGES','PUBLIC', 'PRECISION', 'PRIMARY', 'PROCEDURE','POSITION','PLAN', 'PASSWORD','PAGE','PAGES','PAGE_SIZE','POST_EVENT','PRIVILEGES','PUBLIC',
'RIGHT', 'ROLE', 'REFERENCES', 'ROLLBACK','RELEASE', 'RETAIN', 'RETURNING_VALUES', 'RETURNS','REVOKE', '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', 'SELECT', 'SET', 'SINGULAR', 'SOME', 'STARTING', 'SUM', 'SKIP','SUB_TYPE', 'SIZE', 'SEGMENT', 'SORT', 'SNAPSHOT','SCHEMA','SHADOW','SUSPEND','SQLCODE','SMALLINT',
'TABLE','TRIGGER', 'TIME','TIMESTAMP', 'TYPE', 'TO', 'TRANSACTION','THEN', 'TABLE', 'TEXT', 'TRIGGER', 'TIME', 'TIMESTAMP', 'TYPE', 'TO', 'TRANSACTION', 'THEN',
'UNION', 'UPDATE', 'UPPER', 'UNIQUE', 'USER', 'UNION', 'UPDATE', 'UPPER', 'UNIQUE', 'USER',
'VALUE','VALUES','VARIABLE', 'VIEW','VARCHAR','VARYING', 'VALUE','VALUES','VARIABLE', 'VIEW','VARCHAR','VARYING',
'WHERE', 'WITH', 'WHILE','WORK','WHEN' 'WHERE', 'WITH', 'WHILE','WORK','WHEN'
@ -637,7 +638,7 @@ begin
BuildKeyWords; BuildKeyWords;
P:=FKeyWords.Find(S); P:=FKeyWords.Find(S);
If (P<>Nil) then If (P<>Nil) then
Result:=P^; Result:=P^; //keyword found
{ I:=FirstKeyword; { I:=FirstKeyword;
While (Result=tsqlIdentifier) and (I<=Lastkeyword) do While (Result=tsqlIdentifier) and (I<=Lastkeyword) do
begin begin

View File

@ -166,6 +166,8 @@ type
procedure TestBlob4; procedure TestBlob4;
procedure TestBlob5; procedure TestBlob5;
procedure TestBlob6; procedure TestBlob6;
procedure TestBlob7;
procedure TestBlob8;
procedure TestBlobError1; procedure TestBlobError1;
procedure TestBlobError2; procedure TestBlobError2;
procedure TestBlobError3; procedure TestBlobError3;
@ -175,6 +177,7 @@ type
procedure TestBlobError7; procedure TestBlobError7;
procedure TestSmallInt; procedure TestSmallInt;
procedure TestFloat; procedure TestFloat;
procedure TestDoublePrecision;
end; end;
{ TTestCheckParser } { TTestCheckParser }
@ -1746,6 +1749,29 @@ begin
AssertEquals('Blob segment size',0,TD.Len); AssertEquals('Blob segment size',0,TD.Len);
AssertEquals('Character set','',TD.Charset); AssertEquals('Character set','',TD.Charset);
end; end;
procedure TTestTypeParser.TestBlob7;
var
TD : TSQLTypeDefinition;
begin
TD:=TestType('BLOB SUB_TYPE BINARY',[],sdtBlob);
AssertEquals('Blob type 0',0,TD.BlobType);
AssertEquals('Blob segment size',0,TD.Len);
AssertEquals('Character set','',TD.Charset);
end;
procedure TTestTypeParser.TestBlob8;
var
TD : TSQLTypeDefinition;
begin
TD:=TestType('BLOB SUB_TYPE TEXT',[],sdtBlob);
AssertEquals('Blob type 1',1,TD.BlobType);
AssertEquals('Blob segment size',0,TD.Len);
AssertEquals('Character set','',TD.Charset);
end;
procedure TTestTypeParser.TestSmallInt; procedure TTestTypeParser.TestSmallInt;
Var Var
@ -1761,6 +1787,13 @@ begin
TD:=TestType('FLOAT',[],sdtFloat); TD:=TestType('FLOAT',[],sdtFloat);
end; end;
procedure TTestTypeParser.TestDoublePrecision;
var
TD : TSQLTypeDefinition;
begin
TD:=TestType('DOUBLE PRECISION',[],sdtDoublePrecision);
end;
procedure TTestTypeParser.TestBlobError1; procedure TTestTypeParser.TestBlobError1;
begin begin
FerrSource:='BLOB (1,)'; FerrSource:='BLOB (1,)';

View File

@ -1,6 +1,6 @@
{ {
This file is part of the Free Component Library This file is part of the Free Component Library
Copyright (c) 2010 by the Free Pascal development team Copyright (c) 2010-2014 by the Free Pascal development team
SQL source lexical scanner test suite SQL source lexical scanner test suite
@ -291,7 +291,7 @@ Var
begin begin
CreateScanner(ASource); CreateScanner(ASource);
J:=Scanner.FetchToken; J:=Scanner.FetchToken;
EN2:=GetEnumName(TypeINfo(TSQLToken),Ord(AToken)); EN2:=GetEnumName(TypeInfo(TSQLToken),Ord(AToken));
AssertEquals(Format('Source %s should result in %s.',[ASource,EN2]),AToken,J); AssertEquals(Format('Source %s should result in %s.',[ASource,EN2]),AToken,J);
end; end;