[yunqa.de] Re: How to correctly avoid 'database is locked' in multi user

  • From: Delphi Inspiration <delphi@xxxxxxxx>
  • To: yunqa@xxxxxxxxxxxxx
  • Date: Sat, 12 Jan 2013 23:00:31 +0100

On 11.01.2013 20:37, H M wrote:

> I tried uploading this a few hours ago but it didn't seem to make it to
> the list. Here it is again without the .exe files in the zip in case that was 
> the
> reason.

Thanks for your efforts. Did you receive an error message? For the future, 
please know that I do not need *.exe compiled applications to debug and 
reproduce problems.

Your code is correct. However, it revealed that for multi-statement SQL run on 
a database with a reserved lock, sqlite3_exec_with_callback() incorrectly 
returns SQLITE_OK instead of SQLITE_BUSY.

To solve, please replace the sqlite3_exec_with_callback() implementation in 
DISQLite3Database.pas with the following:

function sqlite3_exec_with_callback(
  const ADBHandle: sqlite3_ptr;
  const ASQL: Utf8String;
  const ACallback: TDISQLite3_Callback_{$IFDEF SUPPORTS_DEFAULTPARAMS} = 
nil{$ENDIF};
  const AUserData: Pointer{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF}): 
Integer;
var
  CallbackResult: Boolean;
  SqlStart, SqlTail: PUtf8Char;
  SqlLength: C_int;
  Stmt: sqlite3_stmt_ptr;
begin
  if not Assigned(ADBHandle) then
    begin
      Result := SQLITE_MISUSE;
      Exit;
    end;

  SqlLength := Length(ASQL);
  if SqlLength = 0 then
    begin
      Result := SQLITE_OK;
      Exit;
    end;

  SqlStart := Pointer(ASQL);
  repeat

    Result := sqlite3_prepare_v2(ADBHandle, SqlStart, SqlLength + 1, @Stmt, 
@SqlTail);
    if Result <> SQLITE_OK then
      Break;

    if Assigned(Stmt) then
      begin
        try
          CallbackResult := True;
          Result := sqlite3_step(Stmt);
          if Assigned(ACallback) and (Result and $FF = SQLITE_ROW) then

            repeat
              CallbackResult := ACallback(Stmt, AUserData);
              if not CallbackResult then
                Break;
              Result := sqlite3_step(Stmt);
            until Result and $FF <> SQLITE_ROW;
        finally
          Result := sqlite3_finalize(Stmt);
        end;
        if not CallbackResult then
          Result := SQLITE_ABORT;
      end;

    if Result <> SQLITE_OK then
      Break;

    Dec(SqlLength, SqlTail - SqlStart);
    if SqlLength <= 0 then
      Break;
    SqlStart := SqlTail;
  until False;
end;

Thanks for the report,

Ralf
_______________________________________________
Delphi Inspiration mailing list
yunqa@xxxxxxxxxxxxx
//www.freelists.org/list/yunqa



Other related posts: