@@ -0,0 +1,753 @@
1+{-# LANGUAGE BangPatterns, DeriveDataTypeable, OverloadedStrings, DoAndIfThenElse, RecordWildCards, NamedFieldPuns #-}
2+
3+-- |
4+-- Module: Database.PostgreSQL.Simple
5+-- Copyright: (c) 2011 MailRank, Inc.
6+-- (c) 2011 Leon P Smith
7+-- License: BSD3
8+-- Maintainer: Leon P Smith <leon@melding-monads.com>
9+-- Stability: experimental
10+-- Portability: portable
11+--
12+-- A mid-level client library for the MySQL database, aimed at ease of
13+-- use and high performance.
14+
15+module Database.PostgreSQL.Simple
16+ (
17+ -- * Writing queries
18+ -- $use
19+
20+ -- ** The Query type
21+ -- $querytype
22+
23+ -- ** Parameter substitution
24+ -- $subst
25+
26+ -- *** Type inference
27+ -- $inference
28+
29+ -- ** Substituting a single parameter
30+ -- $only_param
31+
32+ -- ** Representing a list of values
33+ -- $in
34+
35+ -- ** Modifying multiple rows at once
36+ -- $many
37+
38+ -- * Extracting results
39+ -- $result
40+
41+ -- ** Handling null values
42+ -- $null
43+
44+ -- ** Type conversions
45+ -- $types
46+
47+ -- * Types
48+ Base.ConnectInfo(..)
49+ , Connection
50+ , Query
51+ , In(..)
52+ , Binary(..)
53+ , Only(..)
54+ -- ** Exceptions
55+ , FormatError(fmtMessage, fmtQuery, fmtParams)
56+ , QueryError(qeMessage, qeQuery)
57+ , ResultError(errSQLType, errHaskellType, errMessage)
58+ -- * Connection management
59+ , Base.connect
60+ , Base.connectPostgreSQL
61+ , Base.postgreSQLConnectionString
62+ , Base.defaultConnectInfo
63+ , Base.close
64+ -- * Queries that return results
65+ , query
66+ , query_
67+{--
68+ -- * Queries that stream results
69+ , fold
70+ , fold_
71+ , forEach
72+ , forEach_
73+--}
74+ -- * Statements that do not return results
75+ , execute
76+ , execute_
77+ , executeMany
78+-- , Base.insertID
79+ -- * Transaction handling
80+ , withTransaction
81+-- , Base.autocommit
82+ , begin
83+ , commit
84+ , rollback
85+ -- * Helper functions
86+ , formatMany
87+ , formatQuery
88+ ) where
89+
90+import Blaze.ByteString.Builder (Builder, fromByteString, toByteString)
91+import Blaze.ByteString.Builder.Char8 (fromChar)
92+import Control.Applicative ((<$>), pure)
93+import Control.Concurrent.MVar
94+import Control.Exception (Exception, bracket, onException, throw, throwIO)
95+import Control.Monad (forM)
96+import Control.Monad.Fix (fix)
97+import Data.ByteString (ByteString)
98+-- import qualified Data.ByteString as B (unpack)
99+import Data.Char(ord)
100+import Data.Int (Int64)
101+import qualified Data.IntMap as IntMap
102+import Data.List (intersperse)
103+import Data.Monoid (mappend, mconcat)
104+import Data.Typeable (Typeable)
105+--import Database.MySQL.Base (Connection, Result)
106+--import Database.MySQL.Base.Types (Field)
107+import Database.PostgreSQL.Simple.BuiltinTypes (oid2builtin, builtin2typname)
108+import Database.PostgreSQL.Simple.Param (Action(..), inQuotes)
109+import Database.PostgreSQL.Simple.QueryParams (QueryParams(..))
110+import Database.PostgreSQL.Simple.Result (ResultError(..))
111+import Database.PostgreSQL.Simple.QueryResults (QueryResults(..))
112+-- import Database.PostgreSQL.Simple.Result (ResultError(..))
113+import Database.PostgreSQL.Simple.Types (Binary(..), In(..), Only(..), Query(..))
114+import Database.PostgreSQL.Simple.Implementation as Base
115+import qualified Database.PostgreSQL.LibPQ as PQ
116+import Text.Regex.PCRE.Light (compile, caseless, match)
117+import qualified Data.ByteString.Char8 as B
118+--import qualified Database.MySQL.Base as Base
119+
120+-- | Exception thrown if a 'Query' could not be formatted correctly.
121+-- This may occur if the number of \'@?@\' characters in the query
122+-- string does not match the number of parameters provided.
123+data FormatError = FormatError {
124+ fmtMessage :: String
125+ , fmtQuery :: Query
126+ , fmtParams :: [ByteString]
127+ } deriving (Eq, Show, Typeable)
128+
129+instance Exception FormatError
130+
131+-- | Exception thrown if 'query' is used to perform an @INSERT@-like
132+-- operation, or 'execute' is used to perform a @SELECT@-like operation.
133+data QueryError = QueryError {
134+ qeMessage :: String
135+ , qeQuery :: Query
136+ } deriving (Eq, Show, Typeable)
137+
138+instance Exception QueryError
139+
140+-- | Format a query string.
141+--
142+-- This function is exposed to help with debugging and logging. Do not
143+-- use it to prepare queries for execution.
144+--
145+-- String parameters are escaped according to the character set in use
146+-- on the 'Connection'.
147+--
148+-- Throws 'FormatError' if the query string could not be formatted
149+-- correctly.
150+formatQuery :: QueryParams q => Connection -> Query -> q -> IO ByteString
151+formatQuery conn q@(Query template) qs
152+ | null xs && '?' `B.notElem` template = return template
153+ | otherwise = toByteString <$> buildQuery conn q template xs
154+ where xs = renderParams qs
155+
156+-- | Format a query string with a variable number of rows.
157+--
158+-- This function is exposed to help with debugging and logging. Do not
159+-- use it to prepare queries for execution.
160+--
161+-- The query string must contain exactly one substitution group,
162+-- identified by the SQL keyword \"@VALUES@\" (case insensitive)
163+-- followed by an \"@(@\" character, a series of one or more \"@?@\"
164+-- characters separated by commas, and a \"@)@\" character. White
165+-- space in a substitution group is permitted.
166+--
167+-- Throws 'FormatError' if the query string could not be formatted
168+-- correctly.
169+formatMany :: (QueryParams q) => Connection -> Query -> [q] -> IO ByteString
170+formatMany _ q [] = fmtError "no rows supplied" q []
171+formatMany conn q@(Query template) qs = do
172+ case match re template [] of
173+ Just [_,before,qbits,after] -> do
174+ bs <- mapM (buildQuery conn q qbits . renderParams) qs
175+ return . toByteString . mconcat $ fromByteString before :
176+ intersperse (fromChar ',') bs ++
177+ [fromByteString after]
178+ _ -> error "foo"
179+ where
180+ re = compile "^([^?]+\\bvalues\\s*)\
181+ \(\\(\\s*[?](?:\\s*,\\s*[?])*\\s*\\))\
182+ \([^?]*)$"
183+ [caseless]
184+
185+escapeStringConn conn s = withConnection conn $ \c -> do
186+ PQ.escapeStringConn c s
187+
188+buildQuery :: Connection -> Query -> ByteString -> [Action] -> IO Builder
189+buildQuery conn q template xs = zipParams (split template) <$> mapM sub xs
190+ where quote = inQuotes . fromByteString . maybe undefined id
191+ sub (Plain b) = pure b
192+ sub (Escape s) = quote <$> escapeStringConn conn s
193+ sub (Many ys) = mconcat <$> mapM sub ys
194+ split s = fromByteString h : if B.null t then [] else split (B.tail t)
195+ where (h,t) = B.break (=='?') s
196+ zipParams (t:ts) (p:ps) = t `mappend` p `mappend` zipParams ts ps
197+ zipParams [t] [] = t
198+ zipParams _ _ = fmtError (show (B.count '?' template) ++
199+ " '?' characters, but " ++
200+ show (length xs) ++ " parameters") q xs
201+
202+-- | Execute an @INSERT@, @UPDATE@, or other SQL query that is not
203+-- expected to return results.
204+--
205+-- Returns the number of rows affected.
206+--
207+-- Throws 'FormatError' if the query could not be formatted correctly.
208+execute :: (QueryParams q) => Connection -> Query -> q -> IO Int64
209+execute conn template qs = do
210+ result <- exec conn =<< formatQuery conn template qs
211+ finishExecute conn template result
212+
213+-- | A version of 'execute' that does not perform query substitution.
214+execute_ :: Connection -> Query -> IO Int64
215+execute_ conn q@(Query stmt) = do
216+ result <- exec conn stmt
217+ finishExecute conn q result
218+
219+-- | Execute a multi-row @INSERT@, @UPDATE@, or other SQL query that is not
220+-- expected to return results.
221+--
222+-- Returns the number of rows affected.
223+--
224+-- Throws 'FormatError' if the query could not be formatted correctly.
225+executeMany :: (QueryParams q) => Connection -> Query -> [q] -> IO Int64
226+executeMany _ _ [] = return 0
227+executeMany conn q qs = do
228+ result <- exec conn =<< formatMany conn q qs
229+ finishExecute conn q result
230+
231+finishExecute :: Connection -> Query -> PQ.Result -> IO Int64
232+finishExecute conn q result = do
233+ status <- PQ.resultStatus result
234+ case status of
235+ PQ.EmptyQuery -> fail "empty query" -- FIXME: error message
236+ PQ.CommandOk -> do
237+ ncols <- PQ.nfields result
238+ if ncols /= 0
239+ then throwIO $ QueryError ("execute resulted in " ++ show ncols ++
240+ "-column result") q
241+ else do
242+ nstr <- PQ.cmdTuples result
243+ return $ case nstr of
244+ Nothing -> 0 -- is this appropriate?
245+ Just str -> toInteger str
246+ PQ.TuplesOk -> do
247+ ncols <- PQ.nfields result
248+ throwIO $ QueryError ("execute resulted in " ++ show ncols ++
249+ "-column result") q
250+ PQ.CopyIn -> fail "FIXME: postgresql-simple does not currently support COPY IN"
251+ PQ.CopyOut -> fail "FIXME: postgresql-simple does not currently support COPY OUT"
252+ _ -> do
253+ errormsg <- maybe "" id <$> PQ.resultErrorMessage result
254+ statusmsg <- PQ.resStatus status
255+ state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
256+ throw $ SqlError { sqlState = state
257+ , sqlNativeError = 0 -- FIXME
258+ , sqlErrorMsg = B.concat [ "execute: ", statusmsg
259+ , ": ", errormsg ]}
260+ where
261+ toInteger str = B.foldl' delta 0 str
262+ where
263+ delta acc c =
264+ if '0' <= c && c <= '9'
265+ then 10 * acc + fromIntegral (ord c - ord '0')
266+ else error ("finishExecute: not an int: " ++ B.unpack str)
267+
268+
269+
270+-- | Perform a @SELECT@ or other SQL query that is expected to return
271+-- results. All results are retrieved and converted before this
272+-- function returns.
273+--
274+-- When processing large results, this function will consume a lot of
275+-- client-side memory. Consider using 'fold' instead.
276+--
277+-- Exceptions that may be thrown:
278+--
279+-- * 'FormatError': the query string could not be formatted correctly.
280+--
281+-- * 'QueryError': the result contains no columns (i.e. you should be
282+-- using 'execute' instead of 'query').
283+--
284+-- * 'ResultError': result conversion failed.
285+query :: (QueryParams q, QueryResults r)
286+ => Connection -> Query -> q -> IO [r]
287+query conn template qs = do
288+ result <- exec conn =<< formatQuery conn template qs
289+ finishQuery conn template result
290+
291+-- | A version of 'query' that does not perform query substitution.
292+query_ :: (QueryResults r) => Connection -> Query -> IO [r]
293+query_ conn q@(Query que) = do
294+ result <- exec conn que
295+ finishQuery conn q result
296+{--
297+-- | Perform a @SELECT@ or other SQL query that is expected to return
298+-- results. Results are streamed incrementally from the server, and
299+-- consumed via a left fold.
300+--
301+-- The result consumer must be carefully written to execute
302+-- quickly. If the consumer is slow, server resources will be tied up,
303+-- and other clients may not be able to update the tables from which
304+-- the results are being streamed.
305+--
306+-- When dealing with small results, it may be simpler (and perhaps
307+-- faster) to use 'query' instead.
308+--
309+-- This fold is /not/ strict. The stream consumer is responsible for
310+-- forcing the evaluation of its result to avoid space leaks.
311+--
312+-- Exceptions that may be thrown:
313+--
314+-- * 'FormatError': the query string could not be formatted correctly.
315+--
316+-- * 'QueryError': the result contains no columns (i.e. you should be
317+-- using 'execute' instead of 'query').
318+--
319+-- * 'ResultError': result conversion failed.
320+fold :: (QueryParams q, QueryResults r) =>
321+ Connection
322+ -> Query -- ^ Query template.
323+ -> q -- ^ Query parameters.
324+ -> a -- ^ Initial state for result consumer.
325+ -> (a -> r -> IO a) -- ^ Result consumer.
326+ -> IO a
327+fold conn template qs z f = do
328+ Base.query conn =<< formatQuery conn template qs
329+ finishFold conn template z f
330+--}
331+{--
332+-- | A version of 'fold' that does not perform query substitution.
333+fold_ :: (QueryResults r) =>
334+ Connection
335+ -> Query -- ^ Query.
336+ -> a -- ^ Initial state for result consumer.
337+ -> (a -> r -> IO a) -- ^ Result consumer.
338+ -> IO a
339+fold_ conn q@(Query que) z f = do
340+ Base.query conn que
341+ finishFold conn q z f
342+--}
343+{--
344+-- | A version of 'fold' that does not transform a state value.
345+forEach :: (QueryParams q, QueryResults r) =>
346+ Connection
347+ -> Query -- ^ Query template.
348+ -> q -- ^ Query parameters.
349+ -> (r -> IO ()) -- ^ Result consumer.
350+ -> IO ()
351+forEach conn template qs = fold conn template qs () . const
352+{-# INLINE forEach #-}
353+
354+-- | A version of 'forEach' that does not perform query substitution.
355+forEach_ :: (QueryResults r) =>
356+ Connection
357+ -> Query -- ^ Query template.
358+ -> (r -> IO ()) -- ^ Result consumer.
359+ -> IO ()
360+forEach_ conn template = fold_ conn template () . const
361+{-# INLINE forEach_ #-}
362+--}
363+
364+forM' :: (Ord n, Num n) => n -> n -> (n -> IO a) -> IO [a]
365+forM' lo hi m = loop hi []
366+ where
367+ loop !n !as
368+ | n < lo = return as
369+ | otherwise = do
370+ a <- m n
371+ loop (n-1) (a:as)
372+
373+finishQuery :: (QueryResults r) => Connection -> Query -> PQ.Result -> IO [r]
374+finishQuery conn q result = do
375+ status <- PQ.resultStatus result
376+ case status of
377+ PQ.EmptyQuery -> fail "empty query" -- FIXME: error message
378+ PQ.CommandOk -> do
379+ throwIO $ QueryError "query resulted in a command response" q
380+ PQ.TuplesOk -> do
381+ ncols <- PQ.nfields result
382+ fields <- forM' 0 (ncols-1) $ \column -> do
383+ type_oid <- PQ.ftype result column
384+ typename <- getTypename conn type_oid
385+ return Field{..}
386+ nrows <- PQ.ntuples result
387+ forM' 0 (nrows-1) $ \row -> do
388+ values <- forM' 0 (ncols-1) (\col -> PQ.getvalue' result row col)
389+ case convertResults fields values of
390+ Fail err -> throwIO err
391+ Success a -> return a
392+ PQ.CopyIn -> fail "FIXME: postgresql-simple does not currently support COPY IN"
393+ PQ.CopyOut -> fail "FIXME: postgresql-simple does not currently support COPY OUT"
394+ _ -> do
395+ errormsg <- maybe "" id <$> PQ.resultErrorMessage result
396+ statusmsg <- PQ.resStatus status
397+ state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
398+ throw $ SqlError { sqlState = state
399+ , sqlNativeError = 0 -- FIXME
400+ , sqlErrorMsg = B.concat [ "execute: ", statusmsg
401+ , ": ", errormsg ]}
402+
403+{--
404+withResult (Base.storeResult conn) q $ \r fs -> do
405+ status <-
406+/ flip fix [] $ \loop acc -> do
407+ row <- Base.fetchRow r
408+ case row of
409+ [] -> return (reverse acc)
410+ _ -> let !c = convertResults fs row
411+ in loop (c:acc)
412+--}
413+{--
414+finishFold :: (QueryResults r) =>
415+ Connection -> Query -> a -> (a -> r -> IO a) -> IO a
416+finishFold conn q z0 f = withResult (Base.useResult conn) q $ \r fs ->
417+ flip fix z0 $ \loop z -> do
418+ row <- Base.fetchRow r
419+ case row of
420+ [] -> return z
421+ _ -> (f z $! convertResults fs row) >>= loop
422+--}
423+{--
424+withResult :: (IO Result) -> Query -> (Result -> [Field] -> IO a) -> IO a
425+withResult fetchResult q act = bracket fetchResult Base.freeResult $ \r -> do
426+ ncols <- Base.fieldCount (Right r)
427+ if ncols == 0
428+ then throwIO $ QueryError "query resulted in zero-column result" q
429+ else act r =<< Base.fetchFields r
430+--}
431+-- | Execute an action inside a SQL transaction.
432+--
433+-- This function initiates a transaction with a \"@begin
434+-- transaction@\" statement, then executes the supplied action. If
435+-- the action succeeds, the transaction will be completed with
436+-- 'Base.commit' before this function returns.
437+--
438+-- If the action throws /any/ kind of exception (not just a
439+-- MySQL-related exception), the transaction will be rolled back using
440+-- 'Base.rollback', then the exception will be rethrown.
441+withTransaction :: Connection -> IO a -> IO a
442+withTransaction conn act = do
443+ _ <- begin conn
444+ r <- act `onException` rollback conn
445+ commit conn
446+ return r
447+
448+-- | Rollback a transaction.
449+-- rollback :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
450+rollback :: Connection -> IO ()
451+rollback conn = do
452+ _ <- execute_ conn "ABORT;"
453+ return ()
454+
455+-- | Commit a transaction.
456+-- commit :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
457+commit :: Connection -> IO ()
458+commit conn = do
459+ _ <- execute_ conn "COMMIT;"
460+ return ()
461+
462+-- | Begin a transaction.
463+-- begin :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
464+begin :: Connection -> IO ()
465+begin conn = do
466+ _ <- execute_ conn "BEGIN;"
467+ return ()
468+
469+fmtError :: String -> Query -> [Action] -> a
470+fmtError msg q xs = throw FormatError {
471+ fmtMessage = msg
472+ , fmtQuery = q
473+ , fmtParams = map twiddle xs
474+ }
475+ where twiddle (Plain b) = toByteString b
476+ twiddle (Escape s) = s
477+ twiddle (Many ys) = B.concat (map twiddle ys)
478+
479+-- $use
480+--
481+-- SQL-based applications are somewhat notorious for their
482+-- susceptibility to attacks through the injection of maliciously
483+-- crafted data. The primary reason for widespread vulnerability to
484+-- SQL injections is that many applications are sloppy in handling
485+-- user data when constructing SQL queries.
486+--
487+-- This library provides a 'Query' type and a parameter substitution
488+-- facility to address both ease of use and security.
489+
490+-- $querytype
491+--
492+-- A 'Query' is a @newtype@-wrapped 'ByteString'. It intentionally
493+-- exposes a tiny API that is not compatible with the 'ByteString'
494+-- API; this makes it difficult to construct queries from fragments of
495+-- strings. The 'query' and 'execute' functions require queries to be
496+-- of type 'Query'.
497+--
498+-- To most easily construct a query, enable GHC's @OverloadedStrings@
499+-- language extension and write your query as a normal literal string.
500+--
501+-- > {-# LANGUAGE OverloadedStrings #-}
502+-- >
503+-- > import Database.MySQL.Simple
504+-- >
505+-- > hello = do
506+-- > conn <- connect defaultConnectInfo
507+-- > query conn "select 2 + 2"
508+--
509+-- A 'Query' value does not represent the actual query that will be
510+-- executed, but is a template for constructing the final query.
511+
512+-- $subst
513+--
514+-- Since applications need to be able to construct queries with
515+-- parameters that change, this library provides a query substitution
516+-- capability.
517+--
518+-- The 'Query' template accepted by 'query' and 'execute' can contain
519+-- any number of \"@?@\" characters. Both 'query' and 'execute'
520+-- accept a third argument, typically a tuple. When constructing the
521+-- real query to execute, these functions replace the first \"@?@\" in
522+-- the template with the first element of the tuple, the second
523+-- \"@?@\" with the second element, and so on. If necessary, each
524+-- tuple element will be quoted and escaped prior to substitution;
525+-- this defeats the single most common injection vector for malicious
526+-- data.
527+--
528+-- For example, given the following 'Query' template:
529+--
530+-- > select * from user where first_name = ? and age > ?
531+--
532+-- And a tuple of this form:
533+--
534+-- > ("Boris" :: String, 37 :: Int)
535+--
536+-- The query to be executed will look like this after substitution:
537+--
538+-- > select * from user where first_name = 'Boris' and age > 37
539+--
540+-- If there is a mismatch between the number of \"@?@\" characters in
541+-- your template and the number of elements in your tuple, a
542+-- 'FormatError' will be thrown.
543+--
544+-- Note that the substitution functions do not attempt to parse or
545+-- validate your query. It's up to you to write syntactically valid
546+-- SQL, and to ensure that each \"@?@\" in your query template is
547+-- matched with the right tuple element.
548+
549+-- $inference
550+--
551+-- Automated type inference means that you will often be able to avoid
552+-- supplying explicit type signatures for the elements of a tuple.
553+-- However, sometimes the compiler will not be able to infer your
554+-- types. Consider a care where you write a numeric literal in a
555+-- parameter tuple:
556+--
557+-- > query conn "select ? + ?" (40,2)
558+--
559+-- The above query will be rejected by the compiler, because it does
560+-- not know the specific numeric types of the literals @40@ and @2@.
561+-- This is easily fixed:
562+--
563+-- > query conn "select ? + ?" (40 :: Double, 2 :: Double)
564+--
565+-- The same kind of problem can arise with string literals if you have
566+-- the @OverloadedStrings@ language extension enabled. Again, just
567+-- use an explicit type signature if this happens.
568+
569+-- $only_param
570+--
571+-- Haskell lacks a single-element tuple type, so if you have just one
572+-- value you want substituted into a query, what should you do?
573+--
574+-- The obvious approach would appear to be something like this:
575+--
576+-- > instance (Param a) => QueryParam a where
577+-- > ...
578+--
579+-- Unfortunately, this wreaks havoc with type inference, so we take a
580+-- different tack. To represent a single value @val@ as a parameter, write
581+-- a singleton list @[val]@, use 'Just' @val@, or use 'Only' @val@.
582+--
583+-- Here's an example using a singleton list:
584+--
585+-- > execute conn "insert into users (first_name) values (?)"
586+-- > ["Nuala"]
587+
588+-- $in
589+--
590+-- Suppose you want to write a query using an @IN@ clause:
591+--
592+-- > select * from users where first_name in ('Anna', 'Boris', 'Carla')
593+--
594+-- In such cases, it's common for both the elements and length of the
595+-- list after the @IN@ keyword to vary from query to query.
596+--
597+-- To address this case, use the 'In' type wrapper, and use a single
598+-- \"@?@\" character to represent the list. Omit the parentheses
599+-- around the list; these will be added for you.
600+--
601+-- Here's an example:
602+--
603+-- > query conn "select * from users where first_name in ?" $
604+-- > In ["Anna", "Boris", "Carla"]
605+--
606+-- If your 'In'-wrapped list is empty, the string @\"(null)\"@ will be
607+-- substituted instead, to ensure that your clause remains
608+-- syntactically valid.
609+
610+-- $many
611+--
612+-- If you know that you have many rows of data to insert into a table,
613+-- it is much more efficient to perform all the insertions in a single
614+-- multi-row @INSERT@ statement than individually.
615+--
616+-- The 'executeMany' function is intended specifically for helping
617+-- with multi-row @INSERT@ and @UPDATE@ statements. Its rules for
618+-- query substitution are different than those for 'execute'.
619+--
620+-- What 'executeMany' searches for in your 'Query' template is a
621+-- single substring of the form:
622+--
623+-- > values (?,?,?)
624+--
625+-- The rules are as follows:
626+--
627+-- * The keyword @VALUES@ is matched case insensitively.
628+--
629+-- * There must be no other \"@?@\" characters anywhere in your
630+-- template.
631+--
632+-- * There must one or more \"@?@\" in the parentheses.
633+--
634+-- * Extra white space is fine.
635+--
636+-- The last argument to 'executeMany' is a list of parameter
637+-- tuples. These will be substituted into the query where the @(?,?)@
638+-- string appears, in a form suitable for use in a multi-row @INSERT@
639+-- or @UPDATE@.
640+--
641+-- Here is an example:
642+--
643+-- > executeMany conn
644+-- > "insert into users (first_name,last_name) values (?,?)"
645+-- > [("Boris","Karloff"),("Ed","Wood")]
646+--
647+-- The query that will be executed here will look like this
648+-- (reformatted for tidiness):
649+--
650+-- > insert into users (first_name,last_name) values
651+-- > ('Boris','Karloff'),('Ed','Wood')
652+
653+-- $result
654+--
655+-- The 'query' and 'query_' functions return a list of values in the
656+-- 'QueryResults' typeclass. This class performs automatic extraction
657+-- and type conversion of rows from a query result.
658+--
659+-- Here is a simple example of how to extract results:
660+--
661+-- > import qualified Data.Text as Text
662+-- >
663+-- > xs <- query_ conn "select name,age from users"
664+-- > forM_ xs $ \(name,age) ->
665+-- > putStrLn $ Text.unpack name ++ " is " ++ show (age :: Int)
666+--
667+-- Notice two important details about this code:
668+--
669+-- * The number of columns we ask for in the query template must
670+-- exactly match the number of elements we specify in a row of the
671+-- result tuple. If they do not match, a 'ResultError' exception
672+-- will be thrown.
673+--
674+-- * Sometimes, the compiler needs our help in specifying types. It
675+-- can infer that @name@ must be a 'Text', due to our use of the
676+-- @unpack@ function. However, we have to tell it the type of @age@,
677+-- as it has no other information to determine the exact type.
678+
679+-- $null
680+--
681+-- The type of a result tuple will look something like this:
682+--
683+-- > (Text, Int, Int)
684+--
685+-- Although SQL can accommodate @NULL@ as a value for any of these
686+-- types, Haskell cannot. If your result contains columns that may be
687+-- @NULL@, be sure that you use 'Maybe' in those positions of of your
688+-- tuple.
689+--
690+-- > (Text, Maybe Int, Int)
691+--
692+-- If 'query' encounters a @NULL@ in a row where the corresponding
693+-- Haskell type is not 'Maybe', it will throw a 'ResultError'
694+-- exception.
695+
696+-- $only_result
697+--
698+-- To specify that a query returns a single-column result, use the
699+-- 'Only' type.
700+--
701+-- > xs <- query_ conn "select id from users"
702+-- > forM_ xs $ \(Only dbid) -> {- ... -}
703+
704+-- $types
705+--
706+-- Conversion of SQL values to Haskell values is somewhat
707+-- permissive. Here are the rules.
708+--
709+-- * For numeric types, any Haskell type that can accurately represent
710+-- all values of the given MySQL type is considered \"compatible\".
711+-- For instance, you can always extract a MySQL @TINYINT@ column to
712+-- a Haskell 'Int'. The Haskell 'Float' type can accurately
713+-- represent MySQL integer types of size up to @INT24@, so it is
714+-- considered compatble with those types.
715+--
716+-- * A numeric compatibility check is based only on the type of a
717+-- column, /not/ on its values. For instance, a MySQL @LONG_LONG@
718+-- column will be considered incompatible with a Haskell 'Int8',
719+-- even if it contains the value @1@.
720+--
721+-- * If a numeric incompatibility is found, 'query' will throw a
722+-- 'ResultError'.
723+--
724+-- * The 'String' and 'Text' types are assumed to be encoded as
725+-- UTF-8. If you use some other encoding, decoding may fail or give
726+-- wrong results. In such cases, write a @newtype@ wrapper and a
727+-- custom 'Result' instance to handle your encoding.
728+
729+getTypename :: Connection -> PQ.Oid -> IO ByteString
730+getTypename conn@Connection{..} oid =
731+ case oid2builtin oid of
732+ Just builtin -> return $! builtin2typname builtin
733+ Nothing -> do
734+ oidmap <- takeMVar connectionObjects
735+ case IntMap.lookup (oid2int oid) oidmap of
736+ Just name -> putMVar connectionObjects oidmap >> return name
737+ Nothing -> do
738+ names <- query conn "SELECT typname FROM pg_type WHERE oid=?"
739+ (Only oid)
740+ name <- case names of
741+ [] -> return $ throw SqlError {
742+ sqlNativeError = -1,
743+ sqlErrorMsg = "invalid type oid",
744+ sqlState = ""
745+ }
746+ [Only x] -> return x
747+ _ -> fail "typename query returned more than one result"
748+ -- oid is a primary key, so the query should
749+ -- never return more than one result
750+ putMVar connectionObjects (IntMap.insert (oid2int oid) name oidmap)
751+ return name
752+ `onException` do
753+ putMVar connectionObjects oidmap