#!perl ## Test the COPY functionality use strict; use warnings; use Data::Dumper; use Test::More; use lib 't','.'; require 'dbdpg_test_setup.pl'; select(($|=1,select(STDERR),$|=1)[1]); my $dbh = connect_database(); if (defined $dbh) { plan tests => 55; } else { plan skip_all => 'Connection to database failed, cannot continue testing'; } ok( defined $dbh, 'Connect to database for bytea testing'); my ($sth,$count,$result,$expected,@data); my $table = 'dbd_pg_test4'; $dbh->do(qq{CREATE TABLE $table(id2 integer, val2 text)}); $dbh->commit(); my $pgversion = $dbh->{pg_server_version}; # # Test of the pg_putline and pg_endcopy methods # ## pg_putline should fail unless we are in a COPY IN state eval { $dbh->pg_putline("12\tMulberry"); }; ok($@, 'pg_putline fails when issued without a preceding COPY command'); $dbh->do("COPY $table FROM STDIN"); $result = $dbh->pg_putline("12\tMulberry\n"); is($result,1,'putline returned a value of 1 for success'); $result = $dbh->pg_putline("13\tStrawberry\n"); is($result,1,'putline returned a value of 1 for success'); $result = $dbh->pg_putline("14\tBlueberry\n"); is($result,1,'putline returned a value of 1 for success'); ## Commands are not allowed while in a COPY IN state eval { $dbh->do(q{SELECT 'dbdpg_copytest'}); }; ok($@, 'do() fails while in a COPY IN state'); ## pg_getline is not allowed as we are in a COPY_IN state $data[0] = ''; eval { $dbh->pg_getline($data[0], 100); }; ok($@, 'pg_getline fails while in a COPY IN state'); $result = $dbh->pg_endcopy(); is($result,1,'pg_endcopy returned a 1'); ## Make sure we can issue normal commands again $dbh->do(q{SELECT 'dbdpg_copytest'}); ## Make sure we are out of the COPY IN state and pg_putline no longer works eval { $dbh->pg_putline("16\tBlackberry"); }; ok($@, 'pg_putline fails when issued after pg_endcopy called'); ## Check that our lines were inserted properly $expected = [[12 => 'Mulberry'],[13 => 'Strawberry'],[14 => 'Blueberry']]; $result = $dbh->selectall_arrayref("SELECT id2,val2 FROM $table ORDER BY id2"); is_deeply( $result, $expected, 'putline inserted values correctly'); # pg_endcopy should not work because we are no longer in a COPY state eval { $dbh->pg_endcopy; }; ok($@, 'pg_endcopy fails when called twice after COPY IN'); $dbh->commit(); # # Test of the pg_getline method # ## pg_getline should fail unless we are in a COPY OUT state eval { $dbh->pg_getline($data[0], 100); }; ok($@, 'pg_getline fails when issued without a preceding COPY command'); $dbh->do("COPY $table TO STDOUT"); my ($buffer,$badret,$badval) = ('',0,0); $result = $dbh->pg_getline($data[0], 100); is ($result, 1, 'pg_getline returned a 1'); ## Commands are not allowed while in a COPY OUT state eval { $dbh->do(q{SELECT 'dbdpg_copytest'}); }; ok($@, 'do() fails while in a COPY OUT state'); ## pg_putline is not allowed as we are in a COPY OUT state eval { $dbh->pg_putline("99\tBogusberry"); }; ok($@, 'pg_putline fails while in a COPY OUT state'); $data[1]=$data[2]=$data[3]=''; $result = $dbh->pg_getline($data[1], 100); is ($result, 1, 'pg_getline returned a 1'); $result = $dbh->pg_getline($data[2], 100); is ($result, 1, 'pg_getline returned a 1'); $result = $dbh->pg_getline($data[3], 100); is ($result, '', 'pg_getline returns empty on final call'); $result = \@data; $expected = ["12\tMulberry\n","13\tStrawberry\n","14\tBlueberry\n",'']; is_deeply( $result, $expected, 'getline returned all rows successfuly'); ## Make sure we can issue normal commands again $dbh->do(q{SELECT 'dbdpg_copytest'}); ## Make sure we are out of the COPY OUT state and pg_getline no longer works eval { $data[5]=''; $dbh->pg_getline($data[5], 100); }; ok($@, 'pg_getline fails when issued after pg_endcopy called'); ## pg_endcopy should fail because we are no longer in a COPY state eval { $dbh->pg_endcopy; }; ok($@, 'pg_endcopy fails when called twice after COPY OUT'); ## ## Test the new COPY methods ## $dbh->do("DELETE FROM $table"); my $t=q{pg_putcopydata fails if not after a COPY statement}; eval { $dbh->pg_putcopydata("pizza\tpie"); }; like($@, qr{COPY command}, $t); $t=q{pg_getcopydata fails if not after a COPY statement}; eval { $dbh->pg_getcopydata($data[0]); }; like($@, qr{COPY command}, $t); $t=q{pg_getcopydata_async fails if not after a COPY statement}; eval { $dbh->pg_getcopydata_async($data[0]); }; like($@, qr{COPY command}, $t); $t=q{pg_putcopyend warns but does not die if not after a COPY statement}; eval { require Test::Warn; }; if ($@) { pass('Skipping Test::Warn test'); } else { Test::Warn::warning_like (sub { $dbh->pg_putcopyend(); }, qr/until a COPY/, $t); } $t=q{pg_getcopydata does not work if we are using COPY .. FROM}; $dbh->rollback(); $dbh->do("COPY $table FROM STDIN"); eval { $dbh->pg_getcopydata($data[0]); }; like($@, qr{COPY command}, $t); $t=q{pg_putcopydata does not work if we are using COPY .. TO}; $dbh->rollback(); $dbh->do("COPY $table TO STDOUT"); eval { $dbh->pg_putcopydata("pizza\tpie"); }; like($@, qr{COPY command}, $t); $t=q{pg_putcopydata works and returns a 1 on success}; $dbh->rollback(); $dbh->do("COPY $table FROM STDIN"); $result = $dbh->pg_putcopydata("15\tBlueberry"); is ($result, 1, $t); $t=q{pg_putcopydata works on second call}; $dbh->rollback(); $dbh->do("COPY $table FROM STDIN"); $result = $dbh->pg_putcopydata("16\tMoreBlueberries"); is ($result, 1, $t); $t=q{pg_putcopydata fails with invalid data}; $dbh->rollback(); $dbh->do("COPY $table FROM STDIN"); eval { $dbh->pg_putcopydata(); }; ok($@, $t); $t=q{Calling pg_getcopydata gives an error when in the middle of COPY .. FROM}; eval { $dbh->pg_getcopydata($data[0]); }; like($@, qr{COPY command}, $t); $t=q{Calling do() gives an error when in the middle of COPY .. FROM}; eval { $dbh->do('SELECT 123'); }; like($@, qr{call pg_putcopyend}, $t); $t=q{pg_putcopydata works after a rude non-COPY attempt}; eval { $result = $dbh->pg_putcopydata("17\tMoreBlueberries"); }; is($@, q{}, $t); is ($result, 1, $t); $t=q{pg_putcopyend works and returns a 1}; eval { $result = $dbh->pg_putcopyend(); }; is($@, q{}, $t); is ($result, 1, $t); $dbh->commit(); $t=q{pg_putcopydata fails after pg_putcopyend is called}; eval { $result = $dbh->pg_putcopydata('root'); }; like($@, qr{COPY command}, $t); $t=q{Normal queries work after pg_putcopyend is called}; eval { $dbh->do('SELECT 123'); }; is($@, q{}, $t); $t=q{Data from pg_putcopydata was entered correctly}; $result = $dbh->selectall_arrayref("SELECT id2,val2 FROM $table ORDER BY id2"); $expected = [['12','Mulberry'],['13','Strawberry'],[14,'Blueberry'],[17,'MoreBlueberries']]; is_deeply($result, $expected, $t); $dbh->do("COPY $table TO STDOUT"); $t=q{pg_getcopydata fails when argument is not a variable}; eval { $dbh->pg_getcopydata('wrongo'); }; like($@, qr{read-only}, $t); $t=q{pg_getcopydata works and returns the length of the string}; $data[0] = 'old'; eval { $dbh->pg_getcopydata($data[0]); }; is($@, q{}, $t); is($data[0], "13\tStrawberry\n", $t); $t=q{pg_getcopydata works when argument is a reference}; eval { $dbh->pg_getcopydata(\$data[0]); }; is($@, q{}, $t); is($data[0], "14\tBlueberry\n", $t); $t=q{Calling do() gives an error when in the middle of COPY .. TO}; eval { $dbh->do('SELECT 234'); }; like($@, qr{pg_getcopydata}, $t); $t=q{Calling pg_putcopydata gives an errors when in the middle of COPY .. TO}; eval { $dbh->pg_putcopydata('pie'); }; like($@, qr{COPY command}, $t); $t=q{pg_getcopydata returns 0 when no more data}; $dbh->pg_getcopydata(\$data[0]); eval { $result = $dbh->pg_getcopydata(\$data[0]); }; is($@, q{}, $t); is($data[0], '', $t); is($result, -1, $t); $t=q{Normal queries work after pg_getcopydata runs out}; eval { $dbh->do('SELECT 234'); }; is($@, q{}, $t); SKIP: { $pgversion < 80200 and skip 'Server version 8.2 or greater needed for test', 1; $t=q{pg_getcopydata works when pulling from an empty table into an empty var}; $dbh->do(q{COPY (SELECT 1 FROM pg_class LIMIT 0) TO STDOUT}); eval { my $newvar; $dbh->pg_getcopydata($newvar); }; is($@, q{}, $t); }; # # Make sure rollback and commit reset our internal copystate tracking # $dbh->do("COPY $table TO STDOUT"); $dbh->commit(); eval { $dbh->do(q{SELECT 'dbdpg_copytest'}); }; ok(!$@, 'commit resets COPY state'); $dbh->do("COPY $table TO STDOUT"); $dbh->rollback(); eval { $dbh->do(q{SELECT 'dbdpg_copytest'}); }; ok(!$@, 'rollback resets COPY state'); # # Keep old-style calls around for backwards compatibility # $dbh->do("COPY $table FROM STDIN"); $result = $dbh->func("13\tOlive\n", 'putline'); is ($result, 1, q{old-style dbh->func('text', 'putline') still works}); $dbh->pg_endcopy; $dbh->do("COPY $table TO STDOUT"); $result = $dbh->func($data[0], 100, 'getline'); is ($result, 1, q{old-style dbh->func(var, length, 'getline') still works}); 1 while ($result = $dbh->func($data[0], 100, 'getline')); $dbh->do("DROP TABLE $table"); $dbh->commit(); cleanup_database($dbh,'test'); $dbh->disconnect;