@@ -1,4 +1,4 @@
1−module main
1+module sqlite3
2import sqlexpr
2import sqlexpr
@@ -6,7 +6,17 @@ import sqlexpr
6%link "sqlite3api.o"
6%link "sqlite3api.o"
7%include "sqlite3api.h"
7%include "sqlite3api.h"
9+-----------------------------------------------------------------------------
12+-- Copyright : (c) The University of St Andrews, 2012
14+-- Library built on top of FFI supporting basic SQLite C/C++ Interface
17+-----------------------------------------------------------------------------
19+-- | The types supported by Idris returned by the database functions.
11data DBVal = DBInt Int
21data DBVal = DBInt Int
12 | DBText String
22 | DBText String
@@ -55,15 +65,24 @@ runDB (MkDB f) = do f' <- f
55 Right v => return v
65 Right v => return v
56 Left str => ioError str
66 Left str => ioError str
68+-----------------------------------------------------------------------------
69+-- | Opens an SQLite database file as specified by the String name argument.
70+-----------------------------------------------------------------------------
59open_db : String -> DB DBPointer
72open_db : String -> DB DBPointer
60open_db name = do x <- liftIO(mkForeign (FFun "sqlite3_open_idr" [FString] FPtr) name)
73open_db name = do x <- liftIO(mkForeign (FFun "sqlite3_open_idr" [FString] FPtr) name)
61 return (MkDBPointer x)
74 return (MkDBPointer x)
76+-----------------------------------------------------------------------------
77+-- | Destructor for the DBPointer.
78+-----------------------------------------------------------------------------
63close_db : DBPointer -> DB Int
80close_db : DBPointer -> DB Int
64close_db (MkDBPointer pointer) = liftIO (mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer)
81close_db (MkDBPointer pointer) = liftIO (mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer)
66−
83+-----------------------------------------------------------------------------
84+-- | Wrapper around prepare, step and finalize.
85+-----------------------------------------------------------------------------
68exec_db : DBPointer -> String -> DB Int
87exec_db : DBPointer -> String -> DB Int
69exec_db (MkDBPointer pointer) stmt = do
88exec_db (MkDBPointer pointer) stmt = do
@@ -72,11 +91,32 @@ exec_db (MkDBPointer pointer) stmt = do
72 then fail "Could not execute."
91 then fail "Could not execute."
73 else return x
92 else return x
94+-----------------------------------------------------------------------------
95+-- | Executes a prepared query. Use of this version is recommended.
96+-----------------------------------------------------------------------------
98+exec_db_v2 : StmtPtr -> DB Int
99+exec_db_v2 (MkStmtPtr pointer) = do
100+ x <- liftIO (mkForeign (FFun "exec_db" [FPtr] FInt) pointer)
102+ then fail "No data returned."
105+-----------------------------------------------------------------------------
106+-- | Returns the error stored in the buffer by exec_db function.
107+-- This function can only be used with exec_db and get_table.
108+-- Only these functions store any occured error in the buffer array.
109+-----------------------------------------------------------------------------
77get_error : DBPointer -> IO String
111get_error : DBPointer -> IO String
78get_error (MkDBPointer pointer) =mkForeign (FFun "sqlite3_get_error" [FPtr] FString)pointer
112get_error (MkDBPointer pointer) =mkForeign (FFun "sqlite3_get_error" [FPtr] FString)pointer
115+-----------------------------------------------------------------------------
116+-- | Compiles the query inot a byte-code program in order to execute it.
117+-- Returns a pointer to a Statement pointer on a successful call.
118+-- Returns a null pointer on a failure.
119+-----------------------------------------------------------------------------
81prepare_db : DBPointer -> String -> DB StmtPtr
121prepare_db : DBPointer -> String -> DB StmtPtr
82prepare_db (MkDBPointer pointer) cmd = do
122prepare_db (MkDBPointer pointer) cmd = do
@@ -86,12 +126,11 @@ prepare_db (MkDBPointer pointer) cmd = do
86 then fail "Error occured while preparing"
126 then fail "Error occured while preparing"
87 else return (MkStmtPtr result)
127 else return (MkStmtPtr result)
89−exec_db_v2 : StmtPtr -> DB Int
129+-----------------------------------------------------------------------------
90−exec_db_v2 (MkStmtPtr pointer) = do
130+-- | Returns the error stored in the buffer by exec_db function.
91− x <- liftIO (mkForeign (FFun "exec_db" [FPtr] FInt) pointer)
131+-- This function can only be used with exec_db and get_table.
92− if (x == 21)
132+-- Only these functions store any occured error in the buffer array.
93− then fail "No data returned."
133+-----------------------------------------------------------------------------
96step_db : StmtPtr -> DB Int
135step_db : StmtPtr -> DB Int
97step_db (MkStmtPtr pointer)= do
136step_db (MkStmtPtr pointer)= do
@@ -100,6 +139,10 @@ step_db (MkStmtPtr pointer)= do
100 then fail "SQLITE_DONE"
139 then fail "SQLITE_DONE"
101 else return x
140 else return x
142+-----------------------------------------------------------------------------
143+-- | Deletes a prepared statement. This function must be called after
145+-----------------------------------------------------------------------------
104finalize_db : StmtPtr -> DB Int
147finalize_db : StmtPtr -> DB Int
105finalize_db (MkStmtPtr pointer) = do
148finalize_db (MkStmtPtr pointer) = do
@@ -108,6 +151,10 @@ finalize_db (MkStmtPtr pointer) = do
108 then fail "Could not finalize"
151 then fail "Could not finalize"
109 else return x
152 else return x
154+-----------------------------------------------------------------------------
155+-- | Resets a prepared statement pointer back to its initial state.
156+-----------------------------------------------------------------------------
111reset_db : StmtPtr -> DB Int
158reset_db : StmtPtr -> DB Int
112reset_db (MkStmtPtr pointer) = do
159reset_db (MkStmtPtr pointer) = do
113 x <- liftIO(mkForeign (FFun "sqlite3_reset_idr" [FPtr] FInt)pointer)
160 x <- liftIO(mkForeign (FFun "sqlite3_reset_idr" [FPtr] FInt)pointer)
@@ -115,6 +162,10 @@ reset_db (MkStmtPtr pointer) = do
115 then fail "Could not reset"
162 then fail "Could not reset"
116 else return x
163 else return x
165+-----------------------------------------------------------------------------
166+-- | These routines obtain column information.
167+-----------------------------------------------------------------------------
118column_count : DBPointer -> IO (Either String Int)
169column_count : DBPointer -> IO (Either String Int)
119column_count (MkDBPointer pointer) = do
170column_count (MkDBPointer pointer) = do
120 x <- mkForeign (FFun "sqlite3_column_count_idr" [FPtr] FInt)pointer
171 x <- mkForeign (FFun "sqlite3_column_count_idr" [FPtr] FInt)pointer
@@ -144,6 +195,9 @@ column_text (MkDBPointer pointer) iCol =mkForeign (FFun "sqlite3_column_text_idr
144column_Int : DBPointer -> Int -> IO Int
195column_Int : DBPointer -> Int -> IO Int
145column_Int (MkDBPointer pointer) iCol =mkForeign (FFun "sqlite3_column_int_idr" [FPtr, FInt] FInt)pointer iCol
196column_Int (MkDBPointer pointer) iCol =mkForeign (FFun "sqlite3_column_int_idr" [FPtr, FInt] FInt)pointer iCol
198+-----------------------------------------------------------------------------
199+-- | These routines support some of SQLite backup functions.
200+-----------------------------------------------------------------------------
148backup_init : DBPointer -> String -> DBPointer -> String -> IO DBPointer
202backup_init : DBPointer -> String -> DBPointer -> String -> IO DBPointer
149backup_init (MkDBPointer des_pointer) destName (MkDBPointer src_pointer) srcName = do x <- mkForeign (FFun "sqlite3_backup_init_idr" [FPtr,FString, FPtr, FString] FPtr)des_pointer destName src_pointer srcName
203backup_init (MkDBPointer des_pointer) destName (MkDBPointer src_pointer) srcName = do x <- mkForeign (FFun "sqlite3_backup_init_idr" [FPtr,FString, FPtr, FString] FPtr)des_pointer destName src_pointer srcName
@@ -159,6 +213,12 @@ backup_remaining : DBPointer -> IO Int
159backup_remaining (MkDBPointer pointer) =mkForeign (FFun "sqlite3_backup_remaining_idr" [FPtr] FInt)pointer
213backup_remaining (MkDBPointer pointer) =mkForeign (FFun "sqlite3_backup_remaining_idr" [FPtr] FInt)pointer
216+-----------------------------------------------------------------------------
217+-- | Use of this interface is not recommended.
218+-- This function returns a result table. The functions num_row and num_col
219+-- are used to obtain the number of rows and columns.
220+-- These functions can be used to print the resulting table.
221+-----------------------------------------------------------------------------
163get_table : DBPointer -> String -> DB TBPointer
223get_table : DBPointer -> String -> DB TBPointer
164get_table (MkDBPointer pointer) name = do
224get_table (MkDBPointer pointer) name = do
@@ -173,6 +233,15 @@ get_table (MkDBPointer pointer) name = do
236+free_table : TBPointer -> IO ()
237+free_table (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_free_table_idr" [FPtr] FUnit)pointer
240+-----------------------------------------------------------------------------
241+-- | This version of these function obtain the row and column number
242+-- from the Table struct. These functions are only used with get_table.
243+-----------------------------------------------------------------------------
176num_row : TBPointer -> IO Int
245num_row : TBPointer -> IO Int
177num_row (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row" [FPtr] FInt)pointer
246num_row (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row" [FPtr] FInt)pointer
178 return (x)
247 return (x)
@@ -181,30 +250,10 @@ num_col : TBPointer -> IO Int
181num_col (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col" [FPtr] FInt)pointer
250num_col (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col" [FPtr] FInt)pointer
182 return (x)
251 return (x)
184−
253+-----------------------------------------------------------------------------
185−get_data : DBPointer -> String -> Int -> Int -> IO DBVal
254+-- | This version of these function obtain the row and column number
186−get_data (MkDBPointer pointer) tbl_name row col = do
255+-- from the Database struct.
187− ty <- get_data_type pointer tbl_name row col
256+-----------------------------------------------------------------------------
190− get_data_type : Ptr -> String -> Int -> Int -> IO Int
191− get_data_type pointer tbl_name row col =mkForeign (FFun "sqlite3_get_data_type" [FPtr, FString, FInt, FInt] FInt)pointer tbl_name row col
193− get_data_val_int : Ptr -> String -> Int -> Int -> IO Int
194− get_data_val_int pointer tbl_name row col =mkForeign (FFun "sqlite3_get_val_int" [FPtr, FString, FInt, FInt] FInt)pointer tbl_name row col
196− get_data_val_text : Ptr -> String -> Int -> Int -> IO String
197− get_data_val_text pointer tbl_name row col =mkForeign (FFun "sqlite3_get_val_text" [FPtr, FString, FInt, FInt] FString)pointer tbl_name row col
199− get_data_val_float : Ptr -> String -> Int -> Int -> IO Float
200− get_data_val_float pointer tbl_name row col =mkForeign (FFun "sqlite3_get_float" [FPtr, FString, FInt, FInt] FFloat)pointer tbl_name row col
203− helper : Int -> IO DBVal
204− helper 1 = do i <- get_data_val_int pointer tbl_name row col; return (DBInt i)
205− helper 2 = do i <- get_data_val_float pointer tbl_name row col; return (DBFloat i)
206− helper 3 = do i <- get_data_val_text pointer tbl_name row col; return (DBText i)
207− helper _ = return (DBNull)
209num_row_v2 : DBPointer -> IO Int
258num_row_v2 : DBPointer -> IO Int
210num_row_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row_v2" [FPtr] FInt)pointer
259num_row_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row_v2" [FPtr] FInt)pointer
@@ -214,14 +263,19 @@ num_col_v2 : DBPointer -> IO Int
214num_col_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col_v2" [FPtr] FInt)pointer
263num_col_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col_v2" [FPtr] FInt)pointer
215 return (x)
264 return (x)
266+-----------------------------------------------------------------------------
267+-- | This function prints the result of a query by checking the type
268+-- of each value returned, it then calls the appropriate function.
269+-- Ther result is one of the DBVal variants.
270+-----------------------------------------------------------------------------
218−get_data_v2 : DBPointer -> Int -> Int -> IO DBVal
272+get_data : DBPointer -> Int -> Int -> IO DBVal
219−get_data_v2 (MkDBPointer pointer) row col = do
273+get_data (MkDBPointer pointer) row col = do
220− ty <- get_data_type_v2 pointer row col
274+ ty <- get_data_type pointer row col
221 helper ty
275 helper ty
223− get_data_type_v2 : Ptr ->Int -> Int -> IO Int
277+ get_data_type : Ptr ->Int -> Int -> IO Int
224− get_data_type_v2 pointer row col =mkForeign (FFun "sqlite3_get_data_type_v2" [FPtr, FInt, FInt] FInt)pointer row col
278+ get_data_type pointer row col =mkForeign (FFun "sqlite3_get_data_type_v2" [FPtr, FInt, FInt] FInt)pointer row col
226 get_data_val_int : Ptr -> Int -> IO Int
280 get_data_val_int : Ptr -> Int -> IO Int
227 get_data_val_int pointer col =mkForeign (FFun "sqlite3_get_val_int_v2" [FPtr,FInt] FInt)pointer col
281 get_data_val_int pointer col =mkForeign (FFun "sqlite3_get_val_int_v2" [FPtr,FInt] FInt)pointer col
@@ -240,43 +294,49 @@ get_data_v2 (MkDBPointer pointer) row col = do
240 helper 3 = do i <- get_data_val_text pointer col; return (DBText i)
294 helper 3 = do i <- get_data_val_text pointer col; return (DBText i)
241 helper _ =return (DBNull)
295 helper _ =return (DBNull)
243−
297+-----------------------------------------------------------------------------
298+-- | This function makes use of get_data to get all the result.
299+-----------------------------------------------------------------------------
244−toList_v2 : DBPointer -> DB Table
301+toList : DBPointer -> DB Table
245−toList_v2 db = do
302+toList db = do
246− nbR <- liftIO (num_row_v2 db)
303+ nbR <- liftIO (num_row_v2 db)
247− nmC <- liftIO (num_col_v2 db)
304+ nmC <- liftIO (num_col_v2 db)
248− res <- forM [0..(nbR-1)] (\ i =>
305+ res <- forM [0..(nbR-1)] (\ i =>
249− forM [0..(nmC-1)] (\ j =>
306+ forM [0..(nmC-1)] (\ j =>
250− liftIO(get_data_v2 db i j)
307+ liftIO(get_data db i j)
254− return res
311+ return res
257strcat : String -> String-> String
314strcat : String -> String-> String
258strcat str1 str2 = (str1 ++ str2)
315strcat str1 str2 = (str1 ++ str2)
260−free_table : TBPointer -> IO ()
317+-----------------------------------------------------------------------------
261−free_table (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_free_table_idr" [FPtr] FUnit)pointer
318+-- | This version of toList retunrs result from get_table
262− return ()
319+-----------------------------------------------------------------------------
265−toList : String -> String -> DBPointer -> DB Table
321+--toList_v2 : String -> String -> DBPointer -> DB Table
266−toList name stmt x = do
322+--toList_v2 name stmt x = do
267− ptr <- (get_table x (stmt))
323+-- ptr <- (get_table x (stmt))
268− nbR <- liftIO (num_row ptr)
324+-- nbR <- liftIO (num_row ptr)
269− nmC <- liftIO (num_col ptr)
325+-- nmC <- liftIO (num_col ptr)
270− res <- forM [0..(nbR-1)] (\ i =>
326+-- res <- forM [0..(nbR-1)] (\ i =>
271− forM [0..(nmC-1)] (\ j =>
327+-- forM [0..(nmC-1)] (\ j =>
272− liftIO(get_data x name i j)
328+-- liftIO(get_data x name i j)
276− liftIO (free_table ptr)
332+-- liftIO (free_table ptr)
277− return res
333+-- return res
336+-----------------------------------------------------------------------------
337+-- | These routines support binding the types supported by Idris.
338+-----------------------------------------------------------------------------
280bind_int : StmtPtr -> Int -> Int -> DB StmtPtr
340bind_int : StmtPtr -> Int -> Int -> DB StmtPtr
281bind_int (MkStmtPtr pointer) indexval val = do
341bind_int (MkStmtPtr pointer) indexval val = do
282 x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FPtr)pointer indexval val)
342 x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FPtr)pointer indexval val)
@@ -302,12 +362,17 @@ bind_text (MkStmtPtr pointer) text indexval lengthval = do
302 then fail "Could not bind text."
362 then fail "Could not bind text."
303 else return (MkStmtPtr x)
363 else return (MkStmtPtr x)
305−--bind_null : StmtPtr -> Int -> DB StmtPtr
365+bind_null : StmtPtr -> Int -> DB StmtPtr
306−--bind_null (MkStmtPtr pointer) indexval =do
366+bind_null (MkStmtPtr pointer) indexval = do
307−-- x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FInt)pointer indexval)
367+ x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FPtr)pointer indexval)
368+ flag <- liftIO(nullPtr x)
308−-- if (x /= 0)
369+ if flag
309−-- then fail "Could not bind null."
370+ then fail "Could not bind null."
310−-- else return x
371+ else return (MkStmtPtr x)
373+-----------------------------------------------------------------------------
375+-----------------------------------------------------------------------------
312strlen : String -> DB Int
377strlen : String -> DB Int
313strlen str = liftIO(mkForeign (FFun "strLength" [FString] FInt) str)
378strlen str = liftIO(mkForeign (FFun "strLength" [FString] FInt) str)
@@ -318,29 +383,9 @@ instance Show DBVal where
318 show (DBFloat i) = "Float val: " ++ show i ++ "\n"
383 show (DBFloat i) = "Float val: " ++ show i ++ "\n"
319 show (DBNull ) = "NULL"
384 show (DBNull ) = "NULL"
321−print_data_v2 : DBVal -> String
386+-----------------------------------------------------------------------------
322−print_data_v2 = show
387+-- | Multi bind a list of values.
323−
388+-----------------------------------------------------------------------------
325−test = do db <- open_db "somedb.db"
326− stmt <- (prepare_db db "insert into tbl1 values (?,?);")
328− bind_text stmt "testing" 2 4
336−test3 = do db <- open_db "students.db"
337− stmt <- (prepare_db db "SELECT Student.Name FROM Student, Module, Enrollment WHERE Module.Credits = 30 AND Student.School_student = Enrollment.School_Student AND Student.School = Enrollment.School AND Enrollment.Code = Module.Code")
345bindMulti : StmtPtr-> List (Maybe (Int, Value)) -> DB StmtPtr
390bindMulti : StmtPtr-> List (Maybe (Int, Value)) -> DB StmtPtr
346bindMulti pointer [] = return pointer
391bindMulti pointer [] = return pointer
@@ -356,81 +401,3 @@ bindMulti pointer ((Just (indexs, val))::vs) = case val of
357 (VFloat floatval) => do x <- bind_float pointer indexs floatval
402 (VFloat floatval) => do x <- bind_float pointer indexs floatval
358 bindMulti(x) vs
403 bindMulti(x) vs
360−testexpr = do db <- open_db "somedb.db"
361− let sql = (evalSQL [] ((SELECT ALL)(TBL "tbl1") (OR (AND (MkCond (Equals (VCol "data")(VStr "data0"))) (MkCond (Equals (VCol "num")(VInt 1))) ) (MkCond (Equals (VCol "num")(VInt 2))))))
363− let list = (snd sql)
365− stmt <- (prepare_db db x)
375−testupdate = do db <- open_db "somedb.db"
376− let sql = (evalSQL [] (UPDATE (TBL "tbl1") (WHERE (SET (MkCond (Equals(VCol "data") (VStr "data0"))) ) (MkCond (Equals (VCol "num") (VInt 2))) ) ))
378− let list = (snd sql)
380− stmt <- (prepare_db db x)
388−testInsert = do db <- open_db "somedb.db"
389− let sql = (evalSQL [] (INSERT (TBL "tbl1") [(VInt 2),(VStr "histring2")]))
391− let list = (snd sql)
393− stmt <- (prepare_db db x)
401−testNull = do db <- open_db "somedb.db"
402− let sql = (evalSQL [] ((SELECT ALL)(TBL "tbl1") (MkCond (MkNULL (VCol "data")))))
404− let list = (snd sql)
406− stmt <- (prepare_db db x)
415−testInsertWithCond : DB()
416−testInsertWithCond = do db <- open_db "somedb.db"
417− let sql = (evalSQL [] (INSERTC (TBL "tbl1") [(VCol "data"),(VCol "num")] [(VInt 201),(VStr "newinserted")]))
419− let list = (snd sql)
421− stmt <- (prepare_db db x)
430−main = do --x <- runDB (test3)
431− y <- runDB (testInsertWithCond)