extralite-bundle 2.3 → 2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,8 +20,14 @@ static size_t Query_size(const void *ptr) {
20
20
 
21
21
  static void Query_mark(void *ptr) {
22
22
  Query_t *query = ptr;
23
- rb_gc_mark(query->db);
24
- rb_gc_mark(query->sql);
23
+ rb_gc_mark_movable(query->db);
24
+ rb_gc_mark_movable(query->sql);
25
+ }
26
+
27
+ static void Query_compact(void *ptr) {
28
+ Query_t *query = ptr;
29
+ query->db = rb_gc_location(query->db);
30
+ query->sql = rb_gc_location(query->sql);
25
31
  }
26
32
 
27
33
  static void Query_free(void *ptr) {
@@ -32,8 +38,8 @@ static void Query_free(void *ptr) {
32
38
 
33
39
  static const rb_data_type_t Query_type = {
34
40
  "Query",
35
- {Query_mark, Query_free, Query_size,},
36
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
41
+ {Query_mark, Query_free, Query_size, Query_compact},
42
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
37
43
  };
38
44
 
39
45
  static VALUE Query_allocate(VALUE klass) {
@@ -67,10 +73,12 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
67
73
  if (!RSTRING_LEN(sql))
68
74
  rb_raise(cError, "Cannot prepare an empty SQL query");
69
75
 
76
+ RB_OBJ_WRITE(self, &query->db, db);
77
+ RB_OBJ_WRITE(self, &query->sql, sql);
78
+
70
79
  query->db = db;
71
80
  query->db_struct = self_to_database(db);
72
81
  query->sqlite3_db = Database_sqlite3_db(db);
73
- query->sql = sql;
74
82
  query->stmt = NULL;
75
83
  query->closed = 0;
76
84
  query->eof = 0;
@@ -134,14 +142,14 @@ VALUE Query_reset(VALUE self) {
134
142
  * Bound parameters can be specified as a list of values or as a hash mapping
135
143
  * parameter names to values. When parameters are given as a splatted array, the
136
144
  * query should specify parameters using `?`:
137
- *
145
+ *
138
146
  * query = db.prepare('select * from foo where x = ?')
139
147
  * query.bind(42)
140
148
  *
141
149
  * Named placeholders are specified using `:`. The placeholder values are
142
150
  * specified using a hash, where keys are either strings are symbols. String
143
151
  * keys can include or omit the `:` prefix. The following are equivalent:
144
- *
152
+ *
145
153
  * query = db.prepare('select * from foo where x = :bar')
146
154
  * query.bind(bar: 42)
147
155
  *
@@ -171,19 +179,18 @@ VALUE Query_eof_p(VALUE self) {
171
179
  static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(query_ctx *)) {
172
180
  Query_t *query = self_to_query(self);
173
181
  if (query->closed) rb_raise(cError, "Query is closed");
174
-
182
+
175
183
  if (!query->stmt) query_reset(query);
176
184
  if (query->eof) return rb_block_given_p() ? self : Qnil;
177
185
 
178
- query_ctx ctx = {
186
+ query_ctx ctx = QUERY_CTX(
179
187
  self,
180
- query->sqlite3_db,
188
+ query->db_struct,
181
189
  query->stmt,
182
190
  Qnil,
183
191
  QUERY_MODE(max_rows == SINGLE_ROW ? QUERY_SINGLE_ROW : QUERY_MULTI_ROW),
184
- MAX_ROWS(max_rows),
185
- 0
186
- };
192
+ MAX_ROWS(max_rows)
193
+ );
187
194
  VALUE result = call(&ctx);
188
195
  query->eof = ctx.eof;
189
196
  return (ctx.mode == QUERY_YIELD) ? self : result;
@@ -193,12 +200,12 @@ static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(q
193
200
 
194
201
  /* Returns the next 1 or more rows from the associated query's result set as a
195
202
  * hash.
196
- *
203
+ *
197
204
  * If no row count is given, a single row is returned. If a row count is given,
198
205
  * an array containing up to the `row_count` rows is returned. If `row_count` is
199
206
  * -1, all rows are returned. If the end of the result set has been reached,
200
207
  * `nil` is returned.
201
- *
208
+ *
202
209
  * If a block is given, rows are passed to the block and self is returned.
203
210
  *
204
211
  * @overload next()
@@ -219,12 +226,12 @@ VALUE Query_next_hash(int argc, VALUE *argv, VALUE self) {
219
226
 
220
227
  /* Returns the next 1 or more rows from the associated query's result set as an
221
228
  * array.
222
- *
229
+ *
223
230
  * If no row count is given, a single row is returned. If a row count is given,
224
231
  * an array containing up to the `row_count` rows is returned. If `row_count` is
225
232
  * -1, all rows are returned. If the end of the result set has been reached,
226
233
  * `nil` is returned.
227
- *
234
+ *
228
235
  * If a block is given, rows are passed to the block and self is returned.
229
236
  *
230
237
  * @overload next_ary()
@@ -241,12 +248,12 @@ VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
241
248
  /* Returns the next 1 or more rows from the associated query's result set as an
242
249
  * single values. If the result set contains more than one column an error is
243
250
  * raised.
244
- *
251
+ *
245
252
  * If no row count is given, a single row is returned. If a row count is given,
246
253
  * an array containing up to the `row_count` rows is returned. If `row_count` is
247
254
  * -1, all rows are returned. If the end of the result set has been reached,
248
255
  * `nil` is returned.
249
- *
256
+ *
250
257
  * If a block is given, rows are passed to the block and self is returned.
251
258
  *
252
259
  * @overload next_ary()
@@ -261,7 +268,7 @@ VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self) {
261
268
  }
262
269
 
263
270
  /* Returns all rows in the associated query's result set as hashes.
264
- *
271
+ *
265
272
  * @overload to_a()
266
273
  * @return [Array<Hash>] all rows
267
274
  * @overload to_a_hash
@@ -274,7 +281,7 @@ VALUE Query_to_a_hash(VALUE self) {
274
281
  }
275
282
 
276
283
  /* Returns all rows in the associated query's result set as arrays.
277
- *
284
+ *
278
285
  * @return [Array<Array>] all rows
279
286
  */
280
287
  VALUE Query_to_a_ary(VALUE self) {
@@ -285,7 +292,7 @@ VALUE Query_to_a_ary(VALUE self) {
285
292
 
286
293
  /* Returns all rows in the associated query's result set as single values. If
287
294
  * the result set contains more than one column an error is raised.
288
- *
295
+ *
289
296
  * @return [Array<Object>] all rows
290
297
  */
291
298
  VALUE Query_to_a_single_column(VALUE self) {
@@ -297,7 +304,7 @@ VALUE Query_to_a_single_column(VALUE self) {
297
304
  /* Iterates through the result set, passing each row to the given block as a
298
305
  * hash. If no block is given, returns a `Extralite::Iterator` instance in hash
299
306
  * mode.
300
- *
307
+ *
301
308
  * @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
302
309
  */
303
310
  VALUE Query_each_hash(VALUE self) {
@@ -311,7 +318,7 @@ VALUE Query_each_hash(VALUE self) {
311
318
  /* Iterates through the result set, passing each row to the given block as an
312
319
  * array. If no block is given, returns a `Extralite::Iterator` instance in
313
320
  * array mode.
314
- *
321
+ *
315
322
  * @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
316
323
  */
317
324
  VALUE Query_each_ary(VALUE self) {
@@ -326,7 +333,7 @@ VALUE Query_each_ary(VALUE self) {
326
333
  * single value. If the result set contains more than one column an error is
327
334
  * raised. If no block is given, returns a `Extralite::Iterator` instance in
328
335
  * single column mode.
329
- *
336
+ *
330
337
  * @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
331
338
  */
332
339
  VALUE Query_each_single_column(VALUE self) {
@@ -366,30 +373,213 @@ VALUE Query_execute(int argc, VALUE *argv, VALUE self) {
366
373
  return Query_perform_next(self, ALL_ROWS, safe_query_changes);
367
374
  }
368
375
 
369
- /* Executes the query for each set of parameters in the given array. Parameters
370
- * can be specified as either an array (for unnamed parameters) or a hash (for
371
- * named parameters). Returns the number of changes effected. This method is
372
- * designed for inserting multiple records.
376
+ /* call-seq:
377
+ * query << [...] -> query
378
+ * query << { ... } -> query
379
+ *
380
+ * Runs the with the given parameters, returning the total changes effected.
381
+ * This method should be used for data- or schema-manipulation queries.
382
+ *
383
+ * Query parameters to be bound to placeholders in the query can be specified as
384
+ * a list of values or as a hash mapping parameter names to values. When
385
+ * parameters are given as an array, the query should specify parameters using
386
+ * `?`:
387
+ *
388
+ * query = db.prepare('update foo set x = ? where y = ?')
389
+ * query << [42, 43]
390
+ *
391
+ * Named placeholders are specified using `:`. The placeholder values are
392
+ * specified using a hash, where keys are either strings are symbols. String
393
+ * keys can include or omit the `:` prefix. The following are equivalent:
394
+ *
395
+ * query = db.prepare('update foo set x = :bar')
396
+ * query << { bar: 42 }
397
+ * query << { 'bar' => 42 }
398
+ * query << { ':bar' => 42 }
399
+ */
400
+ VALUE Query_execute_chevrons(VALUE self, VALUE params) {
401
+ Query_execute(1, &params, self);
402
+ return self;
403
+ }
404
+
405
+ /* call-seq:
406
+ * query.batch_execute(params_array) -> changes
407
+ * query.batch_execute(enumerable) -> changes
408
+ * query.batch_execute(callable) -> changes
409
+ *
410
+ * Executes the query for each set of parameters in the paramter source. If an
411
+ * enumerable is given, it is iterated and each of its values is used as the
412
+ * parameters for running the query. If a callable is given, it is called
413
+ * repeatedly and each of its return values is used as the parameters, until nil
414
+ * is returned.
415
+ *
416
+ * Returns the number of changes effected. This method is designed for inserting
417
+ * multiple records.
373
418
  *
374
419
  * query = db.prepare('insert into foo values (?, ?, ?)')
375
420
  * records = [
376
421
  * [1, 2, 3],
377
422
  * [4, 5, 6]
378
423
  * ]
379
- * query.execute_multi(records)
424
+ * query.batch_execute(records)
425
+ *
426
+ * source = [
427
+ * [1, 2, 3],
428
+ * [4, 5, 6]
429
+ * ]
430
+ * query.batch_execute { records.shift }
380
431
  *
381
- * @param parameters [Array<Array, Hash>] array of parameters to run query with
432
+ * @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] array of parameters to run query with
382
433
  * @return [Integer] number of changes effected
383
434
  */
384
- VALUE Query_execute_multi(VALUE self, VALUE parameters) {
435
+ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
385
436
  Query_t *query = self_to_query(self);
386
437
  if (query->closed) rb_raise(cError, "Query is closed");
387
438
 
388
439
  if (!query->stmt)
389
440
  prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
390
441
 
391
- query_ctx ctx = { self, query->sqlite3_db, query->stmt, parameters, QUERY_MODE(QUERY_MULTI_ROW), ALL_ROWS };
392
- return safe_execute_multi(&ctx);
442
+ query_ctx ctx = QUERY_CTX(
443
+ self,
444
+ query->db_struct,
445
+ query->stmt,
446
+ parameters,
447
+ QUERY_MODE(QUERY_MULTI_ROW),
448
+ ALL_ROWS
449
+ );
450
+ return safe_batch_execute(&ctx);
451
+ }
452
+
453
+ /* call-seq:
454
+ * query.batch_query(sql, params_array) -> rows
455
+ * query.batch_query(sql, enumerable) -> rows
456
+ * query.batch_query(sql, callable) -> rows
457
+ * query.batch_query(sql, params_array) { |rows| ... } -> changes
458
+ * query.batch_query(sql, enumerable) { |rows| ... } -> changes
459
+ * query.batch_query(sql, callable) { |rows| ... } -> changes
460
+ *
461
+ * Executes the prepared query for each list of parameters in the given paramter
462
+ * source. If a block is given, it is called with the resulting rows for each
463
+ * invocation of the query, and the total number of changes is returned.
464
+ * Otherwise, an array containing the resulting rows for each invocation is
465
+ * returned.
466
+ *
467
+ * q = db.prepare('insert into foo values (?, ?) returning bar, baz')
468
+ * records = [
469
+ * [1, 2],
470
+ * [3, 4]
471
+ * ]
472
+ * q.batch_query(records)
473
+ * #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
474
+ * *
475
+ * @param sql [String] query SQL
476
+ * @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
477
+ * @return [Array<Hash>, Integer] Total number of changes effected
478
+ */
479
+ VALUE Query_batch_query(VALUE self, VALUE parameters) {
480
+ Query_t *query = self_to_query(self);
481
+ if (query->closed) rb_raise(cError, "Query is closed");
482
+
483
+ if (!query->stmt)
484
+ prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
485
+
486
+ query_ctx ctx = QUERY_CTX(
487
+ self,
488
+ query->db_struct,
489
+ query->stmt,
490
+ parameters,
491
+ QUERY_MODE(QUERY_MULTI_ROW),
492
+ ALL_ROWS
493
+ );
494
+ return safe_batch_query(&ctx);
495
+ }
496
+
497
+ /* call-seq:
498
+ * query.batch_query_ary(sql, params_array) -> rows
499
+ * query.batch_query_ary(sql, enumerable) -> rows
500
+ * query.batch_query_ary(sql, callable) -> rows
501
+ * query.batch_query_ary(sql, params_array) { |rows| ... } -> changes
502
+ * query.batch_query_ary(sql, enumerable) { |rows| ... } -> changes
503
+ * query.batch_query_ary(sql, callable) { |rows| ... } -> changes
504
+ *
505
+ * Executes the prepared query for each list of parameters in the given paramter
506
+ * source. If a block is given, it is called with the resulting rows for each
507
+ * invocation of the query, and the total number of changes is returned.
508
+ * Otherwise, an array containing the resulting rows for each invocation is
509
+ * returned. Rows are represented as arrays.
510
+ *
511
+ * q = db.prepare('insert into foo values (?, ?) returning bar, baz')
512
+ * records = [
513
+ * [1, 2],
514
+ * [3, 4]
515
+ * ]
516
+ * q.batch_query_ary(records)
517
+ * #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
518
+ * *
519
+ * @param sql [String] query SQL
520
+ * @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
521
+ * @return [Array<Hash>, Integer] Total number of changes effected
522
+ */
523
+ VALUE Query_batch_query_ary(VALUE self, VALUE parameters) {
524
+ Query_t *query = self_to_query(self);
525
+ if (query->closed) rb_raise(cError, "Query is closed");
526
+
527
+ if (!query->stmt)
528
+ prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
529
+
530
+ query_ctx ctx = QUERY_CTX(
531
+ self,
532
+ query->db_struct,
533
+ query->stmt,
534
+ parameters,
535
+ QUERY_MODE(QUERY_MULTI_ROW),
536
+ ALL_ROWS
537
+ );
538
+ return safe_batch_query_ary(&ctx);
539
+ }
540
+
541
+ /* call-seq:
542
+ * query.batch_query_single_column(sql, params_array) -> rows
543
+ * query.batch_query_single_column(sql, enumerable) -> rows
544
+ * query.batch_query_single_column(sql, callable) -> rows
545
+ * query.batch_query_single_column(sql, params_array) { |rows| ... } -> changes
546
+ * query.batch_query_single_column(sql, enumerable) { |rows| ... } -> changes
547
+ * query.batch_query_single_column(sql, callable) { |rows| ... } -> changes
548
+ *
549
+ * Executes the prepared query for each list of parameters in the given paramter
550
+ * source. If a block is given, it is called with the resulting rows for each
551
+ * invocation of the query, and the total number of changes is returned.
552
+ * Otherwise, an array containing the resulting rows for each invocation is
553
+ * returned. Rows are represented as single values.
554
+ *
555
+ * q = db.prepare('insert into foo values (?, ?) returning bar, baz')
556
+ * records = [
557
+ * [1, 2],
558
+ * [3, 4]
559
+ * ]
560
+ * q.batch_query_single_column(records)
561
+ * #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
562
+ * *
563
+ * @param sql [String] query SQL
564
+ * @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
565
+ * @return [Array<Hash>, Integer] Total number of changes effected
566
+ */
567
+ VALUE Query_batch_query_single_column(VALUE self, VALUE parameters) {
568
+ Query_t *query = self_to_query(self);
569
+ if (query->closed) rb_raise(cError, "Query is closed");
570
+
571
+ if (!query->stmt)
572
+ prepare_single_stmt(query->sqlite3_db, &query->stmt, query->sql);
573
+
574
+ query_ctx ctx = QUERY_CTX(
575
+ self,
576
+ query->db_struct,
577
+ query->stmt,
578
+ parameters,
579
+ QUERY_MODE(QUERY_MULTI_ROW),
580
+ ALL_ROWS
581
+ );
582
+ return safe_batch_query_single_column(&ctx);
393
583
  }
394
584
 
395
585
  /* Returns the database associated with the query.
@@ -405,7 +595,7 @@ VALUE Query_database(VALUE self) {
405
595
  }
406
596
 
407
597
  /* Returns the SQL string for the query.
408
- *
598
+ *
409
599
  * @return [String] SQL string
410
600
  */
411
601
  VALUE Query_sql(VALUE self) {
@@ -414,7 +604,7 @@ VALUE Query_sql(VALUE self) {
414
604
  }
415
605
 
416
606
  /* Returns the column names for the query without running it.
417
- *
607
+ *
418
608
  * @return [Array<Symbol>] column names
419
609
  */
420
610
  VALUE Query_columns(VALUE self) {
@@ -423,8 +613,21 @@ VALUE Query_columns(VALUE self) {
423
613
  return Query_perform_next(self, ALL_ROWS, safe_query_columns);
424
614
  }
425
615
 
616
+ /* call-seq:
617
+ * query.clone -> copy
618
+ * query.dup -> copy
619
+ *
620
+ * Returns a new query instance for the same SQL as the original query.
621
+ *
622
+ * @return [Extralite::Query] copy of query
623
+ */
624
+ VALUE Query_clone(VALUE self) {
625
+ Query_t *query = self_to_query(self);
626
+ return rb_funcall(cQuery, ID_new, 2, query->db, query->sql);
627
+ }
628
+
426
629
  /* Closes the query. Attempting to run a closed query will raise an error.
427
- *
630
+ *
428
631
  * @return [Extralite::Query] self
429
632
  */
430
633
  VALUE Query_close(VALUE self) {
@@ -438,7 +641,7 @@ VALUE Query_close(VALUE self) {
438
641
  }
439
642
 
440
643
  /* Returns true if the query is closed.
441
- *
644
+ *
442
645
  * @return [boolean] true if query is closed
443
646
  */
444
647
  VALUE Query_closed_p(VALUE self) {
@@ -449,7 +652,7 @@ VALUE Query_closed_p(VALUE self) {
449
652
  /* Returns the current [status
450
653
  * value](https://sqlite.org/c3ref/c_stmtstatus_counter.html) for the given op.
451
654
  * To reset the value, pass true as reset.
452
- *
655
+ *
453
656
  * @overload status(op)
454
657
  * @param op [Integer] status op
455
658
  * @return [Integer] current status value for the given op
@@ -486,7 +689,7 @@ VALUE Query_inspect(VALUE self) {
486
689
  rb_str_cat2(sql, "...");
487
690
  }
488
691
  sql = rb_funcall(sql, ID_inspect, 0);
489
-
692
+
490
693
  RB_GC_GUARD(sql);
491
694
  return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sql);
492
695
  }
@@ -501,8 +704,10 @@ void Init_ExtraliteQuery(void) {
501
704
  rb_define_method(cQuery, "close", Query_close, 0);
502
705
  rb_define_method(cQuery, "closed?", Query_closed_p, 0);
503
706
  rb_define_method(cQuery, "columns", Query_columns, 0);
707
+ rb_define_method(cQuery, "clone", Query_clone, 0);
504
708
  rb_define_method(cQuery, "database", Query_database, 0);
505
709
  rb_define_method(cQuery, "db", Query_database, 0);
710
+ rb_define_method(cQuery, "dup", Query_clone, 0);
506
711
 
507
712
  rb_define_method(cQuery, "each", Query_each_hash, 0);
508
713
  rb_define_method(cQuery, "each_ary", Query_each_ary, 0);
@@ -511,7 +716,11 @@ void Init_ExtraliteQuery(void) {
511
716
 
512
717
  rb_define_method(cQuery, "eof?", Query_eof_p, 0);
513
718
  rb_define_method(cQuery, "execute", Query_execute, -1);
514
- rb_define_method(cQuery, "execute_multi", Query_execute_multi, 1);
719
+ rb_define_method(cQuery, "<<", Query_execute_chevrons, 1);
720
+ rb_define_method(cQuery, "batch_execute", Query_batch_execute, 1);
721
+ rb_define_method(cQuery, "batch_query", Query_batch_query, 1);
722
+ rb_define_method(cQuery, "batch_query_ary", Query_batch_query_ary, 1);
723
+ rb_define_method(cQuery, "batch_query_single_column", Query_batch_query_single_column, 1);
515
724
  rb_define_method(cQuery, "initialize", Query_initialize, 2);
516
725
  rb_define_method(cQuery, "inspect", Query_inspect, 0);
517
726