Skip to content

Commit 8feaea0

Browse files
committed
Introduce on-demand connection acquisition mode
1 parent 203e557 commit 8feaea0

File tree

13 files changed

+540
-371
lines changed

13 files changed

+540
-371
lines changed

.github/workflows/haskell-ci.yml

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
#
99
# For more information, see https://github.com/haskell-CI/haskell-ci
1010
#
11-
# version: 0.19.20250216
11+
# version: 0.19.20250821
1212
#
13-
# REGENDATA ("0.19.20250216",["github","--config=cabal.haskell-ci","cabal.project"])
13+
# REGENDATA ("0.19.20250821",["github","--config=cabal.haskell-ci","cabal.project"])
1414
#
1515
name: Haskell-CI
1616
on:
@@ -38,24 +38,29 @@ jobs:
3838
strategy:
3939
matrix:
4040
include:
41-
- compiler: ghc-9.12.1
41+
- compiler: ghc-9.14.0.20250819
4242
compilerKind: ghc
43-
compilerVersion: 9.12.1
43+
compilerVersion: 9.14.0.20250819
44+
setup-method: ghcup-prerelease
45+
allow-failure: false
46+
- compiler: ghc-9.12.2
47+
compilerKind: ghc
48+
compilerVersion: 9.12.2
4449
setup-method: ghcup
4550
allow-failure: false
46-
- compiler: ghc-9.10.1
51+
- compiler: ghc-9.10.2
4752
compilerKind: ghc
48-
compilerVersion: 9.10.1
53+
compilerVersion: 9.10.2
4954
setup-method: ghcup
5055
allow-failure: false
5156
- compiler: ghc-9.8.4
5257
compilerKind: ghc
5358
compilerVersion: 9.8.4
5459
setup-method: ghcup
5560
allow-failure: false
56-
- compiler: ghc-9.6.6
61+
- compiler: ghc-9.6.7
5762
compilerKind: ghc
58-
compilerVersion: 9.6.6
63+
compilerVersion: 9.6.7
5964
setup-method: ghcup
6065
allow-failure: false
6166
- compiler: ghc-9.4.8
@@ -68,16 +73,6 @@ jobs:
6873
compilerVersion: 9.2.8
6974
setup-method: ghcup
7075
allow-failure: false
71-
- compiler: ghc-9.0.2
72-
compilerKind: ghc
73-
compilerVersion: 9.0.2
74-
setup-method: ghcup
75-
allow-failure: false
76-
- compiler: ghc-8.10.7
77-
compilerKind: ghc
78-
compilerVersion: 8.10.7
79-
setup-method: ghcup
80-
allow-failure: false
8176
fail-fast: false
8277
steps:
8378
- name: apt-get install
@@ -87,12 +82,12 @@ jobs:
8782
- name: Install GHCup
8883
run: |
8984
mkdir -p "$HOME/.ghcup/bin"
90-
curl -sL https://downloads.haskell.org/ghcup/0.1.30.0/x86_64-linux-ghcup-0.1.30.0 > "$HOME/.ghcup/bin/ghcup"
85+
curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup"
9186
chmod a+x "$HOME/.ghcup/bin/ghcup"
9287
- name: Install cabal-install
9388
run: |
94-
"$HOME/.ghcup/bin/ghcup" install cabal 3.12.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
95-
echo "CABAL=$HOME/.ghcup/bin/cabal-3.12.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
89+
"$HOME/.ghcup/bin/ghcup" install cabal 3.16.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
90+
echo "CABAL=$HOME/.ghcup/bin/cabal-3.16.0.0 -vnormal+nowrap" >> "$GITHUB_ENV"
9691
- name: Install GHC (GHCup)
9792
if: matrix.setup-method == 'ghcup'
9893
run: |
@@ -107,6 +102,21 @@ jobs:
107102
HCKIND: ${{ matrix.compilerKind }}
108103
HCNAME: ${{ matrix.compiler }}
109104
HCVER: ${{ matrix.compilerVersion }}
105+
- name: Install GHC (GHCup prerelease)
106+
if: matrix.setup-method == 'ghcup-prerelease'
107+
run: |
108+
"$HOME/.ghcup/bin/ghcup" config add-release-channel prereleases
109+
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
110+
HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
111+
HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
112+
HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
113+
echo "HC=$HC" >> "$GITHUB_ENV"
114+
echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
115+
echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
116+
env:
117+
HCKIND: ${{ matrix.compilerKind }}
118+
HCNAME: ${{ matrix.compiler }}
119+
HCVER: ${{ matrix.compilerVersion }}
110120
- name: Set PATH and environment variables
111121
run: |
112122
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
@@ -117,7 +127,7 @@ jobs:
117127
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
118128
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
119129
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
120-
echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
130+
if [ $((HCNUMVER >= 91400)) -ne 0 ] ; then echo "HEADHACKAGE=true" >> "$GITHUB_ENV" ; else echo "HEADHACKAGE=false" >> "$GITHUB_ENV" ; fi
121131
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
122132
env:
123133
HCKIND: ${{ matrix.compilerKind }}
@@ -145,6 +155,18 @@ jobs:
145155
repository hackage.haskell.org
146156
url: http://hackage.haskell.org/
147157
EOF
158+
if $HEADHACKAGE; then
159+
cat >> $CABAL_CONFIG <<EOF
160+
repository head.hackage.ghc.haskell.org
161+
url: https://ghc.gitlab.haskell.org/head.hackage/
162+
secure: True
163+
root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d
164+
26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329
165+
f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89
166+
key-threshold: 3
167+
active-repositories: hackage.haskell.org, head.hackage.ghc.haskell.org:override
168+
EOF
169+
fi
148170
cat >> $CABAL_CONFIG <<EOF
149171
program-default-options
150172
ghc-options: $GHCJOBS +RTS -M3G -RTS
@@ -193,12 +215,19 @@ jobs:
193215
touch cabal.project.local
194216
echo "packages: ${PKGDIR_hpqtypes}" >> cabal.project
195217
echo "package hpqtypes" >> cabal.project
196-
echo " ghc-options: -Werror=missing-methods" >> cabal.project
218+
echo " ghc-options: -Werror=missing-methods -Werror=missing-fields" >> cabal.project
219+
if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo "package hpqtypes" >> cabal.project ; fi
220+
if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo " ghc-options: -Werror=unused-packages" >> cabal.project ; fi
221+
echo "package hpqtypes" >> cabal.project
222+
echo " ghc-options: -Werror=incomplete-patterns -Werror=incomplete-uni-patterns" >> cabal.project
197223
cat >> cabal.project <<EOF
198224
allow-newer: *:base
199225
allow-newer: *:ghc-prim
200226
allow-newer: *:template-haskell
201227
EOF
228+
if $HEADHACKAGE; then
229+
echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> cabal.project
230+
fi
202231
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(hpqtypes)$/; }' >> cabal.project.local
203232
cat cabal.project
204233
cat cabal.project.local

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# hpqtypes-1.13.0.0 (2025-??-??)
2+
* Drop support for GHC < 9.2.
23
* Include time spent executing queries in `ConnectionStats`.
34
* Add `initialConnectionStats`.
5+
* Introduce on-demand connection acquisition mode.
46

57
# hpqtypes-1.12.0.0 (2024-03-18)
68
* Drop support for GHC 8.8.

hpqtypes.cabal

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ author: Scrive AB
2121
maintainer: Andrzej Rybczak <andrzej@rybczak.net>
2222
copyright: Scrive AB
2323
category: Database
24-
tested-with: GHC == { 8.10.7, 9.0.2, 9.2.8, 9.4.8, 9.6.6, 9.8.4, 9.10.1, 9.12.1 }
24+
tested-with: GHC == { 9.2.8, 9.4.8, 9.6.7, 9.8.4, 9.10.2, 9.12.2, 9.14.1 }
2525

2626
extra-source-files: README.md
2727
, CHANGELOG.md
@@ -93,12 +93,11 @@ library
9393
, Database.PostgreSQL.PQTypes.Internal.C.Interface
9494
, Database.PostgreSQL.PQTypes.Internal.C.Get
9595

96-
build-depends: base >= 4.14 && < 5
96+
build-depends: base >= 4.16 && < 5
9797
, text >= 0.11
9898
, aeson >= 1.0
9999
, async >= 2.1.1.1
100100
, bytestring >= 0.9
101-
, semigroups >= 0.16
102101
, time >= 1.4
103102
, vector >= 0.10
104103
, transformers-base >= 0.4
@@ -117,7 +116,7 @@ library
117116

118117
hs-source-dirs: src
119118

120-
ghc-options: -Wall -Wprepositive-qualified-module
119+
ghc-options: -Wall -Werror=prepositive-qualified-module
121120

122121
include-dirs: libpqtypes/src
123122

@@ -173,7 +172,7 @@ library
173172

174173
test-suite hpqtypes-tests
175174
type: exitcode-stdio-1.0
176-
ghc-options: -Wall -Wprepositive-qualified-module -threaded
175+
ghc-options: -Wall -Werror=prepositive-qualified-module -threaded
177176

178177
hs-source-dirs: test
179178
main-is: Main.hs
@@ -206,7 +205,6 @@ test-suite hpqtypes-tests
206205
, text-show
207206
, time >= 1.4
208207
, transformers-base >= 0.4
209-
, unordered-containers
210208
, vector
211209
, uuid-types
212210

src/Database/PostgreSQL/PQTypes/Class.hs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,34 @@ class (Applicative m, Monad m) => MonadDB m where
3030
-- given name.
3131
runPreparedQuery :: (HasCallStack, IsSQL sql) => QueryName -> sql -> m Int
3232

33-
-- | Get last SQL query that was executed.
34-
getLastQuery :: m SomeSQL
33+
-- | Get last SQL query that was executed and ID of the server process
34+
-- attached to the session that executed it.
35+
getLastQuery :: m (BackendPid, SomeSQL)
3536

3637
-- | Subsequent queries in the callback do not alter the result of
3738
-- 'getLastQuery'.
3839
withFrozenLastQuery :: m a -> m a
3940

40-
-- | Get ID of the server process attached to the current session.
41-
getBackendPid :: m BackendPid
42-
4341
-- | Get current connection statistics.
44-
getConnectionStats :: HasCallStack => m ConnectionStats
42+
getConnectionStats :: m ConnectionStats
4543

4644
-- | Get current query result.
4745
getQueryResult :: FromRow row => m (Maybe (QueryResult row))
4846

4947
-- | Clear current query result.
5048
clearQueryResult :: m ()
5149

52-
-- | Get current transaction settings.
53-
getTransactionSettings :: m TransactionSettings
50+
-- | Get current connection acquisition mode.
51+
getConnectionAcquisitionMode :: HasCallStack => m ConnectionAcquisitionMode
52+
53+
-- | Acquire and hold a connection with a given isolation level and
54+
-- permissions. If the connection is already held, nothing happens.
55+
acquireAndHoldConnection :: HasCallStack => IsolationLevel -> Permissions -> m ()
5456

55-
-- | Set transaction settings to supplied ones. Note that it
56-
-- won't change any properties of currently running transaction,
57-
-- only the subsequent ones.
58-
setTransactionSettings :: TransactionSettings -> m ()
57+
-- | Unsafely switch to the 'AcquireOnDemand' mode. This function is unsafe
58+
-- because if a connection is already held, the transaction in progress is
59+
-- commited, so atomicity guarantee is lost.
60+
unsafeAcquireOnDemandConnection :: HasCallStack => m ()
5961

6062
-- | Attempt to receive a notification from the server. This
6163
-- function waits until a notification arrives or specified
@@ -72,15 +74,15 @@ class (Applicative m, Monad m) => MonadDB m where
7274
-- for further info), therefore calling this function within
7375
-- a transaction block will return 'Just' only if notifications
7476
-- were received before the transaction began.
75-
getNotification :: Int -> m (Maybe Notification)
77+
getNotification :: HasCallStack => Int -> m (Maybe Notification)
7678

7779
-- | Execute supplied monadic action with new connection
7880
-- using current connection source and transaction settings.
7981
--
8082
-- Particularly useful when you want to spawn a new thread, but
8183
-- do not want the connection in child thread to be shared with
8284
-- the parent one.
83-
withNewConnection :: m a -> m a
85+
withNewConnection :: HasCallStack => m a -> m a
8486

8587
-- | Generic, overlappable instance.
8688
instance
@@ -97,11 +99,11 @@ instance
9799
runPreparedQuery name = withFrozenCallStack $ lift . runPreparedQuery name
98100
getLastQuery = lift getLastQuery
99101
withFrozenLastQuery m = controlT $ \run -> withFrozenLastQuery (run m)
100-
getBackendPid = lift getBackendPid
101-
getConnectionStats = withFrozenCallStack $ lift getConnectionStats
102+
getConnectionStats = lift getConnectionStats
102103
getQueryResult = lift getQueryResult
103104
clearQueryResult = lift clearQueryResult
104-
getTransactionSettings = lift getTransactionSettings
105-
setTransactionSettings = lift . setTransactionSettings
105+
getConnectionAcquisitionMode = lift getConnectionAcquisitionMode
106+
acquireAndHoldConnection isoLevel = lift . acquireAndHoldConnection isoLevel
107+
unsafeAcquireOnDemandConnection = lift unsafeAcquireOnDemandConnection
106108
getNotification = lift . getNotification
107109
withNewConnection m = controlT $ \run -> withNewConnection (run m)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
module Database.PostgreSQL.PQTypes.Internal.BackendPid
22
( BackendPid (..)
3+
, noBackendPid
34
) where
45

56
-- | Process ID of the server process attached to the current session.
67
newtype BackendPid = BackendPid Int
78
deriving newtype (Eq, Ord, Show)
9+
10+
noBackendPid :: BackendPid
11+
noBackendPid = BackendPid 0

0 commit comments

Comments
 (0)