FU::Pg: Rename q() and Q() to sql() and SQL()
Because this easily confuses syntax highlighters and some humans with the q// string syntax. Also for consistency with the 'fu->sql()' aliases. The old names are still available as alias.
This commit is contained in:
parent
876613d03f
commit
8140fefbca
10 changed files with 206 additions and 200 deletions
8
FU.pm
8
FU.pm
|
|
@ -646,8 +646,8 @@ sub db {
|
|||
};
|
||||
}
|
||||
|
||||
sub sql { shift->db->q(@_) }
|
||||
sub SQL { shift->db->Q(@_) }
|
||||
sub sql { shift->db->sql(@_) }
|
||||
sub SQL { shift->db->SQL(@_) }
|
||||
|
||||
sub _fmt_section($s) { $s =~ s/^\s*/ /r =~ s/\s+$//r =~ s/\n/\n /rg }
|
||||
|
||||
|
|
@ -1306,11 +1306,11 @@ has successfully been processed, or rolled back if there was an error.
|
|||
|
||||
=item fu->sql($query, @params)
|
||||
|
||||
Convenient short-hand for C<< fu->db->q($query, @params) >>.
|
||||
Convenient short-hand for C<< fu->db->sql($query, @params) >>.
|
||||
|
||||
=item fu->SQL(@args)
|
||||
|
||||
Convenient short-hand for C<< fu->db->Q(@args) >>.
|
||||
Convenient short-hand for C<< fu->db->SQL(@args) >>.
|
||||
|
||||
=item fu->log_verbose($message)
|
||||
|
||||
|
|
|
|||
8
FU.xs
8
FU.xs
|
|
@ -277,10 +277,10 @@ void exec(fupg_conn *c, SV *sv)
|
|||
FUPG_CONN_COOKIE;
|
||||
ST(0) = fupg_exec(aTHX_ c, SvPVutf8_nolen(sv));
|
||||
|
||||
void q(fupg_conn *c, SV *sv, ...)
|
||||
void sql(fupg_conn *c, SV *sv, ...)
|
||||
CODE:
|
||||
FUPG_CONN_COOKIE;
|
||||
ST(0) = fupg_q(aTHX_ c, c->stflags, SvPVutf8_nolen(sv), ax, items);
|
||||
ST(0) = fupg_sql(aTHX_ c, c->stflags, SvPVutf8_nolen(sv), ax, items);
|
||||
|
||||
void copy(fupg_conn *c, SV *sv)
|
||||
CODE:
|
||||
|
|
@ -353,10 +353,10 @@ void exec(fupg_txn *t, SV *sv)
|
|||
FUPG_TXN_COOKIE;
|
||||
ST(0) = fupg_exec(aTHX_ t->conn, SvPVutf8_nolen(sv));
|
||||
|
||||
void q(fupg_txn *t, SV *sv, ...)
|
||||
void sql(fupg_txn *t, SV *sv, ...)
|
||||
CODE:
|
||||
FUPG_TXN_COOKIE;
|
||||
ST(0) = fupg_q(aTHX_ t->conn, t->stflags, SvPVutf8_nolen(sv), ax, items);
|
||||
ST(0) = fupg_sql(aTHX_ t->conn, t->stflags, SvPVutf8_nolen(sv), ax, items);
|
||||
|
||||
# XXX: The copy object should probably keep a ref on the transaction
|
||||
void copy(fupg_txn *t, SV *sv)
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ my @sections = (
|
|||
|
||||
pgst => sub {
|
||||
return () if !$FU::DB;
|
||||
my $lst = eval { $FU::DB->q(
|
||||
my $lst = eval { $FU::DB->sql(
|
||||
'SELECT generic_plans + custom_plans, statement FROM pg_prepared_statements ORDER BY generic_plans + custom_plans DESC, statement'
|
||||
)->cache(0)->alla } || do { warn "Unable to collect prepared statement list: $@"; return () };
|
||||
return () if !@$lst;
|
||||
|
|
|
|||
68
FU/Pg.pm
68
FU/Pg.pm
|
|
@ -7,7 +7,7 @@ _load_libpq();
|
|||
package FU::Pg::conn {
|
||||
sub lib_version { FU::Pg::lib_version() }
|
||||
|
||||
sub Q {
|
||||
sub SQL {
|
||||
require FU::SQL;
|
||||
my $s = shift;
|
||||
my($sql, $params) = FU::SQL::SQL(@_)->compile(
|
||||
|
|
@ -15,7 +15,7 @@ package FU::Pg::conn {
|
|||
in_style => 'pg',
|
||||
quote_identifier => sub { $s->conn->escape_identifier(@_) },
|
||||
);
|
||||
$s->q($sql, @$params);
|
||||
$s->sql($sql, @$params);
|
||||
}
|
||||
|
||||
sub set_type($s, $n, @arg) {
|
||||
|
|
@ -26,7 +26,13 @@ package FU::Pg::conn {
|
|||
}
|
||||
};
|
||||
|
||||
*FU::Pg::txn::Q = \*FU::Pg::conn::Q;
|
||||
*FU::Pg::txn::SQL = \*FU::Pg::conn::SQL;
|
||||
|
||||
# Compat
|
||||
*FU::Pg::conn::q = \*FU::Pg::conn::sql;
|
||||
*FU::Pg::txn::q = \*FU::Pg::txn::sql;
|
||||
*FU::Pg::conn::Q = \*FU::Pg::conn::SQL;
|
||||
*FU::Pg::txn::Q = \*FU::Pg::txn::SQL;
|
||||
|
||||
package FU::Pg::error {
|
||||
use overload '""' => sub($e, @) { $e->{full_message} };
|
||||
|
|
@ -47,10 +53,10 @@ FU::Pg - The Ultimate (synchronous) Interface to PostgreSQL
|
|||
|
||||
$conn->exec('CREATE TABLE books (id SERIAL, title text, read bool)');
|
||||
|
||||
$conn->q('INSERT INTO books (title) VALUES ($1)', 'Revelation Space')->exec;
|
||||
$conn->q('INSERT INTO books (title) VALUES ($1)', 'The Invincible')->exec;
|
||||
$conn->sql('INSERT INTO books (title) VALUES ($1)', 'Revelation Space')->exec;
|
||||
$conn->sql('INSERT INTO books (title) VALUES ($1)', 'The Invincible')->exec;
|
||||
|
||||
for my ($id, $title) ($conn->q('SELECT * FROM books')->flat->@*) {
|
||||
for my ($id, $title) ($conn->sql('SELECT * FROM books')->flat->@*) {
|
||||
print "$id: $title\n";
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +147,7 @@ a table, column, function, etc) in an SQL statement.
|
|||
|
||||
=item $conn->text($enable)
|
||||
|
||||
Set the default settings for new statements created with B<< $conn->q() >>.
|
||||
Set the default settings for new statements created with B<< $conn->sql() >>.
|
||||
|
||||
=item $conn->cache_size($num)
|
||||
|
||||
|
|
@ -169,7 +175,7 @@ Also worth noting that the subroutine is called from the context of the code
|
|||
executing the query, but I<before> the query results have been returned.
|
||||
|
||||
The subroutine is (currently) only called for queries executed through C<<
|
||||
$conn->exec >>, C<< $conn->q >>, C<< $conn->Q >> and their C<$txn> variants;
|
||||
$conn->exec >>, C<< $conn->sql >>, C<< $conn->SQL >> and their C<$txn> variants;
|
||||
C<< $conn->copy >> statements and internal queries performed by this module
|
||||
(such as for transaction management, querying type information, etc) do not
|
||||
trigger the callback. Statements that result in an error being thrown during or
|
||||
|
|
@ -193,7 +199,7 @@ 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 with C<CREATE TABLE>).
|
||||
|
||||
=item $conn->q($sql, @params)
|
||||
=item $conn->sql($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.
|
||||
|
|
@ -209,15 +215,15 @@ Note that this method just creates a statement object, the query is not
|
|||
prepared or executed until the appropriate statement methods (see below) are
|
||||
used.
|
||||
|
||||
=item $conn->Q(@args)
|
||||
=item $conn->SQL(@args)
|
||||
|
||||
Same as C<< $conn->q() >> but uses L<FU::SQL> to construct the query and bind
|
||||
Same as C<< $conn->sql() >> but uses L<FU::SQL> to construct the query and bind
|
||||
parameters. Uses the 'pg' C<in_style> and C<< $conn->escape_identifier() >> for
|
||||
identifier quoting.
|
||||
|
||||
=back
|
||||
|
||||
Statement objects returned by C<< $conn->q() >> support the following
|
||||
Statement objects returned by C<< $conn->sql() >> support the following
|
||||
configuration parameters, which can be set before the statement is executed:
|
||||
|
||||
=over
|
||||
|
|
@ -252,7 +258,7 @@ depending on how you'd like to obtain the results:
|
|||
Execute the query and return the number of rows affected. Similar to C<<
|
||||
$conn->exec >>.
|
||||
|
||||
my $v = $conn->q('UPDATE books SET read = true WHERE id = 1')->exec;
|
||||
my $v = $conn->sql('UPDATE books SET read = true WHERE id = 1')->exec;
|
||||
# $v = 1
|
||||
|
||||
=item $st->val
|
||||
|
|
@ -261,7 +267,7 @@ Return the first column of the first row. Throws an error if the query does not
|
|||
return exactly one column, or if multiple rows are returned. Returns I<undef>
|
||||
if no rows are returned or if its value is I<NULL>.
|
||||
|
||||
my $v = $conn->q('SELECT COUNT(*) FROM books')->val;
|
||||
my $v = $conn->sql('SELECT COUNT(*) FROM books')->val;
|
||||
# $v = 2
|
||||
|
||||
=item $st->rowl
|
||||
|
|
@ -269,7 +275,7 @@ if no rows are returned or if its value is I<NULL>.
|
|||
Return the first row as a list, or an empty list if no rows are returned.
|
||||
Throws an error if the query returned more than one row.
|
||||
|
||||
my($id, $title) = $conn->q('SELECT id, title FROM books LIMIT 1')->rowl;
|
||||
my($id, $title) = $conn->sql('SELECT id, title FROM books LIMIT 1')->rowl;
|
||||
# ($id, $title) = (1, 'Revelation Space');
|
||||
|
||||
=item $st->rowa
|
||||
|
|
@ -278,7 +284,7 @@ Return the first row as an arrayref, equivalent to C<< [$st->rowl] >> but might
|
|||
be slightly more efficient. Returns C<undef> if the query did not generate any
|
||||
rows.
|
||||
|
||||
my $row = $conn->q('SELECT id, title FROM books LIMIT 1')->rowa;
|
||||
my $row = $conn->sql('SELECT id, title FROM books LIMIT 1')->rowa;
|
||||
# $row = [1, 'Revelation Space'];
|
||||
|
||||
=item $st->rowh
|
||||
|
|
@ -287,14 +293,14 @@ Return the first row as a hashref. Returns C<undef> if the query did not
|
|||
generate any rows. Throws an error if the query returns multiple columns with
|
||||
the same name.
|
||||
|
||||
my $row = $conn->q('SELECT id, title FROM books LIMIT 1')->rowh;
|
||||
my $row = $conn->sql('SELECT id, title FROM books LIMIT 1')->rowh;
|
||||
# $row = { id => 1, title => 'Revelation Space' };
|
||||
|
||||
=item $st->alla
|
||||
|
||||
Return all rows as an arrayref of arrayrefs.
|
||||
|
||||
my $data = $conn->q('SELECT id, title FROM books')->alla;
|
||||
my $data = $conn->sql('SELECT id, title FROM books')->alla;
|
||||
# $data = [
|
||||
# [ 1, 'Revelation Space' ],
|
||||
# [ 2, 'The Invincible' ],
|
||||
|
|
@ -305,7 +311,7 @@ Return all rows as an arrayref of arrayrefs.
|
|||
Return all rows as an arrayref of hashrefs. Throws an error if the query
|
||||
returns multiple columns with the same name.
|
||||
|
||||
my $data = $conn->q('SELECT id, title FROM books')->allh;
|
||||
my $data = $conn->sql('SELECT id, title FROM books')->allh;
|
||||
# $data = [
|
||||
# { id => 1, title => 'Revelation Space' },
|
||||
# { id => 2, title => 'The Invincible' },
|
||||
|
|
@ -315,7 +321,7 @@ returns multiple columns with the same name.
|
|||
|
||||
Return an arrayref with all rows flattened.
|
||||
|
||||
my $data = $conn->q('SELECT id, title FROM books')->flat;
|
||||
my $data = $conn->sql('SELECT id, title FROM books')->flat;
|
||||
# $data = [
|
||||
# 1, 'Revelation Space',
|
||||
# 2, 'The Invincible',
|
||||
|
|
@ -327,7 +333,7 @@ Return a hashref where the first result column is used as key and the second
|
|||
column as value. If the query only returns a single column, C<true> is used as
|
||||
value instead. An error is thrown if the query returns 3 or more columns.
|
||||
|
||||
my $data = $conn->q('SELECT id, title FROM books')->kvv;
|
||||
my $data = $conn->sql('SELECT id, title FROM books')->kvv;
|
||||
# $data = {
|
||||
# 1 => 'Revelation Space',
|
||||
# 2 => 'The Invincible',
|
||||
|
|
@ -338,7 +344,7 @@ value instead. An error is thrown if the query returns 3 or more columns.
|
|||
Return a hashref where the first result column is used as key and the remaining
|
||||
columns are stored as arrayref.
|
||||
|
||||
my $data = $conn->q('SELECT id, title, read FROM books')->kva;
|
||||
my $data = $conn->sql('SELECT id, title, read FROM books')->kva;
|
||||
# $data = {
|
||||
# 1 => [ 'Revelation Space', true ],
|
||||
# 2 => [ 'The Invincible', false ],
|
||||
|
|
@ -349,7 +355,7 @@ columns are stored as arrayref.
|
|||
Return a hashref where the first result column is used as key and the remaining
|
||||
columns are stored as hashref.
|
||||
|
||||
my $data = $conn->q('SELECT id, title, read FROM books')->kvh;
|
||||
my $data = $conn->sql('SELECT id, title, read FROM books')->kvh;
|
||||
# $data = {
|
||||
# 1 => { title => 'Revelation Space', read => true },
|
||||
# 2 => { title => 'The Invincible', read => false },
|
||||
|
|
@ -361,7 +367,7 @@ The only time you actually need to assign a statement object to a variable is
|
|||
when you want to inspect the statement using one of the methods below, in all
|
||||
other cases you can chain the methods for more concise code. For example:
|
||||
|
||||
my $data = $conn->q('SELECT a, b FROM table')->cache(0)->text->alla;
|
||||
my $data = $conn->sql('SELECT a, b FROM table')->cache(0)->text->alla;
|
||||
|
||||
Statement objects can be inspected with the following methods (many of which
|
||||
only make sense after the query has been executed):
|
||||
|
|
@ -381,10 +387,10 @@ Returns the provided bind parameters as an arrayref.
|
|||
Returns an arrayref of integers indicating the type (as I<oid>) of each
|
||||
parameter in the given C<$sql> string. Example:
|
||||
|
||||
my $oids = $conn->q('SELECT id FROM books WHERE id = $1 AND title = $2')->param_types;
|
||||
my $oids = $conn->sql('SELECT id FROM books WHERE id = $1 AND title = $2')->param_types;
|
||||
# $oids = [23,25]
|
||||
|
||||
my $oids = $conn->q('SELECT id FROM books')->params;
|
||||
my $oids = $conn->sql('SELECT id FROM books')->params;
|
||||
# $oids = []
|
||||
|
||||
This method can be called before the query has been executed, but will then
|
||||
|
|
@ -397,7 +403,7 @@ prepared statement caching is disabled and C<text_params> is enabled.
|
|||
Returns an arrayref of hashrefs describing each column that the statement
|
||||
returns.
|
||||
|
||||
my $cols = $conn->q('SELECT id, title FROM books')->columns;
|
||||
my $cols = $conn->sql('SELECT id, title FROM books')->columns;
|
||||
# $cols = [
|
||||
# { name => 'id', oid => 23 },
|
||||
# { name => 'title', oid => 25 },
|
||||
|
|
@ -446,7 +452,7 @@ fail while a transaction object is alive.
|
|||
my $txn = $conn->txn;
|
||||
|
||||
# run queries
|
||||
$txn->q('DELETE FROM books WHERE id = $1', 1)->exec;
|
||||
$txn->sql('DELETE FROM books WHERE id = $1', 1)->exec;
|
||||
|
||||
# run commands in a subtransaction
|
||||
{
|
||||
|
|
@ -467,9 +473,9 @@ Transaction methods:
|
|||
|
||||
=item $txn->exec(..)
|
||||
|
||||
=item $txn->q(..)
|
||||
=item $txn->sql(..)
|
||||
|
||||
=item $txn->Q(..)
|
||||
=item $txn->SQL(..)
|
||||
|
||||
Run a query inside the transaction. These work the same as the respective
|
||||
methods on the parent C<$conn> object.
|
||||
|
|
@ -492,7 +498,7 @@ when the object goes out of scope.
|
|||
|
||||
=item $txn->text($enable)
|
||||
|
||||
Set the default settings for new statements created with B<< $txn->q() >>.
|
||||
Set the default settings for new statements created with B<< $txn->sql() >>.
|
||||
|
||||
These settings are inherited from the main connection when the transaction is
|
||||
created. Subtransactions inherit these settings from their parent transaction.
|
||||
|
|
|
|||
4
bench.PL
4
bench.PL
|
|
@ -211,8 +211,8 @@ def 'xml/a', 'HTML fragment', [ 'Rate' ],
|
|||
|
||||
my sub dbi { my $sum = 0; my $st = $dbi->prepare_cached($_[0]); for my $row ($dbi->selectall_arrayref($st)->@*) { $sum ^= $_ for @$row; } }
|
||||
my sub pq { my $sum = 0; $pq->prepare('' => $_[0]); for my $row ($pq->execQueryPrepared('')->rows) { $sum ^= $_ for @$row; } }
|
||||
my sub fub { my $sum = 0; for my $row ($fu->q($_[0])->alla->@*) { $sum ^= $_ for @$row; } }
|
||||
my sub fut { my $sum = 0; for my $row ($fu->q($_[0])->text->alla->@*) { $sum ^= $_ for @$row; } }
|
||||
my sub fub { my $sum = 0; for my $row ($fu->sql($_[0])->alla->@*) { $sum ^= $_ for @$row; } }
|
||||
my sub fut { my $sum = 0; for my $row ($fu->sql($_[0])->text->alla->@*) { $sum ^= $_ for @$row; } }
|
||||
|
||||
def 'pg/ints', 'Fetch and bitwise-or 20k integers', [ 'Smallint', 'Bigint' ],
|
||||
[ 'DBD::Pg', undef, sub { dbi($small) }, sub { dbi($big) } ],
|
||||
|
|
|
|||
2
c/pgst.c
2
c/pgst.c
|
|
@ -76,7 +76,7 @@ static SV *fupg_exec(pTHX_ fupg_conn *c, const char *sql) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static SV *fupg_q(pTHX_ fupg_conn *c, int stflags, const char *query, I32 ax, I32 argc) {
|
||||
static SV *fupg_sql(pTHX_ fupg_conn *c, int stflags, const char *query, I32 ax, I32 argc) {
|
||||
fupg_st *st = safecalloc(1, sizeof(fupg_st));
|
||||
st->conn = c;
|
||||
st->cookie = c->cookie;
|
||||
|
|
|
|||
190
t/pgconnect.t
190
t/pgconnect.t
|
|
@ -37,7 +37,7 @@ subtest '$conn->exec', sub {
|
|||
ok !defined $conn->exec('');
|
||||
is $conn->exec('SELECT 1'), 1;
|
||||
|
||||
ok !eval { $conn->q('SELEXT')->param_types; };
|
||||
ok !eval { $conn->sql('SELEXT')->param_types; };
|
||||
okerr ERROR => prepare => qr/syntax error/;
|
||||
|
||||
is $conn->exec('SET client_encoding=utf8'), undef;
|
||||
|
|
@ -46,7 +46,7 @@ subtest '$conn->exec', sub {
|
|||
|
||||
subtest '$st prepare & exec', sub {
|
||||
{
|
||||
my $st = $conn->q('SELECT 1');
|
||||
my $st = $conn->sql('SELECT 1');
|
||||
is_deeply $st->param_types, [];
|
||||
is_deeply $st->columns, [{ name => '?column?', oid => 23 }];
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ subtest '$st prepare & exec', sub {
|
|||
}
|
||||
|
||||
{
|
||||
my $st = $conn->q("SELECT \$1::int AS a, \$2::char(5) AS \"\x{1F603}\"", 1, 2);
|
||||
my $st = $conn->sql("SELECT \$1::int AS a, \$2::char(5) AS \"\x{1F603}\"", 1, 2);
|
||||
is_deeply $st->param_types, [ 23, 1042 ];
|
||||
is_deeply $st->columns, [
|
||||
{ oid => 23, name => 'a' },
|
||||
|
|
@ -74,28 +74,28 @@ subtest '$st prepare & exec', sub {
|
|||
|
||||
is $conn->exec('SELECT 1 FROM pg_prepared_statements'), 0;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1', 1)->exec; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1', 1)->exec; 1 };
|
||||
like $@, qr/bind message supplies 1 parameters, but prepared statement/;
|
||||
|
||||
ok !eval { $conn->q('SELECT $1')->exec; 1 };
|
||||
ok !eval { $conn->sql('SELECT $1')->exec; 1 };
|
||||
like $@, qr/bind message supplies 0 parameters, but prepared statement/;
|
||||
|
||||
# prepare + describe won't let us detect empty queries, hmm...
|
||||
is_deeply $conn->q('')->param_types, [];
|
||||
is_deeply $conn->q('')->columns, [];
|
||||
is_deeply $conn->sql('')->param_types, [];
|
||||
is_deeply $conn->sql('')->columns, [];
|
||||
|
||||
ok !eval { $conn->q('')->exec; 1 };
|
||||
ok !eval { $conn->sql('')->exec; 1 };
|
||||
okerr FATAL => exec => qr/unexpected status code/;
|
||||
|
||||
is $conn->q('SET client_encoding=utf8')->exec, undef;
|
||||
is $conn->sql('SET client_encoding=utf8')->exec, undef;
|
||||
|
||||
ok !eval { $conn->q('select 1; select 2')->exec; 1 };
|
||||
ok !eval { $conn->sql('select 1; select 2')->exec; 1 };
|
||||
okerr ERROR => exec => qr/cannot insert multiple commands into a prepared statement/;
|
||||
|
||||
# Interleaved
|
||||
{
|
||||
my $x = $conn->q('SELECT 1 as a');
|
||||
my $y = $conn->q('SELECT 2 as b');
|
||||
my $x = $conn->sql('SELECT 1 as a');
|
||||
my $y = $conn->sql('SELECT 2 as b');
|
||||
is_deeply $x->columns, [ { oid => 23, name => 'a' } ];
|
||||
is_deeply $y->columns, [ { oid => 23, name => 'b' } ];
|
||||
is $x->val, 1;
|
||||
|
|
@ -104,137 +104,137 @@ subtest '$st prepare & exec', sub {
|
|||
};
|
||||
|
||||
subtest '$st->val', sub {
|
||||
ok !eval { $conn->q('SELECT')->val; 1 };
|
||||
ok !eval { $conn->sql('SELECT')->val; 1 };
|
||||
like $@, qr/on query returning no data/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1, 2')->val; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1, 2')->val; 1 };
|
||||
like $@, qr/on query returning more than one column/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1 UNION SELECT 2')->val; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION SELECT 2')->val; 1 };
|
||||
like $@, qr/on query returning more than one row/;
|
||||
|
||||
ok !defined $conn->q('SELECT 1 WHERE false')->val;
|
||||
ok !defined $conn->q('SELECT null')->val;
|
||||
is $conn->q('SELECT $1::text', "\x{1F603}")->val, "\x{1F603}";
|
||||
ok !defined $conn->sql('SELECT 1 WHERE false')->val;
|
||||
ok !defined $conn->sql('SELECT null')->val;
|
||||
is $conn->sql('SELECT $1::text', "\x{1F603}")->val, "\x{1F603}";
|
||||
};
|
||||
|
||||
subtest '$st->rowl', sub {
|
||||
ok !eval { $conn->q('SELECT 1 UNION SELECT 2')->rowl; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION SELECT 2')->rowl; 1 };
|
||||
like $@, qr/on query returning more than one row/;
|
||||
|
||||
ok !eval { $conn->q('SELEXT')->rowl; 1; };
|
||||
is scalar $conn->q('SELECT')->rowl, 0;
|
||||
is scalar $conn->q('SELECT 1, 2')->rowl, 2;
|
||||
is_deeply [$conn->q('SELECT')->rowl], [];
|
||||
is_deeply [$conn->q('SELECT 1, null')->rowl], [1, undef];
|
||||
is_deeply [$conn->q('SELECT 1, $1', undef)->rowl], [1, undef];
|
||||
is_deeply [$conn->q('SELECT 1, $1::int', undef)->text_params(0)->rowl], [1, undef];
|
||||
is_deeply [$conn->q('SELECT 1 WHERE false')->rowl], [];
|
||||
ok !eval { $conn->sql('SELEXT')->rowl; 1; };
|
||||
is scalar $conn->sql('SELECT')->rowl, 0;
|
||||
is scalar $conn->sql('SELECT 1, 2')->rowl, 2;
|
||||
is_deeply [$conn->sql('SELECT')->rowl], [];
|
||||
is_deeply [$conn->sql('SELECT 1, null')->rowl], [1, undef];
|
||||
is_deeply [$conn->sql('SELECT 1, $1', undef)->rowl], [1, undef];
|
||||
is_deeply [$conn->sql('SELECT 1, $1::int', undef)->text_params(0)->rowl], [1, undef];
|
||||
is_deeply [$conn->sql('SELECT 1 WHERE false')->rowl], [];
|
||||
};
|
||||
|
||||
subtest '$st->rowa', sub {
|
||||
ok !eval { $conn->q('SELECT 1 UNION SELECT 2')->rowa; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION SELECT 2')->rowa; 1 };
|
||||
like $@, qr/on query returning more than one row/;
|
||||
|
||||
ok !eval { $conn->q('SELEXT')->rowa; 1; };
|
||||
is $conn->q('SELECT 1 WHERE false')->rowa, undef;
|
||||
is_deeply $conn->q('SELECT')->rowa, [];
|
||||
is_deeply $conn->q('SELECT 1, 2')->rowa, [1, 2];
|
||||
is_deeply $conn->q('SELECT 1, null')->rowa, [1, undef];
|
||||
is_deeply $conn->q('SELECT 1, $1', undef)->rowa, [1, undef];
|
||||
is_deeply $conn->q('SELECT 1, $1::int', undef)->text_params(0)->rowa, [1, undef];
|
||||
ok !eval { $conn->sql('SELEXT')->rowa; 1; };
|
||||
is $conn->sql('SELECT 1 WHERE false')->rowa, undef;
|
||||
is_deeply $conn->sql('SELECT')->rowa, [];
|
||||
is_deeply $conn->sql('SELECT 1, 2')->rowa, [1, 2];
|
||||
is_deeply $conn->sql('SELECT 1, null')->rowa, [1, undef];
|
||||
is_deeply $conn->sql('SELECT 1, $1', undef)->rowa, [1, undef];
|
||||
is_deeply $conn->sql('SELECT 1, $1::int', undef)->text_params(0)->rowa, [1, undef];
|
||||
|
||||
};
|
||||
|
||||
subtest '$st->rowh', sub {
|
||||
ok !eval { $conn->q('SELECT 1 UNION SELECT 2')->rowh; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION SELECT 2')->rowh; 1 };
|
||||
like $@, qr/on query returning more than one row/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1 as a, 2 as a')->rowh; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 as a, 2 as a')->rowh; 1 };
|
||||
like $@, qr/Query returns multiple columns with the same name/;
|
||||
|
||||
is $conn->q('SELECT 1 WHERE false')->rowh, undef;
|
||||
is_deeply $conn->q('SELECT')->rowh, {};
|
||||
is_deeply $conn->q('SELECT 1 as a, 2 as b')->rowh, {a => 1, b => 2};
|
||||
is_deeply $conn->q('SELECT 1 as a, null as b')->rowh, {a => 1, b => undef};
|
||||
is_deeply $conn->q('SELECT 1 as a, $1::int as b', undef)->rowh, {a => 1, b => undef};
|
||||
is $conn->sql('SELECT 1 WHERE false')->rowh, undef;
|
||||
is_deeply $conn->sql('SELECT')->rowh, {};
|
||||
is_deeply $conn->sql('SELECT 1 as a, 2 as b')->rowh, {a => 1, b => 2};
|
||||
is_deeply $conn->sql('SELECT 1 as a, null as b')->rowh, {a => 1, b => undef};
|
||||
is_deeply $conn->sql('SELECT 1 as a, $1::int as b', undef)->rowh, {a => 1, b => undef};
|
||||
};
|
||||
|
||||
subtest '$st->alla', sub {
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->alla, [];
|
||||
is_deeply $conn->q('SELECT')->alla, [[]];
|
||||
is_deeply $conn->q('SELECT 1')->alla, [[1]];
|
||||
is_deeply $conn->q('SELECT 1, null UNION ALL SELECT NULL, 2')->alla, [[1,undef],[undef,2]];
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->alla, [];
|
||||
is_deeply $conn->sql('SELECT')->alla, [[]];
|
||||
is_deeply $conn->sql('SELECT 1')->alla, [[1]];
|
||||
is_deeply $conn->sql('SELECT 1, null UNION ALL SELECT NULL, 2')->alla, [[1,undef],[undef,2]];
|
||||
};
|
||||
|
||||
subtest '$st->allh', sub {
|
||||
ok !eval { $conn->q('SELECT 1 as a, 2 as a')->allh; 1 };
|
||||
ok !eval { $conn->sql('SELECT 1 as a, 2 as a')->allh; 1 };
|
||||
like $@, qr/Query returns multiple columns with the same name/;
|
||||
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->allh, [];
|
||||
is_deeply $conn->q('SELECT')->allh, [{}];
|
||||
is_deeply $conn->q('SELECT 1 a')->allh, [{a=>1}];
|
||||
is_deeply $conn->q('SELECT 1 a, null b UNION ALL SELECT NULL, 2')->allh, [{a=>1,b=>undef},{a=>undef,b=>2}];
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->allh, [];
|
||||
is_deeply $conn->sql('SELECT')->allh, [{}];
|
||||
is_deeply $conn->sql('SELECT 1 a')->allh, [{a=>1}];
|
||||
is_deeply $conn->sql('SELECT 1 a, null b UNION ALL SELECT NULL, 2')->allh, [{a=>1,b=>undef},{a=>undef,b=>2}];
|
||||
};
|
||||
|
||||
subtest '$st->flat', sub {
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->flat, [];
|
||||
is_deeply $conn->q('SELECT')->flat, [];
|
||||
is_deeply $conn->q('SELECT 1')->flat, [1];
|
||||
is_deeply $conn->q('SELECT 1, null UNION ALL SELECT NULL, 2')->flat, [1,undef,undef,2];
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->flat, [];
|
||||
is_deeply $conn->sql('SELECT')->flat, [];
|
||||
is_deeply $conn->sql('SELECT 1')->flat, [1];
|
||||
is_deeply $conn->sql('SELECT 1, null UNION ALL SELECT NULL, 2')->flat, [1,undef,undef,2];
|
||||
};
|
||||
|
||||
subtest '$st->kvv', sub {
|
||||
ok !eval { $conn->q('SELECT')->kvv; 1; };
|
||||
ok !eval { $conn->sql('SELECT')->kvv; 1; };
|
||||
like $@, qr/returning no data/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1, 2, 3')->kvv; 1; };
|
||||
ok !eval { $conn->sql('SELECT 1, 2, 3')->kvv; 1; };
|
||||
like $@, qr/returning more than two columns/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1 UNION ALL SELECT 1')->kvv; 1; };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION ALL SELECT 1')->kvv; 1; };
|
||||
like $@, qr/is duplicated/;
|
||||
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->kvv, {};
|
||||
is_deeply $conn->q('SELECT 1')->kvv, {1=>1};
|
||||
is_deeply $conn->q('SELECT 1, null UNION ALL SELECT 3, 2')->kvv, {1=>undef,3=>2};
|
||||
$conn->q('SELECT 1')->kvv->{1} = 0;
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->kvv, {};
|
||||
is_deeply $conn->sql('SELECT 1')->kvv, {1=>1};
|
||||
is_deeply $conn->sql('SELECT 1, null UNION ALL SELECT 3, 2')->kvv, {1=>undef,3=>2};
|
||||
$conn->sql('SELECT 1')->kvv->{1} = 0;
|
||||
};
|
||||
|
||||
subtest '$st->kva', sub {
|
||||
ok !eval { $conn->q('SELECT')->kva; 1; };
|
||||
ok !eval { $conn->sql('SELECT')->kva; 1; };
|
||||
like $@, qr/returning no data/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1 UNION ALL SELECT 1')->kva; 1; };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION ALL SELECT 1')->kva; 1; };
|
||||
like $@, qr/is duplicated/;
|
||||
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->kva, {};
|
||||
is_deeply $conn->q('SELECT 1')->kva, {1=>[]};
|
||||
is_deeply $conn->q("SELECT 1, null, 'hi' UNION ALL SELECT 3, 2, 'ok'")->kva,
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->kva, {};
|
||||
is_deeply $conn->sql('SELECT 1')->kva, {1=>[]};
|
||||
is_deeply $conn->sql("SELECT 1, null, 'hi' UNION ALL SELECT 3, 2, 'ok'")->kva,
|
||||
{1=>[undef,'hi'], 3=>[2, 'ok']};
|
||||
};
|
||||
|
||||
subtest '$st->kvh', sub {
|
||||
ok !eval { $conn->q('SELECT')->kvh; 1; };
|
||||
ok !eval { $conn->sql('SELECT')->kvh; 1; };
|
||||
like $@, qr/returning no data/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1 UNION ALL SELECT 1')->kvh; 1; };
|
||||
ok !eval { $conn->sql('SELECT 1 UNION ALL SELECT 1')->kvh; 1; };
|
||||
like $@, qr/is duplicated/;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1, 2, 3')->kvh; 1; };
|
||||
ok !eval { $conn->sql('SELECT 1, 2, 3')->kvh; 1; };
|
||||
like $@, qr/Query returns multiple columns with the same name/;
|
||||
|
||||
is_deeply $conn->q('SELECT 1 WHERE false')->kvh, {};
|
||||
is_deeply $conn->q('SELECT 1')->kvh, {1=>{}};
|
||||
is_deeply $conn->q("SELECT 1 as a , null as a, 'hi' as b UNION ALL SELECT 3, 2, 'ok'")->kvh,
|
||||
is_deeply $conn->sql('SELECT 1 WHERE false')->kvh, {};
|
||||
is_deeply $conn->sql('SELECT 1')->kvh, {1=>{}};
|
||||
is_deeply $conn->sql("SELECT 1 as a , null as a, 'hi' as b UNION ALL SELECT 3, 2, 'ok'")->kvh,
|
||||
{1=>{a=>undef,b=>'hi'}, 3=>{a=>2,b=>'ok'}};
|
||||
};
|
||||
|
||||
subtest 'txn', sub {
|
||||
$conn->exec('CREATE TEMPORARY TABLE fupg_tst (id int)');
|
||||
$conn->txn->exec('INSERT INTO fupg_tst VALUES (1)'); # rolled back
|
||||
is $conn->q('SELECT COUNT(*) FROM fupg_tst')->val, 0;
|
||||
is $conn->sql('SELECT COUNT(*) FROM fupg_tst')->val, 0;
|
||||
|
||||
my $st = $conn->q('SELECT COUNT(*) FROM fupg_tst');
|
||||
my $st = $conn->sql('SELECT COUNT(*) FROM fupg_tst');
|
||||
my $sst;
|
||||
{
|
||||
my $txn = $conn->txn;
|
||||
|
|
@ -246,13 +246,13 @@ subtest 'txn', sub {
|
|||
|
||||
ok !eval { $conn->exec('SELECT 1'); 1 };
|
||||
like $@, qr/Invalid operation on the top-level connection/;
|
||||
ok !eval { $conn->q('SELECT 1'); 1 };
|
||||
ok !eval { $conn->sql('SELECT 1'); 1 };
|
||||
like $@, qr/Invalid operation on the top-level connection/;
|
||||
ok !eval { $conn->txn; 1 };
|
||||
like $@, qr/Invalid operation on the top-level connection/;
|
||||
|
||||
$txn->exec('INSERT INTO fupg_tst VALUES (1)');
|
||||
$sst = $txn->q('SELECT 1');
|
||||
$sst = $txn->sql('SELECT 1');
|
||||
|
||||
is $conn->status, 'txn_idle';
|
||||
is $txn->status, 'idle';
|
||||
|
|
@ -268,7 +268,7 @@ subtest 'txn', sub {
|
|||
like $@, qr/Invalid operation on a transaction that has already been marked as done/;
|
||||
ok !eval { $txn->exec('select 1'); 1 };
|
||||
like $@, qr/Invalid operation on a transaction that has already been marked as done/;
|
||||
ok !eval { $txn->q('select 1'); 1 };
|
||||
ok !eval { $txn->sql('select 1'); 1 };
|
||||
like $@, qr/Invalid operation on a transaction that has already been marked as done/;
|
||||
|
||||
ok !eval { $conn->exec('SELECT 1'); 1 };
|
||||
|
|
@ -295,7 +295,7 @@ subtest 'txn', sub {
|
|||
|
||||
{
|
||||
my $txn = $conn->txn;
|
||||
my $st = $txn->q('SELECT count(*) FROM fupg_tst WHERE id = 2');
|
||||
my $st = $txn->sql('SELECT count(*) FROM fupg_tst WHERE id = 2');
|
||||
{
|
||||
my $sub = $txn->txn;
|
||||
is $conn->status, 'txn_idle';
|
||||
|
|
@ -316,7 +316,7 @@ subtest 'txn', sub {
|
|||
is $txn->status, 'idle';
|
||||
is $st->val, 0;
|
||||
|
||||
$st = $txn->q('SELECT count(*) FROM fupg_tst WHERE id = 2');
|
||||
$st = $txn->sql('SELECT count(*) FROM fupg_tst WHERE id = 2');
|
||||
{
|
||||
my $sub = $txn->txn;
|
||||
$sub->exec('INSERT INTO fupg_tst VALUES (2)');
|
||||
|
|
@ -339,19 +339,19 @@ subtest 'txn', sub {
|
|||
$sub->commit;
|
||||
}
|
||||
# We didn't commit $txn, so $sub got aborted as well
|
||||
is $conn->q('SELECT count(*) FROM fupg_tst WHERE id = 3')->val, 0;
|
||||
is $conn->sql('SELECT count(*) FROM fupg_tst WHERE id = 3')->val, 0;
|
||||
};
|
||||
|
||||
{
|
||||
local $_ = 'x';
|
||||
my $st = $conn->q('SELECT $1', $_);
|
||||
my $st = $conn->sql('SELECT $1', $_);
|
||||
$_ = 'y';
|
||||
is $st->val, 'x', 'shallow copy';
|
||||
}
|
||||
|
||||
{
|
||||
my $x = [1,2];
|
||||
my $st = $conn->q('SELECT $1::int[]', $x)->text(0);
|
||||
my $st = $conn->sql('SELECT $1::int[]', $x)->text(0);
|
||||
$x->[1] = 3;
|
||||
is_deeply $st->val, [1,3], 'not deep copy';
|
||||
}
|
||||
|
|
@ -360,7 +360,7 @@ subtest 'txn', sub {
|
|||
{
|
||||
# Exact format returned by escape_literal() can differ between Postgres versions and configurations.
|
||||
my $x = q{"' \" \\};
|
||||
is $conn->q('SELECT '.$conn->escape_literal($x))->val, $x;
|
||||
is $conn->sql('SELECT '.$conn->escape_literal($x))->val, $x;
|
||||
|
||||
# Format can also change, but unsure how to test this otherwise.
|
||||
is $conn->escape_identifier('hel\l"o'), '"hel\l""o"';
|
||||
|
|
@ -371,32 +371,32 @@ subtest 'Prepared statement cache', sub {
|
|||
my $txn = $conn->txn;
|
||||
$txn->cache;
|
||||
my $numexec = sub($sql) {
|
||||
$txn->q('SELECT generic_plans + custom_plans FROM pg_prepared_statements WHERE statement = $1', $sql)->cache(0)->val
|
||||
$txn->sql('SELECT generic_plans + custom_plans FROM pg_prepared_statements WHERE statement = $1', $sql)->cache(0)->val
|
||||
};
|
||||
is $txn->q('SELECT 1')->val, 1;
|
||||
is $txn->sql('SELECT 1')->val, 1;
|
||||
is $numexec->('SELECT 1'), 1;
|
||||
|
||||
my $sql = 'SELECT $1::int as a, $2::text as b';
|
||||
ok !defined $numexec->($sql);
|
||||
|
||||
my $params = $txn->q($sql)->param_types;
|
||||
my $params = $txn->sql($sql)->param_types;
|
||||
is_deeply $params, [23, 25];
|
||||
is $numexec->($sql), 0;
|
||||
my $cparams = $txn->q($sql)->param_types;
|
||||
my $cparams = $txn->sql($sql)->param_types;
|
||||
is_deeply $cparams, $params;
|
||||
|
||||
my $cols = $txn->q($sql)->columns;
|
||||
my $cols = $txn->sql($sql)->columns;
|
||||
is_deeply $cols, [{ name => 'a', oid => 23 }, { name => 'b', oid => 25 }];
|
||||
my $ccols = $txn->q($sql)->columns;
|
||||
my $ccols = $txn->sql($sql)->columns;
|
||||
is_deeply $ccols, $cols;
|
||||
|
||||
$txn->q($sql, 0, '')->exec;
|
||||
$txn->sql($sql, 0, '')->exec;
|
||||
is $numexec->($sql), 1;
|
||||
$txn->q($sql, 0, '')->exec;
|
||||
$txn->sql($sql, 0, '')->exec;
|
||||
is $numexec->($sql), 2;
|
||||
|
||||
is $numexec->('SELECT 1'), 1;
|
||||
$txn->q('SELECT 2')->exec;
|
||||
$txn->sql('SELECT 2')->exec;
|
||||
ok !defined $numexec->('SELECT 1');
|
||||
is $numexec->('SELECT 2'), 1;
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ subtest 'Tracing', sub {
|
|||
my @log;
|
||||
$conn->query_trace(sub($st) { push @log, $st });
|
||||
|
||||
is_deeply $conn->q('SELECT 1 AS a, $1 AS b', 123)->text_params(0)->rowa, [ 1, 123 ];
|
||||
is_deeply $conn->sql('SELECT 1 AS a, $1 AS b', 123)->text_params(0)->rowa, [ 1, 123 ];
|
||||
is scalar @log, 1;
|
||||
my $st = shift @log;
|
||||
is ref $st, 'FU::Pg::st';
|
||||
|
|
@ -451,7 +451,7 @@ subtest 'Tracing', sub {
|
|||
};
|
||||
|
||||
{
|
||||
my $st = $conn->q("SELECT 1");
|
||||
my $st = $conn->sql("SELECT 1");
|
||||
undef $conn; # statement keeps the connection alive
|
||||
is $st->val, 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ is $conn->status, 'idle';
|
|||
$c->write($bin);
|
||||
$c->close;
|
||||
|
||||
is $txn->q('SELECT sum(v) FROM fupg_copy_test')->val, 1+1+2+2+3+3;
|
||||
is $txn->sql('SELECT sum(v) FROM fupg_copy_test')->val, 1+1+2+2+3+3;
|
||||
$txn->rollback;
|
||||
}
|
||||
is $conn->q('SELECT sum(v) FROM fupg_copy_test')->val, 1+2+3;
|
||||
is $conn->sql('SELECT sum(v) FROM fupg_copy_test')->val, 1+2+3;
|
||||
|
||||
done_testing;
|
||||
|
|
|
|||
|
|
@ -10,31 +10,31 @@ my $conn = FU::Pg->connect($ENV{FU_TEST_DB});
|
|||
$conn->_debug_trace(0);
|
||||
|
||||
|
||||
is_deeply $conn->Q('SELECT', 1, '::int')->param_types, [23];
|
||||
is_deeply $conn->Q('SELECT 1', IN([1,2,3]))->param_types, [1007];
|
||||
is $conn->Q('SELECT 1', IN([1,2,3]))->val, 1;
|
||||
is_deeply $conn->SQL('SELECT', 1, '::int')->param_types, [23];
|
||||
is_deeply $conn->SQL('SELECT 1', IN([1,2,3]))->param_types, [1007];
|
||||
is $conn->SQL('SELECT 1', IN([1,2,3]))->val, 1;
|
||||
|
||||
ok !eval { $conn->q('SELECT $1::aclitem', '')->exec; 1 };
|
||||
ok !eval { $conn->sql('SELECT $1::aclitem', '')->exec; 1 };
|
||||
like $@, qr/Unable to send type/;
|
||||
|
||||
|
||||
subtest 'type overrides', sub {
|
||||
$conn->set_type(int4 => recv => 'bytea');
|
||||
is $conn->q('SELECT 5::int4')->val, "\0\0\0\5";
|
||||
is_deeply $conn->q('SELECT ARRAY[5::int4]')->val, ["\0\0\0\5"];
|
||||
is $conn->sql('SELECT 5::int4')->val, "\0\0\0\5";
|
||||
is_deeply $conn->sql('SELECT ARRAY[5::int4]')->val, ["\0\0\0\5"];
|
||||
|
||||
$conn->set_type(int4 => send => 'bytea');
|
||||
is $conn->q('SELECT $1::int4', "\0\0\0\5")->val, 5;
|
||||
is_deeply $conn->q('SELECT $1::int4[]', ["\0\0\0\5"])->val, [5];
|
||||
is $conn->sql('SELECT $1::int4', "\0\0\0\5")->val, 5;
|
||||
is_deeply $conn->sql('SELECT $1::int4[]', ["\0\0\0\5"])->val, [5];
|
||||
|
||||
$conn->set_type(int4 => 'int2');
|
||||
ok !eval { $conn->q('SELECT 5::int4')->val };
|
||||
ok !eval { $conn->sql('SELECT 5::int4')->val };
|
||||
like $@, qr/Error parsing value/;
|
||||
ok !eval { $conn->q('SELECT $1::int4', 5)->val };
|
||||
ok !eval { $conn->sql('SELECT $1::int4', 5)->val };
|
||||
like $@, qr/insufficient data left in message/;
|
||||
|
||||
$conn->set_type(int4 => undef);
|
||||
is $conn->q('SELECT 5::int4')->val, 5;
|
||||
is $conn->sql('SELECT 5::int4')->val, 5;
|
||||
|
||||
ok !eval { $conn->set_type(int4 => 1007); };
|
||||
like $@, qr/Cannot set a type to array/;
|
||||
|
|
@ -46,23 +46,23 @@ subtest 'type overrides', sub {
|
|||
|
||||
subtest 'type override callback', sub {
|
||||
$conn->set_type(text => recv => sub { length $_[0] });
|
||||
is $conn->q('SELECT $1', 'a')->val, 1;
|
||||
is $conn->q('SELECT $1', 'ab')->val, 2;
|
||||
is $conn->q('SELECT $1', 'abc')->val, 3;
|
||||
is $conn->q('SELECT $1', 'abcd')->val, 4;
|
||||
is $conn->sql('SELECT $1', 'a')->val, 1;
|
||||
is $conn->sql('SELECT $1', 'ab')->val, 2;
|
||||
is $conn->sql('SELECT $1', 'abc')->val, 3;
|
||||
is $conn->sql('SELECT $1', 'abcd')->val, 4;
|
||||
|
||||
$conn->set_type(text => send => sub { 'l'.length $_[0] });
|
||||
is $conn->q('SELECT $1', 'a')->val, 'l1';
|
||||
is $conn->q('SELECT $1', 'ab')->val, 'l2';
|
||||
is $conn->q('SELECT $1', 'abc')->val, 'l3';
|
||||
is $conn->q('SELECT $1', 'abcd')->val, 'l4';
|
||||
is $conn->sql('SELECT $1', 'a')->val, 'l1';
|
||||
is $conn->sql('SELECT $1', 'ab')->val, 'l2';
|
||||
is $conn->sql('SELECT $1', 'abc')->val, 'l3';
|
||||
is $conn->sql('SELECT $1', 'abcd')->val, 'l4';
|
||||
};
|
||||
|
||||
|
||||
subtest 'custom types', sub {
|
||||
my $txn = $conn->txn;
|
||||
|
||||
is $txn->Q('SELECT 1', IN([1,2,3]))->val, 1;
|
||||
is $txn->SQL('SELECT 1', IN([1,2,3]))->val, 1;
|
||||
|
||||
$txn->exec(<<~_);
|
||||
CREATE TYPE fupg_test_enum AS ENUM('aa', 'bb', 'ccccccccccccccccccc');
|
||||
|
|
@ -73,21 +73,21 @@ subtest 'custom types', sub {
|
|||
domain fupg_test_domain
|
||||
);
|
||||
_
|
||||
is $txn->q("SELECT 'aa'::fupg_test_enum")->val, 'aa';
|
||||
is $txn->q('SELECT $1::fupg_test_enum', 'ccccccccccccccccccc')->val, 'ccccccccccccccccccc';
|
||||
is $txn->sql("SELECT 'aa'::fupg_test_enum")->val, 'aa';
|
||||
is $txn->sql('SELECT $1::fupg_test_enum', 'ccccccccccccccccccc')->val, 'ccccccccccccccccccc';
|
||||
|
||||
is_deeply $txn->q("SELECT '{aa,bb,null}'::fupg_test_enum[]")->val, ['aa','bb',undef];
|
||||
is $txn->q('SELECT $1::fupg_test_enum[]', ['aa','bb',undef])->text_results->val, '{aa,bb,NULL}';
|
||||
is_deeply $txn->sql("SELECT '{aa,bb,null}'::fupg_test_enum[]")->val, ['aa','bb',undef];
|
||||
is $txn->sql('SELECT $1::fupg_test_enum[]', ['aa','bb',undef])->text_results->val, '{aa,bb,NULL}';
|
||||
|
||||
is $txn->q("SELECT 'aa'::fupg_test_domain")->val, 'aa';
|
||||
is $txn->q('SELECT $1::fupg_test_domain', 'bb')->val, 'bb';
|
||||
is $txn->sql("SELECT 'aa'::fupg_test_domain")->val, 'aa';
|
||||
is $txn->sql('SELECT $1::fupg_test_domain', 'bb')->val, 'bb';
|
||||
|
||||
is_deeply $txn->q("SELECT '{aa,bb,null}'::fupg_test_domain[]")->val, ['aa','bb',undef];
|
||||
is $txn->q('SELECT $1::fupg_test_domain[]', ['aa','bb',undef])->text_results->val, '{aa,bb,NULL}';
|
||||
is_deeply $txn->sql("SELECT '{aa,bb,null}'::fupg_test_domain[]")->val, ['aa','bb',undef];
|
||||
is $txn->sql('SELECT $1::fupg_test_domain[]', ['aa','bb',undef])->text_results->val, '{aa,bb,NULL}';
|
||||
|
||||
my $val = { a => undef, aenum => ['aa','bb'], domain => 'aa' };
|
||||
is_deeply $txn->q("SELECT '(,\"{aa,bb}\",aa)'::fupg_test_record")->val, $val;
|
||||
is $txn->q('SELECT $1::fupg_test_record', $val)->text_results->val, '(,"{aa,bb}",aa)';
|
||||
is_deeply $txn->sql("SELECT '(,\"{aa,bb}\",aa)'::fupg_test_record")->val, $val;
|
||||
is $txn->sql('SELECT $1::fupg_test_record', $val)->text_results->val, '(,"{aa,bb}",aa)';
|
||||
|
||||
$txn->exec(<<~_);
|
||||
CREATE TEMPORARY TABLE fupg_test_table (
|
||||
|
|
@ -96,7 +96,7 @@ subtest 'custom types', sub {
|
|||
);
|
||||
_
|
||||
|
||||
$val = $txn->q(q{SELECT '{"(\"(2,{},bb)\",)","(\"(,,)\",bb)"}'::fupg_test_table[]})->val;
|
||||
$val = $txn->sql(q{SELECT '{"(\"(2,{},bb)\",)","(\"(,,)\",bb)"}'::fupg_test_table[]})->val;
|
||||
is_deeply $val, [
|
||||
{ rec => { a => 2, aenum => [], domain => 'bb' }, dom => undef },
|
||||
{ rec => { a => undef, aenum => undef, domain => undef }, dom => 'bb' },
|
||||
|
|
@ -106,7 +106,7 @@ subtest 'custom types', sub {
|
|||
$val->[1]{rec} = 0;
|
||||
$val->[1]{dom} = 0;
|
||||
|
||||
is $txn->q('SELECT $1::fupg_test_table[]', [
|
||||
is $txn->sql('SELECT $1::fupg_test_table[]', [
|
||||
{ rec => { a => 2, aenum => [], domain => 'bb' }, dom => undef },
|
||||
{ rec => {}, dom => 'bb', extra => 1 },
|
||||
])->text_results->val, '{"(\"(2,{},bb)\",)","(\"(,,)\",bb)"}';
|
||||
|
|
@ -114,46 +114,46 @@ subtest 'custom types', sub {
|
|||
# Wonky Postgres behavior: selecting a domain directly actually returns the
|
||||
# underlying type, but going through an array does work.
|
||||
$conn->set_type(fupg_test_domain => 21);
|
||||
is_deeply $txn->q("SELECT ARRAY['aa'::fupg_test_domain]")->val, [0x6161];
|
||||
is_deeply $txn->sql("SELECT ARRAY['aa'::fupg_test_domain]")->val, [0x6161];
|
||||
|
||||
# Bind param type doesn't match column type, argh.
|
||||
is $txn->q('SELECT $1::fupg_test_domain', 0x6161)->val, 'aa';
|
||||
is $txn->sql('SELECT $1::fupg_test_domain', 0x6161)->val, 'aa';
|
||||
|
||||
# Same for selecting from a table :(
|
||||
$txn->exec("INSERT INTO fupg_test_table VALUES (NULL, 'bb')");
|
||||
is $txn->q("SELECT dom FROM fupg_test_table")->val, 'bb';
|
||||
is $txn->sql("SELECT dom FROM fupg_test_table")->val, 'bb';
|
||||
$conn->set_type(fupg_test_enum => 21);
|
||||
is $txn->q("SELECT dom FROM fupg_test_table")->val, 0x6262;
|
||||
is $txn->sql("SELECT dom FROM fupg_test_table")->val, 0x6262;
|
||||
};
|
||||
|
||||
|
||||
subtest 'identifier quoting', sub {
|
||||
my $txn = $conn->txn;
|
||||
$txn->exec('CREATE TEMPORARY TABLE fupg_test_tbl ("desc" int, ok int, "hello world" int)');
|
||||
ok $txn->Q('INSERT INTO fupg_test_tbl', VALUES {desc => 5, ok => 10, 'hello world', 15})->exec;
|
||||
is $txn->Q('SELECT', IDENT 'hello world', 'FROM fupg_test_tbl')->val, 15;
|
||||
ok $txn->SQL('INSERT INTO fupg_test_tbl', VALUES {desc => 5, ok => 10, 'hello world', 15})->exec;
|
||||
is $txn->SQL('SELECT', IDENT 'hello world', 'FROM fupg_test_tbl')->val, 15;
|
||||
};
|
||||
|
||||
|
||||
subtest 'vndbid', sub {
|
||||
plan skip_all => 'type not loaded in the database' if !$conn->q("SELECT 1 FROM pg_type WHERE typname = 'vndbtag'")->val;
|
||||
plan skip_all => 'type not loaded in the database' if !$conn->sql("SELECT 1 FROM pg_type WHERE typname = 'vndbtag'")->val;
|
||||
|
||||
for my $t (qw/a zz xxx/) {
|
||||
is $conn->q('SELECT $1::vndbtag', $t)->val, $t;
|
||||
is $conn->q('SELECT $1::vndbtag', $t)->text_params->val, $t;
|
||||
is $conn->q('SELECT $1::vndbtag', $t)->text_results->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbtag', $t)->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbtag', $t)->text_params->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbtag', $t)->text_results->val, $t;
|
||||
}
|
||||
ok !eval { $conn->q('SELECT $1::vndbtag', '')->val };
|
||||
ok !eval { $conn->q('SELECT $1::vndbtag', 'abcd')->val };
|
||||
ok !eval { $conn->sql('SELECT $1::vndbtag', '')->val };
|
||||
ok !eval { $conn->sql('SELECT $1::vndbtag', 'abcd')->val };
|
||||
|
||||
for my $t (qw/a123 zz992883231 xxx18388123/) {
|
||||
is $conn->q('SELECT $1::vndbid', $t)->val, $t;
|
||||
is $conn->q('SELECT $1::vndbid', $t)->text_params->val, $t;
|
||||
is $conn->q('SELECT $1::vndbid', $t)->text_results->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbid', $t)->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbid', $t)->text_params->val, $t;
|
||||
is $conn->sql('SELECT $1::vndbid', $t)->text_results->val, $t;
|
||||
}
|
||||
ok !eval { $conn->q('SELECT $1::vndbid', '')->val };
|
||||
ok !eval { $conn->q('SELECT $1::vndbid', 'ab')->val };
|
||||
ok !eval { $conn->q('SELECT $1::vndbid', 'ab1219229999999999')->val };
|
||||
ok !eval { $conn->sql('SELECT $1::vndbid', '')->val };
|
||||
ok !eval { $conn->sql('SELECT $1::vndbid', 'ab')->val };
|
||||
ok !eval { $conn->sql('SELECT $1::vndbid', 'ab1219229999999999')->val };
|
||||
};
|
||||
|
||||
done_testing;
|
||||
|
|
|
|||
20
t/pgtypes.t
20
t/pgtypes.t
|
|
@ -22,7 +22,7 @@ sub v($type, $p_in, @args) {
|
|||
my $oid;
|
||||
utf8::encode($test);
|
||||
{
|
||||
my $st = $conn->q("SELECT \$1::$type", $s_in)->text_params;
|
||||
my $st = $conn->sql("SELECT \$1::$type", $s_in)->text_params;
|
||||
$oid = $st->param_types->[0];
|
||||
my $array = $st->flat;
|
||||
my $res = $array->[0];
|
||||
|
|
@ -32,11 +32,11 @@ sub v($type, $p_in, @args) {
|
|||
$array->[0] = 0; # Must be writable
|
||||
}
|
||||
{
|
||||
my $res = $conn->q("SELECT \$1::$type", $p_in)->text_results->val;
|
||||
my $res = $conn->sql("SELECT \$1::$type", $p_in)->text_results->val;
|
||||
is $res, $s_out, "$test bin->text";
|
||||
}
|
||||
{
|
||||
my $res = $conn->q("SELECT \$1::$type", $p_in)->val;
|
||||
my $res = $conn->sql("SELECT \$1::$type", $p_in)->val;
|
||||
is_deeply $res, $p_out, "$test bin->bin";
|
||||
}
|
||||
{
|
||||
|
|
@ -52,11 +52,11 @@ sub v($type, $p_in, @args) {
|
|||
sub f($type, $p_in) {
|
||||
my $test = "$type $p_in" =~ s/\n/\\n/rg;
|
||||
utf8::encode($test);
|
||||
ok !eval { $conn->q("SELECT \$1::$type", $p_in)->val; 1 }, "$test fail";
|
||||
ok !eval { $conn->sql("SELECT \$1::$type", $p_in)->val; 1 }, "$test fail";
|
||||
}
|
||||
|
||||
{ # void
|
||||
my $array = $conn->q('SELECT pg_sleep(0)')->flat;
|
||||
my $array = $conn->sql('SELECT pg_sleep(0)')->flat;
|
||||
ok !defined $array->[0];
|
||||
$array->[0] = 0;
|
||||
}
|
||||
|
|
@ -187,11 +187,11 @@ f 'oidvector', [undef];
|
|||
|
||||
# Example from https://www.postgresql.org/docs/17/arrays.html#ARRAYS-IO
|
||||
# Lower bounds are discarded.
|
||||
is_deeply $conn->q("SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[]")->val, [[[1,2,3],[4,5,6]]];
|
||||
is_deeply $conn->sql("SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[]")->val, [[[1,2,3],[4,5,6]]];
|
||||
|
||||
is $conn->q('SELECT ($1::int2[])[2]', [1,2,3,4])->val, 2;
|
||||
is $conn->q('SELECT ($1::int2vector)[1]', [1,2,3,4])->val, 2;
|
||||
is $conn->q('SELECT ($1::oidvector)[1]', [1,2,3,4])->val, 2;
|
||||
is $conn->sql('SELECT ($1::int2[])[2]', [1,2,3,4])->val, 2;
|
||||
is $conn->sql('SELECT ($1::int2vector)[1]', [1,2,3,4])->val, 2;
|
||||
is $conn->sql('SELECT ($1::oidvector)[1]', [1,2,3,4])->val, 2;
|
||||
|
||||
is_deeply [$conn->bin2text(
|
||||
16, $conn->perl2bin(16, 1),
|
||||
|
|
@ -207,7 +207,7 @@ is_deeply [$conn->bin2text(
|
|||
}
|
||||
|
||||
{
|
||||
my $v = $conn->q("SELECT '{t,f,NULL}'::bool[]")->val;
|
||||
my $v = $conn->sql("SELECT '{t,f,NULL}'::bool[]")->val;
|
||||
is_deeply $v, [true, false, undef];
|
||||
$_ = 0 for @$v;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue