sqlite3 2.9.6 → 2.10.2

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.
@@ -120,3 +120,98 @@ rb_sqlite3_raise_with_sql(sqlite3 *db, int status, const char *sql)
120
120
 
121
121
  rb_exc_raise(exception);
122
122
  }
123
+
124
+ /* Each call into sqlite that can run callbacks pushes a frame on the current
125
+ * fiber's chain. A callback that fails records its rb_protect state in the top
126
+ * frame, and the call resumes Ruby's pending jump once sqlite returns. Ruby
127
+ * code that runs in between, such as a finalizer during an allocation, pushes
128
+ * its own frame for any nested call, so it never takes the outer call's jump.
129
+ * The chain is fiber-local because Ruby code inside a callback can switch
130
+ * threads or fibers, and a Ruby thread can move between native threads inside
131
+ * rb_protect. */
132
+ typedef struct {
133
+ rb_sqlite3_callback_frame_t *top;
134
+ } callback_frames_t;
135
+
136
+ static const rb_data_type_t callback_frames_type = {
137
+ .wrap_struct_name = "SQLite3::CallbackFrames",
138
+ .function = {
139
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
140
+ },
141
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
142
+ };
143
+
144
+ static ID id_callback_frames;
145
+
146
+ /* Ruby code can overwrite or delete the fiber-local, so check its type. */
147
+ static VALUE
148
+ current_callback_frames_holder(void)
149
+ {
150
+ VALUE holder = rb_thread_local_aref(rb_thread_current(), id_callback_frames);
151
+ return rb_typeddata_is_kind_of(holder, &callback_frames_type) ? holder : Qnil;
152
+ }
153
+
154
+ static callback_frames_t *
155
+ current_callback_frames(void)
156
+ {
157
+ VALUE holder = current_callback_frames_holder();
158
+ return NIL_P(holder) ? NULL : (callback_frames_t *)RTYPEDDATA_DATA(holder);
159
+ }
160
+
161
+ void
162
+ rb_sqlite3_push_callback_frame(rb_sqlite3_callback_frame_t *frame)
163
+ {
164
+ VALUE holder = current_callback_frames_holder();
165
+ callback_frames_t *frames;
166
+
167
+ if (NIL_P(holder)) {
168
+ holder = TypedData_Make_Struct(rb_cObject, callback_frames_t, &callback_frames_type, frames);
169
+ rb_thread_local_aset(rb_thread_current(), id_callback_frames, holder);
170
+ }
171
+ frames = (callback_frames_t *)RTYPEDDATA_DATA(holder);
172
+
173
+ frame->state = 0;
174
+ frame->prev = frames->top;
175
+ frame->holder = holder;
176
+ frames->top = frame;
177
+ }
178
+
179
+ int
180
+ rb_sqlite3_pop_callback_frame(rb_sqlite3_callback_frame_t *frame)
181
+ {
182
+ ((callback_frames_t *)RTYPEDDATA_DATA(frame->holder))->top = frame->prev;
183
+ return frame->state;
184
+ }
185
+
186
+ VALUE
187
+ rb_sqlite3_protect_callback(VALUE (*body)(VALUE), VALUE data, int *failed)
188
+ {
189
+ callback_frames_t *frames = current_callback_frames();
190
+ rb_sqlite3_callback_frame_t *frame = frames ? frames->top : NULL;
191
+ VALUE result;
192
+ int state;
193
+
194
+ if (frame && frame->state) {
195
+ *failed = 1;
196
+ return Qnil;
197
+ }
198
+
199
+ result = rb_protect(body, data, &state);
200
+ *failed = state != 0;
201
+
202
+ if (frame) {
203
+ frame->state = state;
204
+ } else if (state) {
205
+ /* sqlite ran the callback from a call that cannot resume the jump, such
206
+ * as Statement#reset!, so the error is dropped */
207
+ rb_set_errinfo(Qnil);
208
+ }
209
+
210
+ return result;
211
+ }
212
+
213
+ void
214
+ init_sqlite3_exception(void)
215
+ {
216
+ id_callback_frames = rb_intern("__sqlite3_callback_frames__");
217
+ }
@@ -9,4 +9,25 @@ void rb_sqlite3_raise(sqlite3 *db, int status);
9
9
  void rb_sqlite3_raise_msg(sqlite3 *db, int status, const char *msg);
