繁体   English   中英

从Oracle移植到Postgres

[英]Porting from Oracle to Postgres

较早之前,我们的托管环境是在Oracle上运行的,但是现在,我们最近改用了postgres。 我相信移植表已经很成功了,因为它已经可以正常工作很长时间了。 我实际上一直在努力移植程序,但由于某种原因无法正常工作。 我浏览了ora2pg的文档部分,但无法破解,我相信这是最后的难题。

我从这个开始,在Oracle中看起来像这样:

create or replace
procedure c_audit(anonymous in boolean, aud_level IN varchar)
AUTHID CURRENT_USER IS 

  script varchar2(32000);
  acc_select varchar(100);
  open_cursor integer;
  returnval integer;
  p_id integer;
  a_id integer;
  p_name varchar2(100);
  a_name varchar2(100);
  v_count integer;
  c_count integer;
  doc_count integer;
  curr_user varchar(100);
begin

for i in (select a.a_name a_name, a.a_id, p.name p_name, p.id p_id, ds.username username
from c_account a
inner join c_pro p on a.a_id = p.a_id
inner join c_dat_ds_xref x on p.id = x.p_id
inner join c_data ds on x.id_datasource = ds.id
inner join c_conntypes ct on x.id_conntype = ct.id_conntype
where ct.typeid = 'CAPTURE'
order by a.a_name, p.name)
LOOP
    curr_user := i.username;
    IF anonymous = true
    THEN
        acc_select := 'select ' || '''' || i.a_id || '''' || ' a_id,' || '''' || i.p_id || '''' || ' p_id';

    ELSE
        acc_select := 'select ' || '''' || i.a_name || '''' || ' a_name,' || '''' || i.p_name || '''' || ' p_name';
    END IF;

    IF upper(aud_level) = 'VERBATIM'
    THEN         
          script:= acc_select || '
        , count(distinct d.document_id) docCount 
        , sum(case when v.document_id is null or v.verbatim_type_value = ''NO_VERBATIM_TEXT'' then 0 else 1 end) VerbCount 
        , sum(case when v.document_id is null then (select to_number(prop_value) verbSize 
                                        from c_properties 
                                        where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                                        and id_pro = 0) else v.credits end) CreditCount 
        from ' || i.username || '.p_document d 
        left outer join ( 
                        select vi.document_id, t.verbatim_type_value 
                        , case when dbms_lob.substr(vi.extracted_original,8) = ''<cbnull>''
                          or t.verbatim_type_value = ''NO_VERBATIM_TEXT''
                                        then coalesce(s2.strucCredit, .25)                            
                                        else ceil(vi.extracted_original_size/coalesce(s.verbSize, 2048)) end credits                          
                        from ' || i.username || '.p_verbatim vi 
                        left outer join ' || i.username || '.pd_verbatim_type t on vi.verbatim_type_id = t.verbatim_type_id
                        , ( 
                                        select to_number(prop_value) verbSize 
                                        from c_properties 
                                        where prop_name = ''METERING.MAXSIZE.VERBATIM'' 
                                        and id_pro = 0 
                        ) s 
                        , ( 
                                        select to_number(prop_value) strucCredit 
                                        from c_properties 
                                        where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                                        and id_pro = 0 
                        ) s2 
        ) v on d.document_id = v.document_id';
    ELSE    
        IF upper(aud_level) = 'DOCUMENT'
        THEN
            script:= acc_select || '
            , count(distinct a.document_id) docCount
            , sum(credits) creditCount
            from (
            select d.document_id, ceil(sum(v.extracted_original_size)/coalesce(s.verbSize,2048)) credits
            from ' || i.username || '.p_document d
            inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
            inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
            , ( 
                            select to_number(prop_value) verbSize 
                            from c_properties 
                            where prop_name = ''METERING.MAXSIZE.VERBATIM'' 
                            and id_pro = 0 
            ) s 
            where t.verbatim_type_value <> ''NO_VERBATIM_TEXT''
            and dbms_lob.substr(v.extracted_original,8) <> ''<cbnull>''
            group by d.document_id, s.verbSize
            union
            select d.document_id, coalesce(s2.strucCredit, .25)
            from ' || i.username || '.p_document d
            , ( 
                            select to_number(prop_value) strucCredit 
                            from c_properties 
                            where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                            and id_pro = 0 
            ) s2 
            where d.document_id not in (select distinct v.document_id from ' || i.username || '.p_verbatim v)
            union 
            select distinct d.document_id, coalesce(s2.strucCredit, .25)
            from ' || i.username || '.p_document d
            inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
            inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
            , ( 
                            select to_number(prop_value) strucCredit 
                            from c_properties 
                            where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                            and id_pro = 0 
            ) s2 
            where (t.verbatim_type_value = ''NO_VERBATIM_TEXT''
            or dbms_lob.substr(v.extracted_original,8) = ''<cbnull>'')
            ) a';
            ELSE
                dbms_output.put_line('Invalid choice for audit level, no audit generated');
                exit;
            END IF;
    END IF;
