Skip to content

Commit e760c88

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

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

src/Database/PostgreSQL/LibPQ.hs

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

699+
-- | Prepare the given parameter bytestring for passing on to libpq,
700+
-- without copying for binary parameters.
701+
--
702+
-- This is safe to use to pass parameters to libpq considering:
703+
-- * libpq treats the parameter data as read-only
704+
-- * 'ByteString' uses pinned memory
705+
-- * the reference to the 'CString' doesn't escape
706+
unsafeUseParamAsCString :: (B.ByteString, Format) -> (CString -> IO a) -> IO a
707+
unsafeUseParamAsCString (bs, format) =
708+
case format of
709+
Binary -> B.unsafeUseAsCString bs
710+
Text -> B.useAsCString bs
711+
699712
-- | Convert a list of parameters to the format expected by libpq FFI calls.
700713
withParams :: [Maybe (Oid, B.ByteString, Format)]
701714
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
702715
-> IO a
703716
withParams params action =
704717
unsafeWithArray n oids $ \ts ->
705-
withMany (maybeWith B.useAsCString) values $ \c_values ->
718+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
706719
unsafeWithArray n c_values $ \vs ->
707720
unsafeWithArray n c_lengths $ \ls ->
708721
unsafeWithArray n formats $ \fs ->
@@ -718,20 +731,20 @@ withParams params action =
718731
accum (Just (t,v,f)) ~(AccumParams i xs ys zs ws) =
719732
let !z = intToCInt (B.length v)
720733
!w = toCInt f
721-
in AccumParams (i + 1) (t : xs) (Just v : ys) (z : zs) (w : ws)
734+
in AccumParams (i + 1) (t : xs) (Just (v, f) : ys) (z : zs) (w : ws)
722735

723736
intToCInt :: Int -> CInt
724737
intToCInt = toEnum
725738

726-
data AccumParams = AccumParams !Int ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
739+
data AccumParams = AccumParams !Int ![Oid] ![Maybe (B.ByteString, Format)] ![CInt] ![CInt]
727740

728741
-- | Convert a list of parameters to the format expected by libpq FFI calls,
729742
-- prepared statement variant.
730743
withParamsPrepared :: [Maybe (B.ByteString, Format)]
731744
-> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
732745
-> IO a
733746
withParamsPrepared params action =
734-
withMany (maybeWith B.useAsCString) values $ \c_values ->
747+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
735748
unsafeWithArray n c_values $ \vs ->
736749
unsafeWithArray n c_lengths $ \ls ->
737750
unsafeWithArray n formats $ \fs ->
@@ -740,16 +753,16 @@ withParamsPrepared params action =
740753
AccumPrepParams n values c_lengths formats =
741754
foldr accum (AccumPrepParams 0 [] [] []) params
742755

743-
accum :: Maybe (B.ByteString ,Format) -> AccumPrepParams -> AccumPrepParams
756+
accum :: Maybe (B.ByteString, Format) -> AccumPrepParams -> AccumPrepParams
744757
accum Nothing ~(AccumPrepParams i a b c) =
745758
AccumPrepParams (i + 1) (Nothing : a) (0 : b) (0 : c)
746759

747760
accum (Just (v, f)) ~(AccumPrepParams i xs ys zs) =
748761
let !y = intToCInt (B.length v)
749762
!z = toCInt f
750-
in AccumPrepParams (i + 1) (Just v : xs) (y : ys) (z : zs)
763+
in AccumPrepParams (i + 1) (Just (v, f) : xs) (y : ys) (z : zs)
751764

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

754767
-- | Submits a command to the server and waits for the result.
755768
--

0 commit comments

Comments
 (0)