मेरे पास एक नई परियोजना है जिस पर मैं काम कर रहा हूं, जहां मैं एक Oracle नौकरी रद्द करना चाहता हूं जो मैंने आईटी कर्मचारियों को दिए हैं जो 30 दिनों से अधिक पुराने हैं। समस्याओं के निवारण के लिए हमारे आईटी कर्मचारियों को कुछ उत्पादन तालिकाओं तक कभी-कभार पहुंच की आवश्यकता होती है। हम उन टेबल पर SELECT privs प्रदान करते हैं जिनकी व्यक्ति को आवश्यकता होती है, लेकिन कोई भी मुझे कभी नहीं बताता कि वे अपने कार्य के साथ कब हो जाते हैं और वे विशेषाधिकार हमेशा के लिए बाहर बैठ जाते हैं। मैं चाहता था कि एक सिस्टम स्वचालित रूप से 30 दिनों से अधिक पुराने विशेषाधिकारों को रद्द कर दे ताकि मुझे इसे करने के लिए याद न रखना पड़े। इससे पहले कि मैं विशेषाधिकारों को रद्द कर पाता, मुझे उन विशेषाधिकारों को ट्रैक करने का एक तरीका चाहिए था। इसलिए मैंने एक ट्रिगर बनाया जो अनुदान जारी होने पर निकाल दिया जाता है और विवरण को तालिका में लॉग करता है। बाद में, Oracle जॉब उस तालिका को स्कैन करेगा और उन विशेषाधिकारों को रद्द कर देगा जो बहुत पुराने हैं। मेरा ट्रिगर कोड इस प्रकार है:
create or replace trigger sys.grant_logging_trig after grant on database declare priv dbms_standard.ora_name_list_t; who dbms_standard.ora_name_list_t; npriv pls_integer; nwho pls_integer; begin npriv := ora_privilege_list(priv); if (ora_sysevent = 'GRANT') then nwho := ora_grantee(who); else nwho := ora_revokee(who); end if; for i in 1..npriv loop for j in 1..nwho loop insert into system.grant_logging values ( systimestamp, ora_login_user, ora_sysevent, who(j), priv(i), ora_dict_obj_owner, ora_dict_obj_name ); end loop; end loop; end; /
उपरोक्त कोड मूल नहीं है। मुझे इंटरनेट पर एक अच्छा उदाहरण मिला और कुछ चीजों को संशोधित किया। 3 सप्ताह के लिए कोड का परीक्षण करने के बाद, मैंने ट्रिगर को उत्पादन में रोल किया। मुझे एक त्रुटि प्राप्त करने में केवल कुछ दिन लगे।
SQL> CREATE USER bob IDENTIFIED BY password; ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-04088: error during execution of trigger 'SYS.GRANT_LOGGING_TRIG' ORA-00604: error occurred at recursive SQL level 2 ORA-06502: PL/SQL: numeric or value error ORA-06512: at line 28पर
हमम...मैं एक उपयोगकर्ता बना रहा हूं जो कुछ भी नहीं दे रहा है। लेकिन हम निश्चित रूप से देख सकते हैं कि मेरे ट्रिगर को निष्पादित करने में समस्या हो रही है। तो यह ट्रिगर फायरिंग क्यों कर रहा है अगर मैं केवल एक उपयोगकर्ता बना रहा हूं? एक साधारण एसक्यूएल ट्रेस ने मुझे दिखाया कि उस रिकर्सिव एसक्यूएल के साथ क्या हो रहा था। परदे के पीछे, Oracle मेरी ओर से निम्नलिखित जारी कर रहा है:
जनता को "बॉब" उपयोगकर्ता पर विरासत में मिले विशेषाधिकार प्रदान करें;
ठीक है ... तो इस बिंदु पर, मुझे पता है कि जब मैं एक उपयोगकर्ता बनाता हूं तो एक अनुदान जारी किया जा रहा है लेकिन यह विफल क्यों हो रहा है? मैंने इस ट्रिगर को सिस्टम विशेषाधिकारों के साथ परीक्षण किया और यह ठीक काम किया। दी, मैंने INHERIT PRIVILEGES का परीक्षण नहीं किया, इसलिए यह एक किनारे का मामला है।
डिबगिंग प्रयासों की एक अच्छी मात्रा के बाद, मैंने निर्धारित किया कि ora_privilege_list फ़ंक्शन कॉल "निजी" नामक संग्रह में एक खाली सेट लौटा रहा है। जैसे, npriv एक NULL मान पर सेट हो रहा है। क्योंकि एनपीआरआईवी न्यूल है, जहां "फॉर आई इन 1..एनप्रिव" लिखा है, वह लाइन ज्यादा मायने नहीं रखती है, इसलिए त्रुटि।
मेरी राय में, ora_privilege_list को एक आइटम, "इनहेरिट PRIVILEGES" वापस करना चाहिए और मेरा मानना है कि यह उस सूची को बग के रूप में वापस नहीं कर रहा है। हालांकि, अगर ora_privilege_list एक खाली संग्रह वापस करने जा रहा है, तो फ़ंक्शन से आउटपुट शून्य होना चाहिए और फिर npriv को अधिक उचित मूल्य मिलेगा। शिक्षा के उद्देश्य से, ora_privilege_list DBMS_STANDARD.PRIVILEGE_LIST का पर्याय है।
यह सब कहा जा रहा है, मैं Oracle फ़ंक्शन को नियंत्रित नहीं कर सकता। और मैं ओरेकल के लिए DBMS_STANDARD में अपना कोड बदलने के लिए इंतजार नहीं करना चाहता जो मुझे लगता है कि यह होना चाहिए। तो मैं इस मुद्दे को संभालने के लिए सिर्फ अपने ट्रिगर को कोड करूंगा। दो सरल पंक्तियों को जोड़ने से मेरी समस्या हल हो गई (नीचे बोल्ड में देखा गया)।
create or replace trigger sys.grant_logging_trig after grant on database declare priv dbms_standard.ora_name_list_t; who dbms_standard.ora_name_list_t; npriv pls_integer; nwho pls_integer; begin npriv := ora_privilege_list(priv); if (ora_sysevent = 'GRANT') then nwho := ora_grantee(who); else nwho := ora_revokee(who); end if; if to_char(npriv) is not null then for i in 1..npriv loop for j in 1..nwho loop insert into system.grant_logging values ( systimestamp, ora_login_user, ora_sysevent, who(j), priv(i), ora_dict_obj_owner, ora_dict_obj_name ); end loop; end loop; end if; end; /
तो फिक्स बहुत आसान है। यदि एनपीआरआईवी शून्य नहीं है, तो केवल दो फॉर लूप निष्पादित करें।