Oracle
 sql >> डेटाबेस >  >> RDS >> Oracle

Oracle 18c और 19c . में ड्रॉप कॉलम बग को संबोधित करना

प्रगति की राह कभी-कभी कठिन हो सकती है। Oracle संस्करण 18 और 19 कोई अपवाद नहीं हैं। संस्करण 18.x तक Oracle में स्तंभों को अप्रयुक्त के रूप में चिह्नित करने और अंततः उन्हें छोड़ने में कोई समस्या नहीं थी। कुछ दिलचस्प परिस्थितियों को देखते हुए, नवीनतम दो Oracle संस्करण ORA-00600 त्रुटियों को फेंक सकते हैं जब कॉलम को अप्रयुक्त के रूप में सेट किया जाता है और फिर गिरा दिया जाता है। यह त्रुटि उत्पन्न करने वाली स्थितियां सामान्य नहीं हो सकती हैं, लेकिन दुनिया भर में बड़ी संख्या में Oracle संस्थापन हैं और यह बहुत संभव है कि कोई व्यक्ति, कहीं न कहीं, इस बग का सामना करेगा।

कहानी दो टेबल और एक ट्रिगर से शुरू होती है:

create table trg_tst1 (c0 varchar2(30), c1 varchar2(30), c2 varchar2(30), c3 varchar2(30), c4 varchar2(30));
create table trg_tst2 (c_log varchar2(30));

create or replace trigger trg_tst1_cpy_val
after insert or update on trg_tst1
for each row
begin
        IF :new.c3 is not null then
                insert into trg_tst2 values (:new.c3);
        end if;
end;
/

डेटा तालिका TRG_TST1 में डाला गया है और, बशर्ते कि शर्तें पूरी हों, डेटा TRG_TST2 तालिका में दोहराया गया है। TRG_TST1 में दो पंक्तियाँ डाली जाती हैं ताकि सम्मिलित पंक्तियों में से केवल एक को TRG_TST2 में कॉपी किया जा सके। प्रत्येक सम्मिलित तालिका के बाद TRG_TST2 पूछताछ की जाती है और परिणाम प्रदर्शित होते हैं:

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c3) values ('Inserting c3 - should log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c4) values ('Inserting c4 - should not log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 

अब 'मज़ा' शुरू होता है - TST_TRG1 में दो स्तंभों को 'अप्रयुक्त' के रूप में चिह्नित किया जाता है और फिर गिरा दिया जाता है, और तालिका TST_TRG2 को छोटा कर दिया जाता है। TST_TRG1 में इन्सर्ट को फिर से निष्पादित किया जाता है, लेकिन इस बार खतरनाक ORA-00600 त्रुटियां उत्पन्न होती हैं। यह देखने के लिए कि ये त्रुटियां क्यों होती हैं, USER_OBJECTS से ट्रिगर की स्थिति की सूचना दी जाती है:

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > --  Drop some columns in two steps then
SMERBLE @ gwunkus > --  truncate trg_tst2 and repeat the test
SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > --  ORA-00600 errors are raised
SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > --  The trigger is not invalidated and
SMERBLE @ gwunkus > --  thus is not recompiled.
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > alter table trg_tst1 set unused (c1, c2);

Table altered.

SMERBLE @ gwunkus > alter table trg_tst1 drop unused columns;

Table altered.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > select object_name, status from user_objects where object_name in (select trigger_name from user_triggers);


OBJECT_NAME                         STATUS
----------------------------------- -------
TRG_TST1_CPY_VAL                    VALID

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > truncate table trg_tst2;

Table truncated.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c3) values ('Inserting c3 - should log');

insert into trg_tst1(c3) values ('Inserting c3 - should log')
            *
ERROR at line 1:
ORA-00600: internal error code, arguments: [insChkBuffering_1], [4], [4], [], [], [], [], [], [], [], [], []


SMERBLE @ gwunkus > select * from trg_tst2;

no rows selected

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c4) values ('Inserting c4 - should not log');

insert into trg_tst1(c4) values ('Inserting c4 - should not log')
            *
ERROR at line 1:
ORA-00600: internal error code, arguments: [insChkBuffering_1], [4], [4], [], [], [], [], [], [], [], [], []


