root/branches/release-26/lib/MT/ObjectDriver/DDL/SQLite.pm @ 1174

Revision 1174, 6.0 kB (checked in by bchoate, 23 months ago)

Updated copyright year for source.

  • 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
80    return $defs;
81}
82
83sub column_defs {
84    my $ddl = shift; 
85    my ($class) = @_;
86
87    my $driver = $class->driver;
88    my $dbh = $driver->r_handle;
89    my $table_name = $class->table_name;
90    my $field_prefix = $class->datasource;
91    my $props = $class->properties;
92    my $obj_defs = $class->column_defs;
93
94    return undef unless $dbh;
95
96    # Disable RaiseError if set, since the table we're about to describe
97    # may not actually exist (in which case, the return value is undef,
98    # signalling an nonexistent table to the caller).
99    local $dbh->{RaiseError} = 0;
100    my $sth = $dbh->prepare('SELECT * FROM ' . $table_name . ' LIMIT 1')
101        or return undef;
102    $sth->execute or return undef;
103    my $fields = $sth->{'NUM_OF_FIELDS'};
104    my $coltypes = $sth->{'TYPE'};
105    my $name = $sth->{'NAME'};
106    my $null = $sth->{'NULLABLE'};
107    #my $skip_null_checks;
108    #if (!$null || !@$null) {
109    #    $skip_null_checks = 1;
110    #}
111    my $defs = {};
112    foreach (my $col = 0; $col < $fields; $col++) {
113        my $colname = lc $name->[$col];
114        $colname =~ s/^\Q$field_prefix\E_//i;
115        my $coltype = $ddl->db2type($coltypes->[$col]);
116        if ($coltypes->[$col] =~ m/\((\d+)\)/) {
117            $defs->{$colname}{size} = $1;
118        }
119        $defs->{$colname}{type} = $coltype;
120        if ($colname =~ m/_id$/) {
121            $defs->{$colname}{key} = 1;
122        }
123        if ( $coltype eq 'integer' && $defs->{$colname}{key} ) {
124            # with sqlite, integer primary keys auto increment. always.
125            $defs->{$colname}{auto} = 1;
126        }
127        #if ($skip_null_checks) {
128        if ( exists $obj_defs->{$colname} ) {
129            $defs->{$colname}{not_null} = $obj_defs->{$colname}{not_null};
130        }
131        #} else {
132        #    if ( (defined $null->[$col]) && ($null->[$col] == 0) ) {
133        #        $defs->{$colname}{not_null} = 1;
134        #    }
135        #}
136    }
137    $sth->finish;
138    return $defs;
139}
140
141sub db2type {
142    my $ddl = shift;
143    my ($db_type) = @_;
144    $db_type =~ s/\(\d+\)//g;
145    if ($db_type eq 'varchar') {
146        $db_type = 'string';
147    }
148    return $db_type;
149}
150
151sub type2db {
152    my $ddl = shift;
153    my ($def) = @_;
154    my $type = (ref($def) eq 'HASH') ? $def->{type} : $def;
155    if ($type eq 'string') {
156        $type = 'varchar(' . $def->{size} . ')';
157    }
158    return $type;
159}
160
161sub can_add_constraint { 0 }
162
163sub unique_constraint_sql {
164    my $ddl = shift;
165    my ($class) = @_;
166
167    my $table_name = $class->table_name;
168    my $props = $class->properties;
169    my $field_prefix = $class->datasource;
170    my $indexes = $props->{indexes};
171
172    my @stmts;
173    if ($indexes) {
174        # FIXME: Handle possible future primary key tuple case
175        my $pk = $props->{primary_key};
176        foreach my $name (keys %$indexes) {
177            next if $pk && $name eq $pk;
178            if (ref $indexes->{$name} eq 'HASH') {
179                my $idx_info = $indexes->{$name};
180                next unless exists($idx_info->{unique}) && $idx_info->{unique};
181                my $column_list = $idx_info->{columns} || [ $name ];
182                my $columns = '';
183                foreach my $col (@$column_list) {
184                    $columns .= ',' unless $columns eq '';
185                    $columns .= $field_prefix . '_' . $col;
186                }
187                if ($columns) {
188                    push @stmts, "CONSTRAINT ${table_name}_$name UNIQUE ($columns)";
189                }
190            }
191        }
192    }
193    if (@stmts) {
194        return ',' . join("\n", @stmts);
195    }
196    return q();
197}
198
199sub drop_index_sql {
200    my $ddl = shift;
201    my ($class, $key) = @_;
202    my $table_name = $class->table_name;
203
204    my $props = $class->properties;
205    my $indexes = $props->{indexes};
206    return q() unless exists($indexes->{$key});
207
208    return "DROP INDEX ${table_name}_$key";
209}
210
2111;
Note: See TracBrowser for help on using the browser.