1 ! Copyright (C) 2008 Chris Double, Doug Coleman.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types alien.data arrays calendar.format
4 calendar.parser combinators db db.errors db.sqlite.errors
5 db.sqlite.ffi db.types io.backend io.encodings.string
6 io.encodings.utf8 kernel math namespaces present sequences
10 : sqlite-compile-options ( -- seq )
12 [ 1 + ] [ sqlite3_compileoption_get ] bi dup
15 ERROR: sqlite-error < db-error n string ;
17 : sqlite-other-error ( n -- * )
18 dup sqlite-error-messages nth sqlite-error ;
20 : sqlite-statement-error ( -- * )
21 db-connection get handle>> sqlite3_errmsg
22 parse-sqlite-sql-error throw ;
24 : sqlite-check-result ( n -- )
27 { SQLITE_ERROR [ sqlite-statement-error ] }
28 [ sqlite-other-error ]
31 : sqlite-open ( path -- db )
33 { void* } [ sqlite3_open sqlite-check-result ]
36 : sqlite-close ( db -- )
37 sqlite3_close sqlite-check-result ;
39 : sqlite-prepare ( db sql -- handle )
40 utf8 encode dup length
42 [ sqlite3_prepare_v2 sqlite-check-result ]
43 with-out-parameters drop ;
45 : sqlite-bind-parameter-index ( handle name -- index )
46 sqlite3_bind_parameter_index ;
48 : parameter-index ( handle name text -- handle name text )
49 [ dupd sqlite-bind-parameter-index ] dip ;
51 : sqlite-bind-text ( handle index text -- )
52 utf8 encode dup length SQLITE_TRANSIENT
53 sqlite3_bind_text sqlite-check-result ;
55 : sqlite-bind-int ( handle i n -- )
56 sqlite3_bind_int sqlite-check-result ;
58 : sqlite-bind-int64 ( handle i n -- )
59 sqlite3_bind_int64 sqlite-check-result ;
61 : sqlite-bind-uint64 ( handle i n -- )
62 ! there is no sqlite3_bind_uint64 function
63 sqlite3_bind_int64 sqlite-check-result ;
65 : sqlite-bind-double ( handle i x -- )
66 sqlite3_bind_double sqlite-check-result ;
68 : sqlite-bind-null ( handle i -- )
69 sqlite3_bind_null sqlite-check-result ;
71 : sqlite-bind-blob ( handle i byte-array -- )
72 dup length SQLITE_TRANSIENT
73 sqlite3_bind_blob sqlite-check-result ;
75 : sqlite-bind-text-by-name ( handle name text -- )
76 parameter-index sqlite-bind-text ;
78 : sqlite-bind-int-by-name ( handle name int -- )
79 parameter-index sqlite-bind-int ;
81 : sqlite-bind-int64-by-name ( handle name int64 -- )
82 parameter-index sqlite-bind-int64 ;
84 : sqlite-bind-uint64-by-name ( handle name int64 -- )
85 parameter-index sqlite-bind-uint64 ;
87 : sqlite-bind-boolean-by-name ( handle name obj -- )
88 >boolean 1 0 ? parameter-index sqlite-bind-int ;
90 : sqlite-bind-double-by-name ( handle name double -- )
91 parameter-index sqlite-bind-double ;
93 : sqlite-bind-blob-by-name ( handle name blob -- )
94 parameter-index sqlite-bind-blob ;
96 : sqlite-bind-null-by-name ( handle name obj -- )
97 parameter-index drop sqlite-bind-null ;
99 : (sqlite-bind-type) ( handle key value type -- )
100 dup array? [ first ] when
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 [ duration>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 ] }
123 : sqlite-bind-type ( handle key value type -- )
124 ! null and empty values need to be set by sqlite-bind-null-by-name
126 NULL = [ 2drop NULL NULL ] when
129 ] if* (sqlite-bind-type) ;
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 ;
141 : sqlite3-column-null ( sqlite n obj -- obj/f )
142 [ sqlite3_column_type SQLITE_NULL = f ] dip ? ; inline
144 ! sqlite_column_int returns 0 for both a ``0`` and for ``NULL``
145 ! so call sqlite3_column_type if it's 0
146 : sqlite3-column-int ( handle index -- int/f )
147 2dup sqlite3_column_int dup 0 = [ sqlite3-column-null ] [ 2nip ] if ;
149 : sqlite3-column-int64 ( handle index -- int/f )
150 2dup sqlite3_column_int64 dup 0 = [ sqlite3-column-null ] [ 2nip ] if ;
152 : sqlite3-column-uint64 ( handle index -- int/f )
153 ! there is no sqlite3_column_uint64
154 2dup sqlite3_column_int64 dup 0 = [ sqlite3-column-null ] [ 2nip ] if ;
156 : sqlite3-column-double ( handle index -- int/f )
157 2dup sqlite3_column_double dup 0.0 = [ sqlite3-column-null ] [ 2nip ] if ;
159 : sqlite-column-blob ( handle index -- byte-array/f )
160 [ sqlite3_column_bytes ] 2keep
164 sqlite3_column_blob swap memory>byte-array
167 : sqlite-column-typed ( handle index type -- obj )
168 dup array? [ first ] when
170 { +db-assigned-id+ [ sqlite3_column_int64 ] }
171 { +random-id+ [ sqlite3-column-uint64 ] }
172 { INTEGER [ sqlite3-column-int ] }
173 { BIG-INTEGER [ sqlite3-column-int64 ] }
174 { SIGNED-BIG-INTEGER [ sqlite3-column-int64 ] }
175 { UNSIGNED-BIG-INTEGER [ sqlite3-column-uint64 ] }
176 { BOOLEAN [ sqlite3-column-int 1 = ] }
177 { DOUBLE [ sqlite3-column-double ] }
178 { TEXT [ sqlite3_column_text ] }
179 { VARCHAR [ sqlite3_column_text ] }
180 { DATE [ sqlite3_column_text dup [ ymd>timestamp ] when ] }
181 { TIME [ sqlite3_column_text dup [ hms>duration ] when ] }
182 { TIMESTAMP [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
183 { DATETIME [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
184 { BLOB [ sqlite-column-blob ] }
185 { URL [ sqlite3_column_text dup [ >url ] when ] }
186 { FACTOR-BLOB [ sqlite-column-blob dup [ bytes>object ] when ] }
190 : sqlite-row ( handle -- seq )
191 dup sqlite-#columns [ sqlite-column ] with map-integers ;
193 : sqlite-step-has-more-rows? ( prepared -- ? )
196 { SQLITE_DONE [ f ] }
197 [ sqlite-check-result f ]
200 : sqlite-next ( prepared -- ? )
201 sqlite3_step sqlite-step-has-more-rows? ;
203 : current-sqlite-filename ( -- path/f )
204 db-connection get [ handle>> f sqlite3_db_filename ] [ f ] if* ;