Get list of arguments with default value

2019-06-25 13:25发布

问题:

I use ALL_ARGUMENTS to get list of arguments in oracle 10g, but I can't find out is there default value for argument. Haw can I do it?

回答1:

you might need to resort to plsql programming in 10g, in the vein of the code sample below. this solution is certainly brute-force in some sense, as you basically write part of a function/procedure declaration parser using very low-level primitives. however, regular expression functions aren't available in 10g either ...

the gist of the code is:

  • iterate over the source code lines of procedure/function declarations
  • note the name of the most recently declared routine
  • analyze all lines containing the keyword 'DEFAULT', getting the argument name and the default value spec (this is not outlined in detail in the code sample).

beware of pitfalls:

  • multiline declarations
  • C-style comments containing C-style comment opening strings ( a la /* blah blah / blah blah **/ )
  • string literals containing keywords

hope that helps anyway, best regards.

the code:

DECLARE
   l_arg_and_more    VARCHAR2(400);
   l_current_unit    VARCHAR2(400);
   l_default_spec    VARCHAR2(400);
   l_offset_default  BINARY_INTEGER;
   l_offset_eoname   BINARY_INTEGER;
BEGIN
   FOR i IN (
        select text
         from all_source
        where owner = '<name of owner>'
          and name = '<object name>'
          and type in ( 'PACKAGE', 'PROCEDURE', 'FUNCTION')
          and text not like '--%'
     order by line
   ) LOOP
      IF i.text LIKE '%FUNCTION%' OR i.text LIKE '%PROCEDURE%' THEN
         IF i.text LIKE '%FUNCTION%' THEN
            l_current_unit    := LTRIM(SUBSTR(i.text, INSTR(i.text, 'FUNCTION') + LENGTH('FUNCTION')), ' ');
            l_offset_eoname   := INSTR(l_current_unit, ' ');              
            IF l_offset_eoname = 0 OR l_offset_eoname > INSTR(l_current_unit, '(') THEN
               l_offset_eoname   := INSTR(l_current_unit, '(');
            END IF;
            IF l_offset_eoname <> 0 THEN
               l_current_unit := SUBSTR(l_current_unit, 1, l_offset_eoname-1);
            ELSE
               l_current_unit := 'unidentified';
            END IF;
         END IF;
      END IF;
      --
      IF i.text LIKE '%DEFAULT%' THEN
         l_offset_default  := INSTR (i.text, 'DEFAULT');
         l_arg_and_more    := SUBSTR(i.text, 1, l_offset_default - 1);
         l_default_spec    := SUBSTR(i.text, l_offset_default + LENGTH('DEFAULT') + 1);
         --
         -- process l_arg_and_more to get the arg name, l_default_spec for the default value
         --
      END IF;
   END LOOP;              
END;


回答2:

I know it is a bit too late but this may help. I'm facing similar problem at this time. Needs more testing...

SELECT SUBSTR(final_str, start_pos+1, (end_pos-start_pos-1) ) dflt_values, start_pos, end_pos  
 FROM 
 (
  SELECT start_pos, final_end_pos end_pos, MOD(ROWNUM, 2) rno, final_str  FROM
  (
   SELECT distinct start_pos, end_pos, final_str, (CASE WHEN end_pos < start_pos THEN (start_pos*2) ELSE end_pos END) final_end_pos
     FROM
    (
    SELECT Instr(final_str, '=', LEVEL) start_pos, Instr(final_str, ',', LEVEL) end_pos, final_str  --<<-- distinct 
      FROM 
    (
     SELECT RTRIM(SUBSTR(str, 1, e_start), ',')||RTRIM(SUBSTR(str, e_start, e_end-e_start), ')') final_str
     , e_start
     , e_end
 , e_end-e_start
      FROM
    (
    SELECT str, Instr(str, ',', 1, 5) e_start, Instr(str, ')') e_end
      FROM
    (
     SELECT REPLACE(REPLACE(REPLACE(SUBSTR(str, INSTR(str, '(')+1), chr(32), ''), chr(10), chr(32) ), 'DEFAULT', ':=') str
       FROM
    (
     SELECT 'PROCEDURE Some_Proc(p_arg1  VARCHAR2:= ''Arg1''
                      , p_arg2  VARCHAR2:= ''Arg2''
                      , p_arg3  DATE     DEFAULT ''SYSDATE-90''                                                                                   
                      , p_arg4  VARCHAR2 DEFAULT ''NULL''                                          
                      , p_arg5  NUMBER  := ''10'')' str
       FROM dual
    ))))
    CONNECT BY LEVEL <= LENGTH(final_str)
    )
  WHERE start_pos > 0
  ORDER BY start_pos, end_pos
 ))
 WHERE rno > 0
 /


回答3:

In the view SYS.ALL_ARGUMENTS there is a column named DEFAULT_VALUE, but even in 11g it's type is LONG and is a headache to work around and convert to CLOB.

The "easiest" (not the best) way is to create a table from this view, using TO_LOB to convert this field to a CLOB and work with that.