extralite 2.15 → 3.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/test-bundle.yml +1 -1
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +106 -42
- data/TODO.md +2 -16
- data/examples/transform.rb +61 -0
- data/ext/extralite/changeset.c +11 -11
- data/ext/extralite/common.c +234 -22
- data/ext/extralite/database.c +157 -100
- data/ext/extralite/extralite.h +52 -6
- data/ext/extralite/extralite_ext.c +2 -0
- data/ext/extralite/query.c +67 -41
- data/ext/extralite/transform.c +420 -0
- data/gemspec.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +102 -1
- data/test/perf_array.rb +1 -1
- data/test/perf_hash.rb +1 -1
- data/test/perf_hash_prepared.rb +2 -2
- data/test/perf_splat.rb +1 -1
- data/test/perf_transform.rb +58 -0
- data/test/test_database.rb +37 -10
- data/test/test_query.rb +11 -15
- data/test/test_transform.rb +817 -0
- metadata +6 -2
data/ext/extralite/common.c
CHANGED
|
@@ -151,7 +151,7 @@ static inline void column_names_setup(struct column_names *names, int count) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
static inline void column_names_set(struct column_names *names, int idx, VALUE value) {
|
|
154
|
-
if (names->count <= MAX_EMBEDDED_COLUMN_NAMES)
|
|
154
|
+
if (names->count <= MAX_EMBEDDED_COLUMN_NAMES)
|
|
155
155
|
names->names[idx] = value;
|
|
156
156
|
else
|
|
157
157
|
rb_ary_push(names->array, value);
|
|
@@ -331,7 +331,7 @@ void *stmt_iterate_step(void *ptr) {
|
|
|
331
331
|
inline enum gvl_mode stepwise_gvl_mode(query_ctx *ctx) {
|
|
332
332
|
// a negative or zero threshold means the GVL is always held during iteration.
|
|
333
333
|
if (ctx->gvl_release_threshold <= 0) return GVL_HOLD;
|
|
334
|
-
|
|
334
|
+
|
|
335
335
|
if (!sqlite3_stmt_busy(ctx->stmt)) return GVL_RELEASE;
|
|
336
336
|
|
|
337
337
|
// if positive, the GVL is normally held, and release every <threshold> steps.
|
|
@@ -366,6 +366,218 @@ VALUE cleanup_stmt(query_ctx *ctx) {
|
|
|
366
366
|
return Qnil;
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
+
static inline void add_transform_container_obj(VALUE row, struct transform_node *col, VALUE obj) {
|
|
370
|
+
if (col->flags & TRANSFORM_F_ARRAY) {
|
|
371
|
+
VALUE array = rb_hash_aref(row, col->name);
|
|
372
|
+
if (NIL_P(array)) {
|
|
373
|
+
array = rb_ary_new();
|
|
374
|
+
rb_hash_aset(row, col->name, array);
|
|
375
|
+
RB_GC_GUARD(array);
|
|
376
|
+
}
|
|
377
|
+
rb_ary_push(array, obj);
|
|
378
|
+
}
|
|
379
|
+
else
|
|
380
|
+
rb_hash_aset(row, col->name, obj);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
static VALUE run_transform(VALUE identity_storage, struct transform_node *node, sqlite3_stmt *stmt);
|
|
384
|
+
|
|
385
|
+
static inline VALUE json_parse(VALUE json) {
|
|
386
|
+
if (NIL_P(mJSON)) {
|
|
387
|
+
rb_require("json");
|
|
388
|
+
mJSON = rb_const_get(rb_cObject, rb_intern_const("JSON"));
|
|
389
|
+
}
|
|
390
|
+
return rb_funcall(mJSON, ID_parse, 1, json);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
static inline VALUE get_transform_column_value(struct transform_node *col, sqlite3_stmt *stmt) {
|
|
394
|
+
int native_type = sqlite3_column_type(stmt, col->idx);
|
|
395
|
+
switch (col->type) {
|
|
396
|
+
case TRANSFORM_T_AUTO:
|
|
397
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
398
|
+
return get_column_value(stmt, col->idx, native_type);
|
|
399
|
+
case TRANSFORM_T_INTEGER:
|
|
400
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
401
|
+
return get_column_value(stmt, col->idx, SQLITE_INTEGER);
|
|
402
|
+
case TRANSFORM_T_FLOAT:
|
|
403
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
404
|
+
return get_column_value(stmt, col->idx, SQLITE_FLOAT);
|
|
405
|
+
case TRANSFORM_T_TEXT:
|
|
406
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
407
|
+
return get_column_value(stmt, col->idx, SQLITE_TEXT);
|
|
408
|
+
case TRANSFORM_T_BOOL:
|
|
409
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
410
|
+
int64_t v = sqlite3_column_int64(stmt, col->idx);
|
|
411
|
+
return v ? Qtrue : Qfalse;
|
|
412
|
+
case TRANSFORM_T_JSON:
|
|
413
|
+
if (native_type == SQLITE_NULL) return Qnil;
|
|
414
|
+
VALUE json = get_column_value(stmt, col->idx, SQLITE_TEXT);
|
|
415
|
+
return json_parse(json);
|
|
416
|
+
RB_GC_GUARD(json);
|
|
417
|
+
case TRANSFORM_T_PROC:
|
|
418
|
+
VALUE val = get_column_value(stmt, col->idx, native_type);
|
|
419
|
+
return rb_funcall(col->conversion_proc, ID_call, 1, val);
|
|
420
|
+
RB_GC_GUARD(val);
|
|
421
|
+
default:
|
|
422
|
+
rb_raise(cError, "Invalid column value");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
VALUE run_transform_with_identity(
|
|
427
|
+
VALUE identity_storage, struct transform_node *node, sqlite3_stmt *stmt
|
|
428
|
+
) {
|
|
429
|
+
VALUE row = Qnil;
|
|
430
|
+
VALUE identity_map = Qnil;
|
|
431
|
+
|
|
432
|
+
VALUE identity_value = get_transform_column_value(node->identity_node, stmt);
|
|
433
|
+
// get_column_value(
|
|
434
|
+
// stmt, node->identity_idx, sqlite3_column_type(stmt, node->identity_idx)
|
|
435
|
+
// );
|
|
436
|
+
VALUE identity_map_key = ULONG2NUM((uint64_t)node);
|
|
437
|
+
identity_map = rb_hash_aref(identity_storage, identity_map_key);
|
|
438
|
+
|
|
439
|
+
if (NIL_P(identity_map)) {
|
|
440
|
+
identity_map = rb_hash_new();
|
|
441
|
+
rb_hash_aset(identity_storage, identity_map_key, identity_map);
|
|
442
|
+
}
|
|
443
|
+
row = rb_hash_aref(identity_map, identity_value);
|
|
444
|
+
if (!NIL_P(row)) {
|
|
445
|
+
struct transform_node *col = node->subnodes_head;
|
|
446
|
+
while (col) {
|
|
447
|
+
if (col->type == TRANSFORM_T_RELATION) {
|
|
448
|
+
VALUE obj = run_transform(identity_storage, col, stmt);
|
|
449
|
+
if (!NIL_P(obj)) add_transform_container_obj(row, col, obj);
|
|
450
|
+
}
|
|
451
|
+
col = col->next;
|
|
452
|
+
}
|
|
453
|
+
return (node->flags & TRANSFORM_F_NAME) ? row : Qnil;
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
// not found in identity map
|
|
457
|
+
row = rb_hash_new();
|
|
458
|
+
struct transform_node *col = node->subnodes_head;
|
|
459
|
+
while (col) {
|
|
460
|
+
if (col == node->identity_node) {
|
|
461
|
+
rb_hash_aset(row, col->name, identity_value);
|
|
462
|
+
rb_hash_aset(identity_map, identity_value, row);
|
|
463
|
+
}
|
|
464
|
+
else if (col->type == TRANSFORM_T_RELATION) {
|
|
465
|
+
VALUE obj = run_transform(identity_storage, col, stmt);
|
|
466
|
+
if (!NIL_P(obj)) add_transform_container_obj(row, col, obj);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
VALUE value = get_transform_column_value(col, stmt);
|
|
470
|
+
rb_hash_aset(row, col->name, value);
|
|
471
|
+
RB_GC_GUARD(value);
|
|
472
|
+
}
|
|
473
|
+
col = col->next;
|
|
474
|
+
}
|
|
475
|
+
return row;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
RB_GC_GUARD(identity_map);
|
|
479
|
+
RB_GC_GUARD(row);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
VALUE run_transform_no_identity(
|
|
483
|
+
VALUE identity_storage, struct transform_node *node, sqlite3_stmt *stmt
|
|
484
|
+
) {
|
|
485
|
+
VALUE row = rb_hash_new();
|
|
486
|
+
struct transform_node *col = node->subnodes_head;
|
|
487
|
+
while (col) {
|
|
488
|
+
if (col->type == TRANSFORM_T_RELATION) {
|
|
489
|
+
VALUE obj = run_transform(identity_storage, col, stmt);
|
|
490
|
+
if (!NIL_P(obj)) add_transform_container_obj(row, col, obj);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
VALUE value = get_transform_column_value(col, stmt);
|
|
494
|
+
rb_hash_aset(row, col->name, value);
|
|
495
|
+
RB_GC_GUARD(value);
|
|
496
|
+
}
|
|
497
|
+
col = col->next;
|
|
498
|
+
}
|
|
499
|
+
return row;
|
|
500
|
+
RB_GC_GUARD(row);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
static inline VALUE run_transform(
|
|
504
|
+
VALUE identity_storage, struct transform_node *node, sqlite3_stmt *stmt
|
|
505
|
+
) {
|
|
506
|
+
// fprintf(stdout, "transform_container: %p flags: %02x identity_idx: %d\n", node, node->flags, node->identity_idx);
|
|
507
|
+
// if (node->flags & TRANSFORM_F_NAME) INSPECT(" name", node->name);
|
|
508
|
+
if (node->identity_node) {
|
|
509
|
+
return run_transform_with_identity(identity_storage, node, stmt);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
return run_transform_no_identity(identity_storage, node, stmt);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
VALUE safe_query_transform(query_ctx *ctx) {
|
|
517
|
+
VALUE array = rb_ary_new();
|
|
518
|
+
VALUE identity_storage = rb_hash_new();
|
|
519
|
+
VALUE row = Qnil;
|
|
520
|
+
// int column_count = sqlite3_column_count(ctx->stmt);
|
|
521
|
+
struct transform_node *transform_root = get_transform_root(ctx->transform);
|
|
522
|
+
|
|
523
|
+
int row_count = 0;
|
|
524
|
+
while (stmt_iterate(ctx)) {
|
|
525
|
+
row_count++;
|
|
526
|
+
row = run_transform(identity_storage, transform_root, ctx->stmt);
|
|
527
|
+
if (!NIL_P(row)) {
|
|
528
|
+
rb_ary_push(array, row);
|
|
529
|
+
if (ctx->max_rows != ALL_ROWS && row_count >= ctx->max_rows)
|
|
530
|
+
goto done;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
done:
|
|
535
|
+
switch (ctx->row_mode) {
|
|
536
|
+
case ROW_YIELD:
|
|
537
|
+
rb_ary_each(array);
|
|
538
|
+
return ctx->self;
|
|
539
|
+
case ROW_MULTI:
|
|
540
|
+
return array;
|
|
541
|
+
case ROW_SINGLE:
|
|
542
|
+
return rb_ary_entry(array, 0);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return Qnil;
|
|
546
|
+
RB_GC_GUARD(identity_storage);
|
|
547
|
+
RB_GC_GUARD(row);
|
|
548
|
+
RB_GC_GUARD(array);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
VALUE safe_query_single_row_transform(query_ctx *ctx) {
|
|
552
|
+
VALUE array = rb_ary_new();
|
|
553
|
+
VALUE identity_storage = rb_hash_new();
|
|
554
|
+
VALUE row = Qnil;
|
|
555
|
+
// int column_count = sqlite3_column_count(ctx->stmt);
|
|
556
|
+
struct transform_node *transform_root = get_transform_root(ctx->transform);
|
|
557
|
+
|
|
558
|
+
int row_count = 0;
|
|
559
|
+
while (stmt_iterate(ctx)) {
|
|
560
|
+
row_count++;
|
|
561
|
+
row = run_transform(identity_storage, transform_root, ctx->stmt);
|
|
562
|
+
if (!NIL_P(row)) { rb_ary_push(array, row); }
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
row = rb_ary_entry(array, 0);
|
|
566
|
+
switch (ctx->row_mode) {
|
|
567
|
+
case ROW_YIELD:
|
|
568
|
+
rb_yield(row);
|
|
569
|
+
return ctx->self;
|
|
570
|
+
case ROW_MULTI:
|
|
571
|
+
case ROW_SINGLE:
|
|
572
|
+
return row;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return Qnil;
|
|
576
|
+
RB_GC_GUARD(identity_storage);
|
|
577
|
+
RB_GC_GUARD(row);
|
|
578
|
+
RB_GC_GUARD(array);
|
|
579
|
+
}
|
|
580
|
+
|
|
369
581
|
VALUE safe_query_splat(query_ctx *ctx);
|
|
370
582
|
|
|
371
583
|
VALUE safe_query_hash(query_ctx *ctx) {
|
|
@@ -374,12 +586,12 @@ VALUE safe_query_hash(query_ctx *ctx) {
|
|
|
374
586
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
375
587
|
struct column_names names = get_column_names(ctx->stmt, column_count);
|
|
376
588
|
int row_count = 0;
|
|
377
|
-
int do_transform = !NIL_P(ctx->
|
|
589
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
378
590
|
|
|
379
591
|
while (stmt_iterate(ctx)) {
|
|
380
592
|
row = row_to_hash(ctx->stmt, column_count, &names);
|
|
381
593
|
if (do_transform)
|
|
382
|
-
row = INVOKE_PROC(ctx->
|
|
594
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
383
595
|
row_count++;
|
|
384
596
|
switch (ctx->row_mode) {
|
|
385
597
|
case ROW_YIELD:
|
|
@@ -416,7 +628,7 @@ VALUE safe_query_hash(query_ctx *ctx) {
|
|
|
416
628
|
#define ARGV_GET_ROW(ctx, column_count, argv_values, row, do_transform, return_rows) \
|
|
417
629
|
row_to_splat_values(ctx->stmt, column_count, argv_values); \
|
|
418
630
|
if (do_transform) \
|
|
419
|
-
row = INVOKE_PROC(ctx->
|
|
631
|
+
row = INVOKE_PROC(ctx->transform, column_count, argv_values); \
|
|
420
632
|
else if (return_rows) \
|
|
421
633
|
row = column_count == 1 ? argv_values[0] : rb_ary_new_from_values(column_count, argv_values);
|
|
422
634
|
|
|
@@ -428,7 +640,7 @@ VALUE safe_query_splat(query_ctx *ctx) {
|
|
|
428
640
|
if (column_count > MAX_ARGV_COLUMNS)
|
|
429
641
|
rb_raise(cError, "Conversion is supported only up to %d columns", MAX_ARGV_COLUMNS);
|
|
430
642
|
|
|
431
|
-
int do_transform = !NIL_P(ctx->
|
|
643
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
432
644
|
int return_rows = (ctx->row_mode != ROW_YIELD);
|
|
433
645
|
|
|
434
646
|
int row_count = 0;
|
|
@@ -463,12 +675,12 @@ VALUE safe_query_array(query_ctx *ctx) {
|
|
|
463
675
|
VALUE row = Qnil;
|
|
464
676
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
465
677
|
int row_count = 0;
|
|
466
|
-
int do_transform = !NIL_P(ctx->
|
|
678
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
467
679
|
|
|
468
680
|
while (stmt_iterate(ctx)) {
|
|
469
681
|
row = row_to_array(ctx->stmt, column_count);
|
|
470
682
|
if (do_transform)
|
|
471
|
-
row = INVOKE_PROC(ctx->
|
|
683
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
472
684
|
row_count++;
|
|
473
685
|
switch (ctx->row_mode) {
|
|
474
686
|
case ROW_YIELD:
|
|
@@ -496,8 +708,8 @@ VALUE safe_query_single_row_hash(query_ctx *ctx) {
|
|
|
496
708
|
|
|
497
709
|
if (stmt_iterate(ctx)) {
|
|
498
710
|
row = row_to_hash(ctx->stmt, column_count, &names);
|
|
499
|
-
if (!NIL_P(ctx->
|
|
500
|
-
row = INVOKE_PROC(ctx->
|
|
711
|
+
if (!NIL_P(ctx->transform))
|
|
712
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
501
713
|
}
|
|
502
714
|
|
|
503
715
|
RB_GC_GUARD(row);
|
|
@@ -511,7 +723,7 @@ VALUE safe_query_single_row_splat(query_ctx *ctx) {
|
|
|
511
723
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
512
724
|
if (column_count > MAX_ARGV_COLUMNS)
|
|
513
725
|
rb_raise(cError, "Conversion is supported only up to %d columns", MAX_ARGV_COLUMNS);
|
|
514
|
-
int do_transform = !NIL_P(ctx->
|
|
726
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
515
727
|
|
|
516
728
|
if (stmt_iterate(ctx)) {
|
|
517
729
|
ARGV_GET_ROW(ctx, column_count, argv_values, row, do_transform, 1);
|
|
@@ -525,12 +737,12 @@ VALUE safe_query_single_row_splat(query_ctx *ctx) {
|
|
|
525
737
|
VALUE safe_query_single_row_array(query_ctx *ctx) {
|
|
526
738
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
527
739
|
VALUE row = Qnil;
|
|
528
|
-
int do_transform = !NIL_P(ctx->
|
|
740
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
529
741
|
|
|
530
742
|
if (stmt_iterate(ctx)) {
|
|
531
743
|
row = row_to_array(ctx->stmt, column_count);
|
|
532
744
|
if (do_transform)
|
|
533
|
-
row = INVOKE_PROC(ctx->
|
|
745
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
534
746
|
}
|
|
535
747
|
|
|
536
748
|
RB_GC_GUARD(row);
|
|
@@ -549,12 +761,12 @@ static inline VALUE batch_iterate_hash(query_ctx *ctx) {
|
|
|
549
761
|
VALUE row = Qnil;
|
|
550
762
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
551
763
|
struct column_names names = get_column_names(ctx->stmt, column_count);
|
|
552
|
-
const int do_transform = !NIL_P(ctx->
|
|
764
|
+
const int do_transform = !NIL_P(ctx->transform);
|
|
553
765
|
|
|
554
766
|
while (stmt_iterate(ctx)) {
|
|
555
767
|
row = row_to_hash(ctx->stmt, column_count, &names);
|
|
556
768
|
if (do_transform)
|
|
557
|
-
row = INVOKE_PROC(ctx->
|
|
769
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
558
770
|
rb_ary_push(rows, row);
|
|
559
771
|
}
|
|
560
772
|
|
|
@@ -568,12 +780,12 @@ static inline VALUE batch_iterate_array(query_ctx *ctx) {
|
|
|
568
780
|
VALUE rows = rb_ary_new();
|
|
569
781
|
VALUE row = Qnil;
|
|
570
782
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
571
|
-
int do_transform = !NIL_P(ctx->
|
|
783
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
572
784
|
|
|
573
785
|
while (stmt_iterate(ctx)) {
|
|
574
786
|
row = row_to_array(ctx->stmt, column_count);
|
|
575
787
|
if (do_transform)
|
|
576
|
-
row = INVOKE_PROC(ctx->
|
|
788
|
+
row = INVOKE_PROC(ctx->transform, 1, &row);
|
|
577
789
|
rb_ary_push(rows, row);
|
|
578
790
|
}
|
|
579
791
|
|
|
@@ -589,7 +801,7 @@ static inline VALUE batch_iterate_splat(query_ctx *ctx) {
|
|
|
589
801
|
int column_count = sqlite3_column_count(ctx->stmt);
|
|
590
802
|
if (column_count > MAX_ARGV_COLUMNS)
|
|
591
803
|
rb_raise(cError, "Conversion is supported only up to %d columns", MAX_ARGV_COLUMNS);
|
|
592
|
-
int do_transform = !NIL_P(ctx->
|
|
804
|
+
int do_transform = !NIL_P(ctx->transform);
|
|
593
805
|
|
|
594
806
|
while (stmt_iterate(ctx)) {
|
|
595
807
|
ARGV_GET_ROW(ctx, column_count, argv_values, row, do_transform, 1);
|
|
@@ -753,13 +965,13 @@ static inline VALUE batch_run_proc(query_ctx *ctx, enum batch_mode batch_mode) {
|
|
|
753
965
|
static inline VALUE batch_run(query_ctx *ctx, enum batch_mode batch_mode) {
|
|
754
966
|
if (TYPE(ctx->params) == T_ARRAY)
|
|
755
967
|
return batch_run_array(ctx, batch_mode);
|
|
756
|
-
|
|
968
|
+
|
|
757
969
|
if (rb_respond_to(ctx->params, ID_each))
|
|
758
970
|
return batch_run_each(ctx, batch_mode);
|
|
759
|
-
|
|
971
|
+
|
|
760
972
|
if (rb_respond_to(ctx->params, ID_call))
|
|
761
973
|
return batch_run_proc(ctx, batch_mode);
|
|
762
|
-
|
|
974
|
+
|
|
763
975
|
rb_raise(cParameterError, "Invalid parameter source supplied to #batch_execute");
|
|
764
976
|
}
|
|
765
977
|
|
|
@@ -777,7 +989,7 @@ VALUE safe_batch_query(query_ctx *ctx) {
|
|
|
777
989
|
return batch_run(ctx, BATCH_QUERY_ARRAY);
|
|
778
990
|
default:
|
|
779
991
|
rb_raise(cError, "Invalid query mode (safe_batch_query)");
|
|
780
|
-
}
|
|
992
|
+
}
|
|
781
993
|
}
|
|
782
994
|
|
|
783
995
|
VALUE safe_batch_query_array(query_ctx *ctx) {
|