on master help sign in
fixed a bug for nested SELECT queries
8011e70melissam
contribs/lib/SQLite3/._sqlexpr.idr

Binary file not shown.

contribs/lib/SQLite3/._testunit.idr

Binary file not shown.

contribs/lib/SQLite3/sqlexpr.idr+9−9
@@ -157,23 +157,23 @@ listValType xs ((val, types, constr) :: vs) = let (str , newxs) = valString xs v
157evalCond : List (Maybe(Int, Value)) -> Cond -> (String, List (Maybe(Int, Value)))
157evalCond : List (Maybe(Int, Value)) -> Cond -> (String, List (Maybe(Int, Value)))
158evalCond xs (Equals val1 val2) = let (restring , newxs ) = valString xs val1 in
158evalCond xs (Equals val1 val2) = let (restring , newxs ) = valString xs val1 in
159 let (restring2, newxs') = valString newxs val2 in
159 let (restring2, newxs') = valString newxs val2 in
160− (restring ++ " = " ++ restring2, (newxs'))
160+ (restring ++ " = " ++ restring2, newxs')
161
161
162evalCond xs (MkGT val1 val2) = let (restring , newxs ) = valString xs val1 in
162evalCond xs (MkGT val1 val2) = let (restring , newxs ) = valString xs val1 in
163 let (restring2, newxs') = valString newxs val2 in
163 let (restring2, newxs') = valString newxs val2 in
164− (restring ++ " > " ++ restring2, (newxs'))
164+ (restring ++ " > " ++ restring2, newxs')
165
165
166evalCond xs (MkGTE val1 val2) = let (restring , newxs ) = valString xs val1 in
166evalCond xs (MkGTE val1 val2) = let (restring , newxs ) = valString xs val1 in
167 let (restring2, newxs') = valString newxs val2 in
167 let (restring2, newxs') = valString newxs val2 in
168− (restring ++ " >= " ++ restring2, ( newxs'))
168+ (restring ++ " >= " ++ restring2, newxs')
169
169
170evalCond xs (MkLT val1 val2) = let (restring , newxs ) = valString xs val1 in
170evalCond xs (MkLT val1 val2) = let (restring , newxs ) = valString xs val1 in
171 let (restring2, newxs') = valString newxs val2 in
171 let (restring2, newxs') = valString newxs val2 in
172− (restring ++ " < " ++ restring2, (newxs'))
172+ (restring ++ " < " ++ restring2, newxs')
173
173
174evalCond xs (MkLTE val1 val2) = let (restring , newxs ) = valString xs val1 in
174evalCond xs (MkLTE val1 val2) = let (restring , newxs ) = valString xs val1 in
175 let (restring2, newxs') = valString newxs val2 in
175 let (restring2, newxs') = valString newxs val2 in
176− (restring ++ " =< " ++ restring2, ( newxs'))
176+ (restring ++ " =< " ++ restring2, newxs')
177
177
178evalCond xs (MkNULL val) = let (restring , newxs ) = valString xs val in
178evalCond xs (MkNULL val) = let (restring , newxs ) = valString xs val in
179 (restring ++ " IS NULL " , newxs)
179 (restring ++ " IS NULL " , newxs)
@@ -228,26 +228,26 @@ evalSQL xs (SELECT vars sql' c) = let (sqlstring, newxs) = evalSQL xs sql' in
228 case c of
228 case c of
229 Empty => case vars of
229 Empty => case vars of
230 (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
230 (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
231− ++ (putBrackets sqlstring) ++ csstring, newxs')
231+ ++ (putBrackets sqlstring) ++ csstring, newxs)
232
232
233 else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
233 else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
234 ++ csstring, newxs')
234 ++ csstring, newxs')
235
235
236 (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++
236 (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++
237− " FROM " ++ (putBrackets sqlstring) ++ csstring, newxs')
237+ " FROM " ++ (putBrackets sqlstring) ++ csstring, newxs)
238
238
239 else ("SELECT " ++ (unwords selvar )++ " FROM " ++ sqlstring
239 else ("SELECT " ++ (unwords selvar )++ " FROM " ++ sqlstring
240 ++ csstring, newxs')
240 ++ csstring, newxs')
241
241
242 _ => case vars of
242 _ => case vars of
243 (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
243 (ALL ) => if complexType sql' then ("SELECT " ++ "*" ++ " FROM "
244− ++ " WHERE " ++ csstring , newxs')
244+ ++ " WHERE " ++ csstring , newxs)
245 else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
245 else ("SELECT " ++ "*" ++ " FROM " ++ sqlstring
246 ++ " WHERE " ++ csstring , newxs')
246 ++ " WHERE " ++ csstring , newxs')
247
247
248 (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++ " FROM " ++
248 (Cols selvar) => if complexType sql' then ("SELECT " ++ (unwords selvar) ++ " FROM " ++
249 (putBrackets sqlstring) ++ " WHERE "
249 (putBrackets sqlstring) ++ " WHERE "
250− ++ csstring , newxs')
250+ ++ csstring , newxs)
251
251
252 else ("SELECT " ++ (unwords selvar) ++ " FROM " ++ sqlstring
252 else ("SELECT " ++ (unwords selvar) ++ " FROM " ++ sqlstring
253 ++ " WHERE " ++ csstring , newxs')
253 ++ " WHERE " ++ csstring , newxs')
contribs/lib/SQLite3/sqlite3.tex+12−10
@@ -11,25 +11,27 @@
11 \begin{document}
11 \begin{document}
12 \section{Introduction}
12 \section{Introduction}
13\label{Introduction}
13\label{Introduction}
14−This document provides overview of how the library for SQLite works. The code base is written on top of the SQLite3 C/C++ Interface.
14+This document provides overview of how the library for SQLite works. The code base is written on top of the
15+SQLite3 C/C++ Interface.
15This library supports some features of the low-level library, implemented in a higher level basis.
16This library supports some features of the low-level library, implemented in a higher level basis.
16The library allows making use of data types as queries. The aim of this library is to avoid
17The library allows making use of data types as queries. The aim of this library is to avoid
17SQL injections which are the most common security issues.
18SQL injections which are the most common security issues.
18−To avoid this we have defined a datatype which describes qqueries.
19+To avoid this we have defined a datatype which describes queries.
19The queries are written using these data types and parsed as quoted string
20The queries are written using these data types and parsed as quoted string
20while replacing values with indexed question mark to be binded with the statement.
21while replacing values with indexed question mark to be binded with the statement.
21\section{Using the library}
22\section{Using the library}
22\label{Using the library}
23\label{Using the library}
23−Simple examples have been provided in the testunit.idr file.
24+Simple examples have been provided in the \emph{testunit.idr} file.
24To open a database, use the open\_db function which takes the filename as a string.
25To open a database, use the open\_db function which takes the filename as a string.
25−This function implements the sqlite3\_open function .
26+This function implements the sqlite3\_open function.
26−This function returns a pointer to the database which can be used by other function to access the database object.
27+This function returns a pointer to the database which can be used by other function
28+to access the database object.
27Whether or not an error occurs when it is opened,
29Whether or not an error occurs when it is opened,
28resources should be released by passing it to close\_db when it is no longer required.
30resources should be released by passing it to close\_db when it is no longer required.
29−A query can then be builts using the supported data types .
31+A query can then be builts using the supported data types.
30The library supports limited number of queries at the moment. The supported sql commands are :
32The library supports limited number of queries at the moment. The supported sql commands are :
31\newline
33\newline
32−\newline
34+
33\textbf{SELECT,}
35\textbf{SELECT,}
34\textbf{INSERT,}
36\textbf{INSERT,}
35\textbf{UPDATE,}
37\textbf{UPDATE,}
@@ -39,7 +41,7 @@ The library supports limited number of queries at the moment. The supported sql
39\label{Creating Queries}
41\label{Creating Queries}
40
42
41To create a query, use the evalSQL function which takes an empty list and the SQL query.
43To create a query, use the evalSQL function which takes an empty list and the SQL query.
42−The routine evaluates the expression in a divide and conquer manner (or recursive?)
44+The routine evaluates the expression recrusively by dividing it into smaller parts,
43filling up the list with the received values. For instance the following is a valid query:
45filling up the list with the received values. For instance the following is a valid query:
44
46
45let sql = evalSQL [ ] ((SELECT ALL)(TBL ["tbl1"]) (MkCond (MkNULL (VCol "data"))))
47let sql = evalSQL [ ] ((SELECT ALL)(TBL ["tbl1"]) (MkCond (MkNULL (VCol "data"))))
@@ -49,12 +51,12 @@ let sql = evalSQL [ ] ((SELECT ALL)(TBL ["tbl1"]) (MkCond (MkNULL (VCol "data"))
49
51
50The evaluator returns a string and a list of indexed values.
52The evaluator returns a string and a list of indexed values.
51The string part of the query could be parsed to prepare.
53The string part of the query could be parsed to prepare.
52−evalSQL parses the query as a string replacing values with ? and an index starting from one,
54+\emph{evalSQL} parses the query as a string replacing values with \emph{?} and an index starting from one,
53storing them in the list given to it as an argument.
55storing them in the list given to it as an argument.
54For example:
56For example:
55
57
56
58
57−evalSQL [ ] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"]) (MkCond (Equals (VCol "num")(VInt 2))) ) Empty ) )
59+evalSQL [ ] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"])(MkCond(Equals(VCol "num")(VInt 2))))Empty))
58
60
59is passed to prepare as :
61is passed to prepare as :
60
62
contribs/lib/SQLite3/testunit.idr+33−17
@@ -5,21 +5,21 @@ import sqlite3
5testexpr : DB()
5testexpr : DB()
6testexpr = do db <- open_db "somedb.db"
6testexpr = 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))))))
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)
8+ let x = (fst sql) -- get the string
9− let list = (snd sql)
9+ let list = (snd sql) -- list of vals
10− liftIO(print x)
10+ liftIO(print x) -- use liftIO to turn this into DB type
11− stmt <- (prepare_db db x)
11+ stmt <- (prepare_db db x) -- prepare the statement
12− bindMulti stmt list
12+ bindMulti stmt list -- bind the values in the list
13− exec_db_v2 stmt
13+ exec_db_v2 stmt -- execute the prepared query
14− res <- toList_v1 db
14+ res <- toList_v1 db -- toList_v1 to get the result
15− liftIO(print res)
15+ liftIO(print res) -- print the result
16− finalize_db stmt
16+ finalize_db stmt -- Statment pointer must be finalized in the end
17− close_db db
17+ close_db db -- close the datbase
18 return ()
18 return ()
19
19
20testupdate : DB()
20testupdate : DB()
21testupdate = do db <- open_db "somedb.db"
21testupdate = do db <- open_db "somedb.db"
22− let sql = (evalSQL [] (UPDATE (TBL ["tbl1"]) (WHERE (SET (MkCond (Equals(VCol "data") (VStr "data0"))) ) (MkCond (Equals (VCol "num") (VInt 2))) ) ))
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)
23 let x = (fst sql)
24 let list = (snd sql)
24 let list = (snd sql)
25 liftIO(print x)
25 liftIO(print x)
@@ -32,7 +32,7 @@ testupdate = do db <- open_db "somedb.db"
32
32
33testInsert : DB()
33testInsert : DB()
34testInsert = do db <- open_db "somedb.db"
34testInsert = do db <- open_db "somedb.db"
35− let sql = (evalSQL [] (INSERT (TBL ["tbl1"]) [(VInt 2),(VStr "histring2")]))
35+ let sql = (evalSQL [] (INSERT (TBL ["tbl1"]) [(VInt 3),(VStr "ham")]))
36 let x = (fst sql)
36 let x = (fst sql)
37 let list = (snd sql)
37 let list = (snd sql)
38 liftIO(print x)
38 liftIO(print x)
@@ -61,7 +61,7 @@ testNull = do db <- open_db "somedb.db"
61
61
62testInsertWithCond : DB()
62testInsertWithCond : DB()
63testInsertWithCond = do db <- open_db "somedb.db"
63testInsertWithCond = do db <- open_db "somedb.db"
64− let sql = (evalSQL [] (INSERTC (TBL ["tbl1"]) [(VCol "data"),(VCol "num")] [(VInt 201),(VStr "newinserted")]))
64+ let sql = (evalSQL [] (INSERTC (TBL ["tbl1"]) [(VCol "data"),(VCol "num")] [(VInt 30),(VStr "inserthere")]))
65 let x = (fst sql)
65 let x = (fst sql)
66 let list = (snd sql)
66 let list = (snd sql)
67 liftIO(print x)
67 liftIO(print x)
@@ -72,10 +72,10 @@ testInsertWithCond = do db <- open_db "somedb.db"
72 close_db db
72 close_db db
73 return ()
73 return ()
74
74
75−-- Nested queries need to have the same column as the outer queries !!!
75+-- Nested queries need to have the same column as the outer queries.
76testNestedSel1 : DB()
76testNestedSel1 : DB()
77testNestedSel1 = do db <- open_db "somedb.db"
77testNestedSel1 = do db <- open_db "somedb.db"
78− let sql = (evalSQL [] (SELECT (Cols ["data"]) (SELECT (Cols["num","data"]) (TBL ["tbl1"]) (MkCond (Equals (VCol "num")(VInt 2))) ) Empty ) )
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)
79 let x = (fst sql)
80 let list = (snd sql)
80 let list = (snd sql)
81 liftIO(print x)
81 liftIO(print x)
@@ -102,6 +102,7 @@ testCreateTable = do db <- open_db "somedb.db"
102 close_db db
102 close_db db
103 return ()
103 return ()
104
104
105+-- This may be a bit slow
105testMultiTable : DB ()
106testMultiTable : DB ()
106testMultiTable = do db <- open_db "somedb.db"
107testMultiTable = do db <- open_db "somedb.db"
107 let sql = (evalSQL [] ((SELECT ALL )(TBL ["mytable","tbl1"]) (Empty) ) )
108 let sql = (evalSQL [] ((SELECT ALL )(TBL ["mytable","tbl1"]) (Empty) ) )
@@ -117,8 +118,23 @@ testMultiTable = do db <- open_db "somedb.db"
117 close_db db
118 close_db db
118 return ()
119 return ()
119
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+
120
136
121main : IO ()
137main : IO ()
122−main = do x <- runDB (testexpr)
138+main = do x <- runDB (testMultiTable) -- runDB : DB a -> IO a
123− y <- runDB (testNestedSel1)
139+ --y <- runDB (testNestedSel1)
124 return ()
140 return ()