mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 18:09:27 +02:00
sql parser: support A.* syntax
git-svn-id: trunk@46436 -
This commit is contained in:
parent
1ba8255af0
commit
5bac4c25e0
@ -435,7 +435,9 @@ procedure TSQLParser.ParseSelectFieldList(AParent: TSQLSelectStatement;
|
||||
AList: TSQLElementList; Singleton: Boolean);
|
||||
Var
|
||||
F : TSQLSelectField;
|
||||
A : TSQLSelectAsterisk;
|
||||
B : Boolean;
|
||||
Expression : TSQLExpression;
|
||||
|
||||
begin
|
||||
// On entry, we're on the token preceding the field list.
|
||||
@ -479,18 +481,20 @@ begin
|
||||
end;
|
||||
B:=False;
|
||||
end;
|
||||
If (CurrentToken=tsqlMul) then
|
||||
Expression:=ParseExprLevel1(AParent,[eoSelectvalue]);
|
||||
if Expression is TSQLAsteriskExpression then
|
||||
begin
|
||||
If Singleton then
|
||||
Error(SErrNoAsteriskInSingleTon);
|
||||
AList.Add(CreateElement(TSQLSelectAsterisk,AParent));
|
||||
GetNextToken;
|
||||
A:=TSQLSelectAsterisk(CreateElement(TSQLSelectAsterisk,AParent));
|
||||
AList.Add(A);
|
||||
A.Expression:=TSQLAsteriskExpression(Expression);
|
||||
end
|
||||
else
|
||||
begin
|
||||
F:=TSQLSelectField(CreateElement(TSQLSelectField,AParent));
|
||||
AList.Add(F);
|
||||
F.Expression:=ParseExprLevel1(AParent,[eoSelectvalue]);
|
||||
F.Expression:=Expression;
|
||||
If CurrentToken in [tsqlAs,Tsqlidentifier] then
|
||||
begin
|
||||
If currentToken=tsqlAs then
|
||||
@ -2741,6 +2745,7 @@ Var
|
||||
N : String;
|
||||
C : TSQLElementClass;
|
||||
E : TSQLExtractElement;
|
||||
IdentifierPath : TSQLIdentifierPath;
|
||||
|
||||
begin
|
||||
Result:=Nil;
|
||||
@ -2852,6 +2857,11 @@ begin
|
||||
TSQLParameterExpression(Result).Identifier:=CreateIdentifier(Result,N);
|
||||
Consume(tsqlIdentifier);
|
||||
end;
|
||||
tsqlMUL:
|
||||
begin
|
||||
Result:=TSQLAsteriskExpression(CreateElement(TSQLAsteriskExpression,APArent));
|
||||
GetNextToken;
|
||||
end;
|
||||
tsqlIdentifier:
|
||||
begin
|
||||
N:=CurrentTokenString;
|
||||
@ -2860,18 +2870,30 @@ begin
|
||||
If (eoCheckConstraint in EO) and not (eoTableConstraint in EO) then
|
||||
Error(SErrUnexpectedToken,[CurrentTokenString]);
|
||||
// Plain identifier
|
||||
Result:=TSQLIdentifierExpression(CreateElement(TSQLIdentifierExpression,APArent));
|
||||
TSQLIdentifierExpression(Result).IdentifierPath.Add(CreateIdentifier(Result,N));
|
||||
IdentifierPath:=TSQLIdentifierPath.Create;
|
||||
IdentifierPath.Add(CreateIdentifier(Result,N));
|
||||
while (CurrentToken=tsqlDot) do
|
||||
begin
|
||||
GetNextToken;
|
||||
Expect(tsqlIdentifier);
|
||||
N:=CurrentTokenString;
|
||||
TSQLIdentifierExpression(Result).IdentifierPath.Add(CreateIdentifier(Result,N));
|
||||
GetNextToken;
|
||||
if CurrentToken=tsqlMUL then
|
||||
begin
|
||||
Result:=TSQLAsteriskExpression(CreateElement(TSQLAsteriskExpression,APArent));
|
||||
GetNextToken;
|
||||
break;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Expect(tsqlIdentifier);
|
||||
N:=CurrentTokenString;
|
||||
IdentifierPath.Add(CreateIdentifier(Result,N));
|
||||
GetNextToken;
|
||||
end;
|
||||
end;
|
||||
if not Assigned(Result) then
|
||||
Result:=TSQLIdentifierExpression(CreateElement(TSQLIdentifierExpression,APArent));
|
||||
TSQLIdentifierPathExpression(Result).IdentifierPath:=IdentifierPath;
|
||||
// Array access ?
|
||||
If (CurrentToken=tsqlSquareBraceOpen) then
|
||||
If (CurrentToken=tsqlSquareBraceOpen) and (Result is TSQLIdentifierExpression) then
|
||||
// Either something like array[5] or,
|
||||
// in procedures etc array[i:] where i is a variable
|
||||
begin
|
||||
|
@ -195,24 +195,39 @@ Type
|
||||
Property Identifiers[AIndex : Integer] : TSQLIdentifierName Read GetI Write SetI; default;
|
||||
end;
|
||||
|
||||
{ TSQLIdentifierPathExpression }
|
||||
|
||||
TSQLIdentifierPathExpression = Class(TSQLExpression)
|
||||
private
|
||||
FIdentifierPath: TSQLIdentifierPath;
|
||||
Public
|
||||
Destructor Destroy; override;
|
||||
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
|
||||
Property IdentifierPath: TSQLIdentifierPath Read FIdentifierPath Write FIdentifierPath;
|
||||
end;
|
||||
|
||||
{ TSQLIdentifierExpression }
|
||||
|
||||
TSQLIdentifierExpression = Class(TSQLExpression)
|
||||
TSQLIdentifierExpression = Class(TSQLIdentifierPathExpression)
|
||||
private
|
||||
FElementIndex: Integer;
|
||||
FIdentifierPath: TSQLIdentifierPath;
|
||||
function GetIdentifier: TSQLIdentifierName;
|
||||
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 GetIdentifier Write SetIdentifier;
|
||||
Property IdentifierPath: TSQLIdentifierPath Read FIdentifierPath;
|
||||
// For array types: index of element in array
|
||||
Property ElementIndex : Integer Read FElementIndex Write FElementIndex;
|
||||
end;
|
||||
|
||||
{ TSQLAsteriskExpression }
|
||||
|
||||
TSQLAsteriskExpression = Class(TSQLIdentifierPathExpression)
|
||||
Public
|
||||
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
|
||||
end;
|
||||
|
||||
{ TSQLParameterExpression }
|
||||
|
||||
TSQLParameterExpression = Class(TSQLExpression)
|
||||
@ -597,19 +612,33 @@ Type
|
||||
|
||||
{ TSelectField }
|
||||
|
||||
TSQLSelectElement = Class(TSQLElement);
|
||||
TSQLSelectAsterisk = Class(TSQLSelectElement);
|
||||
TSQLSelectElement = Class(TSQLElement)
|
||||
private
|
||||
FExpression: TSQLExpression;
|
||||
Public
|
||||
Destructor Destroy; override;
|
||||
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
|
||||
Property Expression : TSQLExpression Read FExpression Write FExpression;
|
||||
end;
|
||||
|
||||
{ TSQLSelectAsterisk }
|
||||
|
||||
TSQLSelectAsterisk = Class(TSQLSelectElement)
|
||||
private
|
||||
function GetExpression: TSQLAsteriskExpression;
|
||||
procedure SetExpression(const AExpression: TSQLAsteriskExpression);
|
||||
Public
|
||||
Property Expression : TSQLAsteriskExpression Read GetExpression Write SetExpression;
|
||||
end;
|
||||
|
||||
{ TSQLSelectField }
|
||||
|
||||
TSQLSelectField = Class(TSQLSelectElement)
|
||||
private
|
||||
FAliasName: TSQLIdentifierName;
|
||||
FExpression: TSQLExpression;
|
||||
Public
|
||||
Destructor Destroy; override;
|
||||
Function GetAsSQL(Options : TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType; override;
|
||||
Property Expression : TSQLExpression Read FExpression Write FExpression;
|
||||
Property AliasName : TSQLIdentifierName Read FAliasName Write FAliasName;
|
||||
end;
|
||||
|
||||
@ -1972,6 +2001,73 @@ begin
|
||||
Sep:=', ';
|
||||
end;
|
||||
|
||||
{ TSQLAsteriskExpression }
|
||||
|
||||
function TSQLAsteriskExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent: Integer): TSQLStringType;
|
||||
begin
|
||||
Result := inherited GetAsSQL(Options, AIndent);
|
||||
if Result<>'' then
|
||||
Result:=Result+'.';
|
||||
Result:=Result+'*';
|
||||
end;
|
||||
|
||||
{ TSQLIdentifierExpression }
|
||||
|
||||
constructor TSQLIdentifierExpression.Create(AParent: TSQLElement);
|
||||
begin
|
||||
inherited Create(AParent);
|
||||
FElementIndex:=-1;
|
||||
end;
|
||||
|
||||
function TSQLIdentifierExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent: Integer): TSQLStringType;
|
||||
begin
|
||||
Result := inherited GetAsSQL(Options, AIndent);
|
||||
If (ElementIndex<>-1) then
|
||||
Result:=Result+Format('[%d]',[Elementindex]);
|
||||
end;
|
||||
|
||||
function TSQLIdentifierExpression.GetIdentifier: TSQLIdentifierName;
|
||||
begin
|
||||
Result := TSQLIdentifierName(FIdentifierPath.Last);
|
||||
end;
|
||||
|
||||
procedure TSQLIdentifierExpression.SetIdentifier(const AName: TSQLIdentifierName);
|
||||
begin
|
||||
if Assigned(FIdentifierPath) then
|
||||
FIdentifierPath.Clear
|
||||
else
|
||||
FIdentifierPath:=TSQLIdentifierPath.Create;
|
||||
FIdentifierPath.Add(AName);
|
||||
end;
|
||||
|
||||
{ TSQLSelectElement }
|
||||
|
||||
destructor TSQLSelectElement.Destroy;
|
||||
begin
|
||||
FreeAndNil(FExpression);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TSQLSelectElement.GetAsSQL(Options: TSQLFormatOptions; AIndent: Integer): TSQLStringType;
|
||||
begin
|
||||
If Assigned(FExpression) then
|
||||
Result:=FExpression.GetAsSQL(Options)
|
||||
Else
|
||||
Result:='';
|
||||
end;
|
||||
|
||||
{ TSQLSelectAsterisk }
|
||||
|
||||
function TSQLSelectAsterisk.GetExpression: TSQLAsteriskExpression;
|
||||
begin
|
||||
Result:=TSQLAsteriskExpression(inherited Expression)
|
||||
end;
|
||||
|
||||
procedure TSQLSelectAsterisk.SetExpression(const AExpression: TSQLAsteriskExpression);
|
||||
begin
|
||||
inherited Expression:=AExpression;
|
||||
end;
|
||||
|
||||
{ TSQLIdentifierPath }
|
||||
|
||||
function TSQLIdentifierPath.Add(AName: TSQLIdentifierName): Integer;
|
||||
@ -3245,15 +3341,13 @@ end;
|
||||
|
||||
destructor TSQLSelectField.Destroy;
|
||||
begin
|
||||
FreeAndNil(FExpression);
|
||||
FreeAndNil(FAliasName);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TSQLSelectField.GetAsSQL(Options: TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType;
|
||||
begin
|
||||
If Assigned(FExpression) then
|
||||
Result:=FExpression.GetAsSQL(Options);
|
||||
Result := inherited GetAsSQL(Options, AIndent);
|
||||
If Assigned(FAliasName) then
|
||||
Result:=Result+' AS '+FAliasName.GetAsSQL(Options);
|
||||
end;
|
||||
@ -4289,37 +4383,20 @@ begin
|
||||
Result:=Result+sp+SQLKeyWord('MODULE_NAME ',Options)+SQLFormatString(ModuleName,Options);
|
||||
end;
|
||||
|
||||
{ TSQLIdentifierExpression }
|
||||
{ TSQLIdentifierPathExpression }
|
||||
|
||||
constructor TSQLIdentifierExpression.Create(AParent: TSQLElement);
|
||||
begin
|
||||
inherited Create(AParent);
|
||||
FIdentifierPath:=TSQLIdentifierPath.Create;
|
||||
FElementIndex:=-1;
|
||||
end;
|
||||
|
||||
destructor TSQLIdentifierExpression.Destroy;
|
||||
destructor TSQLIdentifierPathExpression.Destroy;
|
||||
begin
|
||||
FreeAndNil(FIdentifierPath);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TSQLIdentifierExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType;
|
||||
function TSQLIdentifierPathExpression.GetAsSQL(Options: TSQLFormatOptions; AIndent : Integer = 0): TSQLStringType;
|
||||
begin
|
||||
Result := FIdentifierPath.GetAsSQL(Options, AIndent);
|
||||
If (ElementIndex<>-1) then
|
||||
Result:=Result+Format('[%d]',[Elementindex]);
|
||||
end;
|
||||
|
||||
function TSQLIdentifierExpression.GetIdentifier: TSQLIdentifierName;
|
||||
begin
|
||||
Result := TSQLIdentifierName(FIdentifierPath.Last);
|
||||
end;
|
||||
|
||||
procedure TSQLIdentifierExpression.SetIdentifier(const AName: TSQLIdentifierName);
|
||||
begin
|
||||
FIdentifierPath.Clear;
|
||||
FIdentifierPath.Add(AName);
|
||||
if Assigned(FIdentifierPath) then
|
||||
Result:=FIdentifierPath.GetAsSQL(Options, AIndent)
|
||||
else
|
||||
Result:='';
|
||||
end;
|
||||
|
||||
{ TSQLSelectExpression }
|
||||
|
@ -400,6 +400,7 @@ type
|
||||
procedure TestSelectOneAllFieldOneTable;
|
||||
procedure TestSelectAsteriskOneTable;
|
||||
procedure TestSelectDistinctAsteriskOneTable;
|
||||
procedure TestSelectAsteriskWithPath;
|
||||
procedure TestSelectOneFieldOneTableAlias;
|
||||
procedure TestSelectOneFieldOneTableAsAlias;
|
||||
procedure TestSelectTwoFieldsTwoTables;
|
||||
@ -3993,6 +3994,17 @@ begin
|
||||
AssertTable(Select.Tables[0],'A');
|
||||
end;
|
||||
|
||||
procedure TTestSelectParser.TestSelectAsteriskWithPath;
|
||||
begin
|
||||
TestSelect('SELECT A.* FROM A');
|
||||
AssertEquals('One field',1,Select.Fields.Count);
|
||||
CheckClass(Select.Fields[0],TSQLSelectAsterisk);
|
||||
AssertEquals('Path count = 1',1,TSQLSelectAsterisk(Select.Fields[0]).Expression.IdentifierPath.Count);
|
||||
AssertEquals('Path table = A','A',TSQLSelectAsterisk(Select.Fields[0]).Expression.IdentifierPath[0].Name);
|
||||
AssertEquals('One table',1,Select.Tables.Count);
|
||||
AssertTable(Select.Tables[0],'A');
|
||||
end;
|
||||
|
||||
procedure TTestSelectParser.TestSelectDistinctAsteriskOneTable;
|
||||
begin
|
||||
TestSelect('SELECT DISTINCT * FROM A');
|
||||
|
Loading…
Reference in New Issue
Block a user