从Oracle移植到Postgres

时间:2015-10-03 23:08:45

标签: oracle postgresql

早些时候我们的托管环境是在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指定的参数太多 其中:PL / pgSQL函数“cb_audit”第145行在RAISE

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

我相信对于移植DBMS_OUTPUT.PUT_LINE,RAISE NOTICE应该是正确的方法。我遇到了另一个错误,即 - to_number(prop_value,'9999.99')的格式,根据提到的here的语法显示正确,但出于某种原因我切换到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。虽然我执行单个subsql并且它们确实返回了预期的计数和结果。我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

您正在使用两种类型的字符串&#34;构建&#34;:并置||运算符和%占位符。两者都是完全合法的,但使用format() function是首选,因为代码更清晰,PG在幕后防范诸如SQL-injection之类的内容。

您得到的错误是您的RAISE NOTICE个命令之一与您提供的参数有%个不同之处;请原谅我不要这么做,但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中使用varibale 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()函数。