pqi-conformance 0.1.2.1 → 0.1.2.2
raw patch · 3 files changed
+30/−3 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +6/−0
- pqi-conformance.cabal +1/−1
- src/library/Pqi/Conformance/Reference.hs +23/−2
CHANGELOG.md view
@@ -1,3 +1,9 @@+# v0.1.2.2++## Fixes++- Fixed the reference adapter's `ntuples` and `nfields` intermittently returning garbage, which made the differential suite fail correct candidates. `postgresql-libpq` imports `PQntuples` and `PQnfields` as pure functions and lets the resulting thunk escape `withForeignPtr`, so if the result handle got collected before the count was forced, the number was read from memory that `PQclear` had already freed. Both counts are now forced while the handle is still alive.+ # v0.1.2.1 - Fixed the publishing.
pqi-conformance.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: pqi-conformance-version: 0.1.2.1+version: 0.1.2.2 category: Database, PostgreSQL, Testing synopsis: Differential conformance tests for pqi adapters description:
src/library/Pqi/Conformance/Reference.hs view
@@ -9,6 +9,8 @@ where import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified GHC.Exts+import qualified GHC.IO import qualified Pqi import Pqi.Conformance.Prelude @@ -119,8 +121,8 @@ Pqi.resultErrorMessage = LibPQ.resultErrorMessage r, Pqi.resultErrorField = \field -> LibPQ.resultErrorField r (toFieldCode field), Pqi.unsafeFreeResult = LibPQ.unsafeFreeResult r,- Pqi.ntuples = fromRow <$> LibPQ.ntuples r,- Pqi.nfields = fromColumn <$> LibPQ.nfields r,+ Pqi.ntuples = strictly r (fromRow <$> LibPQ.ntuples r),+ Pqi.nfields = strictly r (fromColumn <$> LibPQ.nfields r), Pqi.fname = \column -> LibPQ.fname r (toColumn column), Pqi.fnumber = \name -> fmap fromColumn <$> LibPQ.fnumber r name, Pqi.ftable = \column -> fromOid <$> LibPQ.ftable r (toColumn column),@@ -138,6 +140,25 @@ Pqi.cmdStatus = LibPQ.cmdStatus r, Pqi.cmdTuples = LibPQ.cmdTuples r }++-- | Read a number out of a result handle, forcing it while the handle is still+-- guaranteed to be alive.+--+-- @postgresql-libpq@ imports @PQntuples@ and @PQnfields@ as /pure/ functions+-- and defines the wrappers as @withResult res (return . toRow . c_PQntuples)@,+-- so the C call escapes 'Foreign.ForeignPtr.withForeignPtr' as an unevaluated+-- thunk over the raw @PGresult@ pointer. Should the handle become unreachable+-- before that thunk is forced, its @PQclear@ finalizer has already freed the+-- memory and the number read is garbage — which made the reference disagree+-- with a correct candidate whenever a collection happened to land in the+-- window. Every other accessor is imported in 'IO' and is unaffected.+strictly :: LibPQ.Result -> IO Int32 -> IO Int32+strictly r io = do+ !n <- io+ touch r+ pure n+ where+ touch x = GHC.IO.IO \s -> case GHC.Exts.touch# x s of s' -> (# s', () #) -- | Build a 'Pqi.Cancel' whose field closes over the given -- @postgresql-libpq@ cancellation handle.