10
10
  void rb_sqlite3_raise_with_sql(sqlite3 *db, int status, const char *sql);
11
11
 
12
+ typedef struct rb_sqlite3_callback_frame {
13
+ int state;
14
+ struct rb_sqlite3_callback_frame *prev;
15
+ /* the frame lives on the C stack, so GC marks and pins this */
16
+ VALUE holder;
17
+ } rb_sqlite3_callback_frame_t;
18
+
19
+ /* A call into sqlite that can run callbacks is wrapped in a frame. sqlite
20
+ * cannot carry a raise or a throw, so a failed callback records its rb_protect
21
+ * state in the frame, and later callbacks skip their Ruby code. Pop the frame
22
+ * when sqlite returns, then resume the jump with rb_jump_tag if the returned
23
+ * state is nonzero. Run nothing but the sqlite call in between, because a
24
+ * raise there would skip the pop. */
25
+ void rb_sqlite3_push_callback_frame(rb_sqlite3_callback_frame_t *frame);
26
+ int rb_sqlite3_pop_callback_frame(rb_sqlite3_callback_frame_t *frame);
27
+
28
+ /* Runs a callback's Ruby code for sqlite. Sets *failed if it did not complete. */
29
+ VALUE rb_sqlite3_protect_callback(VALUE (*body)(VALUE), VALUE data, int *failed);
30
+
31
+ void init_sqlite3_exception(void);
32
+
12
33
  #endif
@@ -65,7 +65,10 @@ module Sqlite3
65
65
  "-DSQLITE_ENABLE_DBPAGE_VTAB=1",
66
66
  "-DSQLITE_ENABLE_DBSTAT_VTAB=1"
67
67
  ]
68
- env["CFLAGS"] = [user_cflags, env["CFLAGS"], more_cflags].flatten.join(" ")
68
+ # sqlite >= 3.54 requires Vista APIs, same as ruby's default target. Placed first so a
69
+ # user-defined _WIN32_WINNT takes precedence.
70
+ windows_cflags = windows? ? ["-D_WIN32_WINNT=0x0600"] : []
71
+ env["CFLAGS"] = [windows_cflags, user_cflags, env["CFLAGS"], more_cflags].flatten.join(" ")
69
72
  recipe.configure_options += env.slice(*ENV_ALLOWLIST)
70
73
  .map { |key, value| "#{key}=#{value.strip}" }
71
74
  end
@@ -115,9 +118,10 @@ module Sqlite3
115
118
 
116
119
  abort_could_not_find(libname) unless find_library(libname, "sqlite3_libversion_number", "sqlite3.h")
117
120
 
118
- # Truffle Ruby doesn't support this yet:
121
+ # Ruby 3.0+, but not on every implementation:
119
122
  # https://github.com/oracle/truffleruby/issues/3408
120
123
  have_func("rb_enc_interned_str_cstr")
124
+ have_func("rb_enc_interned_str")
121
125
 
122
126
  # Functions defined in 1.9 but not 1.8
123
127
  have_func("rb_proc_arity")
@@ -139,6 +143,8 @@ module Sqlite3
139
143
  have_func("sqlite3_prepare_v2")
140
144
  have_func("sqlite3_db_name", "sqlite3.h") # v3.39.0
141
145
  have_func("sqlite3_error_offset", "sqlite3.h") # v3.38.0
146
+ have_func("sqlite3_serialize", "sqlite3.h") # v3.23.0
147
+ have_func("sqlite3_deserialize", "sqlite3.h") # v3.23.0
142
148
 
143
149
  have_type("sqlite3_int64", "sqlite3.h")
144
150
  have_type("sqlite3_uint64", "sqlite3.h")
@@ -60,6 +60,19 @@ bignum_to_int64(VALUE value, sqlite3_int64 *result)
60
60
  #endif
61
61
  }
62
62
 
63
+ void
64
+ rb_sqlite3_pin_array_and_contents(VALUE ary)
65
+ {
66
+ long i;
67
+
68
+ if (NIL_P(ary) || !ary) { return; }
69
+
70
+ rb_gc_mark(ary);
71
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
72
+ rb_gc_mark(RARRAY_AREF(ary, i));
73
+ }
74
+ }
75
+
63
76
  static VALUE
64
77
  libversion(VALUE UNUSED(klass))
