on master help sign in
Merge pull request #40 from melissam/master
2b755fdEdwin Brady
contribs/lib/SQLite3/._Makefile

Binary file not shown.

contribs/lib/SQLite3/._sqlexpr.idr

Binary file not shown.

contribs/lib/SQLite3/._sqlite3.idr

Binary file not shown.

contribs/lib/SQLite3/._sqlite3api.c

Binary file not shown.

contribs/lib/SQLite3/._sqlite3api.h

Binary file not shown.

contribs/lib/SQLite3/._testunit.idrnew file

Binary file not shown.

contribs/lib/SQLite3/Makefile+3−2
@@ -3,10 +3,11 @@
3
3
4.PHONY: all
4.PHONY: all
5
5
6−sqltest : sqlite3.idr sqlite3api.o
6+sqltest : testunit.idr sqlite3.idr sqlite3api.o
7− idris sqlite3.idr -o sqltest
7+ idris testunit.idr -o sqltest
8
8
9sqlite3api.o : sqlite3api.c
9sqlite3api.o : sqlite3api.c
10 gcc -c sqlite3api.c
10 gcc -c sqlite3api.c
11
11
12all : sqltest sqlite3api.o
12all : sqltest sqlite3api.o
13+
contribs/lib/SQLite3/sqlexpr.idr+189−47
@@ -1,36 +1,71 @@
1−module main
1+module sqlexpr
2import prelude.list
2import prelude.list
3
3
4+-----------------------------------------------------------------------------
5+-- |
6+-- Module : sqlexpr
7+-- Copyright : (c) The University of St Andrews, 2012
8+--
9+-- Implementations for SQLite query data type.
10+--
11+-----------------------------------------------------------------------------
12+
13+
4-----------------------------------------------------------
14-----------------------------------------------------------
5−-- * SQL data type
15+-- | SQL data type
6-----------------------------------------------------------
16-----------------------------------------------------------
7
17
8data Value = VInt Int
18data Value = VInt Int
9 |VStr String
19 |VStr String
20+ |VFloat Float
10 |VCol String
21 |VCol String
22+ |VNULL
23+
24+--Perhaps could extend this by adding
25+-- a dot operator to allow mapping
26+-- between table and column and
27+-- comparing different table columns.
11
28
12data Cond = Equals Value Value
29data Cond = Equals Value Value
13 |MkGT Value Value
30 |MkGT Value Value
14 |MkGTE Value Value
31 |MkGTE Value Value
15 |MkLT Value Value
32 |MkLT Value Value
16 |MkLTE Value Value
33 |MkLTE Value Value
17−--TODO |MkIN (List Value)
34+ |MkNULL Value
18−--TODO |MkIN SQL
19
35
20−
36+
21data Clause = MkCond Cond
37data Clause = MkCond Cond
22 | AND Clause Clause
38 | AND Clause Clause
23 | OR Clause Clause
39 | OR Clause Clause
24 | Empty
40 | Empty
41+ | MkSQL SQL
42+
43+data condClause = SET Clause
44+ |WHERE condClause Clause
25
45
26data SelVar = Cols (List String)
46data SelVar = Cols (List String)
27 |ALL
47 |ALL
28
48
49+data ColType = CInt String -- parsed as string "int"
50+ |Varchar String
51+
52+data Constr = NOTNULL
53+ | UNIQUE Constr
54+ | None
55+ | PRIMARYKEY
56+ | FOREIGNKEY
57+ | CHECK
58+ | DEFAULT
59+
60+
29data SQL = SELECT SelVar SQL Clause
61data SQL = SELECT SelVar SQL Clause
30− | TBL String
62+ | TBL (List String)
31 | INSERT SQL (List Value)
63 | INSERT SQL (List Value)
64+ | INSERTC SQL (List Value) (List Value)
65+ | UPDATE SQL condClause
66+ | CREATE SQL (List (Value, ColType , Constr))
32
67
33−
68+-- remember to remove these funcs later
34foldr1 : (a -> a -> a) -> List a -> a
69foldr1 : (a -> a -> a) -> List a -> a
35foldr1 f [x] = x
70foldr1 f [x] = x
36foldr1 f (x::xs) = f x (foldr1 f xs)
71foldr1 f (x::xs) = f x (foldr1 f xs)
@@ -47,46 +82,115 @@ unwords' ws = (foldr1 addSpace ws)
47unwords : List String -> String
82unwords : List String -> String
48unwords = pack . unwords' . map unpack
83unwords = pack . unwords' . map unpack
49
84
85+-----------------------------------------------------------
86+-- | This function replaces values with question mark
87+-- following by an index number. It then puts the value
88+-- replaced, in the list.
89+-----------------------------------------------------------
90+
91+valString : List (Maybe(Int, Value)) -> Value -> (String, List (Maybe(Int, Value)))
92+valString xs (VInt x) = ("?" ++ show (cast(length xs)+1), xs ++ [Just (cast((length xs)+1),(VInt x))])
93+valString xs (VStr x) = ("?" ++ show (cast(length xs)+1), xs ++ [Just (cast((length xs)+1),(VStr x))])
94+valString xs (VFloat x) = ("?" ++ show (cast(length xs)+1), xs ++ [Just (cast((length xs)+1),(VFloat x))])
95+valString xs (VCol n) = (n, xs)
96+
97+-----------------------------------------------------------
98+-- | This function calls valString on a list of Values
99+-- and separates the values by commas.
100+-----------------------------------------------------------
101+
102+listVal : List (Maybe(Int, Value)) -> List Value -> (String, List (Maybe(Int, Value)))
103+listVal xs [] = ("", xs)
104+listVal xs (v::vs) = let (str, newxs) = (valString xs v) in
105+ let (str', newxs') = listVal newxs vs in
106+ ((unwords(intersperse "," (words(str) ++ words (str')))), newxs')
107+
108+-----------------------------------------------------------
109+-- | Parses the type of column to be created.
110+-----------------------------------------------------------
111+
112+getColType : List (Maybe(Int, Value)) -> ColType -> (String, List (Maybe(Int, Value)))
113+getColType xs (CInt x) = ("int", xs)
114+getColType xs (Varchar str) = ("varchar(255)", xs)
115+
116+-----------------------------------------------------------
117+-- | CREATE Constraints
118+-----------------------------------------------------------
50
119
51−mapping : Int -> List a -> List (Int, a)
120+getConstr : List (Maybe(Int, Value)) -> Constr -> (String, List (Maybe(Int, Value)))
52−mapping counter [] = []
121+getConstr xs (NOTNULL) = ("NOT NULL", xs)
53−mapping counter (x :: xs) = (counter, x) :: mapping (counter + 1) xs
122+getConstr xs (UNIQUE constr) = ("NOT NULL UNIQUE", xs)
123+getConstr xs (PRIMARYKEY) = ("PRIMARY KEY", xs)
124+getConstr xs (FOREIGNKEY) = ("FOREIGN KEY", xs)
125+getConstr xs (CHECK) = ("CHECK", xs)
126+getConstr xs (DEFAULT) = ("DEFAULT", xs)
127+getConstr xs (None) = ("", xs)
54
128
129+putBrackets : String -> String
130+putBrackets str = "(" ++ str ++ ")"
55
131
132+-----------------------------------------------------------
133+-- | Used to detect a complex type in a nested SQLite query
134+-- This function is used for bracketing the nested queries.
135+-----------------------------------------------------------
136+complexType : SQL -> Bool
137+complexType (TBL tbl) = False
138+complexType (SELECT vars sql c) = True
139+
140+-----------------------------------------------------------
141+-- | Used in CREATE
142+-----------------------------------------------------------
143+
56−popintoList : Maybe Value -> List (Maybe Value) -> List (Maybe Value)
144+listValType : List (Maybe(Int, Value)) -> List (Value, ColType , Constr) -> (String, List (Maybe(Int, Value)))
57−popintoList (Just x) [] = [(Just x)]
145+listValType xs [] = ("", xs)
58−popintoList (Just (x)) ((Just x) :: xs) = (popintoList (Just x) xs)
146+listValType xs ((val, types, constr) :: vs) = let (str , newxs) = valString xs val in
59−popintoList Nothing [] = []
147+ let (str' , newxs') = getColType newxs types in
148+ let (str'', newxs'') = getConstr newxs' constr in
149+ let (finalstr, finalxs) = listValType newxs'' vs in
150+ ((unwords(intersperse " " (words(str) ++ words(str') ++ words(str'') ++ words(finalstr)))) , finalxs)
60
151
61−valString : List (Maybe Value) -> Value -> (String, List (Maybe Value))
62−valString xs (VInt x) = ("?", xs ++ [Just (VInt x)])
63−valString xs (VStr x) = ("?", xs ++ [Just (VStr x)])
64−valString xs (VCol n) = (n, xs)
65
152
153+-----------------------------------------------------------
154+-- | Evaluates a conditional WHERE clause
155+-----------------------------------------------------------
66
156
67−evalCond : List (Maybe Value) -> Cond -> (String, List (Maybe Value))
157+evalCond : List (Maybe(Int, Value)) -> Cond -> (String, List (Maybe(Int, Value)))
68evalCond xs (Equals val1 val2) = let (restring , newxs ) = valString xs val1 in
158evalCond xs (Equals val1 val2) = let (restring , newxs ) = valString xs val1 in
69 let (restring2, newxs') = valString newxs val2 in
159 let (restring2, newxs') = valString newxs val2 in
70− (restring ++ " = " ++ restring2, (newxs ++ newxs'))
160+ (restring ++ " = " ++ restring2, newxs')
71
161
72evalCond xs (MkGT val1 val2) = let (restring , newxs ) = valString xs val1 in
162evalCond xs (MkGT val1 val2) = let (restring , newxs ) = valString xs val1 in
73 let (restring2, newxs') = valString newxs val2 in
163 let (restring2, newxs') = valString newxs val2 in
74− (restring ++ " > " ++ restring2, (newxs ++ newxs'))
164+ (restring ++ " > " ++ restring2, newxs')
75
165
76evalCond xs (MkGTE val1 val2) = let (restring , newxs ) = valString xs val1 in
166evalCond xs (MkGTE val1 val2) = let (restring , newxs ) = valString xs val1 in
77 let (restring2, newxs') = valString newxs val2 in
167 let (restring2, newxs') = valString newxs val2 in
78− (restring ++ " >= " ++ restring2, (newxs ++ newxs'))
168+ (restring ++ " >= " ++ restring2, newxs')
79
169
80evalCond xs (MkLT val1 val2) = let (restring , newxs ) = valString xs val1 in
170evalCond xs (MkLT val1 val2) = let (restring , newxs ) = valString xs val1 in
81 let (restring2, newxs') = valString newxs val2 in
171 let (restring2, newxs') = valString newxs val2 in
82− (restring ++ " < " ++ restring2, (newxs ++ newxs'))
172+ (restring ++ " < " ++ restring2, newxs')
83
173
84evalCond xs (MkLTE val1 val2) = let (restring , newxs ) = valString xs val1 in
174evalCond xs (MkLTE val1 val2) = let (restring , newxs ) = valString xs val1 in
85 let (restring2, newxs') = valString newxs val2 in
175 let (restring2, newxs') = valString newxs val2 in
86− (restring ++ " =< " ++ restring2, (newxs ++ newxs'))
176+ (restring ++ " =< " ++ restring2, newxs')
87
177
88−
178+evalCond xs (MkNULL val) = let (restring , newxs ) = valString xs val in
179+ (restring ++ " IS NULL " , newxs)
180+
181+-----------------------------------------------------------
182+-- | Evaluates queries by calling the other functions
183+-- on each part of the query
184+-----------------------------------------------------------
185+evalSQL : List (Maybe(Int, Value)) -> SQL -> ( String, List (Maybe(Int, Value)))
186+-----------------------------------------------------------
187+-- | Evaluates clauses
188+-- Supports WHERE Clause
189+-- WHERE Clause And Another-Clause
190+-- WHERE Clause Or Another-Clause
191+-----------------------------------------------------------
89−clauseString : List (Maybe Value) -> Clause -> (String, List (Maybe Value))
192+clauseString : List (Maybe(Int, Value)) -> Clause -> (String, List (Maybe(Int, Value)))
193+
90clauseString xs (Empty) = ("" , []) -- No condition
194clauseString xs (Empty) = ("" , []) -- No condition
91clauseString xs (MkCond cond') = let (condstr, newxs) = evalCond xs cond' in
195clauseString xs (MkCond cond') = let (condstr, newxs) = evalCond xs cond' in
92 (condstr , newxs)
196 (condstr , newxs)
@@ -99,34 +203,72 @@ clauseString xs (OR c1 c2) = let (clausestr, newxs) = clauseString xs c1 in
99 let (clausestr2, newxs') = clauseString newxs c2 in
203 let (clausestr2, newxs') = clauseString newxs c2 in
100 (clausestr ++ " OR " ++clausestr2 , newxs')
204 (clausestr ++ " OR " ++clausestr2 , newxs')
101
205
102−
206+
103−varString : List String -> String
207+-----------------------------------------------------------
104−varString xs = (unwords xs)
208+-- | Evaluates conditional clauses.
105−
209+-----------------------------------------------------------
106−
210+
107−evalSQL : List (Maybe Value) -> SQL -> ( String, List (Maybe Value))
211+condClauseStr : List (Maybe(Int, Value)) -> condClause -> (String, List (Maybe(Int, Value)))
108−evalSQL xs (TBL tbl) = (tbl, xs)
212+condClauseStr xs (SET setcl) = let (condstr, newxs) = clauseString xs setcl in
213+ (" SET " ++ condstr, newxs)
214+
215+condClauseStr xs (WHERE setcl1 setcl2) = let (condstr, newxs) = condClauseStr xs setcl1 in
216+ let (condstr', newxs') = clauseString newxs setcl2 in
217+ ( condstr ++ " WHERE " ++ condstr', newxs')
218+
219+-- SELECT data from tbl1 where num > (SELECT num from tbl1 where num = 24)
220+-- evalSQL [] ((SELECT ALL)(TBL "tbl")(MkSQL ((SELECT ALL) (TBL "tbl")(MkCond (VCol "))))
221+-- NTBF
222+--clauseString xs (MkSQL sql) = (evalSQL xs sql)
223+
224+-- Separate list of tables
225+-- For complex type, return list returned by evalSQL
226+-- And add brackets
227+evalSQL xs (TBL tbl) = ((unwords (intersperse "," ( tbl))), xs)
109evalSQL xs (SELECT vars sql' c) = let (sqlstring, newxs) = evalSQL xs sql' in
228evalSQL xs (SELECT vars sql' c) = let (sqlstring, newxs) = evalSQL xs sql' in
110 let (csstring, newxs') = clauseString newxs c in
229 let (csstring, newxs') = clauseString newxs c in
111 case c of
230 case c of
112 Empty => case vars of
231 Empty => case vars of
113− (ALL ) => ("SELECT " ++ "*" ++ " FROM (" ++ sqlstring ++ ") " ++ csstring, map snd ( mapping 0 newxs'))
232+ (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
114− (Cols selvar) => ("SELECT " ++ unwords ( intersperse "" ( selvar ++ (words ( " FROM (" ++ sqlstring ++ ")")))) ++ csstring, map snd ( mapping 0 newxs'))
233+ ++ (putBrackets sqlstring) ++ csstring, newxs)
234+
235+ else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
236+ ++ csstring, newxs')
237+
238+ (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++
239+ " FROM " ++ (putBrackets sqlstring) ++ csstring, newxs)
240+
241+ else ("SELECT " ++ (unwords selvar )++ " FROM " ++ sqlstring
242+ ++ csstring, newxs')
115
243
116 _ => case vars of
244 _ => case vars of
117− (ALL ) => ("SELECT " ++ "*" ++ " FROM (" ++ sqlstring ++ ") " ++ "WHERE" ++ csstring, map snd ( mapping 0 newxs'))
245+ (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
118− (Cols selvar) => ("SELECT " ++ unwords ( intersperse "" ( selvar ++ (words ( " FROM (" ++ sqlstring ++ ")")))) ++ "WHERE" ++ csstring, map snd ( mapping 0 newxs'))
246+ ++ " WHERE " ++ csstring , newxs)
247+ else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
248+ ++ " WHERE " ++ csstring , newxs')
249+
250+ (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++ " FROM " ++
251+ (putBrackets sqlstring) ++ " WHERE "
252+ ++ csstring , newxs)
253+
254+ else ("SELECT " ++ (unwords selvar) ++ " FROM " ++ sqlstring
255+ ++ " WHERE " ++ csstring , newxs')
256+
257+
258+evalSQL xs (INSERT sql vals) = let (tblname, newvals) = evalSQL xs sql in
259+ let (str, newxs ) = listVal newvals vals in
260+ ("INSERT INTO " ++ tblname ++ " VALUES (" ++ str ++ ")" , newxs)
119
261
262+evalSQL xs (INSERTC sql cols vals) = let (tblname, newvals) = evalSQL xs sql in
263+ let (strcol, newcol) = listVal newvals cols in
264+ let (strval, newcolval) = listVal newcol vals in
265+ ("INSERT INTO " ++ tblname ++ "(" ++ strcol ++ ")" ++ "VALUES (" ++ strval ++ ")", newcolval)
120
266
121−display : (String, List (Maybe Value)) -> String
122−display (x, (xs)) = show x
123−
124−evalSQL2 : List (Maybe Value) -> String -> (String, List (Maybe Value))
125−evalSQL2 [] sql = (sql, [])
126−evalSQL2 ((Just (VInt x)) :: xs) sql = let ("string" , newxs) = evalSQL2 xs sql in
127− ("string" ++ sql , Just (VInt x) :: newxs)
128
267
129−main : IO ()
268+evalSQL xs (UPDATE sql cl) = let (tblname, newxs) = evalSQL xs sql in
130−main = print (display(evalSQL [] ((SELECT ALL)(TBL "tbl") (MkCond (Equals (VCol "col")(VInt 1))))))
269+ let (csstring, newxs') = condClauseStr newxs cl in
270+ ("UPDATE " ++ tblname ++ csstring, newxs')
131
271
132−
272+evalSQL xs (CREATE sql details) = let (sqlstring, newxs) = evalSQL xs sql in
273+ let (csstring, newxs') = listValType newxs details in
274+ ("CREATE TABLE " ++ sqlstring ++ "(" ++ csstring ++ ")", newxs')
contribs/lib/SQLite3/sqlite3.idr+220−179
@@ -1,4 +1,4 @@
1−module main
1+module sqlite3
2import sqlexpr
2import sqlexpr
3
3
4
4
@@ -6,64 +6,83 @@ import sqlexpr
6%link "sqlite3api.o"
6%link "sqlite3api.o"
7%include "sqlite3api.h"
7%include "sqlite3api.h"
8
8
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+-----------------------------------------------------------------------------
9
18
19+-- | The types supported by Idris returned by the database functions.
10
20
11data DBVal = DBInt Int
21data DBVal = DBInt Int
12 | DBText String
22 | DBText String
13 | DBFloat Float
23 | DBFloat Float
14 | DBNull
24 | DBNull
15
25
16−
26+-- Database pointer
17data DBPointer = MkDBPointer Ptr
27data DBPointer = MkDBPointer Ptr
18−
28+-- Table pointer
19data TBPointer = MkTBPointer Ptr
29data TBPointer = MkTBPointer Ptr
20−
30+-- Statement pointer
21data StmtPtr = MkStmtPtr Ptr
31data StmtPtr = MkStmtPtr Ptr
22−
32+
23Table : Set
33Table : Set
24Table = List (List DBVal)
34Table = List (List DBVal)
25
35
26−
36+-- ForMap used in to_list_v1
27forM : Monad m => List a -> (a -> m b) -> m (List b)
37forM : Monad m => List a -> (a -> m b) -> m (List b)
28forM f xs = mapM xs f
38forM f xs = mapM xs f
29
39
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))
30
53
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
54+liftIO : IO a -> DB a
45−liftIO f = MkDB (do f' <- f
55+liftIO f = MkDB (do f' <- f
46− return (Right f'))
56+ return (Right f'))
47−
57+
48−ioError : String -> IO a
58+ioError : String -> IO a
49−ioError err = do putStrLn err
59+ioError err = do putStrLn err
50− return (believe_me ())
60+ return (believe_me ())
51−
61+
52−runDB : DB a -> IO a
62+runDB : DB a -> IO a
53−runDB (MkDB f) = do f' <- f
63+runDB (MkDB f) = do f' <- f
54− case f' of
64+ case f' of
55− Right v => return v
65+ Right v => return v
56 Left str => ioError str
66 Left str => ioError str
57
67
68+-----------------------------------------------------------------------------
69+-- | Opens an SQLite database file as specified by the String name argument.
70+-----------------------------------------------------------------------------
58
71
59−
60−open_db : String -> IO DBPointer
72+open_db : String -> DB DBPointer
61−open_db name = do x <- mkForeign (FFun "sqlite3_open_idr" [FString] FPtr)name
73+open_db name = do x <- liftIO(mkForeign (FFun "sqlite3_open_idr" [FString] FPtr) name)
62 return (MkDBPointer x)
74 return (MkDBPointer x)
63
75
76+-----------------------------------------------------------------------------
77+-- | Destructor for the DBPointer.
78+-----------------------------------------------------------------------------
79+
64−close_db : DBPointer -> IO Int
80+close_db : DBPointer -> DB Int
65−close_db (MkDBPointer pointer) =mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer
81+close_db (MkDBPointer pointer) = liftIO (mkForeign (FFun "sqlite3_close_idr" [FPtr] FInt)pointer)
66
82
83+-----------------------------------------------------------------------------
84+-- | Wrapper around prepare, step and finalize.
85+-----------------------------------------------------------------------------
67
86
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,35 +91,58 @@ 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
74
93
94+-----------------------------------------------------------------------------
95+-- | Executes a prepared query. Use of this version is recommended.
96+-----------------------------------------------------------------------------
75
97
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+-----------------------------------------------------------------------------
76
110
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
79
113
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+-----------------------------------------------------------------------------
80
120
81prepare_db : DBPointer -> String -> DB StmtPtr
121prepare_db : DBPointer -> String -> DB StmtPtr
82prepare_db (MkDBPointer pointer) cmd = do
122prepare_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)
85 flag <- liftIO(nullPtr result)
124 flag <- liftIO(nullPtr result)
86 if flag
125 if flag
87 then fail "Error occured while preparing"
126 then fail "Error occured while preparing"
88 else return (MkStmtPtr result)
127 else return (MkStmtPtr result)
89
128
90−exec_db_v2 : StmtPtr -> DB Int
129+-----------------------------------------------------------------------------
91−exec_db_v2 (MkStmtPtr pointer) = do
130+-- | Returns the error stored in the buffer by exec_db function.
92− x <- liftIO(mkForeign (FFun "exec_db" [FPtr] FInt)pointer)
131+-- This function can only be used with exec_db and get_table.
93− if (x == 21)
132+-- Only these functions store any occured error in the buffer array.
94− then fail "No data returned."
133+-----------------------------------------------------------------------------
95− else return x
96
134
97step_db : StmtPtr -> DB Int
135step_db : StmtPtr -> DB Int
98−step_db (MkStmtPtr pointer) = do
136+step_db (MkStmtPtr pointer)= do
99 x <- liftIO (mkForeign (FFun "sqlite3_step_idr" [FPtr] FInt)pointer)
137 x <- liftIO (mkForeign (FFun "sqlite3_step_idr" [FPtr] FInt)pointer)
100 if ( x == 101)
138 if ( x == 101)
101 then fail "SQLITE_DONE"
139 then fail "SQLITE_DONE"
102 else return x
140 else return x
103
141
142+-----------------------------------------------------------------------------
143+-- | Deletes a prepared statement. This function must be called after
144+-- prepare function.
145+-----------------------------------------------------------------------------
104
146
105finalize_db : StmtPtr -> DB Int
147finalize_db : StmtPtr -> DB Int
106finalize_db (MkStmtPtr pointer) = do
148finalize_db (MkStmtPtr pointer) = do
@@ -109,6 +151,10 @@ finalize_db (MkStmtPtr pointer) = do
109 then fail "Could not finalize"
151 then fail "Could not finalize"
110 else return x
152 else return x
111
153
154+-----------------------------------------------------------------------------
155+-- | Resets a prepared statement pointer back to its initial state.
156+-----------------------------------------------------------------------------
157+
112reset_db : StmtPtr -> DB Int
158reset_db : StmtPtr -> DB Int
113reset_db (MkStmtPtr pointer) = do
159reset_db (MkStmtPtr pointer) = do
114 x <- liftIO(mkForeign (FFun "sqlite3_reset_idr" [FPtr] FInt)pointer)
160 x <- liftIO(mkForeign (FFun "sqlite3_reset_idr" [FPtr] FInt)pointer)
@@ -116,6 +162,10 @@ reset_db (MkStmtPtr pointer) = do
116 then fail "Could not reset"
162 then fail "Could not reset"
117 else return x
163 else return x
118
164
165+-----------------------------------------------------------------------------
166+-- | These routines obtain column information.
167+-----------------------------------------------------------------------------
168+
119column_count : DBPointer -> IO (Either String Int)
169column_count : DBPointer -> IO (Either String Int)
120column_count (MkDBPointer pointer) = do
170column_count (MkDBPointer pointer) = do
121 x <- mkForeign (FFun "sqlite3_column_count_idr" [FPtr] FInt)pointer
171 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
145column_Int : DBPointer -> Int -> IO Int
195column_Int : DBPointer -> Int -> IO Int
146column_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
147
197
198+-----------------------------------------------------------------------------
199+-- | These routines support some of SQLite backup functions.
200+-----------------------------------------------------------------------------
148
201
149backup_init : DBPointer -> String -> DBPointer -> String -> IO DBPointer
202backup_init : DBPointer -> String -> DBPointer -> String -> IO DBPointer
150backup_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
@@ -160,6 +213,12 @@ backup_remaining : DBPointer -> IO Int
160backup_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
161
214
162
215
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+-----------------------------------------------------------------------------
163
222
164get_table : DBPointer -> String -> DB TBPointer
223get_table : DBPointer -> String -> DB TBPointer
165get_table (MkDBPointer pointer) name = do
224get_table (MkDBPointer pointer) name = do
@@ -174,6 +233,15 @@ get_table (MkDBPointer pointer) name = do
174 return x
233 return x
175
234
176
235
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+
177num_row : TBPointer -> IO Int
245num_row : TBPointer -> IO Int
178num_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
179 return (x)
247 return (x)
@@ -182,30 +250,10 @@ num_col : TBPointer -> IO Int
182num_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
183 return (x)
251 return (x)
184
252
185−
253+-----------------------------------------------------------------------------
186−get_data : DBPointer -> String -> Int -> Int -> IO DBVal
254+-- | This version of these function obtain the row and column number
187−get_data (MkDBPointer pointer) tbl_name row col = do
255+-- from the Database struct.
188− ty <- get_data_type pointer tbl_name row col
256+-----------------------------------------------------------------------------
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)
209
257
210num_row_v2 : DBPointer -> IO Int
258num_row_v2 : DBPointer -> IO Int
211num_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
@@ -215,25 +263,30 @@ num_col_v2 : DBPointer -> IO Int
215num_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
216 return (x)
264 return (x)
217
265
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
271
219−get_data_v2 : DBPointer -> Int -> Int -> IO DBVal
272+get_data : DBPointer -> Int -> Int -> IO DBVal
220−get_data_v2 (MkDBPointer pointer) row col = do
273+get_data (MkDBPointer pointer) row col = do
221− ty <- get_data_type_v2 pointer row col
274+ ty <- get_data_type pointer row col
222 helper ty
275 helper ty
223 where
276 where
224− get_data_type_v2 : Ptr ->Int -> Int -> IO Int
277+ get_data_type : 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
278+ get_data_type pointer row col =mkForeign (FFun "sqlite3_get_data_type" [FPtr, FInt, FInt] FInt)pointer row col
226
279
227 get_data_val_int : Ptr -> Int -> IO Int
280 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
229
282
230 get_data_val_text : Ptr -> Int -> IO String
283 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
232
285
233
286
234
287
235 get_data_val_float : Ptr -> Int -> IO Float
288 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
237
290
238 helper : Int -> IO DBVal
291 helper : Int -> IO DBVal
239 helper 1 = do i <- get_data_val_int pointer col ; return (DBInt i)
292 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
241 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)
242 helper _ =return (DBNull)
295 helper _ =return (DBNull)
243
296
244−
297+-----------------------------------------------------------------------------
298+-- | This function makes use of get_data to get all the result.
299+-----------------------------------------------------------------------------
300+
245−toList_v2 : DBPointer -> DB Table
301+toList_v1 : DBPointer -> DB Table
246−toList_v2 db = do
302+toList_v1 db = do
247− nbR <- liftIO (num_row_v2 db)
303+ nbR <- liftIO (num_row_v2 db)
248− nmC <- liftIO (num_col_v2 db)
304+ nmC <- liftIO (num_col_v2 db)
249− res <- forM [0..(nbR-1)] (\ i =>
305+ res <- forM [0..(nbR-1)] (\ i =>
250− forM [0..(nmC-1)] (\ j =>
306+ forM [0..(nmC-1)] (\ j =>
251− liftIO(get_data_v2 db i j)
307+ liftIO(get_data db i j)
252
308
253− )
309+ )
254− )
310+ )
255− return res
311+ return res
256−
312+
257−
313+
258strcat : String -> String-> String
314strcat : String -> String-> String
259strcat str1 str2 = (str1 ++ str2)
315strcat str1 str2 = (str1 ++ str2)
260
316
261−free_table : TBPointer -> IO ()
317+-----------------------------------------------------------------------------
262−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
263− return ()
319+-- This could be removed if not needed in the future.
264−
320+-----------------------------------------------------------------------------
265
321
266−toList : String -> String -> DBPointer -> DB Table
322+--toList_v2 : String -> String -> DBPointer -> DB Table
267−toList name stmt x = do
323+--toList_v2 name stmt x = do
268− ptr <- (get_table x (stmt))
324+-- ptr <- (get_table x (stmt))
269− nbR <- liftIO (num_row ptr)
325+-- nbR <- liftIO (num_row ptr)
270− nmC <- liftIO (num_col ptr)
326+-- nmC <- liftIO (num_col ptr)
271− res <- forM [0..(nbR-1)] (\ i =>
327+-- res <- forM [0..(nbR-1)] (\ i =>
272− forM [0..(nmC-1)] (\ j =>
328+-- forM [0..(nmC-1)] (\ j =>
273− liftIO(get_data x name i j)
329+-- liftIO(get_data x name i j)
274−
330+--
275− )
331+-- )
276− )
332+-- )
277− liftIO (free_table ptr)
333+-- liftIO (free_table ptr)
278− return res
334+-- return res
279−
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+
280−bind_int : StmtPtr -> Int -> Int -> DB Int
343+bind_int : StmtPtr -> Int -> Int -> DB StmtPtr
281−bind_int (MkStmtPtr pointer) indexval val = do
344+bind_int (MkStmtPtr pointer) indexval val = do
282− x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FInt)pointer indexval val)
345+ x <- liftIO(mkForeign (FFun "sqlite3_bind_int_idr" [FPtr, FInt, FInt] FPtr)pointer indexval val)
346+ flag <- liftIO(nullPtr x)
283− if (x /= 0 )
347+ if flag
284 then fail "Could not bind int."
348 then fail "Could not bind int."
285− else return x
349+ else return (MkStmtPtr x)
286−
350+
287
351
288−bind_float : StmtPtr -> Int -> Int -> DB Int
352+bind_float : StmtPtr -> Int -> Float -> DB StmtPtr
289bind_float (MkStmtPtr pointer) indexval val = do
353bind_float (MkStmtPtr pointer) indexval val = do
290− x <- liftIO(mkForeign (FFun "sqlite3_bind_float_idr" [FPtr, FInt, FInt] FInt)pointer indexval val)
354+ x <- liftIO(mkForeign (FFun "sqlite3_bind_float_idr" [FPtr, FInt, FFloat] FPtr)pointer indexval val)
355+ flag <- liftIO(nullPtr x)
291− if (x /= 0)
356+ if flag
292 then fail "Could not bind float."
357 then fail "Could not bind float."
293− else return x
358+ else return (MkStmtPtr x)
294
359
295−bind_text : StmtPtr -> String -> Int -> Int -> DB Int
360+bind_text : StmtPtr -> String -> Int -> Int -> DB StmtPtr
296bind_text (MkStmtPtr pointer) text indexval lengthval = do
361bind_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)
362+ x <- liftIO(mkForeign (FFun "sqlite3_bind_text_idr" [FPtr, FString, FInt, FInt] FPtr)pointer text indexval lengthval)
363+ flag <- liftIO(nullPtr x)
298− if (x /= 0)
364+ if flag
299 then fail "Could not bind text."
365 then fail "Could not bind text."
300− else return x
366+ else return (MkStmtPtr x)
301
367
302−bind_null : StmtPtr -> Int -> DB Int
368+bind_null : StmtPtr -> Int -> DB StmtPtr
303−bind_null (MkStmtPtr pointer) indexval =do
369+bind_null (MkStmtPtr pointer) indexval = do
304− x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FInt)pointer indexval)
370+ x <- liftIO(mkForeign (FFun "sqlite3_bind_null_idr" [FPtr, FInt] FPtr)pointer indexval)
371+ flag <- liftIO(nullPtr x)
305− if (x /= 0)
372+ if flag
306 then fail "Could not bind null."
373 then fail "Could not bind null."
307− else return x
374+ else return (MkStmtPtr x)
375+
376+-----------------------------------------------------------------------------
377+-- | String Length
378+-----------------------------------------------------------------------------
308
379
380+strlen : String -> DB Int
381+strlen str = liftIO(mkForeign (FFun "strLength" [FString] FInt) str)
309
382
310instance Show DBVal where
383instance Show DBVal where
311 show (DBInt i) = "Int val: " ++ show i ++ "\n"
384 show (DBInt i) = "Int val: " ++ show i ++ "\n"
@@ -313,55 +386,23 @@ instance Show DBVal where
313 show (DBFloat i) = "Float val: " ++ show i ++ "\n"
386 show (DBFloat i) = "Float val: " ++ show i ++ "\n"
314 show (DBNull ) = "NULL"
387 show (DBNull ) = "NULL"
315
388
316−print_data_v2 : DBVal -> String
389+-----------------------------------------------------------------------------
317−print_data_v2 = show
390+-- | Multi bind a list of values.
318−
391+-----------------------------------------------------------------------------
319−test : DB()
392+
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
393+bindMulti : StmtPtr-> List (Maybe (Int, Value)) -> DB StmtPtr
341−--bindMulti (MkStmtPtr pointer) [] = (MkStmtPtr pointer)
394+bindMulti pointer [] = return pointer
342−--bindMulti (MkStmtPtr pointer) xs = let newxs = mapping 0 xs in
343−-- case newxs of
344−-- ((_, Nothing):: vs) => bindMulti (MkStmtPtr pointer) vs
395+bindMulti pointer (Nothing :: vs) = bindMulti pointer vs
345−-- ((index, Just v)::vs) => bindMulti(bind pointer index v) vs
396+bindMulti pointer ((Just (indexs, val))::vs) = case val of
346−
397+ (VInt intval) => do x <- bind_int pointer indexs intval
347−testexpr : DB()
398+ bindMulti(x) vs
348−testexpr = do db <- liftIO (open_db "somedb.db")
399+
349− let sql = (evalSQL [] ((SELECT ALL)(TBL "tbl1")(MkCond (Equals (VCol "data")(VInt 1)))))
400+ (VStr strval) => do len <- strlen strval
350− let x = (display sql)
401+ x <- bind_text pointer strval indexs len
351− liftIO(print x)
402+ bindMulti(x) vs
352− stmt <- (prepare_db db "select * from tbl1 where num =?")
403+
353− --let Int(theval) = getval(getlist(sql))
404+
354− bind_int stmt 0 2
405+ (VFloat floatval) => do x <- bind_float pointer indexs floatval
355− exec_db_v2 stmt
406+
356− res <- toList_v2 db
407+ bindMulti(x) vs
357− liftIO(print res)
408+
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−
contribs/lib/SQLite3/sqlite3.texnew file+157
@@ -0,0 +1,157 @@
1+ \documentclass[11pt]{article}
2+ \topmargin -1.5cm
3+ \oddsidemargin -0.04cm
4+ \evensidemargin -0.04cm
5+ \textwidth 16.59cm
6+ \textheight 21.94cm
7+ %\pagestyle{empty}
8+ \parskip 7.2pt
9+ \parindent 0pt
10+
11+ \begin{document}
12+ \section{Introduction}
13+\label{Introduction}
14+This document provides overview on how the Idris library for SQLite3 works. The code base is written on top of the
15+SQLite3 C/C++ Interface.
16+This library supports some features of the low-level library, implemented in a higher level basis.
17+The library allows making use of queries as data types. The aim of this library is to avoid
18+SQL injections which are the most common security issues.
19+To avoid this we have defined a datatype which describes queries.
20+The queries are written using these data types and parsed as quoted string
21+while replacing values with \emph{indexed question mark} to be binded with the prepared statement.
22+This prevents the user from preparing the queries inappropriately by not allowing to pass
23+any types of values directly to the prepare function. However this is a design choice, the library
24+does not prevent the user from passing a String directly to the prepare function.
25+
26+\section{Using the library}
27+\label{Using the library}
28+Simple examples have been provided in the \emph{testunit.idr} file.
29+To open a database, use the open\_db function which takes the filename as a string.
30+This function implements the sqlite3\_open function.
31+This function returns a pointer to the database which can be used by other function
32+to access the database object.
33+Whether or not an error occurs when it is opened,
34+resources should be released by passing it to close\_db when it is no longer required.
35+A query can then be builts using the supported data types.
36+The library supports limited number of queries at the moment. The supported sql commands are :
37+\newline
38+
39+\textbf{SELECT,}
40+\textbf{INSERT,}
41+\textbf{UPDATE,}
42+\textbf{CREATE}
43+
44+\subsection{Creating Queries}
45+\label{Creating Queries}
46+
47+To create a query, use the evalSQL function which takes an empty list and the SQL query.
48+The routine evaluates the expression recrusively by dividing it into smaller parts,
49+filling up the list with the received values. For instance the following is a valid query:
50+
51+let sql = evalSQL [ ] ((SELECT ALL)(TBL ["tbl1"]) (MkCond (MkNULL (VCol "data"))))
52+\newline
53+\newline{This will be parsed as :}
54+\b{“SELECT * FROM tbl1 WHERE data IS NULL “}
55+
56+The evaluator returns a string and a list of indexed values.
57+The string part of the query could be parsed to prepare.
58+\emph{evalSQL} parses the query as a string replacing values with \emph{?} and an index starting from one,
59+storing them in the list given to it as an argument.
60+For example:
61+
62+
63+evalSQL [ ] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"])
64+\newline (MkCond(Equals(VCol "num")(VInt 2))))Empty))
65+
66+is passed to prepare as :
67+
68+SELECT * FROM tbl1 WHERE data = ?1 AND num = ?2 OR num = ?3
69+
70+and returns the list as follows:
71+\newline{(Just (1, VStr "data0")) ,(Just (2, VInt 1)) , (Just (3, VInt 2))}
72+
73+The values in the list are binded to the statement using bindMulti function.
74+This function takes the statement pointer returned by prepare and the list returned by evalSQL
75+and binds the values by calling the appropriate functions.
76+
77+The function exec\_db\_v2 executes the statement.
78+Note that the other version of exec\_db implements the sqlite3\_exec() interface which is a wrapper
79+around sqlite3\_prepare\_v2(), sqlite3\_step(), and sqlite3\_finalize(),
80+without having to use a lot of code, though the use of this function is not recommended in this case.
81+
82+The functions finalize\_db and close\_db must be called to clean up the open resources.
83+To print the result, the function toList\_v1 can be used which takes a DBPointer and returns
84+the resulting table.
85+
86+\subsection{More Examples}
87+\label{More Examples}
88+Nested expressions are also supported. You could write queries such as :
89+
90+evalSQL [ ] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"]) (MkCond (Equals (VCol "num")(VInt 2)))) Empty)
91+
92+Parsed as :
93+
94+SELECT data FROM (SELECT num data FROM tbl1 WHERE num = ?1)
95+
96+Note that in this example, the inner query must include the same column as the outer one otherwise this query will not validate.
97+
98+\subsection{SQL Data Type}
99+\label{SQL Data Type}
100+The SQL Data Types describe the queries that are supported by the library.
101+The implementation of these datatypes is similar to defining a grammar.
102+Data type Value consists of Int, String and Float.
103+The data type can be extended to further support queries.
104+The evaulator function makes use of smaller function to evaulate parts of the query.
105+For instance given a SELECT qeury, it calls \emph{evalSQL} to obtain the list of tables,
106+and clauseString to evaluate the rest of the expression which could include a WHERE clause or could be Empty.
107+
108+
109+\section{Evaluating Queries}
110+\label{Evaluating Queries}
111+The method used here is a divide and conquer manner which divides the query into smaller
112+parts and deals with each part and puts the results together to return a String representation
113+of the query and a list of values.
114+However this could result to a slow type checking process since it needs to go through all
115+the possibilities to type check. Maybe this can be improved?
116+
117+\subsection{evalSQL Function}
118+\label{evalSQL Function}
119+This is a recursive evaluator which makes a call to itself.
120+An SQL could consist of a SELECT ALL or Columns followed by another SQL
121+which could be a nested query or just the name of the table(s).
122+It then call the appropriate functions to evaluate the query.
123+It returns the well-quoted String expression and a list of indexed values which are passed to the bind function.
124+\section{Pointers passed to Idris functions}
125+\label{Pointers passed to Idris functions}
126+
127+The library uses FFI. In order to make the pointers passed to each function more explicit,
128+we have defined them as data types. For instance open\_db takes a String and returns a DBPointer
129+(Database Pointer) and prepare\_db
130+takes a DBPointer and returns a StmtPtr(Statemenet Pointer).
131+Error handling is done using the \emph {DB a} data type which
132+is either \emph {IO String} indicating an error or \emph{ IO a}.
133+To test the functions in main, you need to use runDB :
134+\begin{center}
135+\centering runDB : DB a $\rightarrow$ IO a
136+\end{center}
137+More examples on how to use the functions can be found in \emph{testunit.idr}
138+
139+\section{Using the C Functions}
140+\label{Using the C Functions}
141+The library includes some wrapper functions such as get\_table
142+and exec\_db. Using these functions mixed with prepare, step or finalize
143+inappropriately could cause segmentation faults.
144+Perhaps these functions could be removed from the library if no longer required in the future
145+since the main purpose of this library is to make use of data types.
146+However these functionalities could be implemented internally without calling
147+the C Interface wrapper functions.
148+
149+\section{Further improving the library}
150+\label{Further improving the library}
151+There are many features that could be added to this library. These include adding more useful SQL Commands,
152+extending the SQL datatype to support more complex queries and possibly improving \emph{evalSQL}
153+for a faster performance.
154+Another useful thing to implement is the dot operator(.) which is the member access operator to yield
155+the value of a field in a table. This enables comparing values in different tables and constructing
156+more complex queries.
157+\end{document}
contribs/lib/SQLite3/sqlite3api.c+147−253
@@ -11,10 +11,18 @@
11#include "sqlite3api.h"
11#include "sqlite3api.h"
12
12
13
13
14−
14+// buffer used for storing queries
15+// Used in high-level functions.
15static char sql_query_buffer[2000];
16static char sql_query_buffer[2000];
17+// array used to store the string
18+//value obtain by get_val_text
16unsigned char* array;
19unsigned char* array;
17−
20+/*
21+ open an SQLite database file as
22+ specified by the filename argument.
23+ Returns pointer to DB struct on success
24+ Null on failure.
25+ */
18void* sqlite3_open_idr(const char *filename){
26void* sqlite3_open_idr(const char *filename){
19
27
20 sqlite3 *db;
28 sqlite3 *db;
@@ -29,51 +37,54 @@ void* sqlite3_open_idr(const char *filename){
29 return dbi;
37 return dbi;
30
38
31}
39}
32−
40+/*
41+ Frees the resource and returns 0 on success
42+ */
33int sqlite3_close_idr(void* db){
43int sqlite3_close_idr(void* db){
34
44
35 DBinfo* dbi =(DBinfo*) db;
45 DBinfo* dbi =(DBinfo*) db;
36 int res =sqlite3_close(dbi->db_ptr);
46 int res =sqlite3_close(dbi->db_ptr);
37 if (res == SQLITE_OK){
47 if (res == SQLITE_OK){
38 free(dbi);
48 free(dbi);
39− printf("Successfuly closed the databse\n");
40 return 0;
49 return 0;
41 }
50 }
42−
43− if(res == SQLITE_BUSY){
44− printf("SQL Busy");
45− return 5;
46− }
47−
48 else {
51 else {
49− return 1;
52+ return res;
50 }
53 }
51}
54}
52−
55+/*
56+ SQLite wrapper around sqlite3_prepare_v2(),
57+ sqlite3_step(), and sqlite3_finalize().
58+ This version of exec cannot be used with prepare.
59+ For executing queries, must use the exec_db function.
60+ */
53int sqlite3_exec_idr(void* db, const char *sql)
61int sqlite3_exec_idr(void* db, const char *sql)
54{
62{
55−
56 DBinfo* dbi =(DBinfo*) db;
63 DBinfo* dbi =(DBinfo*) db;
57 char* err;
64 char* err;
58 int rc;
65 int rc;
59−
60 rc = sqlite3_exec(dbi->db_ptr,sql,NULL, NULL, &err);
66 rc = sqlite3_exec(dbi->db_ptr,sql,NULL, NULL, &err);
61− printf("%d\n", rc);
62 if (rc != SQLITE_OK && err != NULL) {
67 if (rc != SQLITE_OK && err != NULL) {
63 strncpy(dbi->buffer, err, sizeof(dbi->buffer));
68 strncpy(dbi->buffer, err, sizeof(dbi->buffer));
64 sqlite3_free(err);
69 sqlite3_free(err);
65 }
70 }
66 return rc;
71 return rc;
67}
72}
68−
73+/*
69−
74+ Gets the error store in the buffer
75+ in the struct. Some certain functions
76+ have the feature to store errors in a buffer.
77+ */
70char* sqlite3_get_error(void* db) {
78char* sqlite3_get_error(void* db) {
71 DBinfo* dbi =(DBinfo*) db;
79 DBinfo* dbi =(DBinfo*) db;
72 return dbi->buffer;
80 return dbi->buffer;
73}
81}
74−
82+/*
83+ Compiles the query into a byte-code program
84+ Returns a pointer to the sqlite3_stmt pointer
85+ and stores it in the struct.
86+ */
75void* sqlite3_prepare_idr(void *db,const char *zSql){
87void* sqlite3_prepare_idr(void *db,const char *zSql){
76−
77 sqlite3_stmt* stmt;
88 sqlite3_stmt* stmt;
78 const char *tail;
89 const char *tail;
79
90
@@ -86,10 +97,15 @@ void* sqlite3_prepare_idr(void *db,const char *zSql){
86 if(rec != SQLITE_OK){
97 if(rec != SQLITE_OK){
87 return NULL;
98 return NULL;
88 }
99 }
89−
90 return dbi;
100 return dbi;
91}
101}
92−
102+/*
103+ Another wrapper interface that is preserved
104+ for backwards compatibility.
105+ Use of this interface is not recommended.
106+ This was mainly used for testing within the
107+ library.
108+ */
93void* sqlite3_get_table_idr(void* db,
109void* sqlite3_get_table_idr(void* db,
94 const char *sql){
110 const char *sql){
95
111
@@ -98,9 +114,7 @@ void* sqlite3_get_table_idr(void* db,
98
114
99 Table* tbl = malloc(sizeof(Table));
115 Table* tbl = malloc(sizeof(Table));
100 tbl->database = dbi;
116 tbl->database = dbi;
101−
102 int res = sqlite3_get_table(dbi->db_ptr,sql,&tbl->table_data,&tbl->num_row,&tbl->num_col,&err);
117 int res = sqlite3_get_table(dbi->db_ptr,sql,&tbl->table_data,&tbl->num_row,&tbl->num_col,&err);
103−
104 int array_size = sizeof(&tbl->table_data);
118 int array_size = sizeof(&tbl->table_data);
105
119
106 if( res != SQLITE_OK && err != NULL){
120 if( res != SQLITE_OK && err != NULL){
@@ -108,12 +122,20 @@ void* sqlite3_get_table_idr(void* db,
108 sqlite3_free(err);
122 sqlite3_free(err);
109 return NULL;
123 return NULL;
110 }
124 }
111−
112 tbl -> data_size = array_size;
125 tbl -> data_size = array_size;
113− return tbl;
126+ return tbl;
114−
115}
127}
116
128
129+/*
130+ This function executes queries.
131+ This can be used after preparing a query
132+ In case of error or library misuse
133+ it returns 1.
134+ It also calls step in order to obtain
135+ the row and column number and stores them
136+ in the struct. The row number is needed
137+ later on in get_data_type function.
138+ */
117int exec_db(void*p){
139int exec_db(void*p){
118
140
119 DBinfo* dbi =(DBinfo*) p;
141 DBinfo* dbi =(DBinfo*) p;
@@ -129,7 +151,6 @@ int exec_db(void*p){
129 if(rc == SQLITE_ERROR && rc == SQLITE_MISUSE){
151 if(rc == SQLITE_ERROR && rc == SQLITE_MISUSE){
130 return 1;
152 return 1;
131 }
153 }
132−
133 row_counter =0;
154 row_counter =0;
134
155
135 while (rc == SQLITE_ROW) {
156 while (rc == SQLITE_ROW) {
@@ -142,44 +163,68 @@ int exec_db(void*p){
142 dbi->row_count = row_counter;
163 dbi->row_count = row_counter;
143 dbi->col_count = col;
164 dbi->col_count = col;
144 return rc;
165 return rc;
145−
146}
166}
147−
167+/*
168+ Returns row number from DB Struct
169+
170+ */
148int sqlite3_get_num_row_v2(void* p){
171int sqlite3_get_num_row_v2(void* p){
149
172
150 DBinfo* dbi =(DBinfo*) p;
173 DBinfo* dbi =(DBinfo*) p;
151 int row_number =dbi->row_count;
174 int row_number =dbi->row_count;
152 return row_number;
175 return row_number;
153−
154−
155}
176}
156
177
178+/*
179+ Returns column number from DB Struct
180+ */
157int sqlite3_get_num_col_v2(void* p){
181int sqlite3_get_num_col_v2(void* p){
158
182
159 DBinfo* dbi =(DBinfo*) p;
183 DBinfo* dbi =(DBinfo*) p;
160 int col_number =dbi-> col_count;
184 int col_number =dbi-> col_count;
161 return col_number;
185 return col_number;
162−
163}
186}
164
187
165−
188+/*
189+ Another way of obtaining row number
190+ Thought this function gets the value
191+ from Table struct. The value is stored
192+ in the struct after calling get_table.
193+ Using this version is not recommended
194+ unless used with get_table
195+ */
166int sqlite3_get_num_row(void* p){
196int sqlite3_get_num_row(void* p){
167
197
168 Table* tbl =(Table*) p;
198 Table* tbl =(Table*) p;
169 int row_number =tbl->num_row;
199 int row_number =tbl->num_row;
170 return row_number;
200 return row_number;
171−
172−
173}
201}
174
202
203+/*
204+ Another way of obtaining column number
205+ Thought this function gets the value
206+ from Table struct. The value is stored
207+ in the struct after calling get_table.
208+ Using this version is not recommended
209+ unless used with get_table
210+ */
175int sqlite3_get_num_col(void* p){
211int sqlite3_get_num_col(void* p){
176
212
177 Table* tbl =(Table*) p;
213 Table* tbl =(Table*) p;
178 int col_number =tbl-> num_col;
214 int col_number =tbl-> num_col;
179− return col_number;
215+ return col_number;
180−
181}
216}
217+
218+/*
219+ This routine returns the type of value
220+ and must be called after prepare and exec.
221+ Since exec steps through database to obtain
222+ row number, this function calls reset to
223+ set the pointer to its initial state
224+ and then calls sqlite3_column_type
225+ to get the type
226+*/
182−int sqlite3_get_data_type_v2(void* p, int nRow, int nCol){
227+int sqlite3_get_data_type(void* p, int nRow, int nCol){
183
228
184 DBinfo* dbi =(DBinfo*) p;
229 DBinfo* dbi =(DBinfo*) p;
185 int rc, type, row_counter;
230 int rc, type, row_counter;
@@ -198,193 +243,37 @@ int sqlite3_get_data_type_v2(void* p, int nRow, int nCol){
198 return type;
243 return type;
199
244
200}
245}
246+/*
247+ Obtains the integer value in a given column
248+*/
201
249
202−
203−int sqlite3_get_val_int_v2(void* p, int nCol){
250+int sqlite3_get_val_int(void* p, int nCol){
204−
205
251
206 DBinfo* dbi =(DBinfo*) p;
252 DBinfo* dbi =(DBinfo*) p;
207 int val, col;
253 int val, col;
208−
209 val =sqlite3_column_int(dbi->ppStmt, nCol);
254 val =sqlite3_column_int(dbi->ppStmt, nCol);
210 return val;
255 return val;
211−
212−
213−}
214−
215−int sqlite3_get_data_type(void* p,const char* tbl_name, int nRow, int nCol){
216−
217− DBinfo* dbi =(DBinfo*) p;
218− sqlite3_stmt* stmt;
219− const char *tail;
220− int rc,i, val, counter;
221− const char* char_int;
222−
223− counter =0;
224− strcpy(sql_query_buffer, "select * from ");
225− strcat(sql_query_buffer, tbl_name);
226−
227− rc = sqlite3_prepare_v2(dbi->db_ptr, sql_query_buffer, -1, &stmt, &tail);
228− if(rc != SQLITE_OK){
229− fprintf(stderr, "SQL Prepare error\n");
230− return rc;
231− }
232− rc = sqlite3_step(stmt);
233−
234− while (rc == SQLITE_ROW && counter < nRow){
235−
236− rc = sqlite3_step(stmt);
237− counter++;
238−
239− }
240−
241− val =sqlite3_column_type(stmt, nCol);
242−
243− rc =sqlite3_finalize(stmt);
244− if( rc != SQLITE_OK){
245− printf("Couldnt finalize:\n");
246− }
247− return val;
248−
249}
256}
250
257
251−
258+/*
252−int sqlite3_get_val_int(void* p,const char* tbl_name, int nRow, int nCol){
259+ Obtains the text value
253−
260+ Need to allocate memory to store the string
254−
261+ Use GC_malloc since Boehm garbage collector
255− DBinfo* dbi =(DBinfo*) p;
262+ frees the resources .
256− sqlite3_stmt* stmt;
263+ */
257− const char *tail;
258− int rc,i, val, counter;
259− const char* char_int;
260−
261− counter =0;
262− strcpy(sql_query_buffer, "select * from ");
263− strcat(sql_query_buffer, tbl_name);
264−
265− rc = sqlite3_prepare_v2(dbi->db_ptr, sql_query_buffer, -1, &stmt, &tail);
266− if(rc != SQLITE_OK){
267− fprintf(stderr, "SQL Prepare error\n");
268− return rc;
269− }
270− rc = sqlite3_step(stmt);
271−
272− while (rc == SQLITE_ROW && counter < nRow){
273−
274− rc = sqlite3_step(stmt);
275− counter++;
276−
277− }
278−
279− val =sqlite3_column_int(stmt, nCol);
280− rc =sqlite3_finalize(stmt);
281− if( rc != SQLITE_OK){
282− printf("Couldnt finalize:\n");
283− }
284− return val;
285−
286−
287−}
288−
289−const unsigned char* sqlite3_get_val_text_v2(void* p,int nCol){
264+const unsigned char* sqlite3_get_val_text(void* p,int nCol){
290
265
291
266
292 DBinfo* dbi =(DBinfo*) p;
267 DBinfo* dbi =(DBinfo*) p;
293 int rc,i, val, counter;
268 int rc,i, val, counter;
294 const unsigned char* text_val;
269 const unsigned char* text_val;
295−
296 array =(unsigned char *) GC_malloc(1000*sizeof(char));
270 array =(unsigned char *) GC_malloc(1000*sizeof(char));
297−
298 text_val =sqlite3_column_text(dbi->ppStmt, nCol);
271 text_val =sqlite3_column_text(dbi->ppStmt, nCol);
299 memcpy(array, text_val, strlen(text_val));
272 memcpy(array, text_val, strlen(text_val));
300− int size = strlen(text_val);
301−
302 return array;
273 return array;
303
274
304}
275}
305−
306−
307−
308−const unsigned char* sqlite3_get_val_text(void* p,const char* tbl_name,int nRow, int nCol){
309−
310−
311− DBinfo* dbi =(DBinfo*) p;
312− sqlite3_stmt* stmt;
313− const char *tail;
314− int rc,i, val, counter;
315− const unsigned char* text_val;
316−
317− counter =0;
318− strcpy(sql_query_buffer, "select * from ");
319− strcat(sql_query_buffer, tbl_name);
320−
321− rc = sqlite3_prepare_v2(dbi->db_ptr, sql_query_buffer, -1, &stmt, &tail);
322− if(rc != SQLITE_OK){
323− fprintf(stderr, "SQL Prepare error\n");
324− return NULL;
325− }
326− rc = sqlite3_step(stmt);
327−
328− while (rc == SQLITE_ROW && counter < nRow){
329−
330− rc = sqlite3_step(stmt);
331− counter++;
332−
333− }
334−
335−
336− array =(unsigned char *) GC_malloc(1000*sizeof(char));
337−
338− text_val =sqlite3_column_text(stmt, nCol);
339− memcpy(array, text_val, sizeof(text_val));
340− rc =sqlite3_finalize(stmt);
341− if( rc != SQLITE_OK){
342− printf("Couldn't finalize.\n");
343− }
344−
345− return array;
346−
347−}
348−
349−
350−float sqlite3_get_float(void* p,const char* tbl_name, int nRow, int nCol){
276+float sqlite3_get_float(void* p, int nCol){
351−
352− DBinfo* dbi =(DBinfo*) p;
353− sqlite3_stmt* stmt;
354− const char *tail;
355− int rc,i, val, counter;
356− double double_val;
357−
358−
359− counter =0;
360− strcpy(sql_query_buffer, "select * from ");
361− strcat(sql_query_buffer, tbl_name);
362−
363− rc = sqlite3_prepare_v2(dbi->db_ptr, sql_query_buffer, -1, &stmt, &tail);
364− if(rc != SQLITE_OK){
365− fprintf(stderr, "SQL Prepare error\n");
366−
367− }
368− rc = sqlite3_step(stmt);
369−
370− while (rc == SQLITE_ROW && counter < nRow){
371−
372−
373− rc = sqlite3_step(stmt);
374− counter++;
375−
376− }
377− double_val =sqlite3_column_double(stmt, nCol);
378− float float_val =(float)double_val;
379− rc =sqlite3_finalize(stmt);
380− if( rc != SQLITE_OK){
381− printf("Couldn't finalize.\n");
382− }
383− return float_val;
384−
385−}
386−
387−float sqlite3_get_float_v2(void* p, int nCol){
388
277
389 DBinfo* dbi =(DBinfo*) p;
278 DBinfo* dbi =(DBinfo*) p;
390 double double_val;
279 double double_val;
@@ -394,37 +283,40 @@ float sqlite3_get_float_v2(void* p, int nCol){
394 return float_val;
283 return float_val;
395
284
396}
285}
397−
286+/*
287+ frees the pointer returned by get_table.
288+ */
398
289
399void sqlite3_free_table_idr(void* db){
290void sqlite3_free_table_idr(void* db){
400 Table* tbl =(Table*) db;
291 Table* tbl =(Table*) db;
401 sqlite3_free_table(tbl->table_data);
292 sqlite3_free_table(tbl->table_data);
402 free(tbl);
293 free(tbl);
403}
294}
404−
405−
406int sqlite3_step_idr(void* db){
295int sqlite3_step_idr(void* db){
407
296
408 DBinfo* dbi =(DBinfo*) db;
297 DBinfo* dbi =(DBinfo*) db;
409 int rc =sqlite3_step(dbi->ppStmt);
298 int rc =sqlite3_step(dbi->ppStmt);
410 return rc;
299 return rc;
411}
300}
412−
301+/*
302+ Binds integer. This returns a pointer
303+ because of the implementation of BindMulti
304+ which binds multiple values
305+ */
413−int sqlite3_bind_int_idr(void* p,int index, int val){
306+void* sqlite3_bind_int_idr(void* p,int index, int val){
414
307
415 DBinfo* dbi =(DBinfo*) p;
308 DBinfo* dbi =(DBinfo*) p;
416 int rc;
309 int rc;
417
310
418− printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(dbi->ppStmt));
419 rc =sqlite3_bind_int(dbi->ppStmt,index,val);
311 rc =sqlite3_bind_int(dbi->ppStmt,index,val);
420 if(rc != SQLITE_OK){
312 if(rc != SQLITE_OK){
421− return 1;
313+ return NULL;
422 }
314 }
423
315
424− return rc;
316+ return dbi;
425}
317}
426
318
427−int sqlite3_bind_float_idr(void* p,int index, float val){
319+void* sqlite3_bind_float_idr(void* p,int index, float val){
428
320
429 DBinfo* dbi =(DBinfo*) p;
321 DBinfo* dbi =(DBinfo*) p;
430 int rc;
322 int rc;
@@ -433,36 +325,42 @@ int sqlite3_bind_float_idr(void* p,int index, float val){
433 rc =sqlite3_bind_double(dbi->ppStmt,index,res);
325 rc =sqlite3_bind_double(dbi->ppStmt,index,res);
434
326
435 if(rc != SQLITE_OK){
327 if(rc != SQLITE_OK){
436− return 1;
328+ return NULL;
437 }
329 }
438−
439− return rc;
330+ return dbi;
440}
331}
441
332
442−int sqlite3_bind_null_idr(void* p,int index){
333+void* sqlite3_bind_null_idr(void* p,int index){
443
334
444 DBinfo* dbi =(DBinfo*) p;
335 DBinfo* dbi =(DBinfo*) p;
445 int rc;
336 int rc;
446 rc =sqlite3_bind_null(dbi->ppStmt,index);
337 rc =sqlite3_bind_null(dbi->ppStmt,index);
447 if(rc != SQLITE_OK){
338 if(rc != SQLITE_OK){
448− return 1;
339+ return NULL;
449 }
340 }
450
341
451− return rc;
342+ return dbi;
452}
343}
453
344
454−int sqlite3_bind_text_idr(void* p,const char* text, int index,int length){
345+void* sqlite3_bind_text_idr(void* p,const char* text, int index,int length){
455
346
456 DBinfo* dbi =(DBinfo*) p;
347 DBinfo* dbi =(DBinfo*) p;
457 int rc;
348 int rc;
458 rc =sqlite3_bind_text(dbi->ppStmt,index,text,length,SQLITE_STATIC);
349 rc =sqlite3_bind_text(dbi->ppStmt,index,text,length,SQLITE_STATIC);
459 if(rc != SQLITE_OK){
350 if(rc != SQLITE_OK){
460− return 1;
351+ return NULL;
461 }
352 }
462
353
463− return rc;
354+ return dbi;
464−
465}
355}
356+/*
357+ Used for testing column count function.
358+ This function prepares query and by passing
359+ select all, gets the count for column number
360+ Could be used for testing. Not recommended to
361+ be used with prepare and exec
362+ */
363+
466int sqlite3_column_count_idr(void* db, const char* tbl_name){
364int sqlite3_column_count_idr(void* db, const char* tbl_name){
467 DBinfo* dbi =(DBinfo*) db;
365 DBinfo* dbi =(DBinfo*) db;
468 sqlite3_stmt* stmt;
366 sqlite3_stmt* stmt;
@@ -490,16 +388,17 @@ int sqlite3_column_count_idr(void* db, const char* tbl_name){
490 return rc;
388 return rc;
491}
389}
492
390
493−
494int sqlite3_data_count_idr(void* db){
391int sqlite3_data_count_idr(void* db){
495
392
496 DBinfo* dbi =(DBinfo*) db;
393 DBinfo* dbi =(DBinfo*) db;
497 int rc = sqlite3_data_count(dbi->ppStmt);
394 int rc = sqlite3_data_count(dbi->ppStmt);
498
395
499 return rc;
396 return rc;
500−
501}
397}
502−
398+/*
399+ Must be called after prepare to clean up
400+ the resources.
401+ */
503int sqlite3_finalize_idr(void* db){
402int sqlite3_finalize_idr(void* db){
504
403
505 DBinfo* dbi=(DBinfo*) db;
404 DBinfo* dbi=(DBinfo*) db;
@@ -511,9 +410,12 @@ int sqlite3_complete_idr(const char *sql){
511
410
512 int rc = sqlite3_complete(sql);
411 int rc = sqlite3_complete(sql);
513 return rc;
412 return rc;
514−
515−
516}
413}
414+
415+/*
416+ Resets a prepared statement pointer
417+ to its initial state
418+ */
517int sqlite3_reset_idr(void* db){
419int sqlite3_reset_idr(void* db){
518
420
519 DBinfo* dbi=(DBinfo*) db;
421 DBinfo* dbi=(DBinfo*) db;
@@ -521,7 +423,10 @@ int sqlite3_reset_idr(void* db){
521 return rc;
423 return rc;
522
424
523}
425}
524−
426+/*
427+ The following routines may be used to
428+ obtain column related information.
429+ */
525const char *sqlite3_column_name_idr(void* db, int N){
430const char *sqlite3_column_name_idr(void* db, int N){
526
431
527 DBinfo* dbi=(DBinfo*) db;
432 DBinfo* dbi=(DBinfo*) db;
@@ -537,8 +442,6 @@ const char *sqlite3_column_decltype_idr(void* db,int n){
537 return dectype;
442 return dectype;
538
443
539}
444}
540−
541−
542int sqlite3_column_bytes_idr(void* db, int n){
445int sqlite3_column_bytes_idr(void* db, int n){
543
446
544 DBinfo* dbi=(DBinfo*) db;
447 DBinfo* dbi=(DBinfo*) db;
@@ -547,7 +450,6 @@ int sqlite3_column_bytes_idr(void* db, int n){
547
450
548
451
549}
452}
550−
551const void *sqlite3_column_blob_idr(void* db, int iCol){
453const void *sqlite3_column_blob_idr(void* db, int iCol){
552 DBinfo* dbi=(DBinfo*) db;
454 DBinfo* dbi=(DBinfo*) db;
553 const void* data =sqlite3_column_blob(dbi-> ppStmt, iCol);
455 const void* data =sqlite3_column_blob(dbi-> ppStmt, iCol);
@@ -567,7 +469,9 @@ int sqlite3_column_int_idr(void* db, int iCol){
567 return res;
469 return res;
568
470
569}
471}
570−
472+/*
473+ Some back up functions
474+ */
571
475
572void* sqlite3_backup_init_idr(void* pDest,
476void* sqlite3_backup_init_idr(void* pDest,
573 const char *zDestName,
477 const char *zDestName,
@@ -595,10 +499,6 @@ int sqlite3_backup_step_idr(void *backup, int nPage){
595
499
596 DBbackup* dbi=(DBbackup*) backup;
500 DBbackup* dbi=(DBbackup*) backup;
597 int res = sqlite3_backup_step(dbi->backup, nPage);
501 int res = sqlite3_backup_step(dbi->backup, nPage);
598−
599− if( res == SQLITE_OK){
600− printf("Backup Success\n");
601− }
602 return res;
502 return res;
603
503
604
504
@@ -627,23 +527,17 @@ int sqlite3_backup_pagecount_idr(void *backup){
627 return res;
527 return res;
628
528
629}
529}
630−
530+/*
631−int sqlite3_value_bytes_idr(void* value){
531+ Get the length of string
632−
532+ Need this in Idris since length will not
633− DBinfo* dbi=(DBinfo*) value;
533+ work on Strings.
634− int res = sqlite3_value_bytes(dbi->value);
534+ */
635− return res;
535+int strLength(const char * str){
636
536
637−}
537+ int length = strlen(str);
638−
538+ return length;
639−int sqlite3_value_bytes16_idr(void* value){
640
539
641− DBinfo* dbi=(DBinfo*) value;
642− int res =sqlite3_value_bytes16(dbi->value);
643− return res;
644
540
645}
541}
646
542
647
543
648−
649−
contribs/lib/SQLite3/sqlite3api.h+19−35
@@ -14,22 +14,25 @@
14#include <gc.h>
14#include <gc.h>
15
15
16typedef struct {
16typedef struct {
17− sqlite3 *db_ptr;
17+ sqlite3 *db_ptr; // database pointer
18− sqlite3_stmt *ppStmt;
18+ sqlite3_stmt *ppStmt; // statement pointer
19− char buffer[1000];
19+ char buffer[1000]; // bufer to store errors returned by certain functions
20 const char *Ptr_tail;
20 const char *Ptr_tail;
21− sqlite3_blob *blob_ptr;
22 sqlite3_value *value;
21 sqlite3_value *value;
23− int row_count;
22+ int row_count; // row number store by exec function
24 int col_count;
23 int col_count;
25
24
26} DBinfo;
25} DBinfo;
27
26
27+// struct used for backup functions
28typedef struct {
28typedef struct {
29 sqlite3 *source_ptr;
29 sqlite3 *source_ptr;
30 sqlite3_backup *backup;
30 sqlite3_backup *backup;
31}DBbackup ;
31}DBbackup ;
32
32
33+// Table struct used by get_table function
34+// stores row and column
35+// returned by get_table
33typedef struct {
36typedef struct {
34 int num_row;
37 int num_row;
35 int num_col;
38 int num_col;
@@ -39,7 +42,6 @@ typedef struct {
39 DBinfo* database;
42 DBinfo* database;
40}Table;
43}Table;
41
44
42−int* int_list ();
43
45
44void* sqlite3_open_idr(const char *filename);
46void* sqlite3_open_idr(const char *filename);
45
47
@@ -51,15 +53,12 @@ int sqlite3_exec_idr(void*, const char *sql);
51
53
52char* sqlite3_get_error(void* db);
54char* sqlite3_get_error(void* db);
53
55
56+const unsigned char* sqlite3_get_val_text(void* p,int nCol);
54
57
55−const unsigned char* sqlite3_get_val_text(void* p,const char* tbl_name,int nRow, int nCol);
56−
57−const unsigned char* sqlite3_get_val_text_v2(void* p,int nCol);
58−
59−float sqlite3_get_float_v2(void* p, int nCol);
60−
61void* sqlite3_get_table_idr(void* db, const char *sql);
58void* sqlite3_get_table_idr(void* db, const char *sql);
62
59
60+void sqlite3_free_table_idr(void* db);
61+
63int sqlite3_get_num_col(void* p);
62int sqlite3_get_num_col(void* p);
64
63
65int sqlite3_get_num_row(void* p);
64int sqlite3_get_num_row(void* p);
@@ -68,19 +67,11 @@ int sqlite3_get_num_row_v2(void* p);
68
67
69int sqlite3_get_num_col_v2(void* p);
68int sqlite3_get_num_col_v2(void* p);
70
69
71−void* sqlite3_get_data(void* p, int nRow, int nCol);
72−
73−int sqlite3_get_data_type(void* p,const char* tbl_name,int nRow, int nCol);
70+int sqlite3_get_data_type(void* p, int nRow, int nCol);
74−
75−int sqlite3_get_data_type_v2(void* p, int nRow, int nCol);
76
71
77−int sqlite3_get_val_int_v2(void* p,int nCo);
72+int sqlite3_get_val_int(void* p,int nCo);
78
73
79−int sqlite3_get_val_int(void* p,const char* tbl_name, int nRow, int nCol);
80−
81−float sqlite3_get_float(void* p,const char* tbl_name, int nRow, int nCol);
74+float sqlite3_get_float(void* p, int nCol);
82−
83−void sqlite3_free_table_idr(void* db);
84
75
85void* sqlite3_prepare_idr(
76void* sqlite3_prepare_idr(
86 void *db, /* Database handle */
77 void *db, /* Database handle */
@@ -89,15 +80,13 @@ void* sqlite3_prepare_idr(
89
80
90int sqlite3_step_idr(void* stmt);
81int sqlite3_step_idr(void* stmt);
91
82
92−int sqlite3_bind_float_idr(void* p,int index, float val);
83+void* sqlite3_bind_float_idr(void* p,int index, float val);
93−
94−int sqlite3_bind_int_idr(void* p,int index , int val);
95
84
96−int sqlite3_bind_int_idr_v2(void* p,int index , int val);
85+void* sqlite3_bind_int_idr(void* p,int index , int val);
97
86
98−int sqlite3_bind_null_idr(void* p,int index);
87+void* sqlite3_bind_null_idr(void* p,int index);
99
88
100−int sqlite3_bind_text_idr(void* p,const char* text, int index,int length);
89+void* sqlite3_bind_text_idr(void* p,const char* text, int index,int length);
101
90
102int sqlite3_column_count_idr(void* stmt, const char* tbl_name);
91int sqlite3_column_count_idr(void* stmt, const char* tbl_name);
103
92
@@ -138,9 +127,4 @@ int sqlite3_backup_remaining_idr(void *backup);
138
127
139int sqlite3_backup_pagecount_idr(void *backup);
128int sqlite3_backup_pagecount_idr(void *backup);
140
129
141−int sqlite3_value_bytes_idr(void* value);
130+int strLength(const char * str);
142−
143−int sqlite3_value_bytes16_idr(void* value);
144−
145−int sqlite3_errcode(sqlite3 *db);
146−
contribs/lib/SQLite3/testunit.idrnew file+140
@@ -0,0 +1,140 @@
1+module main
2+import sqlite3
3+
4+
5+testexpr : DB()
6+testexpr = do db <- open_db "somedb.db"
7+ 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))))))
8+ let x = (fst sql) -- get the string
9+ let list = (snd sql) -- list of vals
10+ liftIO(print x) -- use liftIO to turn this into DB type
11+ stmt <- (prepare_db db x) -- prepare the statement
12+ bindMulti stmt list -- bind the values in the list
13+ exec_db_v2 stmt -- execute the prepared query
14+ res <- toList_v1 db -- toList_v1 to get the result
15+ liftIO(print res) -- print the result
16+ finalize_db stmt -- Statment pointer must be finalized in the end
17+ close_db db -- close the datbase
18+ return ()
19+
20+testupdate : DB()
21+testupdate = do db <- open_db "somedb.db"
22+ let sql = (evalSQL [] (UPDATE (TBL ["tbl1"]) (WHERE (SET (MkCond (Equals(VCol "data") (VStr "data600"))) ) (MkCond (Equals (VCol "num") (VInt 2))) ) ))
23+ let x = (fst sql)
24+ let list = (snd sql)
25+ liftIO(print x)
26+ stmt <- (prepare_db db x)
27+ bindMulti stmt list
28+ exec_db_v2 stmt
29+ finalize_db stmt
30+ close_db db
31+ return ()
32+
33+testInsert : DB()
34+testInsert = do db <- open_db "somedb.db"
35+ let sql = (evalSQL [] (INSERT (TBL ["tbl1"]) [(VInt 3),(VStr "ham")]))
36+ let x = (fst sql)
37+ let list = (snd sql)
38+ liftIO(print x)
39+ stmt <- (prepare_db db x)
40+ bindMulti stmt list
41+ exec_db_v2 stmt
42+ finalize_db stmt
43+ close_db db
44+ return ()
45+
46+testNull : DB()
47+testNull = do db <- open_db "somedb.db"
48+ let sql = (evalSQL [] ((SELECT ALL)(TBL ["tbl1"]) (MkCond (MkNULL (VCol "data")))))
49+ let x = (fst sql)
50+ let list = (snd sql)
51+ liftIO(print x)
52+ stmt <- (prepare_db db x)
53+ bindMulti stmt list
54+ exec_db_v2 stmt
55+ res <- toList_v1 db
56+ liftIO(print res)
57+ finalize_db stmt
58+ close_db db
59+ return ()
60+
61+
62+testInsertWithCond : DB()
63+testInsertWithCond = do db <- open_db "somedb.db"
64+ let sql = (evalSQL [] (INSERTC (TBL ["tbl1"]) [(VCol "data"),(VCol "num")] [(VInt 30),(VStr "inserthere")]))
65+ let x = (fst sql)
66+ let list = (snd sql)
67+ liftIO(print x)
68+ stmt <- (prepare_db db x)
69+ bindMulti stmt list
70+ exec_db_v2 stmt
71+ finalize_db stmt
72+ close_db db
73+ return ()
74+
75+-- Nested queries need to have the same column as the outer queries.
76+testNestedSel1 : DB()
77+testNestedSel1 = do db <- open_db "somedb.db"
78+ let sql = (evalSQL [] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"]) (MkCond (MkGT (VCol "num")(VInt 2))))Empty))
79+ let x = (fst sql)
80+ let list = (snd sql)
81+ liftIO(print x)
82+ stmt <- (prepare_db db x)
83+ bindMulti stmt list
84+ exec_db_v2 stmt
85+ res <- toList_v1 db
86+ liftIO(print res)
87+ finalize_db stmt
88+ close_db db
89+ return ()
90+
91+-- Testing Create Table
92+testCreateTable : DB ()
93+testCreateTable = do db <- open_db "somedb.db"
94+ let sql = (evalSQL [] (CREATE (TBL ["mynewtbl"]) [ ((VCol "col"),(CInt "int"),(None)) ] ) )
95+ let x = (fst sql)
96+ let list = (snd sql)
97+ liftIO(print x)
98+ stmt <- (prepare_db db x)
99+ bindMulti stmt list
100+ exec_db_v2 stmt
101+ finalize_db stmt
102+ close_db db
103+ return ()
104+
105+-- This may be a bit slow
106+testMultiTable : DB ()
107+testMultiTable = do db <- open_db "somedb.db"
108+ let sql = (evalSQL [] ((SELECT ALL )(TBL ["mytable","tbl1"]) (Empty) ) )
109+ let x = (fst sql)
110+ let list = (snd sql)
111+ liftIO(print x)
112+ stmt <- (prepare_db db x)
113+ bindMulti stmt list
114+ exec_db_v2 stmt
115+ res <- toList_v1 db
116+ liftIO(print res)
117+ finalize_db stmt
118+ close_db db
119+ return ()
120+
121+testSelAll : DB ()
122+testSelAll = do db <- open_db "somedb.db"
123+ let sql = (evalSQL [] ((SELECT ALL )(TBL ["tbl1"]) (Empty) ) )
124+ let x = (fst sql)
125+ let list = (snd sql)
126+ liftIO(print x)
127+ stmt <- (prepare_db db x)
128+ bindMulti stmt list
129+ exec_db_v2 stmt
130+ res <- toList_v1 db
131+ liftIO(print res)
132+ finalize_db stmt
133+ close_db db
134+ return ()
135+
136+
137+main : IO ()
138+main = do x <- runDB (testMultiTable) -- runDB : DB a -> IO a
139+ --y <- runDB (testNestedSel1)
140+ return ()