In article <xcv7kwwstvw....@conquest.OCF.Berkeley.EDU>, Thomas F. Burdick wrote: >delare...@netscape.net (Delaregue) writes:
>> Sorry for the new post
>> I've found a way: >> (concatenate 'string '(#\newline) "or (" c " =...etc...
>> My new born twins baby must be tiring me ;-)
>While this will work, I find it horrid style to format strings this >way. Use FORMAT instead.
Why not make a funtion called catenate, or cat, just for strings. That eliminates the annoying 'string type parameter, and its name abuses the language less (``catenate'' means to chain together, so the ``con'' prefix is superflous).
Invoking an interpretive formatter to glue strings together is neat, but possibly inefficient, not to mention needlessly cryptic.
k...@ashi.footprints.net (Kaz Kylheku) writes: > >While this will work, I find it horrid style to format strings this > >way. Use FORMAT instead.
> Why not make a funtion called catenate, or cat, just for strings. > That eliminates the annoying 'string type parameter, and its name abuses > the language less (``catenate'' means to chain together, so the ``con'' > prefix is superflous).
True, although current usage isn't quite as strict as you're implying. The reason for not making a new function when an acceptable idiom exists is that you raise the barrier for maintainability.
> Invoking an interpretive formatter to glue strings together is neat, > but possibly inefficient, not to mention needlessly cryptic.
If it turns out that this format call is the speed-critical portion of the application, you can always use formatter; personally, I'd find a user function with a non-intuitive name[1] a lot more cryptic than (format nil "~a~%~a" x y) or its formatter equivalent.
Cheers,
Christophe
[1] Ah, the irony... my idea for common-lisp-utilities was for functionality that didn't have a convenient idiom already; so partition and extremize, but not this catenate or Marco's make-array wrapper. Since there doesn't seem to be much demand or even comment, this is largely moot. -- Jesus College, Cambridge, CB5 8BL +44 1223 510 299 http://www-jcsu.jesus.cam.ac.uk/~csr21/ (defun pling-dollar (str schar arg) (first (last +))) (make-dispatch-macro-character #\! t) (set-dispatch-macro-character #\! #\$ #'pling-dollar)
> > >While this will work, I find it horrid style to format strings this > > >way. Use FORMAT instead.
> > Why not make a funtion called catenate, or cat, just for strings. > > That eliminates the annoying 'string type parameter, and its name abuses > > the language less (``catenate'' means to chain together, so the ``con'' > > prefix is superflous).
> True, although current usage isn't quite as strict as you're > implying. The reason for not making a new function when an acceptable > idiom exists is that you raise the barrier for maintainability.
Substantially. I personally would guess the aggregate cost to the community of changing the name of the function from concatenate to catentate would probably be in the multiple millions of dollars in labor at the various companies where Lisp is installed and where a change needs to be implemented. Had the industry such money to spend, it would be better off spending it on R&D...
> > Invoking an interpretive formatter to glue strings together is neat, > > but possibly inefficient, not to mention needlessly cryptic.
> If it turns out that this format call is the speed-critical portion of > the application, you can always use formatter; personally, I'd find a > user function with a non-intuitive name[1] a lot more cryptic than > (format nil "~a~%~a" x y) or its formatter equivalent.
I think the most important stylistic thing to do when you have questions like this is to abstract out the problem. Make a STRING-APPEND. There are a million ways to implement one, but the really important thing is to just get it to where the definition is in one place so that if you decide to change it (e.g., to speed it up) the benefit will be felt in all the points of use.
Btw, I do think FORMAT is likely to be slower than FORMAT. Among other things, it goes through a stream interface which in a simple case like this is serious overkill. Even IF you manage to stack-allocate the stream and its associated buffers, which not all implementations will, the time required to do that allocation is probably already as long as some implementations would take to execute the CONCATENATE.
> Invoking an interpretive formatter to glue strings together is neat, > but possibly inefficient, not to mention needlessly cryptic.
What made you believe it is "interpretive"? Have we not had this stupid discussion about interpreter versus compiler enough times already?
As for cryptic, Greek is cryptic to non-Greeks. Just learn the language. Ignorance of the language is no excuse.
#:Erik -- There is nothing in this message that under normal circumstances should cause Barry Margolin to announce his moral superiority over others, but one never knows how he needs to behave to maintain his belief in it.
>> > >While this will work, I find it horrid style to format strings this >> > >way. Use FORMAT instead.
>> > Why not make a funtion called catenate, or cat, just for strings. >> > That eliminates the annoying 'string type parameter, and its name abuses >> > the language less (``catenate'' means to chain together, so the ``con'' >> > prefix is superflous).
>> True, although current usage isn't quite as strict as you're >> implying. The reason for not making a new function when an acceptable >> idiom exists is that you raise the barrier for maintainability.
>Substantially. I personally would guess the aggregate cost to the >community of changing the name of the function from concatenate to >catentate would probably be in the multiple millions of dollars in
I never proposed a name change for the existing function; I for one am happy that ``catenate'' is an available identifier so that you can write your own function and call it that.
In article <3205088270665...@naggum.net>, Erik Naggum wrote: >* k...@ashi.footprints.net (Kaz Kylheku) >> Invoking an interpretive formatter to glue strings together is neat, >> but possibly inefficient, not to mention needlessly cryptic.
> What made you believe it is "interpretive"? Have we not had this stupid > discussion about interpreter versus compiler enough times already?
What makes you believe that it's *never* interpretive? It's more likely than not to be implemented that way---as a function which scans the string and carries out the formatting actions described therein.
Since my comment was performance related, I had a likely common implementation in mind, which could be possibly quite inefficient for catenating strings.
Of course, I realize that (format nil "~A~A" x y) could be recognized as an idiom, and translated into a direct catenation operation.
I also realize that the performance of the catenation of two strings might not even matter.
Erik Naggum <e...@naggum.net> writes: > * k...@ashi.footprints.net (Kaz Kylheku) > > Invoking an interpretive formatter to glue strings together is neat, > > but possibly inefficient, not to mention needlessly cryptic.
> What made you believe it is "interpretive"? Have we not had this stupid > discussion about interpreter versus compiler enough times already?
> As for cryptic, Greek is cryptic to non-Greeks. Just learn the language. > Ignorance of the language is no excuse.
I'm sure a number of CL implementations don't compile format strings. I think it's fair to characterize them as interpretive since they're sort of like byte-code interpreters.
On Wed, 25 Jul 2001, Kaz Kylheku wrote: > In article <3205088270665...@naggum.net>, Erik Naggum wrote: > >* k...@ashi.footprints.net (Kaz Kylheku) > >> Invoking an interpretive formatter to glue strings together is neat, > >> but possibly inefficient, not to mention needlessly cryptic.
> > What made you believe it is "interpretive"? Have we not had this stupid > > discussion about interpreter versus compiler enough times already?
> What makes you believe that it's *never* interpretive? It's more likely > than not to be implemented that way---as a function which scans > the string and carries out the formatting actions described therein.
Since FORMATTER is in the language and public domain code exists for it, I'd say it's quite likely that implementations do transform some calls to FORMAT with constant format strings into calls of the (compiled) formatter function. On the other hand, firing up the stream and format machinery may be a bigger bottleneck than interpreting the format string. On the third hand, do you really care?
> > > Thomas F. Burdick <t...@OCF.berkeley.EDU> writes:
> > > >While this will work, I find it horrid style to format strings this > > > >way. Use FORMAT instead.
[ ... ] > > > Invoking an interpretive formatter to glue strings together is neat, > > > but possibly inefficient, not to mention needlessly cryptic.
> > If it turns out that this format call is the speed-critical portion of > > the application, you can always use formatter; personally, I'd find a > > user function with a non-intuitive name[1] a lot more cryptic than > > (format nil "~a~%~a" x y) or its formatter equivalent.
> I think the most important stylistic thing to do when you have questions > like this is to abstract out the problem. Make a STRING-APPEND. There > are a million ways to implement one, but the really important thing is > to just get it to where the definition is in one place so that if you > decide to change it (e.g., to speed it up) the benefit will be felt in > all the points of use. [ ... ] > Btw, I do think FORMAT is likely to be slower.
[assuming you meant to omit "than FORMAT"]
> Among other things, it goes through a stream interface which in a > simple case like this is serious overkill. Even IF you manage to > stack-allocate the stream and its associated buffers, which not all > implementations will, the time required to do that allocation is > probably already as long as some implementations would take to > execute the CONCATENATE.
Hmm, my gut reaction is "so, what?". The problem is to stuff data into fields of a formatted SQL query. Isn't that *exactly* the domain of formatted i/o functions? I would find something like: (format nil "select unique(~S.~S) from ~S, ~S~%where ~S.~S = ~S;" table-one desired-field table-one table-two table-two join-field desired-join-value) far preferable to: (cat "select unique(" table-one "." desired-field ") " "from " table-one ", " table-two #\newline "where " table-two "." join-field " = " desired-join-value ";")
The only way I would ever use the second is if I had to for speed. Maybe this is a style point where opinions can differ, but I find the second version horrid and Perl-like, where the first keeps the SQL together and comprehensible.
In article <9jnkd0$43...@216.39.145.192>, Tim Moore wrote: >On Wed, 25 Jul 2001, Kaz Kylheku wrote: >> What makes you believe that it's *never* interpretive? It's more likely >> than not to be implemented that way---as a function which scans >> the string and carries out the formatting actions described therein.
>Since FORMATTER is in the language and public domain code exists for it, >I'd say it's quite likely that implementations do transform some calls to >FORMAT with constant format strings into calls of the (compiled) formatter >function. On the other hand, firing up the stream and format machinery >may be a bigger bottleneck than interpreting the format string. On the >third hand, do you really care?
Erik Naggum <e...@naggum.net> writes: > * k...@ashi.footprints.net (Kaz Kylheku) > > Invoking an interpretive formatter to glue strings together is neat, > > but possibly inefficient, not to mention needlessly cryptic. > What made you believe it is "interpretive"? Have we not had this > stupid discussion about interpreter versus compiler enough times > already?
Because C format strings describe an interpretive sublanguage, and few ever think beyond that :-(.
More reasonably, it is not outrageous to anticipate that it's pretty likely that
may result in some runtime interpretation of the format string, whilst (format T (formatter "Some Directives ~A ~A ~A ~D~%") 'this 'taht 'other 25) is _guaranteed_ to involve some pre-compiling. -- (concatenate 'string "cbbrowne" "@acm.org") http://vip.hyperusa.com/~cbbrowne/linuxdistributions.html "...In my phone conversation with Microsoft's lawyer I copped to the fact that just maybe his client might see me as having been in the past just a bit critical of their products and business practices. This was too bad, he said with a sigh, because they were having a very hard time finding a reporter who both knew the industry well enough to be called an expert and who hadn't written a negative article about Microsoft." -- Robert X. Cringely
t...@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> Kent M Pitman <pit...@world.std.com> writes: > > Btw, I do think FORMAT is likely to be slower. > [assuming you meant to omit "than FORMAT"] > > Among other things, it goes through a stream interface which in a > > simple case like this is serious overkill. Even IF you manage to > > stack-allocate the stream and its associated buffers, which not all > > implementations will, the time required to do that allocation is > > probably already as long as some implementations would take to > > execute the CONCATENATE.
> The problem is to stuff data into fields of a formatted SQL query. > Isn't that *exactly* the domain of formatted i/o functions? I would > find something like: > (format nil "select unique(~S.~S) from ~S, ~S~%where ~S.~S = ~S;" > table-one desired-field > table-one table-two > table-two join-field desired-join-value) > far preferable to: > (cat "select unique(" table-one "." desired-field ") " > "from " table-one ", " table-two #\newline > "where " table-two "." join-field " = " desired-join-value ";")
> The only way I would ever use the second is if I had to for speed. > Maybe this is a style point where opinions can differ, but I find > the second version horrid and Perl-like, where the first keeps the > SQL together and comprehensible.
You've not mentioned, but I'm sure it's the case, that "time doesn't matter" in this case. The amount of time spent pushing the query out to the DBMS and processing the results may be reasonably expected to _vastly_ outweigh any time wasted on string catenation.
I'd suggest that this is a place where efficiency would be quite nicely served by setting up a FORMATTER to save _most_ of the time that gets lost by using a format scheme.
Thus: (defparameter *unique-join-format* (formatter "select unique(~S.~S) from ~S, ~S~ where ~S.~S = ~S;"))
It might even be a reasonable idea to have some scheme for "clause formation" where the selection might get generated by a function call looking vaguely like:
(gen-select :unique '((table-one desired-field)) :from '(table-one table-two) :where '((= (table-two join-field) desired-join-value))) -- (concatenate 'string "cbbrowne" "@ntlug.org") http://vip.hyperusa.com/~cbbrowne/lisp.html If you stand in the middle of a library and shout "Aaaaaaaaargh" at the top of your voice, everyone just stares at you. If you do the same thing on an aeroplane, why does everyone join in?
> What makes you believe that it's *never* interpretive?
I do not believe that. Why do you invent such stupid claims to ask me to refute when nobody have said anything remotely like it?
> It's more likely than not to be implemented that way---as a function > which scans the string and carries out the formatting actions described > therein.
How do you wind up with that "more likely" conclusion? Geez. This is how those arrogant ignorants who claim to know how to implement Lisp turn out to be college drop-outs after a few overdoses of Scheme. Smart people do that string traversal at compile-time and generate the most efficient code that can be known at compile-time. This is not hard. This is _not_ C's printf and like-minded idiocy.
Take a look at the formatter macro the next time you feel the urge to tell people how they "most likely" implement format. A constant string as format's second argument is a bloody obvious candidate for a compiler macro to turn into a macro call to formatter.
> Since my comment was performance related, I had a likely common > implementation in mind, which could be possibly quite inefficient for > catenating strings.
How do you know that it is "likely common"? How much experience do you have evaluating implementation techniques for such things? None, right? You are just guessing and making up statistics about commonality as you go. This is _dishonest_ of you. It would have been honest to admit you made it up with no supporting evidence at all. This is _so_ annoying and it happens all the time to people who have very little clue.
> Of course, I realize that (format nil "~A~A" x y) could be recognized as > an idiom, and translated into a direct catenation operation.
Well, _that_ is fairly unlikely to be optimized away, as ~A does not only print the characters of strings, but does a lot more work than that. However, ~% and ~& do print only newlines. Please do not tell me that '(#\Newline) is better than ~%.
> I also realize that the performance of the catenation of two strings > might not even matter.
That is most probably true, but if it does not matter, the most perspicuous solution should be chosen. In this case, that would actually be writing to a string stream with several format calls, as the amount of stuff to put into that "string" _will_ grow without bound over time.
> Sorry if I upset anyone!
I would have been much happier if you were sorry you had jumped to conclusions from completely absent information, which would be the _cause_ people would be upset. We have been over this "interpreter" misconception _enough_ times already. Just grow a clue: If it would be slow, somebody has already made it more efficient than you can think of. People who just make random noise from their own lack of experience about what other people with such experience would have done need to be refuted and corrected -- over and over again, because the very idea that somebody might have more experience and _might_ have solved their obvious problem simply does not occur to these people, unfathomable as that really is.
There are so many completely bogus reasons _not_ to use good solutions in Common Lisp that never apply to any other language. Why is this? Is it fear of having to know more about Common Lisp than other languages? Look at what people do in Perl, Java, og C++, for crying out loud! And format is supposed to be slow and cryptic? Gimme a _break_! When talking to an SQL database! Sheesh.
Ignorance of the language is no excuse. Sorry for repeating myself.
#:Erik -- There is nothing in this message that under normal circumstances should cause Barry Margolin to announce his moral superiority over others, but one never knows how he needs to behave to maintain his belief in it.
cbbro...@hex.net writes: >> Isn't that *exactly* the domain of formatted i/o functions? I would >> find something like: >> (format nil "select unique(~S.~S) from ~S, ~S~%where ~S.~S = ~S;" >> table-one desired-field >> table-one table-two >> table-two join-field desired-join-value) >> far preferable to: >> (cat "select unique(" table-one "." desired-field ") " >> "from " table-one ", " table-two #\newline >> "where " table-two "." join-field " = " desired-join-value ";")
>> The only way I would ever use the second is if I had to for speed. >> Maybe this is a style point where opinions can differ, but I find >> the second version horrid and Perl-like, where the first keeps the >> SQL together and comprehensible.
> You've not mentioned, but I'm sure it's the case, that "time doesn't > matter" in this case. The amount of time spent pushing the query out > to the DBMS and processing the results may be reasonably expected to > _vastly_ outweigh any time wasted on string catenation.
I'll probably be late with this, but I've had some bad experience with this kind of stuff, so:
SQL needs quoting for some characters etc. You are not doing so in the examples given, this in the end will end up hurting you. Most SQL interfaces have a seperate, less primitive interface where you do thinks like:
This gives you - higher speed, as you can just update the parameters in a loop. - type safety, as the SQL interface can check what you've given it - automatic quoting beyond what is posssible in the simple queries (for example for BLOB's)
And in fact it is even simpler to use. On second thought: why don't you use MaiSQL? :-)
Groetjes, Peter
-- It's logic Jim, but not as we know it. | pvane...@debian.org "God, root, what is difference?" - Pitr| "God is more forgiving." - Dave Aronson| http://cvs2.cons.org/~pvaneynd/
> >> Isn't that *exactly* the domain of formatted i/o functions? I would > >> find something like: > >> (format nil "select unique(~S.~S) from ~S, ~S~%where ~S.~S = ~S;" > >> table-one desired-field > >> table-one table-two > >> table-two join-field desired-join-value) > >> far preferable to: > >> (cat "select unique(" table-one "." desired-field ") " > >> "from " table-one ", " table-two #\newline > >> "where " table-two "." join-field " = " desired-join-value ";")
> >> The only way I would ever use the second is if I had to for speed. > >> Maybe this is a style point where opinions can differ, but I find > >> the second version horrid and Perl-like, where the first keeps the > >> SQL together and comprehensible.
> > You've not mentioned, but I'm sure it's the case, that "time doesn't > > matter" in this case. The amount of time spent pushing the query out > > to the DBMS and processing the results may be reasonably expected to > > _vastly_ outweigh any time wasted on string catenation. > I'll probably be late with this, but I've had some bad experience > with this kind of stuff, so: > SQL needs quoting for some characters etc. You are not doing so in > the examples given, this in the end will end up hurting you.
True enough; I'd noticed, but not commented on that. For instance, a query might look like:
select * from some-table where name='Christopher Browne';
That needs a bit of quoting and such, and this is _NOT_ in the form typically used for quoting.
> Most SQL interfaces have a seperate, less primitive interface where > you do thinks like: > (prepare-query "select unique(?,?) from ?, ? where ? = ?") > (setf (query-parameter 1) 'foo > (query-parameter 2) 'bar > (query-parameter 3) 'table-a > (query-parameter 4) 'table-b > (query-parameter 5) 'foo > (query-parameter 6) 45) > (execute-query) > This gives you > - higher speed, as you can just update the parameters in a loop. > - type safety, as the SQL interface can check what you've given it > - automatic quoting beyond what is posssible in the simple queries > (for example for BLOB's)
Yes, that looks pretty sensible...
> And in fact it is even simpler to use. On second thought: why don't > you use MaiSQL? :-)
-- (reverse (concatenate 'string "ac.notelrac.teneerf@" "454aa")) http://vip.hex.net/~cbbrowne/sap.html Objects & Markets "Object-oriented programming is about the modular separation of what from how. Market-oriented, or agoric, programming additionally allows the modular separation of why." -- Mark Miller
>> This gives you >> - higher speed, as you can just update the parameters in a loop. >> - type safety, as the SQL interface can check what you've given it >> - automatic quoting beyond what is posssible in the simple queries >> (for example for BLOB's)
> Yes, that looks pretty sensible...
Sensible? Using numeric parameter numbers looks pretty horrible to me. Ever time someone modifies the query, all hell will break out.
> >> This gives you > >> - higher speed, as you can just update the parameters in a loop. > >> - type safety, as the SQL interface can check what you've given it > >> - automatic quoting beyond what is posssible in the simple queries > >> (for example for BLOB's)
> > Yes, that looks pretty sensible...
> Sensible? Using numeric parameter numbers looks pretty horrible to me. Ever > time someone modifies the query, all hell will break out.
Its a little horrible, but I don't think its all that fragile- a name based approach would be very desirable.. The example above formats a sql statement, presumably substituting the '?' marks with either a constant or the value a symbol. Once execute-query returns, "output" symbols, somehow indicated, would contain the query output values.
I think its in the right direction for managing complex sets of output rows, where the rows can be iterated over, modified and committed back to the source table. Its one thing Visual Basic does somewhat well & its quite useful.
On the other hand, the technique tends to hold database cursors open along with whatever locks the back end enforces, making concurrency a bit harder to manage. Its not a problem with trivial statements where the involvement of many tables and layers of queries is minimal, but when things get complicated its harder to manage.
I think a slightly better approach would provide two alternatives, first; a preformatted query might generate a list of object instances or sublists, one per output row with the query closed immediately after the fetch. The user can then fiddle with the data and just let it go as convienent and no database resources are locked. This could work for bulk updates too. Normal mapping semantics would probably be a good match with it. Lots of the client/server database API's have a basic interface like this & I think it would fit well with Lisp.
The 2nd approach would be a result-set approach, presumably slower, but allowing the client software to navigate the set and update it in a piecemeal fashion.
Both approaches could be performed in a transaction.
> >> This gives you > >> - higher speed, as you can just update the parameters in a loop. > >> - type safety, as the SQL interface can check what you've given it > >> - automatic quoting beyond what is posssible in the simple queries > >> (for example for BLOB's)
> > Yes, that looks pretty sensible... > Sensible? Using numeric parameter numbers looks pretty horrible to > me. Ever time someone modifies the query, all hell will break out.
I don't mind making "favorable gruntings" about something that's at least moving towards being better. It may not be the final answer, but it's a step towards "rightness," unlike:
(let ((query (concatenate 'string "select unique(" foo "," bar ") from " baz " where " foo " = '" "45" "';"))) (process-query query))
Not entirely incidentally, one of JDBC's query mechanisms is very much similar to the "query-parameter" approach.
Furthermore, I'd have _no_ problem with the notion of having something perhaps as ugly as QUERY-PARAMETER doing the work underneath, with a wrapper that Makes it Pretty on top... -- (concatenate 'string "cbbrowne" "@acm.org") http://www.ntlug.org/~cbbrowne/spreadsheets.html Rules of the Evil Overlord #160. "Before being accepted into my Legions of Terror, potential recruits will have to pass peripheral vision and hearing tests, and be able to recognize the sound of a pebble thrown to distract them." <http://www.eviloverlord.com/>
mike...@mikemac.com (Mike McDonald) writes: >>> (prepare-query "select unique(?,?) from ?, ? where ? = ?") >>> (setf (query-parameter 1) 'foo >>> (query-parameter 2) 'bar >>> (query-parameter 3) 'table-a >>> (query-parameter 4) 'table-b >>> (query-parameter 5) 'foo >>> (query-parameter 6) 45) >>> (execute-query) > Sensible? Using numeric parameter numbers looks pretty horrible to me. Ever > time someone modifies the query, all hell will break out.
It is. A more advanced library would use symbolic names. But most available interfaces (ODBC and JDBC it seems) only give you numeric indexes. Extending the prepare-query and setf-er to accept ?foo variables is pretty easy I guess. But I didn't think of it :-)
I just wanted to point out that concatenating a query string together is the road to hell.
Groetjes, Peter
-- It's logic Jim, but not as we know it. | pvane...@debian.org "God, root, what is difference?" - Pitr| "God is more forgiving." - Dave Aronson| http://cvs2.cons.org/~pvaneynd/
Greg Menke <gregm-n...@mindspring.com> writes: > On the other hand, the technique tends to hold database cursors open > along with whatever locks the back end enforces, making concurrency a > bit harder to manage. Its not a problem with trivial statements where > the involvement of many tables and layers of queries is minimal, but > when things get complicated its harder to manage.
Just a comment (but we are straying a bit far from c.l.l): I've noticed that most interfaces have limited or non-implemented roll-back/commit functionality. So it you want to do something more complex, IMHO it is better to use the DB's own 'language' (I cannot bring myself to call the only horror I sort-of-know: CY/FDY a language) to implement complex operation. Then just use the interface to call those procedures. If you manage to write those procedures automagicly from Lisp, you're made the world a better place :-)
<realism>At least this way you can send the DB-vendor bugreports using only their products, so they cannot point the finger at Lisp anymore</realism>
Groetjes, Peter
-- It's logic Jim, but not as we know it. | pvane...@debian.org "God, root, what is difference?" - Pitr| "God is more forgiving." - Dave Aronson| http://cvs2.cons.org/~pvaneynd/
> > Sensible? Using numeric parameter numbers looks pretty horrible to me. Ever > > time someone modifies the query, all hell will break out.
> It is. A more advanced library would use symbolic names. But most > available interfaces (ODBC and JDBC it seems) only give you numeric > indexes. Extending the prepare-query and setf-er to accept ?foo > variables is pretty easy I guess. But I didn't think of it :-)
> I just wanted to point out that concatenating a query string together > is the road to hell.
I suspect database access is pretty much coincident with the road to hell to begin with. The opposite end of the spectrum might be the Visual Basic "data object" regime where an object represents a table/query and a set of "field" objects are linked to it, which produce values for queries or accept them for update, essentially dispersing the structure of the query or update across a variety of objects. The string concat approach at least consolidates the query- which can be quite helpful.
Though I've not tried it yet, I think something like plob could be a better idea; it seems as if it is lots easier to fetch/update data with it. At least it looks possible to avoid the tedious & fragile query setup & execution of the traditional SQL database api's.