Skip Menu |

This queue is for tickets about the DBIx-Class-Schema-Loader CPAN distribution.

Report information
The Basics
Id: 62648
Status: resolved
Priority: 0/
Queue: DBIx-Class-Schema-Loader

People
Owner: Nobody in particular
Requestors: djh [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.07002
Fixed in: (no value)



Subject: DCSL crashes with some schemas
DBIx::Class::Schema::Loader (DCSL) crashes when processing some schemas that contain columns with names that clash with DBIx::Class methods. A failing test is attached (name-clash-test.pl). The test script creates a SQLite database and then uses DCSL to process it. Once the database has been created, the crash can be reproduced simply by running: dbicdump test::schema 'dbi:SQLite:dbname=name-clash-test.dbfile' The data that causes DCSL to crash is a schema that contains a foreign key column definition 'belongs_to' (it predates DBIC). The same table also has another column that is a foreign key. DCSL emits code that injects a belongs_to relationship called 'belongs_to' into the package and then tries to execute it as though it were the built-in method of the same name. DCSL::Base has a method called _resolve_col_accessor_collisions that notices naming conflicts. But DCSL::RelBuilder doesn't make use of that information. A possible fix would be to make it do so or otherwise make an equivalent check before generating code. But in my view a better solution would be for DCSL to emit warnings about name clashes and not generate code at all. Quietly generating code that isn't going to work even if it doesn't immediately crash, as it does in most cases at present, is not very helpful to the user. A patch for a half-way house that just emits the warnings is also attached. There also needs to be a POD change, probably in the Known Issues section of DBIx::Class::Schema::Loader::Base. Perhaps something like: =head2 Accessor Name Conflicts Because DBIx::Class accessor and relationship methods are in the same class as the meta-methods used to generate them (add_columns() and belongs_to() etc) it is possible although unusual for there to be a conflict between the name of a column in a schema and the name of one of the built-in methods. DBIx::Class::Schema::Loader detects these conflicts and prints warnings. The generated schema is unusable and requires manual editing before use, which must be repeated each time DBIx::Class::Schema::Loader is run. In rare cases, DBIx::Class::Schema::Loader may crash after it has generated the schema. If possible, the recommended solution is to change the name of the column in the database to avoid the conflict. Another question is how to produce a functioning Result class, once one is made aware of the need for customisation. I have found custom_column_info but its POD says "Hook for adding *extra* attributes to the column_info for a column". I have found that I can use it to change existing attributes, specifically 'accessor', so code like that below appears to generate usable classes, even though the replaced accessor name doesn't appear in the generated relationship definition: use DBIx::Class::Schema::Loader qw/ make_schema_at /; sub my_custom_column_info { my ($table_name, $column_name, $column_info) = @_; warn "($table_name, $column_name, $column_info)\n"; if ($column_name eq 'belongs_to') { return { accessor => 'belong_him' }; } } make_schema_at( 'NameClash2::Schema', { debug => 1, dump_directory => '.', custom_column_info => \&my_custom_column_info, }, [ "dbi:SQLite:dbname=$file", '', '', ], ); It's then possible in a script using the generated classes to say $t2_obj->belong_him and get a T1 object in return. Is that a good way to change accessor names or is there a better way? I couldn't find any documentation and am concerned whether it works in all cases and will keep working in the future?
Subject: name-clash-test.pl
#!/usr/bin/perl use strict; use warnings; =head1 NAME name-clash-test.pl - crash DBIx::Class::Schema::Loader when there is a column name that collides with a built-in method name 2010-10-28 =cut my $file = 'name-clash-test.dbfile'; my $ddl1 = ' CREATE TABLE t1 ( id INTEGER PRIMARY KEY, noise TEXT );'; my $ddl2 = ' CREATE TABLE t2 ( id INTEGER PRIMARY KEY, second_foreign_key INTEGER, belongs_to INTEGER, FOREIGN KEY (second_foreign_key) REFERENCES t1(id), FOREIGN KEY (belongs_to) REFERENCES t1(id) );'; my $sql1 = 'INSERT INTO t1 (noise) VALUES ("art of");'; my $sql2 = 'INSERT INTO t2 (belongs_to) VALUES (1);'; unlink $file if -e $file; use DBI; # DBI->trace(1); my $dbh = DBI->connect("dbi:SQLite:dbname=$file", '', '') or die; $dbh->do($ddl1) or die; $dbh->do($ddl2) or die; $dbh->do($sql1) or die; $dbh->do($sql2) or die; $dbh->disconnect or die; use DBIx::Class::Schema::Loader qw/ make_schema_at /; make_schema_at( 'NameClash::Schema', { debug => 1, dump_directory => '.', }, [ "dbi:SQLite:dbname=$file", '', '', ], );
Subject: patch
Download patch
application/octet-stream 1.4k

Message body not shown because it is not plain text.

Fixed in 0.07003 .