الانتقال إلى المحتوى

دروس متقدمة في الــ Pl/sql الدرس الثاني Error Handling


khaled

Recommended Posts

بسم الله الرحمن الرحيم


اعزائي زوار واعضاء منتدى عرب اوركل المحترمين تحية طيبة .
تكملة لما قد بدأناه من قبل(دروس متقدمة في الـPL/SQL) سوف اتطرق اليوم الى شرح الـError Handling وعلى طريقتي الخاصة . وسوف افتح المجال للنقاش بإذن الله .
وبألامثلة سوف نعرج على الاتي :
1- ماهو الـ Exception ومتى يستخدم .
2- مامعنى معالجة الاخطاء وماالفرق بين الاكواد التي تحوي جزء معالجة الأخطاء والتي لا تحيوي
3- مثالين احدهم بالForm Builder والأخر بالVB.NET للتوضيح التعامل مع اجراءات تم انشائها في قاعدة الييانات , لفهم الفائدة من معالجة الأخطاء .

ملاحظة:
هذا الدرس غير منقول من اي كتاب ولا منتدى فهو من اعدادي الخاص , فلا تتوقعوا ان يكون درس مثالي خالي من الأخطاء , لذلك ارحب بكل اقتراحاتكم وتعديلاتكم .

1. 1 ماهو PL/SQL EXCEPTION

هل انت مبرمج هل سبق وان تعاملت مع لغة الفجول بيسك او الفجول بيسك دوت نت او الجافا او الــ PL/SQL ؟ اذا كانت الإجابة بنعم فانت تعرف الـException ومابقي عليك هو ان تعرف متى وكيف تستفيد من هذا الجزء في الكود البرمجي وان كانت الإجابة بلا فإليك التفصيل .



الــ Exception :
هو جزء او Block له نقطة بداية ونقطة نهاية
نقطة بداية

Exception


'Handel error'
نقطة نهايةEnd;


ويكون موجود في نهاية جزء تنفيذي لغرض معالجة الأخطى المتوقعة والغير متوقعة

Begin


جزء تنفيذي Execution part
Exception
معالجة الخطاء المتوقع والغير متوقع في الجزء التنفيذي 'Handel error'
End;




ويتم تنفيذ الكود الموجود في جزء معالجة الأخطاء فقط عند اجبار البرنامج على الذهاب الى قسم معالجة الأخطى عن طريق الامر Raise او في حالة حصول خطاء منطقي .

للتوضيح خذ المثال التالي :

(المثال عبارة عن فنكشن نمرر لها رقم الموظف وتعطينا اسم الموظف إعتماداً على جدول الموظفين الموجود في المستخدم الإفتراضيSCOTT )

create or replace function Get_emp_name(p_empno emp.empno%type) return  varchar2
is
l_ename emp.ename%type;
l_result emp.ename%type;
begin
if p_empno is null Then 
  raise_application_error(-20001,'لم يتم العثور على رقم الموظف');
end if;
select ename into l_ename 
from emp 
where empno =p_empno;
return l_ename;
Exception
  when others then 
	raise_application_error(-20001,'Error in get_Emp_name  :' || sqlerrm); 
end;


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

1- في حالة إجبار البرنامج على الذهاب الى جزء معالجة الأخطاء :
لاحظ جملة الشرط الموجودة مباشرة بعد كلمة Begin والتي تقضي الى اجبار البرنامج على الذهاب الى جزء معالجة الأخطاء بمجرد اكتشاف ان رقم الموظف ( والذي يعتبر مفاح اساسي لارجاع الاسم في هذه الفنكشن ) غير موجود اعتقد انه من المنطقي جداً انهاء الإجراء وإعطاء المستخدم رسالة توضح سبب انهاء الإجراء , وهذا ماسيحصل في حالة استدعاء الفنكشن وتمرير قيمة null لرقم الموظف .
لإثبات مانقول دعنا ننشى شاشة بالدفلوبر تحوي push_button وتحت الحدث when-button-pressed اكتب هذا الكود ثم نفذ .

declare
l_name varchar2(200);
begin
	l_name := get_emp_name(null);
	message(l_name);
exception
  when others Then 
message(sqlerrm);
end;


هذا الخطاء كان متوقعاً (ان يتم تمرير قيمة فارغة لرقم الموظف )لذلك عملت على معالجته واضهرت الرسالة المناسبة للمستخدم . اما اذا كان الخطاء غير متوقع فان الكود الموجود في قسم معالجة الأخطاء (sqlerrm) سوف يظهر رسالة توضح سبب الخطاء .

