Как решить [FireDAC] [Phys] [SQLite] ОШИБКА: невозможно открыть файл базы данных, когда приложение установлено в programFiles? - PullRequest
0 голосов
/ 17 июня 2019

Я разработал инструмент, используя Firedac с базой данных SQLite.

после завершения проекта и создания установщика (InnoSetup) я получаю сообщение об ошибке

[FireDAC] [Phys] [SQLite] ОШИБКА: невозможно открыть файл базы данных

при запуске приложения (двойной щелчок).

Это параметры соединения, которые я использую

constructor TDbInteract.Create(const aDatabasePath: string; const aOnNeedCredentials: TOnNeedCredentials);
var
  aParams: array of string;
begin
  if not TFile.Exists(aDatabasePath) then
    raise Exception.Create('Database file not found');

  aParams := ['DriverID=SQLite',
              'Database=' + aDatabasePath,
              'OpenMode=CreateUTF16',
              'LockingMode=Normal',
              'JournalMode=WAL',
              'StringFormat=Unicode',
              'Synchronous=Full',
              'UpdateOptions.LockWait=True',
              'BusyTimeout=30000',
              'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
  InitiateResource(aParams, aOnNeedCredentials);
end;

procedure TDbInteract.InitiateResource(const aParams: array of string; const aOnNeedCredentials: TOnNeedCredentials);
var
  I: Integer;
  Credentials: TStringDynArray;
begin
  FRowsAffected := 0;
  FIsForeignKeyHonored := True;
  FOwnsResultDataSets := True;
  FDataSetContainer := TDataSetContainer.Create(nil);

  FConnection := TFDConnection.Create(nil);
  try
    for I := Low(aParams) to High(aParams) do
    begin
      FConnection.Params.Add(aParams[I]);
    end;

    if Assigned(aOnNeedCredentials) then
    begin
      aOnNeedCredentials(Self, Credentials);

      for I := Low(Credentials) to High(Credentials) do
      begin
        FConnection.Params.Add(Credentials[I]);
      end;
    end;

    FConnection.Open;
  except
    raise;
  end;
end;

** Выявленные проблемы:

  1. Я где-то читал (не помню страницу, на которой я был), что движок SQLite требует полной блокировки каталога, в который он хочет записать.и это проблема.Как бы то ни было, я запускаю инструмент как invoker, и моя учетная запись является администратором, так что это не проблема.Также у меня есть тот же инструмент, написанный на c #, и эта проблема никогда не возникает.

Решения, которые я нашел:

  1. Запустите инструмент от имени администратора
  2. Не устанавливайте инструмент в каталоге ProgramFiles

Мне действительно не нравятся эти решения.и хотел бы запустить мой инструмент из каталога Files, являющегося частью более крупного проекта.

Примечание : Файл базы данных находится в каталоге программных данных.Он создается инструментом (это работает).

Редактировать: Я только что попытался поместить файл БД в C:\Users\Nacereddine\AppData\Roaming\MyTool И у меня все еще остается та же проблема, когда инструмент установлен в C:\Program Files (x86)\MyTool

Вот так я создаю файл БД

class procedure TDbInteract.CreateSQLiteDb(const aDatabasePath: string; const aTables: TStringDynArray);
var
  I: Integer;
  aParams: array of string;
  aConnection: TFDConnection;
begin
  aParams := ['DriverID=SQLite',
              'Database=' + aDatabasePath,
              'OpenMode=CreateUTF16',
              'LockingMode=Normal',
              'JournalMode=WAL',
              'StringFormat=Unicode',
              'Synchronous=Full',
              'UpdateOptions.LockWait=True',
              'BusyTimeout=30000',
              'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];

  aConnection := TFDConnection.Create(nil);
  try
    for I := Low(aParams) to High(aParams) do
    begin
      aConnection.Params.Add(aParams[I]);
    end;

    aConnection.Open();

    for I := Low(aTables) to High(aTables) do
    begin
      aConnection.ExecSQL(aTables[I]);
    end;
  finally
    aConnection.Close;
    aConnection.Free;
  end;
end;

Примечание: Не знаю, имеет ли это какое-то значение, но файл БД зашифрован.

1 Ответ

1 голос
/ 17 июня 2019

Извините за беспокойство.

Проблема заключалась в том, что у нас был установлен файл локализации db с инструментом в ProgramFiles.

Что заставило меня исключить из моего расследования то, что при открытии этого файла я установил OpenMode на ReadOnly

FConnection.Params.Add('OpenMode=ReadOnly');

но, как я уже говорил в своем вопросе, движок SQLite требует полного доступа к папке, содержащей файл db, поэтому он блокирует его (все равно не нашел страницу, на которой я читал это).

Я проверил это, играя с открытыми режимами и отлаживая инструмент каждый раз. как только я изменил права доступа к файлу и каталогу, ошибка исчезла.

В конце я решил переместить файл локализации в каталог programData с основным файлом базы данных, и все хорошо.

Я понял (спасибо за это @Ken и @David), что каталогу programData также требуются права администратора для записи, и поэтому я перенесу файлы db в более подходящий каталог (т.е. пользователи).

Что полезно из этой проблемы, так это то, что даже если вы подключаетесь к файлу Sqlite db с помощью OpenMode=ReadOnly, вам все равно необходим доступ на запись для пути к этому файлу.

...