mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-08 10:39:29 +02:00
sql parser: support field with schema
git-svn-id: trunk@46421 -
(cherry picked from commit 97ced59af0
)
This commit is contained in:
parent
2889615156
commit
24571f17f2
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user