2- في حالة حصول خطاء منطقي :
لو ان خطاء منطقي حصل في البرنامج كان يتم تنفيذ جملة Select تؤدي الى ارجاع اكثر من سجل او ارجاع صفر سجل (سب وان تحدثنا عن هذا الموضوع في درس الCursor ) فان الPL/SQL سوف تذهب مباشرة الى قسم الأخطاء للبحث عن كود يعالج الخطاء .
مثلاً لو مررنا رقم موظف غير موجود اصلا في الجدول , فان جملة الSelect سوف ترجع صفر سجلات وهذا خطاء منطقي سوف يؤدي الى الانتقال مباشرة الى قسم معالجة الأخطى واعطاء الرسالة التي توضح ذلك .

declare
l_name varchar2(200);
begin
	l_name := get_emp_name(999999);
	message(l_name);
exception
  when others Then 
message(sqlerrm);
end;



12. متى يستخدم الـ Exception :
انا شخصياً افضل استخدام الException في معظم الإجراءات سواً كانت على مستوى قاعدة البيانات (Back-End ) او على مستوى الواجهات (Front-End ) والسبب هو ان يتم التوقف عند كل خطاء متوقع او غير متوقع لمعرفة سبب الخطاء ومعالجته . ولكن هذا لايعني ان اعمل exception في كل الإجراءات على الاطلاق فبعض الإجرات قد تكون اجراءات من المستحيل ان تحوي اخطاء وذلك بسبب طريقة كتابتها , او ان بعض الإجراءات تكون اجراءات فرعية او خاصة Private يتم الوصل اليها عن طريق اجراءات عامة Public , وفي هذه الحالة نستطيع ان نعالج الخطاء في الإجراء العام . هذا ماسنتطرق الي في النقطه رقم 3 (رمي الخطاء الى الإجراء العام او معالجته في الإجراء الحالي) انشاء الله .

2- مامعنى معالجة الاخطاء وماالفرق بين الاكواد التي تحوي جزء معالجة الأخطاء والتي لا تحيوي

معالجة الخطى لا تعني التغلب على الخطاء وجعل البرنامج يعمل وكأن شي لم يحصل , لان الException هو في الاساس جزء من الكود يستفاد منه لمعالجة الأخطاء التي لا يستطيع المبرمج التنبى بها او التي غفل عنها , والدور الاكبر لمعالجة الاخطاء ليس من مهمة الException part الموجود في الكود البرمجي , بل يكمن الدور الاساسي لتفادي الأخطاء على المبرمج نفسه , فيجب ان يحرص كل الحرص على كتابة الكود بصورة تمنع وجود اي شؤائب او اخطاء متوقعة او غير متوقعة في الكود (كفحص القيم والتأكد من سلامتها قبل استخدامها في اي عملية داخل الكود , وكذلك التأكد من سلامة ووجود كل المدخلات اللازمة والتي يحتاجها الكود حتى ينفذ بصورة سلسة وسليمة ) , ومابقي والتي لا تستطيع ان تحصرها يأتي دور الException part في التعامل معها وليس معالجتها بصورة نهائية .

صور معالجة الاخطاء
تأتي صور معالجة الأخطاء بأشكال مختلفة وغير محصورة ’ وذلك يعتمد على طبيعة الخطاء والكود البرمجي الذي ظهر فيه الخطاء ولكن معظم الException Part تحوي او تعطي رسائل للبيئة التي استدعت الكود موضحة فيها سبب الخطاء ومكان او اسم الكود الذي تسبب في الخطاء واي بيانات اخرى كمصدر الخطاء هل هو قاعدة البيانات او الشاشات .

مثال : (تستخدم هذه الفنكشن لاعطاء نتيجة عملية حسابية بين رقمين )

create or replace function my_calc(p_num1 number, p_num2 number , p_opr char :='+') return  number
is
l_Result number(4);
l_num1 number(2);
l_num2 number(2);
begin
 l_num1:=p_num1;
 l_num2:=p_num2;
 if p_opr ='-' Then 
l_Result := l_num1 - l_num2;
 elsif p_opr='*' Then 
l_Result := l_num1 * l_num2;
 elsif p_opr='/' Then 
l_Result := l_num1 / l_num2;
 else
l_Result := l_num1 + l_num2;
 end if;
 return(l_Result);
 exception 
	   when others then   
			raise_application_error(-20001,'Error in my_calc ' || sqlerrm);
end my_calc;




لو نلاحظ ان طبيعة المعالجة في هذا المثال هي عبارة عن رسالة توضيحية فقط توضح سبب الخطاء واسم الفنكشن التي حصل فيها الخطاء . ولكن قد يأتي مبرمج أخر ويقول اني سوف اضيف كود اضافي في الـException Part وذلك تسجيل رسالة الخطاء ووقت حدوث الخطاء ومن هو المستخدم الذي تسبب في ظهور الخطاء (وهذا شكل اخر من اشكال معالجة الخطاء) , واليك المثال السابق بعد التعديل

create or replace function my_calc(p_num1 number, p_num2 number , p_opr char :='+') return  number
is
l_Result number(4);
l_num1 number(2);
l_num2 number(2);
l_error_txt varchar2(200);
begin
 l_num1:=p_num1;
 l_num2:=p_num2;
 if p_opr ='-' Then 
l_Result := l_num1 - l_num2;
 elsif p_opr='*' Then 
l_Result := l_num1 * l_num2;
 elsif p_opr='/' Then 
l_Result := l_num1 / l_num2;
 else
l_Result := l_num1 + l_num2;
 end if;
 return(l_Result);
 exception 
	   when others then   
	   l_error_txt :=sqlerrm;
			insert into error_log values  (user,sysdate,l_error_txt);
			commit;
			raise_application_error(-20001,'Error in my_calc ' || sqlerrm);
end my_calc;


نفذ الفنكشن وحاول ادخال القيم التالية كمعطيات للفنكشن
[font=Tahoma]
1- my_calc(1,1) تنفيذ بدون مشاكل
2- my_calc(1,0,'/') خطاء قسمة على صفر
بعد التنفيذ واعطاء القيم الموضحه في الحالة رقم 2 سوف تلاحظ ظهور راسلة خطاء وفي نفس الوقت تسجيل معلومات الخطاء في الجدول (error_log )

ملاحظه :
يجب انشاء الجدول error_log قبل انشاء وتنفيذ الفنكشن الموضحه في المثال .
[/font]
الفرق بين الاكواد التي تعالج الأخطاء والتي لا تعالج الاخطاء
قد يؤدي الكود الذي يحوي خطاء والذي لم يتم معالجته في اي مرحلة من مراحل التنفيذ الى سلوك غير متوقع في النظام (إنهاء التنفيذ كلياً) كما ان الاكواد التي لا تحوي اجزاء معالجة الاخطاء تؤدي على تعقيد مهمة المطور او المبرمج في متابعة الكود ومعرفة الجزئية التي تسببت في حدوث الخطاء في البرنامج (لان وفي حالات كثيرة تجد ان package او الFunction او الProcedure يعمل على استدعاء كود او subroutine اخر وهذا الsubroutine قد ستدعي اخر وهكذا) فعندما يحصل اي خطاء في subroutine معين ولم يتم معالجه الخطاء داخل الsubroutine فانه سوف يحالو معالجته في الsubroutine الاب وهكذا الى ان يصل الى اخر نقطه في طبقات التنفيذ وهنا تظهر رساله للمستخدم او المطور يخبره بوجود خطاء غير معالج (اين حصل الخطاء وماهو هذه الخطاء وما الذي سبب الخطاء ؟ والإجابه غير معوف والسبب هو عدم معالجه الخطاء ) هذا هو الفرق بين الاكواد التي تعالج الأخطاء والتي لا تعالج .
إذا من الان وصاعداً يجب ان ننتبه لهذة الجزئية المهمة اثناء كتابة الاكواد البرمجية .

تم تعديل بواسطة khaled
رابط هذا التعليق
شارك

السلام عليكم؟

أستاذنا الكبير كلامك أكثر من رائع ونحب نشوفك أكثر يا أستاذي الفاضل...

رابط هذا التعليق
شارك

  • بعد 2 أسابيع...
  • بعد 2 شهور...
  • بعد 1 سنة...

أرجوا المساعدة

انا لاادرى هل اعمل الفانكشن على مستوى الداتا بيز ام على مستوى الفورم

رجاء اريد تنفيذ هذه الفانكشن عملى على فورم حتى احس بكيفية معالجه الاخطاء

وجزاكم الله خير

رابط هذا التعليق
شارك

انضم إلى المناقشة

يمكنك المشاركة الآن والتسجيل لاحقاً. إذا كان لديك حساب, سجل دخولك الآن لتقوم بالمشاركة من خلال حسابك.

زائر
أضف رد على هذا الموضوع...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   تمت استعادة المحتوى السابق الخاص بك.   مسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

جاري التحميل
×
×
  • أضف...

برجاء الإنتباه

بإستخدامك للموقع فأنت تتعهد بالموافقة على هذه البنود: سياسة الخصوصية