begin

open_cursor := dbms_sql.open_cursor;
        DBMS_SQL.PARSE(open_cursor, script,
                   DBMS_SQL.NATIVE);
        IF anonymous = true then
            dbms_sql.define_column(open_cursor,1,a_id);
            dbms_sql.define_column(open_cursor,2,p_id);
        else
            dbms_sql.define_column(open_cursor,1,a_name,100);
            dbms_sql.define_column(open_cursor,2,p_name,100);
        end if;
        dbms_sql.define_column(open_cursor,3,doc_count);
        dbms_sql.define_column(open_cursor,4,v_count);
        IF upper(aud_level) = 'VERBATIM' then
            dbms_sql.define_column(open_cursor,5,c_count);
        end if;
        returnval := DBMS_SQL.EXECUTE(open_cursor);
        loop
            if dbms_sql.fetch_rows(open_cursor) > 0 then
                IF anonymous = true then
                    dbms_sql.column_value(open_cursor,1,a_id);
                    dbms_sql.column_value(open_cursor,2,p_id);
                    dbms_sql.column_value(open_cursor,3,doc_count);
                    dbms_sql.column_value(open_cursor,4,v_count);
                    IF upper(aud_level) = 'VERBATIM' then
                        dbms_sql.column_value(open_cursor,5,c_count);
                        dbms_output.put_line(a_id || ',' || p_id || ',' || doc_count || ',' || v_count || ',' || c_count);
                    else
                        dbms_output.put_line(a_id || ',' || p_id || ',' || doc_count || ',' || v_count);
                    end if;
                else
                    dbms_sql.column_value(open_cursor,1,a_name);
                    dbms_sql.column_value(open_cursor,2,p_name);
                    dbms_sql.column_value(open_cursor,3,doc_count);
                    dbms_sql.column_value(open_cursor,4,v_count);
                    IF upper(aud_level) = 'VERBATIM' then
                        dbms_sql.column_value(open_cursor,5,c_count);
                        dbms_output.put_line(a_name || ',' || p_name || ',' || doc_count || ',' || v_count || ',' || c_count);
                    else
                        dbms_output.put_line(a_name || ',' || p_name || ',' || doc_count || ',' || v_count);
                    end if;
                end if;
            else
                exit;
            end if;
        end loop;

        exception 
            when others then
            --dbms_output.put_line('Error occured. Please check if the current user has Select access to table ' || curr_user || '.p_document ' || curr_user || '.p_verbatim ' || curr_user || '.pd_verbatim_type');
      dbms_output.put_line('Error occured. Please login as ' || curr_user || ' and run the following:');
      dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.P_DOCUMENT to ' || user ||';');
      dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.P_VERBATIM to ' || user ||';');
      dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.pd_verbatim_type to ' || user ||';');
end;
end loop;
end;

就语法而言,此过程是否正确?

CREATE OR REPLACE FUNCTION c_audit(anonymous boolean, aud_level text) RETURNS VOID AS $body$
DECLARE
  script text;
  acc_select text;
  returnval integer;
  p_id integer;
  a_id integer;
  i record;
  p_name text;
  a_name text;
  v_count integer;
  c_count integer;
  doc_count integer;
  curr_user text;
