Description:
Here's a patch which fixes some bugs and enhances some of the various *_info() methods. It does the following:
Improves the TABLE_TYPE value for table_info(). Previously, this was hard-coded to 'TABLE', but since MySQL now supports views, this is no longer
correct. I'm not too thrilled with the _has_views() thing I added, and I suspect there's a better way to get this version info.
Adds primary_key_info(). Once this exists then DBI appears to provide a primary_key() method as well.
I added a new mysql-specific item to the column_info return value, mysql_is_auto_increment. It should be obvious what this does ;)
There's no tests for any of these, but I tested the code with a project I'm working on which makes use of these methods, and it did work.
How to repeat:
Uh, this is silly.
Suggested fix:
diff -ru ../DBD-mysql-4.00.old/lib/DBD/mysql.pm ./lib/DBD/mysql.pm
--- ../DBD-mysql-4.00.old/lib/DBD/mysql.pm 2006-12-28 14:22:31.000000000 -0600
+++ ./lib/DBD/mysql.pm 2006-12-28 14:59:32.000000000 -0600
@@ -183,6 +183,7 @@
package DBD::mysql::db; # ====== DATABASE ======
use strict;
use DBI qw(:sql_types);
+use DBI::Const::GetInfoType;
%DBD::mysql::db::db2ANSI = ("INT" => "INTEGER",
"CHAR" => "CHAR",
@@ -257,14 +258,17 @@
sub table_info ($) {
my $dbh = shift;
- my $sth = $dbh->prepare("SHOW TABLES");
+
+ my $sql = _has_views($dbh) ? 'SHOW FULL TABLES' : 'SHOW TABLES';
+ my $sth = $dbh->prepare($sql);
return undef unless $sth;
if (!$sth->execute()) {
return DBI::set_err($dbh, $sth->err(), $sth->errstr());
}
my @tables;
while (my $ref = $sth->fetchrow_arrayref()) {
- push(@tables, [ undef, undef, $ref->[0], 'TABLE', undef ]);
+ my $type = $ref->[1] && $ref->[1] =~ /view/i ? 'VIEW' : 'TABLE';
+ push(@tables, [ undef, undef, $ref->[0], $type, undef ]);
}
my $dbh2;
if (!($dbh2 = $dbh->{'~dbd_driver~_sponge_dbh'})) {
@@ -283,6 +287,15 @@
}
$sth2;
}
+
+ sub _has_views {
+ my $dbh = shift;
+
+ my ($maj, $min, $point) =
+ $dbh->get_info($GetInfoType{SQL_DBMS_VER}) =~ /(\d+)\.(\d+)\.(\d+)/;
+
+ return 1 if $maj >= 5 && $point >= 1;
+ }
}
sub _ListTables {
@@ -313,7 +326,7 @@
UDT_CAT UDT_SCHEM UDT_NAME DOMAIN_CAT DOMAIN_SCHEM DOMAIN_NAME
SCOPE_CAT SCOPE_SCHEM SCOPE_NAME MAX_CARDINALITY
DTD_IDENTIFIER IS_SELF_REF
- mysql_is_pri_key mysql_type_name mysql_values
+ mysql_is_pri_key mysql_type_name mysql_is_auto_increment mysql_values
);
my %col_info;
@@ -325,6 +338,8 @@
my $type = $row->{type};
$type =~ m/^(\w+)(?:\((.*?)\))?\s*(.*)/;
my $basetype = lc($1);
+ my $typemod = $2;
+ my $attr = $3;
my $info = $col_info{ $row->{field} } = {
TABLE_CAT => $catalog,
@@ -338,15 +353,16 @@
ORDINAL_POSITION => ++$ordinal_pos,
mysql_is_pri_key => ($row->{key} eq 'PRI'),
mysql_type_name => $row->{type},
+ mysql_is_auto_increment => ($row->{extra} =~ /auto_increment/i ? 1 : 0),
};
# This code won't deal with a pathalogical case where a value
# contains a single quote followed by a comma, and doesn't unescape
# any escaped values. But who would use those in an enum or set?
- my @type_params = ($2 && index($2,"'")>=0)
- ? ("$2," =~ /'(.*?)',/g) # assume all are quoted
- : split /,/, $2||''; # no quotes, plain list
- s/''/'/g for @type_params; # undo doubling of quotes
- my @type_attr = split / /, $3||'';
+ my @type_params = ($typemod && index($typemod,"'")>=0)
+ ? ("$typemod," =~ /'(.*?)',/g) # assume all are quoted
+ : split /,/, $typemod||''; # no quotes, plain list
+ s/''/'/g for @type_params; # undo doubling of quotes
+ my @type_attr = split / /, $attr||'';
#warn "$type: $basetype [@type_params] [@type_attr]\n";
$info->{DATA_TYPE} = SQL_VARCHAR();
@@ -433,6 +449,45 @@
return $sth;
}
+sub primary_key_info {
+ my ($dbh, $catalog, $schema, $table) = @_;
+ return $dbh->set_err(1, "primary_key doesn't support table wildcard")
+ if $table !~ /^\w+$/;
+
+ my $table_id = $dbh->quote_identifier($catalog, $schema, $table);
+
+ local $dbh->{FetchHashKeyName} = 'NAME_lc';
+ my $index_sth = $dbh->prepare("SHOW INDEX FROM $table_id");
+ my $index = $dbh->selectall_arrayref($index_sth, { Columns=>{} });
+
+ my @names = qw(
+ TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME
+ KEY_SEQ PK_NAME
+ );
+
+ my @pk_info;
+ for my $row (grep {$_->{key_name} eq 'PRIMARY'} @$index) {
+ push @pk_info, {
+ TABLE_CAT => $catalog,
+ TABLE_SCHEM => $schema,
+ TABLE_NAME => $table,
+ COLUMN_NAME => $row->{column_name},
+ KEY_SEQ => $row->{seq_in_index},
+ PK_NAME => $row->{key_name},
+ };
+ }
+
+ my $sponge = DBI->connect("DBI:Sponge:", '','')
+ or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr");
+ my $sth = $sponge->prepare("column_info $table", {
+ rows => [ map { [ @{$_}{@names} ] } @pk_info ],
+ NUM_OF_FIELDS => scalar @names,
+ NAME => \@names,
+ }) or return $dbh->DBI::set_err($sponge->err(), $sponge->errstr());
+
+ return $sth;
+}
+
Description: Here's a patch which fixes some bugs and enhances some of the various *_info() methods. It does the following: Improves the TABLE_TYPE value for table_info(). Previously, this was hard-coded to 'TABLE', but since MySQL now supports views, this is no longer correct. I'm not too thrilled with the _has_views() thing I added, and I suspect there's a better way to get this version info. Adds primary_key_info(). Once this exists then DBI appears to provide a primary_key() method as well. I added a new mysql-specific item to the column_info return value, mysql_is_auto_increment. It should be obvious what this does ;) There's no tests for any of these, but I tested the code with a project I'm working on which makes use of these methods, and it did work. How to repeat: Uh, this is silly. Suggested fix: diff -ru ../DBD-mysql-4.00.old/lib/DBD/mysql.pm ./lib/DBD/mysql.pm --- ../DBD-mysql-4.00.old/lib/DBD/mysql.pm 2006-12-28 14:22:31.000000000 -0600 +++ ./lib/DBD/mysql.pm 2006-12-28 14:59:32.000000000 -0600 @@ -183,6 +183,7 @@ package DBD::mysql::db; # ====== DATABASE ====== use strict; use DBI qw(:sql_types); +use DBI::Const::GetInfoType; %DBD::mysql::db::db2ANSI = ("INT" => "INTEGER", "CHAR" => "CHAR", @@ -257,14 +258,17 @@ sub table_info ($) { my $dbh = shift; - my $sth = $dbh->prepare("SHOW TABLES"); + + my $sql = _has_views($dbh) ? 'SHOW FULL TABLES' : 'SHOW TABLES'; + my $sth = $dbh->prepare($sql); return undef unless $sth; if (!$sth->execute()) { return DBI::set_err($dbh, $sth->err(), $sth->errstr()); } my @tables; while (my $ref = $sth->fetchrow_arrayref()) { - push(@tables, [ undef, undef, $ref->[0], 'TABLE', undef ]); + my $type = $ref->[1] && $ref->[1] =~ /view/i ? 'VIEW' : 'TABLE'; + push(@tables, [ undef, undef, $ref->[0], $type, undef ]); } my $dbh2; if (!($dbh2 = $dbh->{'~dbd_driver~_sponge_dbh'})) { @@ -283,6 +287,15 @@ } $sth2; } + + sub _has_views { + my $dbh = shift; + + my ($maj, $min, $point) = + $dbh->get_info($GetInfoType{SQL_DBMS_VER}) =~ /(\d+)\.(\d+)\.(\d+)/; + + return 1 if $maj >= 5 && $point >= 1; + } } sub _ListTables { @@ -313,7 +326,7 @@ UDT_CAT UDT_SCHEM UDT_NAME DOMAIN_CAT DOMAIN_SCHEM DOMAIN_NAME SCOPE_CAT SCOPE_SCHEM SCOPE_NAME MAX_CARDINALITY DTD_IDENTIFIER IS_SELF_REF - mysql_is_pri_key mysql_type_name mysql_values + mysql_is_pri_key mysql_type_name mysql_is_auto_increment mysql_values ); my %col_info; @@ -325,6 +338,8 @@ my $type = $row->{type}; $type =~ m/^(\w+)(?:\((.*?)\))?\s*(.*)/; my $basetype = lc($1); + my $typemod = $2; + my $attr = $3; my $info = $col_info{ $row->{field} } = { TABLE_CAT => $catalog, @@ -338,15 +353,16 @@ ORDINAL_POSITION => ++$ordinal_pos, mysql_is_pri_key => ($row->{key} eq 'PRI'), mysql_type_name => $row->{type}, + mysql_is_auto_increment => ($row->{extra} =~ /auto_increment/i ? 1 : 0), }; # This code won't deal with a pathalogical case where a value # contains a single quote followed by a comma, and doesn't unescape # any escaped values. But who would use those in an enum or set? - my @type_params = ($2 && index($2,"'")>=0) - ? ("$2," =~ /'(.*?)',/g) # assume all are quoted - : split /,/, $2||''; # no quotes, plain list - s/''/'/g for @type_params; # undo doubling of quotes - my @type_attr = split / /, $3||''; + my @type_params = ($typemod && index($typemod,"'")>=0) + ? ("$typemod," =~ /'(.*?)',/g) # assume all are quoted + : split /,/, $typemod||''; # no quotes, plain list + s/''/'/g for @type_params; # undo doubling of quotes + my @type_attr = split / /, $attr||''; #warn "$type: $basetype [@type_params] [@type_attr]\n"; $info->{DATA_TYPE} = SQL_VARCHAR(); @@ -433,6 +449,45 @@ return $sth; } +sub primary_key_info { + my ($dbh, $catalog, $schema, $table) = @_; + return $dbh->set_err(1, "primary_key doesn't support table wildcard") + if $table !~ /^\w+$/; + + my $table_id = $dbh->quote_identifier($catalog, $schema, $table); + + local $dbh->{FetchHashKeyName} = 'NAME_lc'; + my $index_sth = $dbh->prepare("SHOW INDEX FROM $table_id"); + my $index = $dbh->selectall_arrayref($index_sth, { Columns=>{} }); + + my @names = qw( + TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME + KEY_SEQ PK_NAME + ); + + my @pk_info; + for my $row (grep {$_->{key_name} eq 'PRIMARY'} @$index) { + push @pk_info, { + TABLE_CAT => $catalog, + TABLE_SCHEM => $schema, + TABLE_NAME => $table, + COLUMN_NAME => $row->{column_name}, + KEY_SEQ => $row->{seq_in_index}, + PK_NAME => $row->{key_name}, + }; + } + + my $sponge = DBI->connect("DBI:Sponge:", '','') + or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); + my $sth = $sponge->prepare("column_info $table", { + rows => [ map { [ @{$_}{@names} ] } @pk_info ], + NUM_OF_FIELDS => scalar @names, + NAME => \@names, + }) or return $dbh->DBI::set_err($sponge->err(), $sponge->errstr()); + + return $sth; +} +