sql parser: support A.* syntax

git-svn-id: trunk@46436 -
This commit is contained in:
ondrej 2020-08-14 18:40:46 +00:00
parent 1ba8255af0
commit 5bac4c25e0
3 changed files with 157 additions and 46 deletions

View File

@ -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

View File

@ -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 }

View File

@ -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');