sqlite3-ruby 1.2.5-x86-mswin32 → 1.3.0.beta.1-x86-mswin32

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.
Files changed (51) hide show
  1. data/API_CHANGES.rdoc +48 -0
  2. data/{History.txt → CHANGELOG.rdoc} +24 -0
  3. data/Manifest.txt +14 -14
  4. data/{README.txt → README.rdoc} +1 -6
  5. data/Rakefile +8 -3
  6. data/ext/sqlite3/database.c +687 -0
  7. data/ext/sqlite3/database.h +15 -0
  8. data/ext/sqlite3/exception.c +94 -0
  9. data/ext/sqlite3/exception.h +8 -0
  10. data/ext/sqlite3/extconf.rb +26 -0
  11. data/ext/sqlite3/sqlite3.c +33 -0
  12. data/ext/sqlite3/sqlite3_ruby.h +43 -0
  13. data/ext/sqlite3/statement.c +412 -0
  14. data/ext/sqlite3/statement.h +16 -0
  15. data/lib/sqlite3.rb +9 -0
  16. data/lib/sqlite3/1.8/sqlite3_native.so +0 -0
  17. data/lib/sqlite3/1.9/sqlite3_native.so +0 -0
  18. data/lib/sqlite3/database.rb +94 -302
  19. data/lib/sqlite3/errors.rb +0 -24
  20. data/lib/sqlite3/pragmas.rb +16 -7
  21. data/lib/sqlite3/resultset.rb +25 -81
  22. data/lib/sqlite3/statement.rb +22 -107
  23. data/lib/sqlite3/version.rb +4 -4
  24. data/setup.rb +2 -2
  25. data/tasks/native.rake +13 -17
  26. data/tasks/vendor_sqlite3.rake +10 -7
  27. data/test/helper.rb +1 -65
  28. data/test/test_database.rb +239 -189
  29. data/test/test_encoding.rb +115 -0
  30. data/test/test_integration.rb +38 -35
  31. data/test/test_integration_open_close.rb +1 -1
  32. data/test/test_integration_pending.rb +6 -4
  33. data/test/test_integration_resultset.rb +20 -8
  34. data/test/test_integration_statement.rb +1 -2
  35. data/test/test_sqlite3.rb +9 -0
  36. data/test/test_statement.rb +193 -0
  37. metadata +84 -49
  38. data/ext/sqlite3_api/extconf.rb +0 -10
  39. data/ext/sqlite3_api/sqlite3_api.i +0 -362
  40. data/ext/sqlite3_api/sqlite3_api_wrap.c +0 -5018
  41. data/lib/1.8/sqlite3_api.so +0 -0
  42. data/lib/1.9/sqlite3_api.so +0 -0
  43. data/lib/sqlite3/driver/dl/api.rb +0 -152
  44. data/lib/sqlite3/driver/dl/driver.rb +0 -307
  45. data/lib/sqlite3/driver/native/driver.rb +0 -219
  46. data/tasks/benchmark.rake +0 -9
  47. data/tasks/gem.rake +0 -32
  48. data/test/bm.rb +0 -140
  49. data/test/driver/dl/tc_driver.rb +0 -292
  50. data/test/native-vs-dl.rb +0 -126
  51. data/test/test_errors.rb +0 -17
@@ -0,0 +1,16 @@
1
+ #ifndef SQLITE3_STATEMENT_RUBY
2
+ #define SQLITE3_STATEMENT_RUBY
3
+
4
+ #include <sqlite3_ruby.h>
5
+
6
+ struct _sqlite3StmtRuby {
7
+ sqlite3_stmt *st;
8
+ int done_p;
9
+ };
10
+
11
+ typedef struct _sqlite3StmtRuby sqlite3StmtRuby;
12
+ typedef sqlite3StmtRuby * sqlite3StmtRubyPtr;
13
+
14
+ void init_sqlite3_statement();
15
+
16
+ #endif
data/lib/sqlite3.rb CHANGED
@@ -1 +1,10 @@
1
+ # support multiple ruby version (fat binaries under windows)
2
+ begin
3
+ RUBY_VERSION =~ /(\d+.\d+)/
4
+ require "sqlite3/#{$1}/sqlite3_native"
5
+ rescue LoadError
6
+ require 'sqlite3/sqlite3_native'
7
+ end
8
+
1
9
  require 'sqlite3/database'
10
+ require 'sqlite3/version'
Binary file
Binary file
@@ -35,7 +35,7 @@ module SQLite3
35
35
  class Database
36
36
  include Pragmas
37
37
 
38
- class <<self
38
+ class << self
39
39
 
40
40
  alias :open :new
41
41
 
@@ -48,12 +48,6 @@ module SQLite3
48
48
 
49
49
  end
50
50
 
51
- # The low-level opaque database handle that this object wraps.
52
- attr_reader :handle
53
-
54
- # A reference to the underlying SQLite3 driver used by this database.
55
- attr_reader :driver
56
-
57
51
  # A boolean that indicates whether rows in result sets should be returned
58
52
  # as hashes or not. By default, rows are returned as arrays.
59
53
  attr_accessor :results_as_hash
@@ -62,54 +56,6 @@ module SQLite3
62
56
  # database.
63
57
  attr_accessor :type_translation
64
58
 
65
- # Create a new Database object that opens the given file. If utf16
66
- # is +true+, the filename is interpreted as a UTF-16 encoded string.
67
- #
68
- # By default, the new database will return result rows as arrays
69
- # (#results_as_hash) and has type translation disabled (#type_translation=).
70
- def initialize( file_name, options={} ) # :yields: db
71
- utf16 = options.fetch(:utf16, false)
72
- load_driver( options[:driver] )
73
-
74
- @statement_factory = options[:statement_factory] || Statement
75
-
76
- result, @handle = @driver.open( file_name, utf16 )
77
- Error.check( result, self, "could not open database" )
78
-
79
- @closed = false
80
- @results_as_hash = options.fetch(:results_as_hash,false)
81
- @type_translation = options.fetch(:type_translation,false)
82
- @translator = nil
83
- @transaction_active = false
84
-
85
- if block_given?
86
- begin
87
- yield self
88
- ensure
89
- self.close
90
- end
91
- end
92
- end
93
-
94
- # Return +true+ if the string is a valid (ie, parsable) SQL statement, and
95
- # +false+ otherwise. If +utf16+ is +true+, then the string is a UTF-16
96
- # character string.
97
- def complete?( string, utf16=false )
98
- @driver.complete?( string, utf16 )
99
- end
100
-
101
- # Return a string describing the last error to have occurred with this
102
- # database.
103
- def errmsg( utf16=false )
104
- @driver.errmsg( @handle, utf16 )
105
- end
106
-
107
- # Return an integer representing the last error to have occurred with this
108
- # database.
109
- def errcode
110
- @driver.errcode( @handle )
111
- end
112
-
113
59
  # Return the type translator employed by this database instance. Each
114
60
  # database instance has its own type translator; this allows for different
115
61
  # type handlers to be installed in each instance without affecting other
@@ -120,35 +66,12 @@ module SQLite3
120
66
  @translator ||= Translator.new
121
67
  end
122
68
 
123
- # Closes this database.
124
- def close
125
- unless @closed
126
- result = @driver.close( @handle )
127
- Error.check( result, self )
128
- end
129
- @closed = true
130
- end
131
-
132
- # Returns +true+ if this database instance has been closed (see #close).
133
- def closed?
134
- @closed
135
- end
136
-
137
- # Installs (or removes) a block that will be invoked for every SQL
138
- # statement executed. The block receives a two parameters: the +data+
139
- # argument, and the SQL statement executed. If the block is +nil+,
140
- # any existing tracer will be uninstalled.
141
- def trace( data=nil, &block )
142
- @driver.trace( @handle, data, &block )
143
- end
144
-
145
69
  # Installs (or removes) a block that will be invoked for every access
