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

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

Overview
Comment:added sqlite3.open_v2() support and optional flags for TSQLDataBase.Create() plus associated read-only TSQLDataBase.OpenV2Flags property
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 82b917a0ca4f0949ea164a739de903c1d5f35af8
User & Date: User 2013-12-31 15:08:39
Context
2013-12-31
15:24
fixed unexpected GPF in TSynCache.Find() e.g. when cache is disabled check-in: 7f89ac7467 user: User tags: trunk
15:08
added sqlite3.open_v2() support and optional flags for TSQLDataBase.Create() plus associated read-only TSQLDataBase.OpenV2Flags property check-in: 82b917a0ca user: User tags: trunk
11:31
  • download and unzip the FishFacts SQLite3 database if not available
  • added button to open the Browser on the AJAX application page
check-in: 6bb6f319f7 user: User tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SynSQLite3.pas.

144
145
146
147
148
149
150


151
152
153
154
155
156
157
...
294
295
296
297
298
299
300





































































301
302
303
304
305
306
307
...
965
966
967
968
969
970
971


















972
973
974
975
976
977
978
....
2134
2135
2136
2137
2138
2139
2140

2141
2142
2143
2144
2145
2146
2147
....
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204



2205
2206
2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
2219
2220
....
2417
2418
2419
2420
2421
2422
2423


2424
2425
2426
2427
2428
2429
2430
....
2808
2809
2810
2811
2812
2813
2814
2815

2816
2817
2818
2819
2820
2821
2822
2823
2824
2825




2826
2827
2828
2829
2830
2831
2832
....
3260
3261
3262
3263
3264
3265
3266


3267
3268
3269
3270
3271
3272
3273
3274
....
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
  - added TSQLRequest.BindS()/FieldS()/FieldDeclaredTypeS() methods for direct
    string process
  - now TSQLRequest.Bind(col,'') will bind '' void text instead of null value
  - added TSQLDataBase.CacheSize and LockingMode properties for performance tuning
  - added TSQLDataBase.MemoryMappedMB for optional Memory-Mapped I/O process
  - added TSQLDatabase.LogResultMaximumSize property to reduce logged extend
  - added TSQLDataBase.LockAndFlushCache method to be used instead of Lock('')


  - set SQLITE_TRANSIENT_VIRTUALTABLE constant, to circumvent Win64 Sqlite3 bug
  - TSQLStatementCached.Prepare won't call BindReset, since it is not mandatory;
    see http://hoogli.com/items/Avoid_sqlite3_clear_bindings().html
  - fixed ticket [f79ff5714b] about potential finalization issues as .bpl in IDE
  - TSQLDataBase.Blob() will now allow negative IDs, and expect 0 to be replaced
    by the latest inserted ID - see ticket [799a2c114c]

................................................................................
  {/ sqlite_exec() return code: File opened that is not a database file  }
  SQLITE_NOTADB = 26;

  {/ sqlite3.step() return code: another result row is ready  }
  SQLITE_ROW = 100;
  {/ sqlite3.step() return code: has finished executing  }
  SQLITE_DONE = 101;






































































  /// DestroyPtr set to SQLITE_STATIC if data is constant and will never change
  // - SQLite assumes that the text or BLOB result is in constant space and
  // does not copy the content of the parameter nor call a destructor on the
  // content when it has finished using that result
  SQLITE_STATIC = pointer(0);

................................................................................
      - an error code (see SQLITE_* const) is returned otherwize - sqlite3.errmsg()
        can be used to obtain an English language description of the error
     - Whatever or not an error occurs when it is opened, resources associated with
       the database connection handle should be released by passing it to
       sqlite3.close() when it is no longer required }
    open: function(filename: PUTF8Char; var DB: TSQLite3DB): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif}



















    ///  specify the encryption key on a newly opened database connection
    // - Assigned(key)=false if encryption is not available for this .dll
    // - SynSQlite3Static will use its own internal encryption format
    key: function(DB: TSQLite3DB; key: pointer; keyLen: Integer): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif}

    /// change the encryption key on a database connection that is already opened
    // -  can also decrypt a previously encrypted database (so that it is accessible
................................................................................
    fPassword: RawUTF8;
    fTransactionActive: boolean;
    fLock: TRTLCriticalSection;
    /// if not nil, cache is used - see UseCache property
    fCache: TSynCache;
    fInternalState: PCardinal;
    fBusyTimeout: Integer;

    {$ifdef WITHLOG}
    fLogResultMaximumSize: integer;
    fLog: TSynLog;
    {$endif}
    /// store TSQLDataBaseSQLFunction instances
    fSQLFunctions: TObjectList;
    function GetUseCache: boolean;
................................................................................
    procedure UnLockJSON(const aJSONResult: RawUTF8; aResultCount: PtrInt);
    /// (re)open the database from file fFileName
    // - TSQLDatabase.Create already opens the database: this method is to be
    // used only on particular cases, e.g. to close temporary a DB file and
    // allow making a backup on its content
    // - returns the SQLITE_* status code, as retrieved from sqlite3.open()
    // so that it should be SQLITE_OK on success
    function DBOpen: integer;
    /// close the opened database
    // - TSQLDatabase.Destroy already closes the database: this method is to be
    // used only on particular cases, e.g. to close temporary a DB file and
    // allow making a backup on its content
    // - returns the SQLITE_* status code, as retrieved from sqlite3.close(fDB)
    // so that it should be SQLITE_OK on success
    function DBClose: integer;
  public
    {/ open a SQLite3 database file
     - open an existing database file or create a new one if no file exists
     - if specified, the password will be used to cypher this file on disk
       (the main SQLite3 database file is encrypted, not the wal file during run)



     - SYSTEMNOCASE collation is added (our custom fast UTF-8 case insensitive compare,
       which is used also in the SQLite3UI unit for coherency and efficiency)
     - ISO8601 collation is added (TDateTime stored as ISO-8601 encoded TEXT)
     - WIN32CASE and WIN32NOCASE collations are added (use slow but accurate Win32 CompareW)
     - some additional SQl functions are registered: MOD, SOUNDEX/SOUNDEXFR/SOUNDEXES,
       RANK, CONCAT
     - initialize a TRTLCriticalSection to ensure that all access to the database is atomic
     - raise an ESQLite3Exception on any error }
    constructor Create(const aFileName: TFileName; const aPassword: RawUTF8='');

    {/ close a database and free its memory and context
      - if TransactionBegin was called but not commited, a RollBack is performed }
    destructor Destroy; override;
    {/ Execute all SQL statements in aSQL UTF-8 encoded string
     - can be prepared with TransactionBegin()
     - raise an ESQLite3Exception on any error }
    procedure ExecuteAll(const aSQL: RawUTF8);
................................................................................
    property LogResultMaximumSize: integer read fLogResultMaximumSize write fLogResultMaximumSize;
    {$endif}
    {/ retrieve or set the user_version stored in the SQLite3 database file
      - user-version is a 32-bit signed integer stored in the database header
      - it can be used to change the database in case of format upgrade (e.g.
        refresh some hand-made triggers) }
    property user_version: cardinal read GetUserVersion write SetUserVersion;


  end;

  /// used to read or write a BLOB Incrementaly
  // - data is read/written directly from/to the SQLite3 BTree
  // - data can be written after a TSQLRequest.BindZero() call to reserve memory
  // - this TStream has a fixed size, but Position property can be used to rewind
  TSQLBlobStream = class(TStream)
................................................................................
    if RawUTF8DynArrayLoadFromContains(Blob,Value,SynCommons.StrLen(Value),
       sqlite3.user_data(Context)=nil)<0 then
      Blob := nil;
  end;
  sqlite3.result_int64(Context,Int64(Blob<>nil));
end;

constructor TSQLDataBase.Create(const aFileName: TFileName; const aPassword: RawUTF8='');

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, '+
      'either set sqlite3 := TSQLite3LibraryDynamic.Create to load sqlite3.dll');
  {$ifdef WITHLOG}
  fLog := SynSQLite3Log.Family.SynLog; // leave fLog=nil if no Logging wanted
  fLogResultMaximumSize := 512;
  {$endif}




  InitializeCriticalSection(fLock);
  fFileName := aFileName;
  fPassword := aPassword;
  fSQLFunctions := TObjectList.Create;
  result := DBOpen;
  if result<>SQLITE_OK then
    raise ESQLite3Exception.Create(fDB,result);
................................................................................
  fLog.Enter;
  {$endif}
  if fDB<>0 then
    raise ESQLite3Exception.Create('DBOpen called twice');
  if (sqlite3=nil) or not Assigned(sqlite3.open) then
    raise ESQLite3Exception.Create('DBOpen called with no sqlite3 global');
  utf8 := StringToUTF8(fFileName);


  result := sqlite3.open(pointer(utf8),fDB);
  if result<>SQLITE_OK then begin
    {$ifdef WITHLOG}
    fLog.Log(sllError,'open("'+utf8+'") failed',self);
    {$endif}
    sqlite3.close(fDB); // should always be closed, even on failure
    fDB := 0;
    exit;
................................................................................
  Caches.ReHash; // need to refresh all hashs
end;


{ TSQLite3LibraryDynamic }

const
  SQLITE3_ENTRIES: array[0..74] of TFileName =
  ('initialize','shutdown','open','key','rekey','close','libversion',
   'errmsg','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','column_blob','value_type','value_numeric_type',
   'value_bytes','value_double','value_int64','value_text','value_blob',
   'result_null','result_int64','result_double','result_blob','result_text',






>
>







 







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







 







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







 







>







 







|












>
>
>








|
>







 







>
>







 







|
>










>
>
>
>







 







>
>
|







 







|
|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
....
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
....
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
....
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
....
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
....
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
....
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
....
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
  - added TSQLRequest.BindS()/FieldS()/FieldDeclaredTypeS() methods for direct
    string process
  - now TSQLRequest.Bind(col,'') will bind '' void text instead of null value
  - added TSQLDataBase.CacheSize and LockingMode properties for performance tuning
  - added TSQLDataBase.MemoryMappedMB for optional Memory-Mapped I/O process
  - added TSQLDatabase.LogResultMaximumSize property to reduce logged extend
  - added TSQLDataBase.LockAndFlushCache method to be used instead of Lock('')
  - added sqlite3.open_v2() support and optional flags for TSQLDataBase.Create()
    plus associated read-only TSQLDataBase.OpenV2Flags property
  - set SQLITE_TRANSIENT_VIRTUALTABLE constant, to circumvent Win64 Sqlite3 bug
  - TSQLStatementCached.Prepare won't call BindReset, since it is not mandatory;
    see http://hoogli.com/items/Avoid_sqlite3_clear_bindings().html
  - fixed ticket [f79ff5714b] about potential finalization issues as .bpl in IDE
  - TSQLDataBase.Blob() will now allow negative IDs, and expect 0 to be replaced
    by the latest inserted ID - see ticket [799a2c114c]

................................................................................
  {/ sqlite_exec() return code: File opened that is not a database file  }
  SQLITE_NOTADB = 26;

  {/ sqlite3.step() return code: another result row is ready  }
  SQLITE_ROW = 100;
  {/ sqlite3.step() return code: has finished executing  }
  SQLITE_DONE = 101;

  /// The database is opened in read-only mode
  // - if the database does not already exist, an error is returned
  // - Ok for sqlite3.open_v2()
  SQLITE_OPEN_READONLY = $00000001;
  /// The database is opened for reading and writing if possible, or reading
  // only if the file is write protected by the operating system
  // - In either case the database must already exist, otherwise an error is
  // returned
  // - Ok for sqlite3.open_v2()
  SQLITE_OPEN_READWRITE = $00000002;
  /// In conjunction with SQLITE_OPEN_READWRITE, optionally create the database
  // file if it does not exist
  // - The database is opened for reading and writing if possible, or reading
  // only if the file is write protected by the operating system
  // - In either case the database must already exist, otherwise an error is returned
  SQLITE_OPEN_CREATE = $00000004;
  /// URI filename interpretation is enabled if the SQLITE_OPEN_URI flag is set
  // in the fourth argument to sqlite3.open_v2(), or if it has been enabled
  // globally using the SQLITE_CONFIG_URI option with the sqlite3.config() method
  // or by the SQLITE_USE_URI compile-time option.
  // - As of SQLite version 3.7.7, URI filename interpretation is turned off by
  // default, but future releases of SQLite might enable URI filename
  // interpretation by default
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_URI = $00000040;  // Ok for sqlite3_open_v2()
  /// If the SQLITE_OPEN_NOMUTEX flag is set, then the database will remain in
  // memory
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_MEMORY = $00000080;  // Ok for sqlite3_open_v2()
  /// If the SQLITE_OPEN_NOMUTEX flag is set, then the database connection opens
  // in the multi-thread threading mode as long as the single-thread mode has
  // not been set at compile-time or start-time
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_NOMUTEX = $00008000;  // Ok for sqlite3_open_v2()
  /// If the SQLITE_OPEN_FULLMUTEX flag is set then the database connection opens
  // in the serialized threading mode unless single-thread was previously selected
  // at compile-time or start-time
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_FULLMUTEX = $00010000;  // Ok for sqlite3_open_v2()
  /// The SQLITE_OPEN_SHAREDCACHE flag causes the database connection to be
  // eligible to use shared cache mode, regardless of whether or not shared
  // cache is enabled using sqlite3.enable_shared_cache()
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_SHAREDCACHE = $00020000;  // Ok for sqlite3_open_v2()
  /// The SQLITE_OPEN_PRIVATECACHE flag causes the database connection to not
  // participate in shared cache mode even if it is enabled
  // - Ok for sqlite3.open_v2(), in conjuction with SQLITE_OPEN_READONLY,
  // SQLITE_OPEN_READWRITE, (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
  SQLITE_OPEN_PRIVATECACHE = $00040000;

{
  SQLITE_OPEN_DELETEONCLOSE  = $00000008;  // VFS only
  SQLITE_OPEN_EXCLUSIVE      = $00000010;  // VFS only
  SQLITE_OPEN_AUTOPROXY      = $00000020;  // VFS only
  SQLITE_OPEN_MAIN_DB        = $00000100;  // VFS only
  SQLITE_OPEN_TEMP_DB        = $00000200;  // VFS only
  SQLITE_OPEN_TRANSIENT_DB   = $00000400;  // VFS only
  SQLITE_OPEN_MAIN_JOURNAL   = $00000800;  // VFS only
  SQLITE_OPEN_TEMP_JOURNAL   = $00001000;  // VFS only
  SQLITE_OPEN_SUBJOURNAL     = $00002000;  // VFS only
  SQLITE_OPEN_MASTER_JOURNAL = $00004000;  // VFS only
  SQLITE_OPEN_WAL            = $00080000;  // VFS only
}

  /// DestroyPtr set to SQLITE_STATIC if data is constant and will never change
  // - SQLite assumes that the text or BLOB result is in constant space and
  // does not copy the content of the parameter nor call a destructor on the
  // content when it has finished using that result
  SQLITE_STATIC = pointer(0);

................................................................................
      - an error code (see SQLITE_* const) is returned otherwize - sqlite3.errmsg()
        can be used to obtain an English language description of the error
     - Whatever or not an error occurs when it is opened, resources associated with
       the database connection handle should be released by passing it to
       sqlite3.close() when it is no longer required }
    open: function(filename: PUTF8Char; var DB: TSQLite3DB): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif}

    {/ Open a SQLite3 database filename, creating a DB handle
     - sqlite3.open_v2() interface works like sqlite3.open() except that it
       accepts two additional parameters for additional control over the new
       database connection.
     - flags parameter to sqlite3.open_v2() can take one of SQLITE_OPEN_READONLY,
       SQLITE_OPEN_READWRITE or (SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)
       values, optionally combined with the SQLITE_OPEN_NOMUTEX,
       SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE, SQLITE_OPEN_PRIVATECACHE,
       and/or SQLITE_OPEN_URI flags
     - If the flags parameter is not one of the combinations shown above optionally
      combined with other SQLITE_OPEN_* bits then the behavior is undefined.
     - The fourth parameter is the name of the sqlite3_vfs object that defines
       the operating system interface that the new database connection should use.
       If the fourth parameter is a nil pointer then the default sqlite3_vfs
       object is used }
    open_v2: function(filename: PUTF8Char; var DB: TSQLite3DB; flags: integer;
      zVfszVfs: PUTF8Char): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif}

    ///  specify the encryption key on a newly opened database connection
    // - Assigned(key)=false if encryption is not available for this .dll
    // - SynSQlite3Static will use its own internal encryption format
    key: function(DB: TSQLite3DB; key: pointer; keyLen: Integer): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif}

    /// change the encryption key on a database connection that is already opened
    // -  can also decrypt a previously encrypted database (so that it is accessible
................................................................................
    fPassword: RawUTF8;
    fTransactionActive: boolean;
    fLock: TRTLCriticalSection;
    /// if not nil, cache is used - see UseCache property
    fCache: TSynCache;
    fInternalState: PCardinal;
    fBusyTimeout: Integer;
    fOpenV2Flags: Integer;
    {$ifdef WITHLOG}
    fLogResultMaximumSize: integer;
    fLog: TSynLog;
    {$endif}
    /// store TSQLDataBaseSQLFunction instances
    fSQLFunctions: TObjectList;
    function GetUseCache: boolean;
................................................................................
    procedure UnLockJSON(const aJSONResult: RawUTF8; aResultCount: PtrInt);
    /// (re)open the database from file fFileName
    // - TSQLDatabase.Create already opens the database: this method is to be
    // used only on particular cases, e.g. to close temporary a DB file and
    // allow making a backup on its content
    // - returns the SQLITE_* status code, as retrieved from sqlite3.open()
    // so that it should be SQLITE_OK on success
    function DBOpen: integer; virtual;
    /// close the opened database
    // - TSQLDatabase.Destroy already closes the database: this method is to be
    // used only on particular cases, e.g. to close temporary a DB file and
    // allow making a backup on its content
    // - returns the SQLITE_* status code, as retrieved from sqlite3.close(fDB)
    // so that it should be SQLITE_OK on success
    function DBClose: integer;
  public
    {/ open a SQLite3 database file
     - open an existing database file or create a new one if no file exists
     - if specified, the password will be used to cypher this file on disk
       (the main SQLite3 database file is encrypted, not the wal file during run)
     - you can specify some optional flags for sqlite3.open_v2() as
       SQLITE_OPEN_READONLY or SQLITE_OPEN_READWRITE instead of supplied default
       value (which corresponds to the sqlite3.open() behavior)
     - SYSTEMNOCASE collation is added (our custom fast UTF-8 case insensitive compare,
       which is used also in the SQLite3UI unit for coherency and efficiency)
     - ISO8601 collation is added (TDateTime stored as ISO-8601 encoded TEXT)
     - WIN32CASE and WIN32NOCASE collations are added (use slow but accurate Win32 CompareW)
     - some additional SQl functions are registered: MOD, SOUNDEX/SOUNDEXFR/SOUNDEXES,
       RANK, CONCAT
     - initialize a TRTLCriticalSection to ensure that all access to the database is atomic
     - raise an ESQLite3Exception on any error }
    constructor Create(const aFileName: TFileName; const aPassword: RawUTF8='';
      aOpenV2Flags: integer=SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE);
    {/ close a database and free its memory and context
      - if TransactionBegin was called but not commited, a RollBack is performed }
    destructor Destroy; override;
    {/ Execute all SQL statements in aSQL UTF-8 encoded string
     - can be prepared with TransactionBegin()
     - raise an ESQLite3Exception on any error }
    procedure ExecuteAll(const aSQL: RawUTF8);
................................................................................
    property LogResultMaximumSize: integer read fLogResultMaximumSize write fLogResultMaximumSize;
    {$endif}
    {/ retrieve or set the user_version stored in the SQLite3 database file
      - user-version is a 32-bit signed integer stored in the database header
      - it can be used to change the database in case of format upgrade (e.g.
        refresh some hand-made triggers) }
    property user_version: cardinal read GetUserVersion write SetUserVersion;
    /// reflects how the database connection was created in the constructor
    property OpenV2Flags: Integer read fOpenV2Flags;
  end;

  /// used to read or write a BLOB Incrementaly
  // - data is read/written directly from/to the SQLite3 BTree
  // - data can be written after a TSQLRequest.BindZero() call to reserve memory
  // - this TStream has a fixed size, but Position property can be used to rewind
  TSQLBlobStream = class(TStream)
................................................................................
    if RawUTF8DynArrayLoadFromContains(Blob,Value,SynCommons.StrLen(Value),
       sqlite3.user_data(Context)=nil)<0 then
      Blob := nil;
  end;
  sqlite3.result_int64(Context,Int64(Blob<>nil));
end;

constructor TSQLDataBase.Create(const aFileName: TFileName; const aPassword: RawUTF8='';
  aOpenV2Flags: integer=SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE);
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, '+
      'either set sqlite3 := TSQLite3LibraryDynamic.Create to load sqlite3.dll');
  {$ifdef WITHLOG}
  fLog := SynSQLite3Log.Family.SynLog; // leave fLog=nil if no Logging wanted
  fLogResultMaximumSize := 512;
  {$endif}
  fOpenV2Flags := aOpenV2Flags;
  if (fOpenV2Flags<>(SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE)) and
     not Assigned(sqlite3.open_v2) then
    raise ESQLite3Exception.Create('Your version of SQLite3 does not support custom OpenV2Flags');
  InitializeCriticalSection(fLock);
  fFileName := aFileName;
  fPassword := aPassword;
  fSQLFunctions := TObjectList.Create;
  result := DBOpen;
  if result<>SQLITE_OK then
    raise ESQLite3Exception.Create(fDB,result);
................................................................................
  fLog.Enter;
  {$endif}
  if fDB<>0 then
    raise ESQLite3Exception.Create('DBOpen called twice');
  if (sqlite3=nil) or not Assigned(sqlite3.open) then
    raise ESQLite3Exception.Create('DBOpen called with no sqlite3 global');
  utf8 := StringToUTF8(fFileName);
  if fOpenV2Flags<>(SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE) then
    result := sqlite3.open_v2(pointer(utf8),fDB,fOpenV2Flags,nil) else
    result := sqlite3.open(pointer(utf8),fDB);
  if result<>SQLITE_OK then begin
    {$ifdef WITHLOG}
    fLog.Log(sllError,'open("'+utf8+'") failed',self);
    {$endif}
    sqlite3.close(fDB); // should always be closed, even on failure
    fDB := 0;
    exit;
................................................................................
  Caches.ReHash; // need to refresh all hashs
end;


{ TSQLite3LibraryDynamic }

const
  SQLITE3_ENTRIES: array[0..75] of TFileName =
  ('initialize','shutdown','open','open_v2','key','rekey','close','libversion',
   'errmsg','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','column_blob','value_type','value_numeric_type',
   'value_bytes','value_double','value_int64','value_text','value_blob',
   'result_null','result_int64','result_double','result_blob','result_text',

Changes to SynSQlite3Static.pas.

1164
1165
1166
1167
1168
1169
1170

1171
1172
1173
1174
1175
1176
1177
....
1265
1266
1267
1268
1269
1270
1271

1272
1273
1274
1275
1276
1277
1278
    result := SQLITE_OK;
end;


function sqlite3_initialize: integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_shutdown: integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_open(filename: PUTF8Char; var DB: TSQLite3DB): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;

function sqlite3_create_function_v2(DB: TSQLite3DB; FunctionName: PUTF8Char;
  nArg, eTextRep: integer; pApp: pointer; xFunc, xStep: TSQLFunctionFunc;
  xFinal: TSQLFunctionFinal; xDestroy: TSQLDestroyPtr): Integer;
  {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_create_collation(DB: TSQLite3DB; CollationName: PUTF8Char;
  StringEncoding: integer; CollateParam: pointer; cmp: TSQLCollateFunc): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_libversion: PUTF8Char; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
................................................................................

constructor TSQLite3LibraryStatic.Create;
begin
  inherited;
  initialize           := @sqlite3_initialize;
  shutdown             := @sqlite3_shutdown;
  open                 := @sqlite3_open;

  key                  := @sqlite3_key;
  rekey                := @sqlite3_rekey;
  close                := @sqlite3_closeInternal;
  libversion           := @sqlite3_libversion;
  errmsg               := @sqlite3_errmsg;
  create_function_v2   := @sqlite3_create_function_v2;
  create_collation     := @sqlite3_create_collation;






>







 







>







1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
....
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
    result := SQLITE_OK;
end;


function sqlite3_initialize: integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_shutdown: integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_open(filename: PUTF8Char; var DB: TSQLite3DB): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_open_v2(filename: PUTF8Char; var DB: TSQLite3DB; flags: Integer; vfs: PUTF8Char): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_create_function_v2(DB: TSQLite3DB; FunctionName: PUTF8Char;
  nArg, eTextRep: integer; pApp: pointer; xFunc, xStep: TSQLFunctionFunc;
  xFinal: TSQLFunctionFinal; xDestroy: TSQLDestroyPtr): Integer;
  {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_create_collation(DB: TSQLite3DB; CollationName: PUTF8Char;
  StringEncoding: integer; CollateParam: pointer; cmp: TSQLCollateFunc): integer; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
function sqlite3_libversion: PUTF8Char; {$ifndef SQLITE3_FASTCALL}cdecl;{$endif} external;
................................................................................

constructor TSQLite3LibraryStatic.Create;
begin
  inherited;
  initialize           := @sqlite3_initialize;
  shutdown             := @sqlite3_shutdown;
  open                 := @sqlite3_open;
  open_v2              := @sqlite3_open_v2;
  key                  := @sqlite3_key;
  rekey                := @sqlite3_rekey;
  close                := @sqlite3_closeInternal;
  libversion           := @sqlite3_libversion;
  errmsg               := @sqlite3_errmsg;
  create_function_v2   := @sqlite3_create_function_v2;
  create_collation     := @sqlite3_create_collation;