SMERBLE @ gwunkus > select * from trg_tst2;

no rows selected

SMERBLE @ gwunkus > 

मुद्दा यह है कि, Oracle 18c और 19c में, 'अप्रयुक्त कॉलम ड्रॉप करें' कार्रवाई ट्रिगर को 'VALID' स्थिति में छोड़ने और विफलता के लिए अगले लेनदेन को सेट करने को अमान्य नहीं करती है। चूंकि ट्रिगर को अगली कॉल पर पुन:संकलित नहीं किया गया था, मूल संकलन वातावरण अभी भी प्रभावी है, एक ऐसा वातावरण जिसमें अब-गिराए गए कॉलम शामिल हैं। Oracle कॉलम C1 और C2 नहीं ढूंढ सकता है, लेकिन ट्रिगर अभी भी उनके मौजूद होने की उम्मीद कर रहा है, इस प्रकार ORA-00600 त्रुटि। माई ओरेकल सपोर्ट इसे एक बग के रूप में रिपोर्ट करता है:

Bug 30404639 : TRIGGER DOES NOT WORK CORRECTLY AFTER ALTER TABLE DROP UNUSED COLUMN.

और रिपोर्ट करता है कि इसका कारण, वास्तव में, आस्थगित कॉलम ड्रॉप के साथ ट्रिगर को अमान्य करने में विफलता है।

तो इस मुद्दे से कैसे निपटें? एक तरीका यह है कि अप्रयुक्त स्तंभों को छोड़ने के बाद ट्रिगर को स्पष्ट रूप से संकलित किया जाए:

SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > -- Compile the trigger after column drops
SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > alter trigger trg_tst1_cpy_val compile;

Trigger altered.

SMERBLE @ gwunkus > 

ट्रिगर के साथ अब वर्तमान परिवेश और तालिका कॉन्फ़िगरेशन का उपयोग करते हुए इंसर्ट सही ढंग से कार्य करता है और ट्रिगर अपेक्षित रूप से सक्रिय होता है:

SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > -- Attempt inserts again
SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > insert into trg_tst1(c3) values ('Inserting c3 - should log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c4) values ('Inserting c4 - should not log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
. लॉग करना चाहिए

इस मुद्दे को हल करने का एक और तरीका मौजूद है; कॉलम को अप्रयुक्त के रूप में चिह्नित न करें और बस उन्हें तालिका से हटा दें। मूल तालिकाओं को छोड़ना, उन्हें फिर से बनाना और सीधे कॉलम ड्रॉप के साथ इस उदाहरण को निष्पादित करना ORA-00600 का कोई संकेत नहीं दिखाता है, और कॉलम ड्रॉप के बाद ट्रिगर स्थिति यह साबित करती है कि ऐसी कोई त्रुटि नहीं डाली जाएगी:

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > drop table trg_tst1 purge;

Table dropped.

SMERBLE @ gwunkus > drop table trg_tst2 purge;

Table dropped.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > --  Re-run the example without marking
SMERBLE @ gwunkus > --  columns as 'unused'
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > create table trg_tst1 (c0 varchar2(30), c1 varchar2(30), c2 varchar2(30), c3 varchar2(30), c4 varchar2(30));

Table created.

SMERBLE @ gwunkus > create table trg_tst2 (c_log varchar2(30));

Table created.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > create or replace trigger trg_tst1_cpy_val
  2  after insert or update on trg_tst1
  3  for each row
  4  begin
  5  	     IF :new.c3 is not null then
  6  		     insert into trg_tst2 values (:new.c3);
  7  	     end if;
  8  end;
  9  /

Trigger created.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c3) values ('Inserting c3 - should log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c4) values ('Inserting c4 - should not log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > --  Drop some columns,
SMERBLE @ gwunkus > --  truncate trg_tst2 and repeat the test
SMERBLE @ gwunkus > --
SMERBLE @ gwunkus > --  No ORA-00600 errors are raised as
SMERBLE @ gwunkus > --  the trigger is invalidated by the
SMERBLE @ gwunkus > --  DDL.  Oracle then recompiles the
SMERBLE @ gwunkus > --  invalid trigger.
SMERBLE @ gwunkus > --  ===================================
SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > alter table trg_tst1 drop (c1,c2);

Table altered.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > select object_name, status from user_objects where object_name in (select trigger_name from user_triggers);

OBJECT_NAME                         STATUS
----------------------------------- -------
TRG_TST1_CPY_VAL                    INVALID

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > truncate table trg_tst2;

Table truncated.

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c3) values ('Inserting c3 - should log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 
SMERBLE @ gwunkus > insert into trg_tst1(c4) values ('Inserting c4 - should not log');

1 row created.

SMERBLE @ gwunkus > select * from trg_tst2;

C_LOG
------------------------------
Inserting c3 - should log

SMERBLE @ gwunkus > 

18c से पहले के Oracle संस्करण अपेक्षित व्यवहार करते हैं, आस्थगित कॉलम ड्रॉप सही ढंग से ट्रिगर स्थिति को 'INVALID' पर सेट करता है:

SMARBLE @ gwankus > select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE	12.1.0.2.0	Production
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production

SMARBLE @ gwankus >
SMARBLE @ gwankus > alter table trg_tst1 set unused (c1, c2);

Table altered.

SMARBLE @ gwankus > alter table trg_tst1 drop unused columns;

Table altered.

SMARBLE @ gwankus >
SMARBLE @ gwankus > select object_name, status from user_objects where object_name in (select trigger_name from user_triggers);

OBJECT_NAME			    STATUS
----------------------------------- -------
TRG_TST1_CPY_VAL		    INVALID

SMARBLE @ gwankus >

18c से पुराने संस्करणों में कॉलम कैसे गिराए जाते हैं, इससे कोई फर्क नहीं पड़ता क्योंकि प्रभावित टेबल पर कोई भी ट्रिगर अमान्य हो जाएगा। उस तालिका पर किसी भी ट्रिगर के लिए अगली कॉल के परिणामस्वरूप एक 'स्वचालित' पुनर्संकलन होगा, निष्पादन वातावरण को ठीक से सेट करना (मतलब प्रभावित तालिका में अनुपलब्ध कॉलम निष्पादन के संदर्भ में नहीं रहेंगे)।

यह संभावना नहीं है कि एक उत्पादन डेटाबेस DEV या TST डेटाबेस में पहले इस तरह के बदलाव किए बिना कॉलम ड्रॉप्स से गुजरेगा। दुर्भाग्य से कॉलम गिराए जाने के बाद परीक्षण सम्मिलन एक परीक्षण नहीं हो सकता है जो इस तरह के परिवर्तन किए जाने के बाद और कोड को पीआरडी में प्रचारित करने से पहले निष्पादित किया जाता है। कॉलम छोड़ने के बाद के प्रभावों का परीक्षण करने वाले एक से अधिक व्यक्ति एक उत्कृष्ट विचार प्रतीत होते हैं, क्योंकि पुरानी कहावत प्रमाणित करती है, 'दो सिर एक से बेहतर होते हैं।' परीक्षण की स्थिति में जितना अधिक बेहतर होगा ताकि कई रास्ते हों संभावित विफलता को प्रस्तुत और निष्पादित किया जा सकता है। किसी बदलाव को और अच्छी तरह से परखने में लगने वाले अतिरिक्त समय का मतलब है कि अप्रत्याशित त्रुटियों के गंभीर रूप से प्रभावित होने या उत्पादन को रोकने की संभावना कम है।

# # #

डेविड फिट्ज़जारेल . के लेख देखें


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. शीर्ष 9 उपयोगी Oracle ऐप्स प्रिंटर प्रश्न

  2. Oracle में SYSDATE फ़ंक्शन

  3. SQL डेवलपर 4.0 का विमोचन

  4. मैं डायनेमिक SQL में DDL/SCL स्टेटमेंट में बाइंड वेरिएबल्स का उपयोग क्यों नहीं कर सकता?

  5. Oracle में किसी तालिका को अद्यतन करना यदि कोई फ़ील्ड मान शून्य है और यह निर्धारित करना कि अद्यतन सफल है