sqlite3-ruby 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sqlite3-ruby might be problematic. Click here for more details.

@@ -0,0 +1,182 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # * The names of its contributors may not be used to endorse or promote
17
+ # products derived from this software without specific prior written
18
+ # permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ # =============================================================================
31
+ #++
32
+
33
+ require 'dl/import'
34
+
35
+ module SQLite3 ; module Driver; module DL;
36
+
37
+ module API
38
+ extend ::DL::Importable
39
+
40
+ library_name = case RUBY_PLATFORM.downcase
41
+ when /linux/
42
+ "libsqlite3.so"
43
+ when /win32/
44
+ "sqlite3.dll"
45
+ else
46
+ abort <<-EOF
47
+ == * UNSUPPORTED PLATFORM ======================================================
48
+ The platform '#{RUBY_PLATFORM}' is unsupported. Please help the author by
49
+ editing the following file to allow your sqlite3 library to be found, and
50
+ submitting a patch to jamis_buck@byu.edu. Thanks!
51
+
52
+ #{' '*((74-__FILE__.length)/2)}-> #{__FILE__} <-
53
+ =========================================================================== * ==
54
+ EOF
55
+ end
56
+
57
+ if defined? SQLITE3_LIB_PATH
58
+ library_name = File.join( SQLITE3_LIB_PATH, library_name )
59
+ end
60
+
61
+ dlload library_name
62
+
63
+ typealias "db", "void*"
64
+ typealias "stmt", "void*"
65
+ typealias "value", "void*"
66
+ typealias "context", "void*"
67
+
68
+ # until Ruby/DL supports 64-bit ints, we'll just treat them as 32-bit ints
69
+ typealias "int64", "unsigned long"
70
+
71
+ extern "const char *sqlite3_libversion()"
72
+
73
+ extern "int sqlite3_open(const char*,db*)"
74
+ extern "int sqlite3_open16(const void*,db*)"
75
+ extern "int sqlite3_close(db)"
76
+ extern "const char* sqlite3_errmsg(db)"
77
+ extern "void* sqlite3_errmsg16(db)"
78
+ extern "int sqlite3_errcode(db)"
79
+
80
+ extern "int sqlite3_prepare(db,const char*,int,stmt*,const char**)"
81
+ extern "int sqlite3_prepare16(db,const void*,int,stmt*,const void**)"
82
+ extern "int sqlite3_finalize(stmt)"
83
+ extern "int sqlite3_reset(stmt)"
84
+ extern "int sqlite3_step(stmt)"
85
+
86
+ extern "int64 sqlite3_last_insert_rowid(db)"
87
+ extern "int sqlite3_changes(db)"
88
+ extern "int sqlite3_total_changes(db)"
89
+ extern "void sqlite3_interrupt(db)"
90
+ extern "ibool sqlite3_complete(const char*)"
91
+ extern "ibool sqlite3_complete16(const void*)"
92
+
93
+ extern "int sqlite3_busy_handler(db,void*,void*)"
94
+ extern "int sqlite3_busy_timeout(db,int)"
95
+
96
+ extern "int sqlite3_set_authorizer(db,void*,void*)"
97
+ extern "void* sqlite3_trace(db,void*,void*)"
98
+
99
+ extern "int sqlite3_bind_blob(stmt,int,const void*,int,void*)"
100
+ extern "int sqlite3_bind_double(stmt,int,double)"
101
+ extern "int sqlite3_bind_int(stmt,int,int)"
102
+ extern "int sqlite3_bind_int64(stmt,int,int64)"
103
+ extern "int sqlite3_bind_null(stmt,int)"
104
+ extern "int sqlite3_bind_text(stmt,int,const char*,int,void*)"
105
+ extern "int sqlite3_bind_text16(stmt,int,const void*,int,void*)"
106
+ #extern "int sqlite3_bind_value(stmt,int,value)"
107
+
108
+ extern "int sqlite3_bind_parameter_count(stmt)"
109
+ extern "const char* sqlite3_bind_parameter_name(stmt,int)"
110
+ extern "int sqlite3_bind_parameter_index(stmt,const char*)"
111
+
112
+ extern "int sqlite3_column_count(stmt)"
113
+ extern "int sqlite3_data_count(stmt)"
114
+
115
+ extern "const void *sqlite3_column_blob(stmt,int)"
116
+ extern "int sqlite3_column_bytes(stmt,int)"
117
+ extern "int sqlite3_column_bytes16(stmt,int)"
118
+ extern "const char *sqlite3_column_decltype(stmt,int)"
119
+ extern "void *sqlite3_column_decltype16(stmt,int)"
120
+ extern "double sqlite3_column_double(stmt,int)"
121
+ extern "int sqlite3_column_int(stmt,int)"
122
+ extern "int64 sqlite3_column_int64(stmt,int)"
123
+ extern "const char *sqlite3_column_name(stmt,int)"
124
+ extern "const void *sqlite3_column_name16(stmt,int)"
125
+ extern "const char *sqlite3_column_text(stmt,int)"
126
+ extern "const void *sqlite3_column_text16(stmt,int)"
127
+ extern "int sqlite3_column_type(stmt,int)"
128
+
129
+ extern "int sqlite3_create_function(db,const char*,int,int,void*,void*,void*,void*)"
130
+ extern "int sqlite3_create_function16(db,const void*,int,int,void*,void*,void*,void*)"
131
+ extern "int sqlite3_aggregate_count(context)"
132
+
133
+ extern "const void *sqlite3_value_blob(value)"
134
+ extern "int sqlite3_value_bytes(value)"
135
+ extern "int sqlite3_value_bytes16(value)"
136
+ extern "double sqlite3_value_double(value)"
137
+ extern "int sqlite3_value_int(value)"
138
+ extern "int64 sqlite3_value_int64(value)"
139
+ extern "const char* sqlite3_value_text(value)"
140
+ extern "const void* sqlite3_value_text16(value)"
141
+ extern "const void* sqlite3_value_text16le(value)"
142
+ extern "const void* sqlite3_value_text16be(value)"
143
+ extern "int sqlite3_value_type(value)"
144
+
145
+ extern "void *sqlite3_aggregate_context(context,int)"
146
+ extern "void *sqlite3_user_data(context)"
147
+ extern "void *sqlite3_get_auxdata(context,int)"
148
+ extern "void sqlite3_set_auxdata(context,int,void*,void*)"
149
+
150
+ extern "void sqlite3_result_blob(context,const void*,int,void*)"
151
+ extern "void sqlite3_result_double(context,double)"
152
+ extern "void sqlite3_result_error(context,const char*,int)"
153
+ extern "void sqlite3_result_error16(context,const void*,int)"
154
+ extern "void sqlite3_result_int(context,int)"
155
+ extern "void sqlite3_result_int64(context,int64)"
156
+ extern "void sqlite3_result_null(context)"
157
+ extern "void sqlite3_result_text(context,const char*,int,void*)"
158
+ extern "void sqlite3_result_text16(context,const void*,int,void*)"
159
+ extern "void sqlite3_result_text16le(context,const void*,int,void*)"
160
+ extern "void sqlite3_result_text16be(context,const void*,int,void*)"
161
+ extern "void sqlite3_result_value(context,value)"
162
+
163
+ extern "int sqlite3_create_collation(db,const char*,int,void*,void*)"
164
+ extern "int sqlite3_create_collation16(db,const char*,int,void*,void*)"
165
+ extern "int sqlite3_collation_needed(db,void*,void*)"
166
+ extern "int sqlite3_collation_needed16(db,void*,void*)"
167
+
168
+ # ==== CRYPTO (NOT IN PUBLIC RELEASE) ====
169
+ if defined?( CRYPTO_API ) && CRYPTO_API
170
+ extern "int sqlite3_key(db,void*,int)"
171
+ extern "int sqlite3_rekey(db,void*,int)"
172
+ end
173
+
174
+ # ==== EXPERIMENTAL ====
175
+ if defined?( EXPERIMENTAL_API ) && EXPERIMENTAL_API
176
+ extern "int sqlite3_progress_handler(db,int,void*,void*)"
177
+ extern "int sqlite3_commit_hook(db,void*,void*)"
178
+ end
179
+
180
+ end
181
+
182
+ end ; end ; end
@@ -0,0 +1,320 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # * The names of its contributors may not be used to endorse or promote
17
+ # products derived from this software without specific prior written
18
+ # permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ # =============================================================================
31
+ #++
32
+
33
+ require 'sqlite3/driver/dl/api'
34
+
35
+ module Kernel
36
+ # Allows arbitrary objects to be passed as a pointer to functions.
37
+ # (Probably not very GC safe, but by encapsulating it like this we
38
+ # can change the implementation later.)
39
+ def to_ptr
40
+ ptr = DL.malloc(DL.sizeof("L"))
41
+ ptr.set_object self
42
+ ptr
43
+ end
44
+ end
45
+
46
+ class DL::PtrData
47
+ # The inverse of the Kernel#to_ptr operation.
48
+ def to_object
49
+ n = to_s(4).unpack("L").first
50
+ return nil if n < 1
51
+ ObjectSpace._id2ref(n)
52
+ end
53
+
54
+ def set_object(obj)
55
+ self[0] = [obj.object_id].pack("L")
56
+ end
57
+ end
58
+
59
+ module SQLite3 ; module Driver ; module DL
60
+
61
+ class Driver
62
+ STATIC = ::DL::PtrData.new(0)
63
+ TRANSIENT = ::DL::PtrData.new(-1)
64
+
65
+ def open( filename, utf16=false )
66
+ handle = ::DL::PtrData.new(0)
67
+ result = API.send( ( utf16 ? :sqlite3_open16 : :sqlite3_open ),
68
+ filename+"\0", handle.ref )
69
+ [ result, handle ]
70
+ end
71
+
72
+ def errmsg( db, utf16=false )
73
+ if utf16
74
+ msg = API.sqlite3_errmsg16( db )
75
+ msg.free = nil
76
+ msg.to_s(utf16_length(msg))
77
+ else
78
+ API.sqlite3_errmsg( db )
79
+ end
80
+ end
81
+
82
+ def prepare( db, sql, utf16=false )
83
+ handle = ::DL::PtrData.new(0)
84
+ remainder = ::DL::PtrData.new(0)
85
+
86
+ result = API.send( ( utf16 ? :sqlite3_prepare16 : :sqlite3_prepare ),
87
+ db, sql+"\0", sql.length, handle.ref, remainder.ref )
88
+
89
+ args = utf16 ? [ utf16_length(remainder) ] : []
90
+ remainder = remainder.to_s( *args )
91
+
92
+ [ result, handle, remainder ]
93
+ end
94
+
95
+ def complete?( sql, utf16=false )
96
+ API.send( utf16 ? :sqlite3_complete16 : :sqlite3_complete, sql+"\0" )
97
+ end
98
+
99
+ def value_blob( value )
100
+ blob = API.sqlite3_value_blob( value )
101
+ blob.free = nil
102
+ blob.to_s( API.sqlite3_value_bytes( value ) )
103
+ end
104
+
105
+ def value_text( value, utf16=false )
106
+ method = case utf16
107
+ when nil, false then :sqlite3_value_text
108
+ when :le then :sqlite3_value_text16le
109
+ when :be then :sqlite3_value_text16be
110
+ else :sqlite3_value_text16
111
+ end
112
+
113
+ result = API.send( method, value )
114
+ if utf16
115
+ result.free = nil
116
+ size = API.sqlite3_value_bytes( value )
117
+ result = result.to_s( size )
118
+ end
119
+
120
+ result
121
+ end
122
+
123
+ def column_blob( stmt, column )
124
+ blob = API.sqlite3_column_blob( stmt, column )
125
+ blob.free = nil
126
+ blob.to_s( API.sqlite3_column_bytes( stmt, column ) )
127
+ end
128
+
129
+ def result_text( func, text, utf16=false )
130
+ method = case utf16
131
+ when false, nil then :sqlite3_result_text
132
+ when :le then :sqlite3_result_text16le
133
+ when :be then :sqlite3_result_text16be
134
+ else :sqlite3_result_text16
135
+ end
136
+
137
+ s = text.to_s
138
+ API.send( method, func, s, s.length, TRANSIENT )
139
+ end
140
+
141
+ def busy_handler( db, data=nil, &block )
142
+ @busy_handler = block
143
+
144
+ unless @busy_handler_callback
145
+ @busy_handler_callback = ::DL.callback( "IPI" ) do |cookie, timeout|
146
+ @busy_handler.call( cookie, timeout ) || 0
147
+ end
148
+ end
149
+
150
+ API.sqlite3_busy_handler( db, block&&@busy_handler_callback, data )
151
+ end
152
+
153
+ def set_authorizer( db, data=nil, &block )
154
+ @authorizer_handler = block
155
+
156
+ unless @authorizer_handler_callback
157
+ @authorizer_handler_callback = ::DL.callback( "IPIPPPP"
158
+ ) do |cookie,mode,a,b,c,d|
159
+ @authorizer_handler.call( cookie, mode,
160
+ a&&a.to_s, b&&b.to_s, c&&c.to_s, d&&d.to_s ) || 0
161
+ end
162
+ end
163
+
164
+ API.sqlite3_set_authorizer( db, block&&@authorizer_handler_callback,
165
+ data )
166
+ end
167
+
168
+ def trace( db, data=nil, &block )
169
+ @trace_handler = block
170
+
171
+ unless @trace_handler_callback
172
+ @trace_handler_callback = ::DL.callback( "IPS" ) do |cookie,sql|
173
+ @trace_handler.call( cookie, sql ) || 0
174
+ end
175
+ end
176
+
177
+ API.sqlite3_trace( db, block&&@trace_handler_callback, data )
178
+ end
179
+
180
+ def create_function( db, name, args, text, cookie,
181
+ func, step, final )
182
+ # begin
183
+ if @func_handler_callback.nil? && func
184
+ @func_handler_callback = ::DL.callback( "0PIP" ) do |context,nargs,args|
185
+ args = args.to_s(nargs*4).unpack("L*").map {|i| ::DL::PtrData.new(i)}
186
+ data = API.sqlite3_user_data( context ).to_object
187
+ data[:func].call( context, *args )
188
+ end
189
+ end
190
+
191
+ if @step_handler_callback.nil? && step
192
+ @step_handler_callback = ::DL.callback( "0PIP" ) do |context,nargs,args|
193
+ args = args.to_s(nargs*4).unpack("L*").map {|i| ::DL::PtrData.new(i)}
194
+ data = API.sqlite3_user_data( context ).to_object
195
+ data[:step].call( context, *args )
196
+ end
197
+ end
198
+
199
+ if @final_handler_callback.nil? && final
200
+ @final_handler_callback = ::DL.callback( "0P" ) do |context|
201
+ data = API.sqlite3_user_data( context ).to_object
202
+ data[:final].call( context )
203
+ end
204
+ end
205
+
206
+ data = { :cookie => cookie,
207
+ :name => name,
208
+ :func => func,
209
+ :step => step,
210
+ :final => final }
211
+
212
+ API.sqlite3_create_function( db, name, args, text, data,
213
+ ( func ? @func_handler_callback : nil ),
214
+ ( step ? @step_handler_callback : nil ),
215
+ ( final ? @final_handler_callback : nil ) )
216
+ end
217
+
218
+ def aggregate_context( context )
219
+ ptr = API.sqlite3_aggregate_context( context, 4 )
220
+ ptr.free = nil
221
+ obj = ptr.to_object
222
+ if obj.nil?
223
+ obj = Hash.new
224
+ ptr.set_object obj
225
+ end
226
+ obj
227
+ end
228
+
229
+ def bind_blob( stmt, index, value )
230
+ s = value.to_s
231
+ API.sqlite3_bind_blob( stmt, index, s, s.length, TRANSIENT )
232
+ end
233
+
234
+ def bind_text( stmt, index, value, utf16=false )
235
+ s = value.to_s
236
+ method = ( utf16 ? :sqlite3_bind_text16 : :sqlite3_bind_text )
237
+ API.send( method, stmt, index, s, s.length, TRANSIENT )
238
+ end
239
+
240
+ def self.api_delegate( name )
241
+ define_method( name ) { |*args| API.send( "sqlite3_#{name}", *args ) }
242
+ end
243
+
244
+ api_delegate :aggregate_count
245
+ api_delegate :bind_double
246
+ api_delegate :bind_int
247
+ api_delegate :bind_null
248
+ api_delegate :bind_parameter_index
249
+ api_delegate :bind_parameter_name
250
+ api_delegate :busy_timeout
251
+ api_delegate :changes
252
+ api_delegate :close
253
+ api_delegate :column_count
254
+ api_delegate :column_decltype
255
+ api_delegate :column_double
256
+ api_delegate :column_int
257
+ api_delegate :column_int64
258
+ api_delegate :column_name
259
+ api_delegate :column_text
260
+ api_delegate :column_type
261
+ api_delegate :data_count
262
+ api_delegate :errcode
263
+ api_delegate :finalize
264
+ api_delegate :interrupt
265
+ api_delegate :last_insert_rowid
266
+ api_delegate :libversion
267
+ api_delegate :reset
268
+ api_delegate :result_error
269
+ api_delegate :step
270
+ api_delegate :total_changes
271
+ api_delegate :value_bytes
272
+ api_delegate :value_bytes16
273
+ api_delegate :value_double
274
+ api_delegate :value_int
275
+ api_delegate :value_int64
276
+ api_delegate :value_type
277
+
278
+ # ==== EXPERIMENTAL ====
279
+ if defined?( EXPERIMENTAL_API ) && EXPERIMENTAL_API
280
+ def progress_handler( db, n, data=nil, &block )
281
+ @progress_handler = block
282
+
283
+ unless @progress_handler_callback
284
+ @progress_handler_callback = ::DL.callback( "IP" ) do |cookie|
285
+ @progress_handler.call( cookie )
286
+ end
287
+ end
288
+
289
+ API.sqlite3_progress_handler( db, n, block&&@progress_handler_callback,
290
+ data )
291
+ end
292
+
293
+ def commit_hook( db, data=nil, &block )
294
+ @commit_hook_handler = block
295
+
296
+ unless @commit_hook_handler_callback
297
+ @commit_hook_handler_callback = ::DL.callback( "IP" ) do |cookie|
298
+ @commit_hook_handler.call( cookie )
299
+ end
300
+ end
301
+
302
+ API.sqlite3_commit_hook( db, block&&@commit_hook_handler_callback,
303
+ data )
304
+ end
305
+ end
306
+
307
+ private
308
+
309
+ def utf16_length(ptr)
310
+ len = 0
311
+ loop do
312
+ break if ptr[len,1] == "\0"
313
+ len += 2
314
+ end
315
+ len
316
+ end
317
+
318
+ end
319
+
320
+ end ; end ; end