2008-10-23 34 views
5

Tôi có một số mã cần đảm bảo một số dữ liệu nằm trong một ens mysql trước khi chèn vào cơ sở dữ liệu. Cách sạch nhất mà tôi đã tìm thấy để thực hiện việc này là mã sau:Làm cách nào để trích xuất các giá trị enum của MySQL trong Perl?

sub enum_values { 
    my ($self, $schema, $table, $column) = @_; 

    # don't eval to let the error bubble up 
    my $columns = $schema->storage->dbh->selectrow_hashref(
     "SHOW COLUMNS FROM `$table` like ?", 
     {}, 
     $column 
    ); 

    unless ($columns) { 
     X::Internal::Database::UnknownColumn->throw(
      column => $column, 
      table => $table, 
     ); 
    } 

    my $type = $columns->{Type} or X::Panic->throw(
     details => "Could not determine type for $table.$column", 
    ); 

    unless ($type =~ /\Aenum\((.*)\)\z/) { 
     X::Internal::Database::IncorrectTypeForColumn->throw(
      type_wanted => 'enum', 
      type_found => $type, 
     ); 
    } 
    $type = $1; 

    require Text::CSV_XS; 
    my $csv = Text::CSV_XS->new; 
    $csv->parse($type) or X::Panic->throw(
     details => "Could not parse enum CSV data: ".$csv->error_input, 
    ); 
    return map { /\A'(.*)'\z/; $1 }$csv->fields; 
} 

Chúng tôi đang sử dụng DBIx::Class. Chắc chắn có một cách tốt hơn để hoàn thành điều này? (Lưu ý rằng biến $ table đến từ mã của chúng tôi, không phải là từ bất kỳ nguồn bên ngoài nào. Do đó, không có vấn đề bảo mật).

Trả lời

13

Không cần phải quá anh hùng. Sử dụng một phiên bản một cách hợp lý hiện đại của DBD::mysql, băm được trả về bởi DBI 's column info phương pháp chứa một phiên bản pre-chia của các giá trị enum hợp lệ trong khóa mysql_values:

my $sth = $dbh->column_info(undef, undef, 'mytable', '%'); 

foreach my $col_info ($sth->fetchrow_hashref) 
{ 
    if($col_info->{'TYPE_NAME'} eq 'ENUM') 
    { 
    # The mysql_values key contains a reference to an array of valid enum values 
    print "Valid enum values for $col_info->{'COLUMN_NAME'}: ", 
      join(', ', @{$col_info->{'mysql_values'}}), "\n"; 
    } 
    ... 
} 
+0

Đẹp :-). Một người nào đó nên tài liệu đó ở một nơi rõ ràng mặc dù. –

+0

Tuyệt vời. Cảm ơn nhiều! – Ovid

+0

FWIW, tôi lấy câu trả lời đó ra khỏi Rose :: DB :: Object, nó sẽ tự động tìm kiếm và cấu hình các lược đồ MySQL, các cột mảng Postgres và nhiều loại khác như vậy. Mã của nó là một nguồn giải đáp tốt khi các tài liệu DBD :: * không hoạt động. –

3

Tôi muốn sử dụng Văn bản :: CSV_XS có thể là quá mức cần thiết, trừ khi bạn có những thứ lạ như dấu phẩy trong enums (một ý tưởng tồi nếu bạn hỏi tôi). Tôi có thể sử dụng điều này để thay thế.

my @fields = $type =~/' ([^']+) ' (?:,|\z) /msgx; 

Ngoài ra, tôi không nghĩ có phím tắt.

+0

Chúng tôi có những ràng buộc khá nghiêm ngặt mà chúng tôi cố gắng tuân theo về quy ước đặt tên, để có vẻ như đơn giản hóa tốt đẹp. Cảm ơn! – Ovid

+0

Một sửa chữa nhỏ mặc dù: nó sẽ xử lý một dấu phẩy trong enum, nó sẽ không xử lý một dấu nháy đơn mặc dù. –

0

tôi đã dành một phần của ngày yêu cầu #dbix -class kênh trên trên MagNet cùng một câu hỏi và đi qua này thiếu câu trả lời. Kể từ khi tôi tìm thấy câu trả lời và không ai khác dường như đã làm như vậy, tôi sẽ dán bảng điểm dưới TL; DR đây:

my $cfg = new Config::Simple($rc_file); 
my $mysql = $cfg->get_block('mysql'); 
my $dsn = 
    "DBI:mysql:database=$mysql->{database};". 
    "host=$mysql->{hostname};port=$mysql->{port}"; 

my $schema = 
    DTSS::CDN::Schema->connect($dsn, $mysql->{user}, $mysql->{password}); 

my $valid_enum_values = 
    $schema->source('Cdnurl')->column_info('scheme')->{extra}->{list}; 

Và bây giờ đăng nhập IRC của tôi đập đầu tôi vào tường:

14:40 < cj> is there a cross-platform way to get the valid values of an 
      enum? 
15:11 < cj> it looks like I could add 'InflateColumn::Object::Enum' to the 
      __PACKAGE__->load_components(...) list for tables with enum 
      columns 
15:12 < cj> and then call values() on the enum column 
15:13 < cj> but how do I get dbic-dump to add 
      'InflateColumn::Object::Enum' to 
      __PACKAGE__->load_components(...) for only tables with enum 
      columns? 
15:20 < cj> I guess I could just add it for all tables, since I'm doing 
      the same for InflateColumn::DateTime 
15:39 < cj> hurm... is there a way to get a column without making a 
      request to the db? 
15:40 < cj> I know that we store in the DTSS::CDN::Schema::Result::Cdnurl 
      class all of the information that I need to know about the 
      scheme column before any request is issued 
15:42 <@ilmari> cj: for Pg and mysql Schema::Loader will add the list of 
       valid values to the ->{extra}->{list} column attribute 
15:43 <@ilmari> cj: if you're using some other database that has enums, 
       patches welcome :) 
15:43 <@ilmari> or even just a link to the documentation on how to extract 
       the values 
15:43 <@ilmari> and a willingness to test if it's not a database I have 
       access to 
15:43 < cj> thanks, but I'm using mysql. if I were using sqlite for this 
      project, I'd probably oblige :-) 
15:44 <@ilmari> cj: to add components to only some tables, use 
       result_components_map 
15:44 < cj> and is there a way to get at those attributes without making a 
      query? 
15:45 < cj> can we do $schema->resultset('Cdnurl') without having it issue 
      a query, for instance? 
15:45 <@ilmari> $result_source->column_info('colname')->{extra}->{list} 
15:45 < cj> and $result_source is $schema->resultset('Cdnurl') ? 
15:45 <@ilmari> dbic never issues a query until you start retrieving the 
       results 
15:45 < cj> oh, nice. 
15:46 <@ilmari> $schema->source('Cdnurl') 
15:46 <@ilmari> the result source is where the result set gets the results 
       from when they are needed 
15:47 <@ilmari> names have meanings :) 
Các vấn đề liên quan