tests to demonstrate issues with aggregate function handling #24
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Added tests to demonstrate three issues with the way sqlite3-ruby
currently handles aggregate functions:
(1) Defining a second aggregate function and using both results in
memory violation. The problem is that
rb_iv_set(self, "@agregator", aggregator);(database.c:399) just overwrites the last reference tothe first AggregateHandler, but SQLite still holds a pointer to it and
will follow the pointer if the first aggregate function is used in a
query.
The most straight-forward fix is to insert the aggregator in a ruby
array and never release it -- similar to how its done for functions.
(2) Using the same aggregate function twice in a query mixes up values
from both columns. For example:
SELECT MYAGGREG(a), MYAGGREG(b) FROM foo;Leads to: Myaggreg.step(a1); Myaggreg.step(b1); Myaggreg.step(a2);
Myaggreg.step(b2); ... ; Myaggreg.finalize(), Myaggreg.finalize()
The SQLite API expects the caller to differentiate between these
chains of invocation via
sqlite3_aggregate_context(), but currentsqlite3-ruby does not account for that.
#44 has been a work around for this in the special case that the first
aggregation is finalized before the second started (separate queries).
sparklemotion#161 does the analog for the function Proxy.
(3) Documentation implies that library users shall explicitly set the
arity of the function. Consequently the library user is likely to
expect that this is passed down to SQLite, so he may define multiple
functions with the same name but different arity and SQLite to use the
most appropriate one (documented sqlite feature). Unfortunately,
sqlite3-ruby does not pass the arity to SQLite, which is surprising
given that different arity-values are accounted for in the C code. The
problem is that sqlite3-ruby does not call the AggregateHandlers
"arity" method but instead queries the arity of
the "step" method from Ruby (sqlite3_obj_method_arity). Confusingly,
this is not the "step" provided by the library user, but the "step" of
the Proxy Wrapper classes introduced by Database.create_aggregate or
Database.create_aggregate_handler. Both of these are just
step(*args), so the arity reported to SQLite is always -1.Things not addressed:
FunctionProxy.count). because @driver does not exist (anymore)
that is never passed down to SQLite. It is not advertised in the
documentation, though.
(cherry picked from commit ae89dea)