⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gasqlparserhelperclasses.pas

📁 一个sql语法分析程序
💻 PAS
📖 第 1 页 / 共 2 页
字号:
        ParsePreFieldExpression(AToken);
      fepsFieldExpression:
        ParseFieldExpression(AToken);
      fepsFieldAlias:
        ParseFieldAlias(AToken);
      fepsFieldAliasParsed:
        if AToken.TokenType <> stDelimitier then
          StartExpressionParse;
      fepsFieldParseFinished:
        raise Exception.Create(SerrFieldParseFinised);
      { fepsExpression:
        Shouldn't get here as IsExpression should be true then }
      else
        raise Exception.CreateFmt(SerrUnecpectedFieldParseState,
          [GetEnumName(TypeInfo(TFieldExprParseState), Ord(FieldParseState))]);
    end;
    if (AToken.TokenType = stComma) then
      ParseComplete := True;
  end;
end;

function TgaSQLField.GetFieldAlias: string;
begin
  if Assigned(FFieldAlias) then
    Result := GetTokenObjAsString(FFieldAlias.TokenObj)
  else
    Result := EmptyStr;
end;

function TgaSQLField.GetFieldName: string;
begin
  if Assigned(FFieldName) then
    Result := GetTokenObjAsString(FFieldName.TokenObj)
  else
    Result := EmptyStr;
end;

function TgaSQLField.GetFieldPrefix: string;
begin
  Result := FFieldPrefixies.AsString;
end;

procedure TgaSQLField.InternalSetParseComplete;
begin
  inherited;
  FFieldParseState := fepsFieldParseFinished;
end;

procedure TgaSQLField.ParseFieldAlias(AToken: TgaSQLTokenObj);
begin
  case AToken.TokenType of
    stDelimitier:
      {no special processing};
    stSymbol, stQuotedSymbol, stString:
      if not AToken.TokenSymbolIs('AS') then
      begin
        FFieldAlias := GetBookmark;
        FFieldParseState := fepsFieldAliasParsed;
      end;
    else
      StartExpressionParse;
  end;
end;

procedure TgaSQLField.ParseFieldExpression(AToken: TgaSQLTokenObj);
begin
  case AToken.TokenType of
    stSymbol, stQuotedSymbol, stPeriod:
      ;
    stDelimitier, stComma:
    begin
      FFieldPrefixies.Last;
      // last one should be the current comma or delimitier
      FFieldPrefixies.Previous;
      if FFieldPrefixies.CurrentItem.TokenType <> stPeriod then
      begin
        Locate(FFieldPrefixies.CurrentItem);
        FFieldName := GetBookmark;
        FFieldPrefixies.Previous;
      end;
      FFieldPrefixies.SetEndPos(FFieldPrefixies, True);
      FFieldParseState := fepsFieldAlias;
      { #ToDo2 Should there be an property do determ whete field alias is
                allowed or not }
    end;
    stOther:
      if AToken.TokenString <> '*' then
        StartExpressionParse;
    else
      StartExpressionParse;
  end;
end;

procedure TgaSQLField.ParsePreFieldExpression(AToken: TgaSQLTokenObj);
begin
  case AToken.TokenType of
    stSymbol, stQuotedSymbol, stPeriod:
    begin
      FFieldPrefixies.SetStartPos(Self, True);
      FFieldParseState := fepsFieldExpression;
    end;
    stDelimitier:
        { skip leading whitespaces };
    stComma:
      IsInvalid := True;
    stOther:
      if AToken.TokenString = '*' then
      begin
        FFieldName := GetBookmark;
        FFieldParseState := fepsFieldAliasParsed;
      end else
        StartExpressionParse;
    else
      StartExpressionParse;
  end;
end;

procedure TgaSQLField.SetFieldAlias(const Value: string);
var
  tmpTokenList: TgaSQLTokenHolderList;
  tmpToken: TgaSQLTokenObj;
begin
  if FieldAlias <> Value then
  begin
    CheckModifyAllowed;
    tmpTokenList := TgaSQLTokenHolderList.Create(nil);
    try
      ParseStringToTokens(Value, tmpTokenList);
      TrimTokenList(tmpTokenList, True);
      if tmpTokenList.Count > 1 then
        raise Exception.CreateFmt(SerrWrongTokenCountInArg, ['Field alias', 1, tmpTokenList.Count]);
      tmpTokenList.First;
      if Assigned(FFieldAlias) then
        FFieldAlias.TokenObj := tmpTokenList.CurrentItem
      else begin
        if IsExpression then
          Last
        else
          GotoBookmark(FFieldName);
        tmpToken := TgaSQLTokenObj.Create;
        tmpToken.SetTokenInfo(' ', stDelimitier, False, #0);
        InsertAfterCurrent(tmpToken, True);
        InsertAfterCurrent(tmpTokenList.CurrentItem, True);
        FFieldAlias := GetBookmark;
      end;
    finally
      tmpTokenList.Free;
    end;
  end;
end;

procedure TgaSQLField.SetFieldName(const Value: string);
var
  tmpTokenList: TgaSQLTokenHolderList;
begin
  if FieldName <> Value then
  begin
    CheckModifyAllowed;
    if IsExpression then
      raise Exception.Create(SerrFieldAttrCantBeChangedInExpression);
    tmpTokenList := TgaSQLTokenHolderList.Create(nil);
    try
      ParseStringToTokens(Value, tmpTokenList);
      TrimTokenList(tmpTokenList, True);
      if tmpTokenList.Count <> 1 then
        raise Exception.CreateFmt(SerrWrongTokenCountInArg, ['Field name', 1, tmpTokenList.Count]);
      tmpTokenList.First;
      FFieldName.TokenObj := tmpTokenList.CurrentItem;
    finally
      tmpTokenList.Free;
    end;
  end;
end;

procedure TgaSQLField.SetFieldPrefix(const Value: string);
var
  tmpStr: string;
  tmpTokenList: TgaSQLTokenHolderList;
begin
  if Value[Length(Value)] = '.' then
    tmpStr := Value
  else
    tmpStr := Value + '.';
  if (FieldPrefix <> tmpStr) then
  begin
    CheckModifyAllowed;
    if IsExpression then
      raise Exception.Create(SerrFieldAttrCantBeChangedInExpression);
    tmpTokenList := TgaSQLTokenHolderList.Create(nil);
    try
      ParseStringToTokens(tmpStr, tmpTokenList);
      TrimTokenList(tmpTokenList, True);
      FieldPrefixies.CopyListContest(tmpTokenList)
    finally
      tmpTokenList.Free;
    end;
  end;
end;

procedure TgaSQLField.StartExpressionParse;
begin
  FreeAndNil(FFieldName);
  FreeAndNil(FFieldAlias);
  FreeAndNil(FFieldPrefixies);
  FIsExpression := True;
  FFieldParseState := fepsExpression;
  First;
  while not Eof do
  begin
    ParseExpression(CurrentItem);
    Next;
  end;
end;

{
*************************** TgaSQLStatementPartList ****************************
}
constructor TgaSQLStatementPartList.Create(AOwnerStatement: 
        TgaCustomSQLStatement; AStatementPartType: TgaSQLStatementPartClass);
begin
  inherited Create;
  FTokenList := TgaSQLTokenList.CreateMirror(AOwnerStatement, 
          AOwnerStatement.CurrentSQL);
  FTokenList.SetStartPos(AOwnerStatement.CurrentSQL, True);
  FStatementPartType := AStatementPartType;
  FOwnerStatement := AOwnerStatement;
end;

destructor TgaSQLStatementPartList.Destroy;
begin
  FreeAndNil(FTokenList);
  inherited Destroy;
end;

procedure TgaSQLStatementPartList.Clear;
begin
  FCurrentPart := nil;
  inherited Clear;
  if Assigned(TokenList) then
    TokenList.Clear;
end;

procedure TgaSQLStatementPartList.ExecuteTokenAdded(Sender: TObject; AToken: 
        TgaSQLTokenObj);
begin
  CurrentPart.ExecuteTokenAdded(Sender, AToken);
  if CurrentPart.ParseComplete then
    FCurrentPart := nil;
  TokenList.Locate(AToken);
end;

function TgaSQLStatementPartList.GetAsString: string;
begin
  Result := inherited GetAsString;
end;

function TgaSQLStatementPartList.GetCurrentPart: TgaSQLStatementPart;
begin
  if not Assigned(FCurrentPart) then
  begin
    FCurrentPart := StatementPartType.Create(OwnerStatement);
    Add(FCurrentPart);
  end;
  Result := FCurrentPart;
end;

function TgaSQLStatementPartList.GetParseComplete: Boolean;
begin
  Result := FParseComplete;
end;

procedure TgaSQLStatementPartList.InternalSetParseComplete;
begin
  FParseComplete := True;
  TokenList.SetEndPos(TokenList, True);
  TokenList.ActiveDataShare := False;
end;

procedure TgaSQLStatementPartList.SetAsString(const Value: string);
var
  tmpTokenList: TgaSQLTokenHolderList;
  AItem: TgaSQLTokenObj;
begin
  tmpTokenList := TgaSQLTokenHolderList.Create(nil);
  try
    ParseStringToTokens(Value, tmpTokenList);
    TrimTokenList(tmpTokenList, True, [stEnd]);
    if tmpTokenList.Count = 0 then
      tmpTokenList.AddToken(TgaSQLTokenObj.CreatePlaceHolder);
    Clear;
    tmpTokenList.First;
    while not tmpTokenList.Eof do
    begin
      AItem := tmpTokenList.CurrentItem;
      TokenList.Add(AItem);
      // #Todo2 this can be optimized
      OwnerStatement.CurrentSQL.Locate(AItem);
      ExecuteTokenAdded(Self, AItem);
      tmpTokenList.Next;
    end;
  finally
    tmpTokenList.Free;
  end;
end;

procedure TgaSQLStatementPartList.SetParseComplete(const Value: Boolean);
begin
  if Value then
    InternalSetParseComplete;
end;

{
******************************* TgaSQLFieldList ********************************
}
constructor TgaSQLFieldList.Create(AOwnerStatement: TgaCustomSQLStatement);
begin
  inherited Create(AOwnerSTatement, TgaSQLField);
end;

{
******************************* TgaSQLTableList ********************************
}
constructor TgaSQLTableList.Create(AOwnerStatement: TgaCustomSQLStatement);
begin
  inherited Create(AOwnerSTatement, TgaSQLTable);
end;

{
****************************** TgaSQLOrderByList *******************************
}
function TgaSQLOrderByList.GetAsString: string;
begin
  Result := EmptyStr;
  if TokenList.IsEmpty then
    Exit;
  TokenList.First;
  if TokenList.CurrentItem.TokenSymbolIs('ORDER') then
  begin
    TokenList.Next;
    while (not TokenList.Eof) and (TokenList.CurrentItem.TokenType = stDelimitier) do
      TokenList.Next;
    if TokenList.CurrentItem.TokenSymbolIs('BY') then
    begin
      TokenList.Next;
      while (not TokenList.Eof) and (TokenList.CurrentItem.TokenType = stDelimitier) do
        TokenList.Next;
    end;
  end;
  while not TokenList.Eof do
  begin
    Result := Result + TokenList.CurrentItem.TokenAsString;
    TokenList.Next;
  end;
end;

procedure TgaSQLOrderByList.SetAsString(const Value: string);
var
  tmpStr: string;
  tmpToken: TgaSQLTokenObj;
begin
  if (Trim(Value) = '') or (SameText('order by ', Copy(Value, 1, 9))) then
    tmpStr := Value
  else
    tmpStr := 'order by ' + Value;
  inherited SetAsString(tmpStr);
  TokenList.Last;
  if TokenList.CurrentItem.TokenType <> stDelimitier then
  begin
    tmpToken := TgaSQLTokenObj.Create;
    tmpToken.SetTokenInfo(#13#10, stDelimitier, False, #0);
    TokenList.Add(tmpToken);
    ExecuteTokenAdded(Self, tmpToken);
  end;
end;

{
***************************** TgaSQLStatementPart ******************************
}
constructor TgaSQLStatementPart.Create(AOwnerStatement: TgaCustomSQLStatement);
begin
  if not Assigned(AOwnerStatement) then
    raise Exception.Create(SerrStmPartWithoutStm);
  inherited CreateMirror(AOwnerStatement, AOwnerStatement.CurrentSQL);
end;

procedure TgaSQLStatementPart.CheckModifyAllowed;
begin
  if not Assigned(OwnerStatement) then
    raise Exception.Create(SerrNowOwnerParser)
end;

function TgaSQLStatementPart.GetAsString: string;
begin
  Result := inherited GetAsString;
end;

function TgaSQLStatementPart.GetParseComplete: Boolean;
begin
  Result := InternalGetParseComplete;
end;

function TgaSQLStatementPart.InternalGetParseComplete: Boolean;
begin
  Result := FParseComplete;
end;

procedure TgaSQLStatementPart.InternalSetParseComplete;
begin
  FParseComplete := True;
  SetEndPos(Self, True);
  ActiveDataShare := False;
end;

procedure TgaSQLStatementPart.SetAsString(const Value: string);
var
  tmpTokenList: TgaSQLTokenHolderList;
begin
  CheckModifyAllowed;
  tmpTokenList := TgaSQLTokenHolderList.Create(nil);
  try
    ParseStringToTokens(Value, tmpTokenList);
    TrimTokenList(tmpTokenList, True, [stEnd]);
    if tmpTokenList.Count = 0 then
      tmpTokenList.AddToken(TgaSQLTokenObj.CreatePlaceHolder);
    CopyListContest(tmpTokenList);
  finally
    tmpTokenList.Free;
  end;
end;

procedure TgaSQLStatementPart.SetIsInvalid(const Value: Boolean);
begin
  FIsInvalid := Value;
end;

procedure TgaSQLStatementPart.SetParseComplete(const Value: Boolean);
begin
  if Value then
    InternalSetParseComplete;
end;

{
******************************* TgaSQLExpression *******************************
}
constructor TgaSQLExpression.Create(AOwnerStatement: TgaCustomSQLStatement);
begin
  inherited Create(AOwnerStatement);
  FisExpression := True;
  FIsCorrect := True;
end;

procedure TgaSQLExpression.AddParen(AToken: TgaSQLTokenObj);
begin
  if FParenCount = 0 then
  begin
    FOldOnStatementAdd := OwnerStatement.OnTokenAdded;
    OwnerStatement.OnTokenAdded := ExecuteTokenAdded;
  end;
  Inc(FParenCount);
end;

procedure TgaSQLExpression.ExecuteTokenAdded(Sender: TObject; AToken: 
        TgaSQLTokenObj);
begin
  inherited ;
  if AToken.TokenType = stComment then
    Exit;
  if IsExpression then
    ParseExpression(AToken);
end;

function TgaSQLExpression.GetCanParseEnd: Boolean;
begin
  Result := ParenCount = 0;
end;

function TgaSQLExpression.GetExpression: string;
begin
  if IsExpression then
    Result := AsString
  else
    Result := EmptyStr;
end;

procedure TgaSQLExpression.ParseExpression(AToken: TgaSQLTokenObj);
begin
  // #Todo3 Expression parsing not implemented... yet
  case AToken.TokenType of
    stLParen:
      AddParen(AToken);
    stRParen:
      RemoveParen(AToken);
  end;
end;

procedure TgaSQLExpression.RemoveParen(AToken: TgaSQLTokenObj);
begin
  Dec(FParenCount);
  if ParenCount = 0 then
    OwnerStatement.OnTokenAdded := FOldOnStatementAdd;
  if ParenCount < 0 then
    FIsCorrect := False;
end;

procedure TgaSQLExpression.SetIsExpression(const Value: Boolean);
begin
  FIsExpression := Value;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -