1 ------------------------------------------------------------------------------
4 -- Copyright (C) 2006-2010 --
5 -- Pascal Obry - Olivier Ramonat --
7 -- This library is free software; you can redistribute it and/or modify --
8 -- it under the terms of the GNU General Public License as published by --
9 -- the Free Software Foundation; either version 2 of the License, or (at --
10 -- your option) any later version. --
12 -- This library is distributed in the hope that it will be useful, but --
13 -- WITHOUT ANY WARRANTY; without even the implied warranty of --
14 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
15 -- General Public License for more details. --
17 -- You should have received a copy of the GNU General Public License --
18 -- along with this library; if not, write to the Free Software Foundation, --
19 -- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --
20 ------------------------------------------------------------------------------
22 with Interfaces
.C
.Strings
;
27 package body DB
.SQLite
is
31 use type sqlite3_h
.Handle_Access
;
33 Module
: constant Logs
.Module_Name
:= "DB_SQLITE";
35 Unique_Handle
: sqlite3_h
.Handle_Access
:= null;
36 -- Unique handle to use when we want to use in memory connection
38 procedure Check_Result
41 Error_Msg
: in Strings
.chars_ptr
:= Strings
.Null_Ptr
);
42 -- Check result, raises and exception if it is an error code
44 procedure Step_Internal
(Iter
: in out Iterator
);
45 -- Advance to the next row and set Iter.More
47 -- Thread safe access to the SQLite database
49 protected SQLite_Safe
is
52 (DB
: in out Handle
; Result
: out int
);
54 pragma Precondition
(DB
.H
/= null);
59 -- Execute an SQL statement
60 -- Raise DB_Error is case of failure
61 pragma Precondition
(SQL
/= "");
62 pragma Precondition
(DB
.H
/= null);
63 pragma Postcondition
(DB
.H
/= null);
70 pragma Precondition
(Name
/= "");
72 function Prepare_Select
74 Iter
: in Standard
.DB
.Iterator
'Class;
75 SQL
: in String) return Standard
.DB
.Iterator
'Class;
76 -- Prepare a select statement
77 pragma Precondition
(SQL
/= "");
78 pragma Precondition
(DB
.H
/= null);
79 pragma Postcondition
(DB
.H
/= null);
83 -----------------------
84 -- Begin_Transaction --
85 -----------------------
87 overriding
procedure Begin_Transaction
(DB
: in Handle
) is
89 Logs
.Write
(Module
, "begin");
90 Execute
(DB
, "begin");
91 end Begin_Transaction
;
97 procedure Check_Result
100 Error_Msg
: in Strings
.chars_ptr
:= Strings
.Null_Ptr
)
102 use type sqlite3_h
.sqlite_result
;
104 DB_Result
: sqlite3_h
.sqlite_result
;
105 for DB_Result
'Address use Result
'Address;
107 function Error_Message
return String;
108 -- Returns and free Error_Msg content if not null
114 function Error_Message
return String is
115 use type Strings
.chars_ptr
;
117 if Error_Msg
= Strings
.Null_Ptr
then
122 V
: constant String := Strings
.Value
(Error_Msg
);
124 sqlite3_h
.sqlite3_free
(Error_Msg
'Address);
131 if not DB_Result
'Valid then
135 Content
=> "SQLite3 has return an unknown result in !" & Routine
);
136 raise DB_Error
with "SQlite: Error (Unknown Error) in " & Routine
;
139 if DB_Result
/= sqlite3_h
.SQLITE_OK
then
144 ("Return_Value", sqlite3_h
.sqlite_result
'Image (DB_Result
))
145 & ", " & Logs
.NV
("routine", Routine
)
146 & ", " & Logs
.NV
("message", Error_Message
));
148 with "SQLite: Error "
149 & sqlite3_h
.sqlite_result
'Image (DB_Result
) & " in " & Routine
;
157 overriding
procedure Close
(DB
: in out Handle
) is
160 Logs
.Write
(Module
, "close");
161 SQLite_Safe
.Close
(DB
, Result
);
162 Check_Result
("close", Result
);
169 overriding
procedure Commit
(DB
: in Handle
) is
171 Logs
.Write
(Module
, "commit");
172 Execute
(DB
, "commit");
179 overriding
procedure Connect
182 User
: in String := "";
183 Password
: in String := "")
185 pragma Unreferenced
(User
, Password
);
189 Logs
.Write
(Module
, "connect " & Logs
.NV
("Name", Name
));
190 SQLite_Safe
.Open
(DB
, Name
, Result
);
191 Check_Result
("connect", Result
);
198 overriding
procedure End_Select
(Iter
: in out Iterator
) is
200 Logs
.Write
(Module
, "end_select");
201 Check_Result
("end_select_reset",
202 sqlite3_h
.sqlite3_reset
(Iter
.S
.all'Address));
203 Check_Result
("end_select",
204 sqlite3_h
.sqlite3_finalize
(Iter
.S
.all'Address));
211 overriding
procedure Execute
(DB
: in Handle
; SQL
: in String) is
213 Logs
.Write
(Module
, "execute : " & Logs
.NV
("SQL", SQL
));
214 SQLite_Safe
.Exec
(DB
, SQL
);
217 raise DB_Error
with "DB_Error on Execute " & SQL
;
224 overriding
procedure Get_Line
225 (Iter
: in out Iterator
;
226 Result
: out String_Vectors
.Vector
)
230 for K
in 0 .. Iter
.Col
- 1 loop
232 Text
: constant Strings
.chars_ptr
:=
233 sqlite3_h
.sqlite3_column_text
(Iter
.S
.all'Address, K
);
234 use type Strings
.chars_ptr
;
236 if Text
/= Strings
.Null_Ptr
then
237 String_Vectors
.Append
239 Interfaces
.C
.Strings
.Value
(Text
));
241 String_Vectors
.Append
(Result
, "");
246 Step_Internal
(Iter
);
249 -----------------------
250 -- Last_Insert_Rowid --
251 -----------------------
253 overriding
function Last_Insert_Rowid
(DB
: in Handle
) return String is
254 Rowid
: constant String :=
255 sqlite3_h
.sqlite_int64
'Image
256 (sqlite3_h
.sqlite3_last_insert_rowid
(DB
.H
.all'Address));
258 -- Skip first whitespace returned by 'Image
259 return Rowid
(Rowid
'First + 1 .. Rowid
'Last);
260 end Last_Insert_Rowid
;
266 overriding
function More
(Iter
: in Iterator
) return Boolean is
275 overriding
procedure Prepare_Select
277 Iter
: in out Standard
.DB
.Iterator
'Class;
281 Iter
:= SQLite_Safe
.Prepare_Select
(DB
, Iter
, SQL
);
288 overriding
procedure Rollback
(DB
: in Handle
) is
290 Logs
.Write
(Module
, "rollback");
291 Execute
(DB
, "rollback");
298 protected body SQLite_Safe
is
305 (DB
: in out Handle
; Result
: out int
) is
307 if DB
.Ref_Count
/= 0 then
308 DB
.Ref_Count
:= DB
.Ref_Count
- 1;
309 Result
:= 0; -- SQLite3_OK;
311 Result
:= sqlite3_h
.sqlite3_close
(DB
.H
.all'Address);
320 (DB
: in Handle
; SQL
: in String)
322 SQL_Stat
: Strings
.chars_ptr
:= Strings
.New_String
(SQL
);
324 Error_Msg
: Strings
.chars_ptr
;
326 Result
:= sqlite3_h
.sqlite3_exec_no_callback
327 (DB
.H
.all'Address, SQL_Stat
, System
.Null_Address
,
328 System
.Null_Address
, Error_Msg
'Address);
330 Check_Result
("Execute", Result
, Error_Msg
);
334 Strings
.Free
(SQL_Stat
);
347 -- Open a database connection
354 SQL_Name
: Strings
.chars_ptr
:= Strings
.New_String
(Name
);
356 Result
:= sqlite3_h
.sqlite3_open
(SQL_Name
, DB
.H
'Address);
357 Strings
.Free
(SQL_Name
);
361 if Name
= In_Memory_Database
then
362 if Unique_Handle
= null then
363 -- Open only one database connection !
365 Unique_Handle
:= DB
.H
;
367 elsif DB
.H
= null then
368 -- Get the open database connection
369 DB
.H
:= Unique_Handle
;
370 Result
:= 0; -- SQLite_OK
372 -- Increment the reference counter
373 DB
.Ref_Count
:= DB
.Ref_Count
+ 1;
376 -- Nothing to do. Return OK
377 Result
:= 0; -- SQLite_OK
389 function Prepare_Select
391 Iter
: in Standard
.DB
.Iterator
'Class;
392 SQL
: in String) return Standard
.DB
.Iterator
'Class
394 Select_Iter
: Standard
.DB
.Iterator
'Class := Iter
;
395 zSql
: Strings
.chars_ptr
:= Strings
.New_String
(SQL
);
398 pragma Assert
(Select_Iter
in Iterator
);
401 (Module
, "prepare select : " & Logs
.NV
("SQL", SQL
));
403 Iterator
(Select_Iter
).H
:= DB
;
404 Iterator
(Select_Iter
).More
:= False;
406 Select_Res
:= sqlite3_h
.sqlite3_prepare_v2
407 (db
=> DB
.H
.all'Address,
409 nByte
=> SQL
'Length + 1,
410 ppStmt
=> Iterator
(Select_Iter
).S
'Address,
411 pzTail
=> System
.Null_Address
);
413 Check_Result
("prepare_select", Select_Res
);
415 Column_Count
: declare
416 use type sqlite3_h
.sqlite_result
;
418 DB_Result
: sqlite3_h
.sqlite_result
;
419 for DB_Result
'Address use Select_Res
'Address;
421 if DB_Result
= sqlite3_h
.SQLITE_DONE
then
422 Iterator
(Select_Iter
).Col
:= 0;
424 Iterator
(Select_Iter
).Col
:=
425 sqlite3_h
.sqlite3_column_count
426 (Iterator
(Select_Iter
).S
.all'Address);
427 Step_Internal
(Iterator
(Select_Iter
));
441 procedure Step_Internal
(Iter
: in out Iterator
) is
444 R
:= sqlite3_h
.sqlite3_step
(Iter
.S
.all'Address);
446 Analyse_Result
: declare
447 Result
: sqlite3_h
.sqlite_result
;
448 for Result
'Address use R
'Address;
450 use type sqlite3_h
.sqlite_result
;
452 if not Result
'Valid then
453 raise DB_Error
with "Wrong result from sqlite3_step ?";
455 if Result
= sqlite3_h
.SQLITE_DONE
then
457 elsif Result
= sqlite3_h
.SQLITE_ROW
then
460 Check_Result
("step_internal", R
);
468 -- sqlite3_initialize is present only in very recent SQLite3
469 -- versions and it is safe to disable the call for now
470 -- Check_Result ("initialize", sqlite3_h.sqlite3_initialize);