
On Mon, Oct 09, 2006 at 04:01:02PM -0600, Tim Smith wrote:
main = do dbh <- connectODBC "DSN=test" res <- DB.getTables dbh -- print (show ((concat . intersperse ", ") res)) DB.disconnect dbh print (show ((concat . intersperse ", ") res))
Am I just expecting the wrong thing from Haskell? Is there a
Yes. Remember the Haskell mantra: no computation is performed before its result is demanded. Since you are not demanding the list of tables until the print statement, the code to get the list of tables is not executed until then. Actually, follow that logic through. Think about when the connection to the database is established. If I understand things properly, it won't happen until your call to disconnect, since nothing demands the handle until then. Note that this is normally not the case, since the first use of it will demand that the connection happens. I think the easiest way around this is to add this line after the call to getTables: return $ seq res res though you may also be able to say: evaluate res (provided you have imported Control.Exception) But the very best way is to simply not disconnect until after you've printed.
technical reason why HDBC can't synchronize the IO so that everything is resolved before the disconnect? Or is this a bug in HDBC?
It's a Feature of Haskell, not a bug. This is the same feature that lets you process infinite lists, treat multi-GB files as strings, and, in fact, treat multi-GB SQL result sets as simple lists. Haskell only loads each line of the file, or row of result, into RAM when it is demanded. (Note that some databases are less lazy than Haskell in this respect, so this only works if your database API can return partial results!) I have tried to put warnings into the HDBC docs where I think people are particularly likely to run afoul of this -- quickQuery springs to mind. Note that the API docs for getTables, at http://darcs.complete.org/hdbc/doc/Database-HDBC.html#v%3AgetTables mention that the data is returned in the same manner as fetchAllRows. Click on the link to fetchAllRows and you see: Lazily fetch all rows from an executed Statement. You can think of this as hGetContents applied to a database result set. The result of this is a lazy list, and each new row will be read, lazily, from the database as the list is processed. When you have exhausted the list, the Statement will be finished. Please note that the careless use of this function can lead to some unpleasant behavior. In particular, if you have not consumed the entire list, then attempt to finish or re-execute the statement, and then attempt to consume more elements from the list, the result will almost certainly not be what you want. But then, similar caveats apply with hGetContents. Bottom line: this is a very convenient abstraction; use it wisely. -- John