sql parser: support field with schema

git-svn-id: trunk@46421 -
(cherry picked from commit 97ced59af0)
This commit is contained in:
ondrej 2020-08-14 10:06:33 +00:00 committed by marcoonthegit
parent 2889615156
commit 24571f17f2
3 changed files with 111 additions and 15 deletions

View File

@ -2757,16 +2757,17 @@ begin
begin
If (eoCheckConstraint in EO) and not (eoTableConstraint in EO) then
Error(SErrUnexpectedToken,[CurrentTokenString]);
If (CurrentToken=tsqlDot) then
// Plain identifier
Result:=TSQLIdentifierExpression(CreateElement(TSQLIdentifierExpression,APArent));
TSQLIdentifierExpression(Result).AddIdentifierToPath(CreateIdentifier(Result,N));
while (CurrentToken=tsqlDot) do
begin
GetNextToken;
Expect(tsqlIdentifier);
N:=N+'.'+CurrentTokenString;
N:=CurrentTokenString;
TSQLIdentifierExpression(Result).AddIdentifierToPath(CreateIdentifier(Result,N));
GetNextToken;
end;
// Plain identifier
Result:=TSQLIdentifierExpression(CreateElement(TSQLIdentifierExpression,APArent));
TSQLIdentifierExpression(Result).Identifier:=CreateIdentifier(Result,N);
// Array access ?
If (CurrentToken=tsqlSquareBraceOpen) then
// Either something like array[5] or,

View File

@ -188,12 +188,20 @@ Type
TSQLIdentifierExpression = Class(TSQLExpression)
private
FElementIndex: Integer;
FIdentifier: TSQLIdentifierName;
FIdentifierPath: array of TSQLIdentifierName;
function GetIdentifier: TSQLIdentifierName;
function GetIdentifierPath(Index: Integer): TSQLIdentifierName;
function GetIdentifierPathCount: Integer;
procedure SetIdentifier(const AName: TSQLIdentifierName);
Public
Constructor Create(AParent : TSQLElement); override;
Destructor Destroy; override;
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
Property Identifier : TSQLIdentifierName Read FIdentifier Write FIdentifier;
Property Identifier : TSQLIdentifierName Read GetIdentifier Write SetIdentifier;
Property IdentifierPathCount: Integer Read GetIdentifierPathCount;
Procedure AddIdentifierToPath(AName: TSQLIdentifierName);
Procedure ClearIdentifierPath;
Property IdentifierPath[Index: Integer] : TSQLIdentifierName Read GetIdentifierPath;
// For array types: index of element in array
Property ElementIndex : Integer Read FElementIndex Write FElementIndex;
end;
@ -4149,20 +4157,66 @@ begin
FElementIndex:=-1;
end;
procedure TSQLIdentifierExpression.AddIdentifierToPath(AName: TSQLIdentifierName);
begin
SetLength(FIdentifierPath, Length(FIdentifierPath)+1);
FIdentifierPath[High(FIdentifierPath)] := AName;
end;
procedure TSQLIdentifierExpression.ClearIdentifierPath;
var
N: TSQLIdentifierName;
begin
for N in FIdentifierPath do
N.Free;
FIdentifierPath:=nil;
end;
destructor TSQLIdentifierExpression.Destroy;
begin
FreeAndNil(FIdentifier);
ClearIdentifierPath;
inherited Destroy;
end;
function TSQLIdentifierExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType;
var
N: TSQLIdentifierName;
begin
If Assigned(FIdentifier) then
Result:= Identifier.GetAsSQL(Options);
Result := '';
for N in FIdentifierPath do
begin
if Result<>'' then
Result:=Result+'.';
Result:=Result+N.GetAsSQL(Options);
end;
If (ElementIndex<>-1) then
Result:=Result+Format('[%d]',[Elementindex]);
end;
function TSQLIdentifierExpression.GetIdentifier: TSQLIdentifierName;
begin
if Length(FIdentifierPath)>0 then
Result:=FIdentifierPath[High(FIdentifierPath)]
else
Result:=nil;
end;
function TSQLIdentifierExpression.GetIdentifierPath(Index: Integer): TSQLIdentifierName;
begin
Result := FIdentifierPath[Index];
end;
function TSQLIdentifierExpression.GetIdentifierPathCount: Integer;
begin
Result := Length(FIdentifierPath);
end;
procedure TSQLIdentifierExpression.SetIdentifier(const AName: TSQLIdentifierName);
begin
ClearIdentifierPath;
AddIdentifierToPath(AName);
end;
{ TSQLSelectExpression }
function TSQLSelectExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType;

View File

