unit Aurelius.Sql.Firebird;

{$I Aurelius.inc}

interface

uses
  Aurelius.Sql.AnsiSqlGenerator,
  Aurelius.Sql.BaseTypes,
  Aurelius.Sql.Commands,
  Aurelius.Sql.Interfaces,
  Aurelius.Sql.Metadata,
  Aurelius.Sql.Register;

type
  TFirebirdSQLGenerator = class(TAnsiSQLGenerator)
  private
    FWideStringCharSet: string;
  protected
    function GetMaxConstraintNameLength: Integer; override;
    procedure DefineColumnType(Column: TColumnMetadata); override;

    function GetGeneratorName: string; override;
    function GetSqlDialect: string; override;

    function GenerateInsert(Command: TInsertCommand): string; override;
    function GenerateGetNextSequenceValue(Command: TGetNextSequenceValueCommand): string; override;
    function GenerateCreateSequence(Sequence: TSequenceMetadata): string; override;
    function GenerateDropSequence(Sequence: TSequenceMetadata): string; override;
    function GenerateLimitedSelect(SelectSql: TSelectSql; Command: TSelectCommand): string; override;
    function GenerateDropDBIndex(DBIndex: TDBIndexMetadata): string; override;

    function GetSupportedFeatures: TDBFeatures; override;
  public
    constructor Create;
    procedure AfterConstruction; override;
    property WideStringCharSet: string read FWideStringCharSet write FWideStringCharSet;
  end;

implementation

uses
  DB, SysUtils,
  Aurelius.Sql.Functions;

{ TFirebirdSQLGenerator }

procedure TFirebirdSQLGenerator.AfterConstruction;
begin
  inherited;
  FWideStringCharSet := 'ISO8859_1';
end;

constructor TFirebirdSQLGenerator.Create;
begin
  inherited Create;

//  RegisterFunction('length', TSimpleSQLFunction.Create('character_length', TypeInfo(integer)));
//  RegisterFunction('position', TSimpleSQLFunction.Create('position', TypeInfo(integer)));
end;

procedure TFirebirdSQLGenerator.DefineColumnType(Column: TColumnMetadata);
begin
  DefineNumericColumnType(Column);
  if Column.DataType <> '' then
    Exit;

  case Column.FieldType of
    ftLargeInt:
      begin
        Column.DataType := 'NUMERIC($pre)';
        Column.Precision := 18;
      end;

    ftWideString:
      Column.DataType := Format('VARCHAR($len) CHARACTER SET %s', [WideStringCharSet]);

    ftFixedWideChar:
      Column.DataType := Format('CHAR($len) CHARACTER SET %s', [WideStringCharSet]);

    ftCurrency:
      begin
        Column.DataType := 'NUMERIC($pre, $sca)';
        Column.Precision := 18;
        Column.Scale := 4;
      end;
//    ftFMTBcd:
//      Column.DataType := 'NUMERIC(18, 9)';

    ftMemo:
      Column.DataType := 'BLOB SUB_TYPE TEXT';
    ftWideMemo:
      Column.DataType := 'BLOB SUB_TYPE TEXT';
    ftBlob:
      Column.DataType := 'BLOB';
  else
    inherited DefineColumnType(Column);
  end;
end;

function TFirebirdSQLGenerator.GenerateCreateSequence(Sequence: TSequenceMetadata): string;
begin
  Result := 'CREATE GENERATOR ' + IdName(Sequence.Name);
end;

function TFirebirdSQLGenerator.GenerateDropDBIndex(DBIndex: TDBIndexMetadata): string;
begin
  Result := 'DROP INDEX ' + DBIndex.Name;
end;

function TFirebirdSQLGenerator.GenerateDropSequence(Sequence: TSequenceMetadata): string;
begin
  Result := 'DROP GENERATOR ' + IdName(Sequence.Name);
end;

function TFirebirdSQLGenerator.GenerateGetNextSequenceValue(
  Command: TGetNextSequenceValueCommand): string;
begin
  Result := 'SELECT GEN_ID(' + IdName(Command.SequenceName) + ', ' +
    IntToStr(Command.Increment) + ') FROM RDB$DATABASE';
end;

function TFirebirdSQLGenerator.GenerateInsert(Command: TInsertCommand): string;
begin
  Result := inherited GenerateInsert(Command);
  if Command.OutputColumn <> '' then
    Result := Result + ' RETURNING ' + Command.OutputColumn;
end;

function TFirebirdSQLGenerator.GenerateLimitedSelect(SelectSql: TSelectSql; Command: TSelectCommand): string;
begin
  Result := GenerateRegularSelect(SelectSql) + sqlLineBreak;
  if Command.HasFirstRow then
    Result := Result + Format('ROWS %d To %d', [Command.FirstRow + 1, Command.LastRow + 1])
  else
    Result := Result + Format('ROWS %d', [Command.MaxRows]);
end;

function TFirebirdSQLGenerator.GetSqlDialect: string;
begin
  Result := 'Firebird';
end;

function TFirebirdSQLGenerator.GetGeneratorName: string;
begin
  Result := 'Firebird SQL Generator';
end;

function TFirebirdSQLGenerator.GetMaxConstraintNameLength: Integer;
begin
  Result := 31;
end;

function TFirebirdSQLGenerator.GetSupportedFeatures: TDBFeatures;
begin
  Result := AllDBFeatures - [TDBFeature.AutoGenerated, TDBFeature.RetrieveIdOnInsert,
    TDBFeature.Schemas];
end;

initialization
  TSQLGeneratorRegister.GetInstance.RegisterGenerator(TFirebirdSQLGenerator.Create);

end.
