【问题标题】:How do I cleanly extract MySQL enum values in Perl?如何在 Perl 中干净地提取 MySQL 枚举值?
【发布时间】:2010-09-18 18:09:18
【问题描述】:

我有一些代码需要在插入数据库之前确保某些数据在 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 变量来自我们的代码,不是来自任何外部来源。因此,没有安全问题。

【问题讨论】:

    标签: mysql perl enums dbix-class


    【解决方案1】:

    没必要这么英勇。使用相当现代的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";
      }
      ...
    }
    

    【讨论】:

    • 很好:-)。不过,应该有人在明显的地方记录下来。
    • FWIW,我从 Rose::DB::Object 中提取了这个答案,它将内省并自动配置 MySQL 枚举、Postgres 数组列和许多其他此类类型。当 DBD::* 文档不足时,它的代码是一个很好的答案来源。
    • 呃。从 DBD::mysql 3.006 升级到最新版本导致我们的验收测试运行时间增加了 35 分钟(原为 50 分钟)。
    【解决方案2】:

    我会说使用 Text::CSV_XS 可能有点过头了,除非你在枚举中有奇怪的东西,比如逗号(如果你问我,这是个坏主意)。我可能会改用这个。

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

    除此之外,我认为没有捷径。

    【讨论】:

    • 在命名约定方面,我们确实有非常严格的限制,因此这似乎是一个很好的简化。谢谢!
    • 一个小的修正:它将处理枚举中的逗号,但它不会处理撇号。
    【解决方案3】:

    我花了一天的时间在 MagNet 上的 #dbix-class 频道上询问同样的问题,并遇到了这个缺乏答案的问题。由于我找到了答案,而且似乎还没有其他人这样做,所以我将在 TL;DR 下方粘贴成绩单:

    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 日志:

    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 :)
    

    【讨论】:

      猜你喜欢
      • 2016-06-08
      • 2012-07-31
      • 2021-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      相关资源
      最近更新 更多