
//////////////////////////////////////////////////
//  Universal Data Access Components
//  Copyright © 2008-2014 Devart. All right reserved.
//////////////////////////////////////////////////

{$IFNDEF CLR}
{$I ODBCDac.inc}
{$IFDEF VER10P}
{$I ODBCUniProvider.inc}
{$ENDIF}
unit ODBCUniProvider;
{$ENDIF}

interface

uses
  SysUtils, Classes, Variants, DB, CRAccess, CRConnectionPool, MemData,
  {$IFNDEF FPC}MemDS{$ELSE}MemDataSet{$ENDIF}, DBAccess,
  CRTypes, CRParser, CRDataTypeMap,
  DAScript, DADump, Uni, UniProvider;

type

{$IFDEF VER16P}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TODBCUniProvider = class(TUniProvider)
  public
    class function GetProviderName: string; override;

    function IsDatabaseSupported: boolean; override;
    function IsPortSupported: boolean; override;
    function IsInOutParamSupported: boolean; override;

    function GetParserClass: TSQLParserClass; override;
    function GetConnectionParametersClass: TCRConnectionParametersClass; override;
    function GetConnectionPoolingManagerClass: TCRConnectionPoolManagerClass; override;
    function GetConnectionClass: TCRConnectionClass; override;
    function GetServerEnumeratorClass: TCRServerEnumeratorClass; override;
    function GetTransactionClass: TCRTransactionClass; override;
    function GetCommandClass: TCRCommandClass; override;
    function GetRecordSetClass: TCRRecordSetClass; override;
    function GetDataSetServiceClass: TDADataSetServiceClass; override;
    function GetScriptProcessorClass: TDAScriptProcessorClass; override;
    function GetLoaderClass: TCRLoaderClass; override;
    function GetDumpProcessorClass: TDADumpProcessorClass; override;
    function GetMetaDataClass: TCRMetaDataClass; override;
    function GetConnectDialogServiceClass: TConnectDialogServiceClass; override;
    function GetFieldTypeMapClass: TDAFieldTypeMapClass; override;
    function GetSqlFormatterClass: TUniSqlFormatterClass; override;
    function GetConverterManagerClass: TConverterManagerClass; override;

    procedure SetObjectProps(Obj: TObject; Options: TStrings; SetAllProps: boolean); override;

    function GetConnectionOptions: TOptionsList; override;
    function GetSQLOptions: TOptionsList; override;
    function GetDataSetOptions: TOptionsList; override;
  end;

  TODBCConnectDialogService = class(TConnectDialogService)
  end;

  TODBCFormatter = class(TUniSqlFormatter)
  protected
  public
    constructor Create; override;
  end;

{$IFNDEF FPC}
procedure RegisterComponent;
{$ELSE}
procedure Register;
{$ENDIF}

implementation

uses
  DAConsts, UniConsts,
{$IFNDEF UNIDACPRO}
  ODBCClasses, ODBCParser, ODBCServices, ODBCConnectionPool, ODBCDataTypeMap;
{$ELSE}
  ODBCClassesUni, ODBCParserUni, ODBCServicesUni, ODBCConnectionPoolUni, ODBCDataTypeMapUni;
{$ENDIF}

var
  ODBCFunctions, ODBCMacros: TStrValueStringList;

class function TODBCUniProvider.GetProviderName: string;
begin
  Result := 'ODBC';
end;

function TODBCUniProvider.IsDatabaseSupported: boolean;
begin
  Result := False;
end;

function TODBCUniProvider.IsPortSupported: boolean;
begin
  Result := False;
end;

function TODBCUniProvider.IsInOutParamSupported: boolean;
begin
  Result := True;
end;

function TODBCUniProvider.GetParserClass: TSQLParserClass;
begin
  Result := TODBCParser;
end;

function TODBCUniProvider.GetConnectionParametersClass: TCRConnectionParametersClass;
begin
  Result := TODBCConnectionParameters;
end;

function TODBCUniProvider.GetConnectionPoolingManagerClass: TCRConnectionPoolManagerClass;
begin
  Result := TODBCConnectionPoolManager;
end;

function TODBCUniProvider.GetConnectionClass: TCRConnectionClass;
begin
  Result := TODBCConnection;
end;

function TODBCUniProvider.GetServerEnumeratorClass: TCRServerEnumeratorClass;
begin
  Result := TODBCServerEnumerator;
end;

function TODBCUniProvider.GetTransactionClass: TCRTransactionClass;
begin
  Result := TODBCTransaction;
end;

function TODBCUniProvider.GetCommandClass: TCRCommandClass;
begin
  Result := TODBCCommand;
end;

function TODBCUniProvider.GetRecordSetClass: TCRRecordSetClass;
begin
  Result := TODBCRecordSet;
end;

function TODBCUniProvider.GetDataSetServiceClass: TDADataSetServiceClass;
begin
  Result := TCustomODBCDataSetService;
end;

function TODBCUniProvider.GetScriptProcessorClass: TDAScriptProcessorClass;
begin
  Result := TODBCScriptProcessor;
end;

function TODBCUniProvider.GetLoaderClass: TCRLoaderClass;
begin
  Result := TODBCLoader;
end;

function TODBCUniProvider.GetDumpProcessorClass: TDADumpProcessorClass;
begin
  Result := TCustomODBCDumpProcessor;
end;

function TODBCUniProvider.GetMetaDataClass: TCRMetaDataClass;
begin
  Result := TODBCMetaData;
end;

function TODBCUniProvider.GetConnectDialogServiceClass: TConnectDialogServiceClass;
begin
  Result := TODBCConnectDialogService;
end;

function TODBCUniProvider.GetFieldTypeMapClass: TDAFieldTypeMapClass;
begin
  Result := TCustomODBCFieldTypeMap;
