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