I have some modification for delphi 2006.

I guess it is more compatible with delphi compilers with 'conditinal expressions(support in delphi 6+)'. smile

http://www.mediafire.com/?4xndnd0cf64z2al

p.s.

more modification for delphi & some bug fix. smile

http://www.mediafire.com/?3jxybdyce1e6nff

sqlite 3.7.0.1 for sqlitepass.

http://www.mediafire.com/?3f278273poa7o1y

2

(3 replies, posted in General)

New SQLitePass3.DLL based on SQLite 3.6.12  smile



http://www.mediafire.com/?indixntdmnq

3

(3 replies, posted in General)

luckylazarus wrote:

Great update Parcel.

BUGFIXES AND ENHANCEMENTS
I would be happy to include your modification or bugfixes in the current 0.42. To do this,  I need to keep track of your contribution (except for the fixes posted on forum).

May be the simplest way would be to mark the code changes with something like

//------- edited by Parcel on dd-mm-yyyy
...code
// ------- end ----------------

What do you think about it ?

If you do, I appreciate it smile


luckylazarus wrote:

UTF8 and UTF16
I'm very concerned with utf8 or utf16 support, even if the component is good enougth for english or french...It could then be used by many others people.
I currently use old fashion Delphi4 to code sqlitepass so I'm missing unicodestrings and I would appreciate your help to turn the component utf compliant from D4 to D2008 and Lazarus/fpc...

UTF-8 support is simple,

but delphi 4 and 5 does not include function "AnsiToUTF8" and "Utf8ToAnsi".

ftWideString support is also difficult for me neutral

If database has 3 records,

delete first or second record or not last record

and then append or insert record,

post or cancel operation is invalid.

record that appended or inserted is duplicated or cleared previous record positon's data.


1
2  <--- delete
3

1
3
?  <--- append

1
4  <--- duplicated
4  <--- new record

cause 3 record  in dataset memory data is lost.


1
2  <--- delete
3

1
?  <--- insert
3

4  <--- duplicated
4  <--- new
3

It's strange... neutral

It happens 3 or more records in dataset.

This archive contains More enhancements and sqlite 3.6.11 dll file.

mbcs ansistring works properly on utf-16 configurations.

Sorry, thers is no comment .

http://www.mediafire.com/?zl51yvyuz3z

Thank you, luckylazarus smile

7

(3 replies, posted in Bug Solved)

Thank you, luckylazarus smile

At loading kexi db,

Following procedure raise range check exception.

procedure TSqlitePassBitArray.Reset;
var
Start, i, FItemsLength: integer;
S: string;
begin
FInternalItems.Clear;
i := 1;
FItemsLength := Length(FItems);
While i < FItemsLength do
    begin
    Start := i;
    // fix range check exception
    While i <= FItemsLength do
      if (not (FItems[i] in [',' , ';'])) then
        inc(i)
        else Break;
    s := System.Copy(FItems, Start, i-Start);
    FInternalItems.Add(System.Copy(FItems, Start, i-Start)+'=0');
    Inc(i);
    end;
end;

smile

Currently, database file encoding and page size is not set correctly at creating database file except Kexi format.

unction TSqlitePassDatabase.CreateDatabase(DbName: String; DbType: TSqlitePassDatabaseType;
                                            Encoding: TSqlitePassEncoding = UTF_8; PageSize: TSqlitePassPageSize = 4096;
                                            AutoVacuum: TSqlitePassAutoVacuumType = 0): Boolean;
...
        ExecSQL('PRAGMA encoding = ' + EncodingStr+';');             
        ExecSQL('PRAGMA page_size = ' + IntToStr(PageSize)+';');
        ExecSQL('PRAGMA Auto_Vacuum = ' + IntToStr(AutoVacuum)+';');

        { Creates system tables for Kexi }
        if DbType = dbtKexi then
           begin
           ExecSQL(KexiDb_CreateSQLStmt);
           ExecSQL(KexiParts_CreateSQLStmt);
           ExecSQL(KexiObjects_CreateSQLStmt);
           ExecSQL(KexiObjectData_CreateSQLStmt);
           ExecSQL(KexiFields_CreateSQLStmt);
           ExecSQL(KexiBlobs_CreateSQLStmt);
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("kexidb_major_ver", "1");');
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("kexidb_minor_ver", "8");');
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("kexiproject_major_ver", "1");');
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("kexiproject_minor_ver", "0");');
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("project_caption", "");');
           ExecSQL('INSERT INTO "kexi__db" (db_property, db_value) VALUES ("project_desc", "");');
           end else
            // for other format
            ExecSQL('CREATE TABLE "sqlitepass__dummy" (dummy TEXT(1));');           
...

Last sql statment is correctly set encoding and pagesize of database file except kexi format.

At different encoding,  'SQLitePass__DbSettings' table's information is not read correctly in utf-16 encodings.

procedure TSqlitePassRecordset.GetRecords(Sql: String);
...
ColumnStr : string;
ColumnSize : integer;
begin
...
         { No fields are defined, so we store all the values as string }
         else begin
              ColumnSize := SqliteDbv3_column_Bytes(PSqliteData,ColumnIndex);
              SetLength(ColumnStr,ColumnSize);
              system.Move(pansichar(SqliteDbv3_column_Blob(PSqliteData,ColumnIndex))^,ColumnStr[1],ColumnSize);
              AddString(Buffer, ColumnStr);
              SetFieldNullValue(RecordIndex, ColumnIndex, False);
              Inc(Buffer, SizeOf(Integer));
              end;
      end; { for }
...

And sqlite3_open function protorype declaration is invalid.

SqliteDbv3_open: function(dbname: PChar; var db:pointer):integer; cdecl;
...
procedure TSqlitePassEngine.OpenDatabase(FullName, LibraryFile: String);
begin
FLibraryLoaded := LoadSqliteLibrary(LibraryFile);
CheckResult(SqliteDbv3_Open(Pchar(FullName), FConnectionHandle));
end;
...

Sorry for short explanation.

I'm not English well neutral

10

(3 replies, posted in Bug Solved)

TSqlitePassPageSize = Word;
...

function TSqlitePassDatabaseOptions.GetFPageSize: TSqlitePassPageSize;
begin
  Result := FDatabase.GetIntPragma('page_size') and $FFFF;
end;
...

function TSqlitePassDatabase.CreateDatabase(DbName: String; DbType: TSqlitePassDatabaseType;
                                            Encoding: TSqlitePassEncoding = UTF_8; PageSize: TSqlitePassPageSize = 4096;
                                            AutoVacuum: TSqlitePassAutoVacuumType = 0): Boolean;
var
EncodingStr: string;
begin
Result := False;
if Not FileExists(DbName) then
   With TSqlitePassEngine.Create(Self) do
        begin
        Try
        OpenDatabase(DbName, FSqliteLibrary);

        Case Encoding of
             UTF_8:    EncodingStr:= '"UTF-8"';
             UTF_16:   EncodingStr:= '"UTF-16"';
             UTF_16le: EncodingStr:= '"UTF-16le"';
             UTF_16be: EncodingStr:= '"UTF-16be"';
             end;
        //DW
        if PageSize<512 then
          PageSize := 512;
        if PageSize>32768 then
          PageSize := 32768;
        Case PageSize of
             512         : PageSize := 512;
             513..1024   : PageSize := 1024;
             1025..2048  : PageSize := 2048;
             2049..4096  : PageSize := 4096;
             4097..8192  : PageSize := 8192;
             8193..16384 : PageSize := 16384;
             16385..32768: PageSize := 32768;
             end;
...

It maybe fix Pagesize exception on designtime.

11

(3 replies, posted in Bug Solved)

function TSqlitePassDatabaseOptions.GetFPageSize: TSqlitePassPageSize;
begin
  Result := FDatabase.GetIntPragma('page_size');
  // Range Check Error
  if Result>High(TSqlitePassPageSize) then
    Result := High(TSqlitePassPageSize);
  if Result<Low(TSqlitePassPageSize) then
    Result := Low(TSqlitePassPageSize);
end;

But it still raise exception on Designtime.

How about change "TSqlitePassPageSize" to "Word"?


{ Translates a SQLite value to its internal storage value in memory
  Returns the size of the value }
function TSqlitePassRecordset.SqliteValueToBuffer(Const PSqliteData: Pointer; Const ColumnIndex: Integer; Const BufferFieldPos: Integer; Const DataType: TFieldType; Buffer: PChar): Integer;
...
  ftDateTime:
    begin
    Result := SizeOf(Double);
    if SqliteDbv3_column_type(PSqliteData, ColumnIndex) = SQLITE_NULL then Exit;
    Case FDatabase.DatatypeOptions.DateTimeStorage of
         dtsDateTime : DoubleValue := SqliteDbv3_column_double(PSqliteData,ColumnIndex);  // miss variable
...

{ Add a String and Returns the Index of the new string in Fstrings Array }
function TSqlitePassRecordset.AddString(Buffer: PChar; StrValue: String): Integer;
begin
 if FRecycledStrings.Count > 0
    then begin
    Result := Integer(FRecycledStrings[Pred(FRecycledStrings.Count)]); // << changed PInteger()^ to Integer
    FRecycledStrings.Delete(Pred(FRecycledStrings.Count));
...

12

(1 replies, posted in Bug Solved)

procedure TSqlitePassDatabaseDataTypeOptions.FindSubString
(Chr: Char; LowerStr: String; Var StartPos, EndPos: Word);
var
StrLength: Integer;
begin
StartPos := Pos(Chr,LowerStr);
StrLength := Length(LowerStr);
if StartPos > 0 then
   begin
   EndPos := StartPos;
   // fix range check error
   While (EndPos <= StrLength) Do
    if (LowerStr[EndPos] = Chr) then
      Inc(EndPos)
      else Break;
   end;
Dec(EndPos,StartPos);
end;

--------------------------------------------------------------------------------------------------------

const
{ Default Fields Type when DatabaseType is dtbUnknown }
DefaultFieldsTypes:array[0..21] of TSqlitePassPresetFieldType =
           ((Name:'widestring'; FieldType:ftString), { must be before string }
            (Name:'string'; FieldType:ftString),
            (Name:'smallint'; FieldType:ftSmallInt), { must be before integer }
            (Name:'largeint'; FieldType:ftLargeint), { must be before integer }
            (Name:'integer'; Fieldtype:ftInteger),
            (Name:'word'; FieldType:ftWord),
            (Name:'float'; FieldType:ftFloat),
            (Name:'boolean'; FieldType:ftBoolean),
            (Name:'currency'; FieldType:ftCurrency), // fix misspell
            (Name:'bcd'; FieldType:ftBCD),
            (Name:'datetime'; FieldType:ftDateTime), { must be before 'date' }
            (Name:'date'; FieldType:ftDate),
            (Name:'time'; FieldType:ftTime),
            (Name:'varbytes'; FieldType:ftVarBytes),
            (Name:'bytes'; FieldType:ftBytes),
            (Name:'autoinc'; FieldType:ftLargeInt),  { Do not set as ftAutoInc }
            (Name:'fmtmemo'; FieldType:ftFmtMemo),   { must be before memo }
            (Name:'memo'; FieldType:ftMemo),
            (Name:'blob'; FieldType:ftBlob),
            (Name:'graphic'; FieldType:ftGraphic),
            (Name:'typedbinary'; FieldType:ftTypedBinary),
            (Name:'fixedchar'; FieldType:ftfixedchar));


-----------------------------------------------------------------------------------------------------------------------

procedure TSqlitePassRecordset.GetRecords(Sql: String);
var
Accept: Boolean;
PSqliteData: Pointer;
ColumnCount, ColumnIndex: Cardinal;
Buffer: PChar;
ValueOffset, BufferSize, ErrorCode,LowerLimit,
UpperLimit, LimitIdx, BufferFieldPos: Integer;
RecordIndex: Integer;
begin
Try
PSqliteData := nil;
...
  for ColumnIndex := 0 to Pred(ColumnCount) do
      begin
      if Assigned(FDataset) then
         { fields are defined }
         begin
         BufferFieldPos := int64(ColumnIndex)-FRowIdTablesCount; // << fix integer overflow
         if ColumnIndex < FRowIdTablesCount
            { Stores the rowid for each table returned by SQL }
            then BufferSize := SqliteValueToBuffer(PSqliteData, ColumnIndex, BufferFieldPos, ftLargeInt, Buffer)
            { Stores the fields values }
            else BufferSize := SqliteValueToBuffer(PSqliteData, ColumnIndex, BufferFieldPos, FDataset.FieldDefs[BufferFieldPos].DataType, Buffer);
         Inc(Buffer, BufferSize);
         end

-------------------------------------------------------------------------------------------------------------------------------

function TSqlitePassRecordset.SetFRecordSize: Integer;
var
i, j: Integer;
begin
  FCalcFieldsCount := 0;
  SetLength(FInternalFieldsOffset, 0);
...
          GetMem(FCalcFieldsNullValuesInitBuffer, FCalcFieldsCount);
          if FCalcFieldsNullValuesInitBuffer<>nil then // fix error, if FCalcFieldsCount=0 then FCalcFieldsNullValuesInitBuffer=nil
          for i := 0 to Pred(FCalcFieldsCount)
              do PByteBool(FCalcFieldsNullValuesInitBuffer + (i * SizeOf(ByteBool)))^ := True;
          { Set the definitive Fields Offset array size }
          SetLength(FInternalFieldsOffset, j);
         end

some fixes at delphi. smile

It's my mistake.

Clear Database Name(property 'DataBase') and assgined at runtime, it works fine.

Thank you, luckylazarus.

14

(2 replies, posted in Bug Solved)

Thank you, luckylazarus smile

15

(3 replies, posted in Bug Solved)

Thank you, luckylazarus. smile

It is DB File.

http://www.mediafire.com/?mhn0ijojdww

17

(2 replies, posted in Bug Solved)

At delphi,

Datetime process function has 'Invalid TTimestamp Value'.

I change that below.

If TTimeStamp field Date is 0, TimeStampToDateTime has raise exception with invalid TTimeStamp value message.

procedure TSqlitePassTranslator.IntegerToTimeText
         (Const Value: Integer;
          Const TimePattern: String;
          Const HourStart, HourLength, MinStart, MinLength, SecStart, SecLength, MSecStart, MSecLength: Word;
          out StrValue: String);
var
Hour, Min, Sec, MSec: Word;
TimePartStr: String;
PStrValue: PChar;
TimeStamp : TTimeStamp;
begin
 Timestamp.Time := Value;
 Timestamp.Date := 1;
 DecodeTime(TimeStampToDateTime(TimeStamp), Hour, Min, Sec, MSec);
 { Necessary conversion oterwise we would be pointing on FDatabase.DatatypeOptions.FTimeFormat }

or

procedure TSqlitePassTranslator.IntegerToTimeText
         (Const Value: Integer;
          Const TimePattern: String;
          Const HourStart, HourLength, MinStart, MinLength, SecStart, SecLength, MSecStart, MSecLength: Word;
          out StrValue: String);
var
Hour, Min, Sec, MSec: Word;
TimePartStr: String;
PStrValue: PChar;
TimeValue : TTime;
begin
 TimeValue := Value / 1000 / 60 / 60 / 24;
 DecodeTime(TimeValue, Hour, Min, Sec, MSec);
 { Necessary conversion oterwise we would be pointing on FDatabase.DatatypeOptions.FTimeFormat }
 StrValue := StrPas(PChar(TimePattern));
 ...

At loading Kexi DB file created by CreateDatabase,

it showed waring message.

   { Storage Version }
   if StorageInfoStrings.Count = 2
      then FStorageVersion := StorageInfoStrings[1];

   if FStorageVersion <> SqlitePassStorageVersion       // FStorageVersion is ''(blank string) at kexi db file.
      then Abort;

19

(3 replies, posted in Bug Solved)

Locate method raise access violation. neutral

I fixed that below.

procedure TSqlitePassDataset.LocateMoveToRecord;
begin
  FLocateMoveState:= grError;
  if (FLocateCurrentItem > -1) and (FLocateCurrentItem < FLocateFoundRecords.Count) then
     begin
     MoveBy(Integer(FLocateFoundRecords.Items[FLocateCurrentItem]) - PInteger(ActiveBuffer)^); // changed
     FLocateMoveState := grOk;
     if FLocateCurrentItem = 0
        then FLocateMoveState := grBOF
        else if FLocateCurrentItem = Pred(FLocateFoundRecords.Count)
             then FLocateMoveState := grEOF;
     end;
end;

It works ok in delphi.