Base ResultSet Class Has Heavy Carp For Dinner

Overview

Need to trace a Chain of Actions and associated ResultSets (or parts thereof) in order to track down a DBIC bug. The investigative technique is to create a default_resultset_class in which we override search_rs to get at three things from each of our resultsets

  • @args
  • _resolved_attrs
  • stack backtrace (Carp::longmess)

Configure your DBIC::Schema with a default_resultset_class

One can setup a default ResultSet class for all Result classes by passing a default_resultset_class option to load_nampespaces in their DBIx::Class::Schema subclass as follows

package MyApp::Schema;

use warnings;
use strict;

use parent 'DBIx::Class::Schema';

__PACKAGE__->load_namespaces( default_resultset_class => '+MyApp::Schema::Base::ResultSet' );

1;

Define a search_rs method in the default_resultset_class

Recall here that the goal is to dump certain values and a stacktrace during the chain of resultsets searched.

package MyApp::Schema::Base::ResultSet;
use strict;
use warnings;
use base qw/DBIx::Class::ResultSet/;
use Data::Dumper;
use Method::Signatures::Simple;

BEGIN {
    *DEBUG = $ENV{DEBUG_RS_SEARCH} ? sub () { 1 } : sub () { 0 }
}

if (DEBUG) {
    method search_rs(@args) {

        my $rs = $self->next::method(@args);
        open( OUT, ">>dump.out" ) or die "Can't open dump.out\n";
        print OUT Dumper [
          scalar localtime(),     \@args,
          $self->_resolved_attrsCarp::longmess()
        ];
        close OUT;
        sleep(1);

        return $rs;
    };
}

1;

I chose to write out to a file since the Dumps were rather long an my yakuake terminal was not wanting me to copy easily.

The Error

The work above is to get some details on the following error when requesting a particular URI in my application.

undef error - DBIx::Class::ResultSet::all(): DBI Exception: DBD::Pg::st execute failed: ERROR: table name “admin_section_student_caches” specified more than once [for Statement “SELECT teacher.id, teacher.uses_online, teacher.client_assigned_id FROM people.students2classes me JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id JOIN people.people person ON person.id = student_2.id JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id ) JOIN people.teachers teacher ON teacher.id = student2class.teacher_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY teacher.id, teacher.uses_online, teacher.client_assigned_id ORDER BY teacher.id” with ParamValues: 1=’154’, 2=’4’] at /usr/local/share/perl/5.10.0/Reaction/InterfaceModel/Collection/DBIC/Role/Base.pm line 48

Dump Results

I then touched the file dump.out in my project root, fired up the application (TPRO) and made the request that causes the error. The args, resolved_attrs and full stack backtrace chain looks like:

DBIC 0.08103 Dump


dump.rs.chain.parts.out

DBIC 0.08102 Dump

For comparison here is the Dump from DBIC 8102 which works as desired:

dump.dbic.08102.txt

First Fix Attempt

DBIC Team provided the following attempt at a fix:

--- lib/DBIx/Class/ResultSet.pm(revision 6509)
+++ lib/DBIx/Class/ResultSet.pm(local)
@@ -2437,7 +2437,7 @@
    my $from = $attrs->{from}
    || [ { $attrs->{alias} => $source->from } ];
 
-  my $seen = { %{$attrs->{seen_join}||{}} };
+  my $seen = $attrs->{seen_join} || {};

   # we need to take the prefetch the attrs into account before we

NOTE: It is not a fix

Further Investigation

The SQL code generated by DBIC using the patch above is now proper. Unfortunately the report URI in question has no data. This may now be a Reaction issue. Let’s us first see what exactly is the SQL from the previously work version of DBIC, 8012

Trace the SQL

To get at the good SQL that was run during the URI request under 8012 we set the environment variables DBIC_TRACE and the make the request. We’ll get a Dump of the SQL issued on the database.

export DBIC_TRACE

Working Under = 0.08102

SELECT me.id, me.grade_id, me.year, me.season FROM assessment.administrations me WHERE ( me.id = ? ): '4'
SELECT me.id, me.district_id, me.client_assigned_id, me.is_active FROM organizations.schools me WHERE ( me.id = ? ): '154'                                                                                                          
SELECT me.id, me.username, me.password, me.is_active, me.last_login, me.login_count, me.role_name, me.title_name, me.plain_pass_for_email FROM people.webusers me WHERE ( id = ? ): '94079'                                         
SELECT section.name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY section.name: '154''4'                                                                   
SELECT me.id, me.name FROM assessment.grades me WHERE ( me.id = ? ): '0'                                          
SELECT me.id, me.name, me.address1, me.address2, me.city, me.state, me.zip, me.phone, me.fax, me.website FROM organizations.organizations me WHERE ( me.id = ? ): '154'                                                             
SELECT teacher.id, teacher.uses_online, teacher.client_assigned_id FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY teacher.id, teacher.uses_online, teacher.client_assigned_id ORDER BY teacher.id'154''4'                               
SELECT SUM(CASE section.name WHEN 'Early Literacy' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonemic Awareness' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonics' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Vocabulary' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Comprehension' THEN admin_section_student_caches.percentage_score ELSE 0 END), cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score, student.id, person.first_name, person.last_name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY student.id, person.first_name, person.last_name, cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score ORDER BY cached_admin_scores.percentage_score: '154''4'  

Not Working under version 0.08103+ (0.08103 w/ patch above)



SELECT me.id, me.grade_id, me.year, me.season FROM assessment.administrations me WHERE ( me.id = ? ): '4'
SELECT me.id, me.district_id, me.client_assigned_id, me.is_active FROM organizations.schools me WHERE ( me.id = ? ): '154'                                                                                                          
SELECT me.id, me.username, me.password, me.is_active, me.last_login, me.login_count, me.role_name, me.title_name, me.plain_pass_for_email FROM people.webusers me WHERE ( id = ? ): '94079'                                         
SELECT section.name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY section.name: '154''4'                                                                   
SELECT me.id, me.name FROM assessment.grades me WHERE ( me.id = ? ): '0'                                          
SELECT me.id, me.name, me.address1, me.address2, me.city, me.state, me.zip, me.phone, me.fax, me.website FROM organizations.organizations me WHERE ( me.id = ? ): '154'                                                             
SELECT teacher.id, teacher.uses_online, teacher.client_assigned_id FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_2 ON ( admin_section_student_caches_2.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_2.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_2 ON section_2.id = admin_section_student_caches_2.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY teacher.id, teacher.uses_online, teacher.client_assigned_id ORDER BY teacher.id'154''4'                                            
SELECT SUM(CASE section.name WHEN 'Early Literacy' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonemic Awareness' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonics' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Vocabulary' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Comprehension' THEN admin_section_student_caches.percentage_score ELSE 0 END), cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score, student.id, person.first_name, person.last_name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_2 ON ( admin_section_student_caches_2.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_2.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_2 ON section_2.id = admin_section_student_caches_2.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_3 ON ( admin_section_student_caches_3.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_3.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_3 ON section_3.id = admin_section_student_caches_3.section_id  JOIN people.students student_3 ON student_3.id = cached_admin_scores.student_id  JOIN people.people person_2 ON person_2.id = student_3.id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY student.id, person.first_name, person.last_name, cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score ORDER BY cached_admin_scores.percentage_score: '154''4'

The Diff

This is the Diff between the SQL of DBIC 8012 and 8013+

--- 1.txt    2009-06-04 19:48:55.000000000 -0400
+++ 2.txt    2009-06-04 19:49:16.000000000 -0400
@@ -4,5 +4,5 @@
 SELECT section.name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY section.name: '154', '4'                                                                   
 SELECT me.id, me.name FROM assessment.grades me WHERE ( me.id = ? ): '0'                                          
 SELECT me.id, me.name, me.address1, me.address2, me.city, me.state, me.zip, me.phone, me.fax, me.website FROM organizations.organizations me WHERE ( me.id = ? ): '154'                                                             
-SELECT teacher.id, teacher.uses_online, teacher.client_assigned_id FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY teacher.id, teacher.uses_online, teacher.client_assigned_id ORDER BY teacher.id: '154', '4'                               
-SELECT SUM(CASE section.name WHEN 'Early Literacy' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonemic Awareness' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonics' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Vocabulary' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Comprehension' THEN admin_section_student_caches.percentage_score ELSE 0 END), cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score, student.id, person.first_name, person.last_name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY student.id, person.first_name, person.last_name, cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score ORDER BY cached_admin_scores.percentage_score: '154', '4'  
+SELECT teacher.id, teacher.uses_online, teacher.client_assigned_id FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_2 ON ( admin_section_student_caches_2.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_2.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_2 ON section_2.id = admin_section_student_caches_2.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY teacher.id, teacher.uses_online, teacher.client_assigned_id ORDER BY teacher.id: '154', '4'                                            
+SELECT SUM(CASE section.name WHEN 'Early Literacy' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonemic Awareness' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Phonics' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Vocabulary' THEN admin_section_student_caches.percentage_score ELSE 0 END), SUM(CASE section.name WHEN 'Comprehension' THEN admin_section_student_caches.percentage_score ELSE 0 END), cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score, student.id, person.first_name, person.last_name FROM people.students2classes me  JOIN people.students student ON student.id = me.student_id LEFT JOIN scores.admin_student_cache cached_admin_scores ON cached_admin_scores.student_id = student.id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches ON ( admin_section_student_caches.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches.student_id = cached_admin_scores.student_id )  JOIN assessment.sections section ON section.id = admin_section_student_caches.section_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_2 ON ( admin_section_student_caches_2.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_2.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_2 ON section_2.id = admin_section_student_caches_2.section_id  JOIN people.students student_2 ON student_2.id = cached_admin_scores.student_id  JOIN people.people person ON person.id = student_2.id  JOIN people.students2classes student2class ON ( student2class.admin_id = cached_admin_scores.admin_id AND student2class.student_id = cached_admin_scores.student_id )  JOIN people.teachers teacher ON teacher.id = student2class.teacher_id LEFT JOIN scores.admin_section_student_cache admin_section_student_caches_3 ON ( admin_section_student_caches_3.admin_id = cached_admin_scores.admin_id AND admin_section_student_caches_3.student_id = cached_admin_scores.student_id ) LEFT JOIN assessment.sections section_3 ON section_3.id = admin_section_student_caches_3.section_id  JOIN people.students student_3 ON student_3.id = cached_admin_scores.student_id  JOIN people.people person_2 ON person_2.id = student_3.id WHERE ( ( me.school_id = ? AND me.admin_id = ? ) ) GROUP BY student.id, person.first_name, person.last_name, cached_admin_scores.total_score_in_stanine, cached_admin_scores.percentage_score ORDER BY cached_admin_scores.percentage_score: '154', '4'


My tags:
 
Popular tags:
 
Powered by MojoMojo