end;

function TODBCUniProvider.GetSqlFormatterClass: TUniSqlFormatterClass;
begin
  Result := TODBCFormatter;
end;

function TODBCUniProvider.GetConverterManagerClass: TConverterManagerClass;
begin
  Result := TODBCConverterManager;
end;

procedure TODBCUniProvider.SetObjectProps(Obj: TObject; Options: TStrings; SetAllProps: boolean);
begin
  inherited;
end;

function TODBCUniProvider.GetConnectionOptions: TOptionsList;
begin
  if FConnectionOptions = nil then begin
    FConnectionOptions := TOptionsList.Create(GetProviderName);
    FConnectionOptions.Add(TIntegerOption.Create('ConnectionTimeout', prConnectionTimeout, [TODBCConnection, TODBCConnectionParameters], 15, True));
    FConnectionOptions.Add(TIntegerOption.Create('DefaultStrParamSize', prDetectFieldsOnPrepare, [TODBCConnection], DefaultStrParamSize));
    FConnectionOptions.Add(TBooleanOption.Create('DetectFieldsOnPrepare', prDetectFieldsOnPrepare, [TODBCConnection], True));
    FConnectionOptions.Add(TEnumeratorOption.Create('DSNType', prDSNType, [TODBCConnection, TODBCConnectionParameters], Variant(ntAuto), TypeInfo(TDSNType)));
    FConnectionOptions.Add(TBooleanOption.Create('UseUnicode', prUseUnicode, [TODBCConnection], False, True));
    FConnectionOptions.Add(TBooleanOption.Create('VarBytesAsBlob', prVarBytesAsBlob, [TODBCConnection], True, False));
  end;
  Result := FConnectionOptions;
end;

function TODBCUniProvider.GetSQLOptions: TOptionsList;
begin
  if FSQLOptions = nil then begin
    FSQLOptions := TOptionsList.Create(GetProviderName);
    FSQLOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TODBCCommand], 0));
  end;
  Result := FSQLOptions;
end;

function TODBCUniProvider.GetDataSetOptions: TOptionsList;
begin
  if FDataSetOptions = nil then begin
    FDataSetOptions := TOptionsList.Create(GetProviderName);
    FDataSetOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TODBCRecordSet], 0));
    FDataSetOptions.Add(TBooleanOption.Create('ExtendedFieldsInfo', prExtendedFieldsInfo, [TODBCRecordSet], False));
    FDataSetOptions.Add(TBooleanOption.Create('FetchAll', prFetchAll, [TODBCRecordSet], True));
  end;
  Result := FDataSetOptions;
end;

{ TODBCFormatter }

constructor TODBCFormatter.Create;
begin
  inherited;

  FFunctions := ODBCFunctions;
  FPredefinedMacros := ODBCMacros;
end;

{$IFNDEF FPC}
procedure RegisterComponent;
{$ELSE}
procedure Register;
{$ENDIF}
begin
  RegisterComponents('UniDAC Providers', [TODBCUniProvider]);
end;

initialization
  UniProviders.RegisterProvider(TODBCUniProvider);

  ODBCFunctions := TStrValueStringList.Create;
  ODBCFunctions.Add('USER', 'USER');
  ODBCFunctions.Add('CHAR_LENGTH', 'LENGTH(%s)');
  ODBCFunctions.Add('LOCATE', 'POSSTR(%1:s, %0:s)');
  ODBCFunctions.Add('SUBSTRING', 'SUBSTR(%s, %s, %s)');
  ODBCFunctions.Add('CONCAT', '%s || %s');
  ODBCFunctions.Add('CHAR', 'CHR(%s)');
  ODBCFunctions.Add('TRIM', 'TRIM(%s)');
  ODBCFunctions.Add('TRUNCATE', 'TRUNCATE(%s, %s)');
  ODBCFunctions.Add('CEILING', 'CEILING(%s)');
  // Date-time
  ODBCFunctions.Add('CURRENT_DATE', 'CURRENT_DATE');
  ODBCFunctions.Add('YEAR', 'YEAR(%s)');
  ODBCFunctions.Add('MONTH', 'MONTH(%s)');
  ODBCFunctions.Add('DAY', 'DAY(%s)');
  //ODBCFunctions.Add('DATEADD', 'DATE(%2:s, ''%1:s %0:s'')');
  //ODBCFunctions.Add('DATEDIFF', 'EXTRACT(%s FROM (%2:s - %1:s))');
  // Date-time literals
  ODBCFunctions.Add('__DATE_TIME_LITERAL', 'CAST(%s AS TIMESTAMP)');
  ODBCFunctions.Add('__DATE_LITERAL', 'CAST(%s AS DATE)');
  ODBCFunctions.Add('__TIME_LITERAL', 'CAST(%s AS TIME)');
  // CONVERT functions
  ODBCFunctions.Add('TODATE', 'CAST(%s AS TIMESTAMP)');
  ODBCFunctions.Add('TONUMBER', 'CAST(%s AS DOUBLE)');
  ODBCFunctions.Add('TOCHAR', 'CAST(%s AS VARCHAR)');

  ODBCMacros := TStrValueStringList.Create;
  ODBCMacros.Add('PROVIDER', 'ODBC');
  ODBCMacros.Add('ODBC', '');
  // DataType macros
  ODBCMacros.Add('DATETIME', 'TIMESTAMP');
  ODBCMacros.Add('DOUBLE', 'DOUBLE');
  ODBCMacros.Add('VARCHAR', 'VARCHAR');

finalization
  UniProviders.UnRegisterProvider(TODBCUniProvider);

  ODBCFunctions.Free;
  ODBCMacros.Free;

end.
