197 lines
5.4 KiB
Perl
197 lines
5.4 KiB
Perl
package FU::PG 0.1;
|
|
use v5.36;
|
|
use FU::XS;
|
|
|
|
_load_libpq();
|
|
|
|
package FU::PG::conn {
|
|
sub lib_version { FU::PG::lib_version() }
|
|
};
|
|
|
|
package FU::PG::error {
|
|
use overload '""' => sub($e, @) { $e->{full_message} };
|
|
}
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
FU::PG - Another PostgreSQL client module
|
|
|
|
=head1 SYNOPSYS
|
|
|
|
my $conn = FU::PG->connect("dbname=test user=test password=nottest");
|
|
|
|
$conn->exec('CREATE TABLE books (id SERIAL, title text)');
|
|
|
|
$conn->q('INSERT INTO books (title) VALUES ($1)', 'Revelation Space')->exec;
|
|
|
|
for my ($id, $title) ($conn->q('SELECT * FROM books')->flat) {
|
|
print "$id: $title\n";
|
|
}
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
FU::PG is a PostgreSQL client module that (attempts) to set itself apart from
|
|
the existing alternatives by offering the following features:
|
|
|
|
=over
|
|
|
|
=item * Automatic conversion of complex types (like JSON, hstore, records, etc)
|
|
to and from convenient corresponding perl values.
|
|
|
|
=item * Support for custom types.
|
|
|
|
=item * Configurable Perl representation of timestamp values (or, well, really
|
|
for any type).
|
|
|
|
=item * Data is transfered in the binary format (which may or may not be more
|
|
efficient, need benchmarks).
|
|
|
|
=item * Convenient and high-level API.
|
|
|
|
=back
|
|
|
|
=head2 Connection setup
|
|
|
|
=over
|
|
|
|
=item B<< FU::PG->connect($string) >>
|
|
|
|
Connect to the PostgreSQL server and return a new C<FU::PG::conn> object.
|
|
C<$string> can either be in key=value format or a URI, refer to L<the
|
|
PostgreSQL
|
|
documentation|https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING>
|
|
for the full list of supported formats and options. You may also pass an empty
|
|
string and leave the configuration up L<environment
|
|
variables|https://www.postgresql.org/docs/current/libpq-envars.html>.
|
|
|
|
=item B<< $conn->server_version >>
|
|
|
|
Returns the version of the PostgreSQL server as an integer in the format of
|
|
C<$major * 10000 + $minor>. For example, returns 170002 for PostgreSQL 17.2.
|
|
|
|
=item B<< $conn->lib_version >>
|
|
|
|
Returns the libpq version in the same format as the C<server_version> method.
|
|
Also available directly as C<FU::PG::lib_version()>.
|
|
|
|
|
|
=back
|
|
|
|
=head2 Querying
|
|
|
|
=over
|
|
|
|
=item B<< $conn->exec($sql) >>
|
|
|
|
Execute one or more SQL commands, separated by a semicolon. Returns the number
|
|
of rows affected by the last statement or I<undef> if that information is not
|
|
available for the given command (like `CREATE TABLE`).
|
|
|
|
=item B<< $conn->q($sql, @params) >>
|
|
|
|
Create a new SQL statement with the given C<$sql> string and an optional list
|
|
of bind parameters. C<$sql> can only hold a single statement.
|
|
|
|
Parameters can be referenced from C<$sql> with numbered placeholders, where
|
|
C<$1> refers to the first parameter, C<$2> to the second, etc. Be careful to
|
|
not accidentally interpolate perl's C<$1> and C<$2>. Using a question mark for
|
|
placeholders, as is common with L<DBI>, is not supported. An error is thrown
|
|
when attempting to execute a query where the number of C<@params> does not
|
|
match the number of placeholders in C<$sql>.
|
|
|
|
Note that this method just creates a statement object, the given query is not
|
|
prepared or executed until the appropriate statement methods (see below) are
|
|
used.
|
|
|
|
=back
|
|
|
|
Statement objects returned by C<< $conn->q() >> support the following methods:
|
|
|
|
=over
|
|
|
|
=item B<< $st->params >>
|
|
|
|
Returns an arrayref of hashrefs describing each parameter in the given C<$sql>
|
|
string. Each parameter only has a single key for now: C<oid>, indicating the
|
|
type Oid. Example:
|
|
|
|
my $params = $conn->q('SELECT id FROM books WHERE id = $1')->params;
|
|
# $params = [ { oid => 23 } ]
|
|
|
|
my $params = $conn->q('SELECT id FROM books')->params;
|
|
# $params = []
|
|
|
|
I<TODO: Resolve the oid to a more human-readable type>
|
|
|
|
=item B<< $st->columns >>
|
|
|
|
Returns an arrayref of hashrefs describing each column that the statement
|
|
returns.
|
|
|
|
my $cols = $conn->q('SELECT id, title FROM books')->columns;
|
|
# $cols = [
|
|
# { name => 'id', oid => 23 },
|
|
# { name => 'title', oid => 25 },
|
|
# ]
|
|
|
|
=back
|
|
|
|
=head2 Transactions
|
|
|
|
I<TODO>
|
|
|
|
=head2 Errors
|
|
|
|
I<TODO>
|
|
|
|
=head1 LIMITATIONS
|
|
|
|
=over
|
|
|
|
=item * Does not support older versions of libpq or PostgreSQL. Currently only
|
|
tested with version 17, but versions a bit older than that ought to work fine
|
|
as well. Much older versions will certainly not work fine.
|
|
|
|
=item * (Probably) not thread-safe.
|
|
|
|
=item * Only supports the UTF-8 encoding for string columns (text, char,
|
|
varchar, etc). When using the binary format (the default) this only works if
|
|
your database encoding is UTF-8. Non-UTF-8 databases are still supported with
|
|
the text format by setting `client_encoding=utf8` as part of the connection
|
|
string or by manually switching to it after C<connect()>:
|
|
|
|
my $conn = FU::PG->connect("");
|
|
$conn->exec('SET client_encoding=utf8');
|
|
|
|
(But you're missing out on most features this module has to offer if you're
|
|
stuck with the text format, so L<DBD::Pg> might be a better choice in that
|
|
case)
|
|
|
|
=item * Only works with blocking (synchronous) calls, not very suitable for use
|
|
in asynchronous frameworks unless you know your queries are fast and you have a
|
|
low-latency connection with the Postgres server.
|
|
|
|
=back
|
|
|
|
Missing features (for now): I<pretty much everything>.
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
=over
|
|
|
|
=item L<DBD::Pg>
|
|
|
|
The venerable Postgres driver for DBI. More stable, portable and battle-tested
|
|
than this module, but type conversions may leave things to be desired.
|
|
|
|
=item L<Pg::PQ>
|
|
|
|
A thin wrapper around libpq. Lacks many higher-level conveniences and does not
|
|
support binary transfers (at the time of writing, but then again there's little
|
|
benefit in dealing with the binary format in pure perl anyway).
|
|
|
|
=back
|