Oracle ve PostgreSQL'de farklı varsayılan hata işleme

Dec 17 2020

Bir PL / SQL (PL / pgSQL) kodunda bir hatayla karşılaştıktan sonra Oracle ve PostgreSQL'in varsayılan davranışını karşılaştırıyorum. Bu amaçla, aşağıda gösterilen benzer bir Oracle ve PostgreSQL kodu yazdım.

Oracle kodu ( db <> keman ):

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 kodu ( db <> keman ):

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;

Not: PostgreSQL'de ek olarak BEGIN TRANSACTIONotomatik kesinlemeyi devre dışı bırakmak için ifadeyi çalıştırıyorum çünkü Oracle'da otomatik kesinleştirme yok ve her iki kodun da benzer olmasını istiyorum.

SELECT * FROM table1Sorgunun sonucu Oracle'da bir satırdır ve PostgreSQL'de satır yoktur.

Gördüğünüz gibi Oracle ve PostgreSQL'deki analog kod farklı sonuçlar veriyor. Varsayılan hata işlemedeki bu farkın nedeni nedir?

Yanıtlar

2 LaurenzAlbe Dec 17 2020 at 21:40

Oracle ve PostgreSQL gerçekten burada farklı davranır.

Oracle, "ifade düzeyinde geri alma" olarak adlandıracağım bir şeye sahiptir: bir işlem içinde çalışan bir ifade bir hataya neden olursa, yalnızca bu ifadenin etkileri geri alınır ve işlem devam eder.

PostgreSQL'de, bir işlemdeki herhangi bir hata, tüm işlemi iptal eder, bu nedenle işlemi yalnızca geri alabilirsiniz ve hiçbir etkisi yoktur. Bu daha çok “ya hep ya hiç” ruhu içinde, ama görebildiğim kadarıyla, SQL standardı bu konuya özel değil, bu yüzden her iki davranış da tartışılabilir.

Bununla birlikte, bir işlemdeki bir hatayı "kurtarmak" için PostgreSQL'de standart uyumlu kayıt noktalarını kullanabilirsiniz:

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;

Ancak işlem başına çok fazla kayıt noktası (64'ten fazla değil) kullanmadığınız konusunda uyarıda bulunun , aksi takdirde performans düşebilir.

1 MT0 Dec 17 2020 at 21:24

Oracle'da iki ayrı işlem kullanıyorsunuz, ilki başarılı ancak ikincisi başarısız oluyor. PostgreSQL'de, ona açıkça yalnızca bir işlemi kullanmasını ve ifadeleri birlikte ele almasını söylüyorsunuz.

Oracle'da, ifadeleri tek bir işlemde gruplamak için bir PL / SQL anonim bloğu kullanıyorsanız:

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

Ve aynı şekilde PostgreSQL'de:

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

Bu durumda, prosedürdeki istisna tüm işlemi geri alacağından tabloda satır olmayacaktır.


Veya Oracle'da şunları yapabilirsiniz:

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;
/

Bu, her iki işlemi de son kesinliğe geri almakla aynı etkiye sahip olacaktır.

db <> Oracle PostgreSQL keman