
//////////////////////////////////////////////////
//  MySQL Data Access Components
//  Copyright © 1998-2025 Devart. All right reserved.
//////////////////////////////////////////////////

{$IFNDEF CLR}

{$I MyDac.inc}

unit MyDesignUtils;
{$ENDIF}

interface

uses
{$IFDEF DBTOOLS}
  DBToolsClient, DBToolsIntf, DB, DesignIntf,
{$ENDIF}
  Classes, SysUtils, CRTypes, DBAccess, CRDataTypeMap,
  CRDesignUtils, DADesignUtils;

type

{$IFDEF DBTOOLS}
  TMyIntegrationTool = ({$IFDEF VER11P}mitDBForgeFusion, {$ENDIF}mitDBForgeStudio, mitNone);
{$ENDIF}

  TMyDesignUtils = class(TDADesignUtils)
    class function GetProjectName: string; override;

  { Component }
  {$IFDEF MYDAC}
    class function GetConnectionList: TObject; override;
  {$ENDIF}
    class function GetDesignCreate(Obj: TComponent): boolean; override;
    class procedure SetDesignCreate(Obj: TComponent; Value: boolean); override;

  { Connection support }
    class function HasConnection(Obj: TComponent): boolean; override;
    class function GetConnection(Obj: TComponent): TCustomDAConnection; override;
    class procedure SetConnection(Obj: TComponent; Value: TCustomDAConnection); override;

  { TDATable support }
    class function GetTableName(Obj: TCustomDADAtaSet): string; override;
    class procedure SetTableName(Obj: TCustomDADAtaSet; const Value: string); override;
    class function GetOrderFields(Obj: TCustomDADAtaSet): string; override;
    class procedure SetOrderFields(Obj: TCustomDADAtaSet; const Value: string); override;
    class procedure PrepareSQL(Obj: TCustomDADAtaSet); override;
    class function GetStoredProcName(Obj: TCustomDADataSet): string; override;
    class procedure SetStoredProcName(Obj: TCustomDADataSet; const Value: string); override;

  { Data Type Mapping }
    class function GetConverterManagerClass: TConverterManagerClass; override;

  {$IFDEF USE_SYNEDIT}
    class function SQLDialect: integer ; override; // SynHighlighterSQL TSQLDialect = (sqlStandard, sqlInterbase6, sqlMSSQL7, sqlMySQL, sqlOracle, sqlSybase, sqlIngres, sqlMSSQL2K);
  {$ENDIF}
  {$IFDEF DBTOOLS}
    class function DBToolsService: TObject; override;
    class function NeedToCheckDbTools: TNeedToCheckDbTools; override;
    class function GetDBToolsServiceVersion: int64; override;
    class function GetDBToolsMenuCaption: string; override;
    class function GetFullName(Obj: TComponent): string; override;
    class function GetObjectType(Obj: TComponent): string; override;
    class function IsStoredProc(Obj: TComponent): boolean; override;

    class procedure GetDBToolsConnectionList(Connection: TCustomDAConnection); override;
    class procedure SetDBToolsDownloadParams(VerbCheck: boolean; Incompatible: boolean); override;

    class procedure LoadIntegrationTool;
    class procedure SaveIntegrationTool(IntegrationTool: TMyIntegrationTool);
    class function GetCurrentIntegrationTool: TMyIntegrationTool;
    class procedure UpdateIntegrationTool;
    class function AreDBToolsUsed: boolean; override;
  {$ENDIF}
  end;

  TMyDesignUtilsClass = class of TMyDesignUtils;

{$IFDEF MSWINDOWS}
{$I MyDacVer.inc}
resourcestring
  sMydacVersion = 'MyDAC ' + MydacVersion;
{$IFNDEF STD}
  sAskIncompatible = 'AskIncompatible';
  sAskNoAddin = 'AskNoAddin';
{$ENDIF}

{$IFDEF DBTOOLS}

const
  sMyIntegrationTool = 'MyIntegrationTool';
{$IFDEF VER11P}
  sDBForgeFusionTool = 'dbForge Fusion for MySQL';
{$ENDIF}
  sDBForgeStudioTool = 'dbForge Studio for MySQL';
  sNoTool = 'No integration';
  sDBToolsNames: array[TMyIntegrationTool] of string = ({$IFDEF VER11P}sDBForgeFusionTool, {$ENDIF}sDBForgeStudioTool, '');

resourcestring
  sDevToolsDownloadCaption = 'MyDAC Information';
  sDevAskIncompatible = 'DevAskIncompatible';
  sDevAskNoAddin = 'DevAskNoAddin';
  sProductAskIncompatible = 'MyDacAskIncompatible';
{$ENDIF}
{$ENDIF}

implementation

uses
{$IFDEF MYDAC}
  MyDesign,
{$ENDIF}
{$IFDEF DBTOOLS}
{$IFDEF VER11P}
  DBForgeClientImp,
{$ENDIF}
  DBForgeStudioClientImp,
  Download,
  Windows,
  Registry,
{$ENDIF}
{$IFNDEF STD}
  MyBackup, MyDump, DADump, MyServerControl, MyEmbConnection,
{$ENDIF}
  MyDataTypeMap, MyAccess;

{ TMyDesignUtils }

class function TMyDesignUtils.GetProjectName: string;
begin
  Result := 'MyDAC';
end;

class function TMyDesignUtils.HasConnection(Obj: TComponent): boolean;
begin
{$IFNDEF STD}
  if Obj is TMyBackup then
    Result := True
  else
  if Obj is TMyServerControl then
    Result := True
  else
{$ENDIF}
    Result := inherited HasConnection(Obj);
end;

class function TMyDesignUtils.GetConnection(Obj: TComponent): TCustomDAConnection;
begin
  Assert(Obj <> nil);
{$IFNDEF STD}
  if Obj is TMyBackup then
    Result := TMyBackup(Obj).Connection
  else
  if Obj is TMyServerControl then
    Result := TMyServerControl(Obj).Connection
  else
{$ENDIF}  
    Result := inherited GetConnection(Obj);
end;

class procedure TMyDesignUtils.SetConnection(Obj: TComponent; Value: TCustomDAConnection);
begin
  Assert(Obj <> nil);
{$IFNDEF STD}
  if Obj is TMyBackup then
    TMyBackup(Obj).Connection := Value as TCustomMyConnection
  else
  if Obj is TMyServerControl then
    TMyServerControl(Obj).Connection := Value as TCustomMyConnection
  else
{$ENDIF}
    inherited;
end;

class function TMyDesignUtils.GetOrderFields(Obj: TCustomDADAtaSet): string;
begin
  Assert(Obj is TCustomMyTable, Obj.ClassName);
  Result := TCustomMyTable(Obj).OrderFields;
end;

class procedure TMyDesignUtils.SetOrderFields(Obj: TCustomDADAtaSet;
  const Value: string);
begin
  Assert(Obj is TCustomMyTable, Obj.ClassName);
  TCustomMyTable(Obj).OrderFields := Value;
end;

class function TMyDesignUtils.GetTableName(Obj: TCustomDADAtaSet): string;
begin
  Assert(Obj is TCustomMyTable, Obj.ClassName);
  Result := TCustomMyTable(Obj).TableName;
end;

class procedure TMyDesignUtils.SetTableName(Obj: TCustomDADAtaSet; const Value: string);
begin
  Assert(Obj is TCustomMyTable, Obj.ClassName);
  TCustomMyTable(Obj).TableName := Value;
end;

class procedure TMyDesignUtils.PrepareSQL(Obj: TCustomDADAtaSet);
begin
  Assert(Obj is TCustomMyTable, Obj.ClassName);
  TCustomMyTable(Obj).PrepareSQL;
end;

class function TMyDesignUtils.GetStoredProcName(Obj: TCustomDADAtaSet): string;
begin
  Assert(Obj is TCustomMyStoredProc, Obj.ClassName);
  Result := TCustomMyStoredProc(Obj).StoredProcName;
end;

class procedure TMyDesignUtils.SetStoredProcName(Obj: TCustomDADAtaSet;
  const Value: string);
begin
  Assert(Obj is TCustomMyStoredProc, Obj.ClassName);
  TCustomMyStoredProc(Obj).StoredProcName := Value;
