2016-03-15 95 views
0

我使用Delphi(Firedac)在SQLite中遇到了一個對我來說無法解決的ATTACH和DETACH問題。使用SQLite的錯誤ATTACH - Delphi中的DETACH

我有連接的一個數據庫文件和附加的第二個具有:

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

其中,變量「Import_DB_filename」包含數據庫文件的完整路徑和文件名。

這工作正常,我可以通過FireDac查詢訪問連接中的兩個數據庫,並且可以毫無問題地完成我的編碼。 然而,事情出錯時拆下:

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

在調試模式下,我總是得到錯誤:

Debugger Exception Notification
E Project My_Program.EXE raised exception class $C0000005 with message 'access violation at 0x00405d7b: read of address 0x00000000'.

顯然出了差錯與內存分配,因爲調試器中(裝配停止)功能SysFreeMem(P:Pointer): Integer;GETMEM.INC

無論我嘗試什麼,錯誤都會持續存在,並會導致內存泄漏,最終導致編譯器(Delphi Seattle Enterprise)崩潰。

即使連接並隨後分離數據庫而不傳遞任何代碼也會導致相同的錯誤。

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

我真希望你能幫助我在這持久的問題。

+0

可以肯定的:所以你已經有一個正確的[Firedac連接建立(http://docwiki.embarcadero.com/RADStudio/XE8/en/Setting_up_Connections_% 28FireDAC%29),現在你想使用[SQLite ATTACH](https://www.sqlite.org/lang_attach.html)將另一個數據庫文件添加到當前連接?並請[編輯]你的問題,包括德爾福版本。 –

+0

爲什麼您需要對兩個數據庫文件使用相同的FDConnection?爲什麼不爲每個人建立一個單獨的連接。 – MartynA

+0

說實話,我不知道我是否已經嘗試過。我會查一下。感謝您的建議。 – JGMS

回答

0

如果您運行下面的項目,你會發現,:

  • 您可以訪問兩個SQLite數據庫很樂意使用單獨的FDConnections和FDTables。

  • 您可以使用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. 
+0

謝謝MartynA, – JGMS

+0

謝謝MartynA,您確信使用兩個FDConnection組件是規避ATTACH和DETACH使用的好方法。我已經相應地更改了我的代碼。但是,錯誤仍然存​​在。顯然,它與附件無關,而與內存分配有關。我一定把它擰到了某個地方。也許你可以暗示我如何解決這樣的錯誤。我安裝了MadExcept,但它沒有給我任何線索。不幸的是,十六進制地址對我來說就像中文。 – JGMS

+0

那麼,「讀取地址0x00000000」表明某些東西沒有被正確初始化,可能是一個Delphi對象,它在調用.Create()之前正在被訪問。確保在項目選項中打開「使用調試DCU」,然後執行項目構建和運行。發生錯誤時,在IDE中轉到** View |調試窗口|調用堆棧**,然後您應該能夠查看堆棧並查看發生異常的位置。 – MartynA