fbpx

ב PLSQL כמו בשפות תכנות רבות אחרות, על מנת לפנות לתוכנית מסויימת, יש להצהיר עליה קודם. אם ננסה לקרוא לתוכנית מסויימת עוד לפני שנוצרה – תתקבל שגיאה.

עם זאת, קיימים מקרים בהם הקריאה לתוכנית תהיה קודמת להרצתה, לדוגמא – כאשר נרצה ליישם לוגיקה מסויימת או לייצר מספר תוכניות אשר כל אחת מהן קוראת לשניה.

באמצעות יכולת ה Forward Declaration נוכל להתמודד עם מצבים מסוג זה. כפי שנראה בדוגמאות הבאות, זו מאפשרת להצהיר על תוכניות מראש ולהשתמש בהן עוד לפני שהוגדרו בפועל.

נתחיל עם דוגמא פשוטה – נייצר בלוק אנונימי עם שתי פרוצדרות אשר מבצעות את הפעולות הבאות :

·       proc_a – מציגה מלל וקוראת ל proc_b

·       proc_bמציגה מלל

וננסה לקרוא לפרוצדורת proc_bמתוך פרוצדורת proc_aעוד לפני שיצרנו אותה.

RAM >> SET SERVEROUTPUT ON
RAM >>
RAM >> -- without forward declaration
RAM >> DECLARE
  2     PROCEDURE proc_a
  3     IS
  4     BEGIN
  5     DBMS_OUTPUT.PUT_LINE ('output from procedure A') ;
  6     proc_b ;
  7     END ;
  8
  9     PROCEDURE proc_b
 10     IS
 11     BEGIN
 12     DBMS_OUTPUT.PUT_LINE ('output from procedure B') ;
 13     END ;
 14  BEGIN
 15     proc_a ;
 16     proc_b ;
 17  END ;
 18  /
        proc_b ;
        *
ERROR at line 6:
ORA-06550: line 6, column 2:
PLS-00313: 'PROC_B' not declared in this scope
ORA-06550: line 6, column 2:
PL/SQL: Statement ignored

כפי שניתן לראות, מתקבלת שגיאה מכיוון שבפעם הראשונה בה התבצעה קריאה ל proc_bזו עדיין לא היתה קיימת. במקרים כמו אלו ניתן להשתמש ב Forward Declaration, כאמור, באמצעות יכולת זו ניתן להצהיר על תוכנית מסויימת עוד לפני שנוצרה, לדוגמא –

RAM >>  -- using forward declaration
RAM >>  DECLARE
  2     -- Forward declaration of procedure b
  3     PROCEDURE proc_b ;
  4
  5     PROCEDURE proc_a
  6     IS
  7     BEGIN
  8     DBMS_OUTPUT.PUT_LINE ('output from procedure A') ;
  9     proc_b ;
 10     END ;
 11
 12     PROCEDURE proc_b
 13     IS
 14     BEGIN
 15     DBMS_OUTPUT.PUT_LINE ('output from procedure B') ;
 16     END ;
 17  BEGIN
 18     proc_a ;
 19     proc_b ;
 20  END ;
 21  /
output from procedure A
output from procedure B
output from procedure B

PL/SQL procedure successfully completed.

RAM >>

בדוגמא האחרונה יכולנו להמנע מכל הבעיה באמצעות תכנון לוגי שונה – הגדרת פרוצדורת proc_b קודם. אך מה היה קורה אם היו קיימות שתי תוכניות אשר קוראות אחת לשניה ? במקרה זה השימוש ב Forward Declarationיהיה חובה.

לדוגמא – 2 פונקציות אשר מקבלות מספר המהווה שכרומבצעות את הפעולות הבאות :

·       above_10k במידה ושכר העובד שווה או מעל  10k הפונקציה תציג את שכרו בתוספת 20% אחרת תתבצע קריאה לפונקצית below_10k

·       below_10k במידה ושכר העובד נמוך מ 10k הפונקציה תציג את שכרו בניכוי 20% אחרת תתבצע קריאה לפונקצית above_10k

