معالجة الاستثناءات في Oracle بل/SQL (أمثلة)

⚡ ملخص ذكي

معالجة الاستثناء في Oracle يلتقط PL/SQL أخطاء وقت التشغيل التي توقف تنفيذ كتلة، مما يسمح للمحرك بنقل التحكم إلى قسم الاستثناء حيث تستجيب المعالجات المحددة مسبقًا والمحددة من قبل المستخدم ومعالجات OTHERS أو تثير الأخطاء أو تنشرها بأمان.

  • ⚙️ أخطاء وقت التشغيل: يحدث استثناء عندما يواجه محرك PL/SQL تعليمات لا يمكنه تنفيذها، مثل قسمة رقم على صفر.
  • 🧱 بنية الكتلة: يتم التعامل مع الاستثناءات في قسم الاستثناءات باستخدام عبارات WHEN، مع وضع عبارة WHEN OTHERS دائمًا في النهاية.
  • 📚 الاستثناءات المحددة مسبقًا: Oracle يُحدد الأخطاء الشائعة مثل NO_DATA_FOUND و ZERO_DIVIDE في الحزمة القياسية، وهي جاهزة للالتقاط مباشرة.
  • 🛠️ الاستثناءات التي يحددها المستخدم: يقوم المبرمجون بتعريف متغيرات الاستثناء الخاصة بهم ورفعها بشكل صريح باستخدام الكلمة المفتاحية RAISE.
  • ⬆️ التكاثر: يتم تمرير الاستثناء غير المعالج إلى الكتلة المحيطة، وتقوم RAISE بإعادة إرسال الإشارة إليه إلى البرنامج الأصل.
  • 🤖 مساعدة الذكاء الاصطناعي: تقوم أدوات برمجة الذكاء الاصطناعي بصياغة كتل الاستثناءات وتحديد مسارات الأخطاء غير المعالجة أثناء المراجعة.

معالجة الاستثناءات في Oracle PL / SQL

ما هو التعامل مع الاستثناءات في PL/SQL؟

يحدث استثناء عندما يواجه محرك PL/SQL تعليمة لا يمكنه تنفيذها بسبب خطأ ينشأ أثناء التشغيل. لا يتم اكتشاف هذه الأخطاء أثناء الترجمة، وبالتالي يجب معالجتها فقط أثناء التشغيل.

على سبيل المثال، إذا تلقى محرك PL/SQL تعليمة لقسمة عدد على صفر، فإنه يُصدر خطأً كاستثناء. ويُصدر محرك PL/SQL هذا الاستثناء فقط أثناء التشغيل.

يؤدي حدوث استثناء إلى توقف البرنامج عن التنفيذ، لذا لتجنب هذه الحالة، يجب التقاط الخطأ ومعالجته بشكل منفصل. تُسمى هذه العملية بمعالجة الاستثناءات، حيث يتولى المبرمج معالجة الخطأ الذي قد يحدث أثناء التشغيل.

بناء جملة معالجة الاستثناءات

تُعالج الاستثناءات على مستوى الكتلة. بمجرد حدوث استثناء في كتلة ما، ينتقل التحكم من قسم التنفيذ في تلك الكتلة، ثم يُعالج الاستثناء في قسم معالجة الاستثناءات في الكتلة نفسها. بعد معالجة الاستثناء، لا يمكن للتحكم العودة إلى قسم التنفيذ في الكتلة ذاتها.

يوضح الرسم التوضيحي أدناه كيف يقع قسم التنفيذ وقسم معالجة الاستثناءات داخل كتلة PL/SQL واحدة:

بنية كتلة PL/SQL مع قسم التنفيذ والاستثناء

يوضح التركيب النحوي أدناه كيفية التقاط ومعالجة الاستثناء.

BEGIN
<execution block>
.
.
EXCEPTION
WHEN <exceptionl_name>
THEN
  <Exception handling code for the “exception 1 _name’' >
WHEN OTHERS
THEN
  <Default exception handling code for all exceptions >
END;

شرح بناء الجملة:

  • في الصيغة أعلاه، تحتوي كتلة معالجة الاستثناءات على سلسلة من شروط WHEN لمعالجة الاستثناءات.
  • يتبع كل شرط WHEN اسم استثناء من المتوقع أن يتم رفعه في وقت التشغيل.
  • عندما يتم طرح استثناء في وقت التشغيل، يقوم محرك PL/SQL بالبحث في جزء معالجة الاستثناءات عن هذا الاستثناء المحدد، بدءًا من عبارة WHEN الأولى والتحرك بالتسلسل.
  • إذا وجد معالجًا للاستثناء الذي تم طرحه، فإنه ينفذ رمز المعالج المحدد هذا.
  • إذا لم تتطابق أي عبارة WHEN مع الاستثناء المُثار، يقوم محرك PL/SQL بتنفيذ جزء WHEN OTHERS، إن وُجد. هذا المعالج مشترك بين جميع الاستثناءات.
  • بعد تشغيل المعالج، ينتقل التحكم من الكتلة الحالية.
  • لا يمكن تنفيذ سوى معالج استثناء واحد لكل كتلة برمجية أثناء التشغيل. بعد تنفيذه، يتخطى المحرك معالجات الاستثناءات المتبقية ويغادر الكتلة البرمجية الحالية.

ملاحظة: يجب دائمًا وضع عبارة WHEN OTHERS في نهاية التسلسل. أي معالج مكتوب بعد WHEN OTHERS لا يتم تنفيذه أبدًا، لأن التحكم يخرج من الكتلة بمجرد تنفيذ WHEN OTHERS.

أنواع الاستثناء

يوجد نوعان من الاستثناءات في PL / SQL.

  • الاستثناءات المحددة مسبقًا
  • الاستثناءات المحددة من قبل المستخدم

الاستثناءات المحددة مسبقًا

Oracle يحتوي على بعض الاستثناءات الشائعة المُعرّفة مسبقًا. لكل استثناء مُعرّف مسبقًا اسم فريد ورقم خطأ، وجميعها مُعلنة في حزمة STANDARD في Oracleفي البرمجة، يمكنك استخدام أسماء الاستثناءات المُعرَّفة مسبقًا هذه مباشرةً لمعالجة الأخطاء المُقابلة. يرتبط العديد منها مباشرةً بأسماء شائعة. SQL أخطاء تواجهها كل يوم.

فيما يلي بعض الاستثناءات المحددة مسبقًا:

استثناء خطأ Code سبب الاستثناء
ACCESS_INTO_NULL ORA-06530 إسناد قيمة لخصائص كائن غير مهيأ
الحالة_غير موجودة ORA-06592 لم يتم استيفاء أي من شروط WHEN في عبارة CASE، ولم يتم تحديد أي شرط ELSE.
COLLECTION_IS_NULL ORA-06531 استخدام أساليب التجميع (باستثناء EXISTS) أو الوصول إلى سمات المجموعة في مجموعة غير مهيأة
CURSOR_ALREADY_OPEN ORA-06511 محاولة فتح أ المؤشر هذا مفتوح بالفعل
DUP_VAL_ON_INDEX ORA-00001 تخزين قيمة مكررة في عمود قاعدة بيانات مقيد بفهرس فريد
INVALID_CURSOR ORA-01001 عمليات المؤشر غير القانونية، مثل إغلاق مؤشر غير مفتوح
رقم غير صالح ORA-01722 فشلت عملية تحويل الحرف إلى رقم بسبب وجود حرف رقمي غير صالح
لاتوجد بيانات ORA-01403 عبارة SELECT التي تحتوي على عبارة INTO لا تجلب أي صفوف
ROW_MISMATCH ORA-06504 نوع بيانات متغير المؤشر غير متوافق مع نوع الإرجاع الفعلي للمؤشر
SUBSCRIPT_BEYOND_COUNT ORA-06533 الإشارة إلى مجموعة برقم فهرس أكبر من حجم المجموعة
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 الإشارة إلى مجموعة برقم فهرس خارج النطاق القانوني (على سبيل المثال، -1)
TOO_MANY_ROWS ORA-01422 عبارة SELECT التي تحتوي على عبارة INTO تُرجع أكثر من صف واحد
VALUE_ERROR ORA-06502 خطأ حسابي أو خطأ في قيود الحجم (على سبيل المثال، تعيين قيمة أكبر من حجم المتغير)
ZERO_DIVIDE ORA-01476 قسمة عدد على صفر

استثناء محدد من قبل المستخدم

إلى جانب الاستثناءات المُعرَّفة مسبقًا المذكورة أعلاه، يُمكن للمبرمج إنشاء استثناءات مُخصصة ومعالجتها. تُنشأ هذه الاستثناءات على مستوى البرنامج الفرعي في قسم التصريح، وتكون مرئية فقط داخل ذلك البرنامج الفرعي. أما الاستثناء المُعرَّف في مواصفات الحزمة فهو استثناء عام، ويكون مرئيًا في أي مكان يُمكن الوصول فيه إلى الحزمة.

بناء الجملة: على مستوى البرنامج الفرعي

DECLARE
<exception_name> EXCEPTION;
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN
<Handler>
END;
  • في الصيغة أعلاه، تم تعريف المتغير 'exception_name' على أنه نوع الاستثناء.
  • ويمكن استخدامه بعد ذلك بنفس طريقة الاستثناء المحدد مسبقًا.

بناء الجملة: على مستوى مواصفات الحزمة

CREATE PACKAGE <package_name>
 IS
<exception_name> EXCEPTION;
.
.
END <package_name>;
  • في الصيغة أعلاه، تم تعريف المتغير 'exception_name' على أنه نوع الاستثناء في مواصفات الحزمة لـ .
  • يمكن استخدامه في جميع أنحاء قاعدة البيانات أينما يمكن استدعاء الحزمة 'package_name'.

استثناء رفع PL/SQL

تُثار جميع الاستثناءات المُعرَّفة مسبقًا ضمنيًا عند حدوث الخطأ المُناسب. أما الاستثناءات التي يُعرِّفها المستخدم، فيجب إثارتها صراحةً باستخدام الكلمة المفتاحية RAISE. يُمكن استخدام RAISE بالطرق الموضحة أدناه.

إذا استُخدمت الدالة RAISE بمفردها داخل معالج الاستثناءات، فإنها تنقل الاستثناء الذي تم رفعه مسبقًا إلى الكتلة الأصلية. ولا يمكن استخدامها إلا داخل كتلة استثناءات، كما هو موضح أدناه.

تُظهر لقطة الشاشة أدناه استخدام RAISE بمفرده لإعادة رفع استثناء إلى الكتلة المحيطة:

نشر استثناء إلى الكتلة الأصلية باستخدام RAISE فقط

CREATE [ PROCEDURE | FUNCTION ]
 AS
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN
             <Handler>
RAISE;
END;

شرح بناء الجملة:

  • في الصيغة أعلاه، يتم استخدام الكلمة المفتاحية RAISE داخل كتلة معالجة الاستثناءات.
  • عندما يواجه البرنامج الاستثناء 'exception_name'، يتم التعامل مع الاستثناء ويكتمل بشكل طبيعي.
  • ثم تقوم الكلمة المفتاحية RAISE في المعالج بنشر نفس الاستثناء إلى البرنامج الأصل.

ملاحظة: عند إثارة استثناء في الكتلة الأصلية، يجب أن يكون الاستثناء الذي يتم إثارته مرئيًا أيضًا في الكتلة الأصلية؛ وإلا Oracle يلقي خطأ.

يمكنك أيضًا استخدام الكلمة المفتاحية RAISE متبوعةً باسم الاستثناء لإطلاق استثناء مُعرَّف من قِبل المستخدم أو مُعرَّف مسبقًا. يُمكن استخدام هذه الصيغة في كلٍّ من جزء التنفيذ وجزء معالجة الاستثناءات.

تُظهر لقطة الشاشة أدناه الأمر RAISE متبوعًا باسم الاستثناء لرفع استثناء معين:

إطلاق استثناء مُسمى مُحدد باستخدام الأمر RAISE متبوعًا باسم الاستثناء

CREATE [ PROCEDURE | FUNCTION ]
AS
BEGIN
<Execution block>
RAISE <exception_name>
EXCEPTION
WHEN <exception_name> THEN
<Handler>
END;

شرح بناء الجملة:

  • في الصيغة أعلاه، يتم استخدام الكلمة المفتاحية RAISE في جزء التنفيذ، متبوعة بالاستثناء 'exception_name'.
  • يؤدي هذا إلى ظهور هذا الاستثناء المحدد في وقت التشغيل، ثم يجب معالجته أو إثارته بشكل أكبر.

مثال 1: في هذا المثال، سنرى:

  • كيفية إعلان استثناء
  • كيفية إثارة الاستثناء المُعلن
  • كيفية نشره إلى الكتلة الرئيسية

تُظهر لقطة الشاشة أدناه الكتلة الكاملة التي تُعلن عن sample_exception، وتُثيرها داخل كتلة متداخلة، وتُمررها إلى الكتلة الرئيسية:

مثال PL/SQL لتعريف وإطلاق استثناء مُعرَّف من قِبل المستخدم في كتلة متداخلة

تُظهر لقطة الشاشة التالية نفس المثال مُكملاً، حيث تلتقط الكتلة الرئيسية في النهاية الاستثناء المُنتشر:

يُظهر الناتج الاستثناء الذي تم التقاطه أولاً في الكتلة المتداخلة ثم في الكتلة الرئيسية

DECLARE
Sample_exception EXCEPTION;
PROCEDURE nested_block
IS
BEGIN
Dbms_output.put_line('Inside nested block');
Dbms_output.put_line('Raising sample_exception from nested block');
RAISE sample_exception;
EXCEPTION
WHEN sample_exception THEN
Dbms_output.put_line ('Exception captured in nested block. Raising to main block');
RAISE;
END;
BEGIN
Dbms_output.put_line('Inside main block');
Dbms_output.put_line('Calling nested block');
Nested_block;
EXCEPTION
WHEN sample_exception THEN
Dbms_output.put_line ('Exception captured in main block');
END;
/

Code التفسير:

  • Code السطر 2: تعريف المتغير 'sample_exception' كنوع استثناء.
  • Code السطر 3: إعلان الإجراء nested_block.
  • Code السطر 6: طباعة العبارة "داخل كتلة متداخلة".
  • Code السطر 7: طباعة العبارة "رفع استثناء sample_exception من كتلة متداخلة".
  • Code السطر 8: رفع الاستثناء باستخدام "RAISE Sample_exception".
  • Code السطر 10: معالج الاستثناء الخاص بالاستثناء sample_exception في الكتلة المتداخلة.
  • Code السطر 11: طباعة العبارة "تم التقاط استثناء في كتلة متداخلة. جارٍ رفعه إلى الكتلة الرئيسية".
  • Code السطر 12: رفع الاستثناء إلى الكتلة الرئيسية (نشره).
  • Code السطر 15: طباعة العبارة "داخل الكتلة الرئيسية".
  • Code السطر 16: طباعة العبارة "استدعاء الكتلة المتداخلة".
  • Code السطر 17: استدعاء إجراء nested_block.
  • Code السطر 19: معالج الاستثناء لـ Sample_exception في الكتلة الرئيسية.
  • Code السطر 20: طباعة العبارة "تم التقاط الاستثناء في الكتلة الرئيسية".

نقاط مهمة يجب ملاحظتها في الاستثناء

  • في الدالة، يجب أن يُعيد الاستثناء قيمةً أو أن يُثير الاستثناء بشكلٍ أكبر؛ وإلا Oracle يُصدر خطأ "تم إرجاع الدالة بدون قيمة" أثناء التشغيل.
  • بيانات التحكم في المعاملات يمكن إصدارها داخل كتلة معالجة الاستثناءات.
  • SQLERRM و SQLCODE هما دالتان مدمجتان تقومان بإرجاع رسالة الاستثناء ورمز الاستثناء على التوالي.
  • إذا لم يتم التعامل مع الاستثناء، فسيتم التراجع عن جميع المعاملات النشطة في تلك الجلسة بشكل افتراضي.
  • RAISE_APPLICATION_ERROR (- ، يمكن استخدام ) بدلاً من RAISE لإظهار خطأ برمز ورسالة مخصصين. يجب أن يكون رمز الخطأ بين -20000 و-20999.

الأسئلة الشائعة

يربط الأمر PRAGMA EXCEPTION_INIT اسم استثناء مُعلن من قِبل المستخدم بـ Oracle رقم الخطأ. بعد الربط، يمكنك معالجة خطأ ORA هذا بالاسم في عبارة WHEN بدلاً من استخدام WHEN OTHERS والتحقق من SQLCODE.

تُعيد الدالة SQLCODE رمز الخطأ الرقمي للاستثناء الحالي، بينما تُعيد الدالة SQLERRM رسالة الخطأ النصية. ويتم استدعاء كلتا الدالتين داخل معالج الاستثناءات، وغالبًا ما يكون ذلك ضمن كتلة WHEN OTHERS، لتسجيل أو عرض الخطأ الذي حدث.

تجنّب استخدام عبارة WHEN OTHERS التي تتجاهل جميع الأخطاء دون تنبيه. فبدون تسجيل رمز الخطأ (SQLCODE) ورمز الخطأ (SQLERRM) أو إعادة رفع الاستثناء باستخدام RAISE، تُخفي هذه العبارة الأخطاء. استخدمها فقط لتسجيل الاستثناء وتنظيفه ثم نشره.

تقبل الدالة RAISE_APPLICATION_ERROR رقم خطأ يتراوح بين -20000 و-20999 ورسالة يصل حجمها إلى 2048 بايت. توقف هذه الدالة التنفيذ وتعيد خطأً مخصصًا إلى التطبيق المُستدعي، مما يجعل الشرط المُعرَّف من قِبل المستخدم يبدو وكأنه خطأ أصلي. Oracle خطأ.

ليس في نفس الكتلة البرمجية - بمجرد انتقال التحكم إلى قسم الاستثناء، تنتهي تلك الكتلة. للمتابعة، ضع العبارة المحفوفة بالمخاطر داخل كتلة BEGIN…EXCEPTION…END داخلية؛ بعد معالجة الخطأ، تستمر الكتلة الخارجية في التنفيذ.

الخطأ هو أي مشكلة تحدث أثناء تشغيل البرنامج أو أثناء ترجمته. أما الاستثناء فهو آلية تشغيل PL/SQL التي تمثل خطأً أثناء التشغيل، حيث تنقل التحكم إلى قسم الاستثناءات ليتمكن البرنامج من الاستجابة بدلاً من التوقف المفاجئ.

نعم. تقوم برامج الذكاء الاصطناعي ومراجعو التعليمات البرمجية باستخدام تقنيات التعلم الآلي بصياغة كتل الاستثناءات، واقتراح الاستثناءات المحددة مسبقًا التي يجب معالجتها، وتحديد مسارات التعليمات البرمجية التي تفتقر إلى معالجات. مع ذلك، ينبغي على المطور التأكد من منطق البرنامج ورسائل الخطأ قبل النشر.

مساعد الطيار جيثب تُكمل هذه الميزة تلقائيًا عبارات WHEN، واستدعاءات RAISE_APPLICATION_ERROR، وكتل EXCEPTION الكاملة من تعليق قصير يصف الغرض. وهذا يُسرّع عملية كتابة التعليمات البرمجية للمعالجات الروتينية، مع العلم أن رموز ورسائل الخطأ المُولّدة تحتاج إلى مراجعة للتأكد من دقتها.

تلخيص هذه التدوينة بـ: