Skip to content

Commit

Permalink
Add pipeline mode API
Browse files Browse the repository at this point in the history
https://www.postgresql.org/docs/current/libpq-pipeline-mode.html

- Test pipelineStatus in smoke test
- Test pipeline mode API
  • Loading branch information
robx authored and phadej committed Aug 24, 2024
1 parent fee482e commit 490b9ca
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 41 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ jobs:
chmod a+x "$HOME/.ghcup/bin/ghcup"
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
"$HOME/.ghcup/bin/ghcup" install cabal 3.12.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
apt-get update
apt-get install -y libpq-dev
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
Expand Down Expand Up @@ -233,7 +235,7 @@ jobs:
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
- name: tests
run: |
$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all
$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
- name: cabal check
run: |
cd ${PKGDIR_postgresql_libpq} || false
Expand All @@ -244,7 +246,7 @@ jobs:
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
$CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
- name: unconstrained build
run: |
rm -f cabal.project.local
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/simple.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
username: ci
password: sw0rdfish
database: test
postgres-version: "14"

- name: Checkout
uses: actions/checkout@v4
Expand Down
5 changes: 1 addition & 4 deletions cabal.haskell-ci
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
branches: master
postgresql: True

-- due build-type: Custom
test-output-direct: False
haddock-components: libs
apt: libpq-dev

constraint-set pkg-config
constraints: postgresql-libpq +use-pkg-config
16 changes: 8 additions & 8 deletions postgresql-libpq-configure/configure
Original file line number Diff line number Diff line change
Expand Up @@ -3570,7 +3570,7 @@ then :
ac_cv_POSTGRESQL_LIBS="$POSTGRESQL_LIBS"
fi
postgresql_version_req=10.22
postgresql_version_req=14.12
found_postgresql="no"
POSTGRESQL_VERSION=""
Expand Down Expand Up @@ -3850,8 +3850,8 @@ do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_PG_CONFIG="$as_dir$ac_prog$ac_exec_ext"
as_fn_executable_p "$ac_path_PG_CONFIG" || continue
ac_cv_path_PG_CONFIG="";$ac_path_PG_CONFIG --includedir > /dev/null \
&& ac_cv_path_PG_CONFIG=$ac_path_PG_CONFIG ac_path_PG_CONFIG_found=:
ac_cv_path_PG_CONFIG="";"$ac_path_PG_CONFIG" --includedir > /dev/null \
&& ac_cv_path_PG_CONFIG="$ac_path_PG_CONFIG" ac_path_PG_CONFIG_found=:
$ac_path_PG_CONFIG_found && break 3
done
done
Expand All @@ -3867,7 +3867,7 @@ fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_PG_CONFIG" >&5
printf "%s\n" "$ac_cv_path_PG_CONFIG" >&6; }
PG_CONFIG=$ac_cv_path_PG_CONFIG
PG_CONFIG="$ac_cv_path_PG_CONFIG"
if test "X$PG_CONFIG" = "X"
then :
break
Expand All @@ -3879,7 +3879,7 @@ if test ${ac_cv_POSTGRESQL_CPPFLAGS+y}
then :
printf %s "(cached) " >&6
else $as_nop
ac_cv_POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes
ac_cv_POSTGRESQL_CPPFLAGS="-I`"$PG_CONFIG" --includedir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_POSTGRESQL_CPPFLAGS" >&5
printf "%s\n" "$ac_cv_POSTGRESQL_CPPFLAGS" >&6; }
Expand All @@ -3895,7 +3895,7 @@ if test ${ac_cv_POSTGRESQL_LDFLAGS+y}
then :
printf %s "(cached) " >&6
else $as_nop
ac_cv_POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes
ac_cv_POSTGRESQL_LDFLAGS="-L`"$PG_CONFIG" --libdir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_POSTGRESQL_LDFLAGS" >&5
printf "%s\n" "$ac_cv_POSTGRESQL_LDFLAGS" >&6; }
Expand Down Expand Up @@ -3924,7 +3924,7 @@ then :
printf %s "(cached) " >&6
else $as_nop
ac_cv_POSTGRESQL_VERSION=`$PG_CONFIG --version | sed "s/^PostgreSQL[[:space:]][[:space:]]*\([0-9.][0-9.]*\).*/\1/"` \
ac_cv_POSTGRESQL_VERSION=`"$PG_CONFIG" --version | sed "s/^PostgreSQL[[:space:]][[:space:]]*\([0-9.][0-9.]*\).*/\1/"` \
|| _AX_LIB_POSTGRESQL_OLD_fail=yes
fi
Expand Down Expand Up @@ -3982,7 +3982,7 @@ x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version
printf "%s\n" "$found_postgresql_req_version" >&6; }
fi
if test "Xfound_postgresql_req_version" = "Xno"
if test "X$found_postgresql_req_version" = "Xno"
then :
break
fi
Expand Down
2 changes: 1 addition & 1 deletion postgresql-libpq-configure/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ AC_CONFIG_MACRO_DIRS([m4])
AC_PROG_CC
AC_PROG_SED

AX_LIB_POSTGRESQL([10.22])
AX_LIB_POSTGRESQL([14.12])

POSTGRESQL_EXTRA_LIBS="pq"
POSTGRESQL_LIBDIR=$(echo "$POSTGRESQL_LDFLAGS"|$SED 's/-L//')
Expand Down
14 changes: 7 additions & 7 deletions postgresql-libpq-configure/m4/ax_lib_postgresql.m4
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,19 @@ AC_DEFUN([_AX_LIB_POSTGRESQL_OLD],[
while true; do
AC_CACHE_CHECK([for the pg_config program], [ac_cv_path_PG_CONFIG],
[AC_PATH_PROGS_FEATURE_CHECK([PG_CONFIG], [pg_config],
[[ac_cv_path_PG_CONFIG="";$ac_path_PG_CONFIG --includedir > /dev/null \
&& ac_cv_path_PG_CONFIG=$ac_path_PG_CONFIG ac_path_PG_CONFIG_found=:]],
[[ac_cv_path_PG_CONFIG="";"$ac_path_PG_CONFIG" --includedir > /dev/null \
&& ac_cv_path_PG_CONFIG="$ac_path_PG_CONFIG" ac_path_PG_CONFIG_found=:]],
[ac_cv_path_PG_CONFIG=""])])
PG_CONFIG=$ac_cv_path_PG_CONFIG
PG_CONFIG="$ac_cv_path_PG_CONFIG"
AS_IF([test "X$PG_CONFIG" = "X"],[break])
AC_CACHE_CHECK([for the PostgreSQL libraries CPPFLAGS],[ac_cv_POSTGRESQL_CPPFLAGS],
[ac_cv_POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes])
[ac_cv_POSTGRESQL_CPPFLAGS="-I`"$PG_CONFIG" --includedir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes])
AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break])
POSTGRESQL_CPPFLAGS="$ac_cv_POSTGRESQL_CPPFLAGS"
AC_CACHE_CHECK([for the PostgreSQL libraries LDFLAGS],[ac_cv_POSTGRESQL_LDFLAGS],
[ac_cv_POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes])
[ac_cv_POSTGRESQL_LDFLAGS="-L`"$PG_CONFIG" --libdir`" || _AX_LIB_POSTGRESQL_OLD_fail=yes])
AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break])
POSTGRESQL_LDFLAGS="$ac_cv_POSTGRESQL_LDFLAGS"
Expand All @@ -80,7 +80,7 @@ AC_DEFUN([_AX_LIB_POSTGRESQL_OLD],[
AC_CACHE_CHECK([for the PostgreSQL version],[ac_cv_POSTGRESQL_VERSION],
[
ac_cv_POSTGRESQL_VERSION=`$PG_CONFIG --version | sed "s/^PostgreSQL[[[:space:]]][[[:space:]]]*\([[0-9.]][[0-9.]]*\).*/\1/"` \
ac_cv_POSTGRESQL_VERSION=`"$PG_CONFIG" --version | sed "s/^PostgreSQL[[[:space:]]][[[:space:]]]*\([[0-9.]][[0-9.]]*\).*/\1/"` \
|| _AX_LIB_POSTGRESQL_OLD_fail=yes
])
AS_IF([test "X$_AX_LIB_POSTGRESQL_OLD_fail" = "Xyes"],[break])
Expand All @@ -96,7 +96,7 @@ AC_DEFUN([_AX_LIB_POSTGRESQL_OLD],[
[found_postgresql_req_version=yes],[found_postgresql_req_version=no])
AC_MSG_RESULT([$found_postgresql_req_version])
])
AS_IF([test "Xfound_postgresql_req_version" = "Xno"],[break])
AS_IF([test "X$found_postgresql_req_version" = "Xno"],[break])
found_postgresql="yes"
break
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.4
name: postgresql-libpq-configure
version: 0.10
version: 0.11
synopsis: low-level binding to libpq: configure based provider
description:
This is a binding to libpq: the C application
Expand Down
4 changes: 2 additions & 2 deletions postgresql-libpq-pkgconfig/postgresql-libpq-pkgconfig.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.4
name: postgresql-libpq-pkgconfig
version: 0.10
version: 0.11
synopsis: low-level binding to libpq: pkg-config based provider
description:
This is a binding to libpq: the C application
Expand Down Expand Up @@ -35,7 +35,7 @@ extra-source-files: CHANGELOG.md
library
default-language: Haskell2010
build-depends: base <5
pkgconfig-depends: libpq >=10.22
pkgconfig-depends: libpq >=14.12

source-repository head
type: git
Expand Down
6 changes: 3 additions & 3 deletions postgresql-libpq.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.4
name: postgresql-libpq
version: 0.10.2.0
version: 0.11.0.0
synopsis: low-level binding to libpq
description:
This is a binding to libpq: the C application
Expand Down Expand Up @@ -81,10 +81,10 @@ library
build-depends: Win32 >=2.2.0.2 && <2.15

if flag(use-pkg-config)
build-depends: postgresql-libpq-pkgconfig ^>=0.10
build-depends: postgresql-libpq-pkgconfig ^>=0.11

else
build-depends: postgresql-libpq-configure ^>=0.10
build-depends: postgresql-libpq-configure ^>=0.11

build-tool-depends: hsc2hs:hsc2hs >=0.68.5

Expand Down
63 changes: 63 additions & 0 deletions src/Database/PostgreSQL/LibPQ.hs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ module Database.PostgreSQL.LibPQ
, FlushStatus(..)
, flush

-- * Pipeline Mode
-- $pipelinemode
, PipelineStatus(..)
, pipelineStatus
, enterPipelineMode
, exitPipelineMode
, pipelineSync
, sendFlushRequest

-- * Cancelling Queries in Progress
-- $cancel
, Cancel
Expand Down Expand Up @@ -1640,6 +1649,60 @@ flush connection =
1 -> return FlushWriting
_ -> return FlushFailed

-- $pipelinemode
-- These functions control behaviour in pipeline mode.
--
-- Pipeline mode allows applications to send a query
-- without having to read the result of the previously
-- sent query. Taking advantage of the pipeline mode,
-- a client will wait less for the server, since multiple
-- queries/results can be sent/received in
-- a single network transaction.

-- | Returns the current pipeline mode status of the libpq connection.
--
-- @since 0.11.0.0
pipelineStatus :: Connection
-> IO PipelineStatus
pipelineStatus connection = do
stat <- withConn connection c_PQpipelineStatus
maybe
(fail $ "Unknown pipeline status " ++ show stat)
return
(fromCInt stat)

-- | Causes a connection to enter pipeline mode if it is currently idle or already in pipeline mode.
--
-- @since 0.11.0.0
enterPipelineMode :: Connection
-> IO Bool
enterPipelineMode connection =
enumFromConn connection c_PQenterPipelineMode

-- | Causes a connection to exit pipeline mode if it is currently in pipeline mode with an empty queue and no pending results.
--
-- @since 0.11.0.0
exitPipelineMode :: Connection
-> IO Bool
exitPipelineMode connection =
enumFromConn connection c_PQexitPipelineMode

-- | Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer. This serves as the delimiter of an implicit transaction and an error recovery point>
--
-- @since 0.11.0.0
pipelineSync :: Connection
-> IO Bool
pipelineSync connection =
enumFromConn connection c_PQpipelineSync

-- | Sends a request for the server to flush its output buffer.
--
-- @since 0.11.0.0
sendFlushRequest :: Connection
-> IO Bool
sendFlushRequest connection =
enumFromConn connection c_PQsendFlushRequest


-- $cancel
-- A client application can request cancellation of a command that is
Expand Down
64 changes: 52 additions & 12 deletions src/Database/PostgreSQL/LibPQ/Enums.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,42 @@ data ExecStatus
| NonfatalError -- ^ A nonfatal error (a notice or
-- warning) occurred.
| FatalError -- ^ A fatal error occurred.
| SingleTuple -- ^ The PGresult contains a single result tuple
| SingleTuple -- ^ The 'Result' contains a single result tuple
-- from the current command. This status occurs
-- only when single-row mode has been selected
-- for the query.

| PipelineSync -- ^ The 'Result' represents a synchronization
-- point in pipeline mode, requested by
-- 'pipelineSync'. This status occurs only
-- when pipeline mode has been selected.
--
-- @since 0.11.0.0

| PipelineAbort -- ^ The 'Result' represents a pipeline that
-- has received an error from the server.
-- 'getResult' must be called repeatedly,
-- and each time it will return this status
-- code until the end of the current pipeline,
-- at which point it will return 'PipelineSync'
-- and normal processing can resume.
--
-- @since 0.11.0.0
deriving (Eq, Show)

instance FromCInt ExecStatus where
fromCInt (#const PGRES_EMPTY_QUERY) = Just EmptyQuery
fromCInt (#const PGRES_COMMAND_OK) = Just CommandOk
fromCInt (#const PGRES_TUPLES_OK) = Just TuplesOk
fromCInt (#const PGRES_COPY_OUT) = Just CopyOut
fromCInt (#const PGRES_COPY_IN) = Just CopyIn
fromCInt (#const PGRES_COPY_BOTH) = Just CopyBoth
fromCInt (#const PGRES_BAD_RESPONSE) = Just BadResponse
fromCInt (#const PGRES_NONFATAL_ERROR) = Just NonfatalError
fromCInt (#const PGRES_FATAL_ERROR) = Just FatalError
fromCInt (#const PGRES_SINGLE_TUPLE) = Just SingleTuple
fromCInt (#const PGRES_EMPTY_QUERY) = Just EmptyQuery
fromCInt (#const PGRES_COMMAND_OK) = Just CommandOk
fromCInt (#const PGRES_TUPLES_OK) = Just TuplesOk
fromCInt (#const PGRES_COPY_OUT) = Just CopyOut
fromCInt (#const PGRES_COPY_IN) = Just CopyIn
fromCInt (#const PGRES_COPY_BOTH) = Just CopyBoth
fromCInt (#const PGRES_BAD_RESPONSE) = Just BadResponse
fromCInt (#const PGRES_NONFATAL_ERROR) = Just NonfatalError
fromCInt (#const PGRES_FATAL_ERROR) = Just FatalError
fromCInt (#const PGRES_SINGLE_TUPLE) = Just SingleTuple
fromCInt (#const PGRES_PIPELINE_SYNC) = Just PipelineSync
fromCInt (#const PGRES_PIPELINE_ABORTED) = Just PipelineAbort
fromCInt _ = Nothing

instance ToCInt ExecStatus where
Expand All @@ -67,6 +86,8 @@ instance ToCInt ExecStatus where
toCInt NonfatalError = (#const PGRES_NONFATAL_ERROR)
toCInt FatalError = (#const PGRES_FATAL_ERROR)
toCInt SingleTuple = (#const PGRES_SINGLE_TUPLE)
toCInt PipelineSync = (#const PGRES_PIPELINE_SYNC)
toCInt PipelineAbort = (#const PGRES_PIPELINE_ABORTED)


data FieldCode
Expand Down Expand Up @@ -230,7 +251,7 @@ instance FromCInt ConnStatus where
fromCInt (#const CONNECTION_SSL_STARTUP) = return ConnectionSSLStartup
-- fromCInt (#const CONNECTION_NEEDED) = return ConnectionNeeded
fromCInt _ = Nothing


data TransactionStatus
= TransIdle -- ^ currently idle
Expand Down Expand Up @@ -263,6 +284,25 @@ instance FromCInt Format where
fromCInt 1 = Just Binary
fromCInt _ = Nothing


-- |
--
-- @since 0.11.0.0
data PipelineStatus
= PipelineOn -- ^ The 'Connection' is in pipeline mode.
| PipelineOff -- ^ The 'Connection' is /not/ in pipeline mode.
| PipelineAborted -- ^ The 'Connection' is in pipeline mode and an error
-- occurred while processing the current pipeline. The
-- aborted flag is cleared when 'getResult' returns a
-- result with status 'PipelineSync'.
deriving (Eq, Show)

instance FromCInt PipelineStatus where
fromCInt (#const PQ_PIPELINE_ON) = return PipelineOn
fromCInt (#const PQ_PIPELINE_OFF) = return PipelineOff
fromCInt (#const PQ_PIPELINE_ABORTED) = return PipelineAborted
fromCInt _ = Nothing

-------------------------------------------------------------------------------
-- System.IO enumerations
-------------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 490b9ca

Please sign in to comment.