Browse Source

sql parser: fix source position

git-svn-id: trunk@46429 -
(cherry picked from commit 56613723b9f60c582df39bf0154dd7dccbe6d1b0)
ondrej 5 years ago
parent
commit
b473b7b5af

+ 14 - 2
packages/fcl-db/src/sql/fpsqlparser.pas

@@ -47,10 +47,14 @@ Type
     FScanner : TSQLScanner;
     FCurrent : TSQLToken;
     FCurrentString : String;
+    FCurrentTokenLine : Integer;
+    FCurrentTokenPos : Integer;
     FPrevious : TSQLToken;
     FFreeScanner : Boolean;
     FPeekToken: TSQLToken;
     FPeekTokenString: String;
+    FPeekTokenLine : Integer;
+    FPeekTokenPos : Integer;
     Procedure CheckEOF;
   protected
     procedure UnexpectedToken; overload;
@@ -173,6 +177,8 @@ Type
     // Auxiliary stuff
     Property CurrentToken : TSQLToken read FCurrent;
     Property CurrentTokenString : String read FCurrentString;
+    Property CurrentTokenLine : Integer read FCurrentTokenLine;
+    Property CurrentTokenPos : Integer read FCurrentTokenPos;
     // Gets next token; also updates current token
     Function GetNextToken : TSQLToken;
     // Looks at next token without changing current token
@@ -325,8 +331,8 @@ function TSQLParser.CreateElement(AElementClass: TSQLElementClass;
 begin
   Result:=AElementClass.Create(AParent);
   Result.Source:=CurSource;
-  Result.SourceLine:=CurLine;
-  Result.SourcePos:=CurPos;
+  Result.SourceLine:=CurrentTokenLine;
+  Result.SourcePos:=CurrentTokenPos;
 end;
 
 function TSQLParser.ParseTableRef(AParent: TSQLSelectStatement
@@ -4190,6 +4196,8 @@ begin
     begin
     FCurrent:=FPeekToken;
     FCurrentString:=FPeekTokenString;
+    FCurrentTokenLine:=FPeekTokenLine;
+    FCurrentTokenPos:=FPeekTokenPos;
     FPeekToken:=tsqlUnknown;
     FPeekTokenString:='';
     end
@@ -4197,6 +4205,8 @@ begin
     begin
     FCurrent:=FScanner.FetchToken;
     FCurrentString:=FScanner.CurTokenString;
+    FCurrentTokenLine:=FScanner.CurTokenRow;
+    FCurrentTokenPos:=FScanner.CurTokenColumn;
     end;
   Result:=FCurrent;
   {$ifdef debugparser}Writeln('GetNextToken : ',GetEnumName(TypeInfo(TSQLToken),Ord(FCurrent)), ' As string: ',FCurrentString);{$endif debugparser}
@@ -4208,6 +4218,8 @@ begin
     begin
     FPeekToken:=FScanner.FetchToken;
     FPeekTokenString:=FScanner.CurTokenString;
+    FPeekTokenLine:=FScanner.CurTokenRow;
+    FPeekTokenPos:=FScanner.CurTokenColumn;
     end;
   {$ifdef debugparser}Writeln('PeekNextToken : ',GetEnumName(TypeInfo(TSQLToken),Ord(FPeekToken)), ' As string: ',FPeekTokenString);{$endif debugparser}
   Result:=FPeekToken;

+ 7 - 1
packages/fcl-db/src/sql/fpsqlscanner.pp

@@ -175,6 +175,8 @@ Type
     FCurRow: Integer;
     FCurToken: TSQLToken;
     FCurTokenString: string;
+    FCurTokenRow: Integer;
+    FCurTokenColumn: Integer;
     FCurLine: string;
     TokenStr: PChar;
     FSourceStream : TStream;
@@ -219,6 +221,8 @@ Type
     property CurColumn: Integer read GetCurColumn;
     property CurToken: TSQLToken read FCurToken;
     property CurTokenString: string read FCurTokenString;
+    Property CurTokenRow : Integer Read FCurTokenRow;
+    Property CurTokenColumn : Integer Read FCurTokenColumn;
     Property ExcludeKeywords : TStrings Read GetExcludeKeywords Write SetExcludeKeywords;
     Property AlternateTerminator : String Read FAlternateTerminator Write FAlternateTerminator;
   end;
@@ -719,6 +723,8 @@ begin
         FCurToken := Result;
         exit;
         end;
+    FCurTokenRow:=CurRow;
+    FCurTokenColumn:=CurColumn;
     FCurTokenString := '';
     case TokenStr[0] of
       #0:         // Empty line
@@ -911,7 +917,7 @@ end;
 
 function TSQLScanner.GetCurColumn: Integer;
 begin
-  Result := TokenStr - PChar(FCurLine);
+  Result := TokenStr - PChar(FCurLine) + 1;
 end;
 
 Procedure TSQLScanner.ClearKeywords(Sender : TObject);

+ 14 - 0
packages/fcl-db/tests/tcparser.pas

@@ -493,6 +493,7 @@ type
     procedure TestWhereSome;
     procedure TestParam;
     procedure TestParamExpr;
+    procedure TestSourcePosition;
   end;
 
   { TTestRollBackParser }
@@ -4128,6 +4129,19 @@ begin
   AssertJoinOn(J.JoinClause,'E','F',boEq);
 end;
 
+procedure TTestSelectParser.TestSourcePosition;
+begin
+  TestSelect('SELECT X FROM ABC');
+  AssertEquals('One table',1,Select.Tables.Count);
+  AssertEquals('Table source position = 1', 1, Select.Tables[0].SourceLine);
+  AssertEquals('Table source position = 15', 15, Select.Tables[0].SourcePos);
+
+  TestSelect('SELECT X'+sLineBreak+'FROM ABC');
+  AssertEquals('One table',1,Select.Tables.Count);
+  AssertEquals('Table source position = 2', 2, Select.Tables[0].SourceLine);
+  AssertEquals('Table source position = 6', 6, Select.Tables[0].SourcePos);
+end;
+
 procedure TTestSelectParser.TestSelectTwoFieldsTwoInnerTablesJoin;
 Var
   J : TSQLJoinTableReference;