pg: Add support for record/composite types

This is simply magical. \o/

Vendored in khashl.h. I wouldn't have used it if this were the only
place where I'd need a custom hash table, but it should come in handy
for other tasks as well, especially when I get to implementing an LRU
for prepared statement caching.

(Can all be done with Perl HV's, but they're less efficient and more
cumbersome for these tasks)
This commit is contained in:
Yorhel 2025-02-11 15:56:35 +01:00
parent 33fe0d98a8
commit 87d99e412b
5 changed files with 642 additions and 4 deletions

View file

@ -6,25 +6,54 @@ die $@ if $@;
plan skip_all => 'Please set FU_TEST_DB to a PostgreSQL connection string to run these tests' if !$ENV{FU_TEST_DB};
my $conn = FU::Pg->connect($ENV{FU_TEST_DB});
$conn->_debug_trace(0);
ok !eval { $conn->q('SELECT $1::aclitem', '')->exec; 1 };
like $@, qr/Unable to send or receive/;
{
my $txn = $conn->txn;
$txn->exec("CREATE TYPE fupg_test_enum AS ENUM('a', 'b', 'ccccccccccccccccccc')");
$txn->exec(<<~_);
CREATE TYPE fupg_test_enum AS ENUM('a', 'b', 'ccccccccccccccccccc');
CREATE DOMAIN fupg_test_domain AS fupg_test_enum CHECK(value IN('a','b'));
CREATE TYPE fupg_test_record AS (
a int,
aenum fupg_test_enum[],
domain fupg_test_domain
);
_
is $txn->q("SELECT 'a'::fupg_test_enum")->val, 'a';
is $txn->q('SELECT $1::fupg_test_enum', 'ccccccccccccccccccc')->val, 'ccccccccccccccccccc';
is_deeply $txn->q("SELECT '{a,b,null}'::fupg_test_enum[]")->val, ['a','b',undef];
is $txn->q('SELECT $1::fupg_test_enum[]', ['a','b',undef])->text_results->val, '{a,b,NULL}';
$txn->exec("CREATE DOMAIN fupg_test_domain AS fupg_test_enum CHECK(value IN('a','b'))");
is $txn->q("SELECT 'a'::fupg_test_domain")->val, 'a';
is $txn->q('SELECT $1::fupg_test_domain', 'b')->val, 'b';
is_deeply $txn->q("SELECT '{a,b,null}'::fupg_test_domain[]")->val, ['a','b',undef];
is $txn->q('SELECT $1::fupg_test_domain[]', ['a','b',undef])->text_results->val, '{a,b,NULL}';
my $val = { a => undef, aenum => ['a','b'], domain => 'a' };
is_deeply $txn->q("SELECT '(,\"{a,b}\",a)'::fupg_test_record")->val, $val;
is $txn->q('SELECT $1::fupg_test_record', $val)->text_results->val, '(,"{a,b}",a)';
$txn->exec(<<~_);
CREATE TEMPORARY TABLE fupg_test_table (
rec fupg_test_record,
dom fupg_test_domain
);
_
is_deeply $txn->q(q{SELECT '{"(\"(2,{},b)\",)","(\"(,,)\",b)"}'::fupg_test_table[]})->val, [
{ rec => { a => 2, aenum => [], domain => 'b' }, dom => undef },
{ rec => { a => undef, aenum => undef, domain => undef }, dom => 'b' },
];
is $txn->q('SELECT $1::fupg_test_table[]', [
{ rec => { a => 2, aenum => [], domain => 'b' }, dom => undef },
{ rec => {}, dom => 'b', extra => 1 },
])->text_results->val, '{"(\"(2,{},b)\",)","(\"(,,)\",b)"}';
}
done_testing;