Skip to content

Commit 77c147f

Browse files
committed
Pass binary parameter data without copying
1 parent e48f161 commit 77c147f

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

src/Database/PostgreSQL/LibPQ.hsc

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -745,13 +745,26 @@ newtype Oid = Oid CUInt deriving (Eq, Ord, Read, Show, Storable, Typeable)
745745
invalidOid :: Oid
746746
invalidOid = Oid (#const InvalidOid)
747747

748+
-- | Prepare the given parameter bytestring for passing on to libpq,
749+
-- without copying for binary parameters.
750+
--
751+
-- This is safe to use to pass parameters to libpq considering:
752+
-- * libpq treats the parameter data as read-only
753+
-- * 'ByteString' uses pinned memory
754+
-- * the reference to the 'CString' doesn't escape
755+
unsafeUseParamAsCString :: (B.ByteString, Format) -> (CString -> IO a) -> IO a
756+
unsafeUseParamAsCString (bs, format) =
757+
case format of
758+
Binary -> B.unsafeUseAsCString bs
759+
Text -> B.useAsCString bs
760+
748761
-- | Convert a list of parameters to the format expected by libpq FFI calls.
749762
withParams :: [Maybe (Oid, B.ByteString, Format)]
750763
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
751764
-> IO a
752765
withParams params action =
753766
withArray oids $ \ts ->
754-
withMany (maybeWith B.useAsCString) values $ \c_values ->
767+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
755768
withArray c_values $ \vs ->
756769
withArray c_lengths $ \ls ->
757770
withArray formats $ \fs ->
@@ -770,7 +783,7 @@ withParams params action =
770783
accum (Just (t,v,f)) ~(AccumParams xs ys zs ws) =
771784
let z = intToCInt (B.length v)
772785
w = formatToCInt f
773-
in z `seq` w `seq` AccumParams (t : xs) (Just v : ys) (z : zs) (w : ws)
786+
in z `seq` w `seq` AccumParams (t : xs) (Just (v, f) : ys) (z : zs) (w : ws)
774787

775788
formatToCInt :: Format -> CInt
776789
formatToCInt Text = 0
@@ -779,15 +792,15 @@ formatToCInt Binary = 1
779792
intToCInt :: Int -> CInt
780793
intToCInt = toEnum
781794

782-
data AccumParams = AccumParams ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
795+
data AccumParams = AccumParams ![Oid] ![Maybe (B.ByteString, Format)] ![CInt] ![CInt]
783796

784797
-- | Convert a list of parameters to the format expected by libpq FFI calls,
785798
-- prepared statement variant.
786799
withParamsPrepared :: [Maybe (B.ByteString, Format)]
787800
-> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
788801
-> IO a
789802
withParamsPrepared params action =
790-
withMany (maybeWith B.useAsCString) values $ \c_values ->
803+
withMany (maybeWith unsafeUseParamAsCString) values $ \c_values ->
791804
withArray c_values $ \vs ->
792805
withArray c_lengths $ \ls ->
793806
withArray formats $ \fs ->
@@ -806,9 +819,9 @@ withParamsPrepared params action =
806819
accum (Just (v, f)) ~(AccumPrepParams xs ys zs) =
807820
let y = intToCInt (B.length v)
808821
z = formatToCInt f
809-
in y `seq` z `seq` AccumPrepParams (Just v : xs) (y : ys) (z : zs)
822+
in y `seq` z `seq` AccumPrepParams (Just (v, f) : xs) (y : ys) (z : zs)
810823

811-
data AccumPrepParams = AccumPrepParams ![Maybe B.ByteString] ![CInt] ![CInt]
824+
data AccumPrepParams = AccumPrepParams ![Maybe (B.ByteString, Format)] ![CInt] ![CInt]
812825

813826
-- | Submits a command to the server and waits for the result.
814827
--

0 commit comments

Comments
 (0)