]> gitweb.factorcode.org Git - factor.git/blob - basis/db/sqlite/lib/lib.factor
3565b098564b95c150e65c7260f244c84ef6ab28
[factor.git] / basis / db / sqlite / lib / lib.factor
1 ! Copyright (C) 2008 Chris Double, Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien.c-types arrays assocs kernel math math.parser
4 namespaces sequences db.sqlite.ffi db combinators
5 continuations db.types calendar.format serialize
6 io.streams.byte-array byte-arrays io.encodings.binary
7 io.backend db.errors present urls io.encodings.utf8
8 io.encodings.string accessors shuffle io db.private ;
9 IN: db.sqlite.lib
10
11 ERROR: sqlite-error < db-error n string ;
12 ERROR: sqlite-sql-error < sql-error n string ;
13
14 : <sqlite-sql-error> ( n string -- error )
15     \ sqlite-sql-error new
16         swap >>string
17         swap >>n ;
18
19 : throw-sqlite-error ( n -- * )
20     dup sqlite-error-messages nth sqlite-error ;
21
22 : sqlite-statement-error ( -- * )
23     SQLITE_ERROR
24     db-connection get handle>> sqlite3_errmsg <sqlite-sql-error> throw ;
25
26 : sqlite-check-result ( n -- )
27     {
28         { SQLITE_OK [ ] }
29         { SQLITE_ERROR [ sqlite-statement-error ] }
30         [ throw-sqlite-error ]
31     } case ;
32
33 : sqlite-open ( path -- db )
34     normalize-path
35     "void*" <c-object>
36     [ sqlite3_open sqlite-check-result ] keep *void* ;
37
38 : sqlite-close ( db -- )
39     sqlite3_close sqlite-check-result ;
40
41 : sqlite-prepare ( db sql -- handle )
42     utf8 encode dup length "void*" <c-object> "void*" <c-object>
43     [ sqlite3_prepare_v2 sqlite-check-result ] 2keep
44     drop *void* ;
45
46 : sqlite-bind-parameter-index ( handle name -- index )
47     sqlite3_bind_parameter_index ;
48
49 : parameter-index ( handle name text -- handle name text )
50     [ dupd sqlite-bind-parameter-index ] dip ;
51
52 : sqlite-bind-text ( handle index text -- )
53     utf8 encode dup length SQLITE_TRANSIENT
54     sqlite3_bind_text sqlite-check-result ;
55
56 : sqlite-bind-int ( handle i n -- )
57     sqlite3_bind_int sqlite-check-result ;
58
59 : sqlite-bind-int64 ( handle i n -- )
60     sqlite3_bind_int64 sqlite-check-result ;
61
62 : sqlite-bind-uint64 ( handle i n -- )
63     sqlite3-bind-uint64 sqlite-check-result ;
64
65 : sqlite-bind-double ( handle i x -- )
66     sqlite3_bind_double sqlite-check-result ;
67
68 : sqlite-bind-null ( handle i -- )
69     sqlite3_bind_null sqlite-check-result ;
70
71 : sqlite-bind-blob ( handle i byte-array -- )
72     dup length SQLITE_TRANSIENT
73     sqlite3_bind_blob sqlite-check-result ;
74
75 : sqlite-bind-text-by-name ( handle name text -- )
76     parameter-index sqlite-bind-text ;
77
78 : sqlite-bind-int-by-name ( handle name int -- )
79     parameter-index sqlite-bind-int ;
80
81 : sqlite-bind-int64-by-name ( handle name int64 -- )
82     parameter-index sqlite-bind-int64 ;
83
84 : sqlite-bind-uint64-by-name ( handle name int64 -- )
85     parameter-index sqlite-bind-uint64 ;
86
87 : sqlite-bind-boolean-by-name ( handle name obj -- )
88     >boolean 1 0 ? parameter-index sqlite-bind-int ;
89
90 : sqlite-bind-double-by-name ( handle name double -- )
91     parameter-index sqlite-bind-double ;
92
93 : sqlite-bind-blob-by-name ( handle name blob -- )
94     parameter-index sqlite-bind-blob ;
95
96 : sqlite-bind-null-by-name ( handle name obj -- )
97     parameter-index drop sqlite-bind-null ;
98
99 : (sqlite-bind-type) ( handle key value type -- )
100     dup array? [ first ] when
101     {
102         { INTEGER [ sqlite-bind-int-by-name ] }
103         { BIG-INTEGER [ sqlite-bind-int64-by-name ] }
104         { SIGNED-BIG-INTEGER [ sqlite-bind-int64-by-name ] }
105         { UNSIGNED-BIG-INTEGER [ sqlite-bind-uint64-by-name ] }
106         { BOOLEAN [ sqlite-bind-boolean-by-name ] }
107         { TEXT [ sqlite-bind-text-by-name ] }
108         { VARCHAR [ sqlite-bind-text-by-name ] }
109         { DOUBLE [ sqlite-bind-double-by-name ] }
110         { DATE [ timestamp>ymd sqlite-bind-text-by-name ] }
111         { TIME [ timestamp>hms sqlite-bind-text-by-name ] }
112         { DATETIME [ timestamp>ymdhms sqlite-bind-text-by-name ] }
113         { TIMESTAMP [ timestamp>ymdhms sqlite-bind-text-by-name ] }
114         { BLOB [ sqlite-bind-blob-by-name ] }
115         { FACTOR-BLOB [ object>bytes sqlite-bind-blob-by-name ] }
116         { URL [ present sqlite-bind-text-by-name ] }
117         { +db-assigned-id+ [ sqlite-bind-int-by-name ] }
118         { +random-id+ [ sqlite-bind-int64-by-name ] }
119         { NULL [ sqlite-bind-null-by-name ] }
120         [ no-sql-type ]
121     } case ;
122
123 : sqlite-bind-type ( handle key value type -- )
124     #! null and empty values need to be set by sqlite-bind-null-by-name
125     over [
126         NULL = [ 2drop NULL NULL ] when
127     ] [
128         drop NULL 
129     ] if* (sqlite-bind-type) ;
130
131 : sqlite-finalize ( handle -- ) sqlite3_finalize sqlite-check-result ;
132 : sqlite-reset ( handle -- ) sqlite3_reset sqlite-check-result ;
133 : sqlite-clear-bindings ( handle -- )
134     sqlite3_clear_bindings sqlite-check-result ;
135 : sqlite-#columns ( query -- int ) sqlite3_column_count ;
136 : sqlite-column ( handle index -- string ) sqlite3_column_text ;
137 : sqlite-column-name ( handle index -- string ) sqlite3_column_name ;
138 : sqlite-column-type ( handle index -- string ) sqlite3_column_type ;
139
140 : sqlite-column-blob ( handle index -- byte-array/f )
141     [ sqlite3_column_bytes ] 2keep
142     pick zero? [
143         3drop f
144     ] [
145         sqlite3_column_blob swap memory>byte-array
146     ] if ;
147
148 : sqlite-column-typed ( handle index type -- obj )
149     dup array? [ first ] when
150     {
151         { +db-assigned-id+ [ sqlite3_column_int64  ] }
152         { +random-id+ [ sqlite3-column-uint64 ] }
153         { INTEGER [ sqlite3_column_int ] }
154         { BIG-INTEGER [ sqlite3_column_int64 ] }
155         { SIGNED-BIG-INTEGER [ sqlite3_column_int64 ] }
156         { UNSIGNED-BIG-INTEGER [ sqlite3-column-uint64 ] }
157         { BOOLEAN [ sqlite3_column_int 1 = ] }
158         { DOUBLE [ sqlite3_column_double ] }
159         { TEXT [ sqlite3_column_text ] }
160         { VARCHAR [ sqlite3_column_text ] }
161         { DATE [ sqlite3_column_text dup [ ymd>timestamp ] when ] }
162         { TIME [ sqlite3_column_text dup [ hms>timestamp ] when ] }
163         { TIMESTAMP [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
164         { DATETIME [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
165         { BLOB [ sqlite-column-blob ] }
166         { URL [ sqlite3_column_text dup [ >url ] when ] }
167         { FACTOR-BLOB [ sqlite-column-blob dup [ bytes>object ] when ] }
168         [ no-sql-type ]
169     } case ;
170
171 : sqlite-row ( handle -- seq )
172     dup sqlite-#columns [ sqlite-column ] with map ;
173
174 : sqlite-step-has-more-rows? ( prepared -- ? )
175     {
176         { SQLITE_ROW [ t ] }
177         { SQLITE_DONE [ f ] }
178         [ sqlite-check-result f ]
179     } case ;
180
181 : sqlite-next ( prepared -- ? )
182     sqlite3_step sqlite-step-has-more-rows? ;