@ -412,6 +412,7 @@ type
procedure TestSelectTwoFieldsBracketThreeTablesJoin;
procedure TestSelectTwoFieldsThreeBracketTablesJoin;
procedure TestSelectTableWithSchema;
procedure TestSelectFieldWithSchema;
procedure TestAggregateCount;
procedure TestAggregateCountAsterisk;
procedure TestAggregateCountAll;
@ -3737,6 +3738,26 @@ begin
AssertException(ESQLParser,@TestParseError);
end;
procedure TTestSelectParser.TestSelectFieldWithSchema;
Var
Expr: TSQLIdentifierExpression;
begin
TestSelect('SELECT S.A.B,C FROM S.A');
AssertEquals('Two fields',2,Select.Fields.Count);
AssertField(Select.Fields[0],'B');
Expr := ((Select.Fields[0] as TSQLSelectField).Expression as TSQLIdentifierExpression);
AssertEquals('Field[0] path has 3 identifiers',3,Expr.IdentifierPathCount);
AssertEquals('Field[0] schema is S','S',Expr.IdentifierPath[0].Name);
AssertEquals('Field[0] table is A','A',Expr.IdentifierPath[1].Name);
AssertField(Select.Fields[1],'C');
AssertEquals('One table',1,Select.Tables.Count);
AssertTable(Select.Tables[0],'A','');
AssertEquals('Table path has 2 objects',2,(Select.Tables[0] as TSQLSimpleTableReference).ObjectNamePathCount);
AssertEquals('Schema name = S','S',(Select.Tables[0] as TSQLSimpleTableReference).ObjectNamePath[0].Name);
end;
procedure TTestSelectParser.TestSelectOneFieldOneTable;
begin
TestSelect('SELECT B FROM A');
@ -3802,12 +3823,17 @@ end;
procedure TTestSelectParser.TestSelectOneTableFieldOneTable;
Var
Expr: TSQLIdentifierExpression;
begin
TestSelect('SELECT A.B FROM A');
AssertEquals('One field',1,Select.Fields.Count);
// Field does not support linking/refering to a table, so the field name is
// assigned as A.B (instead of B with a <link to table A>)
AssertField(Select.Fields[0],'A.B');
// Field supports linking/refering to a table
AssertField(Select.Fields[0],'B');
Expr := ((Select.Fields[0] as TSQLSelectField).Expression as TSQLIdentifierExpression);
AssertEquals('Field has explicit table',2,Expr.IdentifierPathCount);
AssertEquals('Field has explicit table named A','A',Expr.IdentifierPath[0].Name);
AssertEquals('One table',1,Select.Tables.Count);
AssertTable(Select.Tables[0],'A');
end;
@ -3815,6 +3841,7 @@ end;
procedure TTestSelectParser.TestSelectTableWithSchema;
begin
TestSelect('SELECT B,C FROM S.A');
AssertEquals('Two fields',2,Select.Fields.Count);
AssertField(Select.Fields[0],'B');
AssertField(Select.Fields[1],'C');
AssertEquals('One table',1,Select.Tables.Count);
@ -3863,19 +3890,33 @@ begin
end;
procedure TTestSelectParser.TestSelectOneFieldOneTableAlias;
Var
Expr: TSQLIdentifierExpression;
begin
TestSelect('SELECT C.B FROM A C');
AssertEquals('One field',1,Select.Fields.Count);
AssertField(Select.Fields[0],'C.B');
AssertField(Select.Fields[0],'B');
Expr := ((Select.Fields[0] as TSQLSelectField).Expression as TSQLIdentifierExpression);
AssertEquals('Field has explicit table',2,Expr.IdentifierPathCount);
AssertEquals('Field has explicit table named C','C',Expr.IdentifierPath[0].Name);
AssertEquals('One table',1,Select.Tables.Count);
AssertTable(Select.Tables[0],'A');
end;
procedure TTestSelectParser.TestSelectOneFieldOneTableAsAlias;
Var
Expr: TSQLIdentifierExpression;
begin
TestSelect('SELECT C.B FROM A AS C');
AssertEquals('One field',1,Select.Fields.Count);
AssertField(Select.Fields[0],'C.B');
AssertField(Select.Fields[0],'B');
Expr := ((Select.Fields[0] as TSQLSelectField).Expression as TSQLIdentifierExpression);
AssertEquals('Field has explicit table',2,Expr.IdentifierPathCount);
AssertEquals('Field has explicit table named C','C',Expr.IdentifierPath[0].Name);
AssertEquals('One table',1,Select.Tables.Count);
AssertTable(Select.Tables[0],'A');
end;