2008-10-23 39 views
5

我有一些代碼需要確保一些數據在插入到數據庫之前在mysql枚舉中。我發現這樣做的最徹底的方法是將下面的代碼:如何在Perl中乾淨地提取MySQL枚舉值?

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; 
} 

我們使用DBIx::Class。當然有更好的方法來完成這個? (請注意,$ table變量來自我們的代碼,而不是來自任何外部來源的,因此沒有安全問題)。

回答

13

沒有必要這麼英勇。使用DBD::mysql一個合理的現代版,哈希通過DBIcolumn info方法返回包含在關鍵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"; 
    } 
    ... 
} 
3

我會說使用Text :: CSV_XS可能是一種矯枉過正,除非你在enums中有逗號這樣的奇怪東西(如果你問我,這是一個壞主意)。我可能會用這個來代替。

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

除此之外,我不認爲有捷徑。

+0

我們確實有非常嚴格的限制,我們試圖按照命名約定進行操作,所以看起來像一個很好的簡化。謝謝! – Ovid 2008-10-23 10:59:18

+0

雖然有一個小小的修正:它將在枚舉中處理逗號,但它不會處理撇號。 – 2008-10-23 11:31:18

0

我花了一天的部分要求#dbix在MagNet的一級渠道上,同樣的問題,並遇到了這個缺乏答案。

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}; 

而且現在我的IRC日誌打我的頭在牆上:

這裏DR,因爲我找到了答案,並沒有其他人似乎都那麼做,我會貼TL下面的成績單
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 :)