From: Carl Franks Date: Thu, 11 May 2006 11:15:07 +0000 (+0000) Subject: mysql support for extended columns_info_for() X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=74be9e2a5982d744df6ace81e5758ef84e96c9b8;p=dbsrgits%2FDBIx-Class-Historic.git mysql support for extended columns_info_for() --- diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 6a85b2c..269683b 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -2162,6 +2162,63 @@ sub sth { $self->dbh_do('_dbh_sth', $sql); # retry over disconnects } +=head1 columns_info_for + +Keys which may be set include: + +=over + +=item C + +=item C + +=item C + +=item C + +=item C For numeric types. + +=item C + +=item C For list types such as C and C, contains +an arrayref of valid values. + +=item C For numeric types, the minimum valid value. + +=item C For numeric types, the maximum valid value. + +=back + +Keys which may be set for various database's features/bugs. + +=over + +=item C When the C is a length, such as the length of +a C field, if this value is true, the length should be measured in +bytes rather than characters. + +=item C When the size is a length, such as the +length of a C field, if this value is true, trailing spaced should be +counted. + +=item C For decimal types which, when positive, +use the byte reserved for the sign to increase the precision by 1. + +For Example: The normal range of C should be C<-999.99> to +C<999.99>. C indicates that the valid range of values +is actually C<-999.99> to C<9999.99>. + +=item C For decimal types which include the sign and +decimal point in the precision length. + +For Example: The normal range of C should be C<-999.99> to +C<999.99>. C indicates that the valid range of values +is actually C<-9.99> to C<99.99>. + +=back + +=cut + sub _dbh_columns_info_for { my ($self, $dbh, $table) = @_; diff --git a/lib/DBIx/Class/Storage/DBI/mysql.pm b/lib/DBIx/Class/Storage/DBI/mysql.pm index 2c49691..745ae66 100644 --- a/lib/DBIx/Class/Storage/DBI/mysql.pm +++ b/lib/DBIx/Class/Storage/DBI/mysql.pm @@ -102,6 +102,128 @@ sub _subq_update_delete { return shift->_per_row_update_delete (@_); } + +sub columns_info_for { + my ($self, $table) = @_; + + my $result; + + if ($self->dbh->can('column_info')) { + my $old_raise_err = $self->dbh->{RaiseError}; + my $old_print_err = $self->dbh->{PrintError}; + $self->dbh->{RaiseError} = 1; + $self->dbh->{PrintError} = 0; + eval { + my $sth = $self->dbh->column_info( undef, undef, $table, '%' ); + $sth->execute(); + while ( my $info = $sth->fetchrow_hashref() ){ + my %column_info; + $column_info{data_type} = $info->{TYPE_NAME}; + $column_info{size} = $info->{COLUMN_SIZE}; + $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0; + $column_info{default_value} = $info->{COLUMN_DEF}; + + my %info = $self->_extract_mysql_specs($info); + $column_info{$_} = $info{$_} for keys %info; + + $result->{$info->{COLUMN_NAME}} = \%column_info; + } + }; + $self->dbh->{RaiseError} = $old_raise_err; + $self->dbh->{PrintError} = $old_print_err; + return {} if $@; + } + + return $result; +} + +sub _extract_mysql_specs { + my ($self, $info) = @_; + + my $basetype = lc($info->{TYPE_NAME}); + my $mysql_type = lc($info->{mysql_type_name}); + my %column_info; + + if ($basetype eq 'char') { + if ($self->dbh->{mysql_serverinfo} < version->new('4.1')) { + $column_info{length_in_bytes} = 1; + } + $column_info{ignore_trailing_spaces} = 1; + } + elsif ($basetype eq 'varchar') { + if ($self->dbh->{mysql_serverinfo} <= version->new('4.1')) { + $column_info{ignore_trailing_spaces} = 1; + } + if ($self->dbh->{mysql_serverinfo} < version->new('4.1')) { + $column_info{length_in_bytes} = 1; + } + } + elsif ($basetype =~ /text$/) { + if ($basetype =~ /blob$/) { + $column_info{length_in_bytes} = 1; + } + elsif ($self->dbh->{mysql_serverinfo} < version->new('4.1')) { + $column_info{length_in_bytes} = 1; + } + } + elsif ($basetype eq 'binary') { + $column_info{ignore_trailing_spaces} = 1; + $column_info{length_in_bytes} = 1; + } + elsif ($basetype eq 'varbinary') { + if ($self->dbh->{mysql_serverinfo} <= version->new('4.1')) { + $column_info{ignore_trailing_spaces} = 1; + } + $column_info{length_in_bytes} = 1; + } + elsif ($basetype =~ /^(enum|set)/) { + $column_info{data_set} = $info->{mysql_values}; + } + elsif ($basetype =~ /int$/) { + if ($mysql_type =~ /unsigned /) { + my %max = ( + tinyint => 2**8 - 1, + smallint => 2**16 - 1, + mediumint => 2**24 - 1, + int => 2**32 - 1, + bigint => 2**64 - 1, + ); + $column_info{is_unsigned} = 1; + $column_info{range_min} = 0; + $column_info{range_max} = $max{$basetype}; + } + else { # not unsigned + my %min = ( + tinyint => - 2**7, + smallint => - 2**15, + mediumint => - 2**23, + int => - 2**31, + bigint => - 2**63, + ); + my %max = ( + tinyint => 2**7 - 1, + smallint => 2**15 - 1, + mediumint => 2**23 - 1, + int => 2**31 - 1, + bigint => 2**63 - 1, + ); + $column_info{range_min} = $min{$basetype}; + $column_info{range_max} = $max{$basetype}; + } + } + elsif ($basetype =~ /^decimal/) { + if ($self->dbh->{mysql_serverinfo} <= version->new('4.1')) { + $column_info{decimal_high_positive} = 1; + } + if ($self->dbh->{mysql_serverinfo} < version->new('3.23')) { + $column_info{decimal_literal_range} = 1; + } + $column_info{decimal_digits} = $info->{DECIMAL_DIGITS}; + } + + return %column_info; +} + 1; =head1 NAME