1 ! Copyright (C) 2005, 2008 Chris Double, Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays assocs classes compiler db
4 hashtables io.files kernel math math.parser namespaces
5 prettyprint sequences strings classes.tuple alien.c-types
6 continuations db.sqlite.lib db.sqlite.ffi db.tuples
7 words combinators.lib db.types combinators math.intervals
8 io namespaces.lib accessors vectors math.ranges random
9 math.bitfields.lib db.queries destructors ;
13 TUPLE: sqlite-db < db path ;
15 M: sqlite-db make-db* ( path db -- db )
18 M: sqlite-db db-open ( db -- db )
19 dup path>> sqlite-open >>handle ;
21 M: sqlite-db db-close ( handle -- ) sqlite-close ;
22 M: sqlite-db dispose ( db -- ) db-dispose ;
24 TUPLE: sqlite-statement < statement ;
26 TUPLE: sqlite-result-set < result-set has-more? ;
28 M: sqlite-db <simple-statement> ( str in out -- obj )
29 <prepared-statement> ;
31 M: sqlite-db <prepared-statement> ( str in out -- obj )
32 sqlite-statement construct-statement ;
34 : sqlite-maybe-prepare ( statement -- statement )
36 db get handle>> over sql>> sqlite-prepare
40 M: sqlite-statement dispose ( statement -- )
42 [ [ sqlite3_reset drop ] keep sqlite-finalize ] when* ;
44 M: sqlite-result-set dispose ( result-set -- )
47 : reset-statement ( statement -- )
48 sqlite-maybe-prepare handle>> sqlite-reset ;
50 : reset-bindings ( statement -- )
52 handle>> [ sqlite3_reset drop ] [ sqlite3_clear_bindings drop ] bi ;
54 M: sqlite-statement low-level-bind ( statement -- )
55 [ bind-params>> ] [ handle>> ] bi
56 [ swap [ key>> ] [ value>> ] [ type>> ] tri sqlite-bind-type ] curry each ;
58 M: sqlite-statement bind-statement* ( statement -- )
60 dup bound?>> [ dup reset-bindings ] when
63 GENERIC: sqlite-bind-conversion ( tuple obj -- array )
65 TUPLE: sqlite-low-level-binding < low-level-binding key type ;
66 : <sqlite-low-level-binding> ( key value type -- obj )
67 sqlite-low-level-binding new
72 M: sql-spec sqlite-bind-conversion ( tuple spec -- array )
73 [ column-name>> ":" prepend ]
74 [ slot-name>> rot get-slot-named ]
75 [ type>> ] tri <sqlite-low-level-binding> ;
77 M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array )
78 nip [ key>> ] [ value>> ] [ type>> ] tri
79 <sqlite-low-level-binding> ;
81 M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array )
83 [ generator-singleton>> eval-generator tuck ] [ slot-name>> ] bi
85 >r [ key>> ] [ type>> ] bi r> swap <sqlite-low-level-binding> ;
87 M: sqlite-statement bind-tuple ( tuple statement -- )
89 in-params>> [ sqlite-bind-conversion ] with map
90 ] keep bind-statement ;
92 : last-insert-id ( -- id )
93 db get handle>> sqlite3_last_insert_rowid
94 dup zero? [ "last-id failed" throw ] when ;
96 M: sqlite-db insert-tuple* ( tuple statement -- )
97 execute-statement last-insert-id swap set-primary-key ;
99 M: sqlite-result-set #columns ( result-set -- n )
100 handle>> sqlite-#columns ;
102 M: sqlite-result-set row-column ( result-set n -- obj )
103 [ handle>> ] [ sqlite-column ] bi* ;
105 M: sqlite-result-set row-column-typed ( result-set n -- obj )
106 dup pick out-params>> nth type>>
107 >r >r handle>> r> r> sqlite-column-typed ;
109 M: sqlite-result-set advance-row ( result-set -- )
110 dup handle>> sqlite-next >>has-more? drop ;
112 M: sqlite-result-set more-rows? ( result-set -- ? )
115 M: sqlite-statement query-results ( query -- result-set )
117 dup handle>> sqlite-result-set construct-result-set
120 M: sqlite-db create-sql-statement ( class -- statement )
122 "create table " 0% 0%
126 dup type>> lookup-create-type 0%
131 M: sqlite-db drop-sql-statement ( class -- statement )
132 [ "drop table " 0% 0% ";" 0% drop ] query-make ;
134 M: sqlite-db <insert-db-assigned-statement> ( tuple -- statement )
138 remove-db-assigned-id
139 dup [ ", " 0% ] [ column-name>> 0% ] interleave
142 dup type>> +random-id+ = [
145 column-name>> ":" prepend dup 0%
147 ] [ type>> ] tri <generator-bind> 1,
155 M: sqlite-db <insert-user-assigned-statement> ( tuple -- statement )
156 <insert-db-assigned-statement> ;
158 M: sqlite-db bind# ( spec obj -- )
160 [ column-name>> ":" swap next-sql-counter 3append dup 0% ]
162 r> <literal-bind> 1, ;
164 M: sqlite-db bind% ( spec -- )
165 dup 1, column-name>> ":" prepend 0% ;
167 M: sqlite-db persistent-table ( -- assoc )
169 { +db-assigned-id+ { "integer primary key" "integer primary key" "primary key" } }
170 { +user-assigned-id+ { f f "primary key" } }
171 { +random-id+ { "integer primary key" "integer primary key" "primary key" } }
172 { INTEGER { "integer" "integer" "primary key" } }
173 { BIG-INTEGER { "bigint" "bigint" } }
174 { SIGNED-BIG-INTEGER { "bigint" "bigint" } }
175 { UNSIGNED-BIG-INTEGER { "bigint" "bigint" } }
176 { TEXT { "text" "text" } }
177 { VARCHAR { "text" "text" } }
178 { DATE { "date" "date" } }
179 { TIME { "time" "time" } }
180 { DATETIME { "datetime" "datetime" } }
181 { TIMESTAMP { "timestamp" "timestamp" } }
182 { DOUBLE { "real" "real" } }
183 { BLOB { "blob" "blob" } }
184 { FACTOR-BLOB { "blob" "blob" } }
185 { URL { "text" "text" } }
186 { +autoincrement+ { f f "autoincrement" } }
187 { +unique+ { f f "unique" } }
188 { +default+ { f f "default" } }
189 { +null+ { f f "null" } }
190 { +not-null+ { f f "not null" } }
191 { system-random-generator { f f f } }
192 { secure-random-generator { f f f } }
193 { random-generator { f f f } }
196 M: sqlite-db compound ( str seq -- str' )
198 { "default" [ first number>string join-space ] }