RAM >> SET SERVEROUTPUT ON
RAM >>
RAM >> DECLARE
  2     -- Without Forward Declaration
  3     -- FUNCTION below_10k (p_salary number) RETURN number ;
  4
  5     FUNCTION above_10k
  6     (p_salary number)
  7     RETURN number
  8     AS
  9             v_sal number ;
 10     BEGIN
 11     IF p_salary >>= 10000 THEN
 12     v_sal := p_salary * 1.2 ;
 13     ELSE
 14     v_sal := below_10k(p_salary) ;
 15     END IF ;
 16     RETURN v_sal ;
 17     END ;
 18
 19
 20     FUNCTION below_10k
 21     (p_salary number)
 22     RETURN number
 23     AS
 24     v_sal number ;
 25     BEGIN
 26     IF p_salary < 10000 THEN
 27     v_sal := p_salary * 0.8 ;
 28     ELSE
 29     v_sal := above_10k(p_salary) ;
 30     END IF ;
 31     RETURN v_sal ;
 32     END ;
 33
 34     BEGIN
 35
 36     DBMS_OUTPUT.PUT_LINE('Using above_10k function : ') ;
 37     DBMS_OUTPUT.PUT_LINE(above_10k(11000)) ;
 38     DBMS_OUTPUT.PUT_LINE(above_10k(9000)) ;
 39
 40
 41     DBMS_OUTPUT.PUT_LINE('Using below_10k function : ') ;
 42     DBMS_OUTPUT.PUT_LINE(below_10k(11000)) ;
 43     DBMS_OUTPUT.PUT_LINE(below_10k(9000)) ;
 44
 45     END ;
 46     /
        v_sal := below_10k(p_salary) ;
                 *
ERROR at line 14:
ORA-06550: line 14, column 12:
PLS-00313: 'BELOW_10K' not declared in this scope
ORA-06550: line 14, column 3:
PL/SQL: Statement ignored

במקרה כמו זה לא תיהיה אפשרות לפתור את הבעיה באמצעות הגדרת תוכנית מסויימת קודם. מקרה זה מחייב Forward Declaration.

RAM >> SET SERVEROUTPUT ON
RAM >>
RAM >> DECLARE
  2     -- Using Forward Declaration
  3     FUNCTION below_10k (p_salary number) RETURN number ;
  4
  5     FUNCTION above_10k
  6     (p_salary number)
  7     RETURN number
  8     AS
  9             v_sal number ;
 10     BEGIN
 11     IF p_salary >>= 10000 THEN
 12     v_sal := p_salary * 1.2 ;
 13     ELSE
 14     v_sal := below_10k(p_salary) ;
 15     END IF ;
 16     RETURN v_sal ;
 17     END ;
 18
 19
 20     FUNCTION below_10k
 21     (p_salary number)
 22     RETURN number
 23     AS
 24     v_sal number ;
 25     BEGIN
 26     IF p_salary < 10000 THEN
 27     v_sal := p_salary * 0.8 ;
 28     ELSE
 29     v_sal := above_10k(p_salary) ;
 30     END IF ;
 31     RETURN v_sal ;
 32     END ;
 33
 34     BEGIN
 35
 36     DBMS_OUTPUT.PUT_LINE('Using above_10k function : ') ;
 37     DBMS_OUTPUT.PUT_LINE(above_10k(11000)) ;
 38     DBMS_OUTPUT.PUT_LINE(above_10k(9000)) ;
 39
 40
 41     DBMS_OUTPUT.PUT_LINE('Using below_10k function : ') ;
 42     DBMS_OUTPUT.PUT_LINE(below_10k(11000)) ;
 43     DBMS_OUTPUT.PUT_LINE(below_10k(9000)) ;
 44
 45     END ;
 46     /
Using above_10k function :
13200
7200
Using below_10k function :
13200
7200

PL/SQL procedure successfully completed.

RAM >>

נקודה אחרונה לגבי Packages – כאשר התוכנית מוגדרת כחלק מה Spec אין צורך ב Forward Declaration ב Body. כאשר התוכנית לא מוגדרת כחלק מה Spec יש צורך ב Forward Declaration ב Body.

RAM >> ------------------------ Forward Declaration is not needed
RAM >>
RAM >>
RAM >>
RAM >>
RAM >> CREATE OR REPLACE PACKAGE my_pack
  2  IS
  3     FUNCTION above_10k (p_salary number) RETURN number ;
  4     FUNCTION below_10k (p_salary number) RETURN number ;
  5  END my_pack ;
  6  /

Package created.

RAM >>
RAM >> CREATE OR REPLACE PACKAGE BODY my_pack
  2  IS
  3     FUNCTION above_10k
  4  (p_salary number)
  5  RETURN number
  6  AS
  7     v_sal number ;
  8  BEGIN
  9     IF p_salary >>= 10000 THEN
 10     v_sal := p_salary * 1.2 ;
 11     ELSE
 12     v_sal := below_10k(p_salary) ;
 13     END IF ;
 14     RETURN v_sal ;
 15  END ;
 16
 17
 18  FUNCTION below_10k
 19  (p_salary number)
 20  RETURN number
 21  AS
 22     v_sal number ;
 23  BEGIN
 24     IF p_salary < 10000 THEN
 25     v_sal := p_salary * 0.8 ;
 26     ELSE
 27     v_sal := above_10k(p_salary) ;
 28     END IF ;
 29     RETURN v_sal ;
 30  END ;
 31  END my_pack ;
 32  /

