Skip to content

Commit e48f161

Browse files
authored
Merge pull request #30 from haskellari/common-params
exec, query: factor out common parameter handling helpers
2 parents eaaf17e + 9666ffb commit e48f161

File tree

1 file changed

+90
-92
lines changed

1 file changed

+90
-92
lines changed

src/Database/PostgreSQL/LibPQ.hsc

Lines changed: 90 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ import qualified Foreign.ForeignPtr.Unsafe as Unsafe
225225
#endif
226226
import qualified Foreign.Concurrent as FC
227227
import System.Posix.Types ( Fd(..) )
228-
import Data.List ( foldl' )
229228
import System.IO ( IOMode(..), SeekMode(..) )
230229

231230
#if __GLASGOW_HASKELL__ >= 700
@@ -746,6 +745,71 @@ newtype Oid = Oid CUInt deriving (Eq, Ord, Read, Show, Storable, Typeable)
746745
invalidOid :: Oid
747746
invalidOid = Oid (#const InvalidOid)
748747

748+
-- | Convert a list of parameters to the format expected by libpq FFI calls.
749+
withParams :: [Maybe (Oid, B.ByteString, Format)]
750+
-> (CInt -> Ptr Oid -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
751+
-> IO a
752+
withParams params action =
753+
withArray oids $ \ts ->
754+
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
759+
where
760+
AccumParams oids values c_lengths formats =
761+
foldr accum (AccumParams [] [] [] []) params
762+
763+
n :: CInt
764+
!n = intToCInt $ length params
765+
766+
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)
769+
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)
774+
775+
formatToCInt :: Format -> CInt
776+
formatToCInt Text = 0
777+
formatToCInt Binary = 1
778+
779+
intToCInt :: Int -> CInt
780+
intToCInt = toEnum
781+
782+
data AccumParams = AccumParams ![Oid] ![Maybe B.ByteString] ![CInt] ![CInt]
783+
784+
-- | Convert a list of parameters to the format expected by libpq FFI calls,
785+
-- prepared statement variant.
786+
withParamsPrepared :: [Maybe (B.ByteString, Format)]
787+
-> (CInt -> Ptr CString -> Ptr CInt -> Ptr CInt -> IO a)
788+
-> IO a
789+
withParamsPrepared params action =
790+
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
795+
where
796+
AccumPrepParams values c_lengths formats =
797+
foldr accum (AccumPrepParams [] [] []) params
798+
799+
n :: CInt
800+
n = intToCInt $ length params
801+
802+
accum :: Maybe (B.ByteString ,Format) -> AccumPrepParams -> AccumPrepParams
803+
accum Nothing ~(AccumPrepParams a b c) =
804+
AccumPrepParams (Nothing : a) (0 : b) (0 : c)
805+
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)
810+
811+
data AccumPrepParams = AccumPrepParams ![Maybe B.ByteString] ![CInt] ![CInt]
812+
749813
-- | Submits a command to the server and waits for the result.
750814
--
751815
-- Returns a 'Result' or possibly 'Nothing'. A 'Result' will generally
@@ -812,31 +876,12 @@ execParams :: Connection -- ^ connection
812876
-> Format -- ^ result format
813877
-> IO (Maybe Result) -- ^ result
814878
execParams connection statement params rFmt =
815-
do let (oids, values, lengths, formats) =
816-
foldl' accum ([],[],[],[]) $ reverse params
817-
!c_lengths = map toEnum lengths :: [CInt]
818-
!n = toEnum $ length params
819-
!f = toEnum $ fromEnum rFmt
820-
resultFromConn connection $ \c ->
821-
B.useAsCString statement $ \s ->
822-
withArray oids $ \ts ->
823-
withMany (maybeWith B.useAsCString) values $ \c_values ->
824-
withArray c_values $ \vs ->
825-
withArray c_lengths $ \ls ->
826-
withArray formats $ \fs ->
827-
c_PQexecParams c s n ts vs ls fs f
828-
829-
where
830-
accum (!a,!b,!c,!d) Nothing = ( invalidOid:a
831-
, Nothing:b
832-
, 0:c
833-
, 0:d
834-
)
835-
accum (!a,!b,!c,!d) (Just (t,v,f)) = ( t:a
836-
, (Just v):b
837-
, (B.length v):c
838-
, (toEnum $ fromEnum f):d
839-
)
879+
resultFromConn connection $ \c ->
880+
B.useAsCString statement $ \s ->
881+
withParams params $ \n ts vs ls fs ->
882+
c_PQexecParams c s n ts vs ls fs f
883+
where
884+
!f = formatToCInt rFmt
840885

841886

842887
-- | Submits a request to create a prepared statement with the given
@@ -885,7 +930,7 @@ prepare connection stmtName query mParamTypes =
885930
B.useAsCString stmtName $ \s ->
886931
B.useAsCString query $ \q ->
887932
maybeWith withArray mParamTypes $ \o ->
888-
let l = maybe 0 (toEnum . length) mParamTypes
933+
let l = maybe 0 (intToCInt . length) mParamTypes
889934
in c_PQprepare c s q l o
890935

891936

@@ -911,28 +956,13 @@ execPrepared :: Connection -- ^ connection
911956
-> [Maybe (B.ByteString, Format)] -- ^ parameters
912957
-> Format -- ^ result format
913958
-> IO (Maybe Result) -- ^ result
914-
execPrepared connection stmtName mPairs rFmt =
915-
do let (values, lengths, formats) = foldl' accum ([],[],[]) $ reverse mPairs
916-
!c_lengths = map toEnum lengths :: [CInt]
917-
!n = toEnum $ length mPairs
918-
!f = toEnum $ fromEnum rFmt
919-
resultFromConn connection $ \c ->
920-
B.useAsCString stmtName $ \s ->
921-
withMany (maybeWith B.useAsCString) values $ \c_values ->
922-
withArray c_values $ \vs ->
923-
withArray c_lengths $ \ls ->
924-
withArray formats $ \fs ->
925-
c_PQexecPrepared c s n vs ls fs f
926-
959+
execPrepared connection stmtName params rFmt =
960+
resultFromConn connection $ \c ->
961+
B.useAsCString stmtName $ \s ->
962+
withParamsPrepared params $ \n vs ls fs ->
963+
c_PQexecPrepared c s n vs ls fs f
927964
where
928-
accum (!a,!b,!c) Nothing = ( Nothing:a
929-
, 0:b
930-
, 0:c
931-
)
932-
accum (!a,!b,!c) (Just (v, f)) = ( (Just v):a
933-
, (B.length v):b
934-
, (toEnum $ fromEnum f):c
935-
)
965+
!f = formatToCInt rFmt
936966

937967

938968
-- | Submits a request to obtain information about the specified
@@ -1676,31 +1706,13 @@ sendQueryParams :: Connection
16761706
-> Format
16771707
-> IO Bool
16781708
sendQueryParams connection statement params rFmt =
1679-
do let (oids, values, lengths, formats) =
1680-
foldl' accum ([],[],[],[]) $ reverse params
1681-
!c_lengths = map toEnum lengths :: [CInt]
1682-
!n = toEnum $ length params
1683-
!f = toEnum $ fromEnum rFmt
1684-
enumFromConn connection $ \c ->
1685-
B.useAsCString statement $ \s ->
1686-
withArray oids $ \ts ->
1687-
withMany (maybeWith B.useAsCString) values $ \c_values ->
1688-
withArray c_values $ \vs ->
1689-
withArray c_lengths $ \ls ->
1690-
withArray formats $ \fs ->
1691-
c_PQsendQueryParams c s n ts vs ls fs f
1709+
enumFromConn connection $ \c ->
1710+
B.useAsCString statement $ \s ->
1711+
withParams params $ \n ts vs ls fs ->
1712+
c_PQsendQueryParams c s n ts vs ls fs f
16921713

16931714
where
1694-
accum (!a,!b,!c,!d) Nothing = ( invalidOid:a
1695-
, Nothing:b
1696-
, 0:c
1697-
, 0:d
1698-
)
1699-
accum (!a,!b,!c,!d) (Just (t,v,f)) = ( t:a
1700-
, (Just v):b
1701-
, (B.length v):c
1702-
, (toEnum $ fromEnum f):d
1703-
)
1715+
!f = formatToCInt rFmt
17041716

17051717

17061718
-- | Sends a request to create a prepared statement with the given
@@ -1715,7 +1727,7 @@ sendPrepare connection stmtName query mParamTypes =
17151727
B.useAsCString stmtName $ \s ->
17161728
B.useAsCString query $ \q ->
17171729
maybeWith withArray mParamTypes $ \o ->
1718-
let l = maybe 0 (toEnum . length) mParamTypes
1730+
let l = maybe 0 (intToCInt . length) mParamTypes
17191731
in c_PQsendPrepare c s q l o
17201732

17211733

@@ -1726,28 +1738,14 @@ sendQueryPrepared :: Connection
17261738
-> [Maybe (B.ByteString, Format)]
17271739
-> Format
17281740
-> IO Bool
1729-
sendQueryPrepared connection stmtName mPairs rFmt =
1730-
do let (values, lengths, formats) = foldl' accum ([],[],[]) $ reverse mPairs
1731-
!c_lengths = map toEnum lengths :: [CInt]
1732-
!n = toEnum $ length mPairs
1733-
!f = toEnum $ fromEnum rFmt
1734-
enumFromConn connection $ \c ->
1735-
B.useAsCString stmtName $ \s ->
1736-
withMany (maybeWith B.useAsCString) values $ \c_values ->
1737-
withArray c_values $ \vs ->
1738-
withArray c_lengths $ \ls ->
1739-
withArray formats $ \fs ->
1740-
c_PQsendQueryPrepared c s n vs ls fs f
1741+
sendQueryPrepared connection stmtName params rFmt =
1742+
enumFromConn connection $ \c ->
1743+
B.useAsCString stmtName $ \s ->
1744+
withParamsPrepared params $ \n vs ls fs ->
1745+
c_PQsendQueryPrepared c s n vs ls fs f
17411746

17421747
where
1743-
accum (!a,!b,!c) Nothing = ( Nothing:a
1744-
, 0:b
1745-
, 0:c
1746-
)
1747-
accum (!a,!b,!c) (Just (v, f)) = ( (Just v):a
1748-
, (B.length v):b
1749-
, (toEnum $ fromEnum f):c
1750-
)
1748+
!f = formatToCInt rFmt
17511749

17521750

17531751
-- | Submits a request to obtain information about the specified

0 commit comments

Comments
 (0)