root/branches/release-41/lib/MT/ObjectDriver/DDL/SQLite.pm @ 2700

Revision 2700, 6.1 kB (checked in by bchoate, 17 months ago)

Return undef from index_defs when table has no indexes.

  • Property svn:keywords set to Id Revision
Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::ObjectDriver::DDL::SQLite;
8
9use strict;
10use warnings;
11use base qw( MT::ObjectDriver::DDL );
12
13sub index_defs {
14    my $ddl = shift;
15    my ($class) = @_;
16    my $driver = $class->driver;
17    my $dbh = $driver->r_handle;
18    my $field_prefix = $class->datasource;
19    my $table_name = $class->table_name;
20    my $sth = $dbh->prepare(<<SQL)
21SELECT name, sql
22FROM sqlite_master
23WHERE type = "index"
24AND tbl_name="$table_name"
25SQL
26        or return undef;
27    $sth->execute or return undef;
28
29    my $defs = {};
30    while (my $row = $sth->fetchrow_hashref) {
31        my $key = $row->{'name'};
32        next unless $key =~ m/^(mt_)?\Q$field_prefix\E_/;
33        next if $key =~ m/(.+autoindex)/;
34        my $sql = $row->{'sql'}
35            or next;
36
37        $key =~ s/^mt_\Q$field_prefix\E_//;
38        my $cols = [];
39        my $is_unique = 0;
40        my $idx_columns;
41        if ( $sql =~ m/CREATE( UNIQUE)? INDEX (?:.+?) ON $table_name \((.+?)\)/i ) {
42            $is_unique = $1 ? 'unique' eq lc($1) : 0;
43            $idx_columns = $2;
44            for my $col ( split ',', $idx_columns ) {
45                $col =~ s/^\Q$field_prefix\E_//;
46                push @$cols, $col;
47            }
48        }
49        unless ( $is_unique ) {
50            # Check constraints to identify unique index
51            my $sth_tbl = $dbh->prepare(<<TBLSQL);
52SELECT name, sql FROM sqlite_master
53WHERE type = "table" AND name = "$table_name"
54TBLSQL
55            $sth_tbl->execute or next;
56            my $rows_tbl = $sth_tbl->fetchall_hashref('name');
57            $sth_tbl->finish;
58            my $sql_tbl = $rows_tbl->{$table_name}->{'sql'}
59                or next;
60            my $idx_name = $row->{'name'};
61            if ( $sql_tbl =~ m/CONSTRAINT\s+$idx_name\s+UNIQUE\s+\(\s*$idx_columns\s*\)/im ) {
62                $is_unique = 1;
63            }
64        }
65
66        if ( $is_unique ) {
67            $defs->{$key} = { 'unique' => 1, 'columns' => $cols };
68        }
69        else {
70            if ((@$cols == 1) && ($key eq $cols->[0])) {
71                $defs->{$key} = 1;
72            } else {
73                $defs->{$key} = { 'columns' => $cols };
74            }
75        }
76
77    }
78    $sth->finish;
79    return undef unless %$defs;
80
81    return $defs;
82}
83
84sub column_defs {
85    my $ddl = shift; 
86    my ($class) = @_;
87
88    my $driver = $class->driver;
89    my $dbh = $driver->r_handle;
90    my $table_name = $class->table_name;
91    my $field_prefix = $class->datasource;
92    my $props = $class->properties;
93    my $obj_defs = $class->column_defs;
94
95    return undef unless $dbh;
96
97    # Disable RaiseError if set, since the table we're about to describe
98    # may not actually exist (in which case, the return value is undef,
99    # signalling an nonexistent table to the caller).
100    local $dbh->{RaiseError} = 0;
101    my $sth = $dbh->prepare('SELECT * FROM ' . $table_name . ' LIMIT 1')
102        or return undef;
103    $sth->execute or return undef;
104    my $fields = $sth->{'NUM_OF_FIELDS'};
105    my $coltypes = $sth->{'TYPE'};
106    my $name = $sth->{'NAME'};
107    my $null = $sth->{'NULLABLE'};
108    #my $skip_null_checks;
109    #if (!$null || !@$null) {
110    #    $skip_null_checks = 1;
111    #}
112    my $defs = {};
113    foreach (my $col = 0; $col < $fields; $col++) {
114        my $colname = lc $name->[$col];
115        $colname =~ s/^\Q$field_prefix\E_//i;
116        my $coltype = $ddl->db2type($coltypes->[$col]);
117        if ($coltypes->[$col] =~ m/\((\d+)\)/) {
118            $defs->{$colname}{size} = $1;
119        }
120        $defs->{$colname}{type} = $coltype;
121        if ($colname =~ m/_id$/) {
122            $defs->{$colname}{key} = 1;
123        }
124        if ( $coltype eq 'integer' && $defs->{$colname}{key} ) {
125            # with sqlite, integer primary keys auto increment. always.
126            $defs->{$colname}{auto} = 1;
127        }
128        #if ($skip_null_checks) {
129        if ( exists $obj_defs->{$colname} ) {
130            $defs->{$colname}{not_null} = $obj_defs->{$colname}{not_null};
131        }
132        #} else {
133        #    if ( (defined $null->[$col]) && ($null->[$col] == 0) ) {
134        #        $defs->{$colname}{not_null} = 1;
135        #    }
136        #}
137    }
138    $sth->finish;
139    return $defs;
140}
141
142sub db2type {
143    my $ddl = shift;
144    my ($db_type) = @_;
145    $db_type =~ s/\(\d+\)//g;
146    if ($db_type eq 'varchar') {
147        $db_type = 'string';
148    }
149    return $db_type;
150}
151
152sub type2db {
153    my $ddl = shift;
154    my ($def) = @_;
155    my $type = (ref($def) eq 'HASH') ? $def->{type} : $def;
156    if ($type eq 'string') {
157        $type = 'varchar(' . $def->{size} . ')';
158    }
159    return $type;
160}
161
162sub can_add_constraint { 0 }
163
164sub unique_constraint_sql {
165    my $ddl = shift;
166    my ($class) = @_;
167
168    my $table_name = $class->table_name;
169    my $props = $class->properties;
170    my $field_prefix = $class->datasource;
171    my $indexes = $props->{indexes};
172
173    my @stmts;
174    if ($indexes) {
175        # FIXME: Handle possible future primary key tuple case
176        my $pk = $props->{primary_key};
177        foreach my $name (keys %$indexes) {
178            next if $pk && $name eq $pk;
179            if (ref $indexes->{$name} eq 'HASH') {
180                my $idx_info = $indexes->{$name};
181                next unless exists($idx_info->{unique}) && $idx_info->{unique};
182                my $column_list = $idx_info->{columns} || [ $name ];
183                my $columns = '';
184                foreach my $col (@$column_list) {
185                    $columns .= ',' unless $columns eq '';
186                    $columns .= $field_prefix . '_' . $col;
187                }
188                if ($columns) {
189                    push @stmts, "CONSTRAINT ${table_name}_$name UNIQUE ($columns)";
190                }
191            }
192        }
193    }
194    if (@stmts) {
195        return ',' . join("\n", @stmts);
196    }
197    return q();
198}
199
200sub drop_index_sql {
201    my $ddl = shift;
202    my ($class, $key) = @_;
203    my $table_name = $class->table_name;
204
205    my $props = $class->properties;
206    my $indexes = $props->{indexes};
207    return q() unless exists($indexes->{$key});
208
209    return "DROP INDEX ${table_name}_$key";
210}
211
2121;
Note: See TracBrowser for help on using the browser.