on master help sign in
Merge pull request #40 from melissam/master

Latest Version

commit2b755fd8f31c318dd7b5a8b441026f974b453470 authorEdwin Brady <edwin.brady@gmail.com> dateFri 10 Aug 2012, 10:42 (14 years ago) parent0bb157efed637d
13 files changed+875−516
contribs/lib/SQLite3/._Makefile contribs/lib/SQLite3/._sqlexpr.idr contribs/lib/SQLite3/._sqlite3.idr contribs/lib/SQLite3/._sqlite3api.c contribs/lib/SQLite3/._sqlite3api.h contribs/lib/SQLite3/._testunit.idr contribs/lib/SQLite3/Makefile+3−2 contribs/lib/SQLite3/sqlexpr.idr+189−47 contribs/lib/SQLite3/sqlite3.idr+220−179 contribs/lib/SQLite3/sqlite3.tex+157 contribs/lib/SQLite3/sqlite3api.c+147−253 contribs/lib/SQLite3/sqlite3api.h+19−35 contribs/lib/SQLite3/testunit.idr+140
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 @@
33
44.PHONY: all
55
6−sqltest : sqlite3.idr sqlite3api.o
7− idris sqlite3.idr -o sqltest
6+sqltest : testunit.idr sqlite3.idr sqlite3api.o
7+ idris testunit.idr -o sqltest
88
99sqlite3api.o : sqlite3api.c
1010 gcc -c sqlite3api.c
1111
1212all : sqltest sqlite3api.o
13+
contribs/lib/SQLite3/sqlexpr.idr+189−47
@@ -1,36 +1,71 @@
1−module main
1+module sqlexpr
22import prelude.list
33
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+
414-----------------------------------------------------------
5−-- * SQL data type
15+-- | SQL data type
616-----------------------------------------------------------
717
818data Value = VInt Int
919 |VStr String
20+ |VFloat Float
1021 |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.
1128
1229data Cond = Equals Value Value
1330 |MkGT Value Value
1431 |MkGTE Value Value
1532 |MkLT Value Value
1633 |MkLTE Value Value
17−--TODO |MkIN (List Value)
18−--TODO |MkIN SQL
34+ |MkNULL Value
1935
20−
36+
2137data Clause = MkCond Cond
2238 | AND Clause Clause
2339 | OR Clause Clause
2440 | Empty
41+ | MkSQL SQL
42+
43+data condClause = SET Clause
44+ |WHERE condClause Clause
2545
2646data SelVar = Cols (List String)
2747 |ALL
2848
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+
2961data SQL = SELECT SelVar SQL Clause
30− | TBL String
62+ | TBL (List String)
3163 | INSERT SQL (List Value)
64+ | INSERTC SQL (List Value) (List Value)
65+ | UPDATE SQL condClause
66+ | CREATE SQL (List (Value, ColType , Constr))
3267
33−
68+-- remember to remove these funcs later
3469foldr1 : (a -> a -> a) -> List a -> a
3570foldr1 f [x] = x
3671foldr1 f (x::xs) = f x (foldr1 f xs)
@@ -47,46 +82,115 @@ unwords' ws = (foldr1 addSpace ws)
4782unwords : List String -> String
4883unwords = pack . unwords' . map unpack
4984
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+-----------------------------------------------------------
50119
51−mapping : Int -> List a -> List (Int, a)
52−mapping counter [] = []
53−mapping counter (x :: xs) = (counter, x) :: mapping (counter + 1) xs
120+getConstr : List (Maybe(Int, Value)) -> Constr -> (String, List (Maybe(Int, Value)))
121+getConstr xs (NOTNULL) = ("NOT NULL", 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)
54128
129+putBrackets : String -> String
130+putBrackets str = "(" ++ str ++ ")"
55131
56−popintoList : Maybe Value -> List (Maybe Value) -> List (Maybe Value)
57−popintoList (Just x) [] = [(Just x)]
58−popintoList (Just (x)) ((Just x) :: xs) = (popintoList (Just x) xs)
59−popintoList Nothing [] = []
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+
144+listValType : List (Maybe(Int, Value)) -> List (Value, ColType , Constr) -> (String, List (Maybe(Int, Value)))
145+listValType xs [] = ("", xs)
146+listValType xs ((val, types, constr) :: vs) = let (str , newxs) = valString xs val in
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)
60151
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)
65152
153+-----------------------------------------------------------
154+-- | Evaluates a conditional WHERE clause
155+-----------------------------------------------------------
66156
67−evalCond : List (Maybe Value) -> Cond -> (String, List (Maybe Value))
157+evalCond : List (Maybe(Int, Value)) -> Cond -> (String, List (Maybe(Int, Value)))
68158evalCond xs (Equals val1 val2) = let (restring , newxs ) = valString xs val1 in
69159 let (restring2, newxs') = valString newxs val2 in
70− (restring ++ " = " ++ restring2, (newxs ++ newxs'))
160+ (restring ++ " = " ++ restring2, newxs')
71161
72162evalCond xs (MkGT val1 val2) = let (restring , newxs ) = valString xs val1 in
73163 let (restring2, newxs') = valString newxs val2 in
74− (restring ++ " > " ++ restring2, (newxs ++ newxs'))
164+ (restring ++ " > " ++ restring2, newxs')
75165
76166evalCond xs (MkGTE val1 val2) = let (restring , newxs ) = valString xs val1 in
77167 let (restring2, newxs') = valString newxs val2 in
78− (restring ++ " >= " ++ restring2, (newxs ++ newxs'))
168+ (restring ++ " >= " ++ restring2, newxs')
79169
80170evalCond xs (MkLT val1 val2) = let (restring , newxs ) = valString xs val1 in
81171 let (restring2, newxs') = valString newxs val2 in
82− (restring ++ " < " ++ restring2, (newxs ++ newxs'))
172+ (restring ++ " < " ++ restring2, newxs')
83173
84174evalCond xs (MkLTE val1 val2) = let (restring , newxs ) = valString xs val1 in
85175 let (restring2, newxs') = valString newxs val2 in
86− (restring ++ " =< " ++ restring2, (newxs ++ newxs'))
176+ (restring ++ " =< " ++ restring2, newxs')
87177
88−
89−clauseString : List (Maybe Value) -> Clause -> (String, List (Maybe Value))
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+-----------------------------------------------------------
192+clauseString : List (Maybe(Int, Value)) -> Clause -> (String, List (Maybe(Int, Value)))
193+
90194clauseString xs (Empty) = ("" , []) -- No condition
91195clauseString xs (MkCond cond') = let (condstr, newxs) = evalCond xs cond' in
92196 (condstr , newxs)
@@ -99,34 +203,72 @@ clauseString xs (OR c1 c2) = let (clausestr, newxs) = clauseString xs c1 in
99203 let (clausestr2, newxs') = clauseString newxs c2 in
100204 (clausestr ++ " OR " ++clausestr2 , newxs')
101205
102−
103−varString : List String -> String
104−varString xs = (unwords xs)
105−
106−
107−evalSQL : List (Maybe Value) -> SQL -> ( String, List (Maybe Value))
108−evalSQL xs (TBL tbl) = (tbl, xs)
206+
207+-----------------------------------------------------------
208+-- | Evaluates conditional clauses.
209+-----------------------------------------------------------
210+
211+condClauseStr : List (Maybe(Int, Value)) -> condClause -> (String, List (Maybe(Int, Value)))
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)
109228evalSQL xs (SELECT vars sql' c) = let (sqlstring, newxs) = evalSQL xs sql' in
110229 let (csstring, newxs') = clauseString newxs c in
111230 case c of
112231 Empty => case vars of
113− (ALL ) => ("SELECT " ++ "*" ++ " FROM (" ++ sqlstring ++ ") " ++ csstring, map snd ( mapping 0 newxs'))
114− (Cols selvar) => ("SELECT " ++ unwords ( intersperse "" ( selvar ++ (words ( " FROM (" ++ sqlstring ++ ")")))) ++ csstring, map snd ( mapping 0 newxs'))
232+ (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
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')
115243
116244 _ => case vars of
117− (ALL ) => ("SELECT " ++ "*" ++ " FROM (" ++ sqlstring ++ ") " ++ "WHERE" ++ csstring, map snd ( mapping 0 newxs'))
118− (Cols selvar) => ("SELECT " ++ unwords ( intersperse "" ( selvar ++ (words ( " FROM (" ++ sqlstring ++ ")")))) ++ "WHERE" ++ csstring, map snd ( mapping 0 newxs'))
245+ (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
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)
119261
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)
120266
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)
128267
129−main : IO ()
130−main = print (display(evalSQL [] ((SELECT ALL)(TBL "tbl") (MkCond (Equals (VCol "col")(VInt 1))))))
268+evalSQL xs (UPDATE sql cl) = let (tblname, newxs) = evalSQL xs sql in
269+ let (csstring, newxs') = condClauseStr newxs cl in
270+ ("UPDATE " ++ tblname ++ csstring, newxs')
131271
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
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+
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 @@
1111#include "sqlite3api.h"
1212
1313
14−
14+// buffer used for storing queries
15+// Used in high-level functions.
1516static char sql_query_buffer[2000];
17+// array used to store the string
18+//value obtain by get_val_text
1619unsigned 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+ */
1826void* sqlite3_open_idr(const char *filename){
1927
2028 sqlite3 *db;
@@ -29,51 +37,54 @@ void* sqlite3_open_idr(const char *filename){
2937 return dbi;
3038
3139}
32−
40+/*
41+ Frees the resource and returns 0 on success
42+ */
3343int sqlite3_close_idr(void* db){
3444
3545 DBinfo* dbi =(DBinfo*) db;
3646 int res =sqlite3_close(dbi->db_ptr);
3747 if (res == SQLITE_OK){
3848 free(dbi);
39− printf("Successfuly closed the databse\n");
4049 return 0;
4150 }
42−
43− if(res == SQLITE_BUSY){
44− printf("SQL Busy");
45− return 5;
46− }
47−
4851 else {
49− return 1;
52+ return res;
5053 }
5154}
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+ */
5361int sqlite3_exec_idr(void* db, const char *sql)
5462{
55−
5663 DBinfo* dbi =(DBinfo*) db;
5764 char* err;
5865 int rc;
59−
6066 rc = sqlite3_exec(dbi->db_ptr,sql,NULL, NULL, &err);
61− printf("%d\n", rc);
6267 if (rc != SQLITE_OK && err != NULL) {
6368 strncpy(dbi->buffer, err, sizeof(dbi->buffer));
6469 sqlite3_free(err);
6570 }
6671 return rc;
6772}
68−
69−
73+/*
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+ */
7078char* sqlite3_get_error(void* db) {
7179 DBinfo* dbi =(DBinfo*) db;
7280 return dbi->buffer;
7381}
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+ */
7587void* sqlite3_prepare_idr(void *db,const char *zSql){
76−
7788 sqlite3_stmt* stmt;
7889 const char *tail;
7990
@@ -86,10 +97,15 @@ void* sqlite3_prepare_idr(void *db,const char *zSql){
8697 if(rec != SQLITE_OK){
8798 return NULL;
8899 }
89−
90100 return dbi;
91101}
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+ */
93109void* sqlite3_get_table_idr(void* db,
94110 const char *sql){
95111
@@ -98,9 +114,7 @@ void* sqlite3_get_table_idr(void* db,
98114
99115 Table* tbl = malloc(sizeof(Table));
100116 tbl->database = dbi;
101−
102117 int res = sqlite3_get_table(dbi->db_ptr,sql,&tbl->table_data,&tbl->num_row,&tbl->num_col,&err);
103−
104118 int array_size = sizeof(&tbl->table_data);
105119
106120 if( res != SQLITE_OK && err != NULL){
@@ -108,12 +122,20 @@ void* sqlite3_get_table_idr(void* db,
108122 sqlite3_free(err);
109123 return NULL;
110124 }
111−
112125 tbl -> data_size = array_size;
113− return tbl;
114−
126+ return tbl;
115127}
116128
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+ */
117139int exec_db(void*p){
118140
119141 DBinfo* dbi =(DBinfo*) p;
@@ -129,7 +151,6 @@ int exec_db(void*p){
129151 if(rc == SQLITE_ERROR && rc == SQLITE_MISUSE){
130152 return 1;
131153 }
132−
133154 row_counter =0;
134155
135156 while (rc == SQLITE_ROW) {
@@ -142,44 +163,68 @@ int exec_db(void*p){
142163 dbi->row_count = row_counter;
143164 dbi->col_count = col;
144165 return rc;
145−
146166}
147−
167+/*
168+ Returns row number from DB Struct
169+
170+ */
148171int sqlite3_get_num_row_v2(void* p){
149172
150173 DBinfo* dbi =(DBinfo*) p;
151174 int row_number =dbi->row_count;
152175 return row_number;
153−
154−
155176}
156177
178+/*
179+ Returns column number from DB Struct
180+ */
157181int sqlite3_get_num_col_v2(void* p){
158182
159183 DBinfo* dbi =(DBinfo*) p;
160184 int col_number =dbi-> col_count;
161185 return col_number;
162−
163186}
164187
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+ */
166196int sqlite3_get_num_row(void* p){
167197
168198 Table* tbl =(Table*) p;
169199 int row_number =tbl->num_row;
170200 return row_number;
171−
172−
173201}
174202
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+ */
175211int sqlite3_get_num_col(void* p){
176212
177213 Table* tbl =(Table*) p;
178214 int col_number =tbl-> num_col;
179− return col_number;
180−
215+ return col_number;
181216}
182−int sqlite3_get_data_type_v2(void* p, int nRow, int nCol){
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+*/
227+int sqlite3_get_data_type(void* p, int nRow, int nCol){
183228
184229 DBinfo* dbi =(DBinfo*) p;
185230 int rc, type, row_counter;
@@ -198,193 +243,37 @@ int sqlite3_get_data_type_v2(void* p, int nRow, int nCol){
198243 return type;
199244
200245}
246+/*
247+ Obtains the integer value in a given column
248+*/
201249
202−
203−int sqlite3_get_val_int_v2(void* p, int nCol){
204−
250+int sqlite3_get_val_int(void* p, int nCol){
205251
206252 DBinfo* dbi =(DBinfo*) p;
207253 int val, col;
208−
209254 val =sqlite3_column_int(dbi->ppStmt, nCol);
210255 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−
249256}
250257
251−
252−int sqlite3_get_val_int(void* p,const char* tbl_name, int nRow, int nCol){
253−
254−
255− DBinfo* dbi =(DBinfo*) p;
256− sqlite3_stmt* stmt;
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){
258+/*
259+ Obtains the text value
260+ Need to allocate memory to store the string
261+ Use GC_malloc since Boehm garbage collector
262+ frees the resources .
263+ */
264+const unsigned char* sqlite3_get_val_text(void* p,int nCol){
290265
291266
292267 DBinfo* dbi =(DBinfo*) p;
293268 int rc,i, val, counter;
294269 const unsigned char* text_val;
295−
296270 array =(unsigned char *) GC_malloc(1000*sizeof(char));
297−
298271 text_val =sqlite3_column_text(dbi->ppStmt, nCol);
299272 memcpy(array, text_val, strlen(text_val));
300− int size = strlen(text_val);
301−
302273 return array;
303274
304275}
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){
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){
276+float sqlite3_get_float(void* p, int nCol){
388277
389278 DBinfo* dbi =(DBinfo*) p;
390279 double double_val;
@@ -394,37 +283,40 @@ float sqlite3_get_float_v2(void* p, int nCol){
394283 return float_val;
395284
396285}
397−
286+/*
287+ frees the pointer returned by get_table.
288+ */
398289
399290void sqlite3_free_table_idr(void* db){
400291 Table* tbl =(Table*) db;
401292 sqlite3_free_table(tbl->table_data);
402293 free(tbl);
403294}
404−
405−
406295int sqlite3_step_idr(void* db){
407296
408297 DBinfo* dbi =(DBinfo*) db;
409298 int rc =sqlite3_step(dbi->ppStmt);
410299 return rc;
411300}
412−
413−int sqlite3_bind_int_idr(void* p,int index, int val){
301+/*
302+ Binds integer. This returns a pointer
303+ because of the implementation of BindMulti
304+ which binds multiple values
305+ */
306+void* sqlite3_bind_int_idr(void* p,int index, int val){
414307
415308 DBinfo* dbi =(DBinfo*) p;
416309 int rc;
417310
418− printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(dbi->ppStmt));
419311 rc =sqlite3_bind_int(dbi->ppStmt,index,val);
420312 if(rc != SQLITE_OK){
421− return 1;
313+ return NULL;
422314 }
423315
424− return rc;
316+ return dbi;
425317}
426318
427−int sqlite3_bind_float_idr(void* p,int index, float val){
319+void* sqlite3_bind_float_idr(void* p,int index, float val){
428320
429321 DBinfo* dbi =(DBinfo*) p;
430322 int rc;
@@ -433,36 +325,42 @@ int sqlite3_bind_float_idr(void* p,int index, float val){
433325 rc =sqlite3_bind_double(dbi->ppStmt,index,res);
434326
435327 if(rc != SQLITE_OK){
436− return 1;
328+ return NULL;
437329 }
438−
439− return rc;
330+ return dbi;
440331}
441332
442−int sqlite3_bind_null_idr(void* p,int index){
333+void* sqlite3_bind_null_idr(void* p,int index){
443334
444335 DBinfo* dbi =(DBinfo*) p;
445336 int rc;
446337 rc =sqlite3_bind_null(dbi->ppStmt,index);
447338 if(rc != SQLITE_OK){
448− return 1;
339+ return NULL;
449340 }
450341
451− return rc;
342+ return dbi;
452343}
453344
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){
455346
456347 DBinfo* dbi =(DBinfo*) p;
457348 int rc;
458349 rc =sqlite3_bind_text(dbi->ppStmt,index,text,length,SQLITE_STATIC);
459350 if(rc != SQLITE_OK){
460− return 1;
351+ return NULL;
461352 }
462353
463− return rc;
464−
354+ return dbi;
465355}
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+
466364int sqlite3_column_count_idr(void* db, const char* tbl_name){
467365 DBinfo* dbi =(DBinfo*) db;
468366 sqlite3_stmt* stmt;
@@ -490,16 +388,17 @@ int sqlite3_column_count_idr(void* db, const char* tbl_name){
490388 return rc;
491389}
492390
493−
494391int sqlite3_data_count_idr(void* db){
495392
496393 DBinfo* dbi =(DBinfo*) db;
497394 int rc = sqlite3_data_count(dbi->ppStmt);
498395
499396 return rc;
500−
501397}
502−
398+/*
399+ Must be called after prepare to clean up
400+ the resources.
401+ */
503402int sqlite3_finalize_idr(void* db){
504403
505404 DBinfo* dbi=(DBinfo*) db;
@@ -511,9 +410,12 @@ int sqlite3_complete_idr(const char *sql){
511410
512411 int rc = sqlite3_complete(sql);
513412 return rc;
514−
515−
516413}
414+
415+/*
416+ Resets a prepared statement pointer
417+ to its initial state
418+ */
517419int sqlite3_reset_idr(void* db){
518420
519421 DBinfo* dbi=(DBinfo*) db;
@@ -521,7 +423,10 @@ int sqlite3_reset_idr(void* db){
521423 return rc;
522424
523425}
524−
426+/*
427+ The following routines may be used to
428+ obtain column related information.
429+ */
525430const char *sqlite3_column_name_idr(void* db, int N){
526431
527432 DBinfo* dbi=(DBinfo*) db;
@@ -537,8 +442,6 @@ const char *sqlite3_column_decltype_idr(void* db,int n){
537442 return dectype;
538443
539444}
540−
541−
542445int sqlite3_column_bytes_idr(void* db, int n){
543446
544447 DBinfo* dbi=(DBinfo*) db;
@@ -547,7 +450,6 @@ int sqlite3_column_bytes_idr(void* db, int n){
547450
548451
549452}
550−
551453const void *sqlite3_column_blob_idr(void* db, int iCol){
552454 DBinfo* dbi=(DBinfo*) db;
553455 const void* data =sqlite3_column_blob(dbi-> ppStmt, iCol);
@@ -567,7 +469,9 @@ int sqlite3_column_int_idr(void* db, int iCol){
567469 return res;
568470
569471}
570−
472+/*
473+ Some back up functions
474+ */
571475
572476void* sqlite3_backup_init_idr(void* pDest,
573477 const char *zDestName,
@@ -595,10 +499,6 @@ int sqlite3_backup_step_idr(void *backup, int nPage){
595499
596500 DBbackup* dbi=(DBbackup*) backup;
597501 int res = sqlite3_backup_step(dbi->backup, nPage);
598−
599− if( res == SQLITE_OK){
600− printf("Backup Success\n");
601− }
602502 return res;
603503
604504
@@ -627,23 +527,17 @@ int sqlite3_backup_pagecount_idr(void *backup){
627527 return res;
628528
629529}
630−
631−int sqlite3_value_bytes_idr(void* value){
632−
633− DBinfo* dbi=(DBinfo*) value;
634− int res = sqlite3_value_bytes(dbi->value);
635− return res;
530+/*
531+ Get the length of string
532+ Need this in Idris since length will not
533+ work on Strings.
534+ */
535+int strLength(const char * str){
636536
637−}
638−
639−int sqlite3_value_bytes16_idr(void* value){
537+ int length = strlen(str);
538+ return length;
640539
641− DBinfo* dbi=(DBinfo*) value;
642− int res =sqlite3_value_bytes16(dbi->value);
643− return res;
644540
645541}
646542
647543
648−
649−
contribs/lib/SQLite3/sqlite3api.h+19−35
@@ -14,22 +14,25 @@
1414#include <gc.h>
1515
1616typedef struct {
17− sqlite3 *db_ptr;
18− sqlite3_stmt *ppStmt;
19− char buffer[1000];
17+ sqlite3 *db_ptr; // database pointer
18+ sqlite3_stmt *ppStmt; // statement pointer
19+ char buffer[1000]; // bufer to store errors returned by certain functions
2020 const char *Ptr_tail;
21− sqlite3_blob *blob_ptr;
2221 sqlite3_value *value;
23− int row_count;
22+ int row_count; // row number store by exec function
2423 int col_count;
2524
2625} DBinfo;
2726
27+// struct used for backup functions
2828typedef struct {
2929 sqlite3 *source_ptr;
3030 sqlite3_backup *backup;
3131}DBbackup ;
3232
33+// Table struct used by get_table function
34+// stores row and column
35+// returned by get_table
3336typedef struct {
3437 int num_row;
3538 int num_col;
@@ -39,7 +42,6 @@ typedef struct {
3942 DBinfo* database;
4043}Table;
4144
42−int* int_list ();
4345
4446void* sqlite3_open_idr(const char *filename);
4547
@@ -51,15 +53,12 @@ int sqlite3_exec_idr(void*, const char *sql);
5153
5254char* sqlite3_get_error(void* db);
5355
56+const unsigned char* sqlite3_get_val_text(void* p,int nCol);
5457
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−
6158void* sqlite3_get_table_idr(void* db, const char *sql);
6259
60+void sqlite3_free_table_idr(void* db);
61+
6362int sqlite3_get_num_col(void* p);
6463
6564int sqlite3_get_num_row(void* p);
@@ -68,19 +67,11 @@ int sqlite3_get_num_row_v2(void* p);
6867
6968int sqlite3_get_num_col_v2(void* p);
7069
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);
74−
75−int sqlite3_get_data_type_v2(void* p, int nRow, int nCol);
70+int sqlite3_get_data_type(void* p, int nRow, int nCol);
7671
77−int sqlite3_get_val_int_v2(void* p,int nCo);
72+int sqlite3_get_val_int(void* p,int nCo);
7873
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);
82−
83−void sqlite3_free_table_idr(void* db);
74+float sqlite3_get_float(void* p, int nCol);
8475
8576void* sqlite3_prepare_idr(
8677 void *db, /* Database handle */
@@ -89,15 +80,13 @@ void* sqlite3_prepare_idr(
8980
9081int sqlite3_step_idr(void* stmt);
9182
92−int sqlite3_bind_float_idr(void* p,int index, float val);
93−
94−int sqlite3_bind_int_idr(void* p,int index , int val);
83+void* sqlite3_bind_float_idr(void* p,int index, float val);
9584
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);
9786
98−int sqlite3_bind_null_idr(void* p,int index);
87+void* sqlite3_bind_null_idr(void* p,int index);
9988
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);
10190
10291int sqlite3_column_count_idr(void* stmt, const char* tbl_name);
10392
@@ -138,9 +127,4 @@ int sqlite3_backup_remaining_idr(void *backup);
138127
139128int sqlite3_backup_pagecount_idr(void *backup);
140129
141−int sqlite3_value_bytes_idr(void* value);
142−
143−int sqlite3_value_bytes16_idr(void* value);
144−
145−int sqlite3_errcode(sqlite3 *db);
146−
130+int strLength(const char * str);
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 ()