BEGIN
for i in (SELECT a.a_name a_name, a.a_id, p.name p_name, p.id p_id, ds.username username
from c_account a
inner join c_pro p on a.a_id = p.a_id
inner join c_dat_ds_xref x on p.id = x.p_id
inner join c_data ds on x.id_datasource = ds.id
inner join c_conntypes ct on x.id_conntype = ct.id_conntype
where ct.typeid = 'CAPTURE'
order by a.a_name, p.name)
LOOP
    curr_user := i.username;
    IF anonymous = true
    THEN
        acc_select := 'SELECT ' || '''' || i.a_id || '''' || ' AccountID,' || '''' || i.p_id || '''' || ' ProjectID';
    ELSE
        acc_select := 'SELECT ' || '''' || i.a_name || '''' || ' AccountName,' || '''' || i.p_name || '''' || ' ProjectName';
    END IF;
    IF upper(aud_level) = 'VERBATIM' 
    THEN         
          script:= acc_select || '
        , count(distinct d.document_id) docCount 
        , sum(case when coalesce(CAST(v.document_id AS text), '') = '' or v.verbatim_type_value = ''NO_VERBATIM_TEXT'' then 0 else 1 end) VerbCount 
        , sum(case when coalesce(CAST(v.document_id AS text), '') = '' then (SELECT to_number(prop_value,''9999.99'') verbSize 
                                        from c_properties 
                                        where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                                        and id_project = 0) else v.credits end) CreditCount 
        from ' || i.username || '.p_document d 
        left outer join ( 
                        SELECT vi.document_id, t.verbatim_type_value 
                        , case when substr(vi.extracted_original,8) = ''<cbnull>''
                          or t.verbatim_type_value = ''NO_VERBATIM_TEXT''
                                        then coalesce(s2.strucCredit, .25)                            
                                        else ceil(vi.extracted_original_size/coalesce(s.verbSize, 2048)) end credits                          
                        from ' || i.username || '.p_verbatim vi 
                        left outer join ' || i.username || '.pd_verbatim_type t on vi.verbatim_type_id = t.verbatim_type_id
                        , ( 
                                        select to_number(prop_value,''9999.99'') verbSize 
                                        from c_properties 
                                        where prop_name = ''METERING.MAXSIZE.VERBATIM'' 
                                        and id_project = 0 
                        ) s 
                        , ( 
                                        select to_number(prop_value,''9999.99'') strucCredit 
                                        from c_properties 
                                        where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                                        and id_project = 0 
                        ) s2 
        ) v on d.document_id = v.document_id';
        SELECT format(script) into script;
    ELSE IF upper(aud_level) = 'DOCUMENT'
        THEN
            script:= acc_select || '
            , count(distinct a.document_id) docCount
            , sum(credits) creditCount
            from (
            SELECT d.document_id, ceil(sum(v.extracted_original_size)/coalesce(s.verbSize,2048)) credits
            from ' || i.username || '.p_document d
            inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
            inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
            , ( 
                            SELECT to_number(prop_value,''9999.99'') verbSize 
                            from c_properties 
                            where prop_name = ''METERING.MAXSIZE.VERBATIM'' 
                            and id_project = 0 
            ) s 
            where t.verbatim_type_value <> ''NO_VERBATIM_TEXT''
            and substr(v.extracted_original,8) <> ''<cbnull>''
            group by d.document_id, s.verbSize
            union
            select d.document_id, coalesce(s2.strucCredit, .25)
            from ' || i.username || '.p_document d
            , ( 
                            select to_number(prop_value,''9999.99'') strucCredit 
                            from c_properties 
                            where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                            and id_project = 0 
            ) s2 
            where d.document_id not in (select distinct v.document_id from ' || i.username || '.p_verbatim v)
            union 
            select distinct d.document_id, coalesce(s2.strucCredit, .25)
            from ' || i.username || '.p_document d
            inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
            inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
            , ( 
                            select to_number(prop_value,''9999.99'') strucCredit 
                            from c_properties 
                            where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
                            and id_project = 0 
            ) s2 
            where (t.verbatim_type_value = ''NO_VERBATIM_TEXT''
            or substr(v.extracted_original,8) = ''<cbnull>'')
            ) a';
            SELECT format(script) into script;
        ELSE
        SELECT format(script) into script;
        exit;
        END IF;
    END IF;
BEGIN
    IF anonymous = true 
    THEN
        IF upper(aud_level) = 'VERBATIM' 
        THEN
            EXECUTE script into a_id, p_id, doc_count, v_count, c_count;
        ELSE
            EXECUTE script into a_id, p_id, doc_count, c_count;
        END IF;
    ELSE
        IF upper(aud_level) = 'VERBATIM'
        THEN
            EXECUTE script into a_name, p_name, doc_count, v_count, c_count;
        ELSE
            EXECUTE script into a_name, p_name, doc_count, c_count;
        END IF;
    END IF;
    GET DIAGNOSTICS returnval := ROW_COUNT;
        LOOP
            IF returnval > 0
            THEN
                IF anonymous = true
                THEN
                    IF upper(aud_level) = 'VERBATIM'
                    THEN
                        SELECT format ('Information %s, %s, %s, %s, %s', a_id, p_id, doc_count, v_count, c_count);
                    ELSE
                        SELECT format ('Information %s, %s, %s, %s', a_id, p_id, doc_count, c_count);
                    END IF;
                ELSE
                    IF upper(aud_level) = 'VERBATIM'
                    THEN
                        SELECT format ('Information %s, %s, %s, %s, %s', a_name, p_name, doc_count, v_count, c_count);
                    ELSE
                        SELECT format ('Information %s, %s, %s, %s', a_name, p_name, doc_count, c_count);
                    END IF;
                END IF;
            ELSE
                EXIT;
            END IF;
        END LOOP;
    EXCEPTION
        WHEN others THEN
          PERFORM format('Error occured. Please login as %s, %s' ,  curr_user ,  ' and run the following:');
          PERFORM format('GRANT SELECT ON %s.P_DOCUMENT to %s', curr_user, user);
          PERFORM format('GRANT SELECT ON %s.P_VERBATIM to %s', curr_user, user);
          PERFORM format('GRANT SELECT ON %s.pd_verbatim_type to %s', curr_user, user);
