mORMot and Open Source friends
Check-in [d5ff204eea]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:{4633} added soft_heap_limit64() SQLite3 API and fixed config() call on external dll
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d5ff204eea2843f48c8e22900fa22878633fbbaf
User & Date: ab 2018-06-22 10:42:25
Context
2018-06-22
11:32
{4634} globallly cached current date/time information with 8-16ms resolution check-in: 5db4db365c user: ab tags: trunk
10:42
{4633} added soft_heap_limit64() SQLite3 API and fixed config() call on external dll check-in: d5ff204eea user: ab tags: trunk
10:18
{4632} enhancements to FPC/Linux support check-in: 35c13ca271 user: ab tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SynSQLite3.pas.

2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046



















2047
2048
2049
2050
2051
2052
2053
....
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
....
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
....
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
....
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
....
5801
5802
5803
5804
5805
5806
5807

5808
5809
5810
5811
5812
5813
5814
5815
....
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
....
5836
5837
5838
5839
5840
5841
5842
5843

5844
5845
5846
5847
5848
5849
5850
....
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
    /// serialize a database
    // - returns a pointer to memory that is a serialization of the Schema
    // database on database connection DB
    // - if Size is not nil, then the size of the database in bytes is written into Size^
    // - for an ordinary on-disk database file, the serialization is just a copy
    // of the disk file; for an in-memory database or a "TEMP" database, the
    // serialization is the same sequence of bytes which would be written to disk
    // if that database where backed up to disk.
    // - caller is responsible for freeing the returned value (using free_)
    // to avoid a memory leak
    serialize: function(DB: TSQLite3DB; Schema: PUTF8Char; Size: PInt64;
      Flags: integer): pointer; cdecl;

    /// deserialize a database
    // - causes the database connection DB to disconnect from database Schema
    // and then reopen Schema as an in-memory database based on the serialization
    // contained in Data; the serialized database Data is DBSize bytes in size
    // - BufSize is the size of the buffer Data, which might be larger than DBSize
    deserialize: function(DB: TSQLite3DB; Schema: PUTF8Char; Data: pointer;
      DBSize, BufSize: Int64; Flags: integer): pointer; cdecl;
      



















    /// used to make global configuration changes to current database
    config: function(operation: integer): integer;
      {$ifndef DELPHI5OROLDER}cdecl varargs;{$endif}

    /// used to make global configuration changes to current database connection
    db_config: function(DestDB: TSQLite3DB; operation: integer): integer;
      {$ifndef DELPHI5OROLDER}cdecl varargs;{$endif}
................................................................................
    fLibraryName: TFileName;
  public
    /// initialize the specified external library
    // - raise an ESQLite3Exception on error
    constructor Create(const LibraryName: TFileName=SQLITE_LIBRARY_DEFAULT_NAME); reintroduce;
    /// unload the external library
    destructor Destroy; override;
    /// will change the SQLite3 configuration to use Delphi/FPC memory manager
    // - overriden method which does nothing on some platforms found unstable
    procedure ForceToUseSharedMemoryManager; override;
  published
    property LibraryName: TFileName read fLibraryName;
  end;


/// an internal function which calls Freemem(p)
// - can be used to free some PUTF8Char pointer allocated by Delphi Getmem()
................................................................................
{$endif}

constructor TSQLDataBase.Create(const aFileName: TFileName; const aPassword: RawUTF8;
  aOpenV2Flags, aDefaultCacheSize,aDefaultPageSize: integer);
var result: integer;
begin
  if sqlite3=nil then
    raise ESQLite3Exception.Create('No SQLite3 libray available: you shall '+
      'either add SynSQLite3Static to your project uses clause, '+
      'or run sqlite3 := TSQLite3LibraryDynamic.Create(..)');
  {$ifdef WITHLOG}
  fLog := SynSQLite3Log; // leave fLog=nil if no Logging wanted
  fLogResultMaximumSize := 512;
  {$endif}
  if SysUtils.Trim(aFileName)='' then
    raise ESQLite3Exception.CreateUTF8('%.Create('''')',[self]);
  if aOpenV2Flags=0 then
................................................................................
  for i := 0 to fSQLFunctions.Count-1 do
    TSQLDataBaseSQLFunction(fSQLFunctions.List[i]).CreateFunction(DB);
  {$ifdef WITHLOG}
  i := CacheSize;
  if i<0 then
    i := (-i) shr 10 else
    i := PageSize*CacheSize;
  FPCLog.Log(sllDB,'"%" database file of % opened with PageSize=% and CacheSize=% (%)',
    [FileName,KB(GetFileSize),PageSize,CacheSize,KB(i)],self);
  {$endif}
end;

function TSQLDataBase.GetUserVersion: cardinal;
begin
  result := ExecuteNoExceptionInt64('PRAGMA user_version');
................................................................................
    FormatUTF8('% with %ternal MM',[fVersionText,MM[fUseInternalMM]],result);
end;


{ TSQLite3LibraryDynamic }

const
  SQLITE3_ENTRIES: array[0..89] of TFileName =
  ('initialize','shutdown','open','open_v2','key','rekey','close',
   'libversion','errmsg','extended_errcode',
   'create_function','create_function_v2',
   'create_collation','last_insert_rowid','busy_timeout','busy_handler',
   'prepare_v2','finalize','next_stmt','reset','stmt_readonly','step',
   'column_count','column_type','column_decltype','column_name','column_bytes',
   'column_value','column_double','column_int','column_int64','column_text',
................................................................................
   'aggregate_context','bind_text','bind_blob','bind_zeroblob','bind_double',
   'bind_int','bind_int64','bind_null','clear_bindings','bind_parameter_count',
   'blob_open','blob_reopen','blob_close','blob_read','blob_write','blob_bytes',
   'create_module_v2','declare_vtab','set_authorizer','update_hook',
   'commit_hook','rollback_hook','changes','total_changes','malloc', 'realloc',
   'free','memory_used','memory_highwater','trace_v2','limit',
   'backup_init','backup_step','backup_finish','backup_remaining',

   'backup_pagecount','config','db_config','serialize','deserialize');

constructor TSQLite3LibraryDynamic.Create(const LibraryName: TFileName);
var P: PPointerArray;
    i: integer;
begin
  fLibraryName := LibraryName;
  {$ifdef MSWINDOWS}
................................................................................
    fHandle := TLibHandle(dlopen(PChar(LibraryName),0));
    if fHandle=TLibHandle(nil) then
    {$else}
    fHandle := LoadLibrary({$ifndef FPC}pointer{$endif}(LibraryName));
    if fHandle=0 then
    {$endif}
  {$endif MSWINDOWS}
    raise ESQLite3Exception.CreateFmt('Unable to load %s - %s',
      [LibraryName,SysErrorMessage(GetLastError)]);
  P := @@initialize;
  for i := 0 to High(SQLITE3_ENTRIES) do
    P^[i] := {$ifdef BSDNOTDARWIN}dlsym{$else}GetProcAddress{$endif}(
      fHandle,PChar('sqlite3_'+SQLITE3_ENTRIES[i]));
  if not Assigned(initialize) or not Assigned(libversion) or
     not Assigned(open) or not Assigned(close) or not Assigned(create_function) or
     not Assigned(prepare_v2) or not Assigned(create_module_v2) then begin
................................................................................
    {$ifdef BSDNOTDARWIN}
    dlclose(fHandle);
    fHandle := TLibHandle(nil);
    {$else}
    FreeLibrary(fHandle);
    fHandle := 0;
    {$endif}
    raise ESQLite3Exception.CreateFmt('TOO OLD %s - need 3.7 at least!',[LibraryName]);

  end; // some APIs like config() key() or trace() may not be available
  inherited Create; // set fVersionNumber/fVersionText
  {$ifdef WITHLOG}
  SynSQLite3Log.Add.Log(sllInfo,'Loaded external % version %',[LibraryName,Version]);
  {$endif}
end;

................................................................................
  if fHandle<>0 then
    FreeLibrary(fHandle);
  {$endif}
  inherited;
end;


procedure TSQLite3LibraryDynamic.ForceToUseSharedMemoryManager;
begin
  {$ifndef CPU64DELPHI} // buggy as usual
  inherited ForceToUseSharedMemoryManager;
  {$endif}
end;

initialization

finalization
  FreeAndNil(sqlite3); // sqlite3.Free is not reintrant e.g. as .bpl in IDE
end.






|













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<







 







|
|
|







 







|







 







|







 







>
|







 







|
|







 







|
>







 







<
<
<
<
<
<
<





2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
....
2105
2106
2107
2108
2109
2110
2111



2112
2113
2114
2115
2116
2117
2118
....
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
....
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
....
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
....
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
....
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
....
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
....
5875
5876
5877
5878
5879
5880
5881







5882
5883
5884
5885
5886
    /// serialize a database
    // - returns a pointer to memory that is a serialization of the Schema
    // database on database connection DB
    // - if Size is not nil, then the size of the database in bytes is written into Size^
    // - for an ordinary on-disk database file, the serialization is just a copy
    // of the disk file; for an in-memory database or a "TEMP" database, the
    // serialization is the same sequence of bytes which would be written to disk
    // if that database where backed up to disk
    // - caller is responsible for freeing the returned value (using free_)
    // to avoid a memory leak
    serialize: function(DB: TSQLite3DB; Schema: PUTF8Char; Size: PInt64;
      Flags: integer): pointer; cdecl;

    /// deserialize a database
    // - causes the database connection DB to disconnect from database Schema
    // and then reopen Schema as an in-memory database based on the serialization
    // contained in Data; the serialized database Data is DBSize bytes in size
    // - BufSize is the size of the buffer Data, which might be larger than DBSize
    deserialize: function(DB: TSQLite3DB; Schema: PUTF8Char; Data: pointer;
      DBSize, BufSize: Int64; Flags: integer): pointer; cdecl;
      
    /// sets and/or queries the soft limit on the amount of heap memory
    // that may be allocated by SQLite
    // - SQLite strives to keep heap memory utilization below the soft heap limit
    // by reducing the number of pages held in the page cache as heap memory usages
    // approaches the limit. The soft heap limit is "soft" because even though
    // SQLite strives to stay below the limit, it will exceed the limit rather
    // than generate an SQLITE_NOMEM error. In other words, the soft heap limit
    // is advisory only
    // - The return value from soft_heap_limit64() is the size of the soft heap
    // limit prior to the call, or negative in the case of an error. If the
    // argument N is negative then no change is made to the soft heap limit.
    // Hence, the current size of the soft heap limit can be determined by
    // invoking soft_heap_limit64() with a negative argument
    // - This function is useful when you have many SQLite databases open at
    // the same time, as the cache-size setting is per-database (connection),
    // while this limit is global for the process, so this allows to limit the
    // total cache size
    soft_heap_limit64: function(N: Int64): Int64; cdecl;

    /// used to make global configuration changes to current database
    config: function(operation: integer): integer;
      {$ifndef DELPHI5OROLDER}cdecl varargs;{$endif}

    /// used to make global configuration changes to current database connection
    db_config: function(DestDB: TSQLite3DB; operation: integer): integer;
      {$ifndef DELPHI5OROLDER}cdecl varargs;{$endif}
................................................................................
    fLibraryName: TFileName;
  public
    /// initialize the specified external library
    // - raise an ESQLite3Exception on error
    constructor Create(const LibraryName: TFileName=SQLITE_LIBRARY_DEFAULT_NAME); reintroduce;
    /// unload the external library
    destructor Destroy; override;



  published
    property LibraryName: TFileName read fLibraryName;
  end;


/// an internal function which calls Freemem(p)
// - can be used to free some PUTF8Char pointer allocated by Delphi Getmem()
................................................................................
{$endif}

constructor TSQLDataBase.Create(const aFileName: TFileName; const aPassword: RawUTF8;
  aOpenV2Flags, aDefaultCacheSize,aDefaultPageSize: integer);
var result: integer;
begin
  if sqlite3=nil then
    raise ESQLite3Exception.CreateUTF8('%.Create: No SQLite3 libray available'+
      ' - you shall either add SynSQLite3Static to your project uses clause, '+
      'or run sqlite3 := TSQLite3LibraryDynamic.Create(..)',[self]);
  {$ifdef WITHLOG}
  fLog := SynSQLite3Log; // leave fLog=nil if no Logging wanted
  fLogResultMaximumSize := 512;
  {$endif}
  if SysUtils.Trim(aFileName)='' then
    raise ESQLite3Exception.CreateUTF8('%.Create('''')',[self]);
  if aOpenV2Flags=0 then
................................................................................
  for i := 0 to fSQLFunctions.Count-1 do
    TSQLDataBaseSQLFunction(fSQLFunctions.List[i]).CreateFunction(DB);
  {$ifdef WITHLOG}
  i := CacheSize;
  if i<0 then
    i := (-i) shr 10 else
    i := PageSize*CacheSize;
  FPCLog.Log(sllDB,'"%" database file (%) opened with PageSize=% CacheSize=% (%)',
    [FileName,KB(GetFileSize),PageSize,CacheSize,KB(i)],self);
  {$endif}
end;

function TSQLDataBase.GetUserVersion: cardinal;
begin
  result := ExecuteNoExceptionInt64('PRAGMA user_version');
................................................................................
    FormatUTF8('% with %ternal MM',[fVersionText,MM[fUseInternalMM]],result);
end;


{ TSQLite3LibraryDynamic }

const
  SQLITE3_ENTRIES: array[0..90] of TFileName =
  ('initialize','shutdown','open','open_v2','key','rekey','close',
   'libversion','errmsg','extended_errcode',
   'create_function','create_function_v2',
   'create_collation','last_insert_rowid','busy_timeout','busy_handler',
   'prepare_v2','finalize','next_stmt','reset','stmt_readonly','step',
   'column_count','column_type','column_decltype','column_name','column_bytes',
   'column_value','column_double','column_int','column_int64','column_text',
................................................................................
   'aggregate_context','bind_text','bind_blob','bind_zeroblob','bind_double',
   'bind_int','bind_int64','bind_null','clear_bindings','bind_parameter_count',
   'blob_open','blob_reopen','blob_close','blob_read','blob_write','blob_bytes',
   'create_module_v2','declare_vtab','set_authorizer','update_hook',
   'commit_hook','rollback_hook','changes','total_changes','malloc', 'realloc',
   'free','memory_used','memory_highwater','trace_v2','limit',
   'backup_init','backup_step','backup_finish','backup_remaining',
   'backup_pagecount','serialize','deserialize','soft_heap_limit64',
   'config','db_config');

constructor TSQLite3LibraryDynamic.Create(const LibraryName: TFileName);
var P: PPointerArray;
    i: integer;
begin
  fLibraryName := LibraryName;
  {$ifdef MSWINDOWS}
................................................................................
    fHandle := TLibHandle(dlopen(PChar(LibraryName),0));
    if fHandle=TLibHandle(nil) then
    {$else}
    fHandle := LoadLibrary({$ifndef FPC}pointer{$endif}(LibraryName));
    if fHandle=0 then
    {$endif}
  {$endif MSWINDOWS}
    raise ESQLite3Exception.CreateUTF8('%.Create: Unable to load % - %',
      [self,LibraryName,SysErrorMessage(GetLastError)]);
  P := @@initialize;
  for i := 0 to High(SQLITE3_ENTRIES) do
    P^[i] := {$ifdef BSDNOTDARWIN}dlsym{$else}GetProcAddress{$endif}(
      fHandle,PChar('sqlite3_'+SQLITE3_ENTRIES[i]));
  if not Assigned(initialize) or not Assigned(libversion) or
     not Assigned(open) or not Assigned(close) or not Assigned(create_function) or
     not Assigned(prepare_v2) or not Assigned(create_module_v2) then begin
................................................................................
    {$ifdef BSDNOTDARWIN}
    dlclose(fHandle);
    fHandle := TLibHandle(nil);
    {$else}
    FreeLibrary(fHandle);
    fHandle := 0;
    {$endif}
    raise ESQLite3Exception.CreateUTF8('%.Create: TOO OLD % % - need 3.7 at least!',
      [LibraryName,Version]);
  end; // some APIs like config() key() or trace() may not be available
  inherited Create; // set fVersionNumber/fVersionText
  {$ifdef WITHLOG}
  SynSQLite3Log.Add.Log(sllInfo,'Loaded external % version %',[LibraryName,Version]);
  {$endif}
end;

................................................................................
  if fHandle<>0 then
    FreeLibrary(fHandle);
  {$endif}
  inherited;
end;









initialization

finalization
  FreeAndNil(sqlite3); // sqlite3.Free is not reintrant e.g. as .bpl in IDE
end.

Changes to SynopseCommit.inc.

1
'1.18.4632'
|
1
'1.18.4633'