Codebase list libdbix-class-perl / 7608e26
[svn-upgrade] new version libdbix-class-perl (0.08193) Ansgar Burchardt 12 years ago
92 changed file(s) with 1657 addition(s) and 511 deletion(s). Raw diff Collapse all Expand all
00 Revision history for DBIx::Class
1
2 0.08193 2011-07-14 17:00 (UTC)
3 * New Features / Changes
4 - Allow schema cloning to mutate attributes
5 - DBIC now attempts more aggressive de-duplication of where
6 conditions on resultset chaining
7 - The Ordered component is now smarter wrt reordering of dirty
8 objects, and does its job with less storage queries
9 - Logging via DBIC_TRACE=1=<filename> no longer overwrites the
10 logfile on every program startup, appending loglines instead
11
12 * Fixes
13 - Fix issue where the query was becoming overly mangled when trying
14 to use pagination with a query that has a sub-select in the WHERE
15 clause
16 - Fix possible incorrect pagination on Oracle, when a resultset
17 is not ordered by a unique column
18 - Revert "Fix incorrect signature of the default sqlt_deploy_hook"
19 from 0.08191 - documentation was in fact incorrect, not the code
20 - Fix Sybase ASE IC::DateTime support (::Storage going out of sync
21 with new default format expected by DateTime::Format::Sybase)
22 - Fix a bug in update_all() resulting in the first row receiving a
23 different dataset than the subsequent ones
24 - Accomodate MSAccess supporting only 'INNER JOIN' (not plain 'JOIN')
25 - InflateColumn::DateTime option datetime_undef_if_invalid no longer
26 masks missing dependency exceptions (RT#66823)
27 - Fix bug in Schema::Versioned failing to insert a schema version row
28 during upgrades at the turn of the second
29 - Fix incorrect bind of integers >= 2^^32 (bigint columns) to
30 SQL_INTEGER, resulting in silent conversion to '-1'
31 - Fix pre 5.10 failures of t/55namespaces_cleaned.t due to buggy
32 require() (RT#68814)
33 - Oracle autoinc inserts no longer leave open cursors behind
134
235 0.08192 2011-05-10 04:20 (UTC)
336 * Fixes
351351 t/inflate/datetime_determine_parser.t
352352 t/inflate/datetime_firebird.t
353353 t/inflate/datetime_informix.t
354 t/inflate/datetime_missing_deps.t
354355 t/inflate/datetime_msaccess.t
355356 t/inflate/datetime_mssql.t
356357 t/inflate/datetime_mysql.t
390391 t/lib/DBICTest/BaseResult.pm
391392 t/lib/DBICTest/BaseResultSet.pm
392393 t/lib/DBICTest/Cursor.pm
394 t/lib/DBICTest/DeployComponent.pm
393395 t/lib/DBICTest/ErrorComponent.pm
394396 t/lib/DBICTest/FakeComponent.pm
395397 t/lib/DBICTest/ForeignComponent.pm
538540 t/resultset_class.t
539541 t/resultset_overload.t
540542 t/row/filter_column.t
543 t/row/find_one_has_many.t
541544 t/row/inflate_result.t
542545 t/row/pkless.t
543546 t/schema/anon.t
594597 t/storage/stats.t
595598 t/storage/txn.t
596599 t/storage/txn_scope_guard.t
600 t/update/all.t
601 t/update/ident_cond.t
597602 t/update/type_aware.t
598603 t/zzzzzzz_perl_perf_bug.t
599604 t/zzzzzzz_sqlite_deadlock.t
1212 configure_requires:
1313 ExtUtils::MakeMaker: 6.42
1414 distribution_type: module
15 generated_by: 'Module::Install version 1.00'
15 generated_by: 'Module::Install version 1.01'
1616 license: perl
1717 meta-spec:
1818 url: http://module-build.sourceforge.net/META-spec-v1.4.html
3737 Config::Any: 0.20
3838 Context::Preserve: 0.01
3939 DBI: 1.57
40 Data::Compare: 1.22
4041 Data::Dumper::Concise: 2.020
4142 Data::Page: 2.00
4243 File::Path: 2.07
4748 SQL::Abstract: 1.72
4849 Scope::Guard: 0.03
4950 Sub::Name: 0.04
51 Test::Deep: 0.108
5052 Try::Tiny: 0.04
5153 Variable::Magic: 0.44
5254 namespace::clean: 0.20
5860 homepage: http://www.dbix-class.org/
5961 license: http://dev.perl.org/licenses/
6062 repository: git://git.shadowcat.co.uk/dbsrgits/DBIx-Class.git
61 version: 0.08192
63 version: 0.08193
7272 'Path::Class' => '0.18',
7373 'Scope::Guard' => '0.03',
7474 'SQL::Abstract' => '1.72',
75 'Test::Deep' => '0.108',
7576 'Try::Tiny' => '0.04',
77 'Data::Compare' => '1.22',
7678
7779 # XS (or XS-dependent) libs
7880 'DBI' => '1.57',
4141 __PACKAGE__->table('artist');
4242 __PACKAGE__->add_columns(qw/ artistid name /);
4343 __PACKAGE__->set_primary_key('artistid');
44 __PACKAGE__->has_many(cds => 'MyApp::Schema::Result::CD');
44 __PACKAGE__->has_many(cds => 'MyApp::Schema::Result::CD', 'artistid');
4545
4646 1;
4747
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
33 use strict 'vars';
44 use vars qw{$VERSION};
55 BEGIN {
6 $VERSION = '1.00';
6 $VERSION = '1.01';
77 }
88
99 # Suspend handler for "redefined" warnings
88
99 use vars qw{$VERSION @ISA $ISCORE};
1010 BEGIN {
11 $VERSION = '1.00';
11 $VERSION = '1.01';
1212 @ISA = 'Module::Install::Base';
1313 $ISCORE = 1;
1414 }
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
77
88 use vars qw{$VERSION @ISA $ISCORE};
99 BEGIN {
10 $VERSION = '1.00';
10 $VERSION = '1.01';
1111 @ISA = 'Module::Install::Base';
1212 $ISCORE = 1;
1313 }
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
514514 'GNU Free Documentation license' => 'unrestricted', 1,
515515 'GNU Affero General Public License' => 'open_source', 1,
516516 '(?:Free)?BSD license' => 'bsd', 1,
517 'Artistic license 2\.0' => 'artistic_2', 1,
517518 'Artistic license' => 'artistic', 1,
518519 'Apache (?:Software )?license' => 'apache', 1,
519520 'GPL' => 'gpl', 1,
549550
550551 sub _extract_bugtracker {
551552 my @links = $_[0] =~ m#L<(
552 \Qhttp://rt.cpan.org/\E[^>]+|
553 \Qhttp://github.com/\E[\w_]+/[\w_]+/issues|
554 \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list
553 https?\Q://rt.cpan.org/\E[^>]+|
554 https?\Q://github.com/\E[\w_]+/[\w_]+/issues|
555 https?\Q://code.google.com/p/\E[\w_\-]+/issues/list
555556 )>#gx;
556557 my %links;
557558 @links{@links}=();
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = 'Module::Install::Base';
1010 $ISCORE = 1;
1111 }
55
66 use vars qw{$VERSION @ISA $ISCORE};
77 BEGIN {
8 $VERSION = '1.00';
8 $VERSION = '1.01';
99 @ISA = qw{Module::Install::Base};
1010 $ISCORE = 1;
1111 }
3030 # This is not enforced yet, but will be some time in the next few
3131 # releases once we can make sure it won't clash with custom
3232 # Module::Install extensions.
33 $VERSION = '1.00';
33 $VERSION = '1.01';
3434
3535 # Storage for the pseudo-singleton
3636 $MAIN = undef;
466466
467467 1;
468468
469 # Copyright 2008 - 2010 Adam Kennedy.
469 # Copyright 2008 - 2011 Adam Kennedy.
5454 $self->throw_exception( "No relationship to JOIN from ${from_class} to ${to_class}" )
5555 unless $rel_obj;
5656 my $join = $from_class->storage->sql_maker->_join_condition(
57 $from_class->result_source_instance->_resolve_condition(
58 $rel_obj->{cond}, $to, $from) );
57 scalar $from_class->result_source_instance->_resolve_condition(
58 $rel_obj->{cond}, $to, $from
59 )
60 );
5961 return $join;
6062 }
6163
168168 inflate => sub {
169169 my ($value, $obj) = @_;
170170
171 my $dt = try
172 { $obj->_inflate_to_datetime( $value, $infcopy ) }
173 catch {
174 $self->throw_exception ("Error while inflating ${value} for ${column} on ${self}: $_")
175 unless $infcopy->{datetime_undef_if_invalid};
176 undef; # rv
177 };
171 # propagate for error reporting
172 $infcopy->{__dbic_colname} = $column;
173
174 my $dt = $obj->_inflate_to_datetime( $value, $infcopy );
178175
179176 return (defined $dt)
180177 ? $obj->_post_inflate_datetime( $dt, $infcopy )
197194
198195 my $parser = $self->_datetime_parser;
199196 my $preferred_method = sprintf($method_fmt, $info->{ _ic_dt_method });
200 my $method = $parser->can($preferred_method) ? $preferred_method : sprintf($method_fmt, 'datetime');
201 return $parser->$method($value);
197 my $method = $parser->can($preferred_method) || sprintf($method_fmt, 'datetime');
198
199 return try {
200 $parser->$method($value);
201 }
202 catch {
203 $self->throw_exception ("Error while inflating ${value} for $info->{__dbic_colname} on ${self}: $_")
204 unless $info->{datetime_undef_if_invalid};
205 undef; # rv
206 };
202207 }
203208
204209 sub _inflate_to_datetime {
7575 my $rdbms_db2 = {
7676 'DBD::DB2' => '0',
7777 };
78 my $rdbms_db2_400 = {
79 'DBD::ODBC' => '0',
80 };
81 my $rdbms_informix = {
82 'DBD::Informix' => '0',
83 };
84 my $rdbms_sqlanywhere = {
85 'DBD::SQLAnywhere' => '0',
86 };
87 my $rdbms_sqlanywhere_odbc = {
88 'DBD::ODBC' => '0',
89 };
90 my $rdbms_firebird = {
91 'DBD::Firebird' => '0',
92 };
93 my $rdbms_firebird_interbase = {
94 'DBD::InterBase' => '0',
95 };
7896 my $rdbms_firebird_odbc = {
7997 'DBD::ODBC' => '0',
8098 };
333351 },
334352 },
335353
354 rdbms_db2_400 => {
355 req => {
356 %$rdbms_db2_400,
357 },
358 pod => {
359 title => 'DB2 on AS/400 support',
360 desc => 'Modules required to connect to DB2 on AS/400',
361 },
362 },
363
364 rdbms_informix => {
365 req => {
366 %$rdbms_informix,
367 },
368 pod => {
369 title => 'Informix support',
370 desc => 'Modules required to connect to Informix',
371 },
372 },
373
374 rdbms_sqlanywhere => {
375 req => {
376 %$rdbms_sqlanywhere,
377 },
378 pod => {
379 title => 'SQLAnywhere support',
380 desc => 'Modules required to connect to SQLAnywhere',
381 },
382 },
383
384 rdbms_sqlanywhere_odbc => {
385 req => {
386 %$rdbms_sqlanywhere_odbc,
387 },
388 pod => {
389 title => 'SQLAnywhere support via DBD::ODBC',
390 desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
391 },
392 },
393
394 rdbms_firebird => {
395 req => {
396 %$rdbms_firebird,
397 },
398 pod => {
399 title => 'Firebird support',
400 desc => 'Modules required to connect to Firebird',
401 },
402 },
403
404 rdbms_firebird_interbase => {
405 req => {
406 %$rdbms_firebird_interbase,
407 },
408 pod => {
409 title => 'Firebird support via DBD::InterBase',
410 desc => 'Modules required to connect to Firebird via DBD::InterBase',
411 },
412 },
413
414 rdbms_firebird_odbc => {
415 req => {
416 %$rdbms_firebird_odbc,
417 },
418 pod => {
419 title => 'Firebird support via DBD::ODBC',
420 desc => 'Modules required to connect to Firebird via DBD::ODBC',
421 },
422 },
423
336424 # the order does matter because the rdbms support group might require
337425 # a different version that the test group
338426 test_rdbms_pg => {
340428 $ENV{DBICTEST_PG_DSN}
341429 ? (
342430 %$rdbms_pg,
343 'Sys::SigAction' => '0',
431 ($^O ne 'MSWin32' ? ('Sys::SigAction' => '0') : ()),
344432 'DBD::Pg' => '2.009002',
345433 ) : ()
346434 },
420508 $ENV{DBICTEST_SYBASE_DSN}
421509 ? (
422510 %$rdbms_ase,
423 'DateTime::Format::Sybase' => '0',
424511 ) : ()
425512 },
426513 },
430517 $ENV{DBICTEST_DB2_DSN}
431518 ? (
432519 %$rdbms_db2,
520 ) : ()
521 },
522 },
523
524 test_rdbms_db2_400 => {
525 req => {
526 $ENV{DBICTEST_DB2_400_DSN}
527 ? (
528 %$rdbms_db2_400,
529 ) : ()
530 },
531 },
532
533 test_rdbms_informix => {
534 req => {
535 $ENV{DBICTEST_INFORMIX_DSN}
536 ? (
537 %$rdbms_informix,
538 ) : ()
539 },
540 },
541
542 test_rdbms_sqlanywhere => {
543 req => {
544 $ENV{DBICTEST_SQLANYWHERE_DSN}
545 ? (
546 %$rdbms_sqlanywhere,
547 ) : ()
548 },
549 },
550
551 test_rdbms_sqlanywhere_odbc => {
552 req => {
553 $ENV{DBICTEST_SQLANYWHERE_ODBC_DSN}
554 ? (
555 %$rdbms_sqlanywhere_odbc,
556 ) : ()
557 },
558 },
559
560 test_rdbms_firebird => {
561 req => {
562 $ENV{DBICTEST_FIREBIRD_DSN}
563 ? (
564 %$rdbms_firebird,
565 ) : ()
566 },
567 },
568
569 test_rdbms_firebird_interbase => {
570 req => {
571 $ENV{DBICTEST_FIREBIRD_INTERBASE_DSN}
572 ? (
573 %$rdbms_firebird_interbase,
433574 ) : ()
434575 },
435576 },
520661 if (keys %errors) {
521662 my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
522663 $missing .= " (see $class for details)" if $reqs->{$group}{pod};
523 $missing .= "\n";
524664 $res = {
525665 status => 0,
526666 errorlist => \%errors,
1717
1818 ...
1919
20 configure_requires 'DBIx::Class' => '0.08192';
20 configure_requires 'DBIx::Class' => '0.08193';
2121
2222 require DBIx::Class::Optional::Dependencies;
2323
136136
137137 Requirement group: B<rdbms_db2>
138138
139 =head2 DB2 on AS/400 support
140
141 Modules required to connect to DB2 on AS/400
142
143 =over
144
145 =item * DBD::ODBC
146
147 =back
148
149 Requirement group: B<rdbms_db2_400>
150
151 =head2 Firebird support
152
153 Modules required to connect to Firebird
154
155 =over
156
157 =item * DBD::Firebird
158
159 =back
160
161 Requirement group: B<rdbms_firebird>
162
163 =head2 Firebird support via DBD::InterBase
164
165 Modules required to connect to Firebird via DBD::InterBase
166
167 =over
168
169 =item * DBD::InterBase
170
171 =back
172
173 Requirement group: B<rdbms_firebird_interbase>
174
175 =head2 Firebird support via DBD::ODBC
176
177 Modules required to connect to Firebird via DBD::ODBC
178
179 =over
180
181 =item * DBD::ODBC
182
183 =back
184
185 Requirement group: B<rdbms_firebird_odbc>
186
187 =head2 Informix support
188
189 Modules required to connect to Informix
190
191 =over
192
193 =item * DBD::Informix
194
195 =back
196
197 Requirement group: B<rdbms_informix>
198
139199 =head2 MS Access support via DBD::ADO (Windows only)
140200
141201 Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only
235295 =back
236296
237297 Requirement group: B<rdbms_pg>
298
299 =head2 SQLAnywhere support
300
301 Modules required to connect to SQLAnywhere
302
303 =over
304
305 =item * DBD::SQLAnywhere
306
307 =back
308
309 Requirement group: B<rdbms_sqlanywhere>
310
311 =head2 SQLAnywhere support via DBD::ODBC
312
313 Modules required to connect to SQLAnywhere via DBD::ODBC
314
315 =over
316
317 =item * DBD::ODBC
318
319 =back
320
321 Requirement group: B<rdbms_sqlanywhere_odbc>
238322
239323 =head2 SQLite support
240324
11 use strict;
22 use warnings;
33 use base qw( DBIx::Class );
4
5 use List::Util 'first';
6 use namespace::clean;
47
58 =head1 NAME
69
363366
364367 my $position_column = $self->position_column;
365368
366 my $guard;
367
368369 if ($self->is_column_changed ($position_column) ) {
369 # something changed our position, we have no idea where we
370 # used to be - requery without using discard_changes
371 # (we need only a specific column back)
372
373 $guard = $self->result_source->schema->txn_scope_guard;
374
375 my $cursor = $self->result_source->resultset->search(
376 $self->ident_condition,
377 { select => $position_column },
378 )->cursor;
379
380 my ($pos) = $cursor->next;
381 $self->$position_column ($pos);
370 # something changed our position, we need to know where we
371 # used to be - use the stashed value
372 $self->store_column($position_column, delete $self->{_column_data_in_storage}{$position_column});
382373 delete $self->{_dirty_columns}{$position_column};
383374 }
384375
385376 my $from_position = $self->_position;
386377
387378 if ( $from_position == $to_position ) { # FIXME this will not work for non-numeric order
388 $guard->commit if $guard;
389379 return 0;
390380 }
391381
392 $guard ||= $self->result_source->schema->txn_scope_guard;
382 my $guard = $self->result_source->schema->txn_scope_guard;
393383
394384 my ($direction, @between);
395385 if ( $from_position < $to_position ) {
446436 return 0 if ( defined($to_position) and $to_position < 1 );
447437
448438 # check if someone changed the _grouping_columns - this will
449 # prevent _is_in_group working, so we need to requery the db
450 # for the original values
451 my (@dirty_cols, %values, $guard);
439 # prevent _is_in_group working, so we need to restore the
440 # original stashed values
452441 for ($self->_grouping_columns) {
453 $values{$_} = $self->get_column ($_);
454 push @dirty_cols, $_ if $self->is_column_changed ($_);
455 }
456
457 # re-query only the dirty columns, and restore them on the
458 # object (subsequent code will update them to the correct
459 # after-move values)
460 if (@dirty_cols) {
461 $guard = $self->result_source->schema->txn_scope_guard;
462
463 my $cursor = $self->result_source->resultset->search(
464 $self->ident_condition,
465 { select => \@dirty_cols },
466 )->cursor;
467
468 my @original_values = $cursor->next;
469 $self->set_inflated_columns ({ %values, map { $_ => shift @original_values } (@dirty_cols) });
470 delete $self->{_dirty_columns}{$_} for (@dirty_cols);
442 if ($self->is_column_changed ($_)) {
443 $self->store_column($_, delete $self->{_column_data_in_storage}{$_});
444 delete $self->{_dirty_columns}{$_};
445 }
471446 }
472447
473448 if ($self->_is_in_group ($to_group) ) {
476451 $ret = $self->move_to ($to_position);
477452 }
478453
479 $guard->commit if $guard;
480454 return $ret||0;
481455 }
482456
483 $guard ||= $self->result_source->schema->txn_scope_guard;
457 my $guard = $self->result_source->schema->txn_scope_guard;
484458
485459 # Move to end of current group to adjust siblings
486460 $self->move_last;
548522 =cut
549523
550524 sub update {
551 my $self = shift;
552
553 # this is set by _ordered_internal_update()
554 return $self->next::method(@_) if $self->{_ORDERED_INTERNAL_UPDATE};
555
556 my $position_column = $self->position_column;
557 my @ordering_columns = ($self->_grouping_columns, $position_column);
558
559
560 # these steps are necessary to keep the external appearance of
561 # ->update($upd) so that other things overloading update() will
562 # work properly
563 my %original_values = $self->get_columns;
564 my %existing_changes = $self->get_dirty_columns;
565
566 # See if any of the *supplied* changes would affect the ordering
567 # The reason this is so contrived, is that we want to leverage
568 # the datatype aware value comparing, while at the same time
569 # keep the original value intact (it will be updated later by the
570 # corresponding routine)
571
572 my %upd = %{shift || {}};
573 my %changes = %existing_changes;
574
575 for (@ordering_columns) {
576 next unless exists $upd{$_};
577
578 # we do not want to keep propagating this to next::method
579 # as it will be a done deal by the time get there
580 my $value = delete $upd{$_};
581 $self->set_inflated_columns ({ $_ => $value });
582
583 # see if an update resulted in a dirty column
584 # it is important to preserve the old value, as it
585 # will be needed to carry on a successfull move()
586 # operation without re-querying the database
587 if ($self->is_column_changed ($_) && not exists $existing_changes{$_}) {
588 $changes{$_} = $value;
589 $self->set_inflated_columns ({ $_ => $original_values{$_} });
590 delete $self->{_dirty_columns}{$_};
591 }
592 }
593
594 # if nothing group/position related changed - short circuit
595 if (not grep { exists $changes{$_} } ( @ordering_columns ) ) {
596 return $self->next::method( \%upd, @_ );
597 }
598
599 {
600 my $guard = $self->result_source->schema->txn_scope_guard;
601
602 # if any of our grouping columns have been changed
603 if (grep { exists $changes{$_} } ($self->_grouping_columns) ) {
604
605 # create new_group by taking the current group and inserting changes
606 my $new_group = {$self->_grouping_clause};
607 foreach my $col (keys %$new_group) {
608 $new_group->{$col} = $changes{$col} if exists $changes{$col};
609 }
610
611 $self->move_to_group(
612 $new_group,
613 (exists $changes{$position_column}
614 # The FIXME bit contradicts the documentation: POD states that
615 # when changing groups without supplying explicit positions in
616 # move_to_group(), we push the item to the end of the group.
617 # However when I was rewriting this, the position from the old
618 # group was clearly passed to the new one
619 # Probably needs to go away (by ribasushi)
620 ? $changes{$position_column} # means there was a position change supplied with the update too
621 : $self->_position # FIXME! (replace with undef)
622 ),
623 );
624 }
625 elsif (exists $changes{$position_column}) {
626 $self->move_to($changes{$position_column});
627 }
628
629 my @res;
630 if (not defined wantarray) {
631 $self->next::method( \%upd, @_ );
632 }
633 elsif (wantarray) {
634 @res = $self->next::method( \%upd, @_ );
635 }
636 else {
637 $res[0] = $self->next::method( \%upd, @_ );
638 }
639
640 $guard->commit;
641 return wantarray ? @res : $res[0];
642 }
525 my $self = shift;
526
527 # this is set by _ordered_internal_update()
528 return $self->next::method(@_) if $self->result_source->schema->{_ORDERED_INTERNAL_UPDATE};
529
530 my $upd = shift;
531 $self->set_inflated_columns($upd) if $upd;
532
533 my $position_column = $self->position_column;
534 my @group_columns = $self->_grouping_columns;
535
536 # see if the order is already changed
537 my $changed_ordering_cols = { map { $_ => $self->get_column($_) } grep { $self->is_column_changed($_) } ($position_column, @group_columns) };
538
539 # nothing changed - short circuit
540 if (! keys %$changed_ordering_cols) {
541 return $self->next::method( undef, @_ );
542 }
543 elsif (defined first { exists $changed_ordering_cols->{$_} } @group_columns ) {
544 $self->move_to_group(
545 # since the columns are already re-set the _grouping_clause is correct
546 # move_to_group() knows how to get the original storage values
547 { $self->_grouping_clause },
548
549 # The FIXME bit contradicts the documentation: POD states that
550 # when changing groups without supplying explicit positions in
551 # move_to_group(), we push the item to the end of the group.
552 # However when I was rewriting this, the position from the old
553 # group was clearly passed to the new one
554 # Probably needs to go away (by ribasushi)
555 (exists $changed_ordering_cols->{$position_column}
556 ? $changed_ordering_cols->{$position_column} # means there was a position change supplied with the update too
557 : $self->_position # FIXME! (replace with undef)
558 ),
559 );
560 }
561 else {
562 $self->move_to($changed_ordering_cols->{$position_column});
563 }
564
565 return $self;
643566 }
644567
645568 =head2 delete
646569
647 Overrides the DBIC delete() method by first moving the object
570 Overrides the DBIC delete() method by first moving the object
648571 to the last position, then deleting it, thus ensuring the
649572 integrity of the positions.
650573
670593
671594 $guard->commit;
672595 return wantarray ? @res : $res[0];
596 }
597
598 # add the current position/group to the things we track old values for
599 sub _track_storage_value {
600 my ($self, $col) = @_;
601 return $self->next::method($col) || defined first { $_ eq $col } ($self->position_column, $self->_grouping_columns);
673602 }
674603
675604 =head1 METHODS FOR EXTENDING ORDERED
789718 # increment/decrement. So what we do here is check if the
790719 # position column is part of a unique constraint, and do a
791720 # one-by-one update if this is the case
721 # Also we do a one-by-one if the position is part of the PK
722 # since once we update a column via scalarref we lose the
723 # ability to retrieve this column back (we do not know the
724 # id anymore)
792725
793726 my $rsrc = $self->result_source;
794727
795 if (grep { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) ) ) {
796
797 my @pcols = $rsrc->_pri_cols;
798 my $cursor = $shift_rs->search ({}, { order_by => { "-$ord", $position_column }, columns => \@pcols } )->cursor;
728 # set in case there are more cascades combined with $rs->update => $rs_update_all overrides
729 local $rsrc->schema->{_ORDERED_INTERNAL_UPDATE} = 1;
730 my @pcols = $rsrc->primary_columns;
731 my $pos_is_pk = first { $_ eq $position_column } @pcols;
732 if (
733 $pos_is_pk
734 or
735 first { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) )
736 ) {
737 my $cursor = $shift_rs->search (
738 {}, { order_by => { "-$ord", $position_column }, select => [$position_column, @pcols] }
739 )->cursor;
799740 my $rs = $self->result_source->resultset;
800741
801 my @all_pks = $cursor->all;
802 while (my $pks = shift @all_pks) {
742 my @all_data = $cursor->all;
743 while (my $data = shift @all_data) {
744 my $pos = shift @$data;
803745 my $cond;
804746 for my $i (0.. $#pcols) {
805 $cond->{$pcols[$i]} = $pks->[$i];
747 $cond->{$pcols[$i]} = $data->[$i];
806748 }
807749
808 $rs->search($cond)->update ({ $position_column => \ "$position_column $op 1" } );
750 $rs->find($cond)->update ({ $position_column => $pos + ( ($op eq '+') ? 1 : -1 ) });
809751 }
810752 }
811753 else {
838780 sub _siblings {
839781 my $self = shift;
840782 my $position_column = $self->position_column;
841 return $self->_group_rs->search(
842 { $position_column => { '!=' => $self->get_column($position_column) } },
843 );
783 my $pos;
784 return defined ($pos = $self->get_column($position_column))
785 ? $self->_group_rs->search(
786 { $position_column => { '!=' => $pos } },
787 )
788 : $self->_group_rs
789 ;
844790 }
845791
846792 =head2 _position
930876
931877 sub _ordered_internal_update {
932878 my $self = shift;
933 local $self->{_ORDERED_INTERNAL_UPDATE} = 1;
879 local $self->result_source->schema->{_ORDERED_INTERNAL_UPDATE} = 1;
934880 return $self->update (@_);
935881 }
936882
3535 }
3636
3737 sub _ident_values {
38 my ($self) = @_;
38 my ($self, $use_storage_state) = @_;
3939
4040 my (@ids, @missing);
4141
4242 for ($self->_pri_cols) {
43 push @ids, $self->get_column($_);
43 push @ids, ($use_storage_state and exists $self->{_column_data_in_storage}{$_})
44 ? $self->{_column_data_in_storage}{$_}
45 : $self->get_column($_)
46 ;
4447 push @missing, $_ if (! defined $ids[-1] and ! $self->has_column_loaded ($_) );
4548 }
4649
99102 =cut
100103
101104 sub ident_condition {
102 my ($self, $alias) = @_;
105 shift->_mk_ident_cond(@_);
106 }
107
108 sub _storage_ident_condition {
109 shift->_mk_ident_cond(shift, 1);
110 }
111
112 sub _mk_ident_cond {
113 my ($self, $alias, $use_storage_state) = @_;
103114
104115 my @pks = $self->_pri_cols;
105 my @vals = $self->_ident_values;
116 my @vals = $self->_ident_values($use_storage_state);
106117
107118 my (%cond, @undef);
108119 my $prefix = defined $alias ? $alias.'.' : '';
77 use DBIx::Class::ResultSetColumn;
88 use Scalar::Util qw/blessed weaken/;
99 use Try::Tiny;
10 use Data::Compare;
1011
1112 # not importing first() as it will clash with our own method
1213 use List::Util ();
8586 sub get_data {
8687 my $self = shift;
8788 my $request = $self->get_request; # Get a request object somehow.
88 my $schema = $self->get_schema; # Get the DBIC schema object somehow.
89 my $schema = $self->result_source->schema;
8990
9091 my $cd_rs = $schema->resultset('CD')->search({
9192 title => $request->param('title'),
528529
529530 sub _stack_cond {
530531 my ($self, $left, $right) = @_;
532
533 # collapse single element top-level conditions
534 # (single pass only, unlikely to need recursion)
535 for ($left, $right) {
536 if (ref $_ eq 'ARRAY') {
537 if (@$_ == 0) {
538 $_ = undef;
539 }
540 elsif (@$_ == 1) {
541 $_ = $_->[0];
542 }
543 }
544 elsif (ref $_ eq 'HASH') {
545 my ($first, $more) = keys %$_;
546
547 # empty hash
548 if (! defined $first) {
549 $_ = undef;
550 }
551 # one element hash
552 elsif (! defined $more) {
553 if ($first eq '-and' and ref $_->{'-and'} eq 'HASH') {
554 $_ = $_->{'-and'};
555 }
556 elsif ($first eq '-or' and ref $_->{'-or'} eq 'ARRAY') {
557 $_ = $_->{'-or'};
558 }
559 }
560 }
561 }
562
563 # merge hashes with weeding out of duplicates (simple cases only)
564 if (ref $left eq 'HASH' and ref $right eq 'HASH') {
565
566 # shallow copy to destroy
567 $right = { %$right };
568 for (grep { exists $right->{$_} } keys %$left) {
569 # the use of eq_deeply here is justified - the rhs of an
570 # expression can contain a lot of twisted weird stuff
571 delete $right->{$_} if Compare( $left->{$_}, $right->{$_} );
572 }
573
574 $right = undef unless keys %$right;
575 }
576
577
531578 if (defined $left xor defined $right) {
532579 return defined $left ? $left : $right;
533580 }
534 elsif (defined $left) {
535 return { -and => [ map
536 { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
537 ($left, $right)
538 ]};
539 }
540
541 return undef;
581 elsif (! defined $left) {
582 return undef;
583 }
584 else {
585 return { -and => [ $left, $right ] };
586 }
542587 }
543588
544589 =head2 search_literal
17841829 unless ref $values eq 'HASH';
17851830
17861831 my $guard = $self->result_source->schema->txn_scope_guard;
1787 $_->update($values) for $self->all;
1832 $_->update({%$values}) for $self->all; # shallow copy - update will mangle it
17881833 $guard->commit;
17891834 return 1;
17901835 }
1414
1515 use base qw/DBIx::Class/;
1616
17 __PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns
18 _columns _primaries _unique_constraints name resultset_attributes
19 from _relationships column_info_from_storage source_info
20 source_name sqlt_deploy_callback/);
21
22 __PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
23 result_class/);
17 __PACKAGE__->mk_group_accessors(simple => qw/
18 source_name name source_info
19 _ordered_columns _columns _primaries _unique_constraints
20 _relationships resultset_attributes
21 column_info_from_storage
22 /);
23
24 __PACKAGE__->mk_group_accessors(component_class => qw/
25 resultset_class
26 result_class
27 /);
28
29 __PACKAGE__->mk_classdata( sqlt_deploy_callback => 'default_sqlt_deploy_hook' );
2430
2531 =head1 NAME
2632
114120 $new->{_relationships} = { %{$new->{_relationships}||{}} };
115121 $new->{name} ||= "!!NAME NOT SET!!";
116122 $new->{_columns_info_loaded} ||= 0;
117 $new->{sqlt_deploy_callback} ||= "default_sqlt_deploy_hook";
118123 return $new;
119124 }
120125
885890
886891 =over
887892
888 =item Arguments: $callback
893 =item Arguments: $callback_name | \&callback_code
894
895 =item Return value: $callback_name | \&callback_code
889896
890897 =back
891898
892899 __PACKAGE__->sqlt_deploy_callback('mycallbackmethod');
900
901 or
902
903 __PACKAGE__->sqlt_deploy_callback(sub {
904 my ($source_instance, $sqlt_table) = @_;
905 ...
906 } );
893907
894908 An accessor to set a callback to be called during deployment of
895909 the schema via L<DBIx::Class::Schema/create_ddl_dir> or
898912 The callback can be set as either a code reference or the name of a
899913 method in the current result class.
900914
901 If not set, the L</default_sqlt_deploy_hook> is called.
915 Defaults to L</default_sqlt_deploy_hook>.
902916
903917 Your callback will be passed the $source object representing the
904918 ResultSource instance being deployed, and the
918932
919933 =head2 default_sqlt_deploy_hook
920934
921 =over
922
923 =item Arguments: $source, $sqlt_table
924
925 =item Return value: undefined
926
927 =back
928
929 This is the sensible default for L</sqlt_deploy_callback>.
930
931 If a method named C<sqlt_deploy_hook> exists in your Result class, it
932 will be called and passed the current C<$source> and the
933 C<$sqlt_table> being deployed.
935 This is the default deploy hook implementation which checks if your
936 current Result class has a C<sqlt_deploy_hook> method, and if present
937 invokes it B<on the Result class directly>. This is to preserve the
938 semantics of C<sqlt_deploy_hook> which was originally designed to expect
939 the Result class name and the
940 L<$sqlt_table instance|SQL::Translator::Schema::Table> of the table being
941 deployed.
934942
935943 =cut
936944
939947
940948 my $class = $self->result_class;
941949
942 if ($class and my $hook = $class->can('sqlt_deploy_hook')) {
943 $self->$hook(@_);
950 if ($class and $class->can('sqlt_deploy_hook')) {
951 $class->sqlt_deploy_hook(@_);
944952 }
945953 }
946954
10691077 Returns an expression of the source to be supplied to storage to specify
10701078 retrieval from this source. In the case of a database, the required FROM
10711079 clause contents.
1080
1081 =cut
1082
1083 sub from { die 'Virtual method!' }
10721084
10731085 =head2 schema
10741086
14971509 -alias => $as,
14981510 -relation_chain_depth => $seen->{-relation_chain_depth} || 0,
14991511 },
1500 $self->_resolve_condition($rel_info->{cond}, $as, $alias, $join)
1512 scalar $self->_resolve_condition($rel_info->{cond}, $as, $alias, $join)
15011513 ];
15021514 }
15031515 }
15771589
15781590 # FIXME sanity check until things stabilize, remove at some point
15791591 $self->throw_exception (
1580 "A join-free condition returned for relationship '$relname' whithout a row-object to chain from"
1592 "A join-free condition returned for relationship '$relname' without a row-object to chain from"
15811593 ) unless $obj_rel;
15821594
15831595 # FIXME another sanity check
66
77 use DBIx::Class::Exception;
88 use Scalar::Util 'blessed';
9 use List::Util 'first';
910 use Try::Tiny;
1011
1112 ###
355356 # this ensures we fire store_column only once
356357 # (some asshats like overriding it)
357358 if (
358 (! defined $current_rowdata{$_})
359 (!exists $current_rowdata{$_})
359360 or
360 ( $current_rowdata{$_} ne $returned_cols->{$_})
361 (defined $current_rowdata{$_} xor defined $returned_cols->{$_})
362 or
363 (defined $current_rowdata{$_} and $current_rowdata{$_} ne $returned_cols->{$_})
361364 );
362365 }
366
367 delete $self->{_column_data_in_storage};
368 $self->in_storage(1);
363369
364370 $self->{_dirty_columns} = {};
365371 $self->{related_resultsets} = {};
393399 }
394400 }
395401
396 $self->in_storage(1);
397 delete $self->{_orig_ident};
398 delete $self->{_orig_ident_failreason};
399402 delete $self->{_ignore_at_insert};
403
400404 $rollback_guard->commit if $rollback_guard;
401405
402406 return $self;
493497 my %to_update = $self->get_dirty_columns
494498 or return $self;
495499
496 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
497500 $self->throw_exception( "Not in database" ) unless $self->in_storage;
498501
499 $self->throw_exception($self->{_orig_ident_failreason})
500 if ! keys %$ident_cond;
501
502502 my $rows = $self->result_source->storage->update(
503 $self->result_source, \%to_update, $ident_cond
503 $self->result_source, \%to_update, $self->_storage_ident_condition
504504 );
505505 if ($rows == 0) {
506506 $self->throw_exception( "Can't update ${self}: row not found" );
509509 }
510510 $self->{_dirty_columns} = {};
511511 $self->{related_resultsets} = {};
512 delete $self->{_orig_ident};
512 delete $self->{_column_data_in_storage};
513513 return $self;
514514 }
515515
561561 if (ref $self) {
562562 $self->throw_exception( "Not in database" ) unless $self->in_storage;
563563
564 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
565 $self->throw_exception($self->{_orig_ident_failreason})
566 if ! keys %$ident_cond;
567
568564 $self->result_source->storage->delete(
569 $self->result_source, $ident_cond
565 $self->result_source, $self->_storage_ident_condition
570566 );
571567
572 delete $self->{_orig_ident}; # no longer identifiable
568 delete $self->{_column_data_in_storage};
573569 $self->in_storage(undef);
574570 }
575571 else {
834830 sub set_column {
835831 my ($self, $column, $new_value) = @_;
836832
837 # if we can't get an ident condition on first try - mark the object as unidentifiable
838 # (by using an empty hashref) and store the error for further diag
839 unless ($self->{_orig_ident}) {
840 try {
841 $self->{_orig_ident} = $self->ident_condition
842 }
843 catch {
844 $self->{_orig_ident_failreason} = $_;
845 $self->{_orig_ident} = {};
846 };
847 }
848
849 my $old_value = $self->get_column($column);
833 my $had_value = $self->has_column_loaded($column);
834 my ($old_value, $in_storage) = ($self->get_column($column), $self->in_storage)
835 if $had_value;
836
850837 $new_value = $self->store_column($column, $new_value);
851838
852839 my $dirty =
853840 $self->{_dirty_columns}{$column}
854841 ||
855 $self->in_storage # no point tracking dirtyness on uninserted data
842 $in_storage # no point tracking dirtyness on uninserted data
856843 ? ! $self->_eq_column_values ($column, $old_value, $new_value)
857844 : 1
858845 ;
881868 delete $self->{_inflated_column}{$rel};
882869 }
883870 }
871
872 if (
873 # value change from something (even if NULL)
874 $had_value
875 and
876 # no storage - no storage-value
877 $in_storage
878 and
879 # no value already stored (multiple changes before commit to storage)
880 ! exists $self->{_column_data_in_storage}{$column}
881 and
882 $self->_track_storage_value($column)
883 ) {
884 $self->{_column_data_in_storage}{$column} = $old_value;
885 }
884886 }
885887
886888 return $new_value;
904906 else {
905907 return 0;
906908 }
909 }
910
911 # returns a boolean indicating if the passed column should have its original
912 # value tracked between column changes and commitment to storage
913 sub _track_storage_value {
914 my ($self, $col) = @_;
915 return defined first { $col eq $_ } ($self->primary_columns);
907916 }
908917
909918 =head2 set_columns
13621371 $resultset = $resultset->search(undef, $attrs);
13631372 }
13641373
1365 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
1366
1367 $self->throw_exception($self->{_orig_ident_failreason})
1368 if ! keys %$ident_cond;
1369
1370 return $resultset->find($ident_cond);
1374 return $resultset->find($self->_storage_ident_condition);
13711375 }
13721376
13731377 =head2 discard_changes ($attrs?)
14601464 Returns the primary key(s) for a row. Can't be called as a class method.
14611465 Actually implemented in L<DBIx::Class::PK>
14621466
1467 =head1 AUTHORS
1468
1469 Matt S. Trout <mst@shadowcatsystems.co.uk>
1470
1471 =head1 LICENSE
1472
1473 You may distribute this code under the same terms as Perl itself.
1474
1475 =cut
1476
14631477 1;
1464
1465 =head1 AUTHORS
1466
1467 Matt S. Trout <mst@shadowcatsystems.co.uk>
1468
1469 =head1 LICENSE
1470
1471 You may distribute this code under the same terms as Perl itself.
1472
1473 =cut
1474
1475 1;
33 use strict;
44 use warnings;
55 use base 'DBIx::Class::SQLMaker';
6
7 # inner joins must be prefixed with 'INNER '
8 sub new {
9 my $class = shift;
10 my $self = $class->next::method(@_);
11
12 $self->{_default_jointype} = 'INNER';
13
14 return $self;
15 }
616
717 # MSAccess is retarded wrt multiple joins in FROM - it requires a certain
818 # way of parenthesizing each left part before each next right part
213213 );
214214 }
215215
216
216217 =head2 RowNum
218
219 Depending on the resultset attributes one of:
217220
218221 SELECT * FROM (
219222 SELECT *, ROWNUM rownum__index FROM (
221224 ) WHERE ROWNUM <= ($limit+$offset)
222225 ) WHERE rownum__index >= ($offset+1)
223226
227 or
228
229 SELECT * FROM (
230 SELECT *, ROWNUM rownum__index FROM (
231 SELECT ...
232 )
233 ) WHERE rownum__index BETWEEN ($offset+1) AND ($limit+$offset)
234
235 or
236
237 SELECT * FROM (
238 SELECT ...
239 ) WHERE ROWNUM <= ($limit+1)
240
224241 Supported by B<Oracle>.
225242
226243 =cut
233250 my $idx_name = $self->_quote ('rownum__index');
234251 my $order_group_having = $self->_parse_rs_attrs($rs_attrs);
235252
236
237 if ($offset) {
238
239 push @{$self->{limit_bind}}, [ $self->__total_bindtype => $offset + $rows ], [ $self->__offset_bindtype => $offset + 1 ];
240
241 return <<EOS;
253 #
254 # There are two ways to limit in Oracle, one vastly faster than the other
255 # on large resultsets: https://decipherinfosys.wordpress.com/2007/08/09/paging-and-countstopkey-optimization/
256 # However Oracle is retarded and does not preserve stable ROWNUM() values
257 # when called twice in the same scope. Therefore unless the resultset is
258 # ordered by a unique set of columns, it is not safe to use the faster
259 # method, and the slower BETWEEN query is used instead
260 #
261 # FIXME - this is quite expensive, and doe snot perform caching of any sort
262 # as soon as some of the DQ work becomes viable consider switching this
263 # over
264 if ( __order_by_is_unique($rs_attrs) ) {
265
266 # if offset is 0 (first page) the we can skip a subquery
267 if (! $offset) {
268 push @{$self->{limit_bind}}, [ $self->__rows_bindtype => $rows ];
269
270 return <<EOS;
271 SELECT $outsel FROM (
272 SELECT $insel ${stripped_sql}${order_group_having}
273 ) $qalias WHERE ROWNUM <= ?
274 EOS
275 }
276 else {
277 push @{$self->{limit_bind}}, [ $self->__total_bindtype => $offset + $rows ], [ $self->__offset_bindtype => $offset + 1 ];
278
279 return <<EOS;
242280 SELECT $outsel FROM (
243281 SELECT $outsel, ROWNUM $idx_name FROM (
244282 SELECT $insel ${stripped_sql}${order_group_having}
245283 ) $qalias WHERE ROWNUM <= ?
246284 ) $qalias WHERE $idx_name >= ?
247285 EOS
248
286 }
249287 }
250288 else {
251 push @{$self->{limit_bind}}, [ $self->__rows_bindtype => $rows ];
289 push @{$self->{limit_bind}}, [ $self->__offset_bindtype => $offset + 1 ], [ $self->__total_bindtype => $offset + $rows ];
252290
253291 return <<EOS;
254 SELECT $outsel FROM (
292 SELECT $outsel FROM (
293 SELECT $outsel, ROWNUM $idx_name FROM (
255294 SELECT $insel ${stripped_sql}${order_group_having}
256 ) $qalias WHERE ROWNUM <= ?
295 ) $qalias
296 ) $qalias WHERE $idx_name BETWEEN ? AND ?
257297 EOS
258
259 }
260 }
261
262 # used by _Top and _FetchFirst
298 }
299 }
300
301 # determine if the supplied order_by contains a unique column (set)
302 sub __order_by_is_unique {
303 my $rs_attrs = shift;
304 my $rsrc = $rs_attrs->{_rsroot_rsrc};
305 my $order_by = $rs_attrs->{order_by}
306 || return 0;
307
308 my $storage = $rsrc->schema->storage;
309
310 my @order_by_cols = map { $_->[0] } $storage->_extract_order_criteria($order_by)
311 or return 0;
312
313 my $colinfo =
314 $storage->_resolve_column_info($rs_attrs->{from}, \@order_by_cols);
315
316 my $sources = {
317 map {( "$_" => $_ )} map { $_->{-result_source} } values %$colinfo
318 };
319
320 my $supplied_order = {
321 map { $_ => 1 }
322 grep { exists $colinfo->{$_} and ! $colinfo->{$_}{is_nullable} }
323 @order_by_cols
324 };
325
326 return 0 unless keys %$supplied_order;
327
328 for my $uks (
329 map { values %$_ } map { +{ $_->unique_constraints } } values %$sources
330 ) {
331 return 1
332 unless first { ! exists $supplied_order->{$_} } @$uks;
333 }
334
335 return 0;
336 }
337
338 # used by _Top and _FetchFirst below
263339 sub _prep_for_skimming_limit {
264340 my ( $self, $sql, $rs_attrs ) = @_;
265341
622698 'Limit dialect implementation usable only in the context of DBIC (missing $rs_attrs)'
623699 ) unless ref ($rs_attrs) eq 'HASH';
624700
625 # mangle the input sql as we will be replacing the selector
626 $proto_sql =~ s/^ \s* SELECT \s+ .+ \s+ (?= \b FROM \b )//ix
627 or $self->throw_exception("Unrecognizable SELECT: $proto_sql");
701 # mangle the input sql as we will be replacing the selector entirely
702 unless (
703 $rs_attrs->{_selector_sql}
704 and
705 $proto_sql =~ s/^ \s* SELECT \s* \Q$rs_attrs->{_selector_sql}//ix
706 ) {
707 $self->throw_exception("Unrecognizable SELECT: $proto_sql");
708 }
628709
629710 my ($re_sep, $re_alias) = map { quotemeta $_ } ( $self->{name_sep}, $rs_attrs->{alias} );
630711
99 sub insert {
1010 my $self = shift;
1111
12 my $table = $_[0];
13 $table = $self->_quote($table);
14
1512 if (! $_[1] or (ref $_[1] eq 'HASH' and !keys %{$_[1]} ) ) {
13 my $table = $self->_quote($_[0]);
1614 return "INSERT INTO ${table} () VALUES ()"
1715 }
1816
19 return $self->SUPER::insert (@_);
17 return $self->next::method (@_);
2018 }
2119
2220 # Allow STRAIGHT_JOIN's
2725 return ' STRAIGHT_JOIN '
2826 }
2927
30 return $self->SUPER::_generate_join_clause( $join_type );
28 return $self->next::method($join_type);
3129 }
3230
3331 # LOCK IN SHARE MODE
1919 handler => '_where_field_PRIOR',
2020 };
2121
22 $self->SUPER::new (\%opts);
22 $self->next::method(\%opts);
2323 }
2424
2525 sub _assemble_binds {
3535 my ($cb_sql, @cb_bind) = $self->_connect_by($rs_attrs);
3636 push @{$self->{oracle_connect_by_bind}}, @cb_bind;
3737
38 my $sql = $self->SUPER::_parse_rs_attrs(@_);
38 my $sql = $self->next::method(@_);
3939
4040 return "$cb_sql $sql";
4141 }
204204 }
205205 ;
206206
207 $sql = $self->$limiter ($sql, $rs_attrs, $limit, $offset);
207 $sql = $self->$limiter (
208 $sql,
209 { %{$rs_attrs||{}}, _selector_sql => $fields },
210 $limit,
211 $offset
212 );
208213 }
209214 else {
210215 ($sql, @bind) = $self->next::method ($table, $fields, $where, $rs_attrs);
718718 $dt[2],
719719 $dt[1],
720720 $dt[0],
721 $tm[1] / 1000, # convert to millisecs, format as up/down rounded int above
721 int($tm[1] / 1000), # convert to millisecs
722722 ),
723723 });
724724 }
10031003
10041004 =over 4
10051005
1006 =item Arguments: %attrs?
1007
10061008 =item Return Value: $new_schema
10071009
10081010 =back
10091011
10101012 Clones the schema and its associated result_source objects and returns the
1011 copy.
1013 copy. The resulting copy will have the same attributes as the source schema,
1014 except for those attributes explicitly overriden by the provided C<%attrs>.
10121015
10131016 =cut
10141017
10151018 sub clone {
1016 my ($self) = @_;
1017 my $clone = { (ref $self ? %$self : ()) };
1019 my $self = shift;
1020
1021 my $clone = {
1022 (ref $self ? %$self : ()),
1023 (@_ == 1 && ref $_[0] eq 'HASH' ? %{ $_[0] } : @_),
1024 };
10181025 bless $clone, (ref $self || $self);
10191026
10201027 $clone->class_mappings({ %{$clone->class_mappings} });
44 use base 'DBIx::Class::Storage::DBI::UniqueIdentifier';
55 use mro 'c3';
66
7 use DBI ();
78 use List::Util 'first';
89 use namespace::clean;
910
157157 my ( $schema, $table ) = $source_name =~ /( (?:${ql})? \w+ (?:${qr})? ) \. ( (?:${ql})? \w+ (?:${qr})? )/x;
158158
159159 # if no explicit schema was requested - use the default schema (which in the case of Oracle is the db user)
160 $schema ||= uc( ($self->_dbi_connect_info||[])->[1] || '');
160 $schema ||= \'= USER';
161161
162162 my ($sql, @bind) = $sql_maker->select (
163163 'ALL_TRIGGERS',
164164 [qw/TRIGGER_BODY TABLE_OWNER TRIGGER_NAME/],
165165 {
166 $schema ? (OWNER => $schema) : (),
166 OWNER => $schema,
167167 TABLE_NAME => $table || $source_name,
168168 TRIGGERING_EVENT => { -like => '%INSERT%' }, # this will also catch insert_or_update
169169 TRIGGER_TYPE => { -like => '%BEFORE%' }, # we care only about 'before' triggers
173173
174174 # to find all the triggers that mention the column in question a simple
175175 # regex grep since the trigger_body above is a LONG and hence not searchable
176 # via -like
176177 my @triggers = ( map
177178 { my %inf; @inf{qw/body schema name/} = @$_; \%inf }
178179 ( grep
181182 )
182183 );
183184
184 # extract all sequence names mentioned in each trigger
185 for (@triggers) {
186 $_->{sequences} = [ $_->{body} =~ / ( "? [\.\w\"\-]+ "? ) \. nextval /xig ];
187 }
185 # extract all sequence names mentioned in each trigger, throw away
186 # triggers without apparent sequences
187 @triggers = map {
188 my @seqs = $_->{body} =~ / ( [\.\w\"\-]+ ) \. nextval /xig;
189 @seqs
190 ? { %$_, sequences => \@seqs }
191 : ()
192 ;
193 } @triggers;
188194
189195 my $chosen_trigger;
190196
251257 my ( $self, $type, $seq ) = @_;
252258
253259 # use the maker to leverage quoting settings
254 my $sql_maker = $self->sql_maker;
255 my ($id) = $self->_get_dbh->selectrow_array ($sql_maker->select('DUAL', [ ref $seq ? \"$$seq.$type" : "$seq.$type" ] ) );
260 my $sth = $self->_dbh->prepare_cached(
261 $self->sql_maker->select('DUAL', [ ref $seq ? \"$$seq.$type" : "$seq.$type" ] )
262 );
263 $sth->execute;
264 my ($id) = $sth->fetchrow_array;
265 $sth->finish;
256266 return $id;
257267 }
258268
9090 }
9191
9292 sub bind_attribute_by_data_type {
93 $_[1] =~ /^ (?: int(?:eger)? | (?:tiny|small|medium|big)int ) $/ix
93 $_[1] =~ /^ (?: int(?:eger)? | (?:tiny|small|medium)int ) $/ix
9494 ? do { require DBI; DBI::SQL_INTEGER() }
9595 : undef
9696 ;
1717
1818 __PACKAGE__->sql_limit_dialect ('RowCountOrGenericSubQ');
1919 __PACKAGE__->sql_quote_char ([qw/[ ]/]);
20 __PACKAGE__->datetime_parser_type('DateTime::Format::Sybase');
20 __PACKAGE__->datetime_parser_type(
21 'DBIx::Class::Storage::DBI::Sybase::ASE::DateTime::Format'
22 );
2123
2224 __PACKAGE__->mk_group_accessors('simple' =>
2325 qw/_identity _blob_log_on_update _writer_storage _is_extra_storage
2628 _identity_method/
2729 );
2830
31
2932 my @also_proxy_to_extra_storages = qw/
3033 connect_call_set_auto_cast auto_cast connect_call_blob_setup
3134 connect_call_datetime_setup
6871 my $no_bind_vars = __PACKAGE__ . '::NoBindVars';
6972
7073 if ($self->using_freetds) {
71 carp <<'EOF' unless $ENV{DBIC_SYBASE_FREETDS_NOWARN};
74 carp_once <<'EOF' unless $ENV{DBIC_SYBASE_FREETDS_NOWARN};
7275
7376 You are using FreeTDS with Sybase.
7477
849852 $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
850853 $dbh->do('set dateformat mdy'); # input fmt: 08/13/1979 18:08:55.080
851854
852 On connection for use with L<DBIx::Class::InflateColumn::DateTime>, using
853 L<DateTime::Format::Sybase>, which you will need to install.
854
855855 This works for both C<DATETIME> and C<SMALLDATETIME> columns, note that
856856 C<SMALLDATETIME> columns only have minute precision.
857857
870870 'Your DBD::Sybase is too old to support '
871871 .'DBIx::Class::InflateColumn::DateTime, please upgrade!';
872872
873 # FIXME - in retrospect this is a rather bad US-centric choice
874 # of format. Not changing as a bugwards compat, though in reality
875 # the only piece that sees the results of $dt object formatting
876 # (as opposed to parsing) is the database itself, so theoretically
877 # changing both this SET command and the formatter definition of
878 # ::S::D::Sybase::ASE::DateTime::Format below should be safe and
879 # transparent
880
873881 $dbh->do('SET DATEFORMAT mdy');
874 1;
875882 }
876883 }
877884
903910 my ($self, $name) = @_;
904911
905912 $self->_dbh->do("ROLLBACK TRANSACTION $name");
913 }
914
915 package # hide from PAUSE
916 DBIx::Class::Storage::DBI::Sybase::ASE::DateTime::Format;
917
918 my $datetime_parse_format = '%Y-%m-%dT%H:%M:%S.%3NZ';
919 my $datetime_format_format = '%m/%d/%Y %H:%M:%S.%3N';
920
921 my ($datetime_parser, $datetime_formatter);
922
923 sub parse_datetime {
924 shift;
925 require DateTime::Format::Strptime;
926 $datetime_parser ||= DateTime::Format::Strptime->new(
927 pattern => $datetime_parse_format,
928 on_error => 'croak',
929 );
930 return $datetime_parser->parse_datetime(shift);
931 }
932
933 sub format_datetime {
934 shift;
935 require DateTime::Format::Strptime;
936 $datetime_formatter ||= DateTime::Format::Strptime->new(
937 pattern => $datetime_format_format,
938 on_error => 'croak',
939 );
940 return $datetime_formatter->format_datetime(shift);
906941 }
907942
908943 1;
4343
4444 return if ref $self ne __PACKAGE__;
4545 if (not $self->_use_typeless_placeholders) {
46 carp <<'EOF' unless $ENV{DBIC_MSSQL_FREETDS_LOWVER_NOWARN};
46 carp_once <<'EOF' unless $ENV{DBIC_MSSQL_FREETDS_LOWVER_NOWARN};
4747 Placeholders do not seem to be supported in your configuration of
4848 DBD::Sybase/FreeTDS.
4949
33 #
44 # This module contains code that should never have seen the light of day,
55 # does not belong in the Storage, or is otherwise unfit for public
6 # display. The arrival of SQLA2 should immediately oboslete 90% of this
6 # display. The arrival of SQLA2 should immediately obsolete 90% of this
77 #
88
99 use strict;
1414
1515 use List::Util 'first';
1616 use Scalar::Util 'blessed';
17 use Sub::Name 'subname';
1718 use namespace::clean;
1819
1920 #
590591 return \@new_from;
591592 }
592593
594 # yet another atrocity: attempt to extract all columns from a
595 # where condition by hooking _quote
596 sub _extract_condition_columns {
597 my ($self, $cond, $sql_maker) = @_;
598
599 return [] unless $cond;
600
601 $sql_maker ||= $self->{_sql_ident_capturer} ||= do {
602 # FIXME - replace with a Moo trait
603 my $orig_sm_class = ref $self->sql_maker;
604 my $smic_class = "${orig_sm_class}::_IdentCapture_";
605
606 unless ($smic_class->isa('SQL::Abstract')) {
607
608 no strict 'refs';
609 *{"${smic_class}::_quote"} = subname "${smic_class}::_quote" => sub {
610 my ($self, $ident) = @_;
611 if (ref $ident eq 'SCALAR') {
612 $ident = $$ident;
613 my $storage_quotes = $self->sql_quote_char || '"';
614 my ($ql, $qr) = map
615 { quotemeta $_ }
616 (ref $storage_quotes eq 'ARRAY' ? @$storage_quotes : ($storage_quotes) x 2 )
617 ;
618
619 while ($ident =~ /
620 $ql (\w+) $qr
621 |
622 ([\w\.]+)
623 /xg) {
624 $self->{_captured_idents}{$1||$2}++;
625 }
626 }
627 else {
628 $self->{_captured_idents}{$ident}++;
629 }
630 return $ident;
631 };
632
633 *{"${smic_class}::_get_captured_idents"} = subname "${smic_class}::_get_captures" => sub {
634 (delete shift->{_captured_idents}) || {};
635 };
636
637 $self->inject_base ($smic_class, $orig_sm_class);
638
639 }
640
641 $smic_class->new();
642 };
643
644 $sql_maker->_recurse_where($cond);
645
646 return [ sort keys %{$sql_maker->_get_captured_idents} ];
647 }
648
593649 sub _extract_order_criteria {
594650 my ($self, $order_by, $sql_maker) = @_;
595651
6060 my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG}
6161 || $ENV{DBIC_TRACE};
6262 if (defined($debug_env) && ($debug_env =~ /=(.+)$/)) {
63 $fh = IO::File->new($1, 'w')
63 $fh = IO::File->new($1, 'a')
6464 or die("Cannot open trace file $1");
6565 } else {
6666 $fh = IO::File->new('>&STDERR')
1010 # $VERSION declaration must stay up here, ahead of any other package
1111 # declarations, as to not confuse various modules attempting to determine
1212 # this ones version, whether that be s.c.o. or Module::Metadata, etc
13 $VERSION = '0.08192';
13 $VERSION = '0.08193';
1414
1515 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
1616
154154 __PACKAGE__->table('artist');
155155 __PACKAGE__->add_columns(qw/ artistid name /);
156156 __PACKAGE__->set_primary_key('artistid');
157 __PACKAGE__->has_many(cds => 'MyApp::Schema::Result::CD');
157 __PACKAGE__->has_many(cds => 'MyApp::Schema::Result::CD', 'artistid');
158158
159159 1;
160160
00 use strict;
11 use warnings;
22 use Test::More;
3 use DBIx::Class::Optional::Dependencies ();
4
5 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
6 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
37
48 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
59
1515
1616 use threads;
1717 use Test::Exception;
18 use DBIx::Class::Optional::Dependencies ();
1819 use lib qw(t/lib);
20
21 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
22 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
1923
2024 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
2125 plan skip_all => 'Set $ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test'
1717
1818
1919 use threads;
20 use DBIx::Class::Optional::Dependencies ();
2021 use lib qw(t/lib);
22
23 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
24 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
2125
2226 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
2327 plan skip_all => 'Set $ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test'
4343
4444 Class::Accessor::Grouped
4545 Class::C3::Componentised
46
47 Data::Compare
4648 /, $] < 5.010 ? 'MRO::Compat' : () };
4749
4850 $test_hook = sub {
0 # Pre-5.10 perls pollute %INC on unsuccesfull module
1 # require, making it appear as if the module is already
2 # loaded on subsequent require()s
3 # Can't seem to find the exact RT/perldelta entry
4 BEGIN {
5 if ($] < 5.010) {
6 # shut up spurious warnings without loading warnings.pm
7 *CORE::GLOBAL::require = sub {};
8
9 *CORE::GLOBAL::require = sub {
10 my $res = eval { CORE::require($_[0]) };
11 if ($@) {
12 delete $INC{$_[0]};
13 die
14 }
15 $res;
16 }
17 }
18 }
19
020 use strict;
121 use warnings;
222
1434 my @modules = grep {
1535 my $mod = $_;
1636
17 # trap deprecation warnings and whatnot
18 local $SIG{__WARN__} = sub {};
19
2037 # not all modules are loadable at all times
21 eval "require $mod" ? $mod : do {
22 SKIP: { skip "Failed require of $mod: $@", 1 };
23 ();
38 do {
39 # trap deprecation warnings and whatnot
40 local $SIG{__WARN__} = sub {};
41 eval "require $mod";
42 } ? $mod : do {
43 SKIP: { skip "Failed require of $mod: " . ($@ =~ /^(.+?)$/m)[0], 1 };
44 (); # empty RV for @modules
2445 };
25
2646
2747 } find_modules();
2848
55
66 use DBI::Const::GetInfoType;
77 use Scalar::Util qw/weaken/;
8 use DBIx::Class::Optional::Dependencies ();
89
910 use lib qw(t/lib);
1011 use DBICTest;
1112 use DBIC::SqlMakerTest;
13
14 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mysql')
15 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mysql');
1216
1317 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MYSQL_${_}" } qw/DSN USER PASS/};
1418
33 use Test::More;
44 use Test::Exception;
55 use Sub::Name;
6 use DBIx::Class::Optional::Dependencies ();
67 use lib qw(t/lib);
78 use DBICTest;
89
10 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_pg')
11 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_pg');
912
1013 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
1114
11 use warnings;
22
33 use Test::More;
4 use DBIx::Class::Optional::Dependencies ();
45 use lib qw(t/lib);
56 use DBICTest;
7
8 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
9 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
610
711 my ($dsn, $dbuser, $dbpass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
812
44 use Test::More;
55 use Sub::Name;
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78
89 use lib qw(t/lib);
910 use DBICTest;
22
33 use Test::Exception;
44 use Test::More;
5
5 use DBIx::Class::Optional::Dependencies ();
66 use lib qw(t/lib);
77 use DBIC::SqlMakerTest;
88
1414 $ENV{NLS_COMP} = "BINARY";
1515 $ENV{NLS_LANG} = "AMERICAN";
1616
17 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_oracle')
18 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_oracle');
17 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_oracle')
18 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_oracle');
1919
2020 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_ORA_${_}" } qw/DSN USER PASS/};
2121
315315 my $rs = $schema->resultset('Artist')->search({}, {
316316 start_with => { name => 'root' },
317317 connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
318 order_by => { -asc => 'name' },
318 order_by => [ { -asc => 'name' }, { -desc => 'artistid' } ],
319319 rows => 2,
320320 });
321321
328328 FROM artist me
329329 START WITH name = ?
330330 CONNECT BY parentid = PRIOR artistid
331 ORDER BY name ASC
331 ORDER BY name ASC, artistid DESC
332332 ) me
333333 WHERE ROWNUM <= ?
334334 )',
351351 FROM (
352352 SELECT artistid
353353 FROM (
354 SELECT me.artistid
355 FROM artist me
356 START WITH name = ?
357 CONNECT BY parentid = PRIOR artistid
354 SELECT artistid, ROWNUM rownum__index
355 FROM (
356 SELECT me.artistid
357 FROM artist me
358 START WITH name = ?
359 CONNECT BY parentid = PRIOR artistid
360 ) me
358361 ) me
359 WHERE ROWNUM <= ?
362 WHERE rownum__index BETWEEN ? AND ?
360363 ) me
361364 )',
362365 [
363366 [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
364 => 'root'], [ $ROWS => 2 ] ,
367 => 'root'],
368 [ $ROWS => 1 ],
369 [ $TOTAL => 2 ],
365370 ],
366371 );
367372
33 use Test::More;
44 use Test::Exception;
55 use Try::Tiny;
6 use DBIx::Class::Optional::Dependencies ();
67 use lib qw(t/lib);
78 use DBICTest;
9
10 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_db2')
11 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_db2');
812
913 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_DB2_${_}" } qw/DSN USER PASS/};
1014
11 use warnings;
22
33 use Test::More;
4 use DBIx::Class::Optional::Dependencies ();
45 use lib qw(t/lib);
56 use DBICTest;
7
8 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_db2_400')
9 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_db2_400');
610
711 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_DB2_400_${_}" } qw/DSN USER PASS/};
812
22
33 use Test::More;
44 use Test::Exception;
5 use Try::Tiny;
6 use DBIx::Class::SQLMaker::LimitDialects;
7 use DBIx::Class::Optional::Dependencies ();
58 use lib qw(t/lib);
69 use DBICTest;
710 use DBIC::SqlMakerTest;
8 use Try::Tiny;
9
10 use DBIx::Class::SQLMaker::LimitDialects;
11
12 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mssql_odbc')
13 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mssql_odbc');
14
1115 my $OFFSET = DBIx::Class::SQLMaker::LimitDialects->__offset_bindtype;
1216 my $TOTAL = DBIx::Class::SQLMaker::LimitDialects->__total_bindtype;
1317
33
44 use Test::More;
55 use Test::Exception;
6 use DBIx::Class::Optional::Dependencies ();
67 use lib qw(t/lib);
78 use DBICTest;
9
10 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_ase')
11 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_ase');
812
913 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SYBASE_${_}" } qw/DSN USER PASS/};
1014
438442 lives_ok {
439443 $rs->populate([
440444 {
441 bytea => 1,
442445 blob => $binstr{large},
443446 clob => $new_str,
444 a_memo => 2,
445 },
446 {
447 bytea => 1,
447 },
448 {
448449 blob => $binstr{large},
449450 clob => $new_str,
450 a_memo => 2,
451451 },
452452 ]);
453453 } 'insert_bulk with blobs does not die';
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
8
9 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mssql_ado')
10 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mssql_ado');
711
812 # Example DSN (from frew):
913 # dbi:ADO:PROVIDER=sqlncli10;SERVER=tcp:172.24.2.10;MARS Connection=True;Initial Catalog=CIS;UID=cis_web;PWD=...;DataTypeCompatibility=80;
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
8
9 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_informix')
10 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_informix');
711
812 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_INFORMIX_${_}" } qw/DSN USER PASS/};
913
44 use Test::Exception;
55 use Scope::Guard ();
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78 use lib qw(t/lib);
89 use DBICTest;
910
10 DBICTest::Schema->load_classes('ArtistGUID');
11
12 # tests stolen from 748informix.t
13
1411 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SQLANYWHERE_${_}" } qw/DSN USER PASS/};
1512 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_SQLANYWHERE_ODBC_${_}" } qw/DSN USER PASS/};
13
14 plan skip_all => 'Test needs ' .
15 (join ' or ', map { $_ ? $_ : () }
16 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_sqlanywhere'),
17 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_sqlanywhere_odbc'))
18 unless
19 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_sqlanywhere')
20 or
21 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_sqlanywhere_odbc')
22 or
23 (not $dsn || $dsn2);
24
25 DBICTest::Schema->load_classes('ArtistGUID');
26
27 # tests stolen from 748informix.t
1628
1729 plan skip_all => <<'EOF' unless $dsn || $dsn2;
1830 Set $ENV{DBICTEST_SQLANYWHERE_DSN} and/or $ENV{DBICTEST_SQLANYWHERE_ODBC_DSN},
99
1010 use Test::More;
1111 use Test::Exception;
12 use DBIx::Class::Optional::Dependencies ();
1213 use lib qw(t/lib);
1314 use DBICTest;
15
16 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mssql_sybase')
17 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mssql_sybase');
1418
1519 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_${_}" } qw/DSN USER PASS/};
1620
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
78 use Scope::Guard ();
89
10 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_FIREBIRD_${_}" } qw/DSN USER PASS/};
11 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_INTERBASE_${_}" } qw/DSN USER PASS/};
12 my ($dsn3, $user3, $pass3) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
13
14 plan skip_all => 'Test needs ' .
15 (join ' or ', map { $_ ? $_ : () }
16 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird'),
17 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird_interbase'),
18 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird_odbc'))
19 unless
20 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird')
21 or
22 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird_interbase')
23 or
24 $dsn3 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird_odbc')
25 or
26 (not $dsn || $dsn2 || $dsn3);
27
928 # tests stolen from 749sybase_asa.t
1029
11 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_FIREBIRD_${_}" } qw/DSN USER PASS/};
12 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
13
1430 # Example DSNs:
31 # dbi:Firebird:db=/var/lib/firebird/2.5/data/hlaghdb.fdb
1532 # dbi:InterBase:db=/var/lib/firebird/2.5/data/hlaghdb.fdb
16 # dbi:Firebird:db=/var/lib/firebird/2.5/data/hlaghdb.fdb
1733
1834 # Example ODBC DSN:
1935 # dbi:ODBC:Driver=Firebird;Dbname=/var/lib/firebird/2.5/data/hlaghdb.fdb
2036
21 plan skip_all => <<'EOF' unless $dsn || $dsn2;
22 Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN},
37 plan skip_all => <<'EOF' unless $dsn || $dsn2 || $dsn3;
38 Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_INTERBASE_DSN}
39 and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN},
2340 _USER and _PASS to run these tests.
2441
2542 WARNING: this test creates and drops the tables "artist", "bindtype_test" and
3047 my @info = (
3148 [ $dsn, $user, $pass ],
3249 [ $dsn2, $user2, $pass2 ],
50 [ $dsn3, $user3, $pass3 ],
3351 );
3452
3553 my $schema;
44 use Test::Exception;
55 use Scope::Guard ();
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78 use lib qw(t/lib);
89 use DBICTest;
10 use DBIC::DebugObj ();
11 use DBIC::SqlMakerTest;
12
13 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSACCESS_ODBC_${_}" } qw/DSN USER PASS/};
14 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSACCESS_ADO_${_}" } qw/DSN USER PASS/};
15
16 plan skip_all => 'Test needs ' .
17 (join ' or ', map { $_ ? $_ : () }
18 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_odbc'),
19 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_ado'))
20 unless
21 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_odbc')
22 or
23 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_ado')
24 or
25 (not $dsn || $dsn2);
926
1027 DBICTest::Schema->load_classes('ArtistGUID');
1128
1431 # dbi:ADO:Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\rkitover\Documents\access_sample.accdb
1532 # dbi:ADO:Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\rkitover\Documents\access_sample.accdb;Persist Security Info=False'
1633
17 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSACCESS_ODBC_${_}" } qw/DSN USER PASS/};
18 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSACCESS_ADO_${_}" } qw/DSN USER PASS/};
19
2034 plan skip_all => <<'EOF' unless $dsn || $dsn2;
21 Set $ENV{DBICTEST_MSACCESS_ODBC_DSN} and/or $ENV{DBICTEST_MSACCESS_ADO_DSN} (and optionally _USER and _PASS) to run these tests.\nWarning: this test drops and creates the tables 'artist', 'cd', 'bindtype_test' and 'artist_guid'.
35 Set $ENV{DBICTEST_MSACCESS_ODBC_DSN} and/or $ENV{DBICTEST_MSACCESS_ADO_DSN} (and optionally _USER and _PASS) to run these tests.
36 Warning: this test drops and creates the tables 'artist', 'cd', 'bindtype_test' and 'artist_guid'.
2237 EOF
23
24 plan skip_all => 'Test needs ' .
25 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_odbc')
26 . ' or ' .
27 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_ado')
28 unless
29 DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_odbc')
30 or
31 DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_ado');
3238
3339 my @info = (
3440 [ $dsn, $user || '', $pass || '' ],
139145 title => 'my track',
140146 });
141147
148 my ($sql, @bind);
149
142150 my $joined_track = try {
151 local $schema->storage->{debug} = 1;
152 local $schema->storage->{debugobj} = DBIC::DebugObj->new(\$sql, \@bind);
153
143154 $schema->resultset('Artist')->search({
144155 artistid => $first_artistid,
145156 }, {
149160 })->next;
150161 }
151162 catch {
152 diag "Could not execute two-step join: $_";
163 diag "Could not execute two-step left join: $_";
153164 };
154165
166 s/^'//, s/'\z// for @bind;
167
168 is_same_sql_bind(
169 $sql,
170 \@bind,
171 'SELECT [me].[artistid], [me].[name], [me].[rank], [me].[charfield], [tracks].[title] FROM ( ( [artist] [me] LEFT JOIN cd [cds] ON [cds].[artist] = [me].[artistid] ) LEFT JOIN [track] [tracks] ON [tracks].[cd] = [cds].[cdid] ) WHERE ( [artistid] = ? )',
172 [1],
173 'correct SQL for two-step left join',
174 );
175
155176 is try { $joined_track->get_column('track_title') }, 'my track',
156 'two-step join works';
177 'two-step left join works';
178
179 ($sql, @bind) = ();
180
181 $joined_artist = try {
182 local $schema->storage->{debug} = 1;
183 local $schema->storage->{debugobj} = DBIC::DebugObj->new(\$sql, \@bind);
184
185 $schema->resultset('Track')->search({
186 trackid => $track->trackid,
187 }, {
188 join => [{ cd => 'artist' }],
189 '+select' => [ 'artist.name' ],
190 '+as' => [ 'artist_name' ],
191 })->next;
192 }
193 catch {
194 diag "Could not execute two-step inner join: $_";
195 };
196
197 s/^'//, s/'\z// for @bind;
198
199 is_same_sql_bind(
200 $sql,
201 \@bind,
202 'SELECT [me].[trackid], [me].[cd], [me].[position], [me].[title], [me].[last_updated_on], [me].[last_updated_at], [artist].[name] FROM ( ( [track] [me] INNER JOIN cd [cd] ON [cd].[cdid] = [me].[cd] ) INNER JOIN [artist] [artist] ON [artist].[artistid] = [cd].[artist] ) WHERE ( [trackid] = ? )',
203 [$track->trackid],
204 'correct SQL for two-step inner join',
205 );
206
207 is try { $joined_artist->get_column('artist_name') }, 'foo',
208 'two-step inner join works';
157209
158210 # test basic transactions
159211 $schema->txn_do(sub {
33 use Test::More;
44 use Test::Exception;
55 use Test::Warn;
6 use Config;
7
68 use lib qw(t/lib);
79 use DBICTest;
810
9 my $schema = DBICTest->init_schema(auto_savepoint => 1);
11 # savepoints test
12 {
13 my $schema = DBICTest->init_schema(auto_savepoint => 1);
1014
11 my $ars = $schema->resultset('Artist');
15 my $ars = $schema->resultset('Artist');
1216
13 # test two-phase commit and inner transaction rollback from nested transactions
14 $schema->txn_do(sub {
15 $ars->create({ name => 'in_outer_transaction' });
17 # test two-phase commit and inner transaction rollback from nested transactions
1618 $schema->txn_do(sub {
17 $ars->create({ name => 'in_inner_transaction' });
19 $ars->create({ name => 'in_outer_transaction' });
20 $schema->txn_do(sub {
21 $ars->create({ name => 'in_inner_transaction' });
22 });
23 ok($ars->search({ name => 'in_inner_transaction' })->first,
24 'commit from inner transaction visible in outer transaction');
25 throws_ok {
26 $schema->txn_do(sub {
27 $ars->create({ name => 'in_inner_transaction_rolling_back' });
28 die 'rolling back inner transaction';
29 });
30 } qr/rolling back inner transaction/, 'inner transaction rollback executed';
31 $ars->create({ name => 'in_outer_transaction2' });
1832 });
33
34 ok($ars->search({ name => 'in_outer_transaction' })->first,
35 'commit from outer transaction');
36 ok($ars->search({ name => 'in_outer_transaction2' })->first,
37 'second commit from outer transaction');
1938 ok($ars->search({ name => 'in_inner_transaction' })->first,
20 'commit from inner transaction visible in outer transaction');
21 throws_ok {
22 $schema->txn_do(sub {
23 $ars->create({ name => 'in_inner_transaction_rolling_back' });
24 die 'rolling back inner transaction';
25 });
26 } qr/rolling back inner transaction/, 'inner transaction rollback executed';
27 $ars->create({ name => 'in_outer_transaction2' });
28 });
39 'commit from inner transaction');
40 is $ars->search({ name => 'in_inner_transaction_rolling_back' })->first,
41 undef,
42 'rollback from inner transaction';
43 }
2944
30 ok($ars->search({ name => 'in_outer_transaction' })->first,
31 'commit from outer transaction');
32 ok($ars->search({ name => 'in_outer_transaction2' })->first,
33 'second commit from outer transaction');
34 ok($ars->search({ name => 'in_inner_transaction' })->first,
35 'commit from inner transaction');
36 is $ars->search({ name => 'in_inner_transaction_rolling_back' })->first,
37 undef,
38 'rollback from inner transaction';
45 my $schema = DBICTest->init_schema();
3946
4047 # make sure the side-effects of RT#67581 do not result in data loss
4148 my $row;
42 warnings_exist { $row = $ars->create ({ name => 'alpha rank', rank => 'abc' }) }
49 warnings_exist { $row = $schema->resultset('Artist')->create ({ name => 'alpha rank', rank => 'abc' }) }
4350 [qr/Non-numeric value supplied for column 'rank' despite the numeric datatype/],
4451 'proper warning on string insertion into an numeric column'
4552 ;
4653 $row->discard_changes;
4754 is ($row->rank, 'abc', 'proper rank inserted into database');
4855
56 # and make sure we do not lose actual bigints
57 {
58 package DBICTest::BigIntArtist;
59 use base 'DBICTest::Schema::Artist';
60 __PACKAGE__->table('artist');
61 __PACKAGE__->add_column(bigint => { data_type => 'bigint' });
62 }
63 $schema->register_class(BigIntArtist => 'DBICTest::BigIntArtist');
64 $schema->storage->dbh_do(sub {
65 $_[1]->do('ALTER TABLE artist ADD COLUMN bigint BIGINT');
66 });
67
68 # test upper/lower boundaries for sqlite and some values inbetween
69 # range is -(2**63) .. 2**63 - 1
70 for my $bi (qw/
71 -9223372036854775808
72 -9223372036854775807
73 -8694837494948124658
74 -6848440844435891639
75 -5664812265578554454
76 -5380388020020483213
77 -2564279463598428141
78 2442753333597784273
79 4790993557925631491
80 6773854980030157393
81 7627910776496326154
82 8297530189347439311
83 9223372036854775806
84 9223372036854775807
85 /) {
86 $row = $schema->resultset('BigIntArtist')->create({ bigint => $bi });
87 is ($row->bigint, $bi, "value in object correct ($bi)");
88
89 TODO: {
90 local $TODO = 'This perl does not seem to have 64bit int support - DBI roundtrip of large int will fail'
91 unless $Config{ivsize} >= 8;
92
93 $row->discard_changes;
94 is ($row->bigint, $bi, "value in database correct ($bi)");
95 }
96 }
97
4998 done_testing;
5099
51100 # vim:sts=2 sw=2:
5858 $custom_deployment_statements_called = 0;
5959
6060 # add a temporary sqlt_deploy_hook to a source
61 no warnings 'once';
62 local *DBICTest::Track::sqlt_deploy_hook = sub {
63 my ($self, $sqlt_table) = @_;
61 local $DBICTest::Schema::Track::hook_cb = sub {
62 my ($class, $sqlt_table) = @_;
6463
6564 $deploy_hook_called = 1;
6665
67 is (blessed ($self), 'DBIx::Class::ResultSource::Table', 'Source object passed to plain hook');
66 is ($class, 'DBICTest::Track', 'Result class passed to plain hook');
6867
6968 is (
7069 $sqlt_table->schema->translator->producer_type,
7372 );
7473 };
7574
75 my $component_deploy_hook_called = 0;
76 local $DBICTest::DeployComponent::hook_cb = sub {
77 $component_deploy_hook_called = 1;
78 };
79
7680 $schema->deploy; # do not remove, this fires the is() test in the callback above
7781 ok($deploy_hook_called, 'deploy hook got called');
7882 ok($custom_deployment_statements_called, '->deploy used the schemas deploy_statements method');
83 ok($component_deploy_hook_called, 'component deploy hook got called');
7984 }
8085
8186 {
9595 "overloaded update 7"
9696 );
9797
98 $employee->group_id(2);
99 $employee->name('E of the month');
100 $employee->update({ employee_id => 666, position => 2 });
101 is_deeply(
102 { $employee->get_columns },
103 {
104 employee_id => 666,
105 encoded => undef,
106 group_id => 2,
107 group_id_2 => undef,
108 group_id_3 => undef,
109 name => "E of the month",
110 position => 2
111 },
112 'combined update() worked correctly'
113 );
114 is_deeply(
115 { $employee->get_columns },
116 { $employee->get_from_storage->get_columns },
117 'object matches database state',
118 );
119
120 #####
98121 # multicol tests begin here
122 #####
123
99124 DBICTest::Employee->grouping_column(['group_id_2', 'group_id_3']);
100125 $employees->delete();
101126 foreach my $group_id_2 (1..4) {
11 use warnings;
22
33 use Test::More;
4 use DBIx::Class::Optional::Dependencies ();
45
56 my ($create_sql, $dsn, $user, $pass);
67
78 if ($ENV{DBICTEST_PG_DSN}) {
9 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_pg')
10 unless DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_pg');
11
812 ($dsn, $user, $pass) = @ENV{map { "DBICTEST_PG_${_}" } qw/DSN USER PASS/};
913
1014 $create_sql = "CREATE TABLE artist (artistid serial PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10))";
1115 } elsif ($ENV{DBICTEST_MYSQL_DSN}) {
16 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_mysql')
17 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_mysql');
18
1219 ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MYSQL_${_}" } qw/DSN USER PASS/};
1320
1421 $create_sql = "CREATE TABLE artist (artistid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), rank INTEGER NOT NULL DEFAULT '13', charfield CHAR(10)) ENGINE=InnoDB";
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
78 use Scope::Guard ();
89
910 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_FIREBIRD_${_}" } qw/DSN USER PASS/};
10 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
11 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_INTERBASE_${_}" } qw/DSN USER PASS/};
12 my ($dsn3, $user3, $pass3) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
13
14 plan skip_all => 'Test needs ' .
15 (join ' and ', map { $_ ? $_ : () }
16 DBIx::Class::Optional::Dependencies->req_missing_for('test_dt'),
17 (join ' or ', map { $_ ? $_ : () }
18 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird'),
19 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird_interbase'),
20 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_firebird_odbc')))
21 unless
22 DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt') && (
23 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird')
24 or
25 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird_interbase')
26 or
27 $dsn3 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_firebird_odbc'))
28 or (not $dsn || $dsn2 || $dsn3);
1129
1230 if (not ($dsn || $dsn2)) {
1331 plan skip_all => <<'EOF';
14 Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
32 Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_INTERBASE_DSN}
33 and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
1534 _USER and _PASS to run this test'.
1635 Warning: This test drops and creates a table called 'event'";
1736 EOF
1837 }
1938
20 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
21 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt');
22
2339 my @info = (
2440 [ $dsn, $user, $pass ],
2541 [ $dsn2, $user2, $pass2 ],
42 [ $dsn3, $user3, $pass3 ],
2643 );
2744
2845 my $schema;
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
78 use Scope::Guard ();
9
10 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
11 . ' and ' .
12 DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_informix')
13 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt')
14 && DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_informix');
815
916 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_INFORMIX_${_}" } qw/DSN USER PASS/};
1017
1421 Warning: This test drops and creates a table called 'event'";
1522 EOF
1623 }
17
18 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
19 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt');
2024
2125 my $schema;
2226
0 use strict;
1 use warnings;
2
3 use Test::More;
4 use Test::Exception;
5 use lib qw(t/lib);
6 use DBICTest;
7
8 my $no_class = '_DBICTEST_NONEXISTENT_CLASS_';
9
10 my $schema = DBICTest->init_schema();
11 $schema->storage->datetime_parser_type($no_class);
12
13 my $event = $schema->resultset('Event')->find(1);
14
15 # test that datetime_undef_if_invalid does not eat the missing dep exception
16 throws_ok {
17 my $dt = $event->starts_at;
18 } qr{Can't locate ${no_class}\.pm};
19
20 done_testing;
44 use Test::Exception;
55 use Scope::Guard ();
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78 use lib qw(t/lib);
89 use DBICTest;
910
1011 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSACCESS_ODBC_${_}" } qw/DSN USER PASS/};
1112 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSACCESS_ADO_${_}" } qw/DSN USER PASS/};
1213
14 plan skip_all => 'Test needs ' .
15 (join ' and ', map { $_ ? $_ : () }
16 DBIx::Class::Optional::Dependencies->req_missing_for('test_dt'),
17 (join ' or ', map { $_ ? $_ : () }
18 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_odbc'),
19 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_msaccess_ado')))
20 unless
21 DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt') && (
22 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_odbc')
23 or
24 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_msaccess_ado'))
25 or (not $dsn || $dsn2);
26
1327 plan skip_all => <<'EOF' unless $dsn || $dsn2;
14 Set $ENV{DBICTEST_MSACCESS_ODBC_DSN} and/or $ENV{DBICTEST_MSACCESS_ADO_DSN} (and optionally _USER and _PASS) to run these tests.\nWarning: this test drops and creates the table 'track'.
28 Set $ENV{DBICTEST_MSACCESS_ODBC_DSN} and/or $ENV{DBICTEST_MSACCESS_ADO_DSN} (and optionally _USER and _PASS) to run these tests.
29 Warning: this test drops and creates the table 'track'.
1530 EOF
16
17 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
18 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt');
1931
2032 my @connect_info = (
2133 [ $dsn, $user || '', $pass || '' ],
44 use Test::Exception;
55 use Scope::Guard ();
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78 use lib qw(t/lib);
89 use DBICTest;
910
10 DBICTest::Schema->load_classes('EventSmallDT');
11 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
12 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSSQL_${_}" } qw/DSN USER PASS/};
13 my ($dsn3, $user3, $pass3) = @ENV{map { "DBICTEST_MSSQL_ADO_${_}" } qw/DSN USER PASS/};
14
15 plan skip_all => 'Test needs ' .
16 (join ' and ', map { $_ ? $_ : () }
17 DBIx::Class::Optional::Dependencies->req_missing_for('test_dt'),
18 (join ' or ', map { $_ ? $_ : () }
19 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_mssql_odbc'),
20 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_mssql_sybase'),
21 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_mssql_ado')))
22 unless
23 DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt') && (
24 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_mssql_odbc')
25 or
26 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_mssql_sybase')
27 or
28 $dsn3 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_mssql_ado'))
29 or (not $dsn || $dsn2 || $dsn3);
1130
1231 # use this if you keep a copy of DBD::Sybase linked to FreeTDS somewhere else
1332 BEGIN {
1534 unshift @INC, $_ for split /:/, $lib_dirs;
1635 }
1736 }
18
19 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
20 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSSQL_${_}" } qw/DSN USER PASS/};
21 my ($dsn3, $user3, $pass3) = @ENV{map { "DBICTEST_MSSQL_ADO_${_}" } qw/DSN USER PASS/};
2237
2338 if (not ($dsn || $dsn2 || $dsn3)) {
2439 plan skip_all =>
2843 ." 'track'.";
2944 }
3045
31 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
32 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt');
46 DBICTest::Schema->load_classes('EventSmallDT');
3347
3448 my @connect_info = (
3549 [ $dsn, $user, $pass ],
33 use Test::More;
44 use Test::Exception;
55 use Test::Warn;
6 use DBIx::Class::Optional::Dependencies ();
67 use lib qw(t/lib);
78 use DBICTest;
89 use DBICTest::Schema;
22
33 use Test::More;
44 use Test::Exception;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
8
9 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_oracle')
10 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_oracle');
711
812 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_ORA_${_}" } qw/DSN USER PASS/};
913
1115 plan skip_all => 'Set $ENV{DBICTEST_ORA_DSN}, _USER and _PASS to run this test. ' .
1216 'Warning: This test drops and creates a table called \'track\'';
1317 }
14
15 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_oracle')
16 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_oracle');
1718
1819 # DateTime::Format::Oracle needs this set
1920 $ENV{NLS_DATE_FORMAT} = 'DD-MON-YY';
22
33 use Test::More;
44 use Test::Warn;
5 use DBIx::Class::Optional::Dependencies ();
56 use lib qw(t/lib);
67 use DBICTest;
78
33 use Test::More;
44 use Test::Exception;
55 use Scope::Guard ();
6 use DBIx::Class::Optional::Dependencies ();
67 use lib qw(t/lib);
78 use DBICTest;
89
910 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SQLANYWHERE_${_}" } qw/DSN USER PASS/};
1011 my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_SQLANYWHERE_ODBC_${_}" } qw/DSN USER PASS/};
12
13 plan skip_all => 'Test needs ' .
14 (join ' and ', map { $_ ? $_ : () }
15 DBIx::Class::Optional::Dependencies->req_missing_for('test_dt'),
16 (join ' or ', map { $_ ? $_ : () }
17 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_sqlanywhere'),
18 DBIx::Class::Optional::Dependencies->req_missing_for('test_rdbms_sqlanywhere_odbc')))
19 unless
20 DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt') && (
21 $dsn && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_sqlanywhere')
22 or
23 $dsn2 && DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_sqlanywhere_odbc'))
24 or (not $dsn || $dsn2);
1125
1226 if (not ($dsn || $dsn2)) {
1327 plan skip_all => <<'EOF';
1630 Warning: This test drops and creates a table called 'event'";
1731 EOF
1832 }
19
20 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
21 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt');
2233
2334 my @info = (
2435 [ $dsn, $user, $pass ],
44 use Test::Exception;
55 use Scope::Guard ();
66 use Try::Tiny;
7 use DBIx::Class::Optional::Dependencies ();
78 use lib qw(t/lib);
89 use DBICTest;
910
10 DBICTest::Schema->load_classes('EventSmallDT');
11 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_dt')
12 . ' and ' .
13 DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_ase')
14 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_dt')
15 && DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_ase');
1116
1217 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SYBASE_${_}" } qw/DSN USER PASS/};
1318
1419 if (not ($dsn && $user)) {
1520 plan skip_all =>
1621 'Set $ENV{DBICTEST_SYBASE_DSN}, _USER and _PASS to run this test' .
17 "\nWarning: This test drops and creates a table called 'track'";
22 "\nWarning: This test drops and creates a table called 'track' and " .
23 "'event_small_dt'";
1824 }
1925
20 plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_rdbms_ase')
21 unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_rdbms_ase');
26 DBICTest::Schema->load_classes('EventSmallDT');
2227
2328 my @storage_types = (
2429 'DBI::Sybase::ASE',
33 use strict;
44 use warnings;
55
6 #use base qw/DBIx::Class::Relationship::Cascade::Rekey DBIx::Class::Core/;
67 use base qw/DBIx::Class::Core/;
78 use DBICTest::BaseResultSet;
89
910 __PACKAGE__->table ('bogus');
1011 __PACKAGE__->resultset_class ('DBICTest::BaseResultSet');
1112
13 #sub add_relationship {
14 # my $self = shift;
15 # my $opts = $_[3] || {};
16 # if (grep { $_ eq $_[0] } qw/
17 # cds_90s cds_80s cds_84 artist_undirected_maps mapped_artists last_track
18 # /) {
19 # # nothing - join-dependent or non-cascadeable relationship
20 # }
21 # elsif ($opts->{is_foreign_key_constraint}) {
22 # $opts->{on_update} ||= 'cascade';
23 # }
24 # else {
25 # $opts->{cascade_rekey} = 1
26 # unless ref $_[2] eq 'CODE';
27 # }
28 # $self->next::method(@_[0..2], $opts);
29 #}
30
1231 1;
0 # belongs to t/86sqlt.t
1 package # hide from PAUSE
2 DBICTest::DeployComponent;
3 use warnings;
4 use strict;
5
6 our $hook_cb;
7
8 sub sqlt_deploy_hook {
9 my $class = shift;
10
11 $hook_cb->($class, @_) if $hook_cb;
12 $class->next::method(@_) if $class->next::can;
13 }
14
15 1;
1111 id => { data_type => 'integer', is_auto_increment => 1 },
1212
1313 # this MUST be 'date' for the Firebird and SQLAnywhere tests
14 starts_at => { data_type => 'date' },
14 starts_at => { data_type => 'date', datetime_undef_if_invalid => 1 },
1515
1616 created_on => { data_type => 'timestamp' },
1717 varchar_date => { data_type => 'varchar', size => 20, is_nullable => 1 },
33 use base qw/DBICTest::BaseResult/;
44 use Carp qw/confess/;
55
6 __PACKAGE__->load_components(qw/InflateColumn::DateTime Ordered/);
6 __PACKAGE__->load_components(qw{
7 +DBICTest::DeployComponent
8 InflateColumn::DateTime
9 Ordered
10 });
711
812 __PACKAGE__->table('track');
913 __PACKAGE__->add_columns(
6468 { join_type => 'left' },
6569 );
6670
67 __PACKAGE__->might_have (
68 next_track => __PACKAGE__,
71 __PACKAGE__->has_many (
72 next_tracks => __PACKAGE__,
6973 sub {
7074 my $args = shift;
7175
8286 "$args->{foreign_alias}.position" => { '>' => { -ident => "$args->{self_alias}.position" } },
8387 },
8488 $args->{self_rowobj} && {
85 "$args->{foreign_alias}.cd" => $args->{self_rowobj}->cd,
86 "$args->{foreign_alias}.position" => { '>' => $args->{self_rowobj}->position },
89 "$args->{foreign_alias}.cd" => $args->{self_rowobj}->get_column('cd'),
90 "$args->{foreign_alias}.position" => { '>' => $args->{self_rowobj}->pos },
8791 }
8892 )
8993 }
9094 );
9195
96 our $hook_cb;
97
98 sub sqlt_deploy_hook {
99 my $class = shift;
100
101 $hook_cb->($class, @_) if $hook_cb;
102 $class->next::method(@_) if $class->next::can;
103 }
104
92105 1;
33 use base qw/DBIx::Class::Schema/;
44
55 no warnings qw/qw/;
6
7 __PACKAGE__->mk_group_accessors(simple => 'custom_attr');
68
79 __PACKAGE__->load_classes(qw/
810 Artist
00 --
11 -- Created by SQL::Translator::Producer::SQLite
2 -- Created on Tue Feb 22 18:42:16 2011
2 -- Created on Sat Jun 11 00:39:51 2011
33 --
44
55 --
6767 hello integer NOT NULL,
6868 goodbye integer NOT NULL,
6969 sensors character(10) NOT NULL,
70 read_count integer,
70 read_count int,
7171 PRIMARY KEY (foo, bar, hello, goodbye)
7272 );
7373
193193 }
194194
195195 my $last_tracks_rs = $schema->resultset('Track')->search (
196 {'next_track.trackid' => undef},
197 { join => 'next_track', order_by => 'me.cd' },
196 {'next_tracks.trackid' => undef},
197 { join => 'next_tracks', order_by => 'me.cd' },
198198 );
199199
200200 is_deeply (
0 use strict;
1 use warnings;
2
3 use Test::More;
4 use Test::Exception;
5 use lib qw(t/lib);
6 use DBICTest;
7 use DBIC::DebugObj;
8 use DBIC::SqlMakerTest;
9
10 my $schema = DBICTest->init_schema();
11
12 $schema->resultset('Artist')->delete;
13 $schema->resultset('CD')->delete;
14
15 my $artist = $schema->resultset("Artist")->create({ artistid => 21, name => 'Michael Jackson', rank => 20 });
16 my $cd = $artist->create_related('cds', { year => 1975, title => 'Compilation from 1975' });
17
18 my ($sql, @bind);
19 local $schema->storage->{debug} = 1;
20 local $schema->storage->{debugobj} = DBIC::DebugObj->new(\$sql, \@bind);
21
22 my $find_cd = $artist->find_related('cds',{title => 'Compilation from 1975'});
23
24 s/^'//, s/'\z// for @bind; # why does DBIC::DebugObj not do this?
25
26 is_same_sql_bind (
27 $sql,
28 \@bind,
29 'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track FROM cd me WHERE ( ( me.artist = ? AND me.title = ? ) ) ORDER BY year ASC',
30 [21, 'Compilation from 1975'],
31 'find_related only uses foreign key condition once',
32 );
33
34 done_testing;
66
77 my $schema = DBICTest->init_schema();
88
9 my $clone = $schema->clone;
10 cmp_ok ($clone->storage, 'eq', $schema->storage, 'Storage copied into new schema (not a new instance)');
9 {
10 my $clone = $schema->clone;
11 cmp_ok ($clone->storage, 'eq', $schema->storage, 'Storage copied into new schema (not a new instance)');
12 }
13
14 {
15 is $schema->custom_attr, undef;
16 my $clone = $schema->clone(custom_attr => 'moo');
17 is $clone->custom_attr, 'moo', 'cloning can change existing attrs';
18 }
19
20 {
21 my $clone = $schema->clone({ custom_attr => 'moo' });
22 is $clone->custom_attr, 'moo', 'cloning can change existing attrs';
23 }
24
1125
1226 done_testing;
179179 );
180180 }
181181
182 {
183 my $subq = $schema->resultset('Owners')->search({
184 'books.owner' => { -ident => 'owner.id' },
185 }, { alias => 'owner', select => ['id'] } )->count_rs;
186
187 my $rs_selectas_rel = $schema->resultset('BooksInLibrary')->search( { -exists => $subq->as_query }, { select => ['id','owner'], rows => 1 } );
188
189 is_same_sql_bind(
190 $rs_selectas_rel->as_query,
191 '(
192 SELECT [id], [owner] FROM (
193 SELECT [id], [owner], ROW_NUMBER() OVER( ) AS [rno__row__index] FROM (
194 SELECT [me].[id], [me].[owner]
195 FROM [books] [me]
196 WHERE ( ( (EXISTS (
197 SELECT COUNT( * ) FROM [owners] [owner] WHERE ( [books].[owner] = [owner].[id] )
198 )) AND [source] = ? ) )
199 ) [me]
200 ) [me] WHERE [rno__row__index] >= ? AND [rno__row__index] <= ?
201 )',
202 [
203 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
204 [ $OFFSET => 1 ],
205 [ $TOTAL => 1 ],
206 ],
207 'Pagination with sub-query in WHERE works'
208 );
209
210 }
211
182212
183213 done_testing;
1717
1818 my $rs = $s->resultset ('CD');
1919
20 is_same_sql_bind (
21 $rs->search ({}, { rows => 1, offset => 3,columns => [
22 { id => 'foo.id' },
23 { 'bar.id' => 'bar.id' },
24 { bleh => \ 'TO_CHAR (foo.womble, "blah")' },
25 ]})->as_query,
26 '(
27 SELECT id, bar__id, bleh
20 for my $test_set (
21 {
22 name => 'Rownum subsel aliasing works correctly',
23 rs => $rs->search_rs(undef, {
24 rows => 1,
25 offset => 3,
26 columns => [
27 { id => 'foo.id' },
28 { 'bar.id' => 'bar.id' },
29 { bleh => \'TO_CHAR (foo.womble, "blah")' },
30 ]
31 }),
32 sql => '(
33 SELECT id, bar__id, bleh
2834 FROM (
2935 SELECT id, bar__id, bleh, ROWNUM rownum__index
30 FROM (
31 SELECT foo.id AS id, bar.id AS bar__id, TO_CHAR(foo.womble, "blah") AS bleh
32 FROM cd me
33 ) me
36 FROM (
37 SELECT foo.id AS id, bar.id AS bar__id, TO_CHAR (foo.womble, "blah") AS bleh
38 FROM cd me
39 ) me
40 ) me WHERE rownum__index BETWEEN ? AND ?
41 )',
42 binds => [
43 [ $OFFSET => 4 ],
44 [ $TOTAL => 4 ],
45 ],
46 }, {
47 name => 'Rownum subsel aliasing works correctly with unique order_by',
48 rs => $rs->search_rs(undef, {
49 rows => 1,
50 offset => 3,
51 columns => [
52 { id => 'foo.id' },
53 { 'bar.id' => 'bar.id' },
54 { bleh => \'TO_CHAR (foo.womble, "blah")' },
55 ],
56 order_by => [qw( artist title )],
57 }),
58 sql => '(
59 SELECT id, bar__id, bleh
60 FROM (
61 SELECT id, bar__id, bleh, ROWNUM rownum__index
62 FROM (
63 SELECT foo.id AS id, bar.id AS bar__id, TO_CHAR(foo.womble, "blah") AS bleh
64 FROM cd me
65 ORDER BY artist, title
66 ) me
3467 WHERE ROWNUM <= ?
3568 ) me
36 WHERE rownum__index >= ?
37 )',
38 [
39 [ $TOTAL => 4 ],
40 [ $OFFSET => 4 ],
41 ],
42 'Rownum subsel aliasing works correctly'
43 );
44
45 is_same_sql_bind (
46 $rs->search ({}, { rows => 2, offset => 3,columns => [
47 { id => 'foo.id' },
48 { 'ends_with_me.id' => 'ends_with_me.id' },
49 ]})->as_query,
50 '(SELECT id, ends_with_me__id
69 WHERE rownum__index >= ?
70 )',
71 binds => [
72 [ $TOTAL => 4 ],
73 [ $OFFSET => 4 ],
74 ],
75 }, {
76 name => 'Rownum subsel aliasing #2 works correctly',
77 rs => $rs->search_rs(undef, {
78 rows => 2,
79 offset => 3,
80 columns => [
81 { id => 'foo.id' },
82 { 'ends_with_me.id' => 'ends_with_me.id' },
83 ]
84 }),
85 sql => '(
86 SELECT id, ends_with_me__id
5187 FROM (
5288 SELECT id, ends_with_me__id, ROWNUM rownum__index
53 FROM (
54 SELECT foo.id AS id, ends_with_me.id AS ends_with_me__id
55 FROM cd me
56 ) me
89 FROM (
90 SELECT foo.id AS id, ends_with_me.id AS ends_with_me__id
91 FROM cd me
92 ) me
93 ) me WHERE rownum__index BETWEEN ? AND ?
94 )',
95 binds => [
96 [ $OFFSET => 4 ],
97 [ $TOTAL => 5 ],
98 ],
99 }, {
100 name => 'Rownum subsel aliasing #2 works correctly with unique order_by',
101 rs => $rs->search_rs(undef, {
102 rows => 2,
103 offset => 3,
104 columns => [
105 { id => 'foo.id' },
106 { 'ends_with_me.id' => 'ends_with_me.id' },
107 ],
108 order_by => [qw( artist title )],
109 }),
110 sql => '(
111 SELECT id, ends_with_me__id
112 FROM (
113 SELECT id, ends_with_me__id, ROWNUM rownum__index
114 FROM (
115 SELECT foo.id AS id, ends_with_me.id AS ends_with_me__id
116 FROM cd me
117 ORDER BY artist, title
118 ) me
57119 WHERE ROWNUM <= ?
58120 ) me
59 WHERE rownum__index >= ?
60 )',
61 [
62 [ $TOTAL => 5 ],
63 [ $OFFSET => 4 ],
64 ],
65 'Rownum subsel aliasing works correctly'
66 );
121 WHERE rownum__index >= ?
122 )',
123 binds => [
124 [ $TOTAL => 5 ],
125 [ $OFFSET => 4 ],
126 ],
127 }
128 ) {
129 is_same_sql_bind(
130 $test_set->{rs}->as_query,
131 $test_set->{sql},
132 $test_set->{binds},
133 $test_set->{name});
134 }
67135
68136 {
69137 my $subq = $s->resultset('Owners')->search({
93161 JOIN owners owner ON owner.id = me.owner
94162 WHERE ( source = ? )
95163 ) me
96 WHERE ROWNUM <= ?
97 ) me
98 WHERE rownum__index >= ?
164 ) me
165 WHERE rownum__index BETWEEN ? AND ?
99166 )',
100167 [
101168 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
102169 => 'Library' ],
170 [ $OFFSET => 4 ],
103171 [ $TOTAL => 5 ],
104 [ $OFFSET => 4 ],
105172 ],
106173
107174 'pagination with subquery works'
124191 );
125192 }
126193
194 {
195 my $subq = $s->resultset('Owners')->search({
196 'books.owner' => { -ident => 'owner.id' },
197 }, { alias => 'owner', select => ['id'] } )->count_rs;
198
199 my $rs_selectas_rel = $s->resultset('BooksInLibrary')->search( { -exists => $subq->as_query }, { select => ['id','owner'], rows => 1 } );
200
201 is_same_sql_bind(
202 $rs_selectas_rel->as_query,
203 '(
204 SELECT id, owner FROM (
205 SELECT id, owner, ROWNUM rownum__index FROM (
206 SELECT me.id, me.owner FROM books me WHERE ( ( (EXISTS (SELECT COUNT( * ) FROM owners owner WHERE ( books.owner = owner.id ))) AND source = ? ) )
207 ) me
208 ) me WHERE rownum__index BETWEEN ? AND ?
209 )',
210 [
211 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
212 [ $OFFSET => 1 ],
213 [ $TOTAL => 1 ],
214 ],
215 'Pagination with sub-query in WHERE works'
216 );
217
218 }
219
127220
128221 done_testing;
252252 );
253253 }
254254
255 {
256 my $subq = $schema->resultset('Owners')->search({
257 'books.owner' => { -ident => 'owner.id' },
258 }, { alias => 'owner', select => ['id'] } )->count_rs;
259
260 my $rs_selectas_rel = $schema->resultset('BooksInLibrary')->search( { -exists => $subq->as_query }, { select => ['id','owner'], rows => 1 } );
261
262 is_same_sql_bind(
263 $rs_selectas_rel->as_query,
264 '(SELECT TOP 1 me.id, me.owner FROM books me WHERE ( ( (EXISTS (SELECT COUNT( * ) FROM owners owner WHERE ( books.owner = owner.id ))) AND source = ? ) ) ORDER BY me.id)',
265 [
266 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
267 ],
268 'Pagination with sub-query in WHERE works'
269 );
270
271 }
272
255273 done_testing;
44 use DBICTest;
55 use DBIC::SqlMakerTest;
66
7 use DBIx::Class::SQLMaker::ACCESS;
7 use DBIx::Class::SQLMaker::ACCESS ();
88
99 my $sa = DBIx::Class::SQLMaker::ACCESS->new;
1010
3535 { "track.cd" => "me.cdid" },
3636 ],
3737 [
38 { "-join_type" => "LEFT", artist => "artist" },
38 { artist => "artist" },
3939 { "artist.artistid" => "me.artist" },
4040 ],
4141 ],
4545 );
4646 is_same_sql_bind(
4747 $sql, \@bind,
48 'SELECT track.title, cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM ((cd me LEFT JOIN track track ON track.cd = me.cdid) LEFT JOIN artist artist ON artist.artistid = me.artist)', [],
49 'two-step join parenthesized'
48 'SELECT track.title, cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM ((cd me LEFT JOIN track track ON track.cd = me.cdid) INNER JOIN artist artist ON artist.artistid = me.artist)', [],
49 'two-step join parenthesized and inner join prepended with INNER'
5050 );
5151
5252 done_testing;
00 use strict;
11 use warnings;
2 no warnings 'once';
23
34 use Test::More;
45 use Test::Exception;
89 use DBIC::SqlMakerTest;
910 use Path::Class qw/file/;
1011
12 BEGIN { delete @ENV{qw(DBIC_TRACE_PROFILE)} }
13
1114 my $schema = DBICTest->init_schema();
15
16 my $lfn = file('t/var/sql.log');
17 unlink $lfn or die $!
18 if -e $lfn;
1219
1320 # make sure we are testing the vanilla debugger and not ::PrettyPrint
1421 $schema->storage->debugobj(DBIx::Class::Storage::Statistics->new);
1522
1623 ok ( $schema->storage->debug(1), 'debug' );
17 $schema->storage->debugfh(file('t/var/sql.log')->openw);
24 $schema->storage->debugfh($lfn->openw);
25 $schema->storage->debugfh->autoflush(1);
26 $schema->resultset('CD')->count;
1827
19 $schema->storage->debugfh->autoflush(1);
20 my $rs = $schema->resultset('CD')->search({});
21 $rs->count();
22
23 my $log = file('t/var/sql.log')->openr;
24 my $line = <$log>;
25 $log->close();
26 like($line, qr/^SELECT COUNT/, 'Log success');
28 my @loglines = $lfn->slurp;
29 is (@loglines, 1, 'one line of log');
30 like($loglines[0], qr/^SELECT COUNT/, 'File log via debugfh success');
2731
2832 $schema->storage->debugfh(undef);
29 $ENV{'DBIC_TRACE'} = '=t/var/foo.log';
30 $rs = $schema->resultset('CD')->search({});
31 $rs->count();
32 $log = file('t/var/foo.log')->openr;
33 $line = <$log>;
34 $log->close();
35 like($line, qr/^SELECT COUNT/, 'Log success');
36 $schema->storage->debugobj->debugfh(undef);
37 delete($ENV{'DBIC_TRACE'});
33
34 {
35 local $ENV{DBIC_TRACE} = "=$lfn";
36 unlink $lfn;
37
38 $schema->resultset('CD')->count;
39
40 my $schema2 = DBICTest->init_schema(no_deploy => 1);
41 $schema2->storage->_do_query('SELECT 1'); # _do_query() logs via standard mechanisms
42
43 my @loglines = $lfn->slurp;
44 is(@loglines, 2, '2 lines of log');
45 like($loglines[0], qr/^SELECT COUNT/, 'Env log from schema1 success');
46 like($loglines[1], qr/^SELECT 1:/, 'Env log from schema2 success');
47
48 $schema->storage->debugobj->debugfh(undef)
49 }
3850
3951 open(STDERRCOPY, '>&STDERR');
40 stat(STDERRCOPY); # nop to get warnings quiet
4152 close(STDERR);
4253 dies_ok {
43 $rs = $schema->resultset('CD')->search({});
44 $rs->count();
54 $schema->resultset('CD')->search({})->count;
4555 } 'Died on closed FH';
4656
4757 open(STDERR, '>&STDERRCOPY');
22
33 use Test::More;
44 use Test::Exception;
5
6 use DBIx::Class::Optional::Dependencies ();
57
68 use lib qw(t/lib);
79 use DBICTest;
1113 SKIP: {
1214 skip "Skipping $type tests without DBICTEST_${type}_DSN", 1
1315 unless $ENV{"DBICTEST_${type}_DSN"};
16
17 if ($type eq 'PG') {
18 skip "skipping Pg tests without dependencies installed", 1
19 unless DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_pg');
20 }
21 elsif ($type eq 'MYSQL') {
22 skip "skipping MySQL tests without dependencies installed", 1
23 unless DBIx::Class::Optional::Dependencies->req_ok_for('test_rdbms_mysql');
24 }
1425
1526 my $schema = DBICTest::Schema->connect (@ENV{map { "DBICTEST_${type}_${_}" } qw/DSN USER PASS/});
1627
22 use Test::More;
33 use Test::Exception;
44 use Data::Dumper::Concise;
5 use Try::Tiny;
56 use lib qw(t/lib);
67 use DBICTest;
78
102103
103104 next unless $dsn;
104105
105 my $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
106 quote_names => 1
107 });
106 my $schema;
107
108 try {
109 $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
110 quote_names => 1
111 });
112 $schema->storage->ensure_connected;
113 1;
114 } || next;
108115
109116 my $expected_quote_char = $expected{$base_class}{quote_char};
110117 my $quote_char_text = dumper($expected_quote_char);
0 use strict;
1 use warnings;
2
3 use Test::More;
4 use lib qw(t/lib);
5 use DBICTest;
6
7 my $schema = DBICTest->init_schema();
8
9 my $new_artist = $schema->resultset('Artist')->create({ name => 'new kid behind the block' });
10
11 # see how many cds do we have, and relink them all to the new guy
12 my $cds = $schema->resultset('CD');
13 my $cds_count = $cds->count;
14 cmp_ok($cds_count, '>', 0, 'have some cds');
15
16 $cds->update_all({ artist => $new_artist });
17
18 is( $new_artist->cds->count, $cds_count, 'All cds properly relinked');
19
20 done_testing;
0 use strict;
1 use warnings;
2
3 use Test::More;
4 use lib qw(t/lib);
5 use DBICTest;
6
7 my $schema = DBICTest->init_schema();
8
9 my $artist = $schema->resultset('Artist')->next;
10
11 is_deeply(
12 [ $artist->id, $artist->ident_condition, $artist->_storage_ident_condition ],
13 [ 1, { artistid => 1 }, { artistid => 1 } ],
14 'Correct identity state of freshly retrieved object',
15 );
16
17 $artist->artistid(888);
18
19 is_deeply(
20 [ $artist->id, $artist->ident_condition, $artist->_storage_ident_condition ],
21 [ 888, { artistid => 888 }, { artistid => 1 } ],
22 'Correct identity state of object with modified PK',
23 );
24
25 $artist->update;
26
27 is_deeply(
28 [ $artist->id, $artist->ident_condition, $artist->_storage_ident_condition ],
29 [ 888, { artistid => 888 }, { artistid => 888 } ],
30 'Correct identity state after storage update',
31 );
32
33 done_testing;