~ubuntu-branches/debian/squeeze/movabletype-opensource/squeeze

« back to all changes in this revision

Viewing changes to lib/MT/ObjectDriver/Driver/DBI.pm

  • Committer: Bazaar Package Importer
  • Author(s): Dominic Hargreaves
  • Date: 2008-06-13 23:28:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080613232840-ya4jfxv1jgl45a3d
Tags: 4.2~rc2-1
* New upstream release candidate
* Update Standards-Version (no changes)
* Ensure that schema upgrade message is always seen

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
# This program is distributed under the terms of the
3
3
# GNU General Public License, version 2.
4
4
#
5
 
# $Id: DBI.pm 1174 2008-01-08 21:02:50Z bchoate $
 
5
# $Id: DBI.pm 2548 2008-06-11 00:07:58Z bchoate $
6
6
 
7
7
package MT::ObjectDriver::Driver::DBI;
8
8
 
63
63
    );
64
64
}
65
65
 
 
66
sub exist {
 
67
    my $driver = shift;
 
68
    my($class, $terms, $args) = @_;
 
69
 
 
70
    return $driver->_select_aggregate(
 
71
        select   => '1',
 
72
        class    => $class,
 
73
        terms    => $terms,
 
74
        args     => $args,
 
75
        override => {
 
76
                     order  => '',
 
77
                     limit  => 1,
 
78
                     offset => undef,
 
79
                    },
 
80
    );
 
81
}
 
82
 
66
83
sub remove_all {
67
84
    my $driver = shift;
68
85
    my ($class) = @_;
100
117
    $driver->_do_group_by("AVG($avg_column) AS avg_$avg_column", @_);
101
118
}
102
119
 
 
120
sub max_group_by {
 
121
    my $driver = shift;
 
122
    my ($class, $terms, $args) = @_;
 
123
 
 
124
    my $max_column = delete $args->{max};
 
125
    return unless $max_column;
 
126
    $max_column = $driver->_decorate_column_name($class, $max_column);
 
127
    $args->{sort} = "max_$max_column" unless exists $args->{sort};
 
128
    $args->{direction} = 'descend' unless exists $args->{direction};
 
129
    $driver->_do_group_by("MAX($max_column) AS max_$max_column", @_);
 
130
}
 
131
 
103
132
sub _do_group_by {
104
133
    my $driver = shift;
105
134
    my ($agg_func, $class, $terms, $args) = @_;
106
135
    my $props = $class->properties;
107
 
    if ($props->{class_type}) {
108
 
        my $class_col = $props->{class_column};
109
 
        unless ($terms->{$class_col}) {
110
 
            $terms->{$class_col} = $class->class_type;
111
 
        }
112
 
    }
113
 
    if ($args->{no_class}) {
114
 
        delete $terms->{$props->{class_column}};
115
 
        delete $args->{no_class};
116
 
    }
117
 
    my $order = delete $args->{sort};
 
136
    $terms ||= {}; $args ||= {}; # declare these for pre_search to work
 
137
    $class->call_trigger('pre_search', $terms, $args);
 
138
    my $order = delete $args->{sort} || '';
118
139
    my $direction = delete $args->{direction};
 
140
    if ( $order =~ /\sdesc|asc/i ) {
 
141
        my @new_order;
 
142
        while ($order =~ /(?:\s*([\w\s\(\)]+?)\s(desc|asc))/ig) {
 
143
            push @new_order, { column => $1, desc => $2 };
 
144
        }
 
145
        $order = \@new_order if @new_order;
 
146
    }
119
147
    my $limit = exists $args->{limit} ? delete $args->{limit} : undef;
120
148
    my $offset = exists $args->{offset} ? delete $args->{offset} : undef;
121
149
    my $stmt = $driver->prepare_statement($class, $terms, $args);
139
167
    }
140
168
    $stmt->group([ map { { column => $_ } } @group ]);
141
169
 
142
 
    ## Ugly.
 
170
    ## Set statement's ORDER clause if any.
 
171
    if ($order) {
 
172
        if (! ref($order)) {
 
173
            $stmt->order( [ { column => $decorate->($order),
 
174
                desc => ($direction || '') eq 'descend' ? 'DESC' : 'ASC'
 
175
            } ] );
 
176
        } else {
 
177
            my @order;
 
178
            foreach my $ord (@$order) {
 
179
                push @order, {
 
180
                    column => $decorate->($ord->{column}),
 
181
                    desc => $ord->{desc},
 
182
                };
 
183
            }
 
184
            $stmt->order(\@order);
 
185
        }
 
186
    }
 
187
 
143
188
    my $sql = $stmt->as_sql;
144
 
    if ($order) {
145
 
        $sql .= "\nORDER BY " . $decorate->($order);
146
 
        if ($direction) {
147
 
            $sql .= $direction eq 'descend' ? ' DESC' : ' ASC';
148
 
        }
149
 
    }
150
189
 
151
190
    my $dbh = $driver->r_handle;
152
191
    $driver->start_query($sql, $stmt->bind);
153
 
    my $sth = $dbh->prepare_cached($sql) or die $sql;
154
 
    $sth->execute(@{ $stmt->bind }) or die $sql;
 
192
    my $sth = $dbh->prepare_cached($sql);
 
193
    $sth->execute(@{ $stmt->bind });
155
194
 
156
195
    my @bindvars;
157
196
    for (@{ $args->{group} }) {
168
207
        }
