Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/fourmolu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: haskell-actions/run-fourmolu@v10
- uses: actions/checkout@v7
- uses: haskell-actions/run-fourmolu@v13
with:
version: "0.15.0.0"
version: "0.19.0.1"
36 changes: 14 additions & 22 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
#
# For more information, see https://github.com/arybczak/haskell-ci
#
# version: 0.19.20260424
# version: 0.19.20260721
#
# REGENDATA ("0.19.20260424",["github","--config=cabal.haskell-ci","cabal.project"])
# REGENDATA ("0.19.20260721",["github","--config=cabal.haskell-ci","cabal.project"])
#
name: Haskell-CI
on:
Expand All @@ -35,7 +35,7 @@ jobs:
timeout-minutes:
60
container:
image: buildpack-deps:jammy
image: buildpack-deps:resolute
services:
postgres:
image: postgres:18
Expand Down Expand Up @@ -71,31 +71,21 @@ jobs:
compilerVersion: 9.6.7
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.4.8
compilerKind: ghc
compilerVersion: 9.4.8
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.2.8
compilerKind: ghc
compilerVersion: 9.2.8
setup-method: ghcup
allow-failure: false
fail-fast: false
steps:
- name: apt-get install
run: |
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
- name: Install GHCup
run: |
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup"
chmod a+x "$HOME/.ghcup/bin/ghcup"
- name: Install cabal-install
run: |
"$HOME/.ghcup/bin/ghcup" install cabal 3.16.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
echo "CABAL=$HOME/.ghcup/bin/cabal-3.16.0.0 -vnormal+nowrap" >> "$GITHUB_ENV"
"$HOME/.ghcup/bin/ghcup" install cabal 3.16.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
echo "CABAL=$HOME/.ghcup/bin/cabal-3.16.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
- name: Install GHC (GHCup)
if: matrix.setup-method == 'ghcup'
run: |
Expand Down Expand Up @@ -148,9 +138,9 @@ jobs:
repository hackage.haskell.org
url: http://hackage.haskell.org/
EOF
if [ $((HCNUMVER >= 90800)) -ne 0 ] ; then echo "semaphore: True" >> $CABAL_CONFIG ; fi
cat >> $CABAL_CONFIG <<EOF
program-default-options
ghc-options: $GHCJOBS +RTS -M3G -RTS
jobs: 4
EOF
cat $CABAL_CONFIG
- name: versions
Expand Down Expand Up @@ -197,10 +187,12 @@ jobs:
echo "packages: ${PKGDIR_hpqtypes}" >> cabal.project
echo "package hpqtypes" >> cabal.project
echo " ghc-options: -Werror=missing-methods -Werror=missing-fields" >> cabal.project
if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo "package hpqtypes" >> cabal.project ; fi
if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo " ghc-options: -Werror=unused-packages" >> cabal.project ; fi
echo "package hpqtypes" >> cabal.project
echo " ghc-options: -Werror=unused-packages" >> cabal.project
echo "package hpqtypes" >> cabal.project
echo " ghc-options: -Werror=incomplete-patterns -Werror=incomplete-uni-patterns" >> cabal.project
if [ $((HCNUMVER < 90800)) -ne 0 ] ; then echo "package hpqtypes" >> cabal.project ; fi
if [ $((HCNUMVER < 90800)) -ne 0 ] ; then echo " ghc-options: -j4" >> cabal.project ; fi
cat >> cabal.project <<EOF
allow-newer: *:base
allow-newer: *:containers
Expand All @@ -221,8 +213,8 @@ jobs:
restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
- name: install dependencies
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only all
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only all
- name: build w/o tests
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
hlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: 'Set up HLint'
uses: haskell-actions/hlint-setup@v2
Expand Down
1 change: 1 addition & 0 deletions .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Replace a $ b $ c with a . b $ c
- group: {name: dollar, enabled: true}

