fcl-db: sqldb: when parsing identifiers (TableName) take into account delimited identifiers (double quoted) separated by point + test. Bug #34511

git-svn-id: trunk@40240 -
This commit is contained in:
lacak 2018-11-06 13:46:37 +00:00
parent b115886930
commit 475fed4e9a
2 changed files with 47 additions and 12 deletions

View File

@ -1518,9 +1518,10 @@ end;
function TSQLConnection.GetStatementInfo(const ASQL: string): TSQLStatementInfo;
type TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
type
TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
TPhraseSeparator = (sepNone, sepWhiteSpace, sepComma, sepComment, sepParentheses, sepDoubleQuote, sepEnd);
TKeyword = (kwWITH, kwSELECT, kwINSERT, kwUPDATE, kwDELETE, kwFROM, kwJOIN, kwWHERE, kwGROUP, kwORDER, kwUNION, kwROWS, kwLIMIT, kwUnknown);
const
KeywordNames: array[TKeyword] of string =
@ -1536,7 +1537,7 @@ var
Keyword, K : TKeyword;
begin
PSQL:=Pchar(ASQL);
PSQL:=PChar(ASQL);
ParsePart := ppStart;
CurrentP := PSQL-1;
@ -1548,7 +1549,6 @@ begin
Result.WhereStopPos := 0;
repeat
begin
inc(CurrentP);
SavedP := CurrentP;
@ -1582,12 +1582,12 @@ begin
Separator := sepNone;
end;
if (CurrentP > SavedP) and (SavedP > PhraseP) then
CurrentP := SavedP; // there is something before comment or left parenthesis
if Separator <> sepNone then
begin
if ((Separator in [sepWhitespace,sepComment]) and (PhraseP = SavedP)) then
if (CurrentP > SavedP) and (SavedP > PhraseP) then
CurrentP := SavedP; // there is something before comment or left parenthesis or double quote
if (Separator in [sepWhitespace,sepComment]) and (SavedP = PhraseP) then
PhraseP := CurrentP; // skip comments (but not parentheses) and white spaces
if (CurrentP-PhraseP > 0) or (Separator = sepEnd) then
@ -1633,10 +1633,12 @@ begin
// and/or derived tables are also not updateable
if Separator in [sepWhitespace, sepComment, sepDoubleQuote, sepEnd] then
begin
Result.TableName := s;
Result.TableName := Result.TableName + s;
Result.Updateable := True;
end;
ParsePart := ppFrom;
// compound delimited classifier like: "schema name"."table name"
if not (CurrentP^ in ['.','"']) then
ParsePart := ppFrom;
end;
ppFrom : begin
if (Keyword in [kwWHERE, kwGROUP, kwORDER, kwLIMIT, kwROWS]) or
@ -1683,7 +1685,6 @@ begin
dec(CurrentP);
PhraseP := CurrentP+1;
end
end;
until CurrentP^=#0;
end;

View File

@ -72,6 +72,7 @@ type
procedure TestUseImplicitTransaction;
procedure TestUseExplicitTransaction;
procedure TestExplicitConnect;
procedure TestGetStatementInfo;
end;
{ TTestTSQLScript }
@ -838,6 +839,39 @@ begin
AssertException('toExplicitStart raises exception on implicit start',EDatabaseError,@TryOpen)
end;
procedure TTestTSQLConnection.TestGetStatementInfo;
var StmtInfo: TSQLStatementInfo;
begin
// single table
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab1');
AssertEquals('StatementType', ord(stSELECT), ord(StmtInfo.StatementType));
AssertEquals('TableName', 'tab1', StmtInfo.TableName);
AssertEquals('Updateable', True, StmtInfo.Updateable);
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab2 WHERE col1=1');
AssertEquals('TableName', 'tab2', StmtInfo.TableName);
AssertEquals('Updateable', True, StmtInfo.Updateable);
// single table with schema
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM dbo.tab2 WHERE col1=1');
AssertEquals('TableName', 'dbo.tab2', StmtInfo.TableName);
AssertEquals('Updateable', True, StmtInfo.Updateable);
// single table with quoted schema
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM "dbo".tab2 WHERE col1=1');
AssertEquals('TableName', '"dbo".tab2', StmtInfo.TableName);
AssertEquals('Updateable', True, StmtInfo.Updateable);
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM "dbo"."tab2" WHERE col1=1');
AssertEquals('TableName', '"dbo"."tab2"', StmtInfo.TableName);
AssertEquals('Updateable', True, StmtInfo.Updateable);
// multiple tables
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM tab3,tab4 WHERE col1=1');
AssertEquals('TableName', '', StmtInfo.TableName);
AssertEquals('Updateable', False, StmtInfo.Updateable);
// function
StmtInfo := SQLDBConnector.Connection.GetStatementInfo('SELECT * FROM dbo.fn1(1)');
AssertEquals('TableName', '', StmtInfo.TableName);
AssertEquals('Updateable', False, StmtInfo.Updateable);
end;
{ TTestTSQLScript }
procedure TTestTSQLScript.TestExecuteScript;