169
208
    }
170
209
    my $i = 0;
171
 
    return sub {
 
210
    my $finish = sub {
 
211
        return unless $sth;
 
212
        $sth->finish;
 
213
        $driver->end_query($sth);
 
214
        undef $sth;
 
215
    };
 
216
    my $iter = sub {
172
217
        unless ($sth->fetch && defined $count && (!defined $limit || ($i < $limit))) {
173
218
            $sth->finish;
174
219
            $driver->end_query($sth);
177
222
        my @returnvals = map { $$_ } @bindvars;
178
223
        $i++;
179
224
        return($count, @returnvals);
180
 
    }
 
225
    };
 
226
    return Data::ObjectDriver::Iterator->new($iter, $finish);
181
227
}
182
228
 
183
229
sub _select_aggregate {
194
240
    }
195
241
 
196
242
    ## Convert $terms and $args like we would for a search.
197
 
    my $terms;
 
243
    my $terms = {};
198
244
    if (ref($orig_terms) eq 'HASH') {
199
245
        $terms = { %$orig_terms };
200
246
    } elsif (ref($orig_terms) eq 'ARRAY') {
201
247
        $terms = [ @$orig_terms ];
202
248
    }
203
 
    my $args  = $orig_args  ? { %$orig_args  } : undef;
 
249
    my $args  = $orig_args  ? { %$orig_args  } : {};
204
250
    $class->call_trigger('pre_search', $terms, $args);
205
251
 
206
252
    my $stmt = $driver->prepare_statement($class, $terms, $args);
326
372
            $stmt->add_select($dbcol => $col);
327
373
        }
328
374
 
329
 
        $stmt->from([ $tbl ]);
 
375
        if ( my $alias = $orig_args->{alias} ) {
 
376
            $stmt->from([ "$tbl $alias" ]);
 
377
        }
 
378
        else {
 
379
            $stmt->from([ $tbl ]);
 
380
        }
330
381
 
331
382
        if (defined($terms)) {
332
383
            $stmt->column_mutator(sub {
333
384
                my ($col) = @_;
334
 
                return $dbd->db_column_name($tbl, $col);
 
385
                my $db_col = $dbd->db_column_name($tbl, $col);
 
386
                if ( my $alias = $orig_args->{alias} ) {
 
387
                    $db_col = "$alias.$db_col";
 
388
                }
 
389
                return $db_col;
335
390
            });
336
391
            if (ref $terms eq 'ARRAY') {
337
392
                $stmt->add_complex_where($terms);
347
402
        ## Set statement's ORDER clause if any.
348
403
        if ($args->{sort} || $args->{direction}) {
349
404
            my $order = $args->{sort} || 'id';
350
 
            my $dir = $args->{direction} &&
351
 
                      $args->{direction} eq 'descend' ? 'DESC' : 'ASC';
352
 
            $stmt->order({
353
 
                column => $dbd->db_column_name($tbl, $order),
354
 
                desc   => $dir,
355
 
            });
 
405
            if (! ref($order)) {
 
406
                my $dir = $args->{direction} &&
 
407
                          $args->{direction} eq 'descend' ? 'DESC' : 'ASC';
 
408
                $stmt->order({
 
409
                    column => $dbd->db_column_name($tbl, $order),
 
410
                    desc   => $dir,
 
411
                });
 
412
            } else {
 
413
                my @order;
 
414
                foreach my $ord (@$order) {
 
415
                    push @order, {
 
416
                        column => $dbd->db_column_name($tbl, $ord->{column}),
 
417
                        desc => $ord->{desc},
 
418
                    };
 
419
                }
 
420
                $stmt->order(\@order);
 
421
            }
 
422
        }
 
423
 
 
424
        if ( my $ft_arg = delete $args->{'freetext'} ) {
 
425
            my @columns = map { $dbd->db_column_name($tbl, $_) } @{ $ft_arg->{'columns'} };
 
426
            $stmt->add_freetext_where( \@columns, $ft_arg->{'search_string'} );
356
427
        }
357
428
    }
358
429
    $stmt->limit($args->{limit}) if $args->{limit};
432
503
    if ($start_val) {
433
504
        ## TODO: support complex primary keys
434
505
        my $col = $args->{sort} || $class->primary_key;
435
 
        $col = $driver->_decorate_column_name($class, $col);
 
506
        if (ref $col eq 'ARRAY') {
 
507
            if (ref $col->[0] eq 'HASH') {
 
508
                # complex 'sort' array/hash structure
 
509
                foreach (@$col) {
 
510
                    $_->{column} = $driver->_decorate_column_name($class, $_->{column});
 
511
                }
 
512
            } else {
 
513
                # primary key as array of column names
 
514
                foreach (@$col) {
 
515
                    $_ = $driver->_decorate_column_name($class, $_);
 
516
                }
 
517
            }
 
518
        } else {
 
519
            $col = $driver->_decorate_column_name($class, $col);
 
520
        }
436
521
        my $op = $args->{direction} eq 'descend' ? '<' : '>';
437
522
        $stmt->add_where($col, { value => $start_val, op => $op });
438
523
    }
450
535
        $sql = [ $sql ];
451
536
    }
452
537
    foreach (@$sql) {
453
 
        $dbh->do($_) or return $driver->error($dbh->errstr);
 
538
        $dbh->do($_) or return $driver->last_error;
454
539
    }
455
540
    1;
456
541
}