END;
END LOOP;
END;
$body$
LANGUAGE PLPGSQL
;
ALTER FUNCTION cb_audit(boolean, text) OWNER TO USER;
-- REVOKE ALL ON FUNCTION cb_audit FROM PUBLIC;

我得到的失败错误是-

错误:为RAISE指定了太多参数其中:RAISE处的PL / pgSQL函数“ cb_audit”行145

我发现这是一个很好的链接,用作参考

我相信,对于移植DBMS_OUTPUT.PUT_LINE,RAISE NOTICE应该是正确的方法。 我遇到了另一个错误-格式为-to_number(prop_value,'9999.99'),按照此处提到的语法正确显示,但是由于某种原因,当我切换到to_number(prop_value,''9999.99'')时,我没有收到错误,但不确定为什么会这样,甚至无法正确运行。

Postgres的版本-

x86_64-unknown-linux-gnu上的PostgreSQL 9.1.10,由gcc(GCC)4.4.7 20120313(Red Hat 4.4.7-3)编译,64位

编辑:我实际上试图根据Patrick的建议修改此功能,但由于某种原因,它在屏幕上未显示任何内容。 我在每个脚本的末尾添加了format(),以将该脚本显示为,但它只是执行了代码并显示c_audit和null。 虽然我执行单个子SQL,但它们确实返回了预期的计数和结果。 我有什么想念的吗?

您正在使用两种类型的字符串“ building”:串联|| 运算符和%占位符。 两者都是完全合法的,但是首选使用format()函数 ,因为代码更简洁,PG可以防止在后台进行SQL注入之类的事情。

您得到的错误是您的RAISE NOTICE命令之一与您提供的参数有%差异。 请原谅我没有查找该line 145 ,但是很难找到line 145 通常,您应该像这样重写它们:

RAISE NOTICE format('GRANT SELECT ON %I.pd_verbatim_type to %I', curr_user, user);

%I占位符将SQL标识符作为输入:它不能为NULL ,并且将正确加引号,以避免SQL注入和关键字冲突。 (从您的代码中,我认为curr_user是架构名称, user是角色名称,都是SQL标识符。)

还要注意,PL / pgSQL函数中的PERFORM语句是不返回数据的SELECT语句,但是执行该语句是为了检查副作用,例如断言某些数据的存在。 因此,没有PERFORM权限,请改用GRANT SELECT

在PostgreSQL中引用时,SQL标识符使用双引号,而字符串文字值使用单引号。 to_number()函数肯定需要单引号。

还有几点可以改善您的代码:

(1)像这样的动态查询中的两个子选择...

'select to_number(prop_value,''9999.99'') strucCredit 
 from c_properties
 where prop_name = ''METERING.STRUCT.ONLY.CHARGE'' 
 and id_project = 0'

...是STABLE :您总是得到相同的结果。 不要将它们留在动态SQL中,而是创建两个变量并将结果放在它们中,然后再执行其他操作:

DECLARE
  ...
  verbSize numeric;
  strucCredit numeric;
BEGIN
  SELECT to_number(prop_value,'9999.99') INTO verbSize 
  FROM c_properties 
  WHERE prop_name = 'METERING.MAXSIZE.VERBATIM' AND id_pro = 0;
  SELECT to_number(prop_value,'9999.99') INTO strucCredit 
  FROM c_properties 
  WHERE prop_name = 'METERING.STRUCT.ONLY.CHARGE' AND id_pro = 0;

  ...

然后在动态SQL中使用verbSizestrucCredit 这样,您只需一次查询这些查询,而不是每次迭代都进行几次查询。

(2)所有动态查询都需要GROUP BY 1, 2子句。

(3)子句CASE WHEN coalesce(CAST(v.document_id AS text), '') = '' ...写法应类似于CASE WHEN v.document_id IS NULL ... ,假定v.document_id不能为一个空字符串。

(4)您将RAISE NOTICE语句更改为SELECT format(...) 后一种形式不产生任何输出,请改用RAISE NOTICE format(...)

(5)也重写您的动态SQL以使用format()函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM