diff --git a/ext/sqlite3/aggregator.c b/ext/sqlite3/aggregator.c index 9c17ea55..6b78b17c 100644 --- a/ext/sqlite3/aggregator.c +++ b/ext/sqlite3/aggregator.c @@ -97,7 +97,7 @@ rb_sqlite3_aggregate_instance_destroy(sqlite3_context *ctx) VALUE *inst_ptr = sqlite3_aggregate_context(ctx, 0); VALUE inst; - if (!inst_ptr || (inst = *inst_ptr)) { + if (!inst_ptr || !(inst = *inst_ptr)) { return; } diff --git a/test/test_integration_aggregate.rb b/test/test_integration_aggregate.rb index 0d71fa47..4a552be2 100644 --- a/test/test_integration_aggregate.rb +++ b/test/test_integration_aggregate.rb @@ -342,6 +342,18 @@ def finalize end end + # Used by one test only, so a live count of 1 means just the template. + class ReleasableAggregator + def step(*args) + @sum ||= 0 + args.each { |a| @sum += a.to_i } + end + + def finalize + @sum + end + end + class AccumulateAggregator2 def step(a, b) @sum ||= 1 @@ -364,6 +376,15 @@ def test_define_aggregator_with_two_different_arities assert_equal 2145, values[1] end + def test_aggregate_instances_are_released_after_each_query + @db.define_aggregator("accumulate", ReleasableAggregator.new) + + 5.times { assert_equal 33, @db.get_first_value("select accumulate(c) from foo") } + GC.start(full_mark: true, immediate_sweep: true) + + assert_equal 1, ObjectSpace.each_object(ReleasableAggregator).count + end + def test_step_on_statement_whose_database_was_closed_does_not_use_freed_aggregator @db.define_aggregator("accumulate", AccumulateAggregator.new) stmt = @db.prepare("select accumulate(c) from foo")