{sigh} from this end, it looks like gmail dropped the attachment I should know better than to click Send twice when nothing seems to happen.
please, just apply it, and I can stop spamming the list ;) On 28/03/06, Carl Franks <[EMAIL PROTECTED]> wrote: > /me predicts mst will be annoyed with the number of revisions when he wakes up > > Here's the latest patch! > > I'm going to try and get some live db tests working, and so hopefully > stop with the buggy nonsense. >
Index: lib/DBIx/Class/Storage/DBI.pm =================================================================== --- lib/DBIx/Class/Storage/DBI.pm (revision 1369) +++ lib/DBIx/Class/Storage/DBI.pm (working copy) @@ -529,6 +529,59 @@ Returns database type info for a given table columns. +Keys which may be set include: + +=over + +=item C<data_type> + +=item C<size> + +=item C<default_value> + +=item C<is_nullable> + +=item C<is_unsigned> For numeric types. + +=item C<decimal_digits> + +=item C<data_set> For list types such as C<enum> and C<set>, contains +an arrayref of valid values. + +=item C<range_min> For numeric types, the minimum valid value. + +=item C<range_max> For numeric types, the maximum valid value. + +=back + +Keys which may be set for various database's features/bugs. + +=over + +=item C<length_in_bytes> When the C<size> is a length, such as the length of +a C<text> field, if this value is true, the length should be measured in +bytes rather than characters. + +=item C<ignore_trailing_spaces> When the size is a length, such as the +length of a C<text> field, if this value is true, trailing spaced should be +counted. + +=item C<decimal_high_positive> 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<DECIMAL(5,2)> should be C<-999.99> to +C<999.99>. C<decimal_high_positive> indicates that the valid range of values +is actually C<-999.99> to C<9999.99>. + +=item C<decimal_literal_range> For decimal types which include the sign and +decimal point in the precision length. + +For Example: The normal range of C<DECIMAL(5,2)> should be C<-999.99> to +C<999.99>. C<decimal_literal_range> indicates that the valid range of values +is actually C<-9.99> to C<99.99>. + +=back + =cut sub columns_info_for { Index: lib/DBIx/Class/Storage/DBI/mysql.pm =================================================================== --- lib/DBIx/Class/Storage/DBI/mysql.pm (revision 1369) +++ lib/DBIx/Class/Storage/DBI/mysql.pm (working copy) @@ -2,21 +2,12 @@ use strict; use warnings; +use Carp::Clan qw/^DBIx::Class/; use base qw/DBIx::Class::Storage::DBI/; # __PACKAGE__->load_components(qw/PK::Auto/); -sub last_insert_id { - return $_[0]->_dbh->{mysql_insertid}; -} - -sub sqlt_type { - return 'MySQL'; -} - -1; - =head1 NAME DBIx::Class::Storage::DBI::mysql - Automatic primary key class for MySQL @@ -31,6 +22,206 @@ This class implements autoincrements for MySQL. +=head1 METHODS + +=head2 columns_info_for + +Extends L<DBIx::Class::Storage::DBI/columns_info_for>. + +=cut + +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 (_version_lt($self->dbh->{mysql_serverinfo}, '4.1')) { + $column_info{length_in_bytes} = 1; + } + $column_info{ignore_trailing_spaces} = 1; + } + elsif ($basetype eq 'varchar') { + if (_version_le($self->dbh->{mysql_serverinfo}, '4.1')) { + $column_info{ignore_trailing_spaces} = 1; + } + if (_version_lt($self->dbh->{mysql_serverinfo}, '4.1')) { + $column_info{length_in_bytes} = 1; + } + } + elsif ($basetype =~ /text$/) { + if ($basetype =~ /blob$/) { + $column_info{length_in_bytes} = 1; + } + elsif (_version_lt($self->dbh->{mysql_serverinfo}, '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 (_version_le($self->dbh->{mysql_serverinfo}, '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 (_version_le($self->dbh->{mysql_serverinfo}, '4.1')) { + $column_info{decimal_high_positive} = 1; + } + if (_version_lt($self->dbh->{mysql_serverinfo}, '3.23')) { + $column_info{decimal_literal_range} = 1; + } + $column_info{decimal_digits} = $info->{DECIMAL_DIGITS}; + } + + return %column_info; +} + +sub _version_eq { + my ($x, $y) = @_; + + ($x, $y) = _version_normalize( @_ ); + + return 1 if defined $x && $x eq $y; + return; +} + +sub _version_lt { + my ($x, $y) = @_; + + ($x, $y) = _version_normalize( @_ ); + + return 1 if defined $x && $x lt $y; + return; +} + +sub _version_gt { + my ($x, $y) = @_; + + ($x, $y) = _version_normalize( @_ ); + + return 1 if defined $x && $x gt $y; + return; +} + +sub _version_le { + my ($x, $y) = @_; + + return 1 if _version_lt($x, $y) || _version_eq($x, $y); + return; +} + +sub _version_ge { + my ($x, $y) = @_; + + return 1 if _version_gt($x, $y) || _version_eq($x, $y); + return; +} + +sub _version_normalize { + my ($x, $y) = @_; + + my ($x1, $x2, $x3) = $x =~ /(^\d+)(?:\.(\d+))?(?:\.(\d+))?/ + or return; + + $x2 = 0 if not defined $x2; + $x3 = 0 if not defined $x3; + + $x = sprintf "%03d%03d%03d", $x1, $x2, $x3; + + my ($y1, $y2, $y3) = $y =~ /(^\d+)(?:\.(\d+))?(?:\.(\d+))?/ + or return; + + $y2 = 0 if not defined $y2; + $y3 = 0 if not defined $y3; + + $y = sprintf "%03d%03d%03d", $y1, $y2, $y3; + + return ($x, $y); +} + +sub last_insert_id { + return $_[0]->_dbh->{mysql_insertid}; +} + +sub sqlt_type { + return 'MySQL'; +} + =head1 AUTHORS Matt S. Trout <[EMAIL PROTECTED]> @@ -40,3 +231,5 @@ You may distribute this code under the same terms as Perl itself. =cut + +1;
_______________________________________________ List: http://lists.rawmode.org/cgi-bin/mailman/listinfo/dbix-class Wiki: http://dbix-class.shadowcatsystems.co.uk/ IRC: irc.perl.org#dbix-class SVN: http://dev.catalyst.perl.org/repos/bast/trunk/DBIx-Class/