extralite 2.4 → 2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,7 +31,7 @@ static inline VALUE get_column_value(sqlite3_stmt *stmt, int col, int type) {
31
31
  return Qnil;
32
32
  }
33
33
 
34
- void bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value);
34
+ int bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value);
35
35
 
36
36
  static inline void bind_key_value(sqlite3_stmt *stmt, VALUE k, VALUE v) {
37
37
  switch (TYPE(k)) {
@@ -72,24 +72,24 @@ void bind_struct_parameter_values(sqlite3_stmt *stmt, VALUE struct_obj) {
72
72
  RB_GC_GUARD(members);
73
73
  }
74
74
 
75
- inline void bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value) {
75
+ inline int bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value) {
76
76
  switch (TYPE(value)) {
77
77
  case T_NIL:
78
78
  sqlite3_bind_null(stmt, pos);
79
- return;
79
+ return 1;
80
80
  case T_FIXNUM:
81
81
  case T_BIGNUM:
82
82
  sqlite3_bind_int64(stmt, pos, NUM2LL(value));
83
- return;
83
+ return 1;
84
84
  case T_FLOAT:
85
85
  sqlite3_bind_double(stmt, pos, NUM2DBL(value));
86
- return;
86
+ return 1;
87
87
  case T_TRUE:
88
88
  sqlite3_bind_int(stmt, pos, 1);
89
- return;
89
+ return 1;
90
90
  case T_FALSE:
91
91
  sqlite3_bind_int(stmt, pos, 0);
92
- return;
92
+ return 1;
93
93
  case T_SYMBOL:
94
94
  value = rb_sym2str(value);
95
95
  case T_STRING:
@@ -97,13 +97,20 @@ inline void bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value) {
97
97
  sqlite3_bind_blob(stmt, pos, RSTRING_PTR(value), RSTRING_LEN(value), SQLITE_TRANSIENT);
98
98
  else
99
99
  sqlite3_bind_text(stmt, pos, RSTRING_PTR(value), RSTRING_LEN(value), SQLITE_TRANSIENT);
100
- return;
100
+ return 1;
101
+ case T_ARRAY:
102
+ {
103
+ int count = RARRAY_LEN(value);
104
+ for (int i = 0; i < count; i++)
105
+ bind_parameter_value(stmt, pos + i, RARRAY_AREF(value, i));
106
+ return count;
107
+ }
101
108
  case T_HASH:
102
109
  bind_hash_parameter_values(stmt, value);
103
- return;
110
+ return 0;
104
111
  case T_STRUCT:
105
112
  bind_struct_parameter_values(stmt, value);
106
- return;
113
+ return 0;
107
114
  default:
108
115
  rb_raise(cParameterError, "Cannot bind parameter at position %d of type %"PRIsVALUE"",
109
116
  pos, rb_class_name(rb_obj_class(value)));
@@ -111,14 +118,18 @@ inline void bind_parameter_value(sqlite3_stmt *stmt, int pos, VALUE value) {
111
118
  }
112
119
 
113
120
  inline void bind_all_parameters(sqlite3_stmt *stmt, int argc, VALUE *argv) {
114
- for (int i = 0; i < argc; i++) bind_parameter_value(stmt, i + 1, argv[i]);
121
+ int pos = 1;
122
+ for (int i = 0; i < argc; i++) {
123
+ pos += bind_parameter_value(stmt, pos, argv[i]);
124
+ }
115
125
  }
116
126
 
117
127
  inline void bind_all_parameters_from_object(sqlite3_stmt *stmt, VALUE obj) {
118
128
  if (TYPE(obj) == T_ARRAY) {
129
+ int pos = 1;
119
130
  int count = RARRAY_LEN(obj);
120
131
  for (int i = 0; i < count; i++)
121
- bind_parameter_value(stmt, i + 1, RARRAY_AREF(obj, i));
132
+ pos += bind_parameter_value(stmt, pos, RARRAY_AREF(obj, i));
122
133
  }
123
134
  else
124
135
  bind_parameter_value(stmt, 1, obj);
@@ -194,9 +205,9 @@ statements. It will release the GVL while the statements are being prepared and
194
205
  executed. All statements excluding the last one are executed. The last statement
195
206
  is not executed, but instead handed back to the caller for looping over results.
196
207
  */
197
- void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql) {
208
+ void prepare_multi_stmt(enum gvl_mode mode, sqlite3 *db, sqlite3_stmt **stmt, VALUE sql) {
198
209
  prepare_stmt_ctx ctx = {db, stmt, RSTRING_PTR(sql), RSTRING_LEN(sql), 0};
199
- gvl_call(GVL_RELEASE, prepare_multi_stmt_impl, (void *)&ctx);
210
+ gvl_call(mode, prepare_multi_stmt_impl, (void *)&ctx);
200
211
  RB_GC_GUARD(sql);
201
212
 
202
213
  switch (ctx.rc) {
@@ -236,9 +247,9 @@ end:
236
247
  return NULL;
237
248
  }
238
249
 
239
- void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql) {
250
+ void prepare_single_stmt(enum gvl_mode mode, sqlite3 *db, sqlite3_stmt **stmt, VALUE sql) {
240
251
  prepare_stmt_ctx ctx = {db, stmt, RSTRING_PTR(sql), RSTRING_LEN(sql), 0};
241
- gvl_call(GVL_RELEASE, prepare_single_stmt_impl, (void *)&ctx);
252
+ gvl_call(mode, prepare_single_stmt_impl, (void *)&ctx);
242
253
  RB_GC_GUARD(sql);
243
254
 
244
255
  switch (ctx.rc) {
@@ -423,8 +434,80 @@ VALUE safe_query_single_value(query_ctx *ctx) {
423
434
  return value;
424
435
  }
425
436
 
426
- VALUE safe_execute_multi(query_ctx *ctx) {
437
+ enum batch_mode {
438
+ BATCH_EXECUTE,
439
+ BATCH_QUERY_ARY,
440
+ BATCH_QUERY_HASH,
441
+ BATCH_QUERY_SINGLE_COLUMN
442
+ };
443
+
444
+ static inline VALUE batch_iterate_hash(query_ctx *ctx) {
445
+ VALUE rows = rb_ary_new();
446
+ VALUE row = Qnil;
447
+ int column_count = sqlite3_column_count(ctx->stmt);
448
+ VALUE column_names = get_column_names(ctx->stmt, column_count);
449
+
450
+ while (stmt_iterate(ctx)) {
451
+ row = row_to_hash(ctx->stmt, column_count, column_names);
452
+ rb_ary_push(rows, row);
453
+ }
454
+
455
+ RB_GC_GUARD(column_names);
456
+ RB_GC_GUARD(rows);
457
+ return rows;
458
+ }
459
+
460
+ static inline VALUE batch_iterate_ary(query_ctx *ctx) {
461
+ VALUE rows = rb_ary_new();
462
+ VALUE row = Qnil;
463
+ int column_count = sqlite3_column_count(ctx->stmt);
464
+
465
+ while (stmt_iterate(ctx)) {
466
+ row = row_to_ary(ctx->stmt, column_count);
467
+ rb_ary_push(rows, row);
468
+ }
469
+
470
+ RB_GC_GUARD(rows);
471
+ return rows;
472
+ }
473
+
474
+ static inline VALUE batch_iterate_single_column(query_ctx *ctx) {
475
+ VALUE rows = rb_ary_new();
476
+ VALUE value = Qnil;
477
+ int column_count = sqlite3_column_count(ctx->stmt);
478
+ if (column_count != 1) rb_raise(cError, "Expected query result to have 1 column");
479
+
480
+ while (stmt_iterate(ctx)) {
481
+ value = get_column_value(ctx->stmt, 0, sqlite3_column_type(ctx->stmt, 0));
482
+ rb_ary_push(rows, value);
483
+ }
484
+
485
+ RB_GC_GUARD(rows);
486
+ return rows;
487
+ }
488
+
489
+ static inline void batch_iterate(query_ctx *ctx, enum batch_mode mode, VALUE *rows) {
490
+ switch (mode) {
491
+ case BATCH_EXECUTE:
492
+ while (stmt_iterate(ctx));
493
+ break;
494
+ case BATCH_QUERY_ARY:
495
+ *rows = batch_iterate_ary(ctx);
496
+ break;
497
+ case BATCH_QUERY_HASH:
498
+ *rows = batch_iterate_hash(ctx);
499
+ break;
500
+ case BATCH_QUERY_SINGLE_COLUMN:
501
+ *rows = batch_iterate_single_column(ctx);
502
+ break;
503
+ }
504
+ }
505
+
506
+ static inline VALUE batch_run_array(query_ctx *ctx, enum batch_mode mode) {
427
507
  int count = RARRAY_LEN(ctx->params);
508
+ int block_given = rb_block_given_p();
509
+ VALUE results = (mode != BATCH_EXECUTE) && !block_given ? rb_ary_new() : Qnil;
510
+ VALUE rows = Qnil;
428
511
  int changes = 0;
429
512
 
430
513
  for (int i = 0; i < count; i++) {
@@ -432,11 +515,135 @@ VALUE safe_execute_multi(query_ctx *ctx) {
432
515
  sqlite3_clear_bindings(ctx->stmt);
433
516
  bind_all_parameters_from_object(ctx->stmt, RARRAY_AREF(ctx->params, i));
434
517
 
435
- while (stmt_iterate(ctx));
518
+ batch_iterate(ctx, mode, &rows);
436
519
  changes += sqlite3_changes(ctx->sqlite3_db);
520
+
521
+ if (mode != BATCH_EXECUTE) {
522
+ if (block_given)
523
+ rb_yield(rows);
524
+ else
525
+ rb_ary_push(results, rows);
526
+ }
527
+ }
528
+
529
+ RB_GC_GUARD(rows);
530
+ RB_GC_GUARD(results);
531
+
532
+ if (mode == BATCH_EXECUTE || block_given)
533
+ return INT2FIX(changes);
534
+ else
535
+ return results;
536
+ }
537
+
538
+ struct batch_execute_each_ctx {
539
+ query_ctx *ctx;
540
+ enum batch_mode mode;
541
+ int block_given;
542
+ VALUE results;
543
+ int changes;
544
+ };
545
+
546
+ static VALUE batch_run_each_iter(RB_BLOCK_CALL_FUNC_ARGLIST(yield_value, vctx)) {
547
+ struct batch_execute_each_ctx *each_ctx = (struct batch_execute_each_ctx*)vctx;
548
+ VALUE rows = Qnil;
549
+
550
+ sqlite3_reset(each_ctx->ctx->stmt);
551
+ sqlite3_clear_bindings(each_ctx->ctx->stmt);
552
+ bind_all_parameters_from_object(each_ctx->ctx->stmt, yield_value);
553
+
554
+ batch_iterate(each_ctx->ctx, each_ctx->mode, &rows);
555
+ each_ctx->changes += sqlite3_changes(each_ctx->ctx->sqlite3_db);
556
+
557
+ if (each_ctx->mode != BATCH_EXECUTE) {
558
+ if (each_ctx->block_given)
559
+ rb_yield(rows);
560
+ else
561
+ rb_ary_push(each_ctx->results, rows);
562
+ }
563
+ RB_GC_GUARD(rows);
564
+
565
+ return Qnil;
566
+ }
567
+
568
+ static inline VALUE batch_run_each(query_ctx *ctx, enum batch_mode mode) {
569
+ struct batch_execute_each_ctx each_ctx = {
570
+ .ctx = ctx,
571
+ .mode = mode,
572
+ .block_given = rb_block_given_p(),
573
+ .results = ((mode != BATCH_EXECUTE) && !rb_block_given_p() ? rb_ary_new() : Qnil),
574
+ .changes = 0
575
+ };
576
+ rb_block_call(ctx->params, ID_each, 0, 0, batch_run_each_iter, (VALUE)&each_ctx);
577
+
578
+ if (mode == BATCH_EXECUTE || each_ctx.block_given)
579
+ return INT2FIX(each_ctx.changes);
580
+ else
581
+ return each_ctx.results;
582
+ }
583
+
584
+ static inline VALUE batch_run_proc(query_ctx *ctx, enum batch_mode mode) {
585
+ VALUE params = Qnil;
586
+ int block_given = rb_block_given_p();
587
+ VALUE results = (mode != BATCH_EXECUTE) && !block_given ? rb_ary_new() : Qnil;
588
+ VALUE rows = Qnil;
589
+ int changes = 0;
590
+
591
+ while (1) {
592
+ params = rb_funcall(ctx->params, ID_call, 0);
593
+ if (NIL_P(params)) break;
594
+
595
+ sqlite3_reset(ctx->stmt);
596
+ sqlite3_clear_bindings(ctx->stmt);
597
+ bind_all_parameters_from_object(ctx->stmt, params);
598
+
599
+ batch_iterate(ctx, mode, &rows);
600
+ changes += sqlite3_changes(ctx->sqlite3_db);
601
+
602
+ if (mode != BATCH_EXECUTE) {
603
+ if (block_given)
604
+ rb_yield(rows);
605
+ else
606
+ rb_ary_push(results, rows);
607
+ }
437
608
  }
438
609
 
439
- return INT2FIX(changes);
610
+ RB_GC_GUARD(rows);
611
+ RB_GC_GUARD(results);
612
+ RB_GC_GUARD(params);
613
+
614
+ if (mode == BATCH_EXECUTE || block_given)
615
+ return INT2FIX(changes);
616
+ else
617
+ return results;
618
+ }
619
+
620
+ static inline VALUE batch_run(query_ctx *ctx, enum batch_mode mode) {
621
+ if (TYPE(ctx->params) == T_ARRAY)
622
+ return batch_run_array(ctx, mode);
623
+
624
+ if (rb_respond_to(ctx->params, ID_each))
625
+ return batch_run_each(ctx, mode);
626
+
627
+ if (rb_respond_to(ctx->params, ID_call))
628
+ return batch_run_proc(ctx, mode);
629
+
630
+ rb_raise(cParameterError, "Invalid parameter source supplied to #batch_execute");
631
+ }
632
+
633
+ VALUE safe_batch_execute(query_ctx *ctx) {
634
+ return batch_run(ctx, BATCH_EXECUTE);
635
+ }
636
+
637
+ VALUE safe_batch_query(query_ctx *ctx) {
638
+ return batch_run(ctx, BATCH_QUERY_HASH);
639
+ }
640
+
641
+ VALUE safe_batch_query_ary(query_ctx *ctx) {
642
+ return batch_run(ctx, BATCH_QUERY_ARY);
643
+ }
644
+
645
+ VALUE safe_batch_query_single_column(query_ctx *ctx) {
646
+ return batch_run(ctx, BATCH_QUERY_SINGLE_COLUMN);
440
647
  }
441
648
 
442
649
  VALUE safe_query_columns(query_ctx *ctx) {