使用DBIx :: Class和PostgreSQL复制索引名称

时间:2013-04-16 09:52:18

标签: perl postgresql dbix-class

我有一个现有的MySQL数据库,我正在尝试使用以下步骤迁移到PostgreSQL。数据库非常简单 - 它有一些外键和其他约束,但没有触发器,程序等。

  1. 使用DBIx::Class::Schema::Loader从现有的MySQL数据库中生成一组Result类。
  2. 使用Result类为PostgreSQL生成一组CREATE TABLE语句。
  3. 使用CREATE TABLE运行psql语句来设置表格(我还没有进行数据导入)。
  4. 我使用的脚本如下(删除了凭据和数据库名称):

    #!/usr/bin/perl
    
    use Modern::Perl;
    use DBIx::Class::Schema::Loader qw/ make_schema_at /;
    
    my $dsn = 'dbi:mysql:dbname=database';
    my $user = '';
    my $pass = '';
    
    make_schema_at(
      'MyDB::Schema',
      { debug => 1, dump_directory => './lib' },
      [ $dsn, $user, $pass
      ],
    );
    
    my $schema = MyDB::Schema->connect($dsn, $user, $pass);
    $schema->create_ddl_dir(['PostgreSQL'], '0.1', './', undef, { add_drop_table => 0 });
    

    脚本成功运行,Result类和.sql文件(包含所有CREATE TABLE语句)看起来都像我期望的那样。

    但是,有几个表的slug列在原始MySQL架构中标记为UNIQUE,并在CREATE TABLE语句中生成以下行:

    "slug" character varying(50) NOT NULL,
    CONSTRAINT "slug" UNIQUE ("slug")
    

    当我尝试导入数据时(使用psql < tables.sql),我在每个表后面都会出现以下错误:{/ 1>列之后有一个唯一的slug列:

    NOTICE:  CREATE TABLE / UNIQUE will create implicit index "slug" for table "mytable"
    ERROR:  relation "slug" already exists
    

    我的理解是索引名称在给定数据库中必须是唯一的。我没有MySQL的这个问题,因为我只声明slug VARCHAR(50) NOT NULL UNIQUE而没有指定索引名称。

    有没有办法让DBIx::Class(或SQL::Translatorcreate_ddl_dir函数使用的)在它输出的数据中生成一个唯一的索引名称?我并不特别在意索引的是什么 - 尽管基于表名的东西是明智的。我查看了文档,但是我看不到任何允许这样做的参数。

    我可以在导入.sql文件之前手动编辑每个约束,但是有超过250个表和很多冲突 - 而且每次调整迁移过程并且必须重新生成时我都必须这样做类和SQL。

1 个答案:

答案 0 :(得分:0)

最后,解决此问题的唯一自动方法是使用Perl脚本,通过解析SQL::Translator的输出并追加_$i,强制每个约束名称(以及自动索引)都是唯一的每个名称,每次看到新约束时$i递增。

代码如下 - 假设您将管理架构在STDIN

#!/usr/bin/perl

use Modern::Perl;

my $i = 1;

while (my $line = <>)
{
  if ($line =~ m/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/)
  {    
    my $constraint_name = $1 . '_' . $i;
    my $column_name = $2;

    my $replace_str = 'CONSTRAINT "' . $constraint_name . '" UNIQUE ("' . $column_name . '")';

    $line =~ s/CONSTRAINT\s+"([a-zA-Z_]+)"\s+UNIQUE\s+\("([a-zA-Z_]+)"\)/$replace_str/;
    $i++;
  }

  print $line;
}