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