Ошибка "SQLITE BUSY" при работе с Sqliite БД

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
artem78
новенький
Сообщения: 50
Зарегистрирован: 09.08.2015 17:52:24

Ошибка "SQLITE BUSY" при работе с Sqliite БД

Сообщение artem78 »

Исходники проекта во вложении. Ошибка происходит здесь:
procedure TTasksFrame.StartTrackingToolButtonClick(Sender: TObject);
begin
with DataModule1.PeriodsDataset do
begin
// ToDo: Check if no unfinished periods
Append;
FieldByName('task_id').AsInteger
:= DataModule1.TasksDataset.FieldByName('id').AsInteger;
FieldByName('begin').AsDateTime := Now;
Post;
ApplyUpdates; <-----
end;
end;


Жду помощи специалистов.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3067
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

При попытке установить в лазарь эту дурацкую приблуду - sql3la, он меня обвалился. Пользуйтесь нормальными компонентами - SqlDB, ZeosDB. Скорее всего у вас установлен AutoCommit, вот оно и валится на ApplyUpdates.
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

artem78 писал(а):Жду помощи специалистов.

О, я уже думал, что объявив приказом по полку отсутствие в SQLite3 типа DATETIME, вы решили, что ловить здесь больше нечего.
Вижу у вас появились новые идеи - использовать Sqldb вместе с Sqlite3Dataset, один конь в упряжке хорошо, а два ещё лучше.
Рискну, однако, предположить, что в этом и есть проблема, не хотят они на добровольной основе делиться доступом к базе.
artem78
новенький
Сообщения: 50
Зарегистрирован: 09.08.2015 17:52:24

Сообщение artem78 »

iskander писал(а):Рискну, однако, предположить, что в этом и есть проблема, не хотят они на добровольной основе делиться доступом к базе.

Я об этом не подумал.
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Для того чтобы в этом убедиться, требуется как минимум скомпилировать ваш пример, но вы же не захотели облегчить жизнь рядового помогальщика, там кроме Sqlite3Dataset болтается ещё некий UniqueInstance, который мне совсем ни разу не упёрся.
Глядя в код модуля tasks, могу предложить вот такой вариант

Код: Выделить всё

unit tasks;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, ComCtrls, DBGrids, taskedit, datamodule, Dialogs;

type

  { TTasksFrame }

  TTasksFrame = class(TFrame)
    TasksDBGrid: TDBGrid;
    ToolBar1: TToolBar;
    AddToolButton: TToolButton;
    RemoveToolButton: TToolButton;
    EditToolButton: TToolButton;
    SeparatorToolButton: TToolButton;
    StartTrackingToolButton: TToolButton;
    StopTrackingToolButton: TToolButton;
    ShowTimeToolButton: TToolButton;
    procedure AddToolButtonClick(Sender: TObject);
    procedure EditToolButtonClick(Sender: TObject);
    procedure RemoveToolButtonClick(Sender: TObject);
    procedure ShowTimeToolButtonClick(Sender: TObject);
    procedure StartTrackingToolButtonClick(Sender: TObject);
    procedure StopTrackingToolButtonClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

implementation

uses
  Variants;

{$R *.lfm}

{ TTasksFrame }

procedure TTasksFrame.AddToolButtonClick(Sender: TObject);
begin
  DataModule1.TasksDataset.Append;
  if TaskEditForm.ShowModal = mrOK then
  begin
    DataModule1.SQLTransaction1.EndTransaction;
    DataModule1.TasksDataset.FieldByName('created').AsDateTime := Now;
    DataModule1.TasksDataset.Post;
    DataModule1.TasksDataset.ApplyUpdates;
    DataModule1.StatsSQLQuery.Open;
  end
  else
    DataModule1.TasksDataset.Cancel;
end;

procedure TTasksFrame.EditToolButtonClick(Sender: TObject);
begin
  if DataModule1.TasksDataset.IsEmpty then
    Exit;

  DataModule1.TasksDataset.Edit;
  if TaskEditForm.ShowModal = mrOK then
  begin
    DataModule1.SQLTransaction1.EndTransaction;
    DataModule1.TasksDataset.FieldByName('modified').AsDateTime := Now;
    DataModule1.TasksDataset.Post;
    DataModule1.TasksDataset.ApplyUpdates;
    DataModule1.StatsSQLQuery.Open;
  end
  else
    DataModule1.TasksDataset.Cancel;
end;

procedure TTasksFrame.RemoveToolButtonClick(Sender: TObject);
var
  Msg: String;
begin
  if DataModule1.TasksDataset.IsEmpty then
    Exit;

  Msg := Format('Are you sure to delete task "%s"?', [DataModule1.TasksDataset.FieldByName('name').AsString]);
  if MessageDlg(Msg, mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  begin
    DataModule1.SQLTransaction1.EndTransaction;
    DataModule1.TasksDataset.Delete;
    DataModule1.TasksDataset.ApplyUpdates;
    DataModule1.StatsSQLQuery.Open;
  end;
end;

procedure TTasksFrame.ShowTimeToolButtonClick(Sender: TObject);
var
  TotalTime: TTime;
  Period: TTime;
begin
  TotalTime:=EncodeTime(0,0,0,0);

  with DataModule1.SQLQuery1 do
  begin
    Close();
    SQL.Text := 'select begin, end from periods where task_id = ' + IntToStr(DataModule1.TasksDataset.FieldByName('id').AsInteger) + ';';
    Open();

    while not EOF do
    begin
      if FieldByName('end').IsNull then
        Period := Now - FieldByName('begin').AsDateTime
      else
        Period := FieldByName('end').AsDateTime - FieldByName('begin').AsDateTime;

      TotalTime:=TotalTime+Period;
      Next;
    end;
  end;

  ShowMessage(TimeToStr(TotalTime));
end;

procedure TTasksFrame.StartTrackingToolButtonClick(Sender: TObject);
begin
  DataModule1.SQLTransaction1.EndTransaction;
  with DataModule1.PeriodsDataset do
  begin
    // ToDo: Check if no unfinished periods
    Append;
    FieldByName('task_id').AsInteger
      := DataModule1.TasksDataset.FieldByName('id').AsInteger;
    FieldByName('begin').AsDateTime := Now;
    Post;
    ApplyUpdates;
  end;
  DataModule1.StatsSQLQuery.Open;
end;

procedure TTasksFrame.StopTrackingToolButtonClick(Sender: TObject);
begin
  with DataModule1.SQLQuery1 do
  begin
    Close;
    SQL.Text := 'update periods set end=:end WHERE `end` IS NULL';
    // ToDo: Check if only one result
    ParamByName('end').AsDateTime:=now - 2415018.5;
    ExecSQL;
    SQLTransaction.CommitRetaining;
    //Close;
  end;
  DataModule1.PeriodsDataset.Close;
  DataModule1.PeriodsDataset.Open;
end;

end.

Надеюсь это поможет.
artem78
новенький
Сообщения: 50
Зарегистрирован: 09.08.2015 17:52:24

Сообщение artem78 »

iskander писал(а):некий UniqueInstance

Он присутствует в сетевом менеджере пакетов.
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Вау, да вы никак решили озаботиться моим просвещением? Весьма похвально, да, что бы я без вас делал...

То есть вы считаете, что каждый, ни в чём не повинный помогальщик просто обязан установить на свой компьютер кучу совершенно ему не нужного хлама только потому, что вы не озаботились очистить от него свой пример?
Последний раз редактировалось iskander 07.02.2022 22:26:36, всего редактировалось 1 раз.
artem78
новенький
Сообщения: 50
Зарегистрирован: 09.08.2015 17:52:24

Сообщение artem78 »

На отдельном примере продемонстрировать проблему было затруднительно, поэтому дал всё что есть (к счастью, кода там совсем немного).
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Ну а код-то из поста выше опробовали?
artem78
новенький
Сообщения: 50
Зарегистрирован: 09.08.2015 17:52:24

Сообщение artem78 »

iskander писал(а):Ну а код-то из поста выше опробовали?

Да. Похоже, работает как надо. Спасибо.

Добавлено спустя 22 часа 39 минут 49 секунд:
Снег Север писал(а):Пользуйтесь нормальными компонентами - SqlDB, ZeosDB

Какие между ними различия? Какой из них порекомендуете выбрать?
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3067
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

artem78 писал(а):Какие между ними различия? Какой из них порекомендуете выбрать?

ZeosDB более универсальные, но для 99% случаев вполне годятся SqlDB.
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Он об этом уже спрашивал.
Ответить