⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 genaa.sql

📁 Oracle PL/SQL procedure generator
💻 SQL
📖 第 1 页 / 共 2 页
字号:
CREATE OR REPLACE PROCEDURE genaa (
   tab_in        IN   VARCHAR2,
   sch_in        IN   VARCHAR2 := NULL,
   delim_in      IN   VARCHAR2 := '^',
   pkg_name_in   IN   VARCHAR2 := NULL,
   display_in    IN   BOOLEAN := FALSE ,
   file_in       IN   VARCHAR2 := NULL,
   dir_in        IN   VARCHAR2 := NULL
)
/* Assumptions:
- Table has a primary key consisting of a single integer value.
*/
IS 
   SUBTYPE identifier_t IS VARCHAR2 (100);

   v_tab          identifier_t := UPPER (tab_in);
   v_sch          identifier_t := NVL (UPPER (sch_in), USER);
   v_pkg_name     identifier_t := NVL (pkg_name_in, tab_in || '_cache');
   
   -- Moved out of parameter list; not implemented
   do_reload_in   BOOLEAN      := FALSE ;
   
   -- Send output to file or screen?
   v_to_screen    BOOLEAN      := file_in IS NULL;
   
   -- Array of output for package
   TYPE lines_t IS TABLE OF VARCHAR2 (1000)
      INDEX BY BINARY_INTEGER;

   output         lines_t;

   TYPE pky_rec IS RECORD (
      NAME          identifier_t,
      column_name   identifier_t,
      column_type   identifier_t,
      array_name    identifier_t
   );

   pky_info       pky_rec;

   TYPE cols_rec IS RECORD (
      NAME            identifier_t,
      TYPE            identifier_t,
      aa_index_type   identifier_t
   );

   TYPE cols_tt IS TABLE OF cols_rec
      INDEX BY BINARY_INTEGER;
	  
   -- Additional fields to avoid hard-coding and unnecessary overhead
   TYPE inds_rec IS RECORD (
      NAME           identifier_t,
      numcols        PLS_INTEGER,
      array_name     identifier_t,
      subtype_name   identifier_t,
      val_for_name   identifier_t,
      cols           cols_tt
   );

   TYPE inds_tt IS TABLE OF inds_rec
      INDEX BY /*BINARY_INTEGER; --*/ identifier_t;
   ucols          inds_tt;
   
   -- Now pl simply writes to the array.
   PROCEDURE pl (str IN VARCHAR2)
   IS
   BEGIN
      output (NVL (output.LAST, 0) + 1) := str;
   END;
   -- Dump to screen or file.
   PROCEDURE dump_output
   IS
   BEGIN
      IF v_to_screen
      THEN
         FOR indx IN output.FIRST .. output.LAST
         LOOP
            DBMS_OUTPUT.put_line (output (indx));
         END LOOP;
      ELSE
         -- Send output to the specified file.
         DECLARE
            fid   UTL_FILE.file_type;
         BEGIN
            fid := UTL_FILE.fopen (dir_in, file_in, 'W');

            FOR indx IN output.FIRST .. output.LAST
            LOOP
               UTL_FILE.put_line (fid, output (indx));
            END LOOP;

            UTL_FILE.fclose (fid);
         EXCEPTION
            WHEN OTHERS
            THEN
               DBMS_OUTPUT.put_line (
                  'Failure to write output to ' || dir_in || '/' || file_in
               );
               UTL_FILE.fclose (fid);
         END;
      END IF;
   END dump_output;

   PROCEDURE assert (condition_in IN BOOLEAN, msg_in IN VARCHAR2)
   IS
   BEGIN
      IF NOT condition_in OR condition_in IS NULL
      THEN
         DBMS_OUTPUT.put_line ('GENAA Error on ' || v_sch || '.' || v_tab || ': ');
         DBMS_OUTPUT.put_line (msg_in);
         raise_application_error (
            -20000,
            'GENAA Error on ' || v_sch || '.' || v_tab || ': ' || msg_in
         );
      END IF;
   END;

   FUNCTION primary_key_name (tab_in IN VARCHAR2, sch_in IN VARCHAR2)
      RETURN VARCHAR2
   IS 
      retval   identifier_t;
   BEGIN
      SELECT cons.constraint_name
        INTO retval
        FROM all_constraints cons
       WHERE cons.owner = sch_in
         AND cons.table_name = tab_in
         AND cons.constraint_type = 'P';

      RETURN retval;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         RETURN NULL;
   END;
   -- Create another function that retrieves all 
   -- column info for the specified index. 
   FUNCTION index_columns (
      tab_in   IN   VARCHAR2,
      sch_in   IN   VARCHAR2 := NULL,
      ind_in   IN   VARCHAR2
   )
      RETURN cols_tt
   IS 
      retval   cols_tt;
   BEGIN
      SELECT   i.column_name, t.data_type,
               DECODE (
                  t.data_type,
                  'INTEGER',
                  'PLS_INTEGER',
                  sch_in || '.' || tab_in || '.' || i.column_name || '%TYPE'
               )
          BULK COLLECT INTO retval
          FROM all_ind_columns i,
               (SELECT column_name, data_type
                  FROM all_tab_columns
                 WHERE table_name = tab_in AND owner = sch_in) t
         WHERE i.index_owner = sch_in
           AND i.table_name = tab_in
           AND i.table_owner = sch_in
           AND i.index_name = ind_in
           AND i.column_name = t.column_name
      ORDER BY column_position;

      RETURN retval;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         RETURN retval;
   END;

   FUNCTION primary_key_columns (
      tab_in   IN   VARCHAR2,
      sch_in   IN   VARCHAR2,
      pky_in   IN   VARCHAR2
   )
      RETURN cols_tt
   IS
   BEGIN
      RETURN index_columns (tab_in, sch_in, pky_in);
   END;

   FUNCTION unique_index_columns (
      tab_in   IN   VARCHAR2,
      sch_in   IN   VARCHAR2,
      pky_in   IN   VARCHAR2
   )
      RETURN inds_tt
   IS 
      CURSOR uinds_cur
      IS
         SELECT index_name
           FROM all_indexes
          WHERE table_name = tab_in
            AND table_owner = sch_in
            AND uniqueness = 'UNIQUE'
            AND index_name != pky_in;

      retval   inds_tt;
   BEGIN
      FOR rec IN uinds_cur
      LOOP
         retval (rec.index_name).NAME := rec.index_name;
         retval (rec.index_name).array_name := rec.index_name || '_aa';
         retval (rec.index_name).subtype_name := rec.index_name || '_t';
         retval (rec.index_name).val_for_name := 'val_for_' || rec.index_name;
         retval (rec.index_name).cols :=
                               index_columns (tab_in, sch_in, rec.index_name);
         retval (rec.index_name).numcols := retval (rec.index_name).cols.COUNT;
      END LOOP;

      RETURN retval;
   END;

   PROCEDURE validate_and_initialize (
      pky_info_out   IN OUT   pky_rec,
      ucols_out      IN OUT   inds_tt
   )
   IS 
      indx      identifier_t;
      pkycols   cols_tt;
   BEGIN
      -- Set primary key information: just the first row of info!
      pky_info_out.NAME := primary_key_name (v_tab, v_sch);
      assert (
         pky_info_out.NAME IS NOT NULL,
         'No primary key available for table or table does not exist.'
      );
      pkycols := primary_key_columns (v_tab, v_sch, pky_info_out.NAME);
      pky_info_out.column_name := pkycols (pkycols.FIRST).NAME;
      pky_info_out.column_type := pkycols (pkycols.FIRST).TYPE;
      pky_info_out.array_name := pky_info_out.NAME || '_aa';
      -- Obtain unique index information.
      ucols_out := unique_index_columns (v_tab, v_sch, pky_info_out.NAME);

      IF display_in
      THEN
         pl ('Columns for primary key on ' || sch_in || '.' || tab_in);

         FOR indx IN 1 .. pkycols.COUNT
         LOOP
            pl (pkycols (indx).NAME || ' - ' || pkycols (indx).TYPE);
         END LOOP;

         pl ('');
         indx := ucols_out.FIRST;

         LOOP
            EXIT WHEN indx IS NULL;
            pl ('Columns for Index ' || indx);
            pl ('Number of columns in Index ' || ucols_out (indx).numcols);

            FOR cindx IN ucols_out (indx).cols.FIRST .. ucols_out (indx).cols.LAST
            LOOP
               pl (
                     ucols_out (indx).cols (cindx).NAME
                  || ' - '
                  || ucols_out (indx).cols (cindx).TYPE
               );
            END LOOP;

            indx := ucols_out.NEXT (indx);
         END LOOP;
      END IF;
   END;

   PROCEDURE gen_package_spec (
      tab_in        IN   VARCHAR2,
      sch_in        IN   VARCHAR2,
      pkg_in        IN   VARCHAR2,
      pky_info_in   IN   pky_rec,
      ucols_in      IN   inds_tt
   )
   IS 
      v_fulltab   identifier_t := v_sch || '.' || v_tab;

      PROCEDURE gen_declarations
      IS 
         indx   identifier_t := ucols_in.FIRST;
      BEGIN
           -- Declare a named type for each index that has more
         -- than one column.
         WHILE indx <= ucols_in.LAST
         LOOP
            IF ucols_in (indx).numcols > 1
            THEN
               pl (
                     'subtype '
                  || ucols_in (indx).subtype_name
                  || ' is varchar2(32767);'
               );
            END IF;

            indx := ucols_in.NEXT (indx);
         END LOOP;
      END;

      PROCEDURE gen_retrieval_function_headers
      IS 
         indx   identifier_t := ucols_in.FIRST;
      BEGIN
         -- Declare a function for each index and pkey
         pl (
               'function onerow ( '
            || pky_info_in.column_name
            || '_in IN '
            || v_fulltab
            || '.'
            || pky_info_in.column_name
            || '%TYPE) return '
            || v_fulltab
            || '%ROWTYPE;'
         );

         WHILE indx <= ucols_in.LAST
         LOOP
            -- Generic VARCHAR2-indexed tables...
            pl ('function onerow_by_' || ucols_in (indx).NAME || ' ( ');

            FOR cindx IN ucols_in (indx).cols.FIRST .. ucols_in (indx).cols.LAST
            LOOP
               pl (
                     ucols_in (indx).cols (cindx).NAME
                  || '_in IN '
                  || v_fulltab
                  || '.'
                  || ucols_in (indx).cols (cindx).NAME
                  || '%TYPE'
               );

               IF cindx < ucols_in (indx).cols.LAST
               THEN
                  pl (',');
               END IF;
            END LOOP;

            pl (') return ' || v_fulltab || '%ROWTYPE;');
            indx := ucols_in.NEXT (indx);
         END LOOP;
      END;

      PROCEDURE gen_reload_logic
      IS
      BEGIN
         IF do_reload_in
         THEN
            -- Include headers to load and set reload interval.
            pl ('procedure load_array;');
         END IF;
      END;

      PROCEDURE gen_test_program
      IS
      BEGIN
         pl ('procedure test;');
      END;
   BEGIN
      pl ('create or replace package ' || pkg_in || ' is ');
      gen_declarations;
      gen_retrieval_function_headers;
      gen_reload_logic;
      gen_test_program;
      pl ('end ' || pkg_in || ';');
      pl ('/');
   END;

   PROCEDURE gen_package_body (
      tab_in        IN   VARCHAR2,
      sch_in        IN   VARCHAR2,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -