1

(1 replies, posted in General)

I planned to release a new version this month but I'm too busy right now, so I have to delay, sorry.

2

(1 replies, posted in Bug Tracking)

Yes,

UncleVader already sent a similar bug report.

bug tracking is on the way...

Any clue is welcome.

Regards

3

(1 replies, posted in General)

I 'll try to have a look. I know it's difficult to catch bug with lazarus. Could you step through the code to get more info on this error ?

4

(1 replies, posted in General)

I'm afraid I don't. Sorry.

Thanks Yann,
I 've made the modification.

Happy New Year 2011 !

Luc

6

(5 replies, posted in General)

Ok Yann,

You are right. It seems I wrote this fix too quickly and missed some important things here ... hmm

As you suggest, I could add the Database to the procedure parameters but I don't want to have too many parameters involved.
I think about it and try to be rid off the Recordest TSqlitePassStringList/TSqlitePassWideStringList calls.

7

(7 replies, posted in Bug Tracking)

The bug is unlikely coming from the DLL. Let's wait for the 0.56 version.
If you still have problem, I will check this.

Regards

8

(5 replies, posted in General)

Yann wrote :

And about params, I don't really understand why binding is made on Recordset data for strings as it's not the case for others types like integer or date and time. So I replaced all "Recordset.GetFieldAs"

in BindAnsiStringFieldValueBufferToSqliteValueAsUTF8

UTF8StrValue := SqlitePassUtils.AnsiToUTF8(PAnsiChar(FieldValueBuffer));

Unfortunately, you shouldn't modify this code because it is also used to bind the values to the update or insert sql statements.
I explain : When a TsqlitePassRecordset record stores a string field, it doesn't directly store a pointer to the string but an integer (index) to a stringlist item. The string itself is stored in the stringlist.

As a consequence, we are dealing here with either a pointer on a string or a stringlist  index (integer).

If the stringlist is convenient for debugging, it should be removed now (same for wideString).

I'm going to work on this implementation change.

As a quick fix, you could use :

procedure TSqlitePassParam.BindValue;
var
MasterDataset: TSqlitePassDataset;
begin
if Assigned(FMasterField)
   then begin
        MasterDataset := TSqlitePassDataset(FMasterField.Dataset);
        FValue := MasterDataset.FRecordset.GetFieldValueBuffer(MasterDataset.GetActiveRecord, FMasterField.Tag);
        if not MasterDataset.FRecordset.FieldIsNull(FValue)
           then FBindValue(FParams.FDataset.FRecordset, FValue, FParams.FDataset.FSQLSelectStmt.StmtHandle, FParamIndex);
        end
   else if Not FIsNull
           then 
// Fix
FBindValue(Nil, FValue, FParams.FDataset.FSQLSelectStmt.StmtHandle, FParamIndex);
//

end;

and

procedure BindAnsiStringFieldValueBufferToSqliteValueAsUTF8
          (Const Recordset: TSqlitePassRecordset;
           Const FieldValueBuffer: PRecBuffer;
           Const PreparedStmt: Pointer;
           Const PreparedStmtFieldNo: Integer);{$IFDEF HasInline} inline; {$ENDIF}
var
UTF8StrValue: UTF8AnsiString;
begin
// Fix
 if Assigned(Recordset)
   then UTF8StrValue := SqlitePassUtils.AnsiToUTF8(Recordset.GetFieldAsAnsiString(FieldValueBuffer))
   else  UTF8StrValue := SqlitePassUtils.AnsiToUTF8(FieldValueBuffer)
//

 With Recordset.FDataset.FDatabase
      do FEngine.CheckResult(SqliteDbv3_bind_text(PreparedStmt, PreparedStmtFieldNo, pAnsiChar(UTF8StrValue), Length(UTF8StrValue), SQLITE_TRANSIENT));
end;

Thanks for all your testing and your usefull and accurate code analysis.

By the way, I'm looking for fast string sorting with custom collation : the current sort implementation (quicksort derivated) is not too bad but kind of slow with strings comparisons and doesn't handle custom char comparison. I've already looked for a better algo, without any success (RadixSort, PostManSort, String Compression that preserves Chars comparison...etc)

Any idea ?

Best regards.

Luc

9

(5 replies, posted in General)

Ok Yann,

Merci pour toutes ces infos. Je fais les corrections pour les AnsiStrings et reviens vers toi pour les bindings, à vérifier.

A+

Luc

Right !

Your fix has been included in the 0.56 version
Thanks again for your contribution
Regards
Luc

