root/branches/release-35/lib/MT/ObjectDriver/DDL/mysql.pm @ 1927

Revision 1927, 6.1 kB (checked in by mpaschal, 20 months ago)

Land the new implementation of metadata based on narrow tables
BugzID: 68749

  • 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::mysql;
8
9use strict;
10use warnings;
11use base qw( MT::ObjectDriver::DDL );
12
13sub can_add_column { 1 }
14sub can_drop_column { 1 }
15sub can_alter_column { 1 }
16
17sub index_defs {
18    my $ddl = shift;
19    my ($class) = @_;
20    my $driver = $class->driver;
21    my $dbh = $driver->r_handle;
22    my $field_prefix = $class->datasource;
23    my $table_name = $class->table_name;
24    local $dbh->{RaiseError} = 0;
25    my $sth = $dbh->prepare('SHOW INDEX FROM ' . $table_name)
26        or return undef;
27    $sth->execute or return undef;
28
29    my $bags = {};
30    my $unique = {};
31    while (my $row = $sth->fetchrow_hashref) {
32        my $key = $row->{'Key_name'};
33        next unless $key =~ m/^(mt_)?\Q$field_prefix\E_/;
34        $key = 'mt_' . $key unless $key =~ m/^mt_/;
35
36        my $type = $row->{'Index_type'};
37
38        # ignore fulltext or other unrecognized indexes for now
39        next unless $type eq 'BTREE';
40
41        my $seq = $row->{'Seq_in_index'};
42        my $col = $row->{'Column_name'};
43        my $non_unique = $row->{'Non_unique'};
44        my $null = $row->{'Null'};
45        $key =~ s/^mt_\Q$field_prefix\E_//;
46        $col =~ s/^\Q$field_prefix\E_//;
47        $unique->{$key} = 1 unless $non_unique;
48        my $idx_bag = $bags->{$key} ||= [];
49        $idx_bag->[$seq - 1] = $col;
50    }
51    $sth->finish;
52    if (!%$bags) {
53        return undef;
54    }
55
56    my $defs = {};
57    foreach my $key (keys %$bags) {
58        my $cols = $bags->{$key};
59        if ($unique->{$key}) {
60            $defs->{$key} = { columns => $cols, unique => 1 };
61        }
62        else {
63            if ((@$cols == 1) && ($key eq $cols->[0])) {
64                $defs->{$key} = 1;
65            } else {
66                $defs->{$key} = { columns => $cols };
67            }
68        }
69    }
70
71    return $defs;
72}
73
74sub column_defs {
75    my $ddl = shift; 
76    my ($class) = @_;
77
78    my $driver = $class->driver;
79    my $dbh = $driver->r_handle;
80    my $field_prefix = $class->datasource;
81    my $table_name = $class->table_name;
82
83    # Disable RaiseError if set, since the table we're about to describe
84    # may not actually exist (in which case, the return value is undef,
85    # signalling an nonexistent table to the caller).
86    local $dbh->{RaiseError} = 0;
87    my $sth = $dbh->prepare('describe ' . $table_name) or return undef;
88    $sth->execute or return undef;
89    my $defs = {};
90    while (my $row = $sth->fetchrow_hashref) {
91        my $colname = lc $row->{Field};
92        next if $colname !~ m/^\Q$field_prefix\E_/i;
93        $colname =~ s/^\Q$field_prefix\E_//i;
94        my $coltype = $row->{Type};
95        my ($size) = ($coltype =~ m/(?:var)?char\((\d+)\)/i ? $1 : undef);
96        $coltype = $ddl->db2type($coltype);
97        $defs->{$colname}{type} = $coltype;
98        $defs->{$colname}{auto} = ($row->{Extra} =~ m/auto_increment/i) ? 1 : 0;
99        if (($coltype eq 'string') && $size) {
100            $defs->{$colname}{size} = $size;
101        }
102        if ( !$row->{Null} || $row->{Null} eq 'NO' || ($coltype eq 'timestamp') ) {
103            $defs->{$colname}{not_null} = 1;
104        } else {
105            $defs->{$colname}{not_null} = 0;
106        }
107    }
108    $sth->finish;
109    if (!%$defs) {
110        return undef;
111    }
112    return $defs;
113}
114
115sub db2type {
116    my $ddl = shift;
117    my ($type) = @_;
118    $type = lc $type;
119    $type =~ s/\(.+//;
120    if ($type eq 'int') {
121        return 'integer';
122    } elsif ($type eq 'smallint') {
123        return 'smallint';
124    } elsif ($type eq 'bigint') {
125        return 'bigint';
126    } elsif ($type eq 'mediumint') {
127        return 'integer';
128    } elsif ($type eq 'bigint') {
129        return 'integer';
130    } elsif ($type eq 'varchar') {
131        return 'string';
132    } elsif ($type eq 'varbinary') {
133        return 'string';
134    } elsif ($type eq 'char') {
135        return 'string';
136    } elsif ($type eq 'mediumtext') {
137        return 'text';
138    } elsif ($type eq 'blob') {
139        return 'blob';
140    } elsif ($type eq 'mediumblob') {
141        return 'blob';
142    } elsif ($type eq 'tinyint') {
143        return 'boolean';
144    } elsif ($type eq 'datetime') {
145        return 'datetime';
146    } elsif ($type eq 'timestamp') {
147        return 'timestamp';
148    } elsif ($type eq 'text') {
149        return 'text';
150    } elsif ($type eq 'float') {
151        return 'float';
152    }
153    Carp::croak("undefined type: " . $type);
154}
155
156sub type2db {
157    my $ddl = shift;
158    my ($def) = @_; 
159    return undef if !defined $def;
160    my $type = $def->{type};
161    if ($type eq 'string') {
162        return 'varchar(' . $def->{size} . ')';
163    } elsif ($type eq 'smallint' ) {
164        return 'smallint';
165    } elsif ($type eq 'bigint' ) {
166        return 'bigint';
167    } elsif ($type eq 'boolean') {
168        return 'tinyint';
169    } elsif ($type eq 'datetime') {
170        return 'datetime';
171    } elsif ($type eq 'timestamp') {
172        return 'timestamp';
173    } elsif ($type eq 'integer') {
174        return 'integer';
175    } elsif ($type eq 'blob') {
176        return 'mediumblob';
177    } elsif ($type eq 'text') {
178        return 'mediumtext';
179    } elsif ($type eq 'float') {
180        return 'float';
181    }
182    Carp::croak("undefined type: ". $type);
183}
184
185sub column_sql {
186    my $ddl = shift;
187    my ($class, $name) = @_;
188    my $sql = $ddl->SUPER::column_sql($class, $name);
189    my $def = $class->column_def($name);
190    $sql .= ' auto_increment' if $def->{auto};
191    return $sql;
192}
193
194sub cast_column_sql {
195    my $ddl = shift;
196    my ($class, $name, $from_def) = @_;
197
198    my $def = $class->column_def($name);
199    my $field_prefix = $class->datasource;
200    my %cast_type = (
201        'string' => 'char',
202        'smallint' => 'signed',
203        'bigint' => 'signed',
204        'integer' => 'signed',
205        'blob' => 'binary',
206        'text' => 'char',
207        'datetime' => 'datetime',
208        'timestamp' => 'timestamp',
209        'boolean' => 'signed',
210        'float' => 'signed',
211    );
212    return "CAST(${field_prefix}_$name AS " . $cast_type{$def->{type}} . ')';
213}
214
215sub drop_table_sql {
216    my $ddl = shift;
217    my ($class) = @_;
218    my $table_name = $class->table_name;
219    return "DROP TABLE IF EXISTS $table_name";
220}
221
2221;
Note: See TracBrowser for help on using the browser.