sqlite3 1.3.13 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,11 +43,9 @@ static VALUE initialize(VALUE self, VALUE db, VALUE sql)
43
43
  if(!db_ctx->db)
44
44
  rb_raise(rb_eArgError, "prepare called on a closed database");
45
45
 
46
- #ifdef HAVE_RUBY_ENCODING_H
47
46
  if(!UTF8_P(sql)) {
48
47
  sql = rb_str_export_to_enc(sql, rb_utf8_encoding());
49
48
  }
50
- #endif
51
49
 
52
50
  #ifdef HAVE_SQLITE3_PREPARE_V2
53
51
  status = sqlite3_prepare_v2(
@@ -110,9 +108,7 @@ static VALUE step(VALUE self)
110
108
  sqlite3_stmt *stmt;
111
109
  int value, length;
112
110
  VALUE list;
113
- #ifdef HAVE_RUBY_ENCODING_H
114
111
  rb_encoding * internal_encoding;
115
- #endif
116
112
 
117
113
  Data_Get_Struct(self, sqlite3StmtRuby, ctx);
118
114
 
@@ -120,17 +116,24 @@ static VALUE step(VALUE self)
120
116
 
121
117
  if(ctx->done_p) return Qnil;
122
118
 
123
- #ifdef HAVE_RUBY_ENCODING_H
124
119
  {
125
120
  VALUE db = rb_iv_get(self, "@connection");
126
121
  rb_funcall(db, rb_intern("encoding"), 0);
127
122
  internal_encoding = rb_default_internal_encoding();
128
123
  }
129
- #endif
130
124
 
131
125
  stmt = ctx->st;
132
126
 
133
127
  value = sqlite3_step(stmt);
128
+ if (rb_errinfo() != Qnil) {
129
+ /* some user defined function was invoked as a callback during step and
130
+ * it raised an exception that has been suppressed until step returns.
131
+ * Now re-raise it. */
132
+ VALUE exception = rb_errinfo();
133
+ rb_set_errinfo(Qnil);
134
+ rb_exc_raise(exception);
135
+ }
136
+
134
137
  length = sqlite3_column_count(stmt);
135
138
  list = rb_ary_new2((long)length);
136
139
 
@@ -148,21 +151,19 @@ static VALUE step(VALUE self)
148
151
  break;
149
152
  case SQLITE_TEXT:
150
153
  {
151
- VALUE str = rb_tainted_str_new(
154
+ VALUE str = rb_str_new(
152
155
  (const char *)sqlite3_column_text(stmt, i),
153
156
  (long)sqlite3_column_bytes(stmt, i)
154
157
  );
155
- #ifdef HAVE_RUBY_ENCODING_H
156
158
  rb_enc_associate_index(str, rb_utf8_encindex());
157
159
  if(internal_encoding)
158
160
  str = rb_str_export_to_enc(str, internal_encoding);
159
- #endif
160
161
  rb_ary_push(list, str);
161
162
  }
162
163
  break;
163
164
  case SQLITE_BLOB:
164
165
  {
165
- VALUE str = rb_tainted_str_new(
166
+ VALUE str = rb_str_new(
166
167
  (const char *)sqlite3_column_blob(stmt, i),
167
168
  (long)sqlite3_column_bytes(stmt, i)
168
169
  );
@@ -225,9 +226,7 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
225
226
  switch(TYPE(value)) {
226
227
  case T_STRING:
227
228
  if(CLASS_OF(value) == cSqlite3Blob
228
- #ifdef HAVE_RUBY_ENCODING_H
229
229
  || rb_enc_get_index(value) == rb_ascii8bit_encindex()
230
- #endif
231
230
  ) {
232
231
  status = sqlite3_bind_blob(
233
232
  ctx->st,
@@ -239,7 +238,6 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
239
238
  } else {
240
239
 
241
240
 
242
- #ifdef HAVE_RUBY_ENCODING_H
243
241
  if (UTF16_LE_P(value) || UTF16_BE_P(value)) {
244
242
  status = sqlite3_bind_text16(
245
243
  ctx->st,
@@ -252,7 +250,6 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
252
250
  if (!UTF8_P(value) || !USASCII_P(value)) {
253
251
  value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
254
252
  }
255
- #endif
256
253
  status = sqlite3_bind_text(
257
254
  ctx->st,
258
255
  index,
@@ -260,9 +257,7 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
260
257
  (int)RSTRING_LEN(value),
261
258
  SQLITE_TRANSIENT
262
259
  );
263
- #ifdef HAVE_RUBY_ENCODING_H
264
260
  }
265
- #endif
266
261
  }
267
262
  break;
268
263
  case T_BIGNUM: {
@@ -316,7 +311,7 @@ static VALUE reset_bang(VALUE self)
316
311
  * Resets the statement. This is typically done internally, though it might
317
312
  * occassionally be necessary to manually reset the statement.
318
313
  */
319
- static VALUE clear_bindings(VALUE self)
314
+ static VALUE clear_bindings_bang(VALUE self)
320
315
  {
321
316
  sqlite3StmtRubyPtr ctx;
322
317
 
@@ -433,7 +428,7 @@ void init_sqlite3_statement()
433
428
  rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
434
429
  rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
435
430
  rb_define_method(cSqlite3Statement, "reset!", reset_bang, 0);
436
- rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings, 0);
431
+ rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings_bang, 0);
437
432
  rb_define_method(cSqlite3Statement, "step", step, 0);
438
433
  rb_define_method(cSqlite3Statement, "done?", done_p, 0);
439
434
  rb_define_method(cSqlite3Statement, "column_count", column_count, 0);
@@ -6,6 +6,7 @@ module SQLite3 ; module Constants
6
6
  UTF16BE = 3
7
7
  UTF16 = 4
8
8
  ANY = 5
9
+ DETERMINISTIC = 0x800
9
10
  end
10
11
 
11
12
  module ColumnType
@@ -54,12 +54,68 @@ module SQLite3
54
54
  # as hashes or not. By default, rows are returned as arrays.
55
55
  attr_accessor :results_as_hash
56
56
 
57
+ # call-seq: SQLite3::Database.new(file, options = {})
58
+ #
59
+ # Create a new Database object that opens the given file. If utf16
60
+ # is +true+, the filename is interpreted as a UTF-16 encoded string.
61
+ #
62
+ # By default, the new database will return result rows as arrays
63
+ # (#results_as_hash) and has type translation disabled (#type_translation=).
64
+
65
+ def initialize file, options = {}, zvfs = nil
66
+ mode = Constants::Open::READWRITE | Constants::Open::CREATE
67
+
68
+ if file.encoding == ::Encoding::UTF_16LE || file.encoding == ::Encoding::UTF_16BE || options[:utf16]
69
+ open16 file
70
+ else
71
+ # The three primary flag values for sqlite3_open_v2 are:
72
+ # SQLITE_OPEN_READONLY
73
+ # SQLITE_OPEN_READWRITE
74
+ # SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -- always used for sqlite3_open and sqlite3_open16
75
+ mode = Constants::Open::READONLY if options[:readonly]
76
+
77
+ if options[:readwrite]
78
+ raise "conflicting options: readonly and readwrite" if options[:readonly]
79
+ mode = Constants::Open::READWRITE
80
+ end
81
+
82
+ if options[:flags]
83
+ if options[:readonly] || options[:readwrite]
84
+ raise "conflicting options: flags with readonly and/or readwrite"
85
+ end
86
+ mode = options[:flags]
87
+ end
88
+
89
+ open_v2 file.encode("utf-8"), mode, zvfs
90
+ end
91
+
92
+ @tracefunc = nil
93
+ @authorizer = nil
94
+ @encoding = nil
95
+ @busy_handler = nil
96
+ @collations = {}
97
+ @functions = {}
98
+ @results_as_hash = options[:results_as_hash]
99
+ @type_translation = options[:type_translation]
100
+ @type_translator = make_type_translator @type_translation
101
+ @readonly = mode & Constants::Open::READONLY != 0
102
+
103
+ if block_given?
104
+ begin
105
+ yield self
106
+ ensure
107
+ close
108
+ end
109
+ end
110
+ end
111
+
57
112
  def type_translation= value # :nodoc:
58
113
  warn(<<-eowarn) if $VERBOSE
59
114
  #{caller[0]} is calling SQLite3::Database#type_translation=
60
115
  SQLite3::Database#type_translation= is deprecated and will be removed
61
116
  in version 2.0.0.
62
117
  eowarn
118
+ @type_translator = make_type_translator value
63
119
  @type_translation = value
64
120
  end
65
121
  attr_reader :type_translation # :nodoc:
@@ -136,25 +192,14 @@ Support for bind parameters as *args will be removed in 2.0.0.
136
192
 
137
193
  prepare( sql ) do |stmt|
138
194
  stmt.bind_params(bind_vars)
139
- columns = stmt.columns
140
- stmt = ResultSet.new(self, stmt).to_a if type_translation
195
+ stmt = ResultSet.new self, stmt
141
196
 
142
197
  if block_given?
143
198
  stmt.each do |row|
144
- if @results_as_hash
145
- yield type_translation ? row : ordered_map_for(columns, row)
146
- else
147
- yield row
148
- end
199
+ yield row
149
200
  end
150
201
  else
151
- if @results_as_hash
152
- stmt.map { |row|
153
- type_translation ? row : ordered_map_for(columns, row)
154
- }
155
- else
156
- stmt.to_a
157
- end
202
+ stmt.to_a
158
203
  end
159
204
  end
160
205
  end
@@ -190,6 +235,9 @@ Support for bind parameters as *args will be removed in 2.0.0.
190
235
  #
191
236
  # This always returns +nil+, making it unsuitable for queries that return
192
237
  # rows.
238
+ #
239
+ # See also #execute_batch2 for additional ways of
240
+ # executing statments.
193
241
  def execute_batch( sql, bind_vars = [], *args )
194
242
  # FIXME: remove this stuff later
195
243
  unless [Array, Hash].include?(bind_vars.class)
@@ -234,6 +282,30 @@ Support for this behavior will be removed in version 2.0.0.
234
282
  nil
235
283
  end
236
284
 
285
+ # Executes all SQL statements in the given string. By contrast, the other
286
+ # means of executing queries will only execute the first statement in the
287
+ # string, ignoring all subsequent statements. This will execute each one
288
+ # in turn. Bind parameters cannot be passed to #execute_batch2.
289
+ #
290
+ # If a query is made, all values will be returned as strings.
291
+ # If no query is made, an empty array will be returned.
292
+ #
293
+ # Because all values except for 'NULL' are returned as strings,
294
+ # a block can be passed to parse the values accordingly.
295
+ #
296
+ # See also #execute_batch for additional ways of
297
+ # executing statments.
298
+ def execute_batch2(sql, &block)
299
+ if block_given?
300
+ result = exec_batch(sql, @results_as_hash)
301
+ result.map do |val|
302
+ yield val
303
+ end
304
+ else
305
+ exec_batch(sql, @results_as_hash)
306
+ end
307
+ end
308
+
237
309
  # This is a convenience method for creating a statement, binding
238
310
  # paramters to it, and calling execute:
239
311
  #
@@ -287,7 +359,11 @@ Support for this will be removed in version 2.0.0.
287
359
  #
288
360
  # See also #get_first_row.
289
361
  def get_first_value( sql, *bind_vars )
290
- execute( sql, *bind_vars ) { |row| return row[0] }
362
+ query( sql, bind_vars ) do |rs|
363
+ if (row = rs.next)
364
+ return @results_as_hash ? row[rs.columns[0]] : row[0]
365
+ end
366
+ end
291
367
  nil
292
368
  end
293
369
 
@@ -316,8 +392,8 @@ Support for this will be removed in version 2.0.0.
316
392
  # end
317
393
  #
318
394
  # puts db.get_first_value( "select maim(name) from table" )
319
- def create_function name, arity, text_rep=Constants::TextRep::ANY, &block
320
- define_function(name) do |*args|
395
+ def create_function name, arity, text_rep=Constants::TextRep::UTF8, &block
396
+ define_function_with_flags(name, text_rep) do |*args|
321
397
  fp = FunctionProxy.new
322
398
  block.call(fp, *args)
323
399
  fp.result
@@ -364,42 +440,52 @@ Support for this will be removed in version 2.0.0.
364
440
  def create_aggregate( name, arity, step=nil, finalize=nil,
365
441
  text_rep=Constants::TextRep::ANY, &block )
366
442
 
367
- factory = Class.new do
443
+ proxy = Class.new do
368
444
  def self.step( &block )
369
- define_method(:step, &block)
445
+ define_method(:step_with_ctx, &block)
370
446
  end
371
447
 
372
448
  def self.finalize( &block )
373
- define_method(:finalize, &block)
449
+ define_method(:finalize_with_ctx, &block)
374
450
  end
375
451
  end
376
452
 
377
453
  if block_given?
378
- factory.instance_eval(&block)
454
+ proxy.instance_eval(&block)
379
455
  else
380
- factory.class_eval do
381
- define_method(:step, step)
382
- define_method(:finalize, finalize)
456
+ proxy.class_eval do
457
+ define_method(:step_with_ctx, step)
458
+ define_method(:finalize_with_ctx, finalize)
383
459
  end
384
460
  end
385
461
 
386
- proxy = factory.new
387
- proxy.extend(Module.new {
388
- attr_accessor :ctx
462
+ proxy.class_eval do
463
+ # class instance variables
464
+ @name = name
465
+ @arity = arity
466
+
467
+ def self.name
468
+ @name
469
+ end
470
+
471
+ def self.arity
472
+ @arity
473
+ end
474
+
475
+ def initialize
476
+ @ctx = FunctionProxy.new
477
+ end
389
478
 
390
479
  def step( *args )
391
- super(@ctx, *args)
480
+ step_with_ctx(@ctx, *args)
392
481
  end
393
482
 
394
483
  def finalize
395
- super(@ctx)
396
- result = @ctx.result
397
- @ctx = FunctionProxy.new
398
- result
484
+ finalize_with_ctx(@ctx)
485
+ @ctx.result
399
486
  end
400
- })
401
- proxy.ctx = FunctionProxy.new
402
- define_aggregator(name, proxy)
487
+ end
488
+ define_aggregator2(proxy, name)
403
489
  end
404
490
 
405
491
  # This is another approach to creating an aggregate function (see
@@ -450,29 +536,75 @@ Support for this will be removed in version 2.0.0.
450
536
  # db.create_aggregate_handler( LengthsAggregateHandler )
451
537
  # puts db.get_first_value( "select lengths(name) from A" )
452
538
  def create_aggregate_handler( handler )
453
- proxy = Class.new do
454
- def initialize klass
455
- @klass = klass
456
- @fp = FunctionProxy.new
539
+ # This is a compatiblity shim so the (basically pointless) FunctionProxy
540
+ # "ctx" object is passed as first argument to both step() and finalize().
541
+ # Now its up to the library user whether he prefers to store his
542
+ # temporaries as instance varibales or fields in the FunctionProxy.
543
+ # The library user still must set the result value with
544
+ # FunctionProxy.result= as there is no backwards compatible way to
545
+ # change this.
546
+ proxy = Class.new(handler) do
547
+ def initialize
548
+ super
549
+ @fp = FunctionProxy.new
457
550
  end
458
551
 
459
552
  def step( *args )
460
- instance.step(@fp, *args)
553
+ super(@fp, *args)
461
554
  end
462
555
 
463
556
  def finalize
464
- instance.finalize @fp
465
- @instance = nil
557
+ super(@fp)
466
558
  @fp.result
467
559
  end
560
+ end
561
+ define_aggregator2(proxy, proxy.name)
562
+ self
563
+ end
468
564
 
469
- private
565
+ # Define an aggregate function named +name+ using a object template
566
+ # object +aggregator+. +aggregator+ must respond to +step+ and +finalize+.
567
+ # +step+ will be called with row information and +finalize+ must return the
568
+ # return value for the aggregator function.
569
+ #
570
+ # _API Change:_ +aggregator+ must also implement +clone+. The provided
571
+ # +aggregator+ object will serve as template that is cloned to provide the
572
+ # individual instances of the aggregate function. Regular ruby objects
573
+ # already provide a suitable +clone+.
574
+ # The functions arity is the arity of the +step+ method.
575
+ def define_aggregator( name, aggregator )
576
+ # Previously, this has been implemented in C. Now this is just yet
577
+ # another compatiblity shim
578
+ proxy = Class.new do
579
+ @template = aggregator
580
+ @name = name
470
581
 
471
- def instance
472
- @instance ||= @klass.new
582
+ def self.template
583
+ @template
584
+ end
585
+
586
+ def self.name
587
+ @name
588
+ end
589
+
590
+ def self.arity
591
+ # this is what sqlite3_obj_method_arity did before
592
+ @template.method(:step).arity
593
+ end
594
+
595
+ def initialize
596
+ @klass = self.class.template.clone
597
+ end
598
+
599
+ def step(*args)
600
+ @klass.step(*args)
601
+ end
602
+
603
+ def finalize
604
+ @klass.finalize
473
605
  end
474
606
  end
475
- define_aggregator(handler.name, proxy.new(handler))
607
+ define_aggregator2(proxy, name)
476
608
  self
477
609
  end
478
610
 
@@ -499,7 +631,7 @@ Support for this will be removed in version 2.0.0.
499
631
  abort = false
500
632
  begin
501
633
  yield self
502
- rescue ::Object
634
+ rescue
503
635
  abort = true
504
636
  raise
505
637
  ensure
@@ -580,12 +712,25 @@ Support for this will be removed in version 2.0.0.
580
712
  end
581
713
  end
582
714
 
715
+ # Translates a +row+ of data from the database with the given +types+
716
+ def translate_from_db types, row
717
+ @type_translator.call types, row
718
+ end
719
+
583
720
  private
584
721
 
585
- def ordered_map_for columns, row
586
- h = Hash[*columns.zip(row).flatten]
587
- row.each_with_index { |r, i| h[i] = r }
588
- h
722
+ NULL_TRANSLATOR = lambda { |_, row| row }
723
+
724
+ def make_type_translator should_translate
725
+ if should_translate
726
+ lambda { |types, row|
727
+ types.zip(row).map do |type, value|
728
+ translator.translate( type, value )
729
+ end
730
+ }
731
+ else
732
+ NULL_TRANSLATOR
733
+ end
589
734
  end
590
735
  end
591
736
  end
@@ -2,17 +2,8 @@ require 'sqlite3/constants'
2
2
 
3
3
  module SQLite3
4
4
  class Exception < ::StandardError
5
- @code = 0
6
-
7
- # The numeric error code that this exception represents.
8
- def self.code
9
- @code
10
- end
11
-
12
5
  # A convenience for accessing the error code for this exception.
13
- def code
14
- self.class.code
15
- end
6
+ attr_reader :code
16
7
  end
17
8
 
18
9
  class SQLException < Exception; end
@@ -19,19 +19,19 @@ module SQLite3
19
19
  # integer that represents truth.
20
20
  def set_boolean_pragma( name, mode )
21
21
  case mode
22
- when String
22
+ when String
23
23
  case mode.downcase
24
- when "on", "yes", "true", "y", "t"; mode = "'ON'"
25
- when "off", "no", "false", "n", "f"; mode = "'OFF'"
26
- else
24
+ when "on", "yes", "true", "y", "t"; mode = "'ON'"
25
+ when "off", "no", "false", "n", "f"; mode = "'OFF'"
26
+ else
27
27
  raise Exception,
28
28
  "unrecognized pragma parameter #{mode.inspect}"
29
29
  end
30
- when true, 1
30
+ when true, 1
31
31
  mode = "ON"
32
- when false, 0, nil
32
+ when false, 0, nil
33
33
  mode = "OFF"
34
- else
34
+ else
35
35
  raise Exception,
36
36
  "unrecognized pragma parameter #{mode.inspect}"
37
37
  end
@@ -108,11 +108,7 @@ object that created this object
108
108
  row = @stmt.step
109
109
  return nil if @stmt.done?
110
110
 
111
- if @db.type_translation
112
- row = @stmt.types.zip(row).map do |type, value|
113
- @db.translator.translate( type, value )
114
- end
115
- end
111
+ row = @db.translate_from_db @stmt.types, row
116
112
 
117
113
  if row.respond_to?(:fields)
118
114
  # FIXME: this can only happen if the translator returns something
@@ -176,11 +172,7 @@ object that created this object
176
172
 
177
173
  # FIXME: type translation is deprecated, so this can be removed
178
174
  # in 2.0
179
- if @db.type_translation
180
- row = @stmt.types.zip(row).map do |type, value|
181
- @db.translator.translate( type, value )
182
- end
183
- end
175
+ row = @db.translate_from_db @stmt.types, row
184
176
 
185
177
  # FIXME: this can be switched to a regular hash in 2.0
186
178
  row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]
@@ -1,12 +1,12 @@
1
1
  module SQLite3
2
2
 
3
- VERSION = '1.3.13'
3
+ VERSION = '1.4.2'
4
4
 
5
5
  module VersionProxy
6
6
 
7
7
  MAJOR = 1
8
- MINOR = 3
9
- TINY = 13
8
+ MINOR = 4
9
+ TINY = 2
10
10
  BUILD = nil
11
11
 
12
12
  STRING = [ MAJOR, MINOR, TINY, BUILD ].compact.join( "." )
File without changes
@@ -6,14 +6,14 @@ rescue LoadError
6
6
  require 'hoe'
7
7
  end
8
8
 
9
- Hoe.plugin :debugging, :doofus, :git, :minitest, :bundler
9
+ Hoe.plugin :debugging, :doofus, :git, :minitest, :bundler, :gemspec
10
10
 
11
11
  HOE = Hoe.spec 'sqlite3' do
12
12
  developer 'Jamis Buck', 'jamis@37signals.com'
13
13
  developer 'Luis Lavena', 'luislavena@gmail.com'
14
14
  developer 'Aaron Patterson', 'aaron@tenderlovemaking.com'
15
15
 
16
- license "BSD-3"
16
+ license "BSD-3-Clause"
17
17
 
18
18
  self.readme_file = 'README.rdoc'
19
19
  self.history_file = 'CHANGELOG.rdoc'
@@ -23,12 +23,14 @@ HOE = Hoe.spec 'sqlite3' do
23
23
  require_rubygems_version ">= 1.3.5"
24
24
 
25
25
  spec_extras[:extensions] = ["ext/sqlite3/extconf.rb"]
26
+ spec_extras[:metadata] = {'msys2_mingw_dependencies' => 'sqlite3'}
26
27
 
27
- extra_dev_deps << ['rake-compiler', "~> 0.9.3"]
28
- extra_dev_deps << ['rake-compiler-dock', "~> 0.5.2"]
28
+ extra_dev_deps << ['rake-compiler', "~> 1.0"]
29
+ extra_dev_deps << ['rake-compiler-dock', "~> 0.6.0"]
29
30
  extra_dev_deps << ["mini_portile", "~> 0.6.2"]
30
31
  extra_dev_deps << ["minitest", "~> 5.0"]
31
32
  extra_dev_deps << ["hoe-bundler", "~> 1.0"]
33
+ extra_dev_deps << ["hoe-gemspec", "~> 1.0"]
32
34
 
33
35
  clean_globs.push('**/test.db')
34
36
  end
@@ -40,6 +40,10 @@ RUBY_EXTENSION = Rake::ExtensionTask.new('sqlite3_native', HOE.spec) do |ext|
40
40
  Rake::ExtensionCompiler.mingw_host
41
41
  ext.cross_compile = true
42
42
  ext.cross_platform = ['i386-mswin32-60', 'i386-mingw32', 'x64-mingw32']
43
+ ext.cross_compiling do |spec|
44
+ # The fat binary gem doesn't depend on the sqlite3 package, since it bundles the library.
45
+ spec.metadata.delete('msys2_mingw_dependencies')
46
+ end
43
47
  rescue RuntimeError
44
48
  # noop
45
49
  end
File without changes