$self->dbh_do('_dbh_sth', $sql); # retry over disconnects
}
+=head1 columns_info_for
+
+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 _dbh_columns_info_for {
my ($self, $dbh, $table) = @_;
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