1 ------------------------------------------------------------------------------
4 -- Copyright (C) 2006-2008 --
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
32 Module
: constant Logs
.Module_Name
:= "DB_SQLITE";
34 Unique_Handle
: sqlite3_h
.Handle_Access
:= null;
35 -- Unique handle to use when we want to use in memory connection
37 procedure Check_Result
40 Error_Msg
: in Strings
.chars_ptr
:= Strings
.Null_Ptr
);
41 -- Check result, raises and exception if it is an error code
43 procedure Step_Internal
(Iter
: in out Iterator
);
44 -- Advance to the next row and set Iter.More
46 -- Thread safe access to the SQLite database
48 protected SQLite_Safe
is
51 (DB
: in out Handle
; Result
: out int
);
57 -- Execute an SQL statement
58 -- Raise DB_Error is case of failure
66 function Prepare_Select
68 Iter
: in Standard
.DB
.Iterator
'Class;
69 SQL
: in String) return Standard
.DB
.Iterator
'Class;
70 -- Prepare a select statement
74 -----------------------
75 -- Begin_Transaction --
76 -----------------------
78 overriding
procedure Begin_Transaction
(DB
: in Handle
) is
80 Logs
.Write
(Module
, "begin");
81 Execute
(DB
, "begin");
82 end Begin_Transaction
;
88 procedure Check_Result
91 Error_Msg
: in Strings
.chars_ptr
:= Strings
.Null_Ptr
)
93 use type sqlite3_h
.sqlite_result
;
95 DB_Result
: sqlite3_h
.sqlite_result
;
96 for DB_Result
'Address use Result
'Address;
98 function Error_Message
return String;
99 -- Returns and free Error_Msg content if not null
105 function Error_Message
return String is
106 use type Strings
.chars_ptr
;
108 if Error_Msg
= Strings
.Null_Ptr
then
112 V
: constant String := Strings
.Value
(Error_Msg
);
114 sqlite3_h
.sqlite3_free
(Error_Msg
'Address);
121 if not DB_Result
'Valid then
125 Content
=> "SQLite3 has return an unknown result in !" & Routine
);
126 raise DB_Error
with "SQlite: Error (Unknown Error) in " & Routine
;
129 if DB_Result
/= sqlite3_h
.SQLITE_OK
then
134 ("Return_Value", sqlite3_h
.sqlite_result
'Image (DB_Result
))
135 & ", " & Logs
.NV
("routine", Routine
)
136 & ", " & Logs
.NV
("message", Error_Message
));
138 with "SQLite: Error "
139 & sqlite3_h
.sqlite_result
'Image (DB_Result
) & " in " & Routine
;
147 overriding
procedure Close
(DB
: in out Handle
) is
150 Logs
.Write
(Module
, "close");
151 SQLite_Safe
.Close
(DB
, Result
);
152 Check_Result
("close", Result
);
159 overriding
procedure Commit
(DB
: in Handle
) is
161 Logs
.Write
(Module
, "commit");
162 Execute
(DB
, "commit");
169 overriding
procedure Connect
172 User
: in String := "";
173 Password
: in String := "")
175 pragma Unreferenced
(User
, Password
);
176 use type sqlite3_h
.Handle_Access
;
180 Logs
.Write
(Module
, "connect " & Logs
.NV
("Name", Name
));
181 SQLite_Safe
.Open
(DB
, Name
, Result
);
182 Check_Result
("connect", Result
);
189 overriding
procedure End_Select
(Iter
: in out Iterator
) is
191 Logs
.Write
(Module
, "end_select");
192 Check_Result
("end_select_reset",
193 sqlite3_h
.sqlite3_reset
(Iter
.S
.all'Address));
194 Check_Result
("end_select",
195 sqlite3_h
.sqlite3_finalize
(Iter
.S
.all'Address));
202 overriding
procedure Execute
(DB
: in Handle
; SQL
: in String) is
204 Logs
.Write
(Module
, "execute : " & Logs
.NV
("SQL", SQL
));
205 SQLite_Safe
.Exec
(DB
, SQL
);
208 raise DB_Error
with "DB_Error on Execute " & SQL
;
215 overriding
procedure Get_Line
216 (Iter
: in out Iterator
;
217 Result
: out String_Vectors
.Vector
)
221 for K
in 0 .. Iter
.Col
- 1 loop
223 Text
: constant Strings
.chars_ptr
:=
224 sqlite3_h
.sqlite3_column_text
(Iter
.S
.all'Address, K
);
225 use type Strings
.chars_ptr
;
227 if Text
/= Strings
.Null_Ptr
then
228 String_Vectors
.Append
230 Interfaces
.C
.Strings
.Value
(Text
));
232 String_Vectors
.Append
(Result
, "");
237 Step_Internal
(Iter
);
240 -----------------------
241 -- Last_Insert_Rowid --
242 -----------------------
244 overriding
function Last_Insert_Rowid
(DB
: in Handle
) return String is
245 Rowid
: constant String :=
246 sqlite3_h
.sqlite_int64
'Image
247 (sqlite3_h
.sqlite3_last_insert_rowid
(DB
.H
.all'Address));
249 -- Skip first whitespace returned by 'Image
250 return Rowid
(Rowid
'First + 1 .. Rowid
'Last);
251 end Last_Insert_Rowid
;
257 overriding
function More
(Iter
: in Iterator
) return Boolean is
266 overriding
procedure Prepare_Select
268 Iter
: in out Standard
.DB
.Iterator
'Class;
272 Iter
:= SQLite_Safe
.Prepare_Select
(DB
, Iter
, SQL
);
279 overriding
procedure Rollback
(DB
: in Handle
) is
281 Logs
.Write
(Module
, "rollback");
282 Execute
(DB
, "rollback");
289 protected body SQLite_Safe
is
296 (DB
: in out Handle
; Result
: out int
) is
298 if DB
.Ref_Count
/= 0 then
299 DB
.Ref_Count
:= DB
.Ref_Count
- 1;
300 Result
:= 0; -- SQLite3_OK;
302 Result
:= sqlite3_h
.sqlite3_close
(DB
.H
.all'Address);
311 (DB
: in Handle
; SQL
: in String) is
312 SQL_Stat
: Strings
.chars_ptr
:= Strings
.New_String
(SQL
);
314 Error_Msg
: Strings
.chars_ptr
;
316 Result
:= sqlite3_h
.sqlite3_exec_no_callback
317 (DB
.H
.all'Address, SQL_Stat
, System
.Null_Address
,
318 System
.Null_Address
, Error_Msg
'Address);
320 Check_Result
("Execute", Result
, Error_Msg
);
323 Strings
.Free
(SQL_Stat
);
336 -- Open a database connection
343 SQL_Name
: Strings
.chars_ptr
:= Strings
.New_String
(Name
);
345 Result
:= sqlite3_h
.sqlite3_open
(SQL_Name
, DB
.H
'Address);
346 Strings
.Free
(SQL_Name
);
349 use type sqlite3_h
.Handle_Access
;
351 if Name
= In_Memory_Database
then
352 if Unique_Handle
= null then
353 -- Open only one database connection !
355 Unique_Handle
:= DB
.H
;
357 elsif DB
.H
= null then
358 -- Get the open database connection
359 DB
.H
:= Unique_Handle
;
360 Result
:= 0; -- SQLite_OK
362 -- Increment the reference counter
363 DB
.Ref_Count
:= DB
.Ref_Count
+ 1;
375 function Prepare_Select
377 Iter
: in Standard
.DB
.Iterator
'Class;
378 SQL
: in String) return Standard
.DB
.Iterator
'Class
380 Select_Iter
: Standard
.DB
.Iterator
'Class := Iter
;
381 zSql
: Strings
.chars_ptr
:= Strings
.New_String
(SQL
);
384 pragma Assert
(Select_Iter
in Iterator
);
387 (Module
, "prepare select : " & Logs
.NV
("SQL", SQL
));
389 Iterator
(Select_Iter
).H
:= DB
;
390 Iterator
(Select_Iter
).More
:= False;
392 Select_Res
:= sqlite3_h
.sqlite3_prepare_v2
393 (db
=> DB
.H
.all'Address,
395 nByte
=> SQL
'Length + 1,
396 ppStmt
=> Iterator
(Select_Iter
).S
'Address,
397 pzTail
=> System
.Null_Address
);
399 Check_Result
("prepare_select", Select_Res
);
401 Column_Count
: declare
402 use type sqlite3_h
.sqlite_result
;
404 DB_Result
: sqlite3_h
.sqlite_result
;
405 for DB_Result
'Address use Select_Res
'Address;
407 if DB_Result
= sqlite3_h
.SQLITE_DONE
then
408 Iterator
(Select_Iter
).Col
:= 0;
410 Iterator
(Select_Iter
).Col
:=
411 sqlite3_h
.Sqlite3_Column_Count
412 (Iterator
(Select_Iter
).S
.all'Address);
413 Step_Internal
(Iterator
(Select_Iter
));
426 procedure Step_Internal
(Iter
: in out Iterator
) is
429 R
:= sqlite3_h
.sqlite3_step
(Iter
.S
.all'Address);
431 Analyse_Result
: declare
432 Result
: sqlite3_h
.sqlite_result
;
433 for Result
'Address use R
'Address;
435 use type sqlite3_h
.sqlite_result
;
437 if not Result
'Valid then
438 raise DB_Error
with "Wrong result from sqlite3_step ?";
440 if Result
= sqlite3_h
.SQLITE_DONE
then
442 elsif Result
= sqlite3_h
.SQLITE_ROW
then
445 Check_Result
("step_internal", R
);
453 -- sqlite3_initialize is present only in very recent SQLite3
454 -- versions and it is safe to disable the call for now
455 -- Check_Result ("initialize", sqlite3_h.sqlite3_initialize);