使用SQLite ATTACH时出错 - Delphi中的DETACH

时间:2016-03-15 14:51:11

标签: sqlite delphi delphi-10-seattle

使用Delphi(Firedac),我在SQLite中体验了ATTACH和DETACH的无法解决的问题。

我连接了一个数据库文件,并附加了第二个:

FDConnection1.ExecSQL('ATTACH DATABASE "' + Import_DB_filename + '" AS IMPORTDB;');

其中,变量'Import_DB_filename'包含数据库文件的完整路径和文件名。

这可以正常工作,我可以通过FireDac查询访问连接中的两个数据库,并且可以毫无问题地进行编码。 但是,在分离时出现问题:

FDConnection1.ExecSQL('DETACH DATABASE IMPORTDB;');

在调试模式下,我总是收到错误:

  

调试器异常通知
    E Project My_Program.EXE引发异常类$ C0000005,消息'访问冲突位于0x00405d7b:读取地址0x00000000'。

显然内存分配出了问题,因为调试器在SysFreeMem(P:Pointer): Integer;中的(汇编)函数GETMEM.INC中停止。

无论我尝试什么,错误都会持续存在,并导致内存泄漏,最终导致编译器崩溃(Delphi Seattle Enterprise)。

即使在不传递任何代码的情况下附加和随后分离数据库也会导致相同的错误。

(FDconnection:锁定模式= lmNormal;                 JournalMode = jmOff或jmWALL或jmdelete)

我希望你能帮我解决这个持久的问题。

1 个答案:

答案 0 :(得分:0)

如果你运行下面的项目,你会发现:

  • 您可以使用单独的FDConnections和FDTables非常愉快地访问两个Sqlite数据库。

  • 您可以使用FireDAC FDDataMove组件将数据从一个数据库中的表移动到另一个数据库中的同名表。

代码:

unit BatchMoveu;

interface

[...]

type
  TForm3 = class(TForm)
    FDConnection1: TFDConnection;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    DBNavigator1: TDBNavigator;
    FDGUIxWaitCursor1: TFDGUIxWaitCursor;
    FDPhysSQLiteDriverLink1: TFDPhysSQLiteDriverLink;
    Button1: TButton;
    FDTable1: TFDTable;
    FDConnection2: TFDConnection;
    DataSource2: TDataSource;
    DBGrid2: TDBGrid;
    btnBatchMove: TButton;
    FDDataMove1: TFDDataMove;
    FDTable2: TFDTable;
    procedure btnBatchMoveClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure PopulateTable1;
    procedure TestDataMove;
  public
    procedure CreateDatabase(DBName : String; FDConnection : TFDConnection;
      FDTable : TFDTable);
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

const
  DBName1 = 'd:\delphi\code\sqlite\db1.sqlite';
  DBName2 = 'd:\delphi\code\sqlite\db2.sqlite';

procedure TForm3.Button1Click(Sender: TObject);
begin
  CreateDatabase(DBName1, FDConnection1, FDTable1);
  CreateDatabase(DBName2, FDConnection2, FDTable2);

  PopulateTable1;

  FDTable2.Open;

end;

procedure TForm3.CreateDatabase(DBName : String; FDConnection : TFDConnection;
  FDTable : TFDTable);
var
  AField : TField;
  i : Integer;
begin
  if FileExists(DBName) then
    DeleteFile(DBName);

  AField := TLargeIntField.Create(Self);
  AField.FieldName := 'ID';
  AField.DataSet := FDTable;
  AField.Name := AField.DataSet.Name + 'IDField';

  AField := TWideStringField.Create(Self);
  AField.Size := 80;
  AField.FieldName := 'Name';
  AField.DataSet := FDTable;
  AField.Name := AField.DataSet.Name + 'NameField';

  FDConnection.Params.Values['database'] := DBName;
  FDConnection.Connected:= True;
  FDTable.CreateTable(False, [tpTable]);
end;

procedure TForm3.PopulateTable1;
var
  i : Integer;
begin
  FDTable1.Open;

  for i:= 1 to 1000 do begin
    FDTable1.InsertRecord([i, 'Row ' + IntToStr(i)]);
  end;
  FDTable1.Close;
  //FDConnection1.Commit;

  FDTable1.Open;
end;

procedure TForm3.TestDataMove;
var
  Item : TFdMappingItem;
begin
  Item := FDDataMove1.Mappings.Add;
  Item.SourceFieldName := 'ID';
  Item.DestinationFieldName := 'ID';

  Item := FDDataMove1.Mappings.Add;
  Item.SourceFieldName := 'Name';
  Item.DestinationFieldName := 'Name';

  FDDataMove1.Source := FDTable1;
  FDDataMove1.Destination := FDTable2;
  FDDataMove1.Options := FDDataMove1.Options - [poOptimiseSrc];
  FDDataMove1.Execute;

  FDConnection2.Connected := False;
  FDTable2.Open;
end;
procedure TForm3.btnBatchMoveClick(Sender: TObject);
begin
  TestDataMove;
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  FDConnection1.Close;
end;

end.