Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*.c,*.h]
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
tab_width = 8
trim_trailing_whitespace = true

[*.rb,Rakefile,*.rake,*.gemspec]
indent_size = 2

[*.yml]
indent_size = 2
290 changes: 145 additions & 145 deletions ext/sqlite3/aggregator.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ typedef struct rb_sqlite3_protected_funcall_args {
static VALUE
rb_sqlite3_protected_funcall_body(VALUE protected_funcall_args_ptr)
{
protected_funcall_args_t *args =
(protected_funcall_args_t*)protected_funcall_args_ptr;
protected_funcall_args_t *args =
(protected_funcall_args_t *)protected_funcall_args_ptr;

return rb_funcall2(args->self, args->method, args->argc, args->params);
return rb_funcall2(args->self, args->method, args->argc, args->params);
}

static VALUE
rb_sqlite3_protected_funcall(VALUE self, ID method, int argc, VALUE *params,
int* exc_status)
int *exc_status)
{
protected_funcall_args_t args = {
.self = self, .method = method, .argc = argc, .params = params
};
return rb_protect(rb_sqlite3_protected_funcall_body, (VALUE)(&args), exc_status);
protected_funcall_args_t args = {
.self = self, .method = method, .argc = argc, .params = params
};
return rb_protect(rb_sqlite3_protected_funcall_body, (VALUE)(&args), exc_status);
}

/* called in rb_sqlite3_aggregator_step and rb_sqlite3_aggregator_final. It
Expand All @@ -54,36 +54,36 @@ rb_sqlite3_protected_funcall(VALUE self, ID method, int argc, VALUE *params,
static VALUE
rb_sqlite3_aggregate_instance(sqlite3_context *ctx)
{
VALUE aw = (VALUE) sqlite3_user_data(ctx);
VALUE handler_klass = rb_iv_get(aw, "-handler_klass");
VALUE inst;
VALUE *inst_ptr = sqlite3_aggregate_context(ctx, (int)sizeof(VALUE));
VALUE aw = (VALUE) sqlite3_user_data(ctx);
VALUE handler_klass = rb_iv_get(aw, "-handler_klass");
VALUE inst;
VALUE *inst_ptr = sqlite3_aggregate_context(ctx, (int)sizeof(VALUE));

if (!inst_ptr) {
rb_fatal("SQLite is out-of-merory");
}
if (!inst_ptr) {
rb_fatal("SQLite is out-of-merory");
}

inst = *inst_ptr;
inst = *inst_ptr;

if (inst == Qfalse) { /* Qfalse == 0 */
VALUE instances = rb_iv_get(aw, "-instances");
int exc_status;
if (inst == Qfalse) { /* Qfalse == 0 */
VALUE instances = rb_iv_get(aw, "-instances");
int exc_status;

inst = rb_class_new_instance(0, NULL, cAggregatorInstance);
rb_iv_set(inst, "-handler_instance", rb_sqlite3_protected_funcall(
handler_klass, rb_intern("new"), 0, NULL, &exc_status));
rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));
inst = rb_class_new_instance(0, NULL, cAggregatorInstance);
rb_iv_set(inst, "-handler_instance", rb_sqlite3_protected_funcall(
handler_klass, rb_intern("new"), 0, NULL, &exc_status));
rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));

rb_ary_push(instances, inst);
rb_ary_push(instances, inst);

*inst_ptr = inst;
}
*inst_ptr = inst;
}

if (inst == Qnil) {
rb_fatal("SQLite called us back on an already destroyed aggregate instance");
}
if (inst == Qnil) {
rb_fatal("SQLite called us back on an already destroyed aggregate instance");
}

return inst;
return inst;
}

