Skip to content

Commit 89c7cb8

Browse files
robxphadej
authored andcommitted
Pass binary parameter data without copying
1 parent a184b11 commit 89c7cb8

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

src/Database/PostgreSQL/LibPQ.hs

+20-7
Original file line numberDiff line numberDiff line change
@@ -654,13 +654,26 @@ connectionUsedPassword connection =
654654
-- 'Result'.
655655
newtype 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.
658671
withParams :: [Maybe (Oid, B.ByteString, Format)]
659672
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
660673
-> IO a
661674
withParams 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

681694
intToCInt :: Int -> CInt
682695
intToCInt = 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.
688701
withParamsPrepared :: [Maybe (B.ByteString, Format)]
689702
-> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
690703
-> IO a
691704
withParamsPrepared 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

Comments
 (0)