diff --git a/packages/fcl-db/src/sqldb/sqldb.pp b/packages/fcl-db/src/sqldb/sqldb.pp index a8165c0856..d0b3f2bb51 100644 --- a/packages/fcl-db/src/sqldb/sqldb.pp +++ b/packages/fcl-db/src/sqldb/sqldb.pp @@ -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; diff --git a/packages/fcl-db/tests/testsqldb.pas b/packages/fcl-db/tests/testsqldb.pas index 1f13f4a83e..003fd53a8d 100644 --- a/packages/fcl-db/tests/testsqldb.pas +++ b/packages/fcl-db/tests/testsqldb.pas @@ -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;