source: trunk/SQLite3/SQLite3Wrap.pas

Last change on this file was 9, checked in by chronos, 2 years ago
  • Modified: Restore pristine files for deleted files with using information from subversion SQLite3 database.
File size: 14.1 KB
Line 
1{*
2 * SQLite for Delphi and FreePascal/Lazarus
3 *
4 * This unit contains easy-to-use object wrapper over SQLite3 API functions.
5 *
6 * Copyright (c) 2013 Yuri Plashenkov
7 *
8 * MIT License
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16
17 * The above copyright notice and this permission notice shall be included in all
18 * copies or substantial portions of the Software.
19
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *}
28
29unit SQLite3Wrap;
30
31{$IFDEF FPC}
32 {$MODE DELPHI}
33{$ENDIF}
34
35interface
36
37uses
38 SysUtils, Classes, SQLite3;
39
40type
41 ESQLite3Error = class(Exception);
42
43 TSQLite3Statement = class;
44 TSQLite3BlobHandler = class;
45
46 { TSQLite3Database class }
47
48 TSQLite3Database = class(TObject)
49 private
50 FHandle: PSQLite3;
51 FStatementList: TList;
52 FBlobHandlerList: TList;
53 FTransactionOpen: Boolean;
54 procedure Check(const ErrCode: Integer);
55 procedure CheckHandle;
56 public
57 constructor Create;
58 destructor Destroy; override;
59
60 procedure Open(const FileName: WideString; Flags: Integer = 0);
61 procedure Close;
62
63 procedure Execute(const SQL: WideString);
64 function LastInsertRowID: Int64;
65 function Prepare(const SQL: WideString): TSQLite3Statement;
66 function BlobOpen(const Table, Column: WideString; const RowID: Int64; const WriteAccess: Boolean = True): TSQLite3BlobHandler;
67
68 procedure BeginTransaction;
69 procedure Commit;
70 procedure Rollback;
71
72 property Handle: PSQLite3 read FHandle;
73 property TransactionOpen: Boolean read FTransactionOpen;
74 end;
75
76 { TSQLite3Statement class }
77
78 TSQLite3Statement = class(TObject)
79 private
80 FHandle: PSQLite3Stmt;
81 FOwnerDatabase: TSQLite3Database;
82 function ParamIndexByName(const ParamName: WideString): Integer;
83 public
84 constructor Create(OwnerDatabase: TSQLite3Database; const SQL: WideString);
85 destructor Destroy; override;
86
87 procedure BindInt(const ParamIndex: Integer; const Value: Integer); overload;
88 procedure BindInt64(const ParamIndex: Integer; const Value: Int64); overload;
89 procedure BindDouble(const ParamIndex: Integer; const Value: Double); overload;
90 procedure BindText(const ParamIndex: Integer; const Value: WideString); overload;
91 procedure BindNull(const ParamIndex: Integer); overload;
92 procedure BindBlob(const ParamIndex: Integer; Data: Pointer; const Size: Integer); overload;
93 procedure BindZeroBlob(const ParamIndex: Integer; const Size: Integer); overload;
94 procedure BindInt(const ParamName: WideString; const Value: Integer); overload;
95 procedure BindInt64(const ParamName: WideString; const Value: Int64); overload;
96 procedure BindDouble(const ParamName: WideString; const Value: Double); overload;
97 procedure BindText(const ParamName: WideString; const Value: WideString); overload;
98 procedure BindNull(const ParamName: WideString); overload;
99 procedure BindBlob(const ParamName: WideString; Data: Pointer; const Size: Integer); overload;
100 procedure BindZeroBlob(const ParamName: WideString; const Size: Integer); overload;
101 procedure ClearBindings;
102
103 function Step: Integer;
104 procedure Reset;
105 function StepAndReset: Integer;
106
107 function ColumnCount: Integer;
108 function ColumnName(const ColumnIndex: Integer): WideString;
109 function ColumnType(const ColumnIndex: Integer): Integer;
110 function ColumnInt(const ColumnIndex: Integer): Integer;
111 function ColumnInt64(const ColumnIndex: Integer): Int64;
112 function ColumnDouble(const ColumnIndex: Integer): Double;
113 function ColumnText(const ColumnIndex: Integer): WideString;
114 function ColumnBlob(const ColumnIndex: Integer): Pointer;
115 function ColumnBytes(const ColumnIndex: Integer): Integer;
116
117 property Handle: PSQLite3Stmt read FHandle;
118 property OwnerDatabase: TSQLite3Database read FOwnerDatabase;
119 end;
120
121 { TSQLite3BlobHandler class }
122
123 TSQLite3BlobHandler = class(TObject)
124 private
125 FHandle: PSQLite3Blob;
126 FOwnerDatabase: TSQLite3Database;
127 public
128 constructor Create(OwnerDatabase: TSQLite3Database; const Table, Column: WideString; const RowID: Int64; const WriteAccess: Boolean = True);
129 destructor Destroy; override;
130
131 function Bytes: Integer;
132 procedure Read(Buffer: Pointer; const Size, Offset: Integer);
133 procedure Write(Buffer: Pointer; const Size, Offset: Integer);
134
135 property Handle: PSQLite3Blob read FHandle;
136 property OwnerDatabase: TSQLite3Database read FOwnerDatabase;
137 end;
138
139implementation
140
141uses
142 SQLite3Utils;
143
144resourcestring
145 SErrorMessage = 'SQLite3 error: %s';
146 SDatabaseNotConnected = 'SQLite3 error: database is not connected.';
147 STransactionAlreadyOpen = 'Transaction is already opened.';
148 SNoTransactionOpen = 'No transaction is open';
149
150{ TSQLite3Database }
151
152procedure TSQLite3Database.BeginTransaction;
153begin
154 if not FTransactionOpen then
155 begin
156 Execute('BEGIN TRANSACTION;');
157 FTransactionOpen := True;
158 end
159 else
160 raise ESQLite3Error.Create(STransactionAlreadyOpen);
161end;
162
163function TSQLite3Database.BlobOpen(const Table, Column: WideString;
164 const RowID: Int64; const WriteAccess: Boolean): TSQLite3BlobHandler;
165begin
166 Result := TSQLite3BlobHandler.Create(Self, Table, Column, RowID, WriteAccess);
167end;
168
169procedure TSQLite3Database.Check(const ErrCode: Integer);
170begin
171 if ErrCode <> SQLITE_OK then
172 raise ESQLite3Error.CreateFmt(SErrorMessage, [UTF8ToStr(sqlite3_errmsg(FHandle))]);
173end;
174
175procedure TSQLite3Database.CheckHandle;
176begin
177 if FHandle = nil then
178 raise ESQLite3Error.Create(SDatabaseNotConnected);
179end;
180
181procedure TSQLite3Database.Close;
182var
183 I: Integer;
184begin
185 if FHandle <> nil then
186 begin
187 if FTransactionOpen then
188 Rollback;
189 // Delete all statements
190 for I := FStatementList.Count - 1 downto 0 do
191 TSQLite3Statement(FStatementList[I]).Free;
192 // Delete all blob handlers
193 for I := FBlobHandlerList.Count - 1 downto 0 do
194 TSQLite3BlobHandler(FBlobHandlerList[I]).Free;
195 sqlite3_close(FHandle);
196 FHandle := nil;
197 end;
198end;
199
200procedure TSQLite3Database.Commit;
201begin
202 if FTransactionOpen then
203 begin
204 Execute('COMMIT;');
205 FTransactionOpen := False;
206 end
207 else
208 raise ESQLite3Error.Create(SNoTransactionOpen);
209end;
210
211constructor TSQLite3Database.Create;
212begin
213 FHandle := nil;
214 FStatementList := TList.Create;
215 FBlobHandlerList := TList.Create;
216end;
217
218destructor TSQLite3Database.Destroy;
219begin
220 Close;
221 FBlobHandlerList.Free;
222 FStatementList.Free;
223 inherited;
224end;
225
226procedure TSQLite3Database.Execute(const SQL: WideString);
227begin
228 CheckHandle;
229 Check(sqlite3_exec(FHandle, PAnsiChar(StrToUTF8(SQL)), nil, nil, nil));
230end;
231
232function TSQLite3Database.LastInsertRowID: Int64;
233begin
234 CheckHandle;
235 Result := sqlite3_last_insert_rowid(FHandle);
236end;
237
238procedure TSQLite3Database.Open(const FileName: WideString; Flags: Integer);
239begin
240 Close;
241 if Flags = 0 then
242 Check(sqlite3_open(PAnsiChar(StrToUTF8(FileName)), FHandle))
243 else
244 Check(sqlite3_open_v2(PAnsiChar(StrToUTF8(FileName)), FHandle, Flags, nil));
245end;
246
247function TSQLite3Database.Prepare(const SQL: WideString): TSQLite3Statement;
248begin
249 Result := TSQLite3Statement.Create(Self, SQL);
250end;
251
252procedure TSQLite3Database.Rollback;
253begin
254 if FTransactionOpen then
255 begin
256 Execute('ROLLBACK;');
257 FTransactionOpen := False;
258 end
259 else
260 raise ESQLite3Error.Create(SNoTransactionOpen);
261end;
262
263{ TSQLite3Statement }
264
265procedure TSQLite3Statement.BindBlob(const ParamIndex: Integer; Data: Pointer;
266 const Size: Integer);
267begin
268 FOwnerDatabase.Check(sqlite3_bind_blob(FHandle, ParamIndex, Data, Size, SQLITE_TRANSIENT));
269end;
270
271procedure TSQLite3Statement.BindDouble(const ParamIndex: Integer;
272 const Value: Double);
273begin
274 FOwnerDatabase.Check(sqlite3_bind_double(FHandle, ParamIndex, Value));
275end;
276
277procedure TSQLite3Statement.BindInt(const ParamIndex, Value: Integer);
278begin
279 FOwnerDatabase.Check(sqlite3_bind_int(FHandle, ParamIndex, Value));
280end;
281
282procedure TSQLite3Statement.BindInt64(const ParamIndex: Integer;
283 const Value: Int64);
284begin
285 FOwnerDatabase.Check(sqlite3_bind_int64(FHandle, ParamIndex, Value));
286end;
287
288procedure TSQLite3Statement.BindNull(const ParamIndex: Integer);
289begin
290 FOwnerDatabase.Check(sqlite3_bind_null(FHandle, ParamIndex));
291end;
292
293procedure TSQLite3Statement.BindText(const ParamIndex: Integer;
294 const Value: WideString);
295var
296 S: AnsiString; { UTF-8 string }
297begin
298 S := StrToUTF8(Value);
299 FOwnerDatabase.Check(
300 sqlite3_bind_text(FHandle, ParamIndex, PAnsiChar(S), Length(S), SQLITE_TRANSIENT)
301 );
302end;
303
304procedure TSQLite3Statement.BindZeroBlob(const ParamIndex, Size: Integer);
305begin
306 FOwnerDatabase.Check(sqlite3_bind_zeroblob(FHandle, ParamIndex, Size));
307end;
308
309procedure TSQLite3Statement.ClearBindings;
310begin
311 FOwnerDatabase.Check(sqlite3_clear_bindings(FHandle));
312end;
313
314function TSQLite3Statement.ColumnBlob(const ColumnIndex: Integer): Pointer;
315begin
316 Result := sqlite3_column_blob(FHandle, ColumnIndex);
317end;
318
319function TSQLite3Statement.ColumnBytes(const ColumnIndex: Integer): Integer;
320begin
321 Result := sqlite3_column_bytes(FHandle, ColumnIndex);
322end;
323
324function TSQLite3Statement.ColumnCount: Integer;
325begin
326 Result := sqlite3_column_count(FHandle);
327end;
328
329function TSQLite3Statement.ColumnDouble(const ColumnIndex: Integer): Double;
330begin
331 Result := sqlite3_column_double(FHandle, ColumnIndex);
332end;
333
334function TSQLite3Statement.ColumnInt(const ColumnIndex: Integer): Integer;
335begin
336 Result := sqlite3_column_int(FHandle, ColumnIndex);
337end;
338
339function TSQLite3Statement.ColumnInt64(const ColumnIndex: Integer): Int64;
340begin
341 Result := sqlite3_column_int64(FHandle, ColumnIndex);
342end;
343
344function TSQLite3Statement.ColumnName(const ColumnIndex: Integer): WideString;
345begin
346 Result := UTF8ToStr(sqlite3_column_name(FHandle, ColumnIndex));
347end;
348
349function TSQLite3Statement.ColumnText(const ColumnIndex: Integer): WideString;
350var
351 Len: Integer;
352begin
353 Len := ColumnBytes(ColumnIndex);
354 Result := UTF8ToStr(sqlite3_column_text(FHandle, ColumnIndex), Len);
355end;
356
357function TSQLite3Statement.ColumnType(const ColumnIndex: Integer): Integer;
358begin
359 Result := sqlite3_column_type(FHandle, ColumnIndex);
360end;
361
362constructor TSQLite3Statement.Create(OwnerDatabase: TSQLite3Database;
363 const SQL: WideString);
364begin
365 FOwnerDatabase := OwnerDatabase;
366 FOwnerDatabase.CheckHandle;
367 FOwnerDatabase.Check(
368 sqlite3_prepare_v2(FOwnerDatabase.Handle, PAnsiChar(StrToUTF8(SQL)), -1, FHandle, nil)
369 );
370 FOwnerDatabase.FStatementList.Add(Self);
371end;
372
373destructor TSQLite3Statement.Destroy;
374begin
375 FOwnerDatabase.FStatementList.Remove(Self);
376 sqlite3_finalize(FHandle);
377 inherited;
378end;
379
380function TSQLite3Statement.ParamIndexByName(const ParamName: WideString): Integer;
381begin
382 Result := sqlite3_bind_parameter_index(FHandle, PAnsiChar(StrToUTF8(ParamName)));
383end;
384
385procedure TSQLite3Statement.Reset;
386begin
387 sqlite3_reset(FHandle);
388end;
389
390function TSQLite3Statement.Step: Integer;
391begin
392 Result := sqlite3_step(FHandle);
393end;
394
395function TSQLite3Statement.StepAndReset: Integer;
396begin
397 Result := Step;
398 Reset;
399end;
400
401procedure TSQLite3Statement.BindBlob(const ParamName: WideString; Data: Pointer;
402 const Size: Integer);
403begin
404 BindBlob(ParamIndexByName(ParamName), Data, Size);
405end;
406
407procedure TSQLite3Statement.BindDouble(const ParamName: WideString;
408 const Value: Double);
409begin
410 BindDouble(ParamIndexByName(ParamName), Value);
411end;
412
413procedure TSQLite3Statement.BindInt(const ParamName: WideString;
414 const Value: Integer);
415begin
416 BindInt(ParamIndexByName(ParamName), Value);
417end;
418
419procedure TSQLite3Statement.BindInt64(const ParamName: WideString;
420 const Value: Int64);
421begin
422 BindInt64(ParamIndexByName(ParamName), Value);
423end;
424
425procedure TSQLite3Statement.BindNull(const ParamName: WideString);
426begin
427 BindNull(ParamIndexByName(ParamName));
428end;
429
430procedure TSQLite3Statement.BindText(const ParamName, Value: WideString);
431begin
432 BindText(ParamIndexByName(ParamName), Value);
433end;
434
435procedure TSQLite3Statement.BindZeroBlob(const ParamName: WideString;
436 const Size: Integer);
437begin
438 BindZeroBlob(ParamIndexByName(ParamName), Size);
439end;
440
441{ TSQLite3BlobHandler }
442
443function TSQLite3BlobHandler.Bytes: Integer;
444begin
445 Result := sqlite3_blob_bytes(FHandle);
446end;
447
448constructor TSQLite3BlobHandler.Create(OwnerDatabase: TSQLite3Database; const Table,
449 Column: WideString; const RowID: Int64; const WriteAccess: Boolean);
450begin
451 FOwnerDatabase := OwnerDatabase;
452 FOwnerDatabase.CheckHandle;
453 FOwnerDatabase.Check(
454 sqlite3_blob_open(FOwnerDatabase.FHandle, 'main', PAnsiChar(StrToUTF8(Table)),
455 PAnsiChar(StrToUTF8(Column)), RowID, Ord(WriteAccess), FHandle)
456 );
457 FOwnerDatabase.FBlobHandlerList.Add(Self);
458end;
459
460destructor TSQLite3BlobHandler.Destroy;
461begin
462 FOwnerDatabase.FBlobHandlerList.Remove(Self);
463 sqlite3_blob_close(FHandle);
464 inherited;
465end;
466
467procedure TSQLite3BlobHandler.Read(Buffer: Pointer; const Size,
468 Offset: Integer);
469begin
470 FOwnerDatabase.Check(sqlite3_blob_read(FHandle, Buffer, Size, Offset));
471end;
472
473procedure TSQLite3BlobHandler.Write(Buffer: Pointer; const Size,
474 Offset: Integer);
475begin
476 FOwnerDatabase.Check(sqlite3_blob_write(FHandle, Buffer, Size, Offset));
477end;
478
479end.
Note: See TracBrowser for help on using the repository browser.