end;

class function TMyDesignUtils.GetConverterManagerClass: TConverterManagerClass;
begin
  Result := TConverterManagerClass(TMyMapRules.GetConverterManager.ClassType);
end;

{$IFDEF USE_SYNEDIT}
class function TMyDesignUtils.SQLDialect: integer;
begin
  Result := 3; // sqlMySQL
end;
{$ENDIF}

{$IFDEF MYDAC}
class function TMyDesignUtils.GetConnectionList: TObject;
begin
  Result := TMyConnectionList.Create;
end;
{$ENDIF}

class function TMyDesignUtils.GetDesignCreate(Obj: TComponent): boolean;
begin
  Assert(Obj <> nil);
{$IFNDEF STD}
  if Obj is TMyBackup then
    Result := TMyBackupUtils.GetDesignCreate(TMyBackup(Obj))
  else
  if Obj is TMyServerControl then
    Result := TMyServerControlUtils.GetDesignCreate(TMyServerControl(Obj))
  else
{$ENDIF}
    Result := inherited GetDesignCreate(Obj);
end;

class procedure TMyDesignUtils.SetDesignCreate(Obj: TComponent; Value: boolean);
begin
  Assert(Obj <> nil);
{$IFNDEF STD}
  if Obj is TMyBackup then
    TMyBackupUtils.SetDesignCreate(TMyBackup(Obj), Value)
  else
  if Obj is TMyServerControl then
    TMyServerControlUtils.SetDesignCreate(TMyServerControl(Obj), Value)
  else
{$ENDIF}
    inherited;
end;

{$IFDEF DBTOOLS}

{$I IdeConsts.inc}

var
  MySQLService: TObject;
  MySQLServiceFault: boolean;
  MySQLServiceNeedToCheck: TNeedToCheckDbTools;
  MySQLServiceVersion: int64;
  MySQLIntegrationTool: TMyIntegrationTool;
  MySQLServiceGUID: TGUID;
  MySQLProviderKey: string;

class function TMyDesignUtils.DBToolsService: TObject;
const
  dbtBigInt = 1;
  dbtBit = $11;
  dbtBlob = 2;
  dbtChar = 3;
  dbtDate = 4;
  dbtDateTime = 5;
  dbtDecimal = 6;
  dbtDouble = 7;
  dbtFloat = 8;
  dbtInt = 9;
  dbtSmallInt = 10;
  dbtText = 11;
  dbtTime = 12;
  dbtTimeStamp = 13;
  dbtTinyInt = 14;
  dbtVarChar = 15;
  dbtYear = $10;
var
  DBToolsServiceClass: TCustomDBToolsServiceClass;
begin
  if (MySQLIntegrationTool <> mitNone) and (MySQLService = nil) and not MySQLServiceFault then begin
    MySQLServiceFault := true;    
    {$IFDEF VER11P}
    if MySQLIntegrationTool = mitDBForgeFusion then
      DBToolsServiceClass := TDBForgeService
    else
    {$ENDIF}
    if MySQLIntegrationTool = mitDBForgeStudio then
      DBToolsServiceClass := TDBForgeStudioService
    else
      DBToolsServiceClass := nil;
    if DBToolsServiceClass <> nil then begin
      MySQLService := DBTools.CreateDBToolsService(DBToolsServiceClass, TMyDesignUtils,
        MySQLServiceGUID, 'Host=;User Id=;Password=;Database=;Port=3306;'
        + 'SSL CA Cert=;SSL Cert=;SSL Key=;SSL Cipher List=;Embedded=False;'
        + 'Server Parameters=;Unicode=False;',
        MySQLProviderKey, MySQLServiceVersion, MySQLServiceNeedToCheck);
      MySQLServiceFault := MySQLService = nil;
      if not MySQLServiceFault then
        with TCustomDBToolsService(MySQLService) do begin
          AddParamTypeMap(ftString, dbtVarChar);
          AddParamTypeMap(ftWideString, dbtVarChar);
          AddParamTypeMap(ftBlob, dbtBlob);
          AddParamTypeMap(ftMemo, dbtText);
          AddParamTypeMap(ftVarBytes, dbtText);
          AddParamTypeMap(ftDate, dbtDate);
          AddParamTypeMap(ftDateTime, dbtDateTime);
          AddParamTypeMap(ftDateTime, dbtTimeStamp);
          AddParamTypeMap(ftTime, dbtTime);
          AddParamTypeMap(ftFixedChar, dbtChar);
          AddParamTypeMap(ftFloat, dbtFloat);
          AddParamTypeMap(ftFloat, dbtDouble);
          AddParamTypeMap(ftBCD, dbtDecimal);
          AddParamTypeMap(ftInteger, dbtInt);
          AddParamTypeMap(ftInteger, dbtYear);
          AddParamTypeMap(ftWord, dbtInt);
          AddParamTypeMap(ftLargeInt, dbtBigInt);
          AddParamTypeMap(ftLargeInt, dbtBit);
          AddParamTypeMap(ftBoolean, dbtBit);
          AddParamTypeMap(ftSmallint, dbtSmallInt);
          AddParamTypeMap(ftSmallint, dbtTinyInt);
        end;
    end;
  end;
  Result := MySQLService;
