better type info for DB2
Rafael Kitover [Mon, 24 May 2010 11:17:25 +0000 (07:17 -0400)]
Changes
TODO
lib/DBIx/Class/Schema/Loader/DBI/DB2.pm
lib/DBIx/Class/Schema/Loader/DBI/Pg.pm
t/13db2_common.t
t/14ora_common.t
t/lib/dbixcsl_common_tests.pm

diff --git a/Changes b/Changes
index 6c286b3..2cd8ff4 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
 Revision history for Perl extension DBIx::Class::Schema::Loader
 
+        - better type info for DB2
+
 0.07000  2010-05-22 23:40:15
         - added qualify_objects option to prepend db_schema to table names
         - fix for negative numeric default values
diff --git a/TODO b/TODO
index bd120ef..ff70b87 100644 (file)
--- a/TODO
+++ b/TODO
@@ -33,7 +33,7 @@
     - add an option to add extra code to Result classes (maybe...)
     - redo in-memory schema as an @INC coderef rather than temp files
     - add option to filter out views
-    - support columns with names like "ro'd p/n"
+    - support columns with names like "ro'd p/n" in MSSQL
 
 - Relationships
    - Re-scan relations/tables after initial relation setup to find
index b996dab..3c4afb2 100644 (file)
@@ -134,11 +134,60 @@ sub _columns_info_for {
             $info->{is_auto_increment} = 1;
         }
 
-        if ((eval { lc ${ $info->{default_value} } }||'') eq 'current timestamp') {
-            ${ $info->{default_value} } = 'current_timestamp';
+        my $data_type = $info->{data_type};
+
+        if ($data_type !~ /^(?:(?:var)?(?:char|graphic)|decimal)\z/i) {
             delete $info->{size};
+        }
+
+        if ($data_type eq 'double') {
+            $info->{data_type} = 'double precision';
+        }
+        elsif ($data_type eq 'decimal') {
+            no warnings 'uninitialized';
+
+            $info->{data_type} = 'numeric';
+
+            my @size = @{ $info->{size} || [] };
+
+            if ($size[0] == 5 && $size[1] == 0) {
+                delete $info->{size};
+            }
+        }
+        elsif ($data_type =~ /^(?:((?:var)?char) \(\) for bit data|(long varchar) for bit data)\z/i) {
+            my $base_type = lc($1 || $2);
+
+            (my $original_type = $data_type) =~ s/[()]+ //;
+
+            $info->{original}{data_type} = $original_type;
+
+            if ($base_type eq 'long varchar') {
+                $info->{data_type} = 'blob';
+            }
+            else {
+                if ($base_type eq 'char') {
+                    $info->{data_type} = 'binary';
+                }
+                elsif ($base_type eq 'varchar') {
+                    $info->{data_type} = 'varbinary';
+                }
+
+                my ($size) = $dbh->selectrow_array(<<'EOF', {}, $self->db_schema, $self->_uc($table), $self->_uc($col));
+SELECT length
+FROM syscat.columns
+WHERE tabschema = ? AND tabname = ? AND colname = ?
+EOF
+
+                $info->{size} = $size if $size;
+            }
+        }
+
+        if ((eval { lc ${ $info->{default_value} } }||'') =~ /^current (date|time(?:stamp)?)\z/i) {
+            my $type = lc($1);
+
+            ${ $info->{default_value} } = 'current_timestamp';
 
-            my $orig_deflt = 'current timestamp';
+            my $orig_deflt = "current $type";
             $info->{original}{default_value} = \$orig_deflt;
         }
     }