65
78
  {
@@ -191,6 +204,7 @@ Init_sqlite3_native(void)
191
204
  sqlite3_initialize();
192
205
  #endif
193
206
 
207
+ init_sqlite3_exception();
194
208
  init_sqlite3_constants();
195
209
  init_sqlite3_database();
196
210
  init_sqlite3_statement();
@@ -45,4 +45,7 @@ extern VALUE cSqlite3Blob;
45
45
 
46
46
  int bignum_to_int64(VALUE big, sqlite3_int64 *result);
47
47
 
48
+ /* Pinning a collection doesn't pin what's in it, hence both. */
49
+ void rb_sqlite3_pin_array_and_contents(VALUE ary);
50
+
48
51
  #endif
@@ -31,7 +31,7 @@ statement_memsize(const void *data)
31
31
  }
32
32
 
33
33
  static const rb_data_type_t statement_type = {
34
- "SQLite3::Backup",
34
+ "SQLite3::Statement",
35
35
  {
36
36
  NULL,
37
37
  statement_deallocate,
@@ -54,8 +54,9 @@ prepare(VALUE self, VALUE db, VALUE sql)
54
54
  {
55
55
  sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
56
56
  sqlite3StmtRubyPtr ctx;
57
- const char *tail = NULL;
58
- int status;
57
+ const char *sql_cstr, *tail = NULL;
58
+ rb_sqlite3_callback_frame_t frame;
59
+ int sql_len, status, callback_state;
59
60
 
60
61
  StringValue(sql);
61
62
 
@@ -66,20 +67,26 @@ prepare(VALUE self, VALUE db, VALUE sql)
66
67
  * variable will keep it from being GCed. */
67
68
  ctx->db = db_ctx;
68
69
 
70
+ timespecclear(&db_ctx->stmt_deadline);
71
+
72
+ sql_cstr = StringValuePtr(sql);
73
+ sql_len = RSTRING_LENINT(sql);
74
+
75
+ rb_sqlite3_push_callback_frame(&frame);
69
76
  #ifdef HAVE_SQLITE3_PREPARE_V2
70
77
  status = sqlite3_prepare_v2(
71
78
  #else
72
79
  status = sqlite3_prepare(
73
80
  #endif
74
81
  db_ctx->db,
75
- (const char *)StringValuePtr(sql),
76
- (int)RSTRING_LEN(sql),
82
+ sql_cstr,
83
+ sql_len,
77
84
  &ctx->st,
78
85
  &tail
79
86
  );
87
+ if ((callback_state = rb_sqlite3_pop_callback_frame(&frame))) { rb_jump_tag(callback_state); }
80
88
 
81
89
  CHECK_PREPARE(db_ctx->db, status, StringValuePtr(sql));
82
- timespecclear(&db_ctx->stmt_deadline);
83
90
 
84
91
  return rb_utf8_str_new_cstr(tail);
85
92
  }
@@ -124,7 +131,8 @@ step(VALUE self)
124
131
  {
125
132
  sqlite3StmtRubyPtr ctx;
126
133
  sqlite3_stmt *stmt;
127
- int value, length;
134
+ rb_sqlite3_callback_frame_t frame;
135
+ int value, length, callback_state;
128
136
  VALUE list;
129
137
  rb_encoding *internal_encoding;
130
138
 
@@ -139,14 +147,17 @@ step(VALUE self)
139
147
 
140
148
  stmt = ctx->st;
141
149
 
150
+ if (!sqlite3_stmt_busy(stmt)) {
151
+ timespecclear(&ctx->db->stmt_deadline);
152
+ }
153
+
154
+ rb_sqlite3_push_callback_frame(&frame);
142
155
  value = sqlite3_step(stmt);
143
- if (rb_errinfo() != Qnil) {
144
- /* some user defined function was invoked as a callback during step and
145
- * it raised an exception that has been suppressed until step returns.
146
- * Now re-raise it. */
147
- VALUE exception = rb_errinfo();
148
- rb_set_errinfo(Qnil);
149
- rb_exc_raise(exception);
156
+ if ((callback_state = rb_sqlite3_pop_callback_frame(&frame))) { rb_jump_tag(callback_state); }
157
+
158
+ if (value == SQLITE_DONE) {
159
+ ctx->done_p = 1;
160
+ return Qnil;
150
161
  }
151
162
 
152
163
  length = sqlite3_column_count(stmt);
@@ -195,10 +206,6 @@ step(VALUE self)
195
206
  }
196
207
  }
197
208
  break;
198
- case SQLITE_DONE:
199
- ctx->done_p = 1;
200
- return Qnil;
201
- break;
202
209
  default:
203
210
  sqlite3_reset(stmt);
204
211
  ctx->done_p = 0;
@@ -216,6 +223,25 @@ step(VALUE self)
216
223
  * Fixnum, it is treated as an index for a positional placeholder.
217
224
  * Otherwise it is used as the name of the placeholder to bind to.
218
225
  *
226
+ * Type mapping from Ruby to SQLite3:
227
+ * - +nil+ → NULL
228
+ * - Integer → INTEGER (or REAL when outside the signed int64 range)
229
+ * - Float → REAL
230
+ * - SQLite3::Blob → BLOB
231
+ * - String with Encoding::ASCII_8BIT (a.k.a. BINARY) → BLOB
232
+ * - String with Encoding::UTF_16LE or Encoding::UTF_16BE → TEXT (bound as UTF-16)
233
+ * - String (all other encodings) → TEXT (re-encoded to UTF-8 if necessary)
234
+ * - Any other type → raises RuntimeError
235
+ *
236
+ * Note: if you have a string with only ASCII characters but ASCII-8BIT
237
+ * encoding and want it bound as TEXT rather than BLOB, re-encode it first:
238
+ *
239
+ * stmt.bind_param(1, my_binary_str.encode(Encoding::UTF_8))
240
+ *
241
+ * The value that this method binds stays bound when you execute or reset the
242
+ * statement. To change the value, bind a new value to the same parameter. To
243
+ * clear all values, call #clear_bindings!.
244
+ *
219
245
  * See also #bind_params.
220
246
  */
221
247
  static VALUE
@@ -254,7 +280,7 @@ bind_param(VALUE self, VALUE key, VALUE value)
254
280
  ctx->st,
255
281
  index,
256
282
  (const char *)StringValuePtr(value),
257
- (int)RSTRING_LEN(value),
283
+ RSTRING_LENINT(value),
258
284
  SQLITE_TRANSIENT
259
285
  );
260
286
  } else {
@@ -265,7 +291,7 @@ bind_param(VALUE self, VALUE key, VALUE value)
265
291
  ctx->st,
266
292
  index,
267
293
  (const char *)StringValuePtr(value),
268
- (int)RSTRING_LEN(value),
294
+ RSTRING_LENINT(value),
269
295
  SQLITE_TRANSIENT
270
296
  );
271
297
  } else {
@@ -276,7 +302,7 @@ bind_param(VALUE self, VALUE key, VALUE value)
276
302
  ctx->st,
277
303
  index,
278
304
  (const char *)StringValuePtr(value),
279
- (int)RSTRING_LEN(value),
305
+ RSTRING_LENINT(value),
280
306
  SQLITE_TRANSIENT
281
307
  );
