@@ -1,4 +1,4 @@
1−module main
1+module sqlite3
22import sqlexpr
33
44
@@ -6,64 +6,83 @@ import sqlexpr
66%link "sqlite3api.o"
77%include "sqlite3api.h"
88
9+-----------------------------------------------------------------------------
10+-- |
11+-- Module : sqlite3
12+-- Copyright : (c) The University of St Andrews, 2012
13+--
14+-- Library built on top of FFI supporting basic SQLite C/C++ Interface
15+-- functions.
16+--
17+-----------------------------------------------------------------------------
918
19+-- | The types supported by Idris returned by the database functions.
1020
1121data DBVal = DBInt Int
1222 | DBText String
1323 | DBFloat Float
1424 | DBNull
1525
16−
26+-- Database pointer
1727data DBPointer = MkDBPointer Ptr
18−
28+-- Table pointer
1929data TBPointer = MkTBPointer Ptr
20−
30+-- Statement pointer
2131data StmtPtr = MkStmtPtr Ptr
22−
32+
2333Table : Set
2434Table = List (List DBVal)
2535
26−
36+-- ForMap used in to_list_v1
2737forM : Monad m => List a -> (a -> m b) -> m (List b)
2838forM f xs = mapM xs f
2939
40+-- Neater error handling done using DB
41+data DB a = MkDB (IO (Either String a))
42+
43+instance Monad DB where
44+ (MkDB l) >>= k = MkDB (do c <- l
45+ case c of
46+ Left err => return (Left err)
47+ Right v => case k v of
48+ MkDB k' => k')
49+ return x = MkDB (return (Right x))
50+
51+fail : String -> DB a
52+fail err = MkDB (return (Left err))
3053
31−data DB a = MkDB (IO (Either String a))
32−
33−instance Monad DB where
34− (MkDB l) >>= k = MkDB (do c <- l
35− case c of
36− Left err => return (Left err)
37− Right v => case k v of
38− MkDB k' => k')
39− return x = MkDB (return (Right x))
40−
41−fail : String -> DB a
42−fail err = MkDB (return (Left err))
43−
44−liftIO : IO a -> DB a
45−liftIO f = MkDB (do f' <- f
46− return (Right f'))
47−
48−ioError : String -> IO a
49−ioError err = do putStrLn err
50− return (believe_me ())
51−
52−runDB : DB a -> IO a
53−runDB (MkDB f) = do f' <- f
54− case f' of
55− Right v => return v
54+liftIO : IO a -> DB a
55+liftIO f = MkDB (do f' <- f
56+ return (Right f'))
57+
58+ioError : String -> IO a
59+ioError err = do putStrLn err
60+ return (believe_me ())
61+
62+runDB : DB a -> IO a
63+runDB (MkDB f) = do f' <- f
64+ case f' of
65+ Right v => return v
5666 Left str => ioError str
5767
68+-----------------------------------------------------------------------------
69+-- | Opens an SQLite database file as specified by the String name argument.
70+-----------------------------------------------------------------------------
5871
59−
60−open_db : String -> IO DBPointer
61−open_db name = do x <- mkForeign (FFun "sqlite3_open_idr" [FString] FPtr)name
72+open_db : String -> DB DBPointer
73+open_db name = do x <- liftIO(mkForeign (FFun "sqlite3_open_idr" [FString] FPtr) name)
6274 return (MkDBPointer x)
6375
64−close_db : DBPointer -> IO Int
65−close_db (MkDBPointer pointer) =mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer
76+-----------------------------------------------------------------------------
77+-- | Destructor for the DBPointer.
78+-----------------------------------------------------------------------------
79+
80+close_db : DBPointer -> DB Int
81+close_db (MkDBPointer pointer) = liftIO (mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer)
6682
83+-----------------------------------------------------------------------------
84+-- | Wrapper around prepare, step and finalize.
85+-----------------------------------------------------------------------------
6786
6887exec_db : DBPointer -> String -> DB Int
6988exec_db (MkDBPointer pointer) stmt = do
@@ -72,35 +91,58 @@ exec_db (MkDBPointer pointer) stmt = do
7291 then fail "Could not execute."
7392 else return x
7493
94+-----------------------------------------------------------------------------
95+-- | Executes a prepared query. Use of this version is recommended.
96+-----------------------------------------------------------------------------
7597
98+exec_db_v2 : StmtPtr -> DB Int
99+exec_db_v2 (MkStmtPtr pointer) = do
100+ x <- liftIO (mkForeign (FFun "exec_db" [FPtr] FInt) pointer)
101+ if (x == 21)
102+ then fail "No data returned."
103+ else return x
104+
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+-----------------------------------------------------------------------------
76110
77111get_error : DBPointer -> IO String
78112get_error (MkDBPointer pointer) =mkForeign (FFun "sqlite3_get_error" [FPtr] FString)pointer
79113
114+
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+-----------------------------------------------------------------------------
80120
81121prepare_db : DBPointer -> String -> DB StmtPtr
82122prepare_db (MkDBPointer pointer) cmd = do
83−
84− result <- liftIO (mkForeign (FFun "sqlite3_prepare_idr" [FPtr, FString] FPtr)pointer cmd)
123+ result <- liftIO(mkForeign (FFun "sqlite3_prepare_idr" [FPtr, FString] FPtr)pointer cmd)
85124 flag <- liftIO(nullPtr result)
86125 if flag
87126 then fail "Error occured while preparing"
88127 else return (MkStmtPtr result)
89128
90−exec_db_v2 : StmtPtr -> DB Int
91−exec_db_v2 (MkStmtPtr pointer) = do
92− x <- liftIO(mkForeign (FFun "exec_db" [FPtr] FInt)pointer)
93− if (x == 21)
94− then fail "No data returned."
95− else return x
129+-----------------------------------------------------------------------------
130+-- | Returns the error stored in the buffer by exec_db function.
131+-- This function can only be used with exec_db and get_table.
132+-- Only these functions store any occured error in the buffer array.
133+-----------------------------------------------------------------------------
96134
97135step_db : StmtPtr -> DB Int
98−step_db (MkStmtPtr pointer) = do
136+step_db (MkStmtPtr pointer)= do
99137 x <- liftIO (mkForeign (FFun "sqlite3_step_idr" [FPtr] FInt)pointer)
100138 if ( x == 101)
101139 then fail "SQLITE_DONE"
102140 else return x
103141
142+-----------------------------------------------------------------------------
143+-- | Deletes a prepared statement. This function must be called after
144+-- prepare function.
145+-----------------------------------------------------------------------------
104146
105147finalize_db : StmtPtr -> DB Int
106148finalize_db (MkStmtPtr pointer) = do
@@ -109,6 +151,10 @@ finalize_db (MkStmtPtr pointer) = do
109151 then fail "Could not finalize"
110152 else return x
111153
154+-----------------------------------------------------------------------------
155+-- | Resets a prepared statement pointer back to its initial state.
156+-----------------------------------------------------------------------------
157+
112158reset_db : StmtPtr -> DB Int
113159reset_db (MkStmtPtr pointer) = do
114160 x <- liftIO(mkForeign (FFun "sqlite3_reset_idr" [FPtr] FInt)pointer)
@@ -116,6 +162,10 @@ reset_db (MkStmtPtr pointer) = do
116162 then fail "Could not reset"
117163 else return x
118164
165+-----------------------------------------------------------------------------
166+-- | These routines obtain column information.
167+-----------------------------------------------------------------------------
168+
119169column_count : DBPointer -> IO (Either String Int)
120170column_count (MkDBPointer pointer) = do
121171 x <- mkForeign (FFun "sqlite3_column_count_idr" [FPtr] FInt)pointer
@@ -145,6 +195,9 @@ column_text (MkDBPointer pointer) iCol =mkForeign (FFun "sqlite3_column_text_idr
145195column_Int : DBPointer -> Int -> IO Int
146196column_Int (MkDBPointer pointer) iCol =mkForeign (FFun "sqlite3_column_int_idr" [FPtr, FInt] FInt)pointer iCol
147197
198+-----------------------------------------------------------------------------
199+-- | These routines support some of SQLite backup functions.
200+-----------------------------------------------------------------------------
148201
149202backup_init : DBPointer -> String -> DBPointer -> String -> IO DBPointer
150203backup_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
@@ -160,6 +213,12 @@ backup_remaining : DBPointer -> IO Int
160213backup_remaining (MkDBPointer pointer) =mkForeign (FFun "sqlite3_backup_remaining_idr" [FPtr] FInt)pointer
161214
162215
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+-----------------------------------------------------------------------------
163222
164223get_table : DBPointer -> String -> DB TBPointer
165224get_table (MkDBPointer pointer) name = do
@@ -174,6 +233,15 @@ get_table (MkDBPointer pointer) name = do
174233 return x
175234
176235
236+free_table : TBPointer -> IO ()
237+free_table (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_free_table_idr" [FPtr] FUnit)pointer
238+ return ()
239+
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+-----------------------------------------------------------------------------
244+
177245num_row : TBPointer -> IO Int
178246num_row (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row" [FPtr] FInt)pointer
179247 return (x)
@@ -182,30 +250,10 @@ num_col : TBPointer -> IO Int
182250num_col (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col" [FPtr] FInt)pointer
183251 return (x)
184252
185−
186−get_data : DBPointer -> String -> Int -> Int -> IO DBVal
187−get_data (MkDBPointer pointer) tbl_name row col = do
188− ty <- get_data_type pointer tbl_name row col
189− helper ty
190− where
191− get_data_type : Ptr -> String -> Int -> Int -> IO Int
192− 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−
194− get_data_val_int : Ptr -> String -> Int -> Int -> IO Int
195− 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−
197− get_data_val_text : Ptr -> String -> Int -> Int -> IO String
198− 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−
200− get_data_val_float : Ptr -> String -> Int -> Int -> IO Float
201− get_data_val_float pointer tbl_name row col =mkForeign (FFun "sqlite3_get_float" [FPtr, FString, FInt, FInt] FFloat)pointer tbl_name row col
202−
203−
204− helper : Int -> IO DBVal
205− helper 1 = do i <- get_data_val_int pointer tbl_name row col; return (DBInt i)
206− helper 2 = do i <- get_data_val_float pointer tbl_name row col; return (DBFloat i)
207− helper 3 = do i <- get_data_val_text pointer tbl_name row col; return (DBText i)
208− helper _ = return (DBNull)
253+-----------------------------------------------------------------------------
254+-- | This version of these function obtain the row and column number
255+-- from the Database struct.
256+-----------------------------------------------------------------------------
209257
210258num_row_v2 : DBPointer -> IO Int
211259num_row_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_row_v2" [FPtr] FInt)pointer
@@ -215,25 +263,30 @@ num_col_v2 : DBPointer -> IO Int
215263num_col_v2 (MkDBPointer pointer) = do x <- mkForeign (FFun "sqlite3_get_num_col_v2" [FPtr] FInt)pointer
216264 return (x)
217265
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+-----------------------------------------------------------------------------
218271
219−get_data_v2 : DBPointer -> Int -> Int -> IO DBVal
220−get_data_v2 (MkDBPointer pointer) row col = do
221− ty <- get_data_type_v2 pointer row col
272+get_data : DBPointer -> Int -> Int -> IO DBVal
273+get_data (MkDBPointer pointer) row col = do
274+ ty <- get_data_type pointer row col
222275 helper ty
223276 where
224− get_data_type_v2 : Ptr ->Int -> Int -> IO Int
225− get_data_type_v2 pointer row col =mkForeign (FFun "sqlite3_get_data_type_v2" [FPtr, FInt, FInt] FInt)pointer row col
277+ get_data_type : Ptr ->Int -> Int -> IO Int
278+ get_data_type pointer row col =mkForeign (FFun "sqlite3_get_data_type" [FPtr, FInt, FInt] FInt)pointer row col
226279
227280 get_data_val_int : Ptr -> Int -> IO Int
228− 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" [FPtr,FInt] FInt)pointer col
229282
230283 get_data_val_text : Ptr -> Int -> IO String
231− get_data_val_text pointer col =mkForeign (FFun "sqlite3_get_val_text_v2" [FPtr, FInt] FString)pointer col
284+ get_data_val_text pointer col =mkForeign (FFun "sqlite3_get_val_text" [FPtr, FInt] FString)pointer col
232285
233286
234287
235288 get_data_val_float : Ptr -> Int -> IO Float
236− get_data_val_float pointer col =mkForeign (FFun "sqlite3_get_float_v2" [FPtr, FInt] FFloat)pointer col
289+ get_data_val_float pointer col =mkForeign (FFun "sqlite3_get_float" [FPtr, FInt] FFloat)pointer col
237290
238291 helper : Int -> IO DBVal
239292 helper 1 = do i <- get_data_val_int pointer col ; return (DBInt i)
@@ -241,71 +294,91 @@ get_data_v2 (MkDBPointer pointer) row col = do
241294 helper 3 = do i <- get_data_val_text pointer col; return (DBText i)
242295 helper _ =return (DBNull)
243296
244−
245−toList_v2 : DBPointer -> DB Table
246−toList_v2 db = do
247− nbR <- liftIO (num_row_v2 db)
248− nmC <- liftIO (num_col_v2 db)
249− res <- forM [0..(nbR-1)] (\ i =>
250− forM [0..(nmC-1)] (\ j =>
251− liftIO(get_data_v2 db i j)
297+-----------------------------------------------------------------------------
298+-- | This function makes use of get_data to get all the result.
299+-----------------------------------------------------------------------------
300+
301+toList_v1 : DBPointer -> DB Table
302+toList_v1 db = do
303+ nbR <- liftIO (num_row_v2 db)
304+ nmC <- liftIO (num_col_v2 db)
305+ res <- forM [0..(nbR-1)] (\ i =>
306+ forM [0..(nmC-1)] (\ j =>
307+ liftIO(get_data db i j)
252308
253− )
254− )
255− return res
256−
257−
309+ )
310+ )
311+ return res
312+
313+
258314strcat : String -> String-> String
259315strcat str1 str2 = (str1 ++ str2)
260316
261−free_table : TBPointer -> IO ()
262−free_table (MkTBPointer pointer) = do x <- mkForeign (FFun "sqlite3_free_table_idr" [FPtr] FUnit)pointer
263− return ()
264−
317+-----------------------------------------------------------------------------
318+-- | This version of toList retunrs result from get_table
319+-- This could be removed if not needed in the future.
320+-----------------------------------------------------------------------------
265321
266−toList : String -> String -> DBPointer -> DB Table
267−toList name stmt x = do
268− ptr <- (get_table x (stmt))
269− nbR <- liftIO (num_row ptr)
270− nmC <- liftIO (num_col ptr)
271− res <- forM [0..(nbR-1)] (\ i =>
272− forM [0..(nmC-1)] (\ j =>
273− liftIO(get_data x name i j)
274−
275− )
276− )
277− liftIO (free_table ptr)
278− return res
279−
280−bind_int : StmtPtr -> Int -> Int -> DB Int
281−bind_int (MkStmtPtr pointer) indexval val = do
282− x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FInt)pointer indexval val)
283− if (x /= 0 )
322+--toList_v2 : String -> String -> DBPointer -> DB Table
323+--toList_v2 name stmt x = do
324+-- ptr <- (get_table x (stmt))
325+-- nbR <- liftIO (num_row ptr)
326+-- nmC <- liftIO (num_col ptr)
327+-- res <- forM [0..(nbR-1)] (\ i =>
328+-- forM [0..(nmC-1)] (\ j =>
329+-- liftIO(get_data x name i j)
330+--
331+-- )
332+-- )
333+-- liftIO (free_table ptr)
334+-- return res
335+
336+
337+-----------------------------------------------------------------------------
338+-- | These routines support binding the types supported by Idris.
339+-- These return a pointer to statement pointer since we want to allow
340+-- binding multiple values by implementing a recursive function.
341+-----------------------------------------------------------------------------
342+
343+bind_int : StmtPtr -> Int -> Int -> DB StmtPtr
344+bind_int (MkStmtPtr pointer) indexval val = do
345+ x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FPtr)pointer indexval val)
346+ flag <- liftIO(nullPtr x)
347+ if flag
284348 then fail "Could not bind int."
285− else return x
286−
349+ else return (MkStmtPtr x)
350+
287351
288−bind_float : StmtPtr -> Int -> Int -> DB Int
352+bind_float : StmtPtr -> Int -> Float -> DB StmtPtr
289353bind_float (MkStmtPtr pointer) indexval val = do
290− x <- liftIO(mkForeign (FFun "sqlite3_bind_float_idr" [FPtr, FInt, FInt] FInt)pointer indexval val)
291− if (x /= 0)
354+ x <- liftIO(mkForeign (FFun "sqlite3_bind_float_idr" [FPtr, FInt, FFloat] FPtr)pointer indexval val)
355+ flag <- liftIO(nullPtr x)
356+ if flag
292357 then fail "Could not bind float."
293− else return x
358+ else return (MkStmtPtr x)
294359
295−bind_text : StmtPtr -> String -> Int -> Int -> DB Int
360+bind_text : StmtPtr -> String -> Int -> Int -> DB StmtPtr
296361bind_text (MkStmtPtr pointer) text indexval lengthval = do
297− x <- liftIO(mkForeign (FFun "sqlite3_bind_text_idr" [FPtr, FString, FInt, FInt] FInt)pointer text indexval lengthval)
298− if (x /= 0)
362+ x <- liftIO(mkForeign (FFun "sqlite3_bind_text_idr" [FPtr, FString, FInt, FInt] FPtr)pointer text indexval lengthval)
363+ flag <- liftIO(nullPtr x)
364+ if flag
299365 then fail "Could not bind text."
300− else return x
366+ else return (MkStmtPtr x)
301367
302−bind_null : StmtPtr -> Int -> DB Int
303−bind_null (MkStmtPtr pointer) indexval =do
304− x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FInt)pointer indexval)
305− if (x /= 0)
368+bind_null : StmtPtr -> Int -> DB StmtPtr
369+bind_null (MkStmtPtr pointer) indexval = do
370+ x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FPtr)pointer indexval)
371+ flag <- liftIO(nullPtr x)
372+ if flag
306373 then fail "Could not bind null."
307− else return x
374+ else return (MkStmtPtr x)
375+
376+-----------------------------------------------------------------------------
377+-- | String Length
378+-----------------------------------------------------------------------------
308379
380+strlen : String -> DB Int
381+strlen str = liftIO(mkForeign (FFun "strLength" [FString] FInt) str)
309382
310383instance Show DBVal where
311384 show (DBInt i) = "Int val: " ++ show i ++ "\n"
@@ -313,55 +386,23 @@ instance Show DBVal where
313386 show (DBFloat i) = "Float val: " ++ show i ++ "\n"
314387 show (DBNull ) = "NULL"
315388
316−print_data_v2 : DBVal -> String
317−print_data_v2 = show
318−
319−test : DB()
320−test = do db <- liftIO (open_db "somedb.db")
321− stmt <- (prepare_db db "insert into tbl1 values (?,?);")
322− bind_int stmt 1 456
323− bind_text stmt "testing" 2 4
324− step_db stmt
325− reset_db stmt
326− finalize_db stmt
327− c <- liftIO (close_db db)
328− return ()
329−
330−test3 : DB()
331−test3 = do db <- liftIO (open_db "students.db")
332− 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")
333− exec_db_v2 stmt
334− res <- toList_v2 db
335− liftIO(print res)
336− finalize_db stmt
337− c <- liftIO (close_db db)
338− return ()
339−
340−--bindMulti : StmtPtr -> List (Int, (Maybe Value)) -> StmtPtr
341−--bindMulti (MkStmtPtr pointer) [] = (MkStmtPtr pointer)
342−--bindMulti (MkStmtPtr pointer) xs = let newxs = mapping 0 xs in
343−-- case newxs of
344−-- ((_, Nothing):: vs) => bindMulti (MkStmtPtr pointer) vs
345−-- ((index, Just v)::vs) => bindMulti(bind pointer index v) vs
346−
347−testexpr : DB()
348−testexpr = do db <- liftIO (open_db "somedb.db")
349− let sql = (evalSQL [] ((SELECT ALL)(TBL "tbl1")(MkCond (Equals (VCol "data")(VInt 1)))))
350− let x = (display sql)
351− liftIO(print x)
352− stmt <- (prepare_db db "select * from tbl1 where num =?")
353− --let Int(theval) = getval(getlist(sql))
354− bind_int stmt 0 2
355− exec_db_v2 stmt
356− res <- toList_v2 db
357− liftIO(print res)
358− finalize_db stmt
359− c <- liftIO (close_db db)
360− return ()
361−
362−main : IO ()
363−main = do --x <- runDB (test3)
364− y <- runDB (testexpr)
365− return ()
366−
367−
389+-----------------------------------------------------------------------------
390+-- | Multi bind a list of values.
391+-----------------------------------------------------------------------------
392+
393+bindMulti : StmtPtr-> List (Maybe (Int, Value)) -> DB StmtPtr
394+bindMulti pointer [] = return pointer
395+bindMulti pointer (Nothing :: vs) = bindMulti pointer vs
396+bindMulti pointer ((Just (indexs, val))::vs) = case val of
397+ (VInt intval) => do x <- bind_int pointer indexs intval
398+ bindMulti(x) vs
399+
400+ (VStr strval) => do len <- strlen strval
401+ x <- bind_text pointer strval indexs len
402+ bindMulti(x) vs
403+
404+
405+ (VFloat floatval) => do x <- bind_float pointer indexs floatval
406+
407+ bindMulti(x) vs
408+