Oracle और PostgreSQL में विभिन्न डिफ़ॉल्ट त्रुटि हैंडलिंग

Dec 17 2020

मैं PL / SQL (PL / pgSQL) कोड में त्रुटि का सामना करने के बाद Oracle और PostgreSQL के डिफ़ॉल्ट व्यवहार की तुलना करता हूं। इस उद्देश्य के लिए, मैंने नीचे दिखाया गया एक अनुरूप ओरेकल और पोस्टग्रेक्यूएल कोड लिखा है।

Oracle कोड ( db <> fiddle ):

CREATE TABLE table1 (col1 int);

CREATE PROCEDURE raise_error AS
BEGIN
  INSERT INTO table1 VALUES (1/0);
END;
/

INSERT INTO table1 VALUES (1);
CALL raise_error();
COMMIT;
SELECT * FROM table1;

PostgreSQL कोड ( db <> फ़िडल ):

CREATE TABLE table1 (col1 int);

CREATE PROCEDURE raise_error() AS $$ BEGIN INSERT INTO table1 VALUES (1/0); END; $$ LANGUAGE plpgsql;

BEGIN TRANSACTION; -- disable auto-commit

INSERT INTO table1 VALUES (1);
CALL raise_error();
COMMIT;
SELECT * FROM table1;

नोट: PostgreSQL में मैं अतिरिक्त रूप BEGIN TRANSACTIONसे ऑटो-कमिट को अक्षम करने के लिए स्टेटमेंट चलाता हूं , क्योंकि ओरेकल में ऑटो-कमिट नहीं है, और मैं चाहता हूं कि दोनों कोड अनुरूप हों।

SELECT * FROM table1क्वेरी का परिणाम Oracle में एक पंक्ति है, और PostgreSQL में कोई पंक्तियाँ नहीं हैं।

जैसा कि आप देख सकते हैं, Oracle और PostgreSQL में अनुरूप कोड अलग-अलग परिणाम देता है। डिफ़ॉल्ट त्रुटि हैंडलिंग में इस अंतर का कारण क्या है?

जवाब

2 LaurenzAlbe Dec 17 2020 at 21:40

Oracle और PostgreSQL वास्तव में यहाँ अलग तरह से व्यवहार करता है।

ओरेकल के पास कुछ ऐसा है जिसे मैं "स्टेटमेंट-लेवल रोलबैक" कहूंगा: यदि लेन-देन के अंदर चलने वाले स्टेटमेंट में त्रुटि होती है, तो केवल उस स्टेटमेंट के प्रभाव वापस आ जाते हैं, और लेन-देन जारी रहता है।

PostgreSQL में, एक लेनदेन के अंदर कोई भी त्रुटि पूरे लेनदेन को रोकती है, इसलिए आप केवल लेन-देन वापस कर सकते हैं, और इसका कोई प्रभाव नहीं पड़ता है। यह "सभी या कुछ नहीं" की भावना में अधिक है, लेकिन जहां तक ​​मैं देख सकता हूं, एसक्यूएल मानक इस बारे में विशिष्ट नहीं है, इसलिए दोनों व्यवहारों का तर्क दिया जा सकता है।

हालाँकि, आप किसी लेनदेन में त्रुटि से "पुनर्प्राप्त" करने के लिए PostgreSQL में मानक अनुरूप बचत बिंदुओं का उपयोग कर सकते हैं:

START TRANSACTION;

INSERT INTO table1 VALUES (1);

/* set a savepoint we can revert to */
SAVEPOINT x;

CALL raise_error();

ROLLBACK TO SAVEPOINT x;

/* now the INSERT can be committed */
COMMIT;

लेकिन चेतावनी दी जाती है कि आप प्रति लेनदेन बहुत अधिक बचत (64 से अधिक नहीं) का उपयोग नहीं करते हैं , अन्यथा प्रदर्शन को भुगतना पड़ सकता है।

1 MT0 Dec 17 2020 at 21:24

ओरेकल में आप दो अलग-अलग लेनदेन का उपयोग कर रहे हैं, पहला सफल है लेकिन दूसरा विफल है। PostgreSQL में, आप स्पष्ट रूप से केवल एक लेनदेन का उपयोग करने और बयानों को एक साथ संभालने के लिए कह रहे हैं।

ओरेकल में, यदि आप पीएल / एसक्यूएल बेनामी ब्लॉक का उपयोग स्टेटमेंट को सिंगल ट्रांजेक्शन में करने के लिए करते हैं:

BEGIN
  INSERT INTO table1 VALUES (1);
  raise_error();
END;
/

और, PostgreSQL में समान रूप से:

DO
$$ BEGIN INSERT INTO table1 VALUES (1); CALL raise_error(); END; $$ LANGUAGE plpgsql;

तब तालिका में कोई पंक्तियाँ नहीं होंगी क्योंकि प्रक्रिया से अपवाद पूरे लेनदेन को रोलबैक करेगा।


या, Oracle में, आप कर सकते हैं:

INSERT INTO table1 VALUES (1);

DECLARE
  divide_by_zero EXCEPTION;
  PRAGMA EXCEPTION_INIT( divide_by_zero, -1476 );
BEGIN
  raise_error();
EXCEPTION
  WHEN DIVIDE_BY_ZERO THEN
    ROLLBACK;
END;
/

जो अंतिम लेनदेन के लिए दोनों लेनदेन को वापस करने का समान प्रभाव होगा।

db <> fiddle Oracle PostgreSQL