Hi Peter,

If you need the full schema files, I could provide a tarball for you. However, 
this is nothing that I would like to see in the mailing list as a whole. It 
would not help most of the people reading this thread...


Am 03.08.2010 um 13:20 schrieb Peter Rabbitson:

> Wolfgang Kinkeldei wrote:
>> Hello,
>> when using subqueries in the 'from' part of a query, sometimes the list of 
>> @bind parameters is not maintained correct. As a simple testcase please find 
>> a primitive subselect enclosed that just does a count with a correlated 
>> subquery.
>> <snip>
>> # a simple counting subquery
>> my $subquery =     $schema->resultset('PersonRole')
>>        ->search( { role_id => 'admin' } ) # 1st bind param
>>        ->count_rs
>>        ->as_query;
>> my @people =     $schema->resultset('Person')
>>        ->search(
>>            {
>>                'me.person_id' => 42, # 2nd bind param
>>            },
>>            {
>>                select => [ $subquery ],
>>                # whatever you join here, @bind gets confused
>>                join => 'person_regions'
>>            })
>>        ->all;
>> <snap>
> 
> 
> All I can say at this point is that the problem lies somewhere in the way
> count_rs processes arguments. However I need to see a *real* world search()
> query to wrap my head around which use-case did I miss when I designed the
> feature. Please provide me with a complete meaningful search()/DBIC_TRACE
> pair, no matter how complex as long as it is complete.

This is the search taken from my project. The points marked like (1), (2), (3) 
contain places where changes make the query work or fail.

A working example omitting bind parameters in the subqueries is this (the 
COUNTing here is done in two different ways but this has no influence of error 
or success):

my $nr_uploads =
    $schema->resultset('Subelement')
      ->search(
          {
              'element.concept_id' => { '=', \'me.concept_id' },
              
              # (1)
              # vanilla SQL works
              'step.flags' => { '~' => \q{E'\\\\mallow_uploads\\\\M'} },
              
              # (1)
              # with bind values here, things get bad
              #'step.flags' => { '~' => '\\mallow_uploads\\M' },
          },
          {
              alias => 'subelement',
              join => ['step', 'element'],
          })
      ->count_rs
      ->as_query;

my $nr_uploads_done =
    $schema->resultset('File')
      ->search(
          {
              'element.concept_id' => { '=', \'me.concept_id' },
              
              # (2)
              # vanilla SQL works
              'file.origin' => { '=' => \q{'satellite'} },
              'file.path' => { '~' => \q{'/A001'} },
              
              # (2)
              ### with bind values here, things get bad.
              ### reason: collecting the binds as 'where' for subselect _AND_ 
as 'from' for main select
              # 'file.origin' => { '=' => 'satellite' },
              # 'file.path' => { '~' => '/A001' },
              ### FIXME: looks we are not interested where the files came from, 
he?
          },
          {
              alias => 'file',
              join => {subelement => ['step', 'element']},
              select => 'count(*)',
              as => 'nr_uploads_done',
          })
      ->as_query;


my $concept_rs =
    $schema->resultset('Concept')
      ->search(
          {
              -not_bool => 'step.is_final',
              'responsibilities.responsibility_kind_id' => 'agency',
              -bool => 'satellites.active',
              'satellites.satellite_id' => 4,
          },
          {
              # (3)
              # when throwing away the joins, things will also work.
              join => [
                'step',
                {responsibilities => {person => {agency => 'satellites'}}},
              ],
              'select' => [
                qw(me.concept_id me.name me.job_no),
                \q{step.name},
                \q{folder_name(me.name || '_' || me.job_no, me.concept_id)},
                $nr_uploads,
                $nr_uploads_done,
              ],
              'as' => [qw(campaign_id name job_no step_name folder_name 
nr_uploads nr_uploads_done)],
          });
          
my @concepts = $concept_rs->all;


