On 1/30/19 3:27 PM, Andy Goth wrote:
The next chance I get (probably tomorrow morning), I'll go ahead and add "step" or "final" as the initial argument to aggregate functions. I'll also lift the prohibition on aggregate functions with no arguments.
This change is now committed. https://chiselapp.com/user/andy/repository/sqlite-andy/info/4fc35d5e09e2a486 I went with a string table approach that can be later expanded to handle method names for window functions.
oo::class create ListAggregate { method step {state args} { concat $state $args } method final {state} { my destroy return $state } } db function list -deterministic -aggregate [ListAggregate new]
This approach won't work. ListAggregate needs to be separately instantiated for every single group, not just once per database connection. Instead, something horrible like this is needed: oo::class create ListAggregate { variable state method step {args} { lappend state {*}$args } method final {} { return $state } } db function list -deterministic -aggregate { apply {{method obj args} { if {$obj eq {}} { set obj [ListAggregate new] } set result [$obj $method {*}$args] if {$method eq "final"} { $obj destroy return $result } else { return $obj } }} } I don't like this one bit. There's more logic adapting between the TclOO implementation and the tclsqlite calling convention than there is actual work being done. It's much simpler to just store the state data in the return value than in an object instantiation. Nevertheless, this approach may be more appropriate for complex window functions, so I'm exploring it rather than dismissing it out of hand. Let's have a choice of calling conventions, so different-sized tasks can have more infrastructure if they need it and less if they don't. By default, use the simple convention I started with, though augmented with method name, because why not. But as an alternative, well... start by looking at this example: oo::class create ListAggregate { variable state method step {args} { lappend state {*}$args } method final {} { return $state } } db function list -deterministic -aggregate -class ListAggregate The addition of the -class switch changes the script to instead be the name of a TclOO class, to which I will refer as $class: 1. Before the first invocation of the step function (or final function, if there are no rows), [$class new] is be called. Its return value is saved as the object instance name, referred to below as $obj. 2. For each row, [$obj step ?arg ...?] is called. 3. After the last row, [$obj final] is called, and its return value is used as the return value of the SQL function. 4. To clean up, [$obj destroy] is called. If an error occurs in step 1, terminate immediately. If an error occurs in steps 2 or 3, go straight to step 4. You may notice TclOO is not actually required. Other object systems such as [incr tcl], XOTcl, Snit, and stooop may be used, though possibly with wrapper shims, but honestly anybody can write commands that behave like $class and $obj are expected to behave. Thus, there is no real dependency on Tcl 8.6. [$class new] and [$obj destroy] may call user-defined constructors and destructors, but while this may be useful to the programmer, it is internal to TclOO and is not SQLite's concern. To recap, when -class is not used, the procedure is as follows, where $script is the script argument to [db function]: 1. For each row, [$script step $state ?arg ...?] is called, where $state is (first row) empty string or (subsequent rows) the return value of the previous call to [$script step]. 2. After the last row, [$script final $state] is called, and its return value is used as the return value of the SQL function. $state is the return value of the last call to [$script step] or empty string if there were no rows. Unless there are comments or objections, I'll try adding -class the next time I get a chance to hack on this. I think it may be overkill for aggregate functions but will probably be useful for window functions. -- Andy Goth | <andrew.m.goth/at/gmail/dot/com> _______________________________________________ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users