282
308
  }
@@ -311,8 +337,11 @@ bind_param(VALUE self, VALUE key, VALUE value)
311
337
 
312
338
  /* call-seq: stmt.reset!
313
339
  *
314
- * Resets the statement. This is typically done internally, though it might
315
- * occasionally be necessary to manually reset the statement.
340
+ * Resets the statement. The library usually calls this method for you, but
341
+ * you can also call it yourself.
342
+ *
343
+ * This method does not clear the values that you bound to the parameters. To
344
+ * clear them, call #clear_bindings!.
316
345
  */
317
346
  static VALUE
318
347
  reset_bang(VALUE self)
@@ -333,8 +362,11 @@ reset_bang(VALUE self)
333
362
 
334
363
  /* call-seq: stmt.clear_bindings!
335
364
  *
336
- * Resets the statement. This is typically done internally, though it might
337
- * occasionally be necessary to manually reset the statement.
365
+ * Sets the value of each parameter in the statement to NULL.
366
+ *
367
+ * The values that you bind with #bind_param, #bind_params, or #execute stay
368
+ * bound when you execute or reset the statement. Call this method to clear
369
+ * them.
338
370
  */
339
371
  static VALUE
340
372
  clear_bindings_bang(VALUE self)
@@ -398,6 +430,33 @@ interned_utf8_cstr(const char *str)
398
430
  }
399
431
  #endif
400
432
 
433
+ /* Like interned_utf8_cstr, but ASCII-downcases as it copies. */
434
+ static VALUE
435
+ interned_downcased_utf8_cstr(const char *str)
436
+ {
437
+ #if HAVE_RB_ENC_INTERNED_STR
438
+ VALUE tmp, ret;
439
+ char *buf;
440
+ size_t i, len;
441
+
442
+ len = strlen(str);
443
+ buf = ALLOCV_N(char, tmp, len);
444
+
445
+ for (i = 0; i < len; i++) {
446
+ unsigned char c = (unsigned char)str[i];
447
+ buf[i] = (char)((c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c);
448
+ }
449
+
450
+ ret = rb_enc_interned_str(buf, (long)len, rb_utf8_encoding());
451
+ ALLOCV_END(tmp);
452
+ return ret;
453
+ #else
454
+ VALUE rb_str = rb_funcall(rb_utf8_str_new_cstr(str), rb_intern("downcase"), 1,
455
+ ID2SYM(rb_intern("ascii")));
456
+ return rb_funcall(rb_str, rb_intern("-@"), 0);
457
+ #endif
458
+ }
459
+
401
460
  /* call-seq: stmt.column_name(index)
402
461
  *
403
462
  * Get the column name at +index+. 0 based.
@@ -425,7 +484,8 @@ column_name(VALUE self, VALUE index)
425
484
 
426
485
  /* call-seq: stmt.column_decltype(index)
427
486
  *
428
- * Get the column type at +index+. 0 based.
487
+ * Get the declared type of the column at +index+, as a UTF-8 string. 0 based.
488
+ * Returns +nil+ if the column has no declared type, such as an expression.
429
489
  */
430
490
  static VALUE
431
491
  column_decltype(VALUE self, VALUE index)
@@ -440,7 +500,24 @@ column_decltype(VALUE self, VALUE index)
440
500
 
441
501
  name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
442
502
 
443
- if (name) { return rb_str_new2(name); }
503
+ if (name) { return rb_utf8_str_new_cstr(name); }
504
+ return Qnil;
505
+ }
506
+
507
+ static VALUE
508
+ column_decltype_downcased(VALUE self, VALUE index)
509
+ {
510
+ sqlite3StmtRubyPtr ctx;
511
+ const char *name;
512
+
513
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
514
+
515
+ REQUIRE_LIVE_DB(ctx);
516
+ REQUIRE_OPEN_STMT(ctx);
517
+
518
+ name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
519
+
520
+ if (name) { return interned_downcased_utf8_cstr(name); }
444
521
  return Qnil;
445
522
  }
446
523
 
@@ -733,6 +810,7 @@ init_sqlite3_statement(void)
733
810
  rb_define_method(cSqlite3Statement, "memused", memused, 0);
734
811
  #endif
735
812
 
813
+ rb_define_private_method(cSqlite3Statement, "column_decltype_downcased", column_decltype_downcased, 1);
736
814
  rb_define_private_method(cSqlite3Statement, "prepare", prepare, 2);
737
815
  rb_define_private_method(cSqlite3Statement, "stats_as_hash", stats_as_hash, 0);
738
816
  rb_define_private_method(cSqlite3Statement, "stat_for", stat_for, 1);
@@ -15,6 +15,15 @@
15
15
  (vsp)->tv_nsec += 1000000000L; \
16
16
  } \
17
17
  } while (0)
18
+ #define timespecadd(tsp, usp, vsp) \
19
+ do { \
20
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
21
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
22
+ if ((vsp)->tv_nsec >= 1000000000L) { \
23
+ (vsp)->tv_sec++; \
24
+ (vsp)->tv_nsec -= 1000000000L; \
25
+ } \
26
+ } while (0)
18
27
  #define timespecafter(tsp, usp) \
19
28
  (((tsp)->tv_sec > (usp)->tv_sec) || \
20
29
  ((tsp)->tv_sec == (usp)->tv_sec && (tsp)->tv_nsec > (usp)->tv_nsec))
@@ -579,6 +579,25 @@ module SQLite3
579
579
  self
580
580
  end
581
581
 
582
+ # The "handler" that #define_aggregator hands to define_aggregator2, which
583
+ # only needs something that responds to +new+ (a fresh aggregator for each
584
+ # aggregate invocation) and +arity+.
585
+ class AggregatorFactory # :nodoc:
586
+ def initialize(template)
587
+ @template = template
588
+ end
589
+
590
+ def new
591
+ @template.clone
592
+ end
593
+
594
+ # this is what sqlite3_obj_method_arity did before
595
+ def arity
596
+ @template.method(:step).arity
597
+ end
598
+ end
599
+ private_constant :AggregatorFactory
600
+
582
601
  # Define an aggregate function named +name+ using a object template
583
602
  # object +aggregator+. +aggregator+ must respond to +step+ and +finalize+.
584
603
  # +step+ will be called with row information and +finalize+ must return the
@@ -592,36 +611,7 @@ module SQLite3
592
611
  def define_aggregator(name, aggregator)
593
612
  # Previously, this has been implemented in C. Now this is just yet
594
613
  # another compatibility shim
595
- proxy = Class.new do
596
- @template = aggregator
597
- @name = name
598
-
599
- def self.template
600
- @template
601
- end
602
-
603
- def self.name
604
- @name
605
- end
606
-
607
- def self.arity
608
- # this is what sqlite3_obj_method_arity did before
609
- @template.method(:step).arity
610
- end
611
-
612
- def initialize
613
- @klass = self.class.template.clone
614
- end
615
-
616
- def step(*args)
617
- @klass.step(*args)
618
- end
619
-
620
- def finalize
621
- @klass.finalize
622
- end
623
- end
624
- define_aggregator2(proxy, name)
614
+ define_aggregator2(AggregatorFactory.new(aggregator), name)
625
615
  self
626
616
  end
627
617
 
@@ -16,8 +16,12 @@ module SQLite3
16
16
  @stmt = stmt
17
17
  end
18
18
 
19
- # Reset the cursor, so that a result set which has reached end-of-file
20
- # can be rewound and reiterated.
19
+ # Resets the cursor to the first row, so that you can iterate over the
20
+ # result set again after it reaches the end.
21
+ #
22
+ # This method binds each argument to the statement with
23
+ # Statement#bind_params. The values that you bound before stay bound
24
+ # unless you bind new values to the same parameters.
21
25
  def reset(*bind_params)
22
26
  @stmt.reset!
23
27
  @stmt.bind_params(*bind_params)
@@ -43,20 +47,26 @@ module SQLite3
43
47
  @stmt.step
44
48
  end
45
49
 
46
- # Required by the Enumerable mixin. Provides an internal iterator over the
47
- # rows of the result set.
50
+ # With a block given, iterates over the rows of the result set, passing each
51
+ # to the block. Returns self.
52
+ # With no block given, returns a new Enumerator.
48
53
  def each
54
+ return enum_for(__method__) unless block_given?
49
55
  while (node = self.next)
50
56
  yield node
51
57
  end
58
+ self
52
59
  end
53
60
 
54
- # Provides an internal iterator over the rows of the result set where
55
- # each row is yielded as a hash.
61
+ # With a block given, iterates over the rows of the result set, passing each
62
+ # to the block as a hash. Returns self.
63
+ # With no block given, returns a new Enumerator.
56
64
  def each_hash
65
+ return enum_for(__method__) unless block_given?
57
66
  while (node = next_hash)
58
67
  yield node
59
68
  end
69
+ self
60
70
  end
61
71
 
62
72
  # Closes the statement that spawned this result set.
@@ -42,11 +42,33 @@ module SQLite3
42
42
  # See Database#execute for a description of the valid placeholder
43
43
  # syntaxes.
44
44
  #
45
+ # Type mapping from Ruby to SQLite3:
46
+ # - +nil+ → NULL
47
+ # - Integer → INTEGER (or REAL when outside the signed int64 range)
48
+ # - Float → REAL
49
+ # - SQLite3::Blob → BLOB
50
+ # - String with Encoding::ASCII_8BIT
51
+ # (a.k.a. BINARY) → BLOB
52
+ # - String with Encoding::UTF_16LE
53
+ # or Encoding::UTF_16BE → TEXT (bound as UTF-16)
54
+ # - String (all other encodings) → TEXT (re-encoded to UTF-8 if needed)
55
+ # - Any other type → raises RuntimeError
56
+ #
57
+ # Note: a String with Encoding::ASCII_8BIT (BINARY) is always bound as a
58
+ # BLOB, even when its bytes are all valid ASCII. If you want such a string
59
+ # compared or stored as TEXT, re-encode it before binding:
60
+ #
61
+ # stmt.bind_params(my_binary_str.encode(Encoding::UTF_8))
62
+ #
45
63
  # Example:
46
64
  #
47
65
  # stmt = db.prepare( "select * from table where a=? and b=?" )
48
66
  # stmt.bind_params( 15, "hello" )
49
67
  #
68
+ # The values that this method binds stay bound when you execute or reset
69
+ # the statement. To change a value, bind a new value to the same
70
+ # parameter. To clear all values, call #clear_bindings!.
71
+ #
50
72
  # See also #execute, #bind_param, Statement#bind_param, and
51
73
  # Statement#bind_params.
52
74
  def bind_params(*bind_vars)
@@ -65,7 +87,17 @@ module SQLite3
65
87
  # statement's virtual machine. If a block was given, the new ResultSet will
66
88
  # be yielded to it; otherwise, the ResultSet will be returned.
67
89
  #
68
- # Any parameters will be bound to the statement using #bind_params.
90
+ # This method binds each argument to the statement with #bind_params. The
91
+ # values stay bound after this method returns. If a later call to #execute
92
+ # does not give a value for a parameter, the statement uses the value from
93
+ # the earlier call. To set all parameters to NULL before you execute the
94
+ # statement again, call #clear_bindings!:
95
+ #
96
+ # stmt = db.prepare( "select :a, :b" )
97
+ # stmt.execute( a: 1, b: 2 ).to_a # => [[1, 2]]
98
+ # stmt.execute( a: 3 ).to_a # => [[3, 2]]
99
+ # stmt.clear_bindings!
100
+ # stmt.execute( a: 3 ).to_a # => [[3, nil]]
69
101
  #
70
102
  # Example:
71
103
  #
@@ -74,7 +106,7 @@ module SQLite3
74
106
  # ...
75
107
  # end
76
108
  #
77
- # See also #bind_params, #execute!.
109
+ # See also #bind_params, #execute!, #clear_bindings!.
78
110
  def execute(*bind_vars)
79
111
  reset! if active? || done?
80
112
 
@@ -91,7 +123,9 @@ module SQLite3
91
123
  # rows returned by executing the statement. Otherwise, each row will be
92
124
  # yielded to the block.
93
125
  #
94
- # Any parameters will be bound to the statement using #bind_params.
126
+ # This method binds each argument to the statement with #bind_params. The
127
+ # values stay bound after this method returns. For more information, see
128
+ # #execute.
95
129
  #
96
130
  # Example:
97
131
  #
@@ -112,9 +146,9 @@ module SQLite3
112
146
  !done?
113
147
  end
114
148
 
115
- # Return an array of the column names for this statement. Note that this
116
- # may execute the statement in order to obtain the metadata; this makes it
117
- # a (potentially) expensive operation.
149
+ # Return a frozen array of the column names for this statement, as frozen
150
+ # UTF-8 strings. Note that this may execute the statement in order to
151
+ # obtain the metadata; this makes it a (potentially) expensive operation.
118
152
  def columns
119
153
  get_metadata unless @columns
120
154
  @columns
@@ -128,9 +162,11 @@ module SQLite3
128
162
  end
129
163
  end
130
164
 
131
- # Return an array of the data types for each column in this statement. Note
132
- # that this may execute the statement in order to obtain the metadata; this
133
- # makes it a (potentially) expensive operation.
165
+ # Return a frozen array of the declared types of the columns in this
166
+ # statement, as frozen UTF-8 strings with ASCII letters downcased. A column
167
+ # with no declared type, such as an expression, has a +nil+ type. Note that
168
+ # this may execute the statement in order to obtain the metadata; this makes
169
+ # it a (potentially) expensive operation.
134
170
  def types
135
171
  must_be_open!
136
172
  get_metadata unless @types
@@ -180,11 +216,10 @@ module SQLite3
180
216
  def get_metadata
181
217
  @columns = Array.new(column_count) do |column|
182
218
  column_name column
183
- end
219
+ end.freeze
184
220
  @types = Array.new(column_count) do |column|
185
- val = column_decltype(column)
186
- val&.downcase
187
- end
221
+ column_decltype_downcased(column)
222
+ end.freeze
188
223
  end
189
224
  end
190
225
  end