end;

class function TMyDesignUtils.NeedToCheckDbTools: TNeedToCheckDbTools;
begin
  DBToolsAvailable;
  Result := MySQLServiceNeedToCheck;
end;

class function TMyDesignUtils.GetDBToolsServiceVersion: int64;
begin
  DBToolsAvailable;
  Result := MySQLServiceVersion;
end;

class function TMyDesignUtils.GetDBToolsMenuCaption: string;
begin
  Result := sDBToolsNames[TMyDesignUtils.GetCurrentIntegrationTool];
end;

class procedure TMyDesignUtils.GetDBToolsConnectionList(Connection: TCustomDAConnection);
var
  MyConnection: TMyConnection;
  IsEmbedded: boolean;
  Service: TCustomDBToolsService;
{$IFNDEF STD}
  i: integer;
  s: string;
{$ENDIF}  
begin
  Assert(MySQLService <> nil);
  Service := TCustomDBToolsService(MySQLService);
  if Connection <> nil then
    with TCustomMyConnection(Connection) do begin
      if Connection is TMyConnection then begin
        MyConnection := TMyConnection(Connection);
        IsEmbedded := MyConnection.Embedded;
      end
      else begin
        MyConnection := nil;
        IsEmbedded := True;
      end;
      if IsEmbedded then
        Service.SkipConnectionParams(1)
      else
        Service.PutConnectionParam(MyConnection.Server); //Host
      Service.PutConnectionParam(Username, cfCaseSensitive);//User Id
      Service.PutConnectionParam(Password, cfNone);//Password
      Service.PutConnectionParam(Database); //Database
      if IsEmbedded then
        Service.SkipConnectionParams(5)
      else begin
        Service.PutConnectionParam(IntToStr(MyConnection.Port)); //Port
        Service.PutConnectionParam(MyConnection.SSLOptions.CACert); //SSL CA Cert
        Service.PutConnectionParam(MyConnection.SSLOptions.Cert); //SSL Cert
        Service.PutConnectionParam(MyConnection.SSLOptions.Key); //SSL Key
        Service.PutConnectionParam(MyConnection.SSLOptions.CipherList); //SSL Cipher List
      end;
      Service.PutConnectionParam(BoolToStr(IsEmbedded, True)); //Embedded

      {$IFNDEF STD}
      if Connection is TMyEmbConnection then begin
        s := '';
        for i := 0 to  TMyEmbConnection(Connection).Params.Count - 1 do begin
          if i <> 0 then
            s := s + ';';
          s := s + TMyEmbConnection(Connection).Params[i];
        end;
        Service.PutConnectionParam(s);
      end
      else
      {$ENDIF}
        if MyConnection.Embedded then
          Service.PutConnectionParam('')
        else
          Service.SkipConnectionParams(1);
  
      Service.PutConnectionParam(BoolToStr(Options.UseUnicode, True)); //UseUnicode
    end;
end;

