Doc fix: DBIx::Class::Row->discard_changes documented twice
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema / Versioned.pm
CommitLineData
a89c6fc0 1package # Hide from PAUSE
2 DBIx::Class::Version::Table;
d88ecca6 3use base 'DBIx::Class::Core';
c9d2e0a2 4use strict;
5use warnings;
6
b4b1e91c 7__PACKAGE__->table('dbix_class_schema_versions');
c9d2e0a2 8
ad1446da 9__PACKAGE__->add_columns
732dc718 10 ( 'version' => {
ad1446da 11 'data_type' => 'VARCHAR',
12 'is_auto_increment' => 0,
13 'default_value' => undef,
14 'is_foreign_key' => 0,
732dc718 15 'name' => 'version',
ad1446da 16 'is_nullable' => 0,
17 'size' => '10'
18 },
732dc718 19 'installed' => {
c9d2e0a2 20 'data_type' => 'VARCHAR',
21 'is_auto_increment' => 0,
22 'default_value' => undef,
23 'is_foreign_key' => 0,
732dc718 24 'name' => 'installed',
c9d2e0a2 25 'is_nullable' => 0,
26 'size' => '20'
ad1446da 27 },
28 );
732dc718 29__PACKAGE__->set_primary_key('version');
c9d2e0a2 30
a89c6fc0 31package # Hide from PAUSE
32 DBIx::Class::Version::TableCompat;
d88ecca6 33use base 'DBIx::Class::Core';
b4b1e91c 34__PACKAGE__->table('SchemaVersions');
35
732dc718 36__PACKAGE__->add_columns
37 ( 'Version' => {
38 'data_type' => 'VARCHAR',
39 },
40 'Installed' => {
41 'data_type' => 'VARCHAR',
42 },
43 );
44__PACKAGE__->set_primary_key('Version');
45
a89c6fc0 46package # Hide from PAUSE
47 DBIx::Class::Version;
c9d2e0a2 48use base 'DBIx::Class::Schema';
49use strict;
50use warnings;
51
52__PACKAGE__->register_class('Table', 'DBIx::Class::Version::Table');
53
a89c6fc0 54package # Hide from PAUSE
55 DBIx::Class::VersionCompat;
b4b1e91c 56use base 'DBIx::Class::Schema';
57use strict;
58use warnings;
59
60__PACKAGE__->register_class('TableCompat', 'DBIx::Class::Version::TableCompat');
61
c9d2e0a2 62
63# ---------------------------------------------------------------------------
8424c090 64
65=head1 NAME
66
67DBIx::Class::Schema::Versioned - DBIx::Class::Schema plugin for Schema upgrades
68
69=head1 SYNOPSIS
70
6c2b68ed 71 package MyApp::Schema;
e84a43c1 72 use base qw/DBIx::Class::Schema/;
73
74 our $VERSION = 0.001;
75
6c2b68ed 76 # load MyApp::Schema::CD, MyApp::Schema::Book, MyApp::Schema::DVD
8424c090 77 __PACKAGE__->load_classes(qw/CD Book DVD/);
78
e84a43c1 79 __PACKAGE__->load_components(qw/Schema::Versioned/);
8424c090 80 __PACKAGE__->upgrade_directory('/path/to/upgrades/');
8424c090 81
82
83=head1 DESCRIPTION
84
e84a43c1 85This module provides methods to apply DDL changes to your database using SQL
86diff files. Normally these diff files would be created using
87L<DBIx::Class::Schema/create_ddl_dir>.
8424c090 88
b4b1e91c 89A table called I<dbix_class_schema_versions> is created and maintained by the
e84a43c1 90module. This is used to determine which version your database is currently at.
91Similarly the $VERSION in your DBIC schema class is used to determine the
92current DBIC schema version.
8424c090 93
e84a43c1 94The upgrade is initiated manually by calling C<upgrade> on your schema object,
95this will attempt to upgrade the database from its current version to the current
96schema version using a diff from your I<upgrade_directory>. If a suitable diff is
97not found then no upgrade is possible.
8424c090 98
93e4d41a 99=head1 GETTING STARTED
100
e84a43c1 101Firstly you need to setup your schema class as per the L</SYNOPSIS>, make sure
102you have specified an upgrade_directory and an initial $VERSION.
93e4d41a 103
e84a43c1 104Then you'll need two scripts, one to create DDL files and diffs and another to perform
105upgrades. Your creation script might look like a bit like this:
93e4d41a 106
e84a43c1 107 use strict;
108 use Pod::Usage;
109 use Getopt::Long;
110 use MyApp::Schema;
8424c090 111
56988b6c 112 my ( $preversion, $help );
e84a43c1 113 GetOptions(
114 'p|preversion:s' => \$preversion,
115 ) or die pod2usage;
8424c090 116
e84a43c1 117 my $schema = MyApp::Schema->connect(
118 $dsn,
119 $user,
120 $password,
121 );
122 my $sql_dir = './sql';
123 my $version = $schema->schema_version();
124 $schema->create_ddl_dir( 'MySQL', $version, $sql_dir, $preversion );
8424c090 125
e84a43c1 126Then your upgrade script might look like so:
127
128 use strict;
129 use MyApp::Schema;
130
131 my $schema = MyApp::Schema->connect(
132 $dsn,
133 $user,
134 $password,
135 );
8424c090 136
e84a43c1 137 if (!$schema->get_db_version()) {
138 # schema is unversioned
139 $schema->deploy();
140 } else {
141 $schema->upgrade();
142 }
143
144The script above assumes that if the database is unversioned then it is empty
145and we can safely deploy the DDL to it. However things are not always so simple.
146
147if you want to initialise a pre-existing database where the DDL is not the same
82625f90 148as the DDL for your current schema version then you will need a diff which
e84a43c1 149converts the database's DDL to the current DDL. The best way to do this is
150to get a dump of the database schema (without data) and save that in your
151SQL directory as version 0.000 (the filename must be as with
82625f90 152L<DBIx::Class::Schema/ddl_filename>) then create a diff using your create DDL
e84a43c1 153script given above from version 0.000 to the current version. Then hand check
82625f90 154and if necessary edit the resulting diff to ensure that it will apply. Once you have
e84a43c1 155done all that you can do this:
156
157 if (!$schema->get_db_version()) {
158 # schema is unversioned
159 $schema->install("0.000");
160 }
161
162 # this will now apply the 0.000 to current version diff
163 $schema->upgrade();
164
165In the case of an unversioned database the above code will create the
82625f90 166dbix_class_schema_versions table and write version 0.000 to it, then
e84a43c1 167upgrade will then apply the diff we talked about creating in the previous paragraph
168and then you're good to go.
8424c090 169
170=cut
171
c9d2e0a2 172package DBIx::Class::Schema::Versioned;
173
174use strict;
175use warnings;
d88ecca6 176use base 'DBIx::Class::Schema';
341d5ede 177
178use Carp::Clan qw/^DBIx::Class/;
d2bc7045 179use Time::HiRes qw/gettimeofday/;
9780718f 180use Try::Tiny;
fd323bf1 181use namespace::clean;
c9d2e0a2 182
183__PACKAGE__->mk_classdata('_filedata');
184__PACKAGE__->mk_classdata('upgrade_directory');
8795fefb 185__PACKAGE__->mk_classdata('backup_directory');
f925f7cb 186__PACKAGE__->mk_classdata('do_backup');
8424c090 187__PACKAGE__->mk_classdata('do_diff_on_init');
188
e84a43c1 189
190=head1 METHODS
191
192=head2 upgrade_directory
193
194Use this to set the directory your upgrade files are stored in.
195
196=head2 backup_directory
197
198Use this to set the directory you want your backups stored in (note that backups
199are disabled by default).
200
201=cut
202
93e4d41a 203=head2 install
c9d2e0a2 204
93e4d41a 205=over 4
c9d2e0a2 206
93e4d41a 207=item Arguments: $db_version
e6129e56 208
93e4d41a 209=back
8424c090 210
93e4d41a 211Call this to initialise a previously unversioned database. The table 'dbix_class_schema_versions' will be created which will be used to store the database version.
8424c090 212
93e4d41a 213Takes one argument which should be the version that the database is currently at. Defaults to the return value of L</schema_version>.
8424c090 214
93e4d41a 215See L</getting_started> for more details.
f81b9157 216
8424c090 217=cut
218
93e4d41a 219sub install
c9d2e0a2 220{
93e4d41a 221 my ($self, $new_version) = @_;
c9d2e0a2 222
93e4d41a 223 # must be called on a fresh database
224 if ($self->get_db_version()) {
a03b396b 225 $self->throw_exception("A versioned schema has already been deployed, try upgrade instead.\n");
8424c090 226 }
c9d2e0a2 227
93e4d41a 228 # default to current version if none passed
229 $new_version ||= $self->schema_version();
8424c090 230
e84a43c1 231 if ($new_version) {
93e4d41a 232 # create versions table and version row
233 $self->{vschema}->deploy;
a354b842 234 $self->_set_db_version({ version => $new_version });
8424c090 235 }
c9d2e0a2 236}
237
e84a43c1 238=head2 deploy
239
240Same as L<DBIx::Class::Schema/deploy> but also calls C<install>.
241
242=cut
243
244sub deploy {
245 my $self = shift;
246 $self->next::method(@_);
247 $self->install();
248}
249
a354b842 250=head2 create_upgrade_path
251
252=over 4
253
254=item Arguments: { upgrade_file => $file }
255
256=back
257
c1300297 258Virtual method that should be overridden to create an upgrade file.
56988b6c 259This is useful in the case of upgrading across multiple versions
a354b842 260to concatenate several files to create one upgrade file.
261
4a743a00 262You'll probably want the db_version retrieved via $self->get_db_version
56988b6c 263and the schema_version which is retrieved via $self->schema_version
4a743a00 264
a354b842 265=cut
266
267sub create_upgrade_path {
d7a58a29 268 ## override this method
a354b842 269}
270
d2bc7045 271=head2 ordered_schema_versions
272
273=over 4
274
275=item Returns: a list of version numbers, ordered from lowest to highest
276
277=back
278
c1300297 279Virtual method that should be overridden to return an ordered list
d2bc7045 280of schema versions. This is then used to produce a set of steps to
281upgrade through to achieve the required schema version.
282
283You may want the db_version retrieved via $self->get_db_version
56988b6c 284and the schema_version which is retrieved via $self->schema_version
d2bc7045 285
286=cut
287
288sub ordered_schema_versions {
56988b6c 289 ## override this method
d2bc7045 290}
291
8424c090 292=head2 upgrade
e2c0df8e 293
d2bc7045 294Call this to attempt to upgrade your database from the version it
295is at to the version this DBIC schema is at. If they are the same
296it does nothing.
e84a43c1 297
d2bc7045 298It will call L</ordered_schema_versions> to retrieve an ordered
299list of schema versions (if ordered_schema_versions returns nothing
300then it is assumed you can do the upgrade as a single step). It
301then iterates through the list of versions between the current db
302version and the schema version applying one update at a time until
48580715 303all relevant updates are applied.
c9d2e0a2 304
d2bc7045 305The individual update steps are performed by using
306L</upgrade_single_step>, which will apply the update and also
307update the dbix_class_schema_versions table.
c9d2e0a2 308
8424c090 309=cut
c9d2e0a2 310
d2bc7045 311sub upgrade {
312 my ($self) = @_;
313 my $db_version = $self->get_db_version();
c9d2e0a2 314
d2bc7045 315 # db unversioned
316 unless ($db_version) {
317 carp 'Upgrade not possible as database is unversioned. Please call install first.';
318 return;
319 }
320
321 # db and schema at same version. do nothing
322 if ( $db_version eq $self->schema_version ) {
323 carp "Upgrade not necessary\n";
324 return;
325 }
326
327 my @version_list = $self->ordered_schema_versions;
328
329 # if nothing returned then we preload with min/max
330 @version_list = ( $db_version, $self->schema_version )
331 unless ( scalar(@version_list) );
332
333 # catch the case of someone returning an arrayref
334 @version_list = @{ $version_list[0] }
335 if ( ref( $version_list[0] ) eq 'ARRAY' );
336
337 # remove all versions in list above the required version
338 while ( scalar(@version_list)
339 && ( $version_list[-1] ne $self->schema_version ) )
340 {
341 pop @version_list;
342 }
343
344 # remove all versions in list below the current version
345 while ( scalar(@version_list) && ( $version_list[0] ne $db_version ) ) {
346 shift @version_list;
347 }
348
349 # check we have an appropriate list of versions
350 if ( scalar(@version_list) < 2 ) {
351 die;
352 }
353
354 # do sets of upgrade
355 while ( scalar(@version_list) >= 2 ) {
356 $self->upgrade_single_step( $version_list[0], $version_list[1] );
357 shift @version_list;
358 }
359}
360
361=head2 upgrade_single_step
362
363=over 4
364
365=item Arguments: db_version - the version currently within the db
366
367=item Arguments: target_version - the version to upgrade to
368
369=back
370
371Call this to attempt to upgrade your database from the
372I<db_version> to the I<target_version>. If they are the same it
373does nothing.
374
375It requires an SQL diff file to exist in your I<upgrade_directory>,
376normally you will have created this using L<DBIx::Class::Schema/create_ddl_dir>.
377
378If successful the dbix_class_schema_versions table is updated with
379the I<target_version>.
380
381This method may be called repeatedly by the upgrade method to
382upgrade through a series of updates.
383
384=cut
385
386sub upgrade_single_step
387{
388 my ($self,
389 $db_version,
390 $target_version) = @_;
c9d2e0a2 391
8424c090 392 # db and schema at same version. do nothing
d2bc7045 393 if ($db_version eq $target_version) {
341d5ede 394 carp "Upgrade not necessary\n";
8424c090 395 return;
c9d2e0a2 396 }
397
37fcb5b5 398 # strangely the first time this is called can
82625f90 399 # differ to subsequent times. so we call it
37fcb5b5 400 # here to be sure.
401 # XXX - just fix it
402 $self->storage->sqlt_type;
d4daee7b 403
8424c090 404 my $upgrade_file = $self->ddl_filename(
405 $self->storage->sqlt_type,
d2bc7045 406 $target_version,
99a74c4a 407 $self->upgrade_directory,
8424c090 408 $db_version,
409 );
c9d2e0a2 410
a354b842 411 $self->create_upgrade_path({ upgrade_file => $upgrade_file });
412
8424c090 413 unless (-f $upgrade_file) {
341d5ede 414 carp "Upgrade not possible, no upgrade file found ($upgrade_file), please create one\n";
8424c090 415 return;
416 }
c9d2e0a2 417
d7a58a29 418 carp "DB version ($db_version) is lower than the schema version (".$self->schema_version."). Attempting upgrade.\n";
a354b842 419
8424c090 420 # backup if necessary then apply upgrade
421 $self->_filedata($self->_read_sql_file($upgrade_file));
422 $self->backup() if($self->do_backup);
423 $self->txn_do(sub { $self->do_upgrade() });
c9d2e0a2 424
b4b1e91c 425 # set row in dbix_class_schema_versions table
d2bc7045 426 $self->_set_db_version({version => $target_version});
8424c090 427}
c9d2e0a2 428
e6129e56 429=head2 do_upgrade
430
c9d2e0a2 431This is an overwritable method used to run your upgrade. The freeform method
432allows you to run your upgrade any way you please, you can call C<run_upgrade>
433any number of times to run the actual SQL commands, and in between you can
434sandwich your data upgrading. For example, first run all the B<CREATE>
82625f90 435commands, then migrate your data from old to new tables/formats, then
e7b14c5b 436issue the DROP commands when you are finished. Will run the whole file as it is by default.
8424c090 437
438=cut
439
440sub do_upgrade
441{
e7b14c5b 442 my ($self) = @_;
8424c090 443
56988b6c 444 # just run all the commands (including inserts) in order
e7b14c5b 445 $self->run_upgrade(qr/.*?/);
8424c090 446}
447
c9d2e0a2 448=head2 run_upgrade
449
450 $self->run_upgrade(qr/create/i);
451
452Runs a set of SQL statements matching a passed in regular expression. The
453idea is that this method can be called any number of times from your
e84a43c1 454C<do_upgrade> method, running whichever commands you specify via the
8424c090 455regex in the parameter. Probably won't work unless called from the overridable
456do_upgrade method.
c9d2e0a2 457
8424c090 458=cut
8795fefb 459
8424c090 460sub run_upgrade
461{
462 my ($self, $stm) = @_;
8795fefb 463
8424c090 464 return unless ($self->_filedata);
465 my @statements = grep { $_ =~ $stm } @{$self->_filedata};
466 $self->_filedata([ grep { $_ !~ /$stm/i } @{$self->_filedata} ]);
8795fefb 467
8424c090 468 for (@statements)
82625f90 469 {
8424c090 470 $self->storage->debugobj->query_start($_) if $self->storage->debug;
abc8f12a 471 $self->apply_statement($_);
8424c090 472 $self->storage->debugobj->query_end($_) if $self->storage->debug;
473 }
8795fefb 474
8424c090 475 return 1;
476}
42416a0b 477
abc8f12a 478=head2 apply_statement
479
480Takes an SQL statement and runs it. Override this if you want to handle errors
481differently.
482
483=cut
484
485sub apply_statement {
486 my ($self, $statement) = @_;
487
d7a58a29 488 $self->storage->dbh->do($_) or carp "SQL was: $_";
abc8f12a 489}
490
93e4d41a 491=head2 get_db_version
492
493Returns the version that your database is currently at. This is determined by the values in the
e84a43c1 494dbix_class_schema_versions table that C<upgrade> and C<install> write to.
93e4d41a 495
496=cut
497
498sub get_db_version
499{
500 my ($self, $rs) = @_;
501
502 my $vtable = $self->{vschema}->resultset('Table');
9780718f 503 my $version = try {
56988b6c 504 $vtable->search({}, { order_by => { -desc => 'installed' }, rows => 1 } )
505 ->get_column ('version')
506 ->next;
93e4d41a 507 };
56988b6c 508 return $version || 0;
93e4d41a 509}
510
511=head2 schema_version
512
513Returns the current schema class' $VERSION
514
515=cut
516
517=head2 backup
518
519This is an overwritable method which is called just before the upgrade, to
520allow you to make a backup of the database. Per default this method attempts
521to call C<< $self->storage->backup >>, to run the standard backup on each
56988b6c 522database type.
93e4d41a 523
524This method should return the name of the backup file, if appropriate..
525
526This method is disabled by default. Set $schema->do_backup(1) to enable it.
527
528=cut
529
530sub backup
531{
532 my ($self) = @_;
533 ## Make each ::DBI::Foo do this
534 $self->storage->backup($self->backup_directory());
535}
536
ecea7937 537=head2 connection
538
539Overloaded method. This checks the DBIC schema version against the DB version and
540warns if they are not the same or if the DB is unversioned. It also provides
541compatibility between the old versions table (SchemaVersions) and the new one
542(dbix_class_schema_versions).
543
48580715 544To avoid the checks on connect, set the environment var DBIC_NO_VERSION_CHECK or alternatively you can set the ignore_version attr in the forth argument like so:
f81b9157 545
546 my $schema = MyApp::Schema->connect(
547 $dsn,
548 $user,
549 $password,
550 { ignore_version => 1 },
551 );
ecea7937 552
553=cut
554
8424c090 555sub connection {
556 my $self = shift;
557 $self->next::method(@_);
8012b15c 558 $self->_on_connect();
8424c090 559 return $self;
560}
561
562sub _on_connect
563{
8012b15c 564 my ($self) = @_;
f81b9157 565
f76f761c 566 my $conn_info = $self->storage->connect_info;
567 $self->{vschema} = DBIx::Class::Version->connect(@$conn_info);
568 my $conn_attrs = $self->{vschema}->storage->_dbic_connect_attributes || {};
06f10f6f 569
b4b1e91c 570 my $vtable = $self->{vschema}->resultset('Table');
571
c99c4801 572 # useful when connecting from scripts etc
f76f761c 573 return if ($conn_attrs->{ignore_version} || ($ENV{DBIC_NO_VERSION_CHECK} && !exists $conn_attrs->{ignore_version}));
c99c4801 574
b4b1e91c 575 # check for legacy versions table and move to new if exists
b4b1e91c 576 unless ($self->_source_exists($vtable)) {
a5722c72 577 my $vtable_compat = DBIx::Class::VersionCompat->connect(@$conn_info)->resultset('TableCompat');
b4b1e91c 578 if ($self->_source_exists($vtable_compat)) {
579 $self->{vschema}->deploy;
732dc718 580 map { $vtable->create({ installed => $_->Installed, version => $_->Version }) } $vtable_compat->all;
f76f761c 581 $self->storage->_get_dbh->do("DROP TABLE " . $vtable_compat->result_source->from);
b4b1e91c 582 }
583 }
f81b9157 584
8424c090 585 my $pversion = $self->get_db_version();
586
587 if($pversion eq $self->schema_version)
588 {
341d5ede 589# carp "This version is already installed\n";
8424c090 590 return 1;
591 }
42416a0b 592
8424c090 593 if(!$pversion)
594 {
341d5ede 595 carp "Your DB is currently unversioned. Please call upgrade on your schema to sync the DB.\n";
8424c090 596 return 1;
597 }
598
d7a58a29 599 carp "Versions out of sync. This is " . $self->schema_version .
8424c090 600 ", your database contains version $pversion, please call upgrade on your Schema.\n";
601}
602
93e4d41a 603# is this just a waste of time? if not then merge with DBI.pm
604sub _create_db_to_schema_diff {
605 my $self = shift;
606
607 my %driver_to_db_map = (
608 'mysql' => 'MySQL'
609 );
610
611 my $db = $driver_to_db_map{$self->storage->dbh->{Driver}->{Name}};
612 unless ($db) {
613 print "Sorry, this is an unsupported DB\n";
614 return;
615 }
616
2527233b 617 unless (DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')) {
618 $self->throw_exception("Unable to proceed without " . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy') );
619 }
93e4d41a 620
b2b2e7fd 621 my $db_tr = SQL::Translator->new({
622 add_drop_table => 1,
93e4d41a 623 parser => 'DBI',
624 parser_args => { dbh => $self->storage->dbh }
625 });
626
627 $db_tr->producer($db);
628 my $dbic_tr = SQL::Translator->new;
629 $dbic_tr->parser('SQL::Translator::Parser::DBIx::Class');
93e4d41a 630 $dbic_tr->data($self);
631 $dbic_tr->producer($db);
632
633 $db_tr->schema->name('db_schema');
634 $dbic_tr->schema->name('dbic_schema');
635
636 # is this really necessary?
637 foreach my $tr ($db_tr, $dbic_tr) {
638 my $data = $tr->data;
639 $tr->parser->($tr, $$data);
640 }
641
82625f90 642 my $diff = SQL::Translator::Diff::schema_diff($db_tr->schema, $db,
93e4d41a 643 $dbic_tr->schema, $db,
644 { ignore_constraint_names => 1, ignore_index_names => 1, caseopt => 1 });
645
646 my $filename = $self->ddl_filename(
647 $db,
648 $self->schema_version,
649 $self->upgrade_directory,
650 'PRE',
651 );
652 my $file;
653 if(!open($file, ">$filename"))
654 {
655 $self->throw_exception("Can't open $filename for writing ($!)");
656 next;
657 }
658 print $file $diff;
659 close($file);
660
341d5ede 661 carp "WARNING: There may be differences between your DB and your DBIC schema. Please review and if necessary run the SQL in $filename to sync your DB.\n";
93e4d41a 662}
663
664
665sub _set_db_version {
666 my $self = shift;
a354b842 667 my ($params) = @_;
668 $params ||= {};
93e4d41a 669
a354b842 670 my $version = $params->{version} ? $params->{version} : $self->schema_version;
93e4d41a 671 my $vtable = $self->{vschema}->resultset('Table');
93e4d41a 672
d2bc7045 673 ##############################################################################
674 # !!! NOTE !!!
675 ##############################################################################
676 #
677 # The travesty below replaces the old nice timestamp format of %Y-%m-%d %H:%M:%S
678 # This is necessary since there are legitimate cases when upgrades can happen
679 # back to back within the same second. This breaks things since we relay on the
680 # ability to sort by the 'installed' value. The logical choice of an autoinc
a03b396b 681 # is not possible, as it will break multiple legacy installations. Also it is
d2bc7045 682 # not possible to format the string sanely, as the column is a varchar(20).
683 # The 'v' character is added to the front of the string, so that any version
684 # formatted by this new function will sort _after_ any existing 200... strings.
685 my @tm = gettimeofday();
686 my @dt = gmtime ($tm[0]);
a03b396b 687 my $o = $vtable->create({
d2bc7045 688 version => $version,
689 installed => sprintf("v%04d%02d%02d_%02d%02d%02d.%03.0f",
690 $dt[5] + 1900,
691 $dt[4] + 1,
692 $dt[3],
693 $dt[2],
694 $dt[1],
695 $dt[0],
696 $tm[1] / 1000, # convert to millisecs, format as up/down rounded int above
697 ),
698 });
93e4d41a 699}
700
701sub _read_sql_file {
702 my $self = shift;
703 my $file = shift || return;
704
82625f90 705 open my $fh, '<', $file or carp("Can't open upgrade file, $file ($!)");
706 my @data = split /\n/, join '', <$fh>;
707 close $fh;
708
b703fec7 709 @data = split /;/,
710 join '',
711 grep { $_ &&
712 !/^--/ &&
713 !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/mi }
714 @data;
82625f90 715
93e4d41a 716 return \@data;
717}
718
719sub _source_exists
720{
721 my ($self, $rs) = @_;
722
c271eec3 723 return try {
724 $rs->search(\'1=0')->cursor->next;
725 1;
726 } catch {
727 0;
728 };
93e4d41a 729}
730
8424c090 7311;
732
733
734=head1 AUTHORS
c9d2e0a2 735
1a9251f7 736Jess Robinson <castaway@desert-island.me.uk>
8424c090 737Luke Saunders <luke@shadowcatsystems.co.uk>
738
739=head1 LICENSE
740
741You may distribute this code under the same terms as Perl itself.