zoukankan      html  css  js  c++  java
  • [PLSQL]Get the Package Specification, and PLS00231

    比如说我有一个Package,它的specification如下,


    CREATE OR REPLACE 
    PACKAGE PACK_TEST 
    AS 


      
    -- Return a list of the package name in current schema
      function GET_PACKAGE_LIST return T_V30_TABLE PIPELINED;
      
      
    -- Return the package specifiction (procedure/function) in the given package of current schema
      function GET_PACKAGE_SPECIFICATION(V_PACKAGE_IN in varchar2return T_V4000_TABLE PIPELINED;
      
      
    -- The following two procedures are to ease calling from outside databae, like in .NET code.
      procedure GET_PACKAGE_LIST(V_RESULT_IN_OUT in OUT SYS_REFCURSOR);
      
    procedure GET_PACKAGE_SPECIFICATION(V_PACKAGE_IN in varchar2, V_RESULT_IN_OUT in OUT SYS_REFCURSOR); 
      
      
    -- Help function 
      -- (It must be pulbic to be used inside the SQL query inside function GET_PACKAGE_SPECIFICATION, 
      -- otherwise, PLS-00231 will arise!)
      function ARG_TABLE_TO_STRING(V_ARG_TABLE in T_V100_TABLE) return varchar2;
      
    END PACK_TEST;

     现在我想通过执行一条SQL语句,得到这个Package里面包含哪些Function和Procedure, 类似于SQL*Plus的命令 DESC <package_name>


    FUNCTION  GET_PACKAGE_LIST () RETURN T_V30_TABLE                                                                                                                        
    FUNCTION  ARG_TABLE_TO_STRING (V_ARG_TABLE IN T_V100_TABLE) RETURN VARCHAR2                                                                                                  
    FUNCTION  GET_PACKAGE_SPECIFICATION (V_PACKAGE_IN IN VARCHAR2RETURN T_V4000_TABLE                                                                     
    PROCEDURE  GET_PACKAGE_LIST (V_RESULT_IN_OUT IN/OUT REF CURSOR)                                                                                                                                                                               
    PROCEDURE  GET_PACKAGE_SPECIFICATION (V_PACKAGE_IN IN VARCHAR2, V_RESULT_IN_OUT IN/OUT REF CURSOR

     其实思路很简单,只要从数据字典视图里面选择需要的数据,然后进行相应的格式化就OK了。下面就是GET_PACKAGE_SPECIFICATION的代码,


     
    function GET_PACKAGE_SPECIFICATION(V_PACKAGE_IN in varchar2return T_V4000_TABLE PIPELINED AS
      
    begin
          
    for REC in 
          (
            
    select 
               T.SUBPROGRAM_TYPE 
    || ' ' ||
               T.SUBPROGRAM_NAME 
    || ' ' ||
               
    ARG_TABLE_TO_STRING(cast(collect(T.ARGUMENT) as T_V100_TABLE)) || ' ' ||
               t.return_caluse  
    as subprogram_spec
            
    from 
            (
            
    select 
                 
    case FIRST_VALUE(POSITION)over(partition by SUBPROGRAM_ID order by sequence) when 0 then 'FUNCTION ' else 'PROCEDURE 'end as SUBPROGRAM_TYPE,
                 
    OBJECT_NAME as SUBPROGRAM_NAME,
                 
    case when ARGUMENT_NAME is not null then ARGUMENT_NAME || ' ' || IN_OUT || ' ' || (case DATA_TYPE when 'TABLE' then TYPE_NAME else DATA_TYPE endend as ARGUMENT,
                 FIRST_VALUE(
    case POSITION when 0 then 'RETURN ' || (case DATA_TYPE when 'TABLE' then TYPE_NAME else DATA_TYPE endendover(partition by subprogram_id order by sequence) as return_caluse
            
    from  USER_ARGUMENTS
            
    where PACKAGE_NAME = V_PACKAGE_IN
            ) t
            
    group by 
             T.SUBPROGRAM_TYPE,
             T.SUBPROGRAM_NAME,
             T.RETURN_CALUSE
         )
         LOOP
           
    pipe row (rec.subprogram_spec);
         
    end LOOP;
         
    return;
      
    end GET_PACKAGE_SPECIFICATION;

     我是从USER_ARGUMENTS里面进行数据查询,然后通过分析函数FIRST_VALUE, 10g新增加的collect聚集函数来进行“格式化”。 

    这里面遇到的一个问题是通过调用function ARG_TABLE_TO_STRING 来把collect函数返回的collection变成字符串。也就是ARG_TABLE_TO_STRING


    function ARG_TABLE_TO_STRING(V_ARG_TABLE in T_V100_TABLE) return varchar2
      
    is 
        V_RETURN 
    varchar2(4000) := '(';
        
        
    -- In case the string length is larger than 4000
        STRING_BUFFER_TOO_SMALL exception;
        
    pragma EXCEPTION_INIT(STRING_BUFFER_TOO_SMALL, -06502);
      
    begin
        
        
    for IDX in 1..V_ARG_TABLE.count
        LOOP
          v_return :
    = v_return || V_ARG_TABLE(IDX) || '';
        
    end LOOP;

        v_return :
    = RTRIM(v_return, ''|| ')';
        
        
    return v_return;
      EXCEPTION
         
    when STRING_BUFFER_TOO_SMALL then
             V_RETURN :
    =  SUBSTR(V_RETURN, 14000 - 5|| ' ...)';
             
    return v_return;
      
    end ARG_TABLE_TO_STRING;

     因为这个函数只是在包的内部调用,因此理应该把这个function私有化,但是这样的话在compile的时候会遇到PLS-00231 的问题。关于这个问题,在这里有很好的讨论解释。 

    造成这个问题的原因是因为我是在SQL语句里面调用这个PL/SQL函数的,因为SQL语句和PL/SQL函数是通过不同的engine(SQL  engine 和 PL/SQL engine) 来解析执行的,因此在SQL语句中执行的FUNCTION必须是public的,这样SQL engine才能访问的。 解决这个问题的方法要么就是将function 公有化,即放在package specification中,或者把function的调用改成PL/SQL代码,不是放在SQL语句中。所以要具体情况具体分析,这里我是选择了前者。

    调用函数GET_PACKAGE_SPECIFICATION就很简单了,直接用一条SQL语句就OK了,


    select * from table(PACK_TEST.GET_PACKAGE_SPECIFICATION('PACK_TEST'));

    总结下:

     1) USR_ARGUMENTS

       2)     Table function / Pipelined

       3)     COLLECT function

       4)     PLS-00231 




    --------------------------------------
    Regards,
    FangwenYu
  • 相关阅读:
    POSTMAN使用教程
    RocketMQ搭建-WEB集成RMQ-SE集成RMQ
    android studio 低版本升级高版本的问题
    SqlServer 2015修改表时出现“save changes is not permitted…”的解决方法
    MATLAB
    新的学习,加油!
    BAK文件怎么恢复到数据库中
    Go语言基础之包
    Go语言基础之文件操作
    python获取多线程的返回值
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/1727699.html
Copyright © 2011-2022 走看看