@@ -654,13 +654,26 @@ connectionUsedPassword connection =
654654-- 'Result'.
655655newtype Result = Result (ForeignPtr PGresult ) deriving (Eq , Show )
656656
657+ -- | Prepare the given parameter bytestring for passing on to libpq,
658+ -- without copying for binary parameters.
659+ --
660+ -- This is safe to use to pass parameters to libpq considering:
661+ -- * libpq treats the parameter data as read-only
662+ -- * 'ByteString' uses pinned memory
663+ -- * the reference to the 'CString' doesn't escape
664+ unsafeUseParamAsCString :: (B. ByteString , Format ) -> (CString -> IO a ) -> IO a
665+ unsafeUseParamAsCString (bs, format) =
666+ case format of
667+ Binary -> B. unsafeUseAsCString bs
668+ Text -> B. useAsCString bs
669+
657670-- | Convert a list of parameters to the format expected by libpq FFI calls.
658671withParams :: [Maybe (Oid , B. ByteString , Format )]
659672 -> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a )
660673 -> IO a
661674withParams params action =
662675 unsafeWithArray n oids $ \ ts ->
663- withMany (maybeWith B. useAsCString ) values $ \ c_values ->
676+ withMany (maybeWith unsafeUseParamAsCString ) values $ \ c_values ->
664677 unsafeWithArray n c_values $ \ vs ->
665678 unsafeWithArray n c_lengths $ \ ls ->
666679 unsafeWithArray n formats $ \ fs ->
@@ -676,20 +689,20 @@ withParams params action =
676689 accum (Just (t,v,f)) ~ (AccumParams i xs ys zs ws) =
677690 let ! z = intToCInt (B. length v)
678691 ! w = toCInt f
679- in AccumParams (i + 1 ) (t : xs) (Just v : ys) (z : zs) (w : ws)
692+ in AccumParams (i + 1 ) (t : xs) (Just (v, f) : ys) (z : zs) (w : ws)
680693
681694intToCInt :: Int -> CInt
682695intToCInt = toEnum
683696
684- data AccumParams = AccumParams ! Int ! [Oid ] ! [Maybe B. ByteString ] ! [CInt ] ! [CInt ]
697+ data AccumParams = AccumParams ! Int ! [Oid ] ! [Maybe ( B. ByteString, Format ) ] ! [CInt ] ! [CInt ]
685698
686699-- | Convert a list of parameters to the format expected by libpq FFI calls,
687700-- prepared statement variant.
688701withParamsPrepared :: [Maybe (B. ByteString , Format )]
689702 -> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a )
690703 -> IO a
691704withParamsPrepared params action =
692- withMany (maybeWith B. useAsCString ) values $ \ c_values ->
705+ withMany (maybeWith unsafeUseParamAsCString ) values $ \ c_values ->
693706 unsafeWithArray n c_values $ \ vs ->
694707 unsafeWithArray n c_lengths $ \ ls ->
695708 unsafeWithArray n formats $ \ fs ->
@@ -698,16 +711,16 @@ withParamsPrepared params action =
698711 AccumPrepParams n values c_lengths formats =
699712 foldr accum (AccumPrepParams 0 [] [] [] ) params
700713
701- accum :: Maybe (B. ByteString , Format ) -> AccumPrepParams -> AccumPrepParams
714+ accum :: Maybe (B. ByteString, Format ) -> AccumPrepParams -> AccumPrepParams
702715 accum Nothing ~ (AccumPrepParams i a b c) =
703716 AccumPrepParams (i + 1 ) (Nothing : a) (0 : b) (0 : c)
704717
705718 accum (Just (v, f)) ~ (AccumPrepParams i xs ys zs) =
706719 let ! y = intToCInt (B. length v)
707720 ! z = toCInt f
708- in AccumPrepParams (i + 1 ) (Just v : xs) (y : ys) (z : zs)
721+ in AccumPrepParams (i + 1 ) (Just (v, f) : xs) (y : ys) (z : zs)
709722
710- data AccumPrepParams = AccumPrepParams ! Int ! [Maybe B. ByteString ] ! [CInt ] ! [CInt ]
723+ data AccumPrepParams = AccumPrepParams ! Int ! [Maybe ( B. ByteString, Format ) ] ! [CInt ] ! [CInt ]
711724
712725-- | Submits a command to the server and waits for the result.
713726--
0 commit comments