class function TMyDesignUtils.GetFullName(Obj: TComponent): string;
begin
  if Obj is TCustomMyTable then
    Result := GetTableName(TCustomDADataSet(Obj))
  else
  if Obj is TCustomMyStoredProc then
    Result := GetStoredProcName(TCustomDADataSet(Obj))
  else
    Result := inherited GetFullName(Obj);
end;

class function TMyDesignUtils.GetObjectType(Obj: TComponent): string;
begin
  if Obj is TCustomMyTable then
    Result := 'Table,View'
  else
  if Obj is TCustomMyStoredProc then
    Result := 'Procedure,Function'
  else
    Result := inherited GetObjectType(Obj);
end;

class function TMyDesignUtils.IsStoredProc(Obj: TComponent): boolean;
begin
  Result := Obj is TCustomMyStoredProc;
end;

class procedure TMyDesignUtils.SetDBToolsDownloadParams(VerbCheck: boolean; Incompatible: boolean);
var
  AskStr, AtomName: string;
  UrlStr, UrlExeStr, ToolsNameStr: string;
{$IFDEF VER11P}
  OutdatedProduct: boolean;
{$ENDIF}
begin
{$IFDEF VER11P}
  if MySQLIntegrationTool = mitDBForgeFusion then begin
    OutdatedProduct := Incompatible and ((GetDBToolsServiceVersion = 0) or
      (GetDBToolsServiceVersion > 3 * $1000000000000{3.0.0.0}));
    if VerbCheck then begin
      AskStr := '_Verb';
      AtomName := '';
    end
    else begin
      AskStr := '';
      if OutdatedProduct then
        AtomName := 'CheckForMyDac atom'
      else
        AtomName := 'CheckForMySQLDevTools atom';
    end;
  
    if OutdatedProduct then begin
      SetToolsCheckingParams(sDevToolsDownloadCaption, GetProjectName, sDBForgeFusionTool,
        sProductAskIncompatible + AskStr, sProductAskIncompatible + AskStr,
        'Software\Devart\mydac', 'Mydac', 'MySQLDeveloper',
        'www.devart.com/mydac',
        'mydac' + IntToStr(IDEInfos[IDEVer].Version) + '.exe',
        AtomName)
    end
    else
      SetToolsCheckingParams(sDevToolsDownloadCaption, sDBForgeFusionTool, sMydacVersion,
        sDevAskIncompatible + AskStr, sDevAskNoAddin + AskStr,
        'Software\Devart\mydac', 'Mydac', 'MySQLDeveloper',
        'www.devart.com/dbforge/mysql/fusion/bds',
        'dbforgemysqlbds' + IntToStr(IDEInfos[IDEVer].BdsVersion) + '.exe',
        AtomName);
  end
  else
{$ENDIF}
  if MySQLIntegrationTool = mitDBForgeStudio then begin
    if VerbCheck then begin
      AskStr := '_Verb';
      AtomName := '';
    end
    else begin
      AskStr := '';
      AtomName := 'CheckForDBForgeMySQL atom';
    end;
    UrlStr := 'www.devart.com/dbforge/mysql/studio';
    UrlExeStr := 'dbforgemysql.exe';
    ToolsNameStr := sDBForgeStudioTool;
    SetToolsCheckingParams(sDevToolsDownloadCaption, ToolsNameStr, sMydacVersion,
      sDevAskIncompatible + AskStr, sDevAskNoAddin + AskStr,
      'Software\Devart\mydac', 'Mydac', 'dbForge Studio',
      UrlStr, UrlExeStr,
      AtomName);
  end;
end;

class procedure TMyDesignUtils.LoadIntegrationTool;
var
  reg: TRegistry;
  ts: string;
