diff --git a/FU.xs b/FU.xs index ffd3df6..f5cf9a3 100644 --- a/FU.xs +++ b/FU.xs @@ -21,6 +21,10 @@ #define BOOL_INTERNALS_sv_isbool_true(x) SvPVXtrue(x) #endif +/* Disable key/value struct packing in khashl, so we can safely take a pointer + * to values inside the hash table. */ +#define kh_packed + #include "c/khashl.h" #include "c/common.c" #include "c/jsonfmt.c" diff --git a/FU/DebugImpl.pm b/FU/DebugImpl.pm index dddc7dc..0852b1c 100644 --- a/FU/DebugImpl.pm +++ b/FU/DebugImpl.pm @@ -44,8 +44,7 @@ my @tabs = ( td_ fu->headers->{$_}; } for sort keys fu->headers->%*; }; - h2_ 'Body'; - p_ 'TODO'; + # TODO: Body? Certainly useful for JSON ('Request') }, diff --git a/FU/Pg.pm b/FU/Pg.pm index 59fa799..d676dd2 100644 --- a/FU/Pg.pm +++ b/FU/Pg.pm @@ -555,9 +555,55 @@ send and receive everything as text!" Instead, in the (default) C mode, the responsibility of converting Postgres data to and from Perl values lies with this module. This allows for a lot of type-specific conveniences, but has the downside of requiring special -code for each supported PostgreSQL type. Most of the Postgres core types are -supported by this module and convert in an intuitive way, but here's a few -type-specific notes: +code for every PostgreSQL type. Most of the core types are supported by this +module and convert in an intuitive way, but you can also configure each type +manually: + +=over + +=item $conn->set_type($target_type, $type) + +=item $conn->set_type($target_type, send => $type, recv => $type) + +Change how C<$target_type> is being converted when used as a bind parameter +(I) or when received from query results (I). The two-argument +version is equivalent to setting I and I to the same C<$type>. + +Types can be specified either by their numeric I or by name. In the latter +case, the name must exactly match the internal type name used by PostgreSQL. +Note that this "internal type name" does not always match the names used in +documentation. For example, I, I and I should be +specified as I, I and I, respectively, and the I type +is internally called I. The full list of recognized types in your +database can be queried with: + + SELECT oid, typname FROM pg_type; + +The C<$target_type> does not have to exist in the database when this method is +called. This method only stores the type in its internal configuration, which +is consulted when executing a query that takes the type as bind parameter or +returns a column of that type. + +The following arguments are supported for C<$type>: + +=over + +=item * I, to reset the conversion functions to their default. + +=item * The numeric I or name of a built-in type supported by this module, +to use those conversion functions. + +=item * A subroutine reference that is called to perform the conversion. For +I, the subroutine is given a Perl value as argument and expected to +return a binary string to be sent to Postgres. For I, the subroutine is +given a binary string received from Postgres and expected to return a Perl +value. + +=back + +=back + +Some built-in types deserve a few additional notes: =over @@ -576,14 +622,18 @@ that along as raw binary strings. =item timestamp / timestamptz These are converted to and from seconds since the Unix epoch as a floating -point value, similar to the C (or better: C) -functions. +point value, for easy comparison against C and related functions. The timestamp types in Postgres have microsecond accuracy. Floating point can represent that without loss for dates that are near enough to the epoch (still seems to be fine in 2025, at least), but this conversion may be lossy for dates far beyond or before the epoch. +Postgres internally represents timestamps as microseconds since 2000-01-01 +stored in a 64-bit integer. If you prefer that, use: + + $conn->set_type(timestamptz => 'int8'); + =item date Converted between strings in C format. Postgres accepts a bunch of @@ -598,6 +648,13 @@ While C is a valid JSON value, there's currently no way to distinguish that from SQL C. When sending C as bind parameter, it is sent as SQL C. +If you prefer to work with JSON are raw text values instead, use: + + $conn->set_type(json => 'text'); + +That doesn't I work for the C type. I mean, it works, but then +there's a single C<"\1"> byte prefixed to the string. + =item arrays PostgreSQL arrays automatically convert to and from Perl arrays as you'd @@ -608,7 +665,19 @@ and all arrays sent to Postgres will use their default 1-based indexing. =item records / row types -These are converted to and from hashrefs. +Typed records are converted to and from hashrefs. Untyped records (i.e. values +of the C pseudo-type) are not supported. + +=item domain types + +These are recognized and automatically converted to and from their underlying +type. It may be tempting to use C to configure special type +conversions for domain types, but beware that PostgreSQL reports columns in the +C