Skip to content

Commit 9282726

Browse files
committed
Pass binary parameter data without copying
1 parent fc19817 commit 9282726

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

src/Database/PostgreSQL/LibPQ.hs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -696,13 +696,28 @@ connectionUsedPassword connection =
696696
newtype Result = Result (ForeignPtr PGresult) deriving (Eq, Show)
697697
data PGresult
698698

699+
data Format = Text | Binary deriving (Eq, Ord, Show, Enum)
700+
701+
-- | Prepare the given parameter bytestring for passing on to libpq,
702+
-- without copying for binary parameters.
703+
--
704+
-- This is safe to use to pass parameters to libpq considering:
705+
-- * libpq treats the parameter data as read-only
706+
-- * 'ByteString' uses pinned memory
707+
-- * the reference to the 'CString' doesn't escape
708+
unsafeUseParamAsCString :: (B.ByteString, Format) -> (CString -> IO a) -> IO a
709+
unsafeUseParamAsCString (bs, format) =
710+
case format of
711+
Binary -> B.unsafeUseAsCString bs
712+
Text -> B.useAsCString bs
713+
699714
-- | Convert a list of parameters to the format expected by libpq FFI calls.
700715
withParams :: [Maybe (Oid, B.ByteString, Format)]
701716
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
702717
-> IO a
703718
withParams params action =
704719
unsafeWithArray n oids $ \ts ->
705-
withMany (maybeWith B.useAsCString) values $ \c_values ->
720+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
706721
unsafeWithArray n c_values $ \vs ->
707722
unsafeWithArray n c_lengths $ \ls ->
708723
unsafeWithArray n formats $ \fs ->
@@ -717,21 +732,25 @@ withParams params action =
717732

718733
accum (Just (t,v,f)) ~(AccumParams i xs ys zs ws) =
719734
let !z = intToCInt (B.length v)
720-
!w = toCInt f
721-
in AccumParams (i + 1) (t : xs) (Just v : ys) (z : zs) (w : ws)
735+
!w = formatToCInt f
736+
in AccumParams (i + 1) (t : xs) (Just (v, f) : ys) (z : zs) (w : ws)
722737

723738
intToCInt :: Int -> CInt
724739
intToCInt = toEnum
725740

726-
data AccumParams = AccumParams !Int ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
741+
formatToCInt :: Format -> CInt
742+
formatToCInt Text = 0
743+
formatToCInt Binary = 1
744+
745+
data AccumParams = AccumParams !Int ![Oid] ![Maybe (B.ByteString, Format)] ![CInt] ![CInt]
727746

728747
-- | Convert a list of parameters to the format expected by libpq FFI calls,
729748
-- prepared statement variant.
730749
withParamsPrepared :: [Maybe (B.ByteString, Format)]
731750
-> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
732751
-> IO a
733752
withParamsPrepared params action =
734-
withMany (maybeWith B.useAsCString) values $ \c_values ->
753+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
735754
unsafeWithArray n c_values $ \vs ->
736755
unsafeWithArray n c_lengths $ \ls ->
737756
unsafeWithArray n formats $ \fs ->
@@ -740,16 +759,16 @@ withParamsPrepared params action =
740759
AccumPrepParams n values c_lengths formats =
741760
foldr accum (AccumPrepParams 0 [] [] []) params
742761

743-
accum :: Maybe (B.ByteString ,Format) -> AccumPrepParams -> AccumPrepParams
762+
accum :: Maybe (B.ByteString, Format) -> AccumPrepParams -> AccumPrepParams
744763
accum Nothing ~(AccumPrepParams i a b c) =
745764
AccumPrepParams (i + 1) (Nothing : a) (0 : b) (0 : c)
746765

747766
accum (Just (v, f)) ~(AccumPrepParams i xs ys zs) =
748767
let !y = intToCInt (B.length v)
749-
!z = toCInt f
750-
in AccumPrepParams (i + 1) (Just v : xs) (y : ys) (z : zs)
768+
!z = formatToCInt f
769+
in AccumPrepParams (i + 1) (Just (v, f) : xs) (y : ys) (z : zs)
751770

752-
data AccumPrepParams = AccumPrepParams !Int ![Maybe B.ByteString] ![CInt] ![CInt]
771+
data AccumPrepParams = AccumPrepParams !Int ![Maybe (B.ByteString, Format)] ![CInt] ![CInt]
753772

754773
-- | Submits a command to the server and waits for the result.
755774
--

0 commit comments

Comments
 (0)