SELECT me.concept_id, me.name, me.job_no, step.name, folder_name(me.name || '_' 
|| me.job_no, me.concept_id), (SELECT COUNT( * ) FROM subelement subelement 
JOIN step step ON step.step_id = subelement.step_id JOIN element element ON 
element.element_id = subelement.element_id WHERE ( ( element.concept_id = 
me.concept_id AND step.flags ~ E'\\mallow_uploads\\M' ) )), (SELECT count(*) 
FROM file file LEFT JOIN subelement subelement ON subelement.subelement_id = 
file.subelement_id LEFT JOIN element element ON element.element_id = 
subelement.element_id WHERE ( ( element.concept_id = me.concept_id AND 
file.origin = 'satellite' AND file.path ~ '/A001' ) )) FROM concept me JOIN 
step step ON step.step_id = me.step_id LEFT JOIN responsibility 
responsibilities ON responsibilities.concept_id = me.concept_id LEFT JOIN 
person person ON person.person_id = responsibilities.person_id LEFT JOIN agency 
agency ON agency.agency_id = person.agency_id LEFT JOIN satellite satellites ON 
satellites.agency_id = agency.agency_id WHERE ( ( satellites.active AND (NOT 
step.is_final) AND responsibilities.responsibility_kind_id = ? AND 
satellites.satellite_id = ? ) ): 'agency', '4'


when changing the condition marked (1) to use bind parameters:

my $nr_uploads =
    $schema->resultset('Subelement')
      ->search(
          {
              'element.concept_id' => { '=', \'me.concept_id' },
              
              # (1)
              # vanilla SQL works
              # 'step.flags' => { '~' => \q{E'\\\\mallow_uploads\\\\M'} },
              
              # (1)
              # with bind values here, things get bad
              'step.flags' => { '~' => '\\mallow_uploads\\M' },
          },
          {
              alias => 'subelement',
              join => ['step', 'element'],
          })
      ->count_rs
      ->as_query;

-- remaining part stays the same, the trace displays:

SELECT me.concept_id, me.name, me.job_no, step.name, folder_name(me.name || '_' 
|| me.job_no, me.concept_id), (SELECT COUNT( * ) FROM subelement subelement 
JOIN step step ON step.step_id = subelement.step_id JOIN element element ON 
element.element_id = subelement.element_id WHERE ( ( element.concept_id = 
me.concept_id AND step.flags ~ ? ) )), (SELECT count(*) FROM file file LEFT 
JOIN subelement subelement ON subelement.subelement_id = file.subelement_id 
LEFT JOIN element element ON element.element_id = subelement.element_id WHERE ( 
( element.concept_id = me.concept_id AND file.origin = 'satellite' AND 
file.path ~ '/A001' ) )) FROM concept me JOIN step step ON step.step_id = 
me.step_id LEFT JOIN responsibility responsibilities ON 
responsibilities.concept_id = me.concept_id LEFT JOIN person person ON 
person.person_id = responsibilities.person_id LEFT JOIN agency agency ON 
agency.agency_id = person.agency_id LEFT JOIN satellite satellites ON 
satellites.agency_id = agency.agency_id WHERE ( ( satellites.active AND (NOT 
step.is_final) AND responsibilities.responsibility_kind_id = ? AND 
satellites.satellite_id = ? ) ): '\mallow_uploads\M', '\mallow_uploads\M', 
'agency', '4'
Cannot bind unknown placeholder 4 (4) at 
/Library/Perl/5.10.0/DBIx/Class/Storage/DBI.pm line 1475.


The query part looks absolutely perfect, only the subquery-bind-parameter is 
used too often :-(



Best,

Wolfgang Kinkeldei

-- 

' /\_/\ ' .print[split??,"".(($/=q|Cms)+-03467:;<=|)=~tr!C-z -B! -z!)x
'( o.o )' .$/]->[hex]foreach split qr<>,qq+1ecd039ad65b025b8063475b+||
' > ^ < ' .q<!-- Wolfgang Kinkeldei - mailto:[email protected] -->



_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[email protected]

Reply via email to