78897988e4eabaa90873807411dda648fb6b8e81
[dbsrgits/DBIx-Class.git] / t / 72pg.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6 use lib qw(t/lib);
7 use DBICTest;
8
9
10 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
11
12 plan skip_all => <<EOM unless $dsn && $user;
13 Set \$ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test
14 ( NOTE: This test drops and creates tables called 'artist', 'casecheck',
15   'array_test' and 'sequence_test' as well as following sequences:
16   'pkid1_seq', 'pkid2_seq' and 'nonpkid_seq''.  as well as following
17   schemas: 'dbic_t_schema', 'dbic_t_schema_2', 'dbic_t_schema_3',
18   'dbic_t_schema_4', and 'dbic_t_schema_5'
19 )
20 EOM
21
22 ### load any test classes that are defined further down in the file
23
24 our @test_classes; #< array that will be pushed into by test classes defined in this file
25 DBICTest::Schema->load_classes( map {s/.+:://;$_} @test_classes ) if @test_classes;
26
27
28 ###  pre-connect tests
29 {
30   my $s = DBICTest::Schema->connect($dsn, $user, $pass);
31
32   ok (!$s->storage->_dbh, 'definitely not connected');
33
34   # Check that datetime_parser returns correctly before we explicitly connect.
35   SKIP: {
36       eval { require DateTime::Format::Pg };
37       skip "DateTime::Format::Pg required", 2 if $@;
38
39       my $store = ref $s->storage;
40       is($store, 'DBIx::Class::Storage::DBI', 'Started with generic storage');
41
42       my $parser = $s->storage->datetime_parser;
43       is( $parser, 'DateTime::Format::Pg', 'datetime_parser is as expected');
44   }
45
46   ok (!$s->storage->_dbh, 'still not connected');
47 }
48 {
49   my $s = DBICTest::Schema->connect($dsn, $user, $pass);
50   # make sure sqlt_type overrides work (::Storage::DBI::Pg does this)
51   ok (!$s->storage->_dbh, 'definitely not connected');
52   is ($s->storage->sqlt_type, 'PostgreSQL', 'sqlt_type correct pre-connection');
53   ok (!$s->storage->_dbh, 'still not connected');
54 }
55
56 ### connect, create postgres-specific test schema
57
58 my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
59
60 drop_test_schema($schema, 'no warn');
61 create_test_schema($schema);
62
63 ### begin main tests
64
65
66 # run a BIG bunch of tests for last-insert-id / Auto-PK / sequence
67 # discovery
68 run_apk_tests($schema); #< older set of auto-pk tests
69 run_extended_apk_tests($schema); #< new extended set of auto-pk tests
70
71 ### type_info tests
72
73 my $test_type_info = {
74     'artistid' => {
75         'data_type' => 'integer',
76         'is_nullable' => 0,
77         'size' => 4,
78     },
79     'name' => {
80         'data_type' => 'character varying',
81         'is_nullable' => 1,
82         'size' => 100,
83         'default_value' => undef,
84     },
85     'rank' => {
86         'data_type' => 'integer',
87         'is_nullable' => 0,
88         'size' => 4,
89         'default_value' => 13,
90
91     },
92     'charfield' => {
93         'data_type' => 'character',
94         'is_nullable' => 1,
95         'size' => 10,
96         'default_value' => undef,
97     },
98     'arrayfield' => {
99         'data_type' => 'integer[]',
100         'is_nullable' => 1,
101         'size' => undef,
102         'default_value' => undef,
103     },
104 };
105
106 my $type_info = $schema->storage->columns_info_for('dbic_t_schema.artist');
107 my $artistid_defval = delete $type_info->{artistid}->{default_value};
108 like($artistid_defval,
109      qr/^nextval\('([^\.]*\.){0,1}artist_artistid_seq'::(?:text|regclass)\)/,
110      'columns_info_for - sequence matches Pg get_autoinc_seq expectations');
111 is_deeply($type_info, $test_type_info,
112           'columns_info_for - column data types');
113
114
115
116
117 ####### Array tests
118
119 BEGIN {
120   package DBICTest::Schema::ArrayTest;
121   push @main::test_classes, __PACKAGE__;
122
123   use strict;
124   use warnings;
125   use base 'DBIx::Class';
126
127   __PACKAGE__->load_components(qw/Core/);
128   __PACKAGE__->table('dbic_t_schema.array_test');
129   __PACKAGE__->add_columns(qw/id arrayfield/);
130   __PACKAGE__->column_info_from_storage(1);
131   __PACKAGE__->set_primary_key('id');
132
133 }
134 SKIP: {
135   skip "Need DBD::Pg 2.9.2 or newer for array tests", 4 if $DBD::Pg::VERSION < 2.009002;
136
137   lives_ok {
138     $schema->resultset('ArrayTest')->create({
139       arrayfield => [1, 2],
140     });
141   } 'inserting arrayref as pg array data';
142
143   lives_ok {
144     $schema->resultset('ArrayTest')->update({
145       arrayfield => [3, 4],
146     });
147   } 'updating arrayref as pg array data';
148
149   $schema->resultset('ArrayTest')->create({
150     arrayfield => [5, 6],
151   });
152
153   my $count;
154   lives_ok {
155     $count = $schema->resultset('ArrayTest')->search({
156       arrayfield => \[ '= ?' => [arrayfield => [3, 4]] ],   #Todo anything less ugly than this?
157     })->count;
158   } 'comparing arrayref to pg array data does not blow up';
159   is($count, 1, 'comparing arrayref to pg array data gives correct result');
160 }
161
162
163
164 ########## Case check
165
166 BEGIN {
167   package DBICTest::Schema::Casecheck;
168   push @main::test_classes, __PACKAGE__;
169
170   use strict;
171   use warnings;
172   use base 'DBIx::Class';
173
174   __PACKAGE__->load_components(qw/Core/);
175   __PACKAGE__->table('dbic_t_schema.casecheck');
176   __PACKAGE__->add_columns(qw/id name NAME uc_name storecolumn/);
177   __PACKAGE__->column_info_from_storage(1);
178   __PACKAGE__->set_primary_key('id');
179
180   sub store_column {
181     my ($self, $name, $value) = @_;
182     $value = '#'.$value if($name eq "storecolumn");
183     $self->maybe::next::method($name, $value);
184   }
185 }
186
187 # store_column is called once for create() for non sequence columns
188 ok(my $storecolumn = $schema->resultset('Casecheck')->create({'storecolumn' => 'a'}));
189 is($storecolumn->storecolumn, '#a'); # was '##a'
190
191 my $name_info = $schema->source('Casecheck')->column_info( 'name' );
192 is( $name_info->{size}, 1, "Case sensitive matching info for 'name'" );
193
194 my $NAME_info = $schema->source('Casecheck')->column_info( 'NAME' );
195 is( $NAME_info->{size}, 2, "Case sensitive matching info for 'NAME'" );
196
197 my $uc_name_info = $schema->source('Casecheck')->column_info( 'uc_name' );
198 is( $uc_name_info->{size}, 3, "Case insensitive matching info for 'uc_name'" );
199
200
201
202
203 ## Test SELECT ... FOR UPDATE
204
205 my $HaveSysSigAction = eval "require Sys::SigAction" && !$@;
206 if( $HaveSysSigAction ) {
207     Sys::SigAction->import( 'set_sig_handler' );
208 }
209 SKIP: {
210     skip "Sys::SigAction is not available", 3 unless $HaveSysSigAction;
211     # create a new schema
212     my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
213     $schema2->source("Artist")->name("dbic_t_schema.artist");
214
215     $schema->txn_do( sub {
216         my $artist = $schema->resultset('Artist')->search(
217             {
218                 artistid => 1
219             },
220             {
221                 for => 'update'
222             }
223         )->first;
224         is($artist->artistid, 1, "select for update returns artistid = 1");
225
226         my $artist_from_schema2;
227         my $error_ok = 0;
228         eval {
229             my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
230             alarm(2);
231             $artist_from_schema2 = $schema2->resultset('Artist')->find(1);
232             $artist_from_schema2->name('fooey');
233             $artist_from_schema2->update;
234             alarm(0);
235         };
236         if (my $e = $@) {
237             $error_ok = $e =~ /DBICTestTimeout/;
238         }
239
240         # Make sure that an error was raised, and that the update failed
241         ok($error_ok, "update from second schema times out");
242         ok($artist_from_schema2->is_column_changed('name'), "'name' column is still dirty from second schema");
243     });
244 }
245
246 SKIP: {
247     skip "Sys::SigAction is not available", 3 unless $HaveSysSigAction;
248     # create a new schema
249     my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
250     $schema2->source("Artist")->name("dbic_t_schema.artist");
251
252     $schema->txn_do( sub {
253         my $artist = $schema->resultset('Artist')->search(
254             {
255                 artistid => 1
256             },
257         )->first;
258         is($artist->artistid, 1, "select for update returns artistid = 1");
259
260         my $artist_from_schema2;
261         my $error_ok = 0;
262         eval {
263             my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
264             alarm(2);
265             $artist_from_schema2 = $schema2->resultset('Artist')->find(1);
266             $artist_from_schema2->name('fooey');
267             $artist_from_schema2->update;
268             alarm(0);
269         };
270         if (my $e = $@) {
271             $error_ok = $e =~ /DBICTestTimeout/;
272         }
273
274         # Make sure that an error was NOT raised, and that the update succeeded
275         ok(! $error_ok, "update from second schema DOES NOT timeout");
276         ok(! $artist_from_schema2->is_column_changed('name'), "'name' column is NOT dirty from second schema");
277     });
278 }
279
280
281 ######## other older Auto-pk tests
282
283 $schema->source("SequenceTest")->name("dbic_t_schema.sequence_test");
284 for (1..5) {
285     my $st = $schema->resultset('SequenceTest')->create({ name => 'foo' });
286     is($st->pkid1, $_, "Oracle Auto-PK without trigger: First primary key");
287     is($st->pkid2, $_ + 9, "Oracle Auto-PK without trigger: Second primary key");
288     is($st->nonpkid, $_ + 19, "Oracle Auto-PK without trigger: Non-primary key");
289 }
290 my $st = $schema->resultset('SequenceTest')->create({ name => 'foo', pkid1 => 55 });
291 is($st->pkid1, 55, "Oracle Auto-PK without trigger: First primary key set manually");
292
293 done_testing;
294
295 exit;
296
297 END {
298     drop_test_schema($schema);
299     eapk_drop_all( $schema)
300 };
301
302
303 ######### SUBROUTINES
304
305 sub create_test_schema {
306     my $schema = shift;
307     $schema->storage->dbh_do(sub {
308       my (undef,$dbh) = @_;
309
310       local $dbh->{Warn} = 0;
311
312       my $std_artist_table = <<EOS;
313 (
314   artistid serial PRIMARY KEY
315   , name VARCHAR(100)
316   , rank INTEGER NOT NULL DEFAULT '13'
317   , charfield CHAR(10)
318   , arrayfield INTEGER[]
319 )
320 EOS
321
322       $dbh->do("CREATE SCHEMA dbic_t_schema");
323       $dbh->do("CREATE TABLE dbic_t_schema.artist $std_artist_table");
324       $dbh->do(<<EOS);
325 CREATE TABLE dbic_t_schema.sequence_test (
326     pkid1 integer
327     , pkid2 integer
328     , nonpkid integer
329     , name VARCHAR(100)
330     , CONSTRAINT pk PRIMARY KEY(pkid1, pkid2)
331 )
332 EOS
333       $dbh->do("CREATE SEQUENCE pkid1_seq START 1 MAXVALUE 999999 MINVALUE 0");
334       $dbh->do("CREATE SEQUENCE pkid2_seq START 10 MAXVALUE 999999 MINVALUE 0");
335       $dbh->do("CREATE SEQUENCE nonpkid_seq START 20 MAXVALUE 999999 MINVALUE 0");
336       $dbh->do(<<EOS);
337 CREATE TABLE dbic_t_schema.casecheck (
338     id serial PRIMARY KEY
339     , "name" VARCHAR(1)
340     , "NAME" VARCHAR(2)
341     , "UC_NAME" VARCHAR(3)
342     , "storecolumn" VARCHAR(10)
343 )
344 EOS
345       $dbh->do(<<EOS);
346 CREATE TABLE dbic_t_schema.array_test (
347     id serial PRIMARY KEY
348     , arrayfield INTEGER[]
349 )
350 EOS
351       $dbh->do("CREATE SCHEMA dbic_t_schema_2");
352       $dbh->do("CREATE TABLE dbic_t_schema_2.artist $std_artist_table");
353       $dbh->do("CREATE SCHEMA dbic_t_schema_3");
354       $dbh->do("CREATE TABLE dbic_t_schema_3.artist $std_artist_table");
355       $dbh->do('set search_path=dbic_t_schema,public');
356       $dbh->do("CREATE SCHEMA dbic_t_schema_4");
357       $dbh->do("CREATE SCHEMA dbic_t_schema_5");
358       $dbh->do(<<EOS);
359  CREATE TABLE dbic_t_schema_4.artist
360  (
361    artistid integer not null default nextval('artist_artistid_seq'::regclass) PRIMARY KEY
362    , name VARCHAR(100)
363    , rank INTEGER NOT NULL DEFAULT '13'
364    , charfield CHAR(10)
365    , arrayfield INTEGER[]
366  );
367 EOS
368       $dbh->do('set search_path=public,dbic_t_schema,dbic_t_schema_3');
369       $dbh->do('create sequence public.artist_artistid_seq'); #< in the public schema
370       $dbh->do(<<EOS);
371  CREATE TABLE dbic_t_schema_5.artist
372  (
373    artistid integer not null default nextval('public.artist_artistid_seq'::regclass) PRIMARY KEY
374    , name VARCHAR(100)
375    , rank INTEGER NOT NULL DEFAULT '13'
376    , charfield CHAR(10)
377    , arrayfield INTEGER[]
378  );
379 EOS
380       $dbh->do('set search_path=dbic_t_schema,public');
381   });
382 }
383
384
385
386 sub drop_test_schema {
387     my ( $schema, $no_warn ) = @_;
388
389     $schema->storage->dbh_do(sub {
390         my (undef,$dbh) = @_;
391
392         local $dbh->{Warn} = 0;
393
394         for my $stat (
395                       'DROP SCHEMA dbic_t_schema_5 CASCADE',
396                       'DROP SEQUENCE public.artist_artistid_seq',
397                       'DROP SCHEMA dbic_t_schema_4 CASCADE',
398                       'DROP SCHEMA dbic_t_schema CASCADE',
399                       'DROP SEQUENCE pkid1_seq',
400                       'DROP SEQUENCE pkid2_seq',
401                       'DROP SEQUENCE nonpkid_seq',
402                       'DROP SCHEMA dbic_t_schema_2 CASCADE',
403                       'DROP SCHEMA dbic_t_schema_3 CASCADE',
404                      ) {
405             eval { $dbh->do ($stat) };
406             diag $@ if $@ && !$no_warn;
407         }
408     });
409 }
410
411
412 ###  auto-pk / last_insert_id / sequence discovery
413 sub run_apk_tests {
414     my $schema = shift;
415
416     # This is in Core now, but it's here just to test that it doesn't break
417     $schema->class('Artist')->load_components('PK::Auto');
418     cmp_ok( $schema->resultset('Artist')->count, '==', 0, 'this should start with an empty artist table');
419
420     # test that auto-pk also works with the defined search path by
421     # un-schema-qualifying the table name
422     apk_t_set($schema,'artist');
423
424     my $unq_new;
425     lives_ok {
426         $unq_new = $schema->resultset('Artist')->create({ name => 'baz' });
427     } 'insert into unqualified, shadowed table succeeds';
428
429     is($unq_new && $unq_new->artistid, 1, "and got correct artistid");
430
431     my @test_schemas = ( [qw| dbic_t_schema_2    1  |],
432                          [qw| dbic_t_schema_3    1  |],
433                          [qw| dbic_t_schema_4    2  |],
434                          [qw| dbic_t_schema_5    1  |],
435                        );
436     foreach my $t ( @test_schemas ) {
437         my ($sch_name, $start_num) = @$t;
438         #test with dbic_t_schema_2
439         apk_t_set($schema,"$sch_name.artist");
440         my $another_new;
441         lives_ok {
442             $another_new = $schema->resultset('Artist')->create({ name => 'Tollbooth Willy'});
443             is( $another_new->artistid,$start_num, "got correct artistid for $sch_name")
444                 or diag "USED SEQUENCE: ".($schema->source('Artist')->column_info('artistid')->{sequence} || '<none>');
445         } "$sch_name liid 1 did not die"
446             or diag "USED SEQUENCE: ".($schema->source('Artist')->column_info('artistid')->{sequence} || '<none>');
447         lives_ok {
448             $another_new = $schema->resultset('Artist')->create({ name => 'Adam Sandler'});
449             is( $another_new->artistid,$start_num+1, "got correct artistid for $sch_name")
450                 or diag "USED SEQUENCE: ".($schema->source('Artist')->column_info('artistid')->{sequence} || '<none>');
451         } "$sch_name liid 2 did not die"
452             or diag "USED SEQUENCE: ".($schema->source('Artist')->column_info('artistid')->{sequence} || '<none>');
453
454     }
455
456     lives_ok {
457         apk_t_set($schema,'dbic_t_schema.artist');
458         my $new = $schema->resultset('Artist')->create({ name => 'foo' });
459         is($new->artistid, 4, "Auto-PK worked");
460         $new = $schema->resultset('Artist')->create({ name => 'bar' });
461         is($new->artistid, 5, "Auto-PK worked");
462     } 'old auto-pk tests did not die either';
463 }
464
465 # sets the artist table name and clears sequence name cache
466 sub apk_t_set {
467     my ( $s, $n ) = @_;
468     $s->source("Artist")->name($n);
469     $s->source('Artist')->column_info('artistid')->{sequence} = undef; #< clear sequence name cache
470 }
471
472
473 ######## EXTENDED AUTO-PK TESTS
474
475 my @eapk_id_columns;
476 BEGIN {
477   package DBICTest::Schema::ExtAPK;
478   push @main::test_classes, __PACKAGE__;
479
480   use strict;
481   use warnings;
482   use base 'DBIx::Class';
483
484   __PACKAGE__->load_components(qw/Core/);
485   __PACKAGE__->table('apk');
486
487   @eapk_id_columns = qw( id1 id2 id3 id4 );
488   __PACKAGE__->add_columns(
489     map { $_ => { data_type => 'integer', is_auto_increment => 1 } }
490        @eapk_id_columns
491   );
492
493   __PACKAGE__->set_primary_key('id2'); #< note the SECOND column is
494                                        #the primary key
495 }
496
497 my @eapk_schemas;
498 BEGIN{ @eapk_schemas = map "dbic_apk_$_", 0..5 }
499
500 sub run_extended_apk_tests {
501   my $schema = shift;
502
503   #save the search path and reset it at the end
504   my $search_path_save = $schema->storage->dbh_do('_get_pg_search_path');
505
506   eapk_drop_all($schema,'no warn');
507
508   # make the test schemas and sequences
509   $schema->storage->dbh_do(sub {
510     my ( undef, $dbh ) = @_;
511
512     $dbh->do("CREATE SCHEMA $_")
513         for @eapk_schemas;
514
515     $dbh->do("CREATE SEQUENCE $eapk_schemas[5].fooseq");
516     $dbh->do("CREATE SEQUENCE $eapk_schemas[4].fooseq");
517     $dbh->do("CREATE SEQUENCE $eapk_schemas[3].fooseq");
518
519     $dbh->do("SET search_path = ".join ',', @eapk_schemas );
520   });
521
522   # clear our search_path cache
523   $schema->storage->{_pg_search_path} = undef;
524
525   eapk_create( $schema,
526                with_search_path => [0,1],
527              );
528   eapk_create( $schema,
529                with_search_path => [1,0,'public'],
530                nextval => "$eapk_schemas[5].fooseq",
531              );
532   eapk_create( $schema,
533                with_search_path => ['public',0,1],
534                qualify_table => 2,
535              );
536   eapk_create( $schema,
537                with_search_path => [3,1,0,'public'],
538                nextval => "$eapk_schemas[4].fooseq",
539              );
540   eapk_create( $schema,
541                with_search_path => [3,1,0,'public'],
542                nextval => "$eapk_schemas[3].fooseq",
543                qualify_table => 4,
544              );
545
546   eapk_poke( $schema, 0 );
547   eapk_poke( $schema, 2 );
548   eapk_poke( $schema, 4 );
549   eapk_poke( $schema, 1 );
550   eapk_poke( $schema, 0 );
551   eapk_poke( $schema, 1 );
552   eapk_poke( $schema, 4 );
553   eapk_poke( $schema, 3 );
554   eapk_poke( $schema, 1 );
555   eapk_poke( $schema, 2 );
556   eapk_poke( $schema, 0 );
557
558   # set our search path back
559   eapk_set_search_path( $schema, @$search_path_save );
560 }
561
562 # do a DBIC create on the apk table in the given schema number (which is an
563 # index of @eapk_schemas)
564
565 my %seqs; #< sanity-check hash of schema.table.col => currval of its sequence
566
567 sub eapk_poke {
568   my ($s, $schema_num) = @_;
569
570   my $schema_name = defined $schema_num
571       ? $eapk_schemas[$schema_num]
572       : '';
573
574   my $schema_name_actual = $schema_name || $s->storage->dbh_do('_get_pg_search_path')->[0];
575
576   $s->source('ExtAPK')->name($schema_name ? $schema_name.'.apk' : 'apk');
577   #< clear sequence name cache
578   $s->source('ExtAPK')->column_info($_)->{sequence} = undef
579       for @eapk_id_columns;
580
581   no warnings 'uninitialized';
582   lives_ok {
583     my $new;
584     for my $inc (1,2,3) {
585       $new = $schema->resultset('ExtAPK')->create({});
586       my $proper_seqval = ++$seqs{"$schema_name_actual.apk.id2"};
587       is( $new->id2, $proper_seqval, "$schema_name_actual.apk.id2 correct inc $inc" )
588           or eapk_seq_diag($s,$schema_name);
589       $new->discard_changes;
590       for my $id (grep $_ ne 'id2', @eapk_id_columns) {
591         my $proper_seqval = ++$seqs{"$schema_name_actual.apk.$id"};
592         is( $new->$id, $proper_seqval, "$schema_name_actual.apk.$id correct inc $inc" )
593             or eapk_seq_diag($s,$schema_name);
594       }
595     }
596   } "create in schema '$schema_name' lives"
597       or eapk_seq_diag($s,$schema_name);
598 }
599
600 # print diagnostic info on which sequences were found in the ExtAPK
601 # class
602 sub eapk_seq_diag {
603     my $s = shift;
604     my $schema = shift || $s->storage->dbh_do('_get_pg_search_path')->[0];
605
606     diag "$schema.apk sequences: ",
607         join(', ',
608              map "$_:".($s->source('ExtAPK')->column_info($_)->{sequence} || '<none>'),
609              @eapk_id_columns
610             );
611 }
612
613 sub eapk_set_search_path {
614     my ($s,@sp) = @_;
615     my $sp = join ',',@sp;
616     $s->storage->dbh_do( sub { $_[1]->do("SET search_path = $sp") } );
617 }
618
619 # create the apk table in the given schema, can set whether the table name is qualified, what the nextval is for the second ID
620 sub eapk_create {
621     my ($schema, %a) = @_;
622
623     $schema->storage->dbh_do(sub {
624         my (undef,$dbh) = @_;
625
626         my $searchpath_save;
627         if ( $a{with_search_path} ) {
628             ($searchpath_save) = $dbh->selectrow_array('SHOW search_path');
629
630             my $search_path = join ',',map {/\D/ ? $_ : $eapk_schemas[$_]} @{$a{with_search_path}};
631
632             $dbh->do("SET search_path = $search_path");
633         }
634
635         my $table_name = $a{qualify_table}
636             ? ($eapk_schemas[$a{qualify_table}] || die). ".apk"
637             : 'apk';
638         local $_[1]->{Warn} = 0;
639
640         my $id_def = $a{nextval}
641             ? "integer primary key not null default nextval('$a{nextval}'::regclass)"
642             : 'serial primary key';
643         $dbh->do(<<EOS);
644 CREATE TABLE $table_name (
645   id1 serial
646   , id2 $id_def
647   , id3 serial
648   , id4 serial
649 )
650 EOS
651
652         if( $searchpath_save ) {
653             $dbh->do("SET search_path = $searchpath_save");
654         }
655     });
656 }
657
658 sub eapk_drop_all {
659     my ( $schema, $no_warn ) = @_;
660
661     $schema->storage->dbh_do(sub {
662         my (undef,$dbh) = @_;
663
664         local $dbh->{Warn} = 0;
665
666         # drop the test schemas
667         for (@eapk_schemas ) {
668             eval{ $dbh->do("DROP SCHEMA $_ CASCADE") };
669             diag $@ if $@ && !$no_warn;
670         }
671
672
673     });
674 }