146
70
  # to the database. If the block returns 0 (or +nil+), the statement
147
71
  # is allowed to proceed. Returning 1 causes an authorization error to
148
72
  # occur, and returning 2 causes the access to be silently denied.
149
- def authorizer( data=nil, &block )
150
- result = @driver.set_authorizer( @handle, data, &block )
151
- Error.check( result, self )
73
+ def authorizer( &block )
74
+ self.authorizer = block
152
75
  end
153
76
 
154
77
  # Returns a Statement object representing the given SQL. This does not
@@ -156,16 +79,14 @@ module SQLite3
156
79
  #
157
80
  # The Statement can then be executed using Statement#execute.
158
81
  #
159
- def prepare( sql )
160
- stmt = @statement_factory.new( self, sql )
161
- if block_given?
162
- begin
163
- yield stmt
164
- ensure
165
- stmt.close
166
- end
167
- else
168
- return stmt
82
+ def prepare sql
83
+ stmt = SQLite3::Statement.new( self, sql )
84
+ return stmt unless block_given?
85
+
86
+ begin
87
+ yield stmt
88
+ ensure
89
+ stmt.close
169
90
  end
170
91
  end
171
92
 
@@ -183,13 +104,38 @@ module SQLite3
183
104
  #
184
105
  # See also #execute2, #query, and #execute_batch for additional ways of
185
106
  # executing statements.
186
- def execute( sql, *bind_vars )
107
+ def execute sql, *bind_vars, &block
108
+ # FIXME: This is a terrible hack and should be removed but is required
109
+ # for older versions of rails
110
+ hack = Object.const_defined?(:ActiveRecord) && sql =~ /^PRAGMA index_list/
111
+
187
112
  prepare( sql ) do |stmt|
188
- result = stmt.execute( *bind_vars )
113
+ stmt.bind_params( *bind_vars )
189
114
  if block_given?
190
- result.each { |row| yield row }
115
+ stmt.each do |row|
116
+ if @results_as_hash
117
+ h = Hash[*stmt.columns.zip(row).flatten]
118
+ row.each_with_index { |r, i| h[i] = r }
119
+
120
+ yield h
121
+ else
122
+ yield row
123
+ end
124
+ end
191
125
  else
192
- return result.inject( [] ) { |arr,row| arr << row; arr }
126
+ if @results_as_hash
127
+ stmt.map { |row|
128
+ h = Hash[*stmt.columns.zip(row).flatten]
129
+ row.each_with_index { |r, i| h[i] = r }
130
+
131
+ # FIXME UGH TERRIBLE HACK!
132
+ h['unique'] = h['unique'].to_s if hack
133
+
134
+ h
135
+ }
136
+ else
137
+ stmt.to_a
138
+ end
193
139
  end
194
140
  end
195
141
  end
@@ -208,10 +154,10 @@ module SQLite3
208
154
  prepare( sql ) do |stmt|
209
155
  result = stmt.execute( *bind_vars )
210
156
  if block_given?
211
- yield result.columns
157
+ yield stmt.columns
212
158
  result.each { |row| yield row }
213
159
  else
214
- return result.inject( [ result.columns ] ) { |arr,row|
160
+ return result.inject( [ stmt.columns ] ) { |arr,row|
215
161
  arr << row; arr }
216
162
  end
217
163
  end
@@ -229,7 +175,12 @@ module SQLite3
229
175
  sql = sql.strip
230
176
  until sql.empty? do
231
177
  prepare( sql ) do |stmt|
232
- stmt.execute( *bind_vars )
178
+ # FIXME: this should probably use sqlite3's api for batch execution
179
+ # This implementation requires stepping over the results.
180
+ if bind_vars.length == stmt.bind_parameter_count
181
+ stmt.bind_params(bind_vars)
182
+ end
183
+ stmt.step
233
184
  sql = stmt.remainder.strip
234
185
  end
235
186
  end
@@ -279,55 +230,7 @@ module SQLite3
279
230
  nil
280
231
  end
281
232
 
282
- # Obtains the unique row ID of the last row to be inserted by this Database
283
- # instance.
284
- def last_insert_row_id
285
- @driver.last_insert_rowid( @handle )
286
- end
287
-
288
- # Returns the number of changes made to this database instance by the last
289
- # operation performed. Note that a "delete from table" without a where
290
- # clause will not affect this value.
291
- def changes
292
- @driver.changes( @handle )
293
- end
294
-
295
- # Returns the total number of changes made to this database instance
296
- # since it was opened.
297
- def total_changes
298
- @driver.total_changes( @handle )
299
- end
300
-
301
- # Interrupts the currently executing operation, causing it to abort.
302
- def interrupt
303
- @driver.interrupt( @handle )
304
- end
305
-
306
- # Register a busy handler with this database instance. When a requested
307
- # resource is busy, this handler will be invoked. If the handler returns
308
- # +false+, the operation will be aborted; otherwise, the resource will
309
- # be requested again.
310
- #
311
- # The handler will be invoked with the name of the resource that was
312
- # busy, and the number of times it has been retried.
313
- #
314
- # See also the mutually exclusive #busy_timeout.
315
- def busy_handler( data=nil, &block ) # :yields: data, retries
316
- result = @driver.busy_handler( @handle, data, &block )
317
- Error.check( result, self )
318
- end
319
-
320
- # Indicates that if a request for a resource terminates because that
321
- # resource is busy, SQLite should sleep and retry for up to the indicated
322
- # number of milliseconds. By default, SQLite does not retry
323
- # busy resources. To restore the default behavior, send 0 as the
324
- # +ms+ parameter.
325
- #
326
- # See also the mutually exclusive #busy_handler.
327
- def busy_timeout( ms )
328
- result = @driver.busy_timeout( @handle, ms )
329
- Error.check( result, self )
330
- end
233
+ alias :busy_timeout :busy_timeout=
331
234
 
332
235
  # Creates a new function for use in SQL statements. It will be added as
333
236
  # +name+, with the given +arity+. (For variable arity functions, use
@@ -352,23 +255,12 @@ module SQLite3
352
255
  # end
353
256
  #
354
257
  # puts db.get_first_value( "select maim(name) from table" )
355
- def create_function( name, arity, text_rep=Constants::TextRep::ANY,
356
- &block ) # :yields: func, *args
357
- # begin
358
- callback = proc do |func,*args|
359
- begin
360
- block.call( FunctionProxy.new( @driver, func ),
361
- *args.map{|v| Value.new(self,v)} )
362
- rescue StandardError, Exception => e
363
- @driver.result_error( func,
364
- "#{e.message} (#{e.class})", -1 )
365
- end
258
+ def create_function name, arity, text_rep=Constants::TextRep::ANY, &block
259
+ define_function(name) do |*args|
260
+ fp = FunctionProxy.new
261
+ block.call(fp, *args)
262
+ fp.result
366
263
  end
367
-
368
- result = @driver.create_function( @handle, name, arity, text_rep, nil,
369
- callback, nil, nil )
370
- Error.check( result, self )
371
-
372
264
  self
373
265
  end
374
266
 
@@ -410,47 +302,40 @@ module SQLite3
410
302
  # aggregate functions.
411
303
  def create_aggregate( name, arity, step=nil, finalize=nil,
412
304
  text_rep=Constants::TextRep::ANY, &block )
413
- # begin
414
- if block
415
- proxy = AggregateDefinitionProxy.new
416
- proxy.instance_eval(&block)
417
- step ||= proxy.step_callback
418
- finalize ||= proxy.finalize_callback
419
- end
420
305
 
421
- step_callback = proc do |func,*args|
422
- ctx = @driver.aggregate_context( func )
423
- unless ctx[:__error]
424
- begin
425
- step.call( FunctionProxy.new( @driver, func, ctx ),
426
- *args.map{|v| Value.new(self,v)} )
427
- rescue Exception => e
428
- ctx[:__error] = e
429
- end
306
+ factory = Class.new do
307
+ def self.step( &block )
308
+ define_method(:step, &block)
309
+ end
310
+
311
+ def self.finalize( &block )
312
+ define_method(:finalize, &block)
430
313
  end
431
314
  end
432
315
 
433
- finalize_callback = proc do |func|
434
- ctx = @driver.aggregate_context( func )
435
- unless ctx[:__error]
436
- begin
437
- finalize.call( FunctionProxy.new( @driver, func, ctx ) )
438
- rescue Exception => e
439
- @driver.result_error( func,
440
- "#{e.message} (#{e.class})", -1 )
441
- end
442
- else
443
- e = ctx[:__error]
444
- @driver.result_error( func,
445
- "#{e.message} (#{e.class})", -1 )
316
+ if block_given?
317
+ factory.instance_eval(&block)
318
+ else
319
+ factory.class_eval do
320
+ define_method(:step, step)
321
+ define_method(:finalize, finalize)
446
322
  end
447
323
  end
448
324
 
449
- result = @driver.create_function( @handle, name, arity, text_rep, nil,
450
- nil, step_callback, finalize_callback )
451
- Error.check( result, self )
325
+ proxy = factory.new
326
+ proxy.extend(Module.new {
327
+ attr_accessor :ctx
452
328
 
453
- self
329
+ def step( *args )
330
+ super(@ctx, *args)
331
+ end
332
+
333
+ def finalize
334
+ super(@ctx)
335
+ end
336
+ })
337
+ proxy.ctx = FunctionProxy.new
338
+ define_aggregator(name, proxy)
454
339
  end
455
340
 
456
341
  # This is another approach to creating an aggregate function (see
@@ -500,47 +385,22 @@ module SQLite3
500
385
  # db.create_aggregate_handler( LengthsAggregateHandler )
501
386
  # puts db.get_first_value( "select lengths(name) from A" )
502
387
  def create_aggregate_handler( handler )
503
- arity = -1
504
- text_rep = Constants::TextRep::ANY
505
-
506
- arity = handler.arity if handler.respond_to?(:arity)
507
- text_rep = handler.text_rep if handler.respond_to?(:text_rep)
508
- name = handler.name
509
-
510
- step = proc do |func,*args|
511
- ctx = @driver.aggregate_context( func )
512
- unless ctx[ :__error ]
513
- ctx[ :handler ] ||= handler.new
514
- begin
515
- ctx[ :handler ].step( FunctionProxy.new( @driver, func, ctx ),
516
- *args.map{|v| Value.new(self,v)} )
517
- rescue Exception, StandardError => e
518
- ctx[ :__error ] = e
519
- end
388
+ proxy = Class.new do
389
+ def initialize handler
390
+ @handler = handler
391
+ @fp = FunctionProxy.new
520
392
  end
521
- end
522
393
 
523
- finalize = proc do |func|
524
- ctx = @driver.aggregate_context( func )
525
- unless ctx[ :__error ]
526
- ctx[ :handler ] ||= handler.new
527
- begin
528
- ctx[ :handler ].finalize( FunctionProxy.new( @driver, func, ctx ) )
529
- rescue Exception => e
530
- ctx[ :__error ] = e
531
- end
394
+ def step( *args )
395
+ @handler.step(@fp, *args)
532
396
  end
533
397
 
534
- if ctx[ :__error ]
535
- e = ctx[ :__error ]
536
- @driver.sqlite3_result_error( func, "#{e.message} (#{e.class})", -1 )
398
+ def finalize
399
+ @handler.finalize @fp
400
+ @fp.result
537
401
  end
538
402
  end
539
-
540
- result = @driver.create_function( @handle, name, arity, text_rep, nil,
541
- nil, step, finalize )
542
- Error.check( result, self )
543
-
403
+ define_aggregator(handler.name, proxy.new(handler.new))
544
404
  self
545
405
  end
546
406
 
@@ -604,33 +464,6 @@ module SQLite3
604
464
  @transaction_active
605
465
  end
606
466
 
607
- # Loads the corresponding driver, or if it is nil, attempts to locate a
608
- # suitable driver.
609
- def load_driver( driver )
610
- case driver
611
- when Class
612
- # do nothing--use what was given
613
- when Symbol, String
614
- require "sqlite3/driver/#{driver.to_s.downcase}/driver"
615
- driver = SQLite3::Driver.const_get( driver )::Driver
616
- else
617
- [ "Native", "DL" ].each do |d|
618
- begin
619
- require "sqlite3/driver/#{d.downcase}/driver"
620
- driver = SQLite3::Driver.const_get( d )::Driver
621
- break
622
- rescue SyntaxError
623
- raise
624
- rescue ScriptError, Exception, NameError
625
- end
626
- end
627
- raise "no driver for sqlite3 found" unless driver
628
- end
629
-
630
- @driver = driver.new
631
- end
632
- private :load_driver
633
-
634
467
  # A helper class for dealing with custom functions (see #create_function,
635
468
  # #create_aggregate, and #create_aggregate_handler). It encapsulates the
636
469
  # opaque function object that represents the current invocation. It also
@@ -640,26 +473,15 @@ module SQLite3
640
473
  # This class will almost _always_ be instantiated indirectly, by working
641
474
  # with the create methods mentioned above.
642
475
  class FunctionProxy
476
+ attr_accessor :result
643
477
 
644
478
  # Create a new FunctionProxy that encapsulates the given +func+ object.
645
479
  # If context is non-nil, the functions context will be set to that. If
646
480
  # it is non-nil, it must quack like a Hash. If it is nil, then none of
647
481
  # the context functions will be available.
648
- def initialize( driver, func, context=nil )
649
- @driver = driver
650
- @func = func
651
- @context = context
652
- end
653
-
654
- # Calls #set_result to set the result of this function.
655
- def result=( result )
656
- set_result( result )
657
- end
658
-
659
- # Set the result of the function to the given value. The function will
660
- # then return this value.
661
- def set_result( result, utf16=false )
662
- @driver.result_text( @func, result, utf16 )
482
+ def initialize
483
+ @result = nil
484
+ @context = {}
663
485
  end
664
486
 
665
487
  # Set the result of the function to the given error message.
@@ -672,50 +494,20 @@ module SQLite3
672
494
  # that the aggregate has processed so far. This will include the current
673
495
  # row, and so will always return at least 1.
674
496
  def count
675
- ensure_aggregate!
676
497
  @driver.aggregate_count( @func )
677
498
  end
678
499
 
679
500
  # Returns the value with the given key from the context. This is only
680
501
  # available to aggregate functions.
681
502
  def []( key )
682
- ensure_aggregate!
683
503
  @context[ key ]
684
504
  end
685
505
 
686
506
  # Sets the value with the given key in the context. This is only
687
507
  # available to aggregate functions.
688
508
  def []=( key, value )
689
- ensure_aggregate!
690
509
  @context[ key ] = value
691
510
  end
692
-
693
- # A function for performing a sanity check, to ensure that the function
694
- # being invoked is an aggregate function. This is implied by the
695
- # existence of the context variable.
696
- def ensure_aggregate!
697
- unless @context
698
- raise MisuseException, "function is not an aggregate"
699
- end
700
- end
701
- private :ensure_aggregate!
702
-
703
- end
704
-
705
- # A proxy used for defining the callbacks to an aggregate function.
706
- class AggregateDefinitionProxy # :nodoc:
707
- attr_reader :step_callback, :finalize_callback
708
-
709
- def step( &block )
710
- @step_callback = block
711
- end
712
-
713
- def finalize( &block )
714
- @finalize_callback = block
715
- end
716
511
  end
717
-
718
512
  end
719
-
720
513
  end
721
-