Your fix has been included in the 0.56 version
Thanks for your contribution
Regards
Luc

12

(7 replies, posted in Bug Tracking)

I couldn't reproduce the bug (tested with my current 0.56 version) but found something that could help : the TDataModule component create order was not set correctly : details fields  dataset created before master fields dataset.

Could you try after modifying the create order ?

Component Create Order Form

Thanks
Luc

13

(7 replies, posted in Bug Tracking)

I've got the file and will let you know asap.

14

(7 replies, posted in Bug Tracking)

Of course, I will.

Could you send a code sample that raise the FastMM memory leak debug dialog ?

Thanks.

15

(4 replies, posted in General)

I'm still working on this part of code... smile

16

(1 replies, posted in General)

SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine. SQLite is the most widely deployed SQL database engine in the world. The source code for SQLite is in the public domain.

http://www.sqlite.org

Regards

17

(6 replies, posted in General)

Hi Francis,

1 ------------
Yesterday, I came up with the same analysis. I have to change the way the parser deals with quoted strings.
Here is a temporarely and quick fix up (not enough time right now)

  Tips : when you want locate a KeyValue containing spaces and starting with a number, in a string field,
     the KeyValue must be between brackets [] in order to be parsed as a single statement i.e.
     MyDataset.Locate('StringField', '45 NEWSPAPERS', []) always returns FALSE
     MyDataset.Locate('StringField', '[45 NEWSPAPERS]', []) returns TRUE