begin
  MySQLIntegrationTool := mitDBForgeStudio;
{$IFDEF VER11P}
  MySQLIntegrationTool := mitDBForgeFusion;
{$ELSE}
{$ENDIF}
  reg := TRegistry.Create(KEY_READ OR KEY_WRITE);
  try
    reg.RootKey := HKEY_CURRENT_USER;
    if reg.OpenKey('\SOFTWARE\Devart\' + TMyDesignUtils.GetProjectName, False) then begin
      ts := reg.ReadString(sMyIntegrationTool);
{$IFDEF VER11P}
      if AnsiSameText(ts, sDBForgeFusionTool) then
        MySQLIntegrationTool := mitDBForgeFusion
      else
{$ENDIF}
      if AnsiSameText(ts, sDBForgeStudioTool) then
        MySQLIntegrationTool := mitDBForgeStudio
      else
      if AnsiSameText(ts, sNoTool) then
        MySQLIntegrationTool := mitNone;
    end;
  finally
    reg.Free;
  end;
end;
                               
class procedure TMyDesignUtils.SaveIntegrationTool(IntegrationTool: TMyIntegrationTool);
var
  reg: TRegistry;
  ts: string;
begin
  if IntegrationTool = MySQLIntegrationTool then exit;
  reg := TRegistry.Create(KEY_READ OR KEY_WRITE);
  try
{$IFDEF VER11P}
    if IntegrationTool = mitDBForgeFusion then
      ts := sDBForgeFusionTool
    else
{$ENDIF}
    if IntegrationTool = mitDBForgeStudio then
      ts := sDBForgeStudioTool
    else
      ts := sNoTool;
    reg.RootKey := HKEY_CURRENT_USER;
    reg.OpenKey('\SOFTWARE\Devart\' + TMyDesignUtils.GetProjectName, True);
    reg.WriteString(sMyIntegrationTool, ts);
    MySQLIntegrationTool := IntegrationTool;

    FreeAndNil(MySQLService);
    MySQLServiceFault := False;
    MySQLServiceNeedToCheck := ncNone;
    MySQLServiceVersion := 0;
    UnregisterDesignNotification(DBTools.DesignNotification);
    DBTools.DesignNotification := nil;
    TMyDesignUtils.UpdateIntegrationTool;
  finally
    reg.Free;
  end;
end;

class function TMyDesignUtils.GetCurrentIntegrationTool: TMyIntegrationTool;
begin
  Result := MySQLIntegrationTool;
end;

class procedure TMyDesignUtils.UpdateIntegrationTool;
const
{$IFDEF VER11P}
  MySQLServiceCLSID_Prefix: string = '{DD06A3A9-B493-4a68-AB0E-038B90BBD';
  MyProviderKey = '{59F90733-4D68-4fdf-82A7-F0FCBF5460AA}';
{$ENDIF}
  MySQLServiceCLSID_DBForgeStudio: TGUID = '{3154A3A9-24BF-4100-B465-77BB531586E5}';
  MyProviderKey_DBForgeStudio = 'dbForge Studio for MySQL';
begin
{$IFDEF VER11P}
  if MySQLIntegrationTool = mitDBForgeFusion then begin
    if IDEInfos[IDEVer].Version >= 14 then
      MySQLServiceGUID := StringToGUID(MySQLServiceCLSID_Prefix + IntToStr(IDEInfos[IDEVer].Version - 1) + '0}')
    else
      MySQLServiceGUID := StringToGUID(MySQLServiceCLSID_Prefix + IntToStr(IDEInfos[IDEVer].Version) + '0}');
    MySQLProviderKey := MyProviderKey;
  end
  else
{$ENDIF}
  if MySQLIntegrationTool = mitDBForgeStudio then begin
    MySQLServiceGUID := MySQLServiceCLSID_DBForgeStudio;
    MySQLProviderKey := MyProviderKey_DBForgeStudio;
    MySQLProviderKey := MyProviderKey_DBForgeStudio;
  end;
  if MySQLIntegrationTool <> mitNone then
    DBTools.CheckDevTools(MySQLServiceGUID, MySQLProviderKey, TMyDesignUtils, MySQLServiceVersion);
end;

class function TMyDesignUtils.AreDBToolsUsed: boolean;
begin
  Result := MySQLIntegrationTool <> mitNone;
end;
{$ENDIF}

initialization
{$IFDEF DBTOOLS}
  TMyDesignUtils.LoadIntegrationTool;
  TMyDesignUtils.UpdateIntegrationTool;
{$ENDIF}

finalization
{$IFDEF DBTOOLS}
  FreeAndNil(MySQLService);
{$ENDIF}

end.
