0

我在 AWS SCT 工具的帮助下将 Oracle db 迁移到了 Aurora postgreSQL。所有包和触发器在 PostgreSQL 中都被转换为函数。我的问题是所有名称都用$(美元)符号转换。

例如,Oracle 中的一个包和相关的存储过程pk_audit.sp_get_audit转换为pk_audit$sp_get_audit带有 $ 符号的 postgreSQL。但是,在中间件数据库对象名称是pk_audit.sp_get_audit. 为了尽量减少中间件的工作量,我需要将所有函数pk_audit$sp_get_auditpk_audit.sp_get_audit.

我已经用 $ 符号转换了 1500 多个函数。需要一个脚本来更改所有用户定义的函数名称。我创建了一个脚本来构建更改脚本。

`select a.alter_statement|| replace(a.rename_statement,'$','.')
From
(
SELECT format('ALTER %s %I.%I(%s)'
            , 'FUNCTION'
              ,CONCAT('"',n.nspname,'"') 
            , p.proname
            , pg_catalog.pg_get_function_identity_arguments(p.oid)
             ) AS alter_statement,
             format('RENAME %s %I.%I(%s);'
            , 'TO' 
            , CONCAT('"',n.nspname,'"') 
            , p.proname
            , pg_catalog.pg_get_function_identity_arguments(p.oid)
             ) AS rename_statement
FROM   pg_catalog.pg_proc p
JOIN   pg_catalog.pg_namespace n ON n.oid = p.pronamespace
and     n.nspname = 'my_schema' ORDER  BY 1
) a;`

但结果是抛出错误。请帮忙谢谢

4

3 回答 3

2

尝试这个:

select a.alter_statement|| replace(a.rename_statement,'$','.')
From
(
SELECT format('ALTER FUNCTION %s.%s(%s) '
              ,CONCAT(n.nspname) 
              , p.proname
              , pg_catalog.pg_get_function_identity_arguments(p.oid)
             ) AS alter_statement,
             format('RENAME TO %I'
             ,p.proname
             ) AS rename_statement
FROM   pg_catalog.pg_proc p
JOIN   pg_catalog.pg_namespace n ON n.oid = p.pronamespace
and     n.nspname = 'newschema' ORDER  BY 1
) a;

例子:

select a.alter_statement|| replace(a.rename_statement,'$','.')
From
(
SELECT format('ALTER FUNCTION %s.%s(%s) '
              ,CONCAT(n.nspname) 
              , p.proname
              , pg_catalog.pg_get_function_identity_arguments(p.oid)
             ) AS alter_statement,
             format('RENAME TO %I'
             ,p.proname
             ) AS rename_statement
FROM   pg_catalog.pg_proc p
JOIN   pg_catalog.pg_namespace n ON n.oid = p.pronamespace
and     n.nspname = 'newschema' ORDER  BY 1
) a;
                                    ?column?                                     
---------------------------------------------------------------------------------
 ALTER FUNCTION newschema.package$function(integer) RENAME TO "package.function"
(1 row)
于 2020-04-02T17:35:07.203 回答
1

最简单的解决方案是使用以下\gexec功能psql

SELECT format(
          'ALTER FUNCTION %s RENAME TO %I',
          oid::regprocedure,
          replace(proname, '$', '.')
       )
FROM pg_proc
WHERE pronamespace::regnamespace::text = 'my_schema' \gexec
于 2020-04-03T06:45:39.837 回答
1

这行不通。即使您生成的语句具有有效的语法,它也会失败,除非您为每个 Oracle 包创建了 Postgres 模式。Oracle 包将多个过程收集到一个数据库对象中。不幸的是 Postgres 没有这样的概念,所以包中的每个过程成为一个独立的函数是 Postgres。这会导致名称中超出 $ 的命名结构问题。在 Oracle 中,对package_name.procedure_name的格式引用表示运行包名称中的过程名称,Postgres 中的同一行代码被解释为schema_name.function_name。这就是转换例程将其替换为package_name$procedure_name的原因它仍然是名称相同的有效 Postgres 架构。(取决于翻译后的名称长度;当 package_name + procedure_name + 1 的组合长度超过 Postgres (63) 中的名称长度限制时,翻译例程会做什么?)这方面可能会使整个系统更容易更新中间件. 这只是您的包转换问题的开始。关于什么:

  • 仅在包规范中定义的包级别类型、游标、变量、集合等。
  • 与上述相同,仅在包体中定义,但不在任何过程中。
  • 从生成的 Poatgres 函数中对上述任何一个的引用。
  • Oracle 中包的其他功能不能直接转换为 Postgres。所有这些都必须查看,并且可能需要对 Postgres 函数和中间件中的一个或两个进行修改。因此,基本上运行转换脚本只是转换过程中许多步骤的第一步。

    祝你好运!
    注意:上面提到的过程是指过程和功能。
于 2020-04-02T17:34:51.517 回答