zeoslib  UNKNOWN
 All Files
ZDbcSqLite.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { SQLite Database Connectivity Classes }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
20 { }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
39 { }
40 { }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZDbcSqLite;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60  ZDbcIntfs, ZDbcConnection, ZPlainSqLiteDriver, ZDbcLogging, ZTokenizer,
61  ZGenericSqlAnalyser, ZURL, ZPlainDriver, ZCompatibility;
62 
63 type
64 
65  {** Implements SQLite Database Driver. }
66  {$WARNINGS OFF}
67  TZSQLiteDriver = class(TZAbstractDriver)
68  public
69  constructor Create; override;
70  function Connect(const Url: TZURL): IZConnection; override;
71  function GetMajorVersion: Integer; override;
72  function GetMinorVersion: Integer; override;
73 
74  function GetTokenizer: IZTokenizer; override;
75  function GetStatementAnalyser: IZStatementAnalyser; override;
76  end;
77  {$WARNINGS ON}
78 
79  {** Represents a SQLite specific connection interface. }
80  IZSQLiteConnection = interface (IZConnection)
81  ['{A4B797A9-7CF7-4DE9-A5BB-693DD32D07D2}']
82  function UseOldBlobEncoding: Boolean;
83  function GetPlainDriver: IZSQLitePlainDriver;
84  function GetConnectionHandle: Psqlite;
85  end;
86 
87  {** Implements SQLite Database Connection. }
88 
89  { TZSQLiteConnection }
90 
91  TZSQLiteConnection = class(TZAbstractConnection, IZSQLiteConnection)
92  private
93  FCatalog: string;
94  FHandle: Psqlite;
95  function UseOldBlobEncoding: Boolean;
96  protected
97  procedure InternalCreate; override;
98  procedure StartTransactionSupport;
99 
100  public
101  destructor Destroy; override;
102 
103  function CreateRegularStatement(Info: TStrings): IZStatement; override;
104  function CreatePreparedStatement(const SQL: string; Info: TStrings):
105  IZPreparedStatement; override;
106 
107  procedure Commit; override;
108  procedure Rollback; override;
109 
110  procedure Open; override;
111  procedure Close; override;
112 
113  procedure SetCatalog(const Catalog: string); override;
114  function GetCatalog: string; override;
115 
116  procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override;
117 
118  function GetClientVersion: Integer; override;
119  function GetHostVersion: Integer; override;
120 
121  function GetPlainDriver: IZSQLitePlainDriver;
122  function GetConnectionHandle: Psqlite;
123 
124  function ReKey(const Key: string): Integer;
125  function Key(const Key: string): Integer;
126  function GetBinaryEscapeString(const Value: RawByteString): String; overload; override;
127  function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override;
128  {$IFDEF ZEOS_TEST_ONLY}
129  constructor Create(const ZUrl: TZURL);
130  {$ENDIF}
131  end;
132 
133 var
134  {** The common driver manager object. }
135  SQLiteDriver: IZDriver;
136 
137 implementation
138 
139 uses
140  ZSysUtils, ZDbcUtils, ZDbcSqLiteStatement, ZSqLiteToken,
141  ZDbcSqLiteUtils, ZDbcSqLiteMetadata, ZSqLiteAnalyser
142  {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
143 
144 { TZSQLiteDriver }
145 
146 {**
147  Constructs this object with default properties.
148 }
149 constructor TZSQLiteDriver.Create;
150 begin
151  inherited Create;
152  AddSupportedProtocol(AddPlainDriverToCache(TZSQLite3PlainDriver.Create, 'sqlite'));
153  AddSupportedProtocol(AddPlainDriverToCache(TZSQLite3PlainDriver.Create));
154 end;
155 
156 {**
157  Attempts to make a database connection to the given URL.
158  The driver should return "null" if it realizes it is the wrong kind
159  of driver to connect to the given URL. This will be common, as when
160  the JDBC driver manager is asked to connect to a given URL it passes
161  the URL to each loaded driver in turn.
162 
163  <P>The driver should raise a SQLException if it is the right
164  driver to connect to the given URL, but has trouble connecting to
165  the database.
166 
167  <P>The java.util.Properties argument can be used to passed arbitrary
168  string tag/value pairs as connection arguments.
169  Normally at least "user" and "password" properties should be
170  included in the Properties.
171 
172  @param url the URL of the database to which to connect
173  @param info a list of arbitrary string tag/value pairs as
174  connection arguments. Normally at least a "user" and
175  "password" property should be included.
176  @return a <code>Connection</code> object that represents a
177  connection to the URL
178 }
179 {$WARNINGS OFF}
180 function TZSQLiteDriver.Connect(const Url: TZURL): IZConnection;
181 begin
182  Result := TZSQLiteConnection.Create(Url);
183 end;
184 {$WARNINGS ON}
185 
186 {**
187  Gets the driver's major version number. Initially this should be 1.
188  @return this driver's major version number
189 }
190 function TZSQLiteDriver.GetMajorVersion: Integer;
191 begin
192  Result := 1;
193 end;
194 
195 {**
196  Gets the driver's minor version number. Initially this should be 0.
197  @return this driver's minor version number
198 }
199 function TZSQLiteDriver.GetMinorVersion: Integer;
200 begin
201  Result := 0;
202 end;
203 
204 {**
205  Gets a SQL syntax tokenizer.
206  @returns a SQL syntax tokenizer object.
207 }
208 function TZSQLiteDriver.GetTokenizer: IZTokenizer;
209 begin
210  Result := TZSQLiteTokenizer.Create; { thread save! Allways return a new Tokenizer! }
211 end;
212 
213 {**
214  Creates a statement analyser object.
215  @returns a statement analyser object.
216 }
217 function TZSQLiteDriver.GetStatementAnalyser: IZStatementAnalyser;
218 begin
219  Result := TZSQLiteStatementAnalyser.Create; { thread save! Allways return a new Analyser! }
220 end;
221 
222 { TZSQLiteConnection }
223 
224 {**
225  Constructs this object and assignes the main properties.
226 }
227 procedure TZSQLiteConnection.InternalCreate;
228 begin
229  FMetadata := TZSQLiteDatabaseMetadata.Create(Self, Url);
230  AutoCommit := True;
231  TransactIsolationLevel := tiNone;
232  CheckCharEncoding('UTF-8');
233  Open;
234 end;
235 
236 {**
237  Destroys this object and cleanups the memory.
238 }
239 destructor TZSQLiteConnection.Destroy;
240 begin
241  inherited Destroy;
242 end;
243 
244 function TZSQLiteConnection.UseOldBlobEncoding: Boolean;
245 begin
246  Result := Url.Properties.Values['OldBlobEncoding'] = 'True';
247 end;
248 
249 {**
250  Set encryption key for a database
251  @param Key the key used to encrypt your database.
252  @return error code from SQLite Key function.
253 }
254 function TZSQLiteConnection.Key(const Key: string):Integer;
255 var
256  ErrorCode: Integer;
257 begin
258  {$IFDEF UNICODE}
259  ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(UTF8String(Key)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Key))));
260  {$ELSE}
261  ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(Key), StrLen(PAnsiChar(Key)));
262  {$ENDIF}
263  Result := ErrorCode;
264 end;
265 
266 {**
267  Reencrypt a database with a new key. The old/current key needs to be
268  set before calling this function.
269  @param Key the new key used to encrypt your database.
270  @return error code from SQLite ReKey function.
271 }
272 function TZSQLiteConnection.ReKey(const Key: string):Integer;
273 var
274  ErrorCode: Integer;
275 begin
276  {$IFDEF UNICODE}
277  ErrorCode := GetPlainDriver.ReKey(FHandle, PAnsiChar(UTF8String(Key)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Key))));
278  {$ELSE}
279  ErrorCode := GetPlainDriver.ReKey(FHandle, PAnsiChar(Key), StrLen(PAnsiChar(Key)));
280  {$ENDIF}
281  Result := ErrorCode;
282 end;
283 
284 {**
285  Opens a connection to database server with specified parameters.
286 }
287 procedure TZSQLiteConnection.Open;
288 var
289  ErrorCode: Integer;
290  ErrorMessage: PAnsiChar;
291  LogMessage: string;
292  SQL: AnsiString;
293  Timeout_ms: Integer;
294 begin
295  if not Closed then
296  Exit;
297  ErrorMessage := '';
298 
299  LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
300 
301 {$IFDEF UNICODE}
302  FHandle := GetPlainDriver.Open(PAnsiChar(AnsiString(UTF8Encode(Database))), 0, ErrorMessage);
303 {$ELSE}
304  FHandle := GetPlainDriver.Open(PAnsiChar(Database), 0, ErrorMessage);
305 {$ENDIF}
306 
307  if FHandle = nil then
308  begin
309  CheckSQLiteError(GetPlainDriver, FHandle, SQLITE_ERROR, ErrorMessage,
310  lcConnect, LogMessage);
311  end;
312  DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage);
313 
314  { Turn on encryption if requested }
315  if StrToBoolEx(Info.Values['encrypted']) then
316  begin
317  {$IFDEF UNICODE}
318  ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(UTF8String(Password)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Password))));
319  {$ELSE}
320  ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(Password), StrLen(PAnsiChar(Password)));
321  {$ENDIF}
322  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, nil, lcConnect, 'SQLite.Key');
323  end;
324 
325  { Set busy timeout if requested }
326  Timeout_ms := StrToIntDef(Info.Values['busytimeout'], -1);
327  if Timeout_ms >= 0 then
328  begin
329  GetPlainDriver.BusyTimeout(FHandle, Timeout_ms);
330  end;
331 
332  try
333  if ( FClientCodePage <> '' ) then
334  begin
335  SQL := 'PRAGMA encoding = '''+AnsiString(FClientCodePage)+'''';
336  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL),
337  nil, nil, ErrorMessage);
338  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL));
339  end;
340 
341  SQL := 'PRAGMA show_datatypes = ON';
342  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL),
343  nil, nil, ErrorMessage);
344  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL));
345 
346  if Info.Values['foreign_keys'] <> '' then
347  begin
348  if StrToBoolEx(Info.Values['foreign_keys']) then
349  SQL := 'PRAGMA foreign_keys = 1'
350  else
351  SQL := 'PRAGMA foreign_keys = 0';
352  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil, ErrorMessage);
353  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL));
354  DriverManager.LogMessage(lcConnect, GetPlainDriver.GetProtocol, String(SQL));
355  end;
356  StartTransactionSupport;
357  except
358  GetPlainDriver.Close(FHandle);
359  FHandle := nil;
360  raise;
361  end;
362 
363  inherited Open;
364 end;
365 
366 {**
367  Creates a <code>Statement</code> object for sending
368  SQL statements to the database.
369  SQL statements without parameters are normally
370  executed using Statement objects. If the same SQL statement
371  is executed many times, it is more efficient to use a
372  <code>PreparedStatement</code> object.
373  <P>
374  Result sets created using the returned <code>Statement</code>
375  object will by default have forward-only type and read-only concurrency.
376 
377  @param Info a statement parameters.
378  @return a new Statement object
379 }
380 function TZSQLiteConnection.CreateRegularStatement(Info: TStrings):
381  IZStatement;
382 begin
383  if IsClosed then
384  Open;
385  Result := TZSQLiteStatement.Create(GetPlainDriver, Self, Info, FHandle);
386 end;
387 
388 {**
389  Creates a <code>PreparedStatement</code> object for sending
390  parameterized SQL statements to the database.
391 
392  A SQL statement with or without IN parameters can be
393  pre-compiled and stored in a PreparedStatement object. This
394  object can then be used to efficiently execute this statement
395  multiple times.
396 
397  <P><B>Note:</B> This method is optimized for handling
398  parametric SQL statements that benefit from precompilation. If
399  the driver supports precompilation,
400  the method <code>prepareStatement</code> will send
401  the statement to the database for precompilation. Some drivers
402  may not support precompilation. In this case, the statement may
403  not be sent to the database until the <code>PreparedStatement</code> is
404  executed. This has no direct effect on users; however, it does
405  affect which method throws certain SQLExceptions.
406 
407  Result sets created using the returned PreparedStatement will have
408  forward-only type and read-only concurrency, by default.
409 
410  @param sql a SQL statement that may contain one or more '?' IN
411  parameter placeholders
412  @param Info a statement parameters.
413  @return a new PreparedStatement object containing the
414  pre-compiled statement
415 }
416 function TZSQLiteConnection.CreatePreparedStatement(const SQL: string;
417  Info: TStrings): IZPreparedStatement;
418 begin
419  if IsClosed then
420  Open;
421  {$IFDEF ZEOS_TEST_ONLY}
422  Case GetTestMode of
423  0:
424  {$ENDIF}
425  Result := TZSQLiteCAPIPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle);
426  {$IFDEF ZEOS_TEST_ONLY}
427  1: Result := TZSQLitePreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle);
428  end;
429  {$ENDIF}
430 end;
431 
432 {**
433  Starts a transaction support.
434 }
435 procedure TZSQLiteConnection.StartTransactionSupport;
436 var
437  ErrorCode: Integer;
438  ErrorMessage: PAnsiChar;
439  SQL: String;
440 begin
441  if TransactIsolationLevel <> tiNone then
442  begin
443  ErrorMessage := '';
444  SQL := 'BEGIN TRANSACTION';
445  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil,
446  ErrorMessage);
447  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL);
448  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
449  end;
450 end;
451 
452 {**
453  Makes all changes made since the previous
454  commit/rollback permanent and releases any database locks
455  currently held by the Connection. This method should be
456  used only when auto-commit mode has been disabled.
457  @see #setAutoCommit
458 }
459 procedure TZSQLiteConnection.Commit;
460 var
461  ErrorCode: Integer;
462  ErrorMessage: PAnsiChar;
463  SQL: PAnsiChar;
464 begin
465  if (TransactIsolationLevel <> tiNone) and not Closed then
466  begin
467  ErrorMessage := '';
468  SQL := 'COMMIT TRANSACTION';
469  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil,
470  ErrorMessage);
471  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL));
472  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL));
473 
474  StartTransactionSupport;
475  end;
476 end;
477 
478 {**
479  Drops all changes made since the previous
480  commit/rollback and releases any database locks currently held
481  by this Connection. This method should be used only when auto-
482  commit has been disabled.
483  @see #setAutoCommit
484 }
485 procedure TZSQLiteConnection.Rollback;
486 var
487  ErrorCode: Integer;
488  ErrorMessage: PAnsiChar;
489  SQL: String;
490 begin
491  if (TransactIsolationLevel <> tiNone) and not Closed then
492  begin
493  ErrorMessage := '';
494  SQL := 'ROLLBACK TRANSACTION';
495  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil,
496  ErrorMessage);
497  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL);
498  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
499 
500  StartTransactionSupport;
501  end;
502 end;
503 
504 {**
505  Releases a Connection's database and JDBC resources
506  immediately instead of waiting for
507  them to be automatically released.
508 
509  <P><B>Note:</B> A Connection is automatically closed when it is
510  garbage collected. Certain fatal errors also result in a closed
511  Connection.
512 }
513 procedure TZSQLiteConnection.Close;
514 var
515  LogMessage: string;
516  ErrorCode: Integer;
517 begin
518  if ( Closed ) or (not Assigned(PlainDriver)) then
519  Exit;
520 
521  LogMessage := 'DISCONNECT FROM "'+Database+'"';
522  if Assigned(DriverManager) then
523  DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage);
524  ErrorCode := GetPlainDriver.Close(FHandle);
525  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, nil,
526  lcOther, LogMessage);
527  FHandle := nil;
528  inherited Close;
529 end;
530 
531 {**
532  Gets a selected catalog name.
533  @return a selected catalog name.
534 }
535 function TZSQLiteConnection.GetCatalog: string;
536 begin
537  Result := FCatalog;
538 end;
539 
540 function TZSQLiteConnection.GetClientVersion: Integer;
541 begin
542  Result := ConvertSQLiteVersionToSQLVersion(GetPlainDriver.LibVersion);
543 end;
544 
545 {**
546  Sets a new selected catalog name.
547  @param Catalog a selected catalog name.
548 }
549 procedure TZSQLiteConnection.SetCatalog(const Catalog: string);
550 begin
551  FCatalog := Catalog;
552 end;
553 
554 {**
555  Sets a new transact isolation level.
556  @param Level a new transact isolation level.
557 }
558 procedure TZSQLiteConnection.SetTransactionIsolation(
559  Level: TZTransactIsolationLevel);
560 var
561  ErrorCode: Integer;
562  ErrorMessage: PAnsiChar;
563  SQL: String;
564 begin
565  if (TransactIsolationLevel <> tiNone) and not Closed then
566  begin
567  ErrorMessage := '';
568  SQL := 'ROLLBACK TRANSACTION';
569  ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil,
570  ErrorMessage);
571  CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL);
572  DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL);
573  end;
574 
575  inherited SetTransactionIsolation(Level);
576 
577  if not Closed then
578  StartTransactionSupport;
579 end;
580 
581 {**
582  Gets a reference to SQLite connection handle.
583  @return a reference to SQLite connection handle.
584 }
585 function TZSQLiteConnection.GetConnectionHandle: Psqlite;
586 begin
587  Result := FHandle;
588 end;
589 
590 {**
591  Gets a SQLite plain driver interface.
592  @return a SQLite plain driver interface.
593 }
594 function TZSQLiteConnection.GetPlainDriver: IZSQLitePlainDriver;
595 begin
596  Result := PlainDriver as IZSQLitePlainDriver;
597 end;
598 
599 {**
600  EgonHugeist:
601  Returns the BinaryString in a Tokenizer-detectable kind
602  If the Tokenizer don't need to predetect it Result := BinaryString
603  @param Value represents the Binary-String
604  @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3)
605  @result the detectable Binary String
606 }
607 function TZSQLiteConnection.GetBinaryEscapeString(const Value: RawByteString): String;
608 begin
609  if GetAutoEncodeStrings then
610  Result := GetDriver.GetTokenizer.AnsiGetEscapeString(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value)))
611  else
612  Result := String(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value)));
613 end;
614 
615 {**
616  EgonHugeist:
617  Returns the BinaryString in a Tokenizer-detectable kind
618  If the Tokenizer don't need to predetect it Result := BinaryString
619  @param Value represents the Binary-String
620  @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3)
621  @result the detectable Binary String
622 }
623 function TZSQLiteConnection.GetBinaryEscapeString(const Value: TByteDynArray): String;
624 begin
625  if GetAutoEncodeStrings then
626  Result := GetDriver.GetTokenizer.AnsiGetEscapeString(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value)))
627  else
628  Result := String(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value)));
629 end;
630 
631 {$IFDEF ZEOS_TEST_ONLY}
632 constructor TZSQLiteConnection.Create(const ZUrl: TZURL);
633 begin
634  inherited Create(ZUrl);
635  end;
636  {$ENDIF}
637 
638 function TZSQLiteConnection.GetHostVersion: Integer;
639 begin
640  Result := ConvertSQLiteVersionToSQLVersion(GetPlainDriver.LibVersion);
641 end;
642 
643 initialization
644  SQLiteDriver := TZSQLiteDriver.Create;
645  DriverManager.RegisterDriver(SQLiteDriver);
646 finalization
647  if DriverManager <> nil then
648  DriverManager.DeregisterDriver(SQLiteDriver);
649  SQLiteDriver := nil;
650 end.
651