Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c1f31ce
Try a new kind of very specialized parser for small types
mzabani Aug 8, 2026
54568cd
Post-rebase fixing
mzabani Aug 12, 2026
aae7968
More specialized instances, more confirmation of benefits
mzabani Aug 12, 2026
3a8976f
Specialized instance for UTCTime => clear benefits once again
mzabani Aug 12, 2026
cfe5355
Tidy up a bit
mzabani Aug 12, 2026
dae7d49
Slightly better understanding of inlining, clearer inlining boundaries
mzabani Aug 13, 2026
f3e9789
Add `inlinedSingleFieldDecoder`
mzabani Aug 13, 2026
ec02583
More comprehensive coverage of types in benchmarks, more specialized …
mzabani Aug 14, 2026
a91c474
Tests for non-specialized field decoders
mzabani Aug 14, 2026
7ed61d0
Tidy up GHC Core
mzabani Aug 14, 2026
8092870
Overlapping Maybe instances do help with the inlined row decoder's pe…
mzabani Aug 15, 2026
d93d721
Very experimental change with `Maybe a` instances
mzabani Aug 16, 2026
1d6df11
A separate field in FieldDecoder for what to decode NULL to
mzabani Aug 17, 2026
4f08722
Try to improve the code, but inlining got worse
mzabani Aug 18, 2026
2f8bf5d
Some memory usage improvements
mzabani Aug 19, 2026
e94adeb
Float decodesSqlNullTo outside and add strictness for better inlining
mzabani Aug 19, 2026
25a04cc
Tidy up, a few more INLINE pragmas
mzabani Aug 19, 2026
6407110
TODOs in the code
mzabani Aug 19, 2026
3c85cec
Trying a specialized notConst method
mzabani Aug 20, 2026
db901f0
Do the JSON types, but hpgsql-simple-compat will break
mzabani Aug 20, 2026
e2eb282
Create new strict and lazy ByteString-like PinnedByteArray types
mzabani Aug 14, 2026
2327091
Stop inlining aggressively in Generically derived row decoders, add a…
mzabani Aug 23, 2026
08ca14e
Don't use inlined row decoders for Tuples
mzabani Aug 23, 2026
7b70240
Update TODO
mzabani Aug 23, 2026
69e89d6
Stop exposing performance-oriented FromPgField methods
mzabani Aug 23, 2026
695dedb
Document why PinnedByteArray
mzabani Aug 23, 2026
e65120a
Custom conversion from PinnedByteArray to Text
mzabani Aug 23, 2026
eb29609
Post-rebase adjustments
mzabani Aug 25, 2026
10f24e2
Document row decoders
mzabani Aug 25, 2026
7530b46
Add benchmark for `singleField fieldDecoder` row decoders
mzabani Aug 25, 2026
b9e2c42
Allocate new buffers with smaller size after extracting a message
mzabani Aug 25, 2026
c381fbd
More things to check in TODO
mzabani Aug 25, 2026
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
2 changes: 1 addition & 1 deletion Runfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ tests:
if [ -n "$NIX" ]; then
nix-build --no-out-link -A "testsPg${pg}" --argstr hspecArgs "$TARGS"
else
cabal build hpgsql-tests hpgsql-simple-compat-tests
cabal build hpgsql-tests # hpgsql-simple-compat-tests
nix-shell -A "shellPg${pg}" ./default.nix --run "./scripts/run-tests-db-internal.sh $TARGS"
fi
done
Expand Down
14 changes: 14 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
- Check that users can define their own types and create FromPgField instances that derive performant instances. Do they override the specialized methods? How do they do that?
- Expose a `PinnedByteArray` with `toByteString` to users, move current module to PinnedByteArray.Internal
- Test both `singleField fieldDecoder` and `singleFieldRowDecoder` for every type in our tests.
- Do _not_ expose new FromPgField methods. Add new EncodingInternal module, instead.
- Check that the non-exposed methods are safe wrt bytearray bounds access by construction, and users can't break that. If that's true, we can omit bounds checks in our row decoding, making row decoders smaller and maybe faster.
- Some types might still not derive specialized row decoders
- "Oh no! No colInfo here.. what do we do!?" in hpgsql-simple-compat. This might require a big rethinking of things..
- Double-check which row encoders we want to use the inlined versions for and which we don't. Tuples?
- Text internals might be easier to use now?
- Expose in the FromPgField class two new methods.. inlined and non inlined row decoders with/without bounds checks. Use with-bounds-checks for MonadicRowDecoder, and without-bounds-checks for regular row decoder, because the latter checks type oids
- The specialized row decoders are already a problem here! They don't check type OIDs and can read bytes partially. We should ensure this mismatch is not possible.
- Is `notInlinedSingleFieldRowDecoder` worth keeping? The Generically derived decoder is almost as fast. Maybe for types that aren't records it's a different story, though?
- Check that we're not holding on to internal buffers when Record fields being materialized into aren't strict
- Write property-based tests for PinnedByteArray functions
1 change: 1 addition & 0 deletions hpgsql-benchmarks/hpgsql-benchmarks.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ executable hpgsql-benchmarks
, hspec-expectations
, postgresql-simple
, resourcet
, scientific
, statistics
, stm
, streaming
Expand Down
87 changes: 67 additions & 20 deletions hpgsql-benchmarks/src/Main.hs

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions hpgsql-simple-compat/src/Database/PostgreSQL/Simple/FromField.hs
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,13 @@ class FromField a where
let dec = Hpgsql.fieldDecoder
in \f ->
if Hpgsql.allowedPgTypes dec f
then \mbs -> Conversion $ \_encCtx -> case Hpgsql.fieldValueDecoder dec f mbs of
Right v -> Ok v
Left err -> Errors [toException $ userError err]
then \mbs -> Conversion $ \_encCtx -> case mbs of
Nothing -> case dec.decodesSqlNullTo of
Left err -> Errors [toException $ userError err]
Right v -> Ok v
Just bs -> case Hpgsql.fieldValueDecoder dec f bs of
Right v -> Ok v
Left err -> Errors [toException $ userError err]
else \_ -> Conversion $ \_encCtx -> Errors [toException $ userError "Invalid type OID for FromField instance"]

instance FromField ()
Expand Down
21 changes: 16 additions & 5 deletions hpgsql-simple-compat/src/Database/PostgreSQL/Simple/HpgsqlUtils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,29 @@ type FieldParser a = Field -> Maybe ByteString -> Conversion a
toHpgsqlFieldDecoder :: FieldParser a -> FieldDecoder a
toHpgsqlFieldDecoder fp =
FieldDecoder
{ fieldValueDecoder = \colInfo mbs ->
let valConv = fp colInfo mbs
{ fieldValueDecoder = \colInfo bs ->
let valConv = fp colInfo (Just bs)
in case runConversion valConv colInfo.encodingContext of
Ok v -> Right v
Errors errs -> Left (show errs),
decodesSqlNullTo =
let valConv = fp (error "Oh no! No colInfo here.. what do we do!?") Nothing
encCtx = error "We could fake an EncodingContext, at least. TODO."
in case runConversion valConv encCtx of
Ok v -> Right v
Errors errs -> Left (show errs),
allowedPgTypes = const True -- No way to check if types are valid ahead of time
}

fromHpgsqlFieldDecoder :: FieldDecoder a -> FieldParser a
fromHpgsqlFieldDecoder dec = \f mbs -> Conversion $ \_encCtx -> case dec.fieldValueDecoder f mbs of
Right v -> Ok v
Left err -> Errors [toException $ userError $ show err]
fromHpgsqlFieldDecoder dec = \f mbs -> Conversion $ \_encCtx ->
case mbs of
Nothing -> case dec.decodesSqlNullTo of
Left err -> Errors [toException $ userError $ show err]
Right v -> Ok v
Just bs -> case dec.fieldValueDecoder f bs of
Right v -> Ok v
Left err -> Errors [toException $ userError $ show err]

-- | Given a Hpgsql query, returns the text format with question marks
-- for query arguments and a row object. With both, you can call
Expand Down
Loading
Loading