git.iko.soy/typeable/postgresql-simple
on 51e1dfc help sign in
890 lines 33 kB history raw
1{-# LANGUAGE DeriveDataTypeable, 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 , FoldOptions(..)
73 , FetchQuantity(..)
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 , TransactionMode(..)
89 , IsolationLevel(..)
90 , ReadWriteMode(..)
91 , defaultTransactionMode
92 , defaultIsolationLevel
93 , defaultReadWriteMode
94 , withTransactionLevel
95 , withTransactionMode
96-- , Base.autocommit
97 , begin
98 , beginLevel
99 , beginMode
100 , commit
101 , rollback
102 -- * Helper functions
103 , formatMany
104 , formatQuery
105 ) where
107import Blaze.ByteString.Builder
108 ( Builder, fromByteString, toByteString )
109import Blaze.ByteString.Builder.Char8 (fromChar)
110import Control.Applicative ((<$>), pure)
111import Control.Concurrent.MVar
112import Control.Exception
113 ( Exception, bracket, onException, throw, throwIO, finally )
114import Control.Monad (foldM)
115import Control.Monad.Fix (fix)
116import Data.ByteString (ByteString)
117import Data.Char(ord)
118import Data.Int (Int64)
119import qualified Data.IntMap as IntMap
120import Data.List (intersperse)
121import Data.Monoid (mappend, mconcat)
122import Data.Typeable (Typeable)
123import Database.PostgreSQL.Simple.BuiltinTypes
124 ( oid2builtin, builtin2typname )
125import Database.PostgreSQL.Simple.FromField (ResultError(..))
126import Database.PostgreSQL.Simple.FromRow (FromRow(..))
127import Database.PostgreSQL.Simple.Ok
128import Database.PostgreSQL.Simple.Param (Action(..), inQuotes)
129import Database.PostgreSQL.Simple.QueryParams (QueryParams(..))
130import Database.PostgreSQL.Simple.Types
131 ( Binary(..), In(..), Only(..), Query(..) )
132import Database.PostgreSQL.Simple.Internal as Base
133import qualified Database.PostgreSQL.LibPQ as PQ
134import Text.Regex.PCRE.Light (compile, caseless, match)
135import qualified Data.ByteString.Char8 as B
136import qualified Data.Vector as V
137import Control.Exception
138import Control.Monad.Trans.Reader
139import Control.Monad.Trans.State.Strict
141-- | Exception thrown if a 'Query' could not be formatted correctly.
142-- This may occur if the number of \'@?@\' characters in the query
143-- string does not match the number of parameters provided.
144data FormatError = FormatError {
145 fmtMessage :: String
146 , fmtQuery :: Query
147 , fmtParams :: [ByteString]
148 } deriving (Eq, Show, Typeable)
150instance Exception FormatError
152-- | Exception thrown if 'query' is used to perform an @INSERT@-like
153-- operation, or 'execute' is used to perform a @SELECT@-like operation.
154data QueryError = QueryError {
155 qeMessage :: String
156 , qeQuery :: Query
157 } deriving (Eq, Show, Typeable)
159instance Exception QueryError
161-- | Format a query string.
162--
163-- This function is exposed to help with debugging and logging. Do not
164-- use it to prepare queries for execution.
165--
166-- String parameters are escaped according to the character set in use
167-- on the 'Connection'.
168--
169-- Throws 'FormatError' if the query string could not be formatted
170-- correctly.
171formatQuery :: QueryParams q => Connection -> Query -> q -> IO ByteString
172formatQuery conn q@(Query template) qs
173 | null xs && '?' `B.notElem` template = return template
174 | otherwise = toByteString <$> buildQuery conn q template xs
175 where xs = renderParams qs
177-- | Format a query string with a variable number of rows.
178--
179-- This function is exposed to help with debugging and logging. Do not
180-- use it to prepare queries for execution.
181--
182-- The query string must contain exactly one substitution group,
183-- identified by the SQL keyword \"@VALUES@\" (case insensitive)
184-- followed by an \"@(@\" character, a series of one or more \"@?@\"
185-- characters separated by commas, and a \"@)@\" character. White
186-- space in a substitution group is permitted.
187--
188-- Throws 'FormatError' if the query string could not be formatted
189-- correctly.
190formatMany :: (QueryParams q) => Connection -> Query -> [q] -> IO ByteString
191formatMany _ q [] = fmtError "no rows supplied" q []
192formatMany conn q@(Query template) qs = do
193 case match re template [] of
194 Just [_,before,qbits,after] -> do
195 bs <- mapM (buildQuery conn q qbits . renderParams) qs
196 return . toByteString . mconcat $ fromByteString before :
197 intersperse (fromChar ',') bs ++
198 [fromByteString after]
199 _ -> error "foo"
200 where
201 re = compile "^([^?]+\\bvalues\\s*)\
202 \(\\(\\s*[?](?:\\s*,\\s*[?])*\\s*\\))\
203 \([^?]*)$"
204 [caseless]
206escapeStringConn conn s = withConnection conn $ \c -> do
207 PQ.escapeStringConn c s
209buildQuery :: Connection -> Query -> ByteString -> [Action] -> IO Builder
210buildQuery conn q template xs = zipParams (split template) <$> mapM sub xs
211 where quote = inQuotes . fromByteString . maybe undefined id
212 sub (Plain b) = pure b
213 sub (Escape s) = quote <$> escapeStringConn conn s
214 sub (Many ys) = mconcat <$> mapM sub ys
215 split s = fromByteString h : if B.null t then [] else split (B.tail t)
216 where (h,t) = B.break (=='?') s
217 zipParams (t:ts) (p:ps) = t `mappend` p `mappend` zipParams ts ps
218 zipParams [t] [] = t
219 zipParams _ _ = fmtError (show (B.count '?' template) ++
220 " '?' characters, but " ++
221 show (length xs) ++ " parameters") q xs
223-- | Execute an @INSERT@, @UPDATE@, or other SQL query that is not
224-- expected to return results.
225--
226-- Returns the number of rows affected.
227--
228-- Throws 'FormatError' if the query could not be formatted correctly.
229execute :: (QueryParams q) => Connection -> Query -> q -> IO Int64
230execute conn template qs = do
231 result <- exec conn =<< formatQuery conn template qs
232 finishExecute conn template result
234-- | A version of 'execute' that does not perform query substitution.
235execute_ :: Connection -> Query -> IO Int64
236execute_ conn q@(Query stmt) = do
237 result <- exec conn stmt
238 finishExecute conn q result
240-- | Execute a multi-row @INSERT@, @UPDATE@, or other SQL query that is not
241-- expected to return results.
242--
243-- Returns the number of rows affected.
244--
245-- Throws 'FormatError' if the query could not be formatted correctly.
246executeMany :: (QueryParams q) => Connection -> Query -> [q] -> IO Int64
247executeMany _ _ [] = return 0
248executeMany conn q qs = do
249 result <- exec conn =<< formatMany conn q qs
250 finishExecute conn q result
252finishExecute :: Connection -> Query -> PQ.Result -> IO Int64
253finishExecute conn q result = do
254 status <- PQ.resultStatus result
255 case status of
256 PQ.CommandOk -> do
257 ncols <- PQ.nfields result
258 if ncols /= 0
259 then throwIO $ QueryError ("execute resulted in " ++ show ncols ++
260 "-column result") q
261 else do
262 nstr <- PQ.cmdTuples result
263 return $ case nstr of
264 Nothing -> 0 -- is this appropriate?
265 Just str -> toInteger str
266 PQ.TuplesOk -> do
267 ncols <- PQ.nfields result
268 throwIO $ QueryError ("execute resulted in " ++ show ncols ++
269 "-column result") q
270 PQ.CopyIn -> fail "FIXME: postgresql-simple does not currently support COPY IN"
271 PQ.CopyOut -> fail "FIXME: postgresql-simple does not currently support COPY OUT"
272 _ -> do
273 errormsg <- maybe "" id <$> PQ.resultErrorMessage result
274 statusmsg <- PQ.resStatus status
275 state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
276 throwIO $ SqlError { sqlState = state
277 , sqlNativeError = fromEnum status
278 , sqlErrorMsg = B.concat [ "execute: ", statusmsg
279 , ": ", errormsg ]}
280 where
281 toInteger str = B.foldl' delta 0 str
282 where
283 delta acc c =
284 if '0' <= c && c <= '9'
285 then 10 * acc + fromIntegral (ord c - ord '0')
286 else error ("finishExecute: not an int: " ++ B.unpack str)
290-- | Perform a @SELECT@ or other SQL query that is expected to return
291-- results. All results are retrieved and converted before this
292-- function returns.
293--
294-- When processing large results, this function will consume a lot of
295-- client-side memory. Consider using 'fold' instead.
296--
297-- Exceptions that may be thrown:
298--
299-- * 'FormatError': the query string could not be formatted correctly.
300--
301-- * 'QueryError': the result contains no columns (i.e. you should be
302-- using 'execute' instead of 'query').
303--
304-- * 'ResultError': result conversion failed.
305query :: (QueryParams q, FromRow r)
306 => Connection -> Query -> q -> IO [r]
307query conn template qs = do
308 result <- exec conn =<< formatQuery conn template qs
309 finishQuery conn template result
311-- | A version of 'query' that does not perform query substitution.
312query_ :: (FromRow r) => Connection -> Query -> IO [r]
313query_ conn q@(Query que) = do
314 result <- exec conn que
315 finishQuery conn q result
317-- | Perform a @SELECT@ or other SQL query that is expected to return
318-- results. Results are streamed incrementally from the server, and
319-- consumed via a left fold.
320--
321-- When dealing with small results, it may be simpler (and perhaps
322-- faster) to use 'query' instead.
323--
324-- This fold is /not/ strict. The stream consumer is responsible for
325-- forcing the evaluation of its result to avoid space leaks.
326--
327-- Exceptions that may be thrown:
328--
329-- * 'FormatError': the query string could not be formatted correctly.
330--
331-- * 'QueryError': the result contains no columns (i.e. you should be
332-- using 'execute' instead of 'query').
333--
334-- * 'ResultError': result conversion failed.
336fold :: ( FromRow row, QueryParams params )
337 => Connection
338 -> Query
339 -> params
340 -> a
341 -> (a -> row -> IO a)
342 -> IO a
343fold = foldWithOptions defaultFoldOptions
345data FetchQuantity
346 = Automatic
347 | Fixed !Int
349data FoldOptions
350 = FoldOptions {
351 fetchQuantity :: !FetchQuantity,
352 transactionMode :: !TransactionMode
353 }
355defaultFoldOptions = FoldOptions {
356 fetchQuantity = Automatic,
357 transactionMode = TransactionMode ReadCommitted ReadOnly
358 }
360foldWithOptions :: ( FromRow row, QueryParams params )
361 => FoldOptions
362 -> Connection
363 -> Query
364 -> params
365 -> a
366 -> (a -> row -> IO a)
367 -> IO a
368foldWithOptions opts conn template qs a f = do
369 q <- formatQuery conn template qs
370 doFold opts conn template (Query q) a f
372-- | A version of 'fold' that does not perform query substitution.
373fold_ :: (FromRow r) =>
374 Connection
375 -> Query -- ^ Query.
376 -> a -- ^ Initial state for result consumer.
377 -> (a -> r -> IO a) -- ^ Result consumer.
378 -> IO a
379fold_ = foldWithOptions_ defaultFoldOptions
382foldWithOptions_ :: (FromRow r) =>
383 FoldOptions
384 -> Connection
385 -> Query -- ^ Query.
386 -> a -- ^ Initial state for result consumer.
387 -> (a -> r -> IO a) -- ^ Result consumer.
388 -> IO a
389foldWithOptions_ opts conn query a f = doFold opts conn query query a f
392doFold :: ( FromRow row )
393 => FoldOptions
394 -> Connection
395 -> Query
396 -> Query
397 -> a
398 -> (a -> row -> IO a)
399 -> IO a
400doFold FoldOptions{..} conn _template q a f = do
401 stat <- withConnection conn PQ.transactionStatus
402 case stat of
403 PQ.TransIdle -> withTransactionMode transactionMode conn go
404 PQ.TransInTrans -> go
405 PQ.TransActive -> fail "foldWithOpts FIXME: PQ.TransActive"
406 -- This _shouldn't_ occur in the current incarnation of
407 -- the library, as we aren't using libpq asynchronously.
408 -- However, it could occur in future incarnations of
409 -- this library or if client code uses the Internal module
410 -- to use raw libpq commands on postgresql-simple connections.
411 PQ.TransInError -> fail "foldWithOpts FIXME: PQ.TransInError"
412 -- This should be turned into a better error message.
413 -- It is probably a bad idea to automatically roll
414 -- back the transaction and start another.
415 PQ.TransUnknown -> fail "foldWithOpts FIXME: PQ.TransUnknown"
416 -- Not sure what this means.
417 where
418 go = do
419 -- FIXME: what about name clashes with already-declared cursors?
420 _ <- execute_ conn ("DECLARE fold NO SCROLL CURSOR FOR "
421 `mappend` q)
422 loop a `finally` execute_ conn "CLOSE fold"
424-- FIXME: choose the Automatic chunkSize more intelligently
425-- One possibility is to use the type of the results, although this
426-- still isn't a perfect solution, given that common types (e.g. text)
427-- are of highly variable size.
428-- A refinement of this technique is to pick this number adaptively
429-- as results are read in from the database.
430 chunkSize = case fetchQuantity of
431 Automatic -> 256
432 Fixed n -> n
433 loop a = do
434 rs <- query conn "FETCH FORWARD ? FROM fold" (Only chunkSize)
435 if null rs then return a else foldM f a rs >>= loop
437-- | A version of 'fold' that does not transform a state value.
438forEach :: (QueryParams q, FromRow r) =>
439 Connection
440 -> Query -- ^ Query template.
441 -> q -- ^ Query parameters.
442 -> (r -> IO ()) -- ^ Result consumer.
443 -> IO ()
444forEach conn template qs = fold conn template qs () . const
445{-# INLINE forEach #-}
447-- | A version of 'forEach' that does not perform query substitution.
448forEach_ :: (FromRow r) =>
449 Connection
450 -> Query -- ^ Query template.
451 -> (r -> IO ()) -- ^ Result consumer.
452 -> IO ()
453forEach_ conn template = fold_ conn template () . const
454{-# INLINE forEach_ #-}
456forM' :: (Ord n, Num n) => n -> n -> (n -> IO a) -> IO [a]
457forM' lo hi m = loop hi []
458 where
459 loop !n !as
460 | n < lo = return as
461 | otherwise = do
462 a <- m n
463 loop (n-1) (a:as)
465finishQuery :: (FromRow r) => Connection -> Query -> PQ.Result -> IO [r]
466finishQuery conn q result = do
467 status <- PQ.resultStatus result
468 case status of
469 PQ.CommandOk -> do
470 throwIO $ QueryError "query resulted in a command response" q
471 PQ.TuplesOk -> do
472 ncols <- PQ.nfields result
473 let unCol (PQ.Col x) = fromIntegral x
474 typenames <- V.generateM (unCol ncols)
475 (\(PQ.Col . fromIntegral -> col) -> do
476 getTypename conn =<< PQ.ftype result col)
477 nrows <- PQ.ntuples result
478 ncols <- PQ.nfields result
479 forM' 0 (nrows-1) $ \row -> do
480 let rw = Row row typenames result
481 case runStateT (runReaderT (unRP fromRow) rw) 0 of
482 Ok (val,col) | col == ncols -> return val
483 | otherwise -> do
484 vals <- forM' 0 (ncols-1) $ \c -> do
485 v <- PQ.getvalue result row c
486 return ( typenames V.! unCol c
487 , fmap ellipsis v )
488 throw (ConversionFailed
489 (show (unCol ncols) ++ " values: " ++ show vals)
490 (show (unCol col) ++ " slots in target type")
491 "mismatch between number of columns to \
492 \convert and number in target type")
493 Errors [] -> throwIO $ ConversionFailed "" "" "unknown error"
494 Errors [x] -> throwIO x
495 Errors xs -> throwIO $ ManyErrors xs
497ellipsis :: ByteString -> ByteString
498ellipsis bs
499 | B.length bs > 15 = B.take 10 bs `B.append` "[...]"
500 | otherwise = bs
502-- | Throw a 'ConversionFailed' exception, indicating a mismatch
503-- between the number of columns in the 'Field' and row, and the
504-- number in the collection to be converted to.
505convertError :: [Field]
506 -- ^ Descriptors of fields to be converted.
507 -> [Maybe ByteString]
508 -- ^ Contents of the row to be converted.
509 -> Int
510 -- ^ Number of columns expected for conversion. For
511 -- instance, if converting to a 3-tuple, the number to
512 -- provide here would be 3.
513 -> Either SomeException a
514convertError fs vs n = Left . SomeException $ ConversionFailed
515 (show (length fs) ++ " values: " ++ show (zip (map typename fs)
516 (map (fmap ellipsis) vs)))
517 (show n ++ " slots in target type")
518 "mismatch between number of columns to convert and number in target type"
521-- | Of the four isolation levels defined by the SQL standard,
522-- these are the three levels distinguished by PostgreSQL as of version 9.0.
523-- See <http://www.postgresql.org/docs/9.1/static/transaction-iso.html>
524-- for more information.
526data IsolationLevel
527 = ReadCommitted
528 | RepeatableRead
529 | Serializable
530 deriving (Show, Eq, Ord, Enum, Bounded)
532data ReadWriteMode
533 = ReadWrite
534 | ReadOnly
535 deriving (Show, Eq, Ord, Enum, Bounded)
537data TransactionMode = TransactionMode {
538 isolationLevel :: !IsolationLevel,
539 readWriteMode :: !ReadWriteMode
540 } deriving (Show, Eq)
542defaultTransactionMode :: TransactionMode
543defaultTransactionMode = TransactionMode ReadCommitted ReadWrite
545defaultIsolationLevel :: IsolationLevel
546defaultIsolationLevel = ReadCommitted
548defaultReadWriteMode :: ReadWriteMode
549defaultReadWriteMode = ReadWrite
551-- | Execute an action inside a SQL transaction.
552--
553-- This function initiates a transaction with a \"@begin
554-- transaction@\" statement, then executes the supplied action. If
555-- the action succeeds, the transaction will be completed with
556-- 'Base.commit' before this function returns.
557--
558-- If the action throws /any/ kind of exception (not just a
559-- PostgreSQL-related exception), the transaction will be rolled back using
560-- 'rollback', then the exception will be rethrown.
561withTransaction :: Connection -> IO a -> IO a
562withTransaction = withTransactionMode defaultTransactionMode
564-- | Execute an action inside a SQL transaction with a given isolation level.
565withTransactionLevel :: IsolationLevel -> Connection -> IO a -> IO a
566withTransactionLevel lvl
567 = withTransactionMode defaultTransactionMode { isolationLevel = lvl }
569-- | Execute an action inside a SQL transaction with a given transaction mode.
570withTransactionMode :: TransactionMode -> Connection -> IO a -> IO a
571withTransactionMode mode conn act = do
572 beginMode mode conn
573 r <- act `onException` rollback conn
574 commit conn
575 return r
577-- | Rollback a transaction.
578rollback :: Connection -> IO ()
579rollback conn = execute_ conn "ABORT" >> return ()
581-- | Commit a transaction.
582commit :: Connection -> IO ()
583commit conn = execute_ conn "COMMIT" >> return ()
585-- | Begin a transaction.
586begin :: Connection -> IO ()
587begin = beginMode defaultTransactionMode
589-- | Begin a transaction with a given isolation level
590beginLevel :: IsolationLevel -> Connection -> IO ()
591beginLevel lvl = beginMode defaultTransactionMode { isolationLevel = lvl }
593-- | Begin a transaction with a given transaction mode
594beginMode :: TransactionMode -> Connection -> IO ()
595beginMode mode conn = do
596 execute_ conn $! case mode of
597 TransactionMode ReadCommitted ReadWrite ->
598 "BEGIN"
599 TransactionMode ReadCommitted ReadOnly ->
600 "BEGIN READ ONLY"
601 TransactionMode RepeatableRead ReadWrite ->
602 "BEGIN ISOLATION LEVEL REPEATABLE READ"
603 TransactionMode RepeatableRead ReadOnly ->
604 "BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY"
605 TransactionMode Serializable ReadWrite ->
606 "BEGIN ISOLATION LEVEL SERIALIZABLE"
607 TransactionMode Serializable ReadOnly ->
608 "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"
609 return ()
611fmtError :: String -> Query -> [Action] -> a
612fmtError msg q xs = throw FormatError {
613 fmtMessage = msg
614 , fmtQuery = q
615 , fmtParams = map twiddle xs
616 }
617 where twiddle (Plain b) = toByteString b
618 twiddle (Escape s) = s
619 twiddle (Many ys) = B.concat (map twiddle ys)
621-- $use
622--
623-- SQL-based applications are somewhat notorious for their
624-- susceptibility to attacks through the injection of maliciously
625-- crafted data. The primary reason for widespread vulnerability to
626-- SQL injections is that many applications are sloppy in handling
627-- user data when constructing SQL queries.
628--
629-- This library provides a 'Query' type and a parameter substitution
630-- facility to address both ease of use and security.
632-- $querytype
633--
634-- A 'Query' is a @newtype@-wrapped 'ByteString'. It intentionally
635-- exposes a tiny API that is not compatible with the 'ByteString'
636-- API; this makes it difficult to construct queries from fragments of
637-- strings. The 'query' and 'execute' functions require queries to be
638-- of type 'Query'.
639--
640-- To most easily construct a query, enable GHC's @OverloadedStrings@
641-- language extension and write your query as a normal literal string.
642--
643-- > {-# LANGUAGE OverloadedStrings #-}
644-- >
645-- > import Database.PostgreSQL.Simple
646-- >
647-- > hello = do
648-- > conn <- connect defaultConnectInfo
649-- > query conn "select 2 + 2"
650--
651-- A 'Query' value does not represent the actual query that will be
652-- executed, but is a template for constructing the final query.
654-- $subst
655--
656-- Since applications need to be able to construct queries with
657-- parameters that change, this library provides a query substitution
658-- capability.
659--
660-- The 'Query' template accepted by 'query' and 'execute' can contain
661-- any number of \"@?@\" characters. Both 'query' and 'execute'
662-- accept a third argument, typically a tuple. When constructing the
663-- real query to execute, these functions replace the first \"@?@\" in
664-- the template with the first element of the tuple, the second
665-- \"@?@\" with the second element, and so on. If necessary, each
666-- tuple element will be quoted and escaped prior to substitution;
667-- this defeats the single most common injection vector for malicious
668-- data.
669--
670-- For example, given the following 'Query' template:
671--
672-- > select * from user where first_name = ? and age > ?
673--
674-- And a tuple of this form:
675--
676-- > ("Boris" :: String, 37 :: Int)
677--
678-- The query to be executed will look like this after substitution:
679--
680-- > select * from user where first_name = 'Boris' and age > 37
681--
682-- If there is a mismatch between the number of \"@?@\" characters in
683-- your template and the number of elements in your tuple, a
684-- 'FormatError' will be thrown.
685--
686-- Note that the substitution functions do not attempt to parse or
687-- validate your query. It's up to you to write syntactically valid
688-- SQL, and to ensure that each \"@?@\" in your query template is
689-- matched with the right tuple element.
691-- $inference
692--
693-- Automated type inference means that you will often be able to avoid
694-- supplying explicit type signatures for the elements of a tuple.
695-- However, sometimes the compiler will not be able to infer your
696-- types. Consider a care where you write a numeric literal in a
697-- parameter tuple:
698--
699-- > query conn "select ? + ?" (40,2)
700--
701-- The above query will be rejected by the compiler, because it does
702-- not know the specific numeric types of the literals @40@ and @2@.
703-- This is easily fixed:
704--
705-- > query conn "select ? + ?" (40 :: Double, 2 :: Double)
706--
707-- The same kind of problem can arise with string literals if you have
708-- the @OverloadedStrings@ language extension enabled. Again, just
709-- use an explicit type signature if this happens.
711-- $only_param
712--
713-- Haskell lacks a single-element tuple type, so if you have just one
714-- value you want substituted into a query, what should you do?
715--
716-- The obvious approach would appear to be something like this:
717--
718-- > instance (Param a) => QueryParam a where
719-- > ...
720--
721-- Unfortunately, this wreaks havoc with type inference, so we take a
722-- different tack. To represent a single value @val@ as a parameter, write
723-- a singleton list @[val]@, use 'Just' @val@, or use 'Only' @val@.
724--
725-- Here's an example using a singleton list:
726--
727-- > execute conn "insert into users (first_name) values (?)"
728-- > ["Nuala"]
730-- $in
731--
732-- Suppose you want to write a query using an @IN@ clause:
733--
734-- > select * from users where first_name in ('Anna', 'Boris', 'Carla')
735--
736-- In such cases, it's common for both the elements and length of the
737-- list after the @IN@ keyword to vary from query to query.
738--
739-- To address this case, use the 'In' type wrapper, and use a single
740-- \"@?@\" character to represent the list. Omit the parentheses
741-- around the list; these will be added for you.
742--
743-- Here's an example:
744--
745-- > query conn "select * from users where first_name in ?" $
746-- > In ["Anna", "Boris", "Carla"]
747--
748-- If your 'In'-wrapped list is empty, the string @\"(null)\"@ will be
749-- substituted instead, to ensure that your clause remains
750-- syntactically valid.
752-- $many
753--
754-- If you know that you have many rows of data to insert into a table,
755-- it is much more efficient to perform all the insertions in a single
756-- multi-row @INSERT@ statement than individually.
757--
758-- The 'executeMany' function is intended specifically for helping
759-- with multi-row @INSERT@ and @UPDATE@ statements. Its rules for
760-- query substitution are different than those for 'execute'.
761--
762-- What 'executeMany' searches for in your 'Query' template is a
763-- single substring of the form:
764--
765-- > values (?,?,?)
766--
767-- The rules are as follows:
768--
769-- * The keyword @VALUES@ is matched case insensitively.
770--
771-- * There must be no other \"@?@\" characters anywhere in your
772-- template.
773--
774-- * There must one or more \"@?@\" in the parentheses.
775--
776-- * Extra white space is fine.
777--
778-- The last argument to 'executeMany' is a list of parameter
779-- tuples. These will be substituted into the query where the @(?,?)@
780-- string appears, in a form suitable for use in a multi-row @INSERT@
781-- or @UPDATE@.
782--
783-- Here is an example:
784--
785-- > executeMany conn
786-- > "insert into users (first_name,last_name) values (?,?)"
787-- > [("Boris","Karloff"),("Ed","Wood")]
788--
789-- The query that will be executed here will look like this
790-- (reformatted for tidiness):
791--
792-- > insert into users (first_name,last_name) values
793-- > ('Boris','Karloff'),('Ed','Wood')
795-- $result
796--
797-- The 'query' and 'query_' functions return a list of values in the
798-- 'FromRow' typeclass. This class performs automatic extraction
799-- and type conversion of rows from a query result.
800--
801-- Here is a simple example of how to extract results:
802--
803-- > import qualified Data.Text as Text
804-- >
805-- > xs <- query_ conn "select name,age from users"
806-- > forM_ xs $ \(name,age) ->
807-- > putStrLn $ Text.unpack name ++ " is " ++ show (age :: Int)
808--
809-- Notice two important details about this code:
810--
811-- * The number of columns we ask for in the query template must
812-- exactly match the number of elements we specify in a row of the
813-- result tuple. If they do not match, a 'ResultError' exception
814-- will be thrown.
815--
816-- * Sometimes, the compiler needs our help in specifying types. It
817-- can infer that @name@ must be a 'Text', due to our use of the
818-- @unpack@ function. However, we have to tell it the type of @age@,
819-- as it has no other information to determine the exact type.
821-- $null
822--
823-- The type of a result tuple will look something like this:
824--
825-- > (Text, Int, Int)
826--
827-- Although SQL can accommodate @NULL@ as a value for any of these
828-- types, Haskell cannot. If your result contains columns that may be
829-- @NULL@, be sure that you use 'Maybe' in those positions of of your
830-- tuple.
831--
832-- > (Text, Maybe Int, Int)
833--
834-- If 'query' encounters a @NULL@ in a row where the corresponding
835-- Haskell type is not 'Maybe', it will throw a 'ResultError'
836-- exception.
838-- $only_result
839--
840-- To specify that a query returns a single-column result, use the
841-- 'Only' type.
842--
843-- > xs <- query_ conn "select id from users"
844-- > forM_ xs $ \(Only dbid) -> {- ... -}
846-- $types
847--
848-- Conversion of SQL values to Haskell values is somewhat
849-- permissive. Here are the rules.
850--
851-- * For numeric types, any Haskell type that can accurately represent
852-- all values of the given PostgreSQL type is considered \"compatible\".
853-- For instance, you can always extract a PostgreSQL 16-bit @SMALLINT@
854-- column to a Haskell 'Int'. The Haskell 'Float' type can accurately
855-- represent a @SMALLINT@, so it is considered compatble with those types.
856--
857-- * A numeric compatibility check is based only on the type of a
858-- column, /not/ on its values. For instance, a PostgreSQL 64-bit
859-- @BIGINT@ column will be considered incompatible with a Haskell
860-- 'Int16', even if it contains the value @1@.
861--
862-- * If a numeric incompatibility is found, 'query' will throw a
863-- 'ResultError'.
864--
865-- * The 'String' and 'Text' types are assumed to be encoded as
866-- UTF-8. If you use some other encoding, decoding may fail or give
867-- wrong results. In such cases, write a @newtype@ wrapper and a
868-- custom 'Result' instance to handle your encoding.
870getTypename :: Connection -> PQ.Oid -> IO ByteString
871getTypename conn@Connection{..} oid =
872 case oid2builtin oid of
873 Just builtin -> return $! builtin2typname builtin
874 Nothing -> modifyMVar connectionObjects $ \oidmap -> do
875 case IntMap.lookup (oid2int oid) oidmap of
876 Just name -> return (oidmap, name)
877 Nothing -> do
878 names <- query conn "SELECT typname FROM pg_type WHERE oid=?"
879 (Only oid)
880 name <- case names of
881 [] -> return $ throw SqlError {
882 sqlNativeError = -1,
883 sqlErrorMsg = "invalid type oid",
884 sqlState = ""
885 }
886 [Only x] -> return x
887 _ -> fail "typename query returned more than one result"
888 -- oid is a primary key, so the query should
889 -- never return more than one result
890 return (IntMap.insert (oid2int oid) name oidmap, name)