- ignore: {name: "Eta reduce"}
- ignore: {name: "Functor law"}
- ignore: {name: "Redundant do"}
- ignore: {name: "Use <=<"}
Expand Down
111 changes: 111 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,114 @@
# hpqtypes-2.0.0.0 (????-??-??)
* Drop support for GHC < 9.6.
* Drop support for `aeson` < 2.0.
* Remove the bundled `libpqtypes` C library. The library now executes queries
with plain `libpq` and handles the binary transport format itself. The
encoders and decoders are derived from the `postgresql-binary` package.
* Replace per-type format strings with type Oids. The `pqOid` and
`pqArrayOid` methods of `PQFormat` replace `pqFormat`, `pqFormat0` and
`pqVariables`. The `Database.PostgreSQL.PQTypes.Internal.Oid` module
provides constants for built-in types.
* Change the type of `toSQL` to `t -> Maybe Encoding`. An `Encoding` is an
encoded value in the binary wire format. `Nothing` represents NULL. The
`PQDest` type family and `ParamAllocator` are gone.
* Change the type of `fromSQL` to `RowDecoder t`, a monadic parser that
consumes consecutive fields of a query result. You build a decoder of a
compound result from the decoders of its fields. The `PQBase` type family
is gone.
* Remove the `PQFormat` superclass of `FromSQL`.
* Remove the `FromRow` class. The row fetching functions (`foldrDB`,
`foldlDB`, `mapDB_`, `fetchMany`, `fetchMaybe`, `fetchOne`) now take an
explicit `RowDecoder` of a row, e.g. `fetchMany ((,) <$> fromSQL <*> fromSQL)`.
* Row fetching functions no longer compare the width of the query result
with the decoder up front. The number of fields that a `RowDecoder`
consumes is not known statically. When it decodes a row, a decoder that
doesn't match the shape of the result throws `RowLengthMismatch`. In
particular, a fetch from a result with no rows always succeeds.
* Reduce the maximum arity of tuples with a `ToRow` instance from 50 to 10.
To pass a larger set of query parameters, combine rows with the `:++:`
type. It was previously known as `:*:`. The new name avoids a conflict
with `GHC.Generics`.
* Remove the parameter of `QueryResult` along with its `Functor` and
`Foldable` instances. The row fetching functions that take a `RowDecoder`
supersede them.
* Remove support for encoding of composite types along with the `Composite`,
`CompositeRow`, `CompositeFromSQL`, `CompositeToSQL`, `CompositeArray1` and
`CompositeArray2` machinery. The `decodeComposite` combinator decodes
composite types. They no longer need registration, and the `csComposites`
field of `ConnectionSettings` is gone. Decoding of anonymous composite
types is now supported.
* Add `genericDecoder`, which decodes consecutive fields of a row into a
product type with a `Generic` instance, e.g. a whole row into a tuple.
Combined with `decodeComposite`, it gives generic `FromSQL` instances for
product types that correspond to composite types.
* Add `PQFormat`, `ToSQL` and `FromSQL` instances for lists and `Vector`s
that encode and decode PostgreSQL arrays. An array of any type with the
relevant instances can be a query parameter, and plain `fromSQL` fetches
it. A multi-dimensional array is a nested list or `Vector`, and mixed
nesting of lists and `Vector`s works too. `String` still corresponds to
`text` and `[String]` to an array of `text`. The
`Database.PostgreSQL.PQTypes.Array` module is gone. The `fromSQLArray`
method of `FromSQL` decodes arrays, and `fromSQLList` backs the list
instance on top of it. `fromSQLArray` defaults to `decodeArray fromSQL`.
An instance can override it with a faster decoder. Scalar types override
it with the dedicated `decodeScalarArray` combinator, which decodes the
elements with a value decoder directly.
* Remove `ArrayItemError`. An error of an array element decoder now reports
the position of the offending element as the column of its
`ConversionError`.
* Remove `QueryError`. When query execution produced no `PGresult`, the
library threw it. This happened e.g. because the connection died while
the query was sent. Such a failure now throws `LibPQError`.
* Derive the `Show` instances of `HPQTypesError` and `LibPQError`, like
those of the other error types. They now print e.g.
`HPQTypesError "reason"` instead of `HPQTypesError (PostgreSQL): reason`.
* Add the `Database.PostgreSQL.PQTypes.Enum` module with the `SQLEnum` and
`SQLEnumAsText` deriving-via helpers. They map Haskell enumeration types
to values of PostgreSQL enum types, or of other types. A scalar parameter
works against both text and enum columns without a cast. An array is sent
as `text[]` and needs a cast against an enum column, e.g.
`... = ANY($1::my_enum_type[])`.
* Add `FromSQL` and `ToSQL` instances for `Scientific`, mapped to `numeric`.
Add a `ToSQL` instance for `Word`, for symmetry with `Int`. `Int` and
`Word` can't be decoded reliably, because their size depends on the
architecture. Their `FromSQL` instances use `TypeError` and point at
`Int64` and `Word64`.
* Add `FromSQL` and `ToSQL` instances for `IP` and `IPRange` from the
`iproute` package, mapped to the `inet` and `cidr` types respectively. An
`inet` value carries the length of its netmask alongside the address. If
the netmask covers the whole address, the value decodes to a bare `IP`.
Otherwise decoding fails instead of dropping the netmask.
* Add support for range types with `FromSQL` and `ToSQL` instances for
`Range` of `Int32`, `Int64`, `Scientific`, `Day`, `LocalTime` and `UTCTime`.
The SQL types are `int4range`, `int8range`, `numrange`, `daterange`,
`tsrange` and `tstzrange` respectively. The
`Database.PostgreSQL.PQTypes.Range` module defines the `Range` and `Bound`
types, and `Database.PostgreSQL.PQTypes` re-exports them.
* Change the representation of `Interval` to mirror the wire format: three
components (microseconds, days, months) of mutually independent duration.
The type is now opaque. The `iyears`, `imonths`, `idays`, `ihours`,
`iminutes`, `iseconds` and `imicroseconds` functions construct values, and
the `Monoid` instance combines them. The sub-day functions now take
`Int64`. The `Eq` and `Ord` instances compare the same way as the
comparison operators of the server, i.e. by an estimate with a month
converted at 30 days and a day at 24 hours. The `Show` instance shows the
components of the wire format instead of a pretty-printed value.
* Reject the `infinity` and `-infinity` values of `date`, `timestamp`,
`timestamptz` and `interval` at decode time. Previously they decoded as a
date far outside the range that the server accepts. The encoders of `Day`,
`LocalTime` and `UTCTime` now reject a value that doesn't fit the wire
format instead of truncating it. Truncation silently sent a different
date, `infinity` among them.
* When built against `libpq` >= 17, cancellation of a query that an
exception interrupted uses the new cancellation API. If the main
connection is encrypted, the cancellation request travels over an
encrypted connection too.
* Fix unreliable cancellation of a query that an asynchronous exception
interrupted. The server discards a cancellation request that reaches it
before the backend started to execute the query. It doesn't report the
discard in any way. An interrupted thread then waited for the query to run
to completion. The library now repeats the request until the query ends.

# hpqtypes-1.15.0.0 (????-??-??)
* Fix a use-after-free of the buffer that holds the connection string in
`connect`. If an asynchronous exception interrupted `connect`, the
Expand Down
35 changes: 35 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,38 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

--------------------------------------------------------------------------

The modules

Database.PostgreSQL.PQTypes.Internal.Decoding
Database.PostgreSQL.PQTypes.Internal.Encoding
Database.PostgreSQL.PQTypes.Range

are derived from the postgresql-binary package
(https://github.com/nikita-volkov/postgresql-binary), which is distributed
under the following terms:

Copyright (c) 2014, Nikita Volkov

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,26 @@
[![Stackage LTS](https://www.stackage.org/package/hpqtypes/badge/lts)](https://www.stackage.org/lts/package/hpqtypes)
[![Stackage Nightly](https://www.stackage.org/package/hpqtypes/badge/nightly)](https://www.stackage.org/nightly/package/hpqtypes)

Efficient and easy-to-use bindings to (slightly modified) libpqtypes,
libpq extension that adds support for binary transport format and
composite types.
hpqtypes provides efficient bindings to `libpq`. Queries and their results
travel in the binary transport format.

Source code of libpqtypes is bundled along with the bindings.
Main features:

Examples can be found in the [examples](https://github.com/scrive/hpqtypes/tree/master/examples) directory.
* You write a query and its parameters separately. SQL injection is not
possible by construction.
* An asynchronous exception interrupts a running query. The library then
cancels the query on the server too. This feature requires the threaded
runtime.
* The `ToSQL` and `FromSQL` type classes convert between Haskell types and
their SQL counterparts. Composable, monadic `RowDecoder`s decode rows. A
`RowDecoder` compares the SQL type of each column with the expected Haskell
type.
* The library supports arrays, anonymous and user-defined composite types,
PostgreSQL enums and NOTIFY/LISTEN. An array is a plain list or a `Vector`.
A multi-dimensional array is a nested list or `Vector`.

The [examples](https://github.com/scrive/hpqtypes/tree/master/examples)
directory contains examples.

If you upgrade from 1.x, read the
[migration guide](https://github.com/scrive/hpqtypes/blob/master/migration-2.0.md).
Loading
Loading