Blog programisty w Oracle PL/SQL

Jest to blog eksperymentatora programisty w PL/SQL dla Oracle. Wszystkie kody tutaj zamieszczone mogą być dowolnie wykorzystywane i zmieniane. A jeśli Ktoś z Gości znajdzie błąd, będę niezwykle wdzięczny...
Zapisz

Szukaj na tym blogu

piątek, 13 kwietnia 2012

Unikalne nazwy dla obiektów

Poniższy trigger wynika z własnych przemyśleń na temat nazywania obiektów w bazie danych i mnóstwa problemów, jeśli w różnych schematach są obiekty o tej samej nazwie np.
  • problemy ze scalaniem schematów, występujące w wyniku rotacji użytkowników baz danych
  • redundancja danych i problemy związane z identyfikacją biznesowego znaczenia obiektów o takiej samej nazwie  
  • kłopoty z utrzymaniem spójności kodu i odwołaniami do obiektów powtarzających się w wielu schematach
  • nadmierne zużycie przestrzeni dyskowej
Poniżej przykłady  problematycznych instrukcji
CREATE TABLE DUAL AS
SELECT * FROM DUAL
        UNION
SELECT * FROM DUAL

RENAME myTable TO DUAL
 
Trigger TRG_CHECK_DUPLICATES jest przykładem rozwiązania omawianego problemu. Został napisany przy następujących założeniach:
  • nie działa dla użytkowników SYS i SYSTEM
  • działa przed operacjami CREATE i RENAME
  • dla operacji RENAME dokonujemy prostej analizy polecenia DDL, dla polecenia CREATE nazwa obiektu pobierana jest z predefiniowanej zmiennej ORA_DICT_OBJ_NAME
  • w komunikacie wyjątku podawane są nazwy już istniejących obiektów dla instrukcji DDL
  • jest instalowany przez DBA w schemacie SYS


CREATE OR REPLACE TRIGGER SYS.TRG_CHECK_DUPLICATES
   BEFORE CREATE
   OR RENAME
   ON  DATABASE
DECLARE
    CURSOR
C (pc_ObjectName VARCHAR2) IS
        SELECT OWNER|| '.' || OBJECT_NAME || ' typu '   || OBJECT_TYPE  AS MSG FROM DBA_OBJECTS
          WHERE OBJECT_NAME = pc_ObjectName
              AND OWNER <> ORA_DICT_OBJ_OWNER;
    vc_ErrorMsg VARCHAR2(500 CHAR);
    vc_SQLStatement VARCHAR2(200 CHAR);
    vc_ObjectName VARCHAR2(30 CHAR);
    vt_List DBMS_STANDARD.ORA_NAME_LIST_T := DBMS_STANDARD.ORA_NAME_LIST_T();
    vn_Size    PLS_INTEGER;
BEGIN
    IF USER IN ('SYS', 'SYSTEM') THEN
          RETURN;
    END IF;
    BEGIN

        IF ORA_SYSEVENT = 'RENAME' THEN
            vn_Size := ora_sql_txt (vt_List);
            FOR i IN 1 .. vn_Size
            LOOP
                vc_SQLStatement := vc_SQLStatement || vt_List (i);
            END LOOP;
           
            vc_ObjectName := REGEXP_SUBSTR(TRIM(vc_SQLStatement), '[[:alnum:]]+[[:cntrl:]]*$',1,1);
            vc_ObjectName := REGEXP_SUBSTR(TRIM(vc_ObjectName), '[[:alnum:]]+',1,1);
         ELSIF ORA_SYSEVENT = 'CREATE' THEN
            vc_ObjectName:= ORA_DICT_OBJ_NAME;
        END IF;
       
        FOR EL IN C(vc_ObjectName)
         LOOP
           IF vc_ErrorMsg IS NULL THEN
                vc_ErrorMsg := 'istnieje już ' || CHR(13) || CHR(10) || EL.MSG;
            ELSE
                vc_ErrorMsg := vc_ErrorMsg || CHR(13) || CHR(10) || EL.MSG ;
            END IF;
         END LOOP;
       
     EXCEPTION WHEN OTHERS THEN
        NULL;
     END;
     IF  vc_ErrorMsg IS NOT NULL THEN
        RAISE_APPLICATION_ERROR(-20101, 'Zdublowane nazwy obiektów: ' || vc_ErrorMsg );
     END IF;
END;
/