Package body created.

RAM >>
RAM >> COL COL_1 FOR 99999
RAM >> COL COL_2 FOR 99999
RAM >> COL COL_3 FOR 99999
RAM >> COL COL_4 FOR 99999
RAM >>
RAM >> SELECT    my_pack.above_10k(11000) AS COL_1,
  2     my_pack.above_10k(9000)  AS COL_2,
  3     my_pack.below_10k(11000) AS COL_3,
  4     my_pack.below_10k(11000) AS COL_4
  5  FROM dual ;

 COL_1  COL_2  COL_3  COL_4
------ ------ ------ ------
 13200   7200  13200  13200

RAM >>
RAM >>
RAM >>
RAM >>
RAM >> ------------------------ Forward Declaration is needed
RAM >>
RAM >>
RAM >>
RAM >>
RAM >>
RAM >> CREATE OR REPLACE PACKAGE my_pack
  2  IS
  3     FUNCTION above_10k (p_salary number) RETURN number ;
  4  END my_pack ;
  5  /

Package created.

RAM >>
RAM >> CREATE OR REPLACE PACKAGE BODY my_pack
  2  IS
  3  FUNCTION above_10k
  4  (p_salary number)
  5  RETURN number
  6  AS
  7     v_sal number ;
  8  BEGIN
  9     IF p_salary >>= 10000 THEN
 10     v_sal := p_salary * 1.2 ;
 11     ELSE
 12     v_sal := below_10k(p_salary) ;
 13     END IF ;
 14     RETURN v_sal ;
 15  END ;
 16
 17
 18  FUNCTION below_10k
 19  (p_salary number)
 20  RETURN number
 21  AS
 22     v_sal number ;
 23  BEGIN
 24     IF p_salary < 10000 THEN
 25     v_sal := p_salary * 0.8 ;
 26     ELSE
 27     v_sal := above_10k(p_salary) ;
 28     END IF ;
 29     RETURN v_sal ;
 30  END ;
 31  END my_pack ;
 32  /

Warning: Package Body created with compilation errors.

RAM >>
RAM >>
RAM >> SHOW ERROR
Errors for PACKAGE BODY MY_PACK:

LINE/COL ERROR
-------- -----------------------------------------------------------------
12/4     PL/SQL: Statement ignored
12/13    PLS-00313: 'BELOW_10K' not declared in this scope
RAM >>
RAM >>
RAM >>
RAM >>
RAM >> ------------------------ Forward Declaration is needed
RAM >>
RAM >>
RAM >>
RAM >>
RAM >> CREATE OR REPLACE PACKAGE my_pack
  2  IS
  3     FUNCTION above_10k (p_salary number) RETURN number ;
  4  END my_pack ;
  5  /

Package created.

RAM >>
RAM >> CREATE OR REPLACE PACKAGE BODY my_pack
  2  IS
  3
  4  -- Using Forward Declaration.
  5  FUNCTION below_10k
  6  (p_salary number)
  7  RETURN number;
  8
  9  FUNCTION above_10k
 10  (p_salary number)
 11  RETURN number
 12  AS
 13     v_sal number ;
 14  BEGIN
 15     IF p_salary >>= 10000 THEN
 16     v_sal := p_salary * 1.2 ;
 17     ELSE
 18     v_sal := below_10k(p_salary) ;
 19     END IF ;
 20     RETURN v_sal ;
 21  END ;
 22
 23
 24  FUNCTION below_10k
 25  (p_salary number)
 26  RETURN number
 27  AS
 28     v_sal number ;
 29  BEGIN
 30     IF p_salary < 10000 THEN
 31     v_sal := p_salary * 0.8 ;
 32     ELSE
 33     v_sal := above_10k(p_salary) ;
 34     END IF ;
 35     RETURN v_sal ;
 36  END ;
 37  END my_pack ;
 38  /

Package body created.

RAM >>
RAM >>
RAM >> SELECT    my_pack.above_10k(11000) AS COL_1,
  2     my_pack.above_10k(9000)  AS COL_2
  3  FROM dual ;

 COL_1  COL_2
------ ------
 13200   7200

RAM >>

נכתב ע"י רם קדם