Skip to content

Commit b8222d6

Browse files
committed
Use withArrayLen to avoid traversing many times
Also calculate length already in a helper accum
1 parent e48f161 commit b8222d6

File tree

3 files changed

+52
-40
lines changed

3 files changed

+52
-40
lines changed

postgresql-libpq.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ library
6363
Database.PostgreSQL.LibPQ
6464
Database.PostgreSQL.LibPQ.Internal
6565

66-
other-modules: Database.PostgreSQL.LibPQ.Compat
66+
other-modules: Database.PostgreSQL.LibPQ.Compat Database.PostgreSQL.LibPQ.Marshal
6767
build-depends:
6868
base >=4.3 && <4.18
6969
, bytestring >=0.9.1.0 && <0.12

src/Database/PostgreSQL/LibPQ.hsc

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ import Data.Typeable
246246

247247
import Database.PostgreSQL.LibPQ.Compat
248248
import Database.PostgreSQL.LibPQ.Internal
249+
import Database.PostgreSQL.LibPQ.Marshal
249250

250251
#if __GLASGOW_HASKELL__ >= 700
251252
import Control.Exception (mask_)
@@ -750,27 +751,24 @@ withParams :: [Maybe (Oid, B.ByteString, Format)]
750751
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
751752
-> IO a
752753
withParams params action =
753-
withArray oids $ \ts ->
754+
unsafeWithArray n oids $ \ts ->
754755
withMany (maybeWith B.useAsCString) values $ \c_values ->
755-
withArray c_values $ \vs ->
756-
withArray c_lengths $ \ls ->
757-
withArray formats $ \fs ->
758-
action n ts vs ls fs
756+
unsafeWithArray n c_values $ \vs ->
757+
unsafeWithArray n c_lengths $ \ls ->
758+
unsafeWithArray n formats $ \fs ->
759+
action (intToCInt n) ts vs ls fs
759760
where
760-
AccumParams oids values c_lengths formats =
761-
foldr accum (AccumParams [] [] [] []) params
762-
763-
n :: CInt
764-
!n = intToCInt $ length params
761+
AccumParams n oids values c_lengths formats =
762+
foldr accum (AccumParams 0 [] [] [] []) params
765763

766764
accum :: Maybe (Oid, B.ByteString, Format) -> AccumParams -> AccumParams
767-
accum Nothing ~(AccumParams a b c d) =
768-
AccumParams (invalidOid : a) (Nothing : b) (0 : c) (0 : d)
765+
accum Nothing ~(AccumParams i a b c d) =
766+
AccumParams (i + 1) (invalidOid : a) (Nothing : b) (0 : c) (0 : d)
769767

770-
accum (Just (t,v,f)) ~(AccumParams xs ys zs ws) =
771-
let z = intToCInt (B.length v)
772-
w = formatToCInt f
773-
in z `seq` w `seq` AccumParams (t : xs) (Just v : ys) (z : zs) (w : ws)
768+
accum (Just (t,v,f)) ~(AccumParams i xs ys zs ws) =
769+
let !z = intToCInt (B.length v)
770+
!w = formatToCInt f
771+
in AccumParams (i + 1) (t : xs) (Just v : ys) (z : zs) (w : ws)
774772

775773
formatToCInt :: Format -> CInt
776774
formatToCInt Text = 0
@@ -779,7 +777,7 @@ formatToCInt Binary = 1
779777
intToCInt :: Int -> CInt
780778
intToCInt = toEnum
781779

782-
data AccumParams = AccumParams ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
780+
data AccumParams = AccumParams !Int ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
783781

784782
-- | Convert a list of parameters to the format expected by libpq FFI calls,
785783
-- prepared statement variant.
@@ -788,27 +786,24 @@ withParamsPrepared :: [Maybe (B.ByteString, Format)]
788786
-> IO a
789787
withParamsPrepared params action =
790788
withMany (maybeWith B.useAsCString) values $ \c_values ->
791-
withArray c_values $ \vs ->
792-
withArray c_lengths $ \ls ->
793-
withArray formats $ \fs ->
794-
action n vs ls fs
789+
unsafeWithArray n c_values $ \vs ->
790+
unsafeWithArray n c_lengths $ \ls ->
791+
unsafeWithArray n formats $ \fs ->
792+
action (intToCInt n) vs ls fs
795793
where
796-
AccumPrepParams values c_lengths formats =
797-
foldr accum (AccumPrepParams [] [] []) params
798-
799-
n :: CInt
800-
n = intToCInt $ length params
794+
AccumPrepParams n values c_lengths formats =
795+
foldr accum (AccumPrepParams 0 [] [] []) params
801796

802797
accum :: Maybe (B.ByteString ,Format) -> AccumPrepParams -> AccumPrepParams
803-
accum Nothing ~(AccumPrepParams a b c) =
804-
AccumPrepParams (Nothing : a) (0 : b) (0 : c)
798+
accum Nothing ~(AccumPrepParams i a b c) =
799+
AccumPrepParams (i + 1) (Nothing : a) (0 : b) (0 : c)
805800

806-
accum (Just (v, f)) ~(AccumPrepParams xs ys zs) =
807-
let y = intToCInt (B.length v)
808-
z = formatToCInt f
809-
in y `seq` z `seq` AccumPrepParams (Just v : xs) (y : ys) (z : zs)
801+
accum (Just (v, f)) ~(AccumPrepParams i xs ys zs) =
802+
let !y = intToCInt (B.length v)
803+
!z = formatToCInt f
804+
in AccumPrepParams (i + 1) (Just v : xs) (y : ys) (z : zs)
810805

811-
data AccumPrepParams = AccumPrepParams ![Maybe B.ByteString] ![CInt] ![CInt]
806+
data AccumPrepParams = AccumPrepParams !Int ![Maybe B.ByteString] ![CInt] ![CInt]
812807

813808
-- | Submits a command to the server and waits for the result.
814809
--
@@ -929,9 +924,8 @@ prepare connection stmtName query mParamTypes =
929924
resultFromConn connection $ \c ->
930925
B.useAsCString stmtName $ \s ->
931926
B.useAsCString query $ \q ->
932-
maybeWith withArray mParamTypes $ \o ->
933-
let l = maybe 0 (intToCInt . length) mParamTypes
934-
in c_PQprepare c s q l o
927+
maybeWithInt withArrayLen mParamTypes $ \l o ->
928+
c_PQprepare c s q (intToCInt l) o
935929

936930

937931
-- | Sends a request to execute a prepared statement with given
@@ -1726,9 +1720,8 @@ sendPrepare connection stmtName query mParamTypes =
17261720
enumFromConn connection $ \c ->
17271721
B.useAsCString stmtName $ \s ->
17281722
B.useAsCString query $ \q ->
1729-
maybeWith withArray mParamTypes $ \o ->
1730-
let l = maybe 0 (intToCInt . length) mParamTypes
1731-
in c_PQsendPrepare c s q l o
1723+
maybeWithInt withArrayLen mParamTypes $ \l o ->
1724+
c_PQsendPrepare c s q (intToCInt l) o
17321725

17331726

17341727
-- | Sends a request to execute a prepared statement with given
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{-# LANGUAGE CPP #-}
2+
module Database.PostgreSQL.LibPQ.Marshal where
3+
4+
import Foreign (Ptr,nullPtr,Storable,allocaArray,pokeArray)
5+
6+
unsafeWithArray :: Storable a => Int -> [a] -> (Ptr a -> IO b) -> IO b
7+
unsafeWithArray len vals f =
8+
#if 0
9+
if len /= length vals then error "unsafeWithArray: len mismatch" else
10+
#endif
11+
allocaArray len $ \ptr -> do
12+
pokeArray ptr vals
13+
f ptr
14+
15+
-- | Like maybe with but takes an int. Usable with 'withArrayLen'.
16+
-- In 'Nothing' case uses 0 and 'nullPtr'.
17+
maybeWithInt :: ( a -> (Int -> Ptr b -> IO c) -> IO c)
18+
-> (Maybe a -> (Int -> Ptr b -> IO c) -> IO c)
19+
maybeWithInt = maybe (\f -> f 0 nullPtr)

0 commit comments

Comments
 (0)