Procedure ProcessNumber;
  var
  CharSet: Set of Char;
  begin
  if Char(FNestingCharStack[FNestingLevel]) = '['
     then ProcessIdentifier
     else
  begin
  if Char(FNestingCharStack[FNestingLevel]) in ['''', '"', '#']
     then begin
          { We have DateTime, Date or Time ? }
          CharSet := ['0'..'9', '.', '-', '/', ':', ' '];
          NewToken.TokenType := ttDateTime;
          end
     else begin
          { We have number ? }
          CharSet := ['0'..'9', '.'];
          NewToken.TokenType := ttNumber;
          end;
  While (Char(CurrentChar^) in CharSet) do Inc(CurrentChar);
  end;
  end;

Think to move the ProcessIdentifier proc above the ProcessNumber proc

2 --------------
DatasetName problem at designtime

procedure TSqlitePassDataset.SQLChanged(Sender: TObject);
begin
  NotifySQLChanged(scProcess);

  if (DatasetName <> '') and not (FInInternalSetDatasetType or (csLoading in ComponentState))
     then DatasetName := '';

  if FDatasetName = '' then
     begin
     FDatasetType := dtUnknown;
     ProcessSQLText;
     end;

  if FParamCheck
     then UpdateParamsList;
end;

Should be ok.

Looking forward further testing

Thanks.
Luc

18

(7 replies, posted in Bug Tracking)

I noticed the problem and give you an answer soon

19

(6 replies, posted in General)

Many thanks,

I didn't have time to check it...
I correct the code in next version.

Regards  smile

20

(6 replies, posted in General)

Hi,

I tried to have this bug showing up, but nothing happened. Could you send a code sample ?

Note : You don't have to {$DEFINE DEBUG_SQLStmt}to debug the library, except if you want to have detail on dataset events, logged to the SqlitePassDebug form (in sqlitePass  \source\debug).

Thanks

21

(4 replies, posted in General)

Hi Dave,

I'm not sure the library should handle that but I will think about it. Your program could scan folders/subfolders,  then fill the Database.sqliteLib property once a correct lib is found.

Do you already have this kind of code ?

Regards
Luc

22

(2 replies, posted in Bug Tracking)

Hi,

I am working on the parser to avoid similar bugs. (several blankspaces or text field begining with numeric values...etc).

Should be fixed in the next release.

Thanks

23

(6 replies, posted in General)

Hi,

how can I determine which database error occured (errorcode ?) within standard exception handler ?

1 - If SqlitePassDatabase.Options.LogErrors = True then you can use the SqlitePassDatabase.DatabaseError.CurrentError.Code to retrieve the last Sqlite Error Code.
You can find more information in SqlitePassDbo (TSqlitePassDatabaseErrorItem and TSqlitePassDatabaseError)

2 - If not, Trap the ErrorCode in :
procedure TSqlitePassDatabaseError.RaiseException(const Msg: String; const ErrorCode: Integer = -1;  Component: TComponent = nil; VerboseLevel: TSqlitePassVerboseLevel = vlLogAndShow);
If ErrorCode was sent back by sqlite, it should be there.

3 - Finally, (Not the easiest way), you can directly use the Sqlite DLL functions (in SqlitePassApi_v3.pas)
SqliteDbv3_errcode:function(db:pointer):integer; cdecl;
SqliteDbv3_errmsg:function(db:pointer):pAnsiChar; cdecl;
SqliteDbv3_errmsg16:function(db:pointer):pWideChar; cdecl;
but you need to provide a handle/pointer on the current db. You will loose the advantage of the wrapper !


I've created database with SQLite Expert (.db3). Then I changed extension to .db.

This is the normal behavior :

function TSqlitePassDatabase.DatabaseTypeFromFileName(FileName: String): TSqlitePassDatabaseType;
begin
FileName := Lowercase(FileName);
      if (AnsiPos('.kexi',  FileName)) > 0 then Result := dbtKexi
 else if (AnsiPos('.s3db',  FileName)) > 0 then Result := dbtSqliteAdmin
 else if (AnsiPos('.db3',   FileName)) > 0 then Result := dbtSqliteExpert
 else if (AnsiPos('.s3fpc', FileName)) > 0 then Result := dbtSqlite4Fpc
 else if (AnsiPos('.sp3',   FileName)) > 0 then Result := dbtSqlitePass
 else Result := dbtUnknown;
end;

but you can always override the default setting :
Fill in the database property
set connected to false
set MyDb.DatabaseType := dbtSqliteExpert
set connected to true


I found that emptytable function finds dataset type dtSQLSelect

The code is :

procedure TSqlitePassDataset.EmptyTable;
begin
  if DatasetType = dtTable then
     begin
     FDatabase.Engine.ExecSQL('DELETE FROM "' + DatasetName + '";');
     Refresh;
     end;
end;

so, the DatasetName property is not a valid table name or your SQL Statement is not recognised as an existing table in the current database.

I check the other issues. Please, send a sample of your data if you want me to test it.

Thanks

24

(6 replies, posted in General)

Hi Zabukowski,

There is no property to disable the LogError Dialog. I will think about it in next release.
As a quick fix, you can easily switch back to classic exception handler if you change the code in SqlitePassDatabase.inc

procedure TSqlitePassDatabaseError.RaiseException(const Msg: String; const ErrorCode: Integer = -1;  Component: TComponent = nil; VerboseLevel: TSqlitePassVerboseLevel = vlLogAndShow);
begin
 { Track multi errors ? }
 if FTrackerErrorCount <> 0
   then VerboseLevel := vlLog;

 { Log, show or both ? }
 Case VerboseLevel of
      vlLog        : LogError(Msg, [], ErrorCode, Component);
      vlShow       : ShowErrorDialog(Msg);
      vlLogAndShow : begin
                     LogError(Msg, [], ErrorCode, Component);
                     ShowErrorDialog;
                     end;
      end;
Abort;
end;

with

procedure TSqlitePassDatabaseError.RaiseException(const Msg: String; const ErrorCode: Integer = -1;  Component: TComponent = nil; VerboseLevel: TSqlitePassVerboseLevel = vlLogAndShow);
begin
 { Track multi errors ? }
 if FTrackerErrorCount <> 0
   then VerboseLevel := vlLog;

 { Log, show or both ? }
 Case VerboseLevel of
      vlLog        : LogError(Msg, [], ErrorCode, Component);
      vlShow       :  raise Exception.Create(Msg);
      vlLogAndShow : begin
                     LogError(Msg, [], ErrorCode, Component);
                     raise Exception.Create(Msg);
                     end;
      end;
end;

Zabukowski wrote

I am doing massive inserts. I've tried to post (commit) after each insert, then i've tried to post at the end of inserts, but there is no noticeable speed difference. Any thoughts ? (btw. I am not using SQL statements, but standard methods - insert, post, cancel etc.)

Try
SqlitePassDatabase1.Engine.Transaction.Start;
....
your code
....
SqlitePassDatabase1.Engine.Transaction.Commit;


You are welcome if you want to send your code, bug reports...and your overall feeling about the components.

Thanks
Luc

25

(10 replies, posted in Bug Tracking)

Hi Dave,

Do you have another msg when you step backward in the error dialog ?

If not, you can always build the packages with debug options on (remove the existing packages, re-open the packages and turn on the compiler debug infos options, then build) and step throught the code.

If it doesn't work for you, feel free to send your sample db. I'll have a look.

Regards. Luc