Am 02.02.14 19:36, schrieb Stephen: > > The original concern was that a generic utility function which wraps > dbi_rows and uses the typical foreach pattern might have it's private > variables clobbered by column names it can't predict. Returning a list > of dicts from dbi_rows is one way around that. > > Looks like there's a couple of different situations where wrappers are > wanted: > > 1) Legacy ACS db_* functions > > Looks like a lot of that code unpacks row ns_sets into local vars > anyway. db_multirow even has an -unclobber switch which restores the > original values of any vars which clash with column names. > > It seems like a bit of a backwards step to add legacy sets to the dbi > api only to have the legacy db_* stuff unpack it again. The best approach for OpenACS would be to rewrite the db-interface based on dbi_*. but this has currently at least two show-stoppers: dbi has no oracle support, and time (too many ns_db calls scattered all over the code, and ns_db has a very wide interface).
i guess you refer by "legacy sets" to the added option "-result sets". i've done this to cope with legacy code of the following form: while { [::db_getrow $db $answers] } { ... ... large body doing something with the ns_set $answers ... } To keep the code working with the old ns_db interface and to support as well additionally dbi, having "dbi_rows" to return a list of ns_sets comes very handy. One can replace the ns_set collecting code by dbi, but one does not have to rewrite the code extracting values from the ns_sets. One could certainly as well use the dicts option for dbi_* and covert the list of dicts to a list of ns_sets in tcl, which is certainly much slower (same with the flat result list). > > 2) New generic xo functions > > I'm not following how the implementation as it is now, which returns a > list of lists with duplicated column names, is faster than just > returning a list of dicts. You have to feed the lists to dict create > before you use it, which is extra work and always going to be slower. i am not following you here. The print string of a tcl dict is a tcl list. there is no need to use "dict create". try: dict get {a 1 b 2} b what i said in the comment was that adding elements to a list is faster than adding entries to the dict in the loop iterating over the columns. Furthermore, the list without the internal representation of the dict (essentially the hash table) requires less memory. > > For any other purpose nested lists are no different than the original > flat list with column list, and don't address the problem of variable > clobbering. > > How about this: > > dbi_dicts cols rows > > Returns a list of dicts by zipping up the cols and rows lists returned > by dbi_rows. It's faster than the current implementation as dbi_rows > only has to construct a flat list rather than the nested list with > duplicated keys, and that means less data to cache in ns_cache, and > parse again when deserialising. you say that set results [dbi_rows -colums cols -- *SQL*] set dicts [dbi_dicts $results $cols] is faster than set dicts [dbi_rows -result dicts -- *SQL*] hard to believe for me. the first form has to create an two more variables and has to iterate over the solutions twice. btw, the code in the tip behaves as ever when the option "-result" is not used. > > Generalising, it could be something like: > > dbi_foreach ?-dict name | -array name | -set name? cols rows ?body? > > I avoided adding the obvious implementation of this because it > encourages stuff like nested queries. With dbi_rows you either get a > list result or a template filled with subst, but no eval. There's only > ever one query active and no visible handle management. what is the problem with a dbi_foreach in the dbi infrastructure of the form: dbi_foreach ?-db name? ?-autonull? ?-timeout t? ?-bind bindSource? ?-max nrows? ?--? query ?body? i've prototyped such a thing, and it seems to work fine with nested queries. i would not be surprised if there would problems with transactions, but i see no reason these can be adressed as well. dbi_foreach allows break-able loops, where one can step over a query with potentially huge amount of results and stop depending on the result of an tcl-call. There is no need to get all results first. dbi_foreach *SQL* { .... if {[some-tcl-call $a $b $c]} { break } ... } How can this be handled with the exising dbi driver? i've no problem dropping the code in favor of some better implementation. -gn PS: using the OpenACS based xowiki with dbi (and the functions in mercurial head) lead to a 20% performance improvement with very little changes. ------------------------------------------------------------------------------ WatchGuard Dimension instantly turns raw network data into actionable security intelligence. It gives you real-time visual feedback on key security issues and trends. Skip the complicated setup - simply import a virtual appliance and go from zero to informed in seconds. http://pubads.g.doubleclick.net/gampad/clk?id=123612991&iu=/4140/ostg.clktrk _______________________________________________ naviserver-devel mailing list naviserver-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/naviserver-devel