index ccf6690..9ec8dee 100644 (file)
@@ -145,6 +145,7 @@ sub _columns_info_for {
         my $data_type = $info->{data_type};
 
         # these types are fixed size
+        # XXX should this be a negative match?
         if ($data_type =~
 /^(?:bigint|int8|bigserial|serial8|boolean|bool|box|bytea|cidr|circle|date|double precision|float8|inet|integer|int|int4|line|lseg|macaddr|money|path|point|polygon|real|float4|smallint|int2|serial|serial4|text)\z/i) {
             delete $info->{size};
index f5f1475..4823d7e 100644 (file)
@@ -16,8 +16,65 @@ my $tester = dbixcsl_common_tests->new(
     preserve_case_mode_is_exclusive => 1,
     quote_char                      => '"',
     data_types => {
-        'timestamp DEFAULT CURRENT TIMESTAMP' => { data_type => 'timestamp', default_value => \'current_timestamp',
-                                                   original => { default_value => \'current timestamp' } },
+        # http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/admin/r0008483.htm
+        #
+        # Numeric Types
+        smallint           => { data_type => 'smallint' },
+        integer            => { data_type => 'integer' },
+        'int'              => { data_type => 'integer' },
+        real               => { data_type => 'real' },
+        'double precision' => { data_type => 'double precision' },
+        double             => { data_type => 'double precision' },
+        float              => { data_type => 'double precision' },
+        'float(24)'        => { data_type => 'real' },
+        'float(25)'        => { data_type => 'double precision' },
+        'float(53)'        => { data_type => 'double precision' },
+        numeric            => { data_type => 'numeric' },
+        decimal            => { data_type => 'numeric' },
+       'numeric(6,3)'     => { data_type => 'numeric', size => [6,3] },
+       'decimal(6,3)'     => { data_type => 'numeric', size => [6,3] },
+
+        # Character String Types
+        char               => { data_type => 'char', size => 1 },
+        'char(3)'          => { data_type => 'char', size => 3 },
+        'varchar(3)'       => { data_type => 'varchar', size => 3 },
+        'long varchar'     => { data_type => 'long varchar' },
+        'clob'             => { data_type => 'clob' },
+
+        # Graphic String Types (double-byte strings)
+        graphic            => { data_type => 'graphic', size => 1 },
+        'graphic(3)'       => { data_type => 'graphic', size => 3 },
+        'vargraphic(3)'    => { data_type => 'vargraphic', size => 3 },
+        'long vargraphic'  => { data_type => 'long vargraphic' },
+        'dbclob'           => { data_type => 'dbclob' },
+
+        # Binary String Types
+        'char for bit data'=> { data_type => 'binary', size => 1, original => { data_type => 'char for bit data' } },
+        'char(3) for bit data'
+                           => { data_type => 'binary', size => 3, original => { data_type => 'char for bit data' } },
+        'varchar(3) for bit data'
+                           => { data_type => 'varbinary', size => 3, original => { data_type => 'varchar for bit data' } },
+        'long varchar for bit data'
+                           => { data_type => 'blob', original => { data_type => 'long varchar for bit data' } },
+        blob               => { data_type => 'blob' },
+
+        # DateTime Types
+        'date'             => { data_type => 'date' },
+        'date default current date'
+                           => { data_type => 'date', default_value => \'current_timestamp',
+                                original => { default_value => \'current date' } },
+        'time'             => { data_type => 'time' },
+        'time default current time'
+                           => { data_type => 'time', default_value => \'current_timestamp',
+                                original => { default_value => \'current time' } },
+        timestamp          => { data_type => 'timestamp' },
+        'timestamp default current timestamp'
+                           => { data_type => 'timestamp', default_value => \'current_timestamp',
+                                original => { default_value => \'current timestamp' } },
+
+        # DATALINK Type
+        # XXX I don't know how to make these
+#        datalink           => { data_type => 'datalink' },
     },
 );
 
index 1232939..294b1e5 100644 (file)
@@ -136,7 +136,7 @@ my $tester = dbixcsl_common_tests->new(
                         'Oracle sequence detection';
                 }
                 else {
-                    skip 1, 'not running common tests';
+                    skip 'not running common tests', 1;
                 }
             }
         },
index af46977..2d76ee0 100644 (file)
@@ -1770,8 +1770,8 @@ sub _custom_column_info {
 }
 
 my %DATA_TYPE_MULTI_TABLE_OVERRIDES = (
-    oracle => qr/\blong\b/,
-    mssql  => qr/\b(?:timestamp|rowversion)\b/,
+    oracle => qr/\blong\b/i,
+    mssql  => qr/\b(?:timestamp|rowversion)\b/i,
 );
 
 sub setup_data_type_tests {
@@ -1784,11 +1784,11 @@ sub setup_data_type_tests {
     # split types into tables based on overrides
     my (@types, @split_off_types, @first_table_types);
     {
-        no warnings 'uninitialized';
+        my $split_off_re = $DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})} || qr/(?!)/;
 
         @types = keys %$types;
-        @split_off_types   = grep  /$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
-        @first_table_types = grep !/$DATA_TYPE_MULTI_TABLE_OVERRIDES{lc($self->{vendor})}/i, @types;
+        @split_off_types   = grep  /$split_off_re/, @types;
+        @first_table_types = grep !/$split_off_re/, @types;
     }
 
     @types = +{ map +($_, $types->{$_}), @first_table_types },