/* called by rb_sqlite3_aggregator_final. Unlinks and frees the
Expand All @@ -92,84 +92,84 @@ rb_sqlite3_aggregate_instance(sqlite3_context *ctx)
static void
rb_sqlite3_aggregate_instance_destroy(sqlite3_context *ctx)
{
VALUE aw = (VALUE) sqlite3_user_data(ctx);
VALUE instances = rb_iv_get(aw, "-instances");
VALUE *inst_ptr = sqlite3_aggregate_context(ctx, 0);
VALUE inst;
VALUE aw = (VALUE) sqlite3_user_data(ctx);
VALUE instances = rb_iv_get(aw, "-instances");
VALUE *inst_ptr = sqlite3_aggregate_context(ctx, 0);
VALUE inst;

if (!inst_ptr || (inst = *inst_ptr)) {
return;
}
if (!inst_ptr || (inst = *inst_ptr)) {
return;
}

if (inst == Qnil) {
rb_fatal("attempt to destroy aggregate instance twice");
}
if (inst == Qnil) {
rb_fatal("attempt to destroy aggregate instance twice");
}

rb_iv_set(inst, "-handler_instance", Qnil); // may catch use-after-free
if (rb_ary_delete(instances, inst) == Qnil) {
rb_fatal("must be in instances at that point");
}
rb_iv_set(inst, "-handler_instance", Qnil); // may catch use-after-free
if (rb_ary_delete(instances, inst) == Qnil) {
rb_fatal("must be in instances at that point");
}

*inst_ptr = Qnil;
*inst_ptr = Qnil;
}

static void
rb_sqlite3_aggregator_step(sqlite3_context * ctx, int argc, sqlite3_value **argv)
rb_sqlite3_aggregator_step(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
VALUE inst = rb_sqlite3_aggregate_instance(ctx);
VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
VALUE * params = NULL;
VALUE one_param;
int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
int i;

if (exc_status) {
return;
}

if (argc == 1) {
one_param = sqlite3val2rb(argv[0]);
params = &one_param;
}
if (argc > 1) {
params = xcalloc((size_t)argc, sizeof(VALUE));
for(i = 0; i < argc; i++) {
params[i] = sqlite3val2rb(argv[i]);
VALUE inst = rb_sqlite3_aggregate_instance(ctx);
VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
VALUE *params = NULL;
VALUE one_param;
int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
int i;

if (exc_status) {
return;
}

if (argc == 1) {
one_param = sqlite3val2rb(argv[0]);
params = &one_param;
}
if (argc > 1) {
params = xcalloc((size_t)argc, sizeof(VALUE));
for (i = 0; i < argc; i++) {
params[i] = sqlite3val2rb(argv[i]);
}
}
rb_sqlite3_protected_funcall(
handler_instance, rb_intern("step"), argc, params, &exc_status);
if (argc > 1) {
xfree(params);
}
}
rb_sqlite3_protected_funcall(
handler_instance, rb_intern("step"), argc, params, &exc_status);
if (argc > 1) {
xfree(params);
}

rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));

rb_iv_set(inst, "-exc_status", INT2NUM(exc_status));
}

/* we assume that this function is only called once per execution context */
static void
rb_sqlite3_aggregator_final(sqlite3_context * ctx)
rb_sqlite3_aggregator_final(sqlite3_context *ctx)
{
VALUE inst = rb_sqlite3_aggregate_instance(ctx);
VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));
VALUE inst = rb_sqlite3_aggregate_instance(ctx);
VALUE handler_instance = rb_iv_get(inst, "-handler_instance");
int exc_status = NUM2INT(rb_iv_get(inst, "-exc_status"));

if (!exc_status) {
VALUE result = rb_sqlite3_protected_funcall(
handler_instance, rb_intern("finalize"), 0, NULL, &exc_status);
if (!exc_status) {
set_sqlite3_func_result(ctx, result);
VALUE result = rb_sqlite3_protected_funcall(
handler_instance, rb_intern("finalize"), 0, NULL, &exc_status);
if (!exc_status) {
set_sqlite3_func_result(ctx, result);
}
}
}

if (exc_status) {
/* the user should never see this, as Statement.step() will pick up the
* outstanding exception and raise it instead of generating a new one
* for SQLITE_ERROR with message "Ruby Exception occurred" */
sqlite3_result_error(ctx, "Ruby Exception occurred", -1);
}
if (exc_status) {
/* the user should never see this, as Statement.step() will pick up the
* outstanding exception and raise it instead of generating a new one
* for SQLITE_ERROR with message "Ruby Exception occurred" */
sqlite3_result_error(ctx, "Ruby Exception occurred", -1);
}

rb_sqlite3_aggregate_instance_destroy(ctx);
rb_sqlite3_aggregate_instance_destroy(ctx);
}

/* call-seq: define_aggregator2(aggregator)
Expand Down Expand Up @@ -205,69 +205,69 @@ rb_sqlite3_aggregator_final(sqlite3_context * ctx)
VALUE
rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name)
{
/* define_aggregator is added as a method to SQLite3::Database in database.c */
sqlite3RubyPtr ctx = sqlite3_database_unwrap(self);
int arity, status;
VALUE aw;
VALUE aggregators;

if (!ctx->db) {
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
}

if (rb_respond_to(aggregator, rb_intern("arity"))) {
VALUE ruby_arity = rb_funcall(aggregator, rb_intern("arity"), 0);
arity = NUM2INT(ruby_arity);
} else {
arity = -1;
}

if (arity < -1 || arity > 127) {
/* define_aggregator is added as a method to SQLite3::Database in database.c */
sqlite3RubyPtr ctx = sqlite3_database_unwrap(self);
int arity, status;
VALUE aw;
VALUE aggregators;

if (!ctx->db) {
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
}

if (rb_respond_to(aggregator, rb_intern("arity"))) {
VALUE ruby_arity = rb_funcall(aggregator, rb_intern("arity"), 0);
arity = NUM2INT(ruby_arity);
} else {
arity = -1;
}

if (arity < -1 || arity > 127) {
#ifdef PRIsVALUE
rb_raise(rb_eArgError, "%"PRIsVALUE" arity=%d out of range -1..127",
self, arity);
rb_raise(rb_eArgError, "%"PRIsVALUE" arity=%d out of range -1..127",
self, arity);
#else
rb_raise(rb_eArgError, "Aggregator arity=%d out of range -1..127", arity);
rb_raise(rb_eArgError, "Aggregator arity=%d out of range -1..127", arity);
#endif
}

if (!rb_ivar_defined(self, rb_intern("-aggregators"))) {
rb_iv_set(self, "-aggregators", rb_ary_new());
}
aggregators = rb_iv_get(self, "-aggregators");

aw = rb_class_new_instance(0, NULL, cAggregatorWrapper);
rb_iv_set(aw, "-handler_klass", aggregator);
rb_iv_set(aw, "-instances", rb_ary_new());

status = sqlite3_create_function(
ctx->db,
StringValueCStr(ruby_name),
arity,
SQLITE_UTF8,
(void*)aw,
NULL,
rb_sqlite3_aggregator_step,
rb_sqlite3_aggregator_final
);

if (status != SQLITE_OK) {
rb_sqlite3_raise(ctx->db, status);
return self; // just in case rb_sqlite3_raise returns.
}

rb_ary_push(aggregators, aw);

return self;
}

if (!rb_ivar_defined(self, rb_intern("-aggregators"))) {
rb_iv_set(self, "-aggregators", rb_ary_new());
}
aggregators = rb_iv_get(self, "-aggregators");

aw = rb_class_new_instance(0, NULL, cAggregatorWrapper);
rb_iv_set(aw, "-handler_klass", aggregator);
rb_iv_set(aw, "-instances", rb_ary_new());

status = sqlite3_create_function(
ctx->db,
StringValueCStr(ruby_name),
arity,
SQLITE_UTF8,
(void *)aw,
NULL,
rb_sqlite3_aggregator_step,
rb_sqlite3_aggregator_final
);

if (status != SQLITE_OK) {
rb_sqlite3_raise(ctx->db, status);
return self; // just in case rb_sqlite3_raise returns.
}

rb_ary_push(aggregators, aw);

return self;
}

void
rb_sqlite3_aggregator_init(void)
{
/* rb_class_new generatos class with undefined allocator in ruby 1.9 */
cAggregatorWrapper = rb_funcall(rb_cClass, rb_intern("new"), 0);
rb_gc_register_mark_object(cAggregatorWrapper);
/* rb_class_new generatos class with undefined allocator in ruby 1.9 */
cAggregatorWrapper = rb_funcall(rb_cClass, rb_intern("new"), 0);
rb_gc_register_mark_object(cAggregatorWrapper);

cAggregatorInstance = rb_funcall(rb_cClass, rb_intern("new"), 0);
rb_gc_register_mark_object(cAggregatorInstance);
cAggregatorInstance = rb_funcall(rb_cClass, rb_intern("new"), 0);
rb_gc_register_mark_object(cAggregatorInstance);
}
6 changes: 2 additions & 4 deletions ext/sqlite3/aggregator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@

#include <sqlite3_ruby.h>

VALUE
rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name);
VALUE rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name);

void
rb_sqlite3_aggregator_init(void);
void rb_sqlite3_aggregator_init(void);

#endif
Loading