Обсуждение: Controling Rule's Firing Order

Поиск
Список
Период
Сортировка

Controling Rule's Firing Order

От
Дата:
Hello!

I have seen in TODO saying that "Allow user to
control trigger firing order" will be added to
version 7.3. This is an extremely good news to me.

I would like to ask two question related to this new
feature:

(Q1) Are we going to be able to control the firing
order for rule too? That is, controling the rule to
be fired before or after some specific triggers?

(Q2) Is there any existing document for version 7.3
explaining how to control the trigger firing order?

My best regards to pgsql developers,

CN

--------------------------------------------------------
You too can have your own email address from Eurosport.
http://www.eurosport.com






Re: Controling Rule's Firing Order

От
Tom Lane
Дата:
<cnliou@eurosport.com> writes:
> (Q2) Is there any existing document for version 7.3
> explaining how to control the trigger firing order?

Rules and triggers both fire in alphabetical order in 7.3.

            regards, tom lane

Re: Controling Rule's Firing Order

От
Дата:
Thank you very much! Tom,

I forgot to raise another question:

Does foreign key constraints also fire in
alphabetical order in 7.3?

Regards,

CN


> Rules and triggers both fire in alphabetical order
in 7.3.

--------------------------------------------------------
You too can have your own email address from Eurosport.
http://www.eurosport.com






Re: Controling Rule's Firing Order

От
Дата:
Please pardon me for having not asked the questions
systematically!

Suppose I have master table (table1) and detail table
(table2), and both table1 have their own triggers and
rules.

In what order do these foreign key constraint,
triggers, and rules be fired?  Please do not forget
to explain whether or not table1 and table2 are
treated in the following manner:

(1) When table1 is deleted, table2 is deleted first.
(2) When primary key value of table1 is updated, the
primary key value of table1 is updated first.

Regards,

CN

--------------------------------------------------------
You too can have your own email address from Eurosport.
http://www.eurosport.com






Re: Controling Rule's Firing Order

От
Tom Lane
Дата:
<cnliou@eurosport.com> writes:
> Does foreign key constraints also fire in
> alphabetical order in 7.3?

Foreign key triggers will fire in alphabetical order along with other
triggers.  This means they're firing based on a textual sort of the
OIDs assigned to the triggers, which will often but not always
correspond to creation order.

I'm having a hard time visualizing a situation where it's reasonable
to depend on FK trigger firing order, actually.  Convince me why I
should care about this?

            regards, tom lane

Re: Controling Rule's Firing Order

От
cn
Дата:
Hello! Tom,

Thank you very much for the patience! Probably you are my last hope.

> Foreign key triggers will fire in alphabetical order along with other triggers.
> This means they're firing based on a textual sort of the OIDs assigned to the
> triggers, which will often but not always correspond to creation order.

I don't fully understand the meaning of the term "firing in alphabetic
order" you mentioned earlier and "they're firing based on a textual sort
of the OIDs assigned to the triggers". OIDs are integers. Why terms
"textual" and "alphabetic" are used?  Did you actually referring them to
the _names_ of triggers, rules, and FK triggers, instead of their OIDs?

Hopefully the answer is not "their oids". Triggers/FK triggers/rules are
frequently dropped and recreated during database development stage.
Please imagine I have rule1, FK trigger2, trigger3, and trigger4 to be
fired in this listed order. If I change the logic of rule1, then I will
also have to remember to drop FK trigger2, trigger3, and trigger4 and
recreate them after rule1 is dropped and recreated. Seeing this, I feel
using OIDs as the control for firing order makes database design work
very complicate and the design result is prone to errors.

Now back to the topic of your concern about the value of controling FK
trigger's firing order. I have prepared this example trying to prove
that they are worthy being added to the already very powerful
postgresql. I want the system to work in this way:

- When exchange rate in SaleMaster is changed or when price in
SaleDetail is inserted/updated/deleted, VoucherDetail reflects the
change immediately.
- VoucherMaster is not created until SaleDetail is inserted.
- VocherMaster is also deleted when SaleMaster is deleted.

Problems arise if I have no control over the firing order of FK trigger
as the following 2 scenarios.

Scenario 1: When SaleNumber in SaleMaster is updated.
If trigger SaleMasterU is fired before FK trigger fkSale, then statement

FOR rec IN SELECT * FROM SaleDetail WHERE SaleNumber=varSaleNo LOOP

in UpdateVoucher(), called by trigger SaleMusterU, will do nothing. This
is because column SaleNumber in SaleDetail now still keeps old value
while varSaleNo contains new one. The net result is that the data is
incorrect.

Scenario 2: When SaleMaster is deleted.
VoucherMaster will be deleted by trigger SaleMasterD. However, if
trigger SaleMasterD is fired before FK trigger fkSale, VoucherMaster
will be re-inserted by trigger SaleDetailD which is an orphan master
row.

Regards,

CN
==============
CREATE TABLE SaleMaster(
SaleNumber INTEGER PRIMARY KEY,
ExchangeRate NUMERIC
);

CREATE TABLE SaleDetail(
CONSTRAINT fkSale FOREIGN KEY (SaleNumber) REFERENCES SaleMaster
(SaleNumber) ON UPDATE CASCADE ON DELETE CASCADE,
PRIMARY KEY (SaleNumber,ItemSold),
SaleNumber INTEGER,
ItemSold TEXT,
price NUMERIC
);

CREATE TABLE VoucherMaster(
VoucherNumber SERIAL PRIMARY KEY,
SaleNumber INTEGER
);

CREATE TABLE VoucherDetail(
CONSTRAINT fkVoucher FOREIGN KEY (VoucherNumber) REFERENCES
VoucherMaster (VoucherNumber) ON UPDATE CASCADE ON DELETE CASCADE,
PRIMARY KEY (VoucherNumber,item),
VoucherNumber SERIAL PRIMARY KEY,
item TEXT,
amount NUMERIC
);

CREATE FUNCTION UpdateVoucher(TEXT) RETURNS BOOLEAN AS '
DECLARE
  varSaleNo ALIAS FOR $1;
  varExchangeRate NUMERIC;
  varVoucherNo TEXT;
  varItem TEXT;
  rec RECORD;
  amount NUMERIC;
BEGIN
  SELECT ExchangeRate INTO varExchangeRate FROM SaleMaster WHERE
SaleNumber=varSaleNo;

  SELECT VoucherNo INTO varVoucherNo FROM VoucherMaster WHERE
SaleNo=varSaleNo;
  IF NOT FOUND THEN
    INSERT INTO VoucherMaster(SaleNo) VALUES (varSaleNo);
  END IF;

  --Delete all VoucherDetail and regenerate.
  DELETE FROM VoucherDetail WHERE VoucherNo=varVoucherNo;

  FOR rec IN SELECT * FROM SaleDetail WHERE SaleNumber=varSaleNo LOOP
    --The logic for the real function is more complicate than this
example.
    --That is this function exists for.
    varItem:=rec.ItemSold;
    amount:=rec.price*varExchangeRate;
    INSERT INTO VoucherDetail VALUES (VoucherNumber,varItem,amount);
  END LOOP;

  RETURN TRUE;
END;' LANGUAGE 'plpgsql';
-----------------------
CREATE FUNCTION FuncSaleMasterU() RETURNS OPAQUE AS '
BEGIN
  IF NEW.SaleNumber <> OLD.SaleNumber THEN
    UPDATE VoucherMaster SET SaleNo=NEW.SaleNumber WHERE
SaleNo=OLD.SaleNumber;
  END IF;

  IF NEW.ExchangeRate <> OLD.ExchangeRate THEN
    PERFORM UpdateVoucher(NEW.SaleNumber);
  END IF;

  RETURN NEW;
END;' LANGUAGE 'plpgsql';

CREATE TRIGGER SaleMasterU AFTER UPDATE ON SaleMaster FOR EACH ROW
EXECUTE PROCEDURE FuncSaleMasterU();
-----------------------
CREATE FUNCTION FuncSaleMasterD() RETURNS OPAQUE AS '
BEGIN
  --If sale master is gone, delete the corresponding voucher master,
too.
  DELETE FROM VoucherMaster WHERE SaleNo=OLD.SaleNumber;
  RETURN OLD;
END;' LANGUAGE 'plpgsql';

CREATE TRIGGER SaleMasterD BEFORE DELETE ON SaleMaster FOR EACH ROW
EXECUTE PROCEDURE FuncSaleMasterD();
-----------------------
CREATE FUNCTION FuncSaleDetailI() RETURNS OPAQUE AS '
BEGIN
  PERFORM UpdateVoucher(NEW.SaleNumber);
  RETURN NEW;
END;' LANGUAGE 'plpgsql';

CREATE TRIGGER SaleDetailI AFTER INSERT ON SaleDetail FOR EACH ROW
EXECUTE PROCEDURE FuncSaleDetailI();
-----------------------
CREATE FUNCTION FuncSaleDetailU() RETURNS OPAQUE AS '
BEGIN
  IF NEW.ItemSold <> OLD.ItemSold THEN
    UPDATE VoucherDetail SET item=NEW.ItemSold WHERE
VoucherNumber=(SELECT VoucherNumber FROM VoucherMaster WHERE
SaleNo=NEW.SaleNumber) AND item=OLD.ItemSold;
  END IF;

  IF NEW.price <> OLD.price THEN
    PERFORM UpdateVoucher(NEW.SaleNumber);
  END IF;

  RETURN NEW;
END;' LANGUAGE 'plpgsql';

CREATE TRIGGER SaleDetailU AFTER UPDATE ON SaleDetail FOR EACH ROW
EXECUTE PROCEDURE FuncSaleDetailU();
--------------------------
CREATE FUNCTION FuncSaleDetailD() RETURNS OPAQUE AS '
BEGIN
  PERFORM UpdateVoucher(OLD.SaleNumber);
  RETURN OLD;
END;' LANGUAGE 'plpgsql';

CREATE TRIGGER SaleDetailD AFTER DELETE ON SaleDetail FOR EACH ROW
EXECUTE PROCEDURE FuncSaleDetailD();

Re: Controling Rule's Firing Order

От
Stephan Szabo
Дата:
On Sat, 24 Aug 2002, cn wrote:

> Hello! Tom,
>
> Thank you very much for the patience! Probably you are my last hope.
>
> > Foreign key triggers will fire in alphabetical order along with other triggers.
> > This means they're firing based on a textual sort of the OIDs assigned to the
> > triggers, which will often but not always correspond to creation order.
>
> I don't fully understand the meaning of the term "firing in alphabetic
> order" you mentioned earlier and "they're firing based on a textual sort
> of the OIDs assigned to the triggers". OIDs are integers. Why terms
> "textual" and "alphabetic" are used?  Did you actually referring them to
> the _names_ of triggers, rules, and FK triggers, instead of their OIDs?

The name of a foreign key trigger is a constant beginning followed by an
oid.

> Now back to the topic of your concern about the value of controling FK
> trigger's firing order. I have prepared this example trying to prove
> that they are worthy being added to the already very powerful
> postgresql. I want the system to work in this way:

You can't easily control which foreign key trigger runs first, but you
should be able to make triggers run before/after the foreign
key trigger by picking names before/after the constant part of the
fk trigger name.  I'm not sure how triggers fired from statements
within trigger functions would play into that however.


Re: Controling Rule's Firing Order

От
Alvaro Herrera
Дата:
cn dijo:


> > Foreign key triggers will fire in alphabetical order along with other triggers.
> > This means they're firing based on a textual sort of the OIDs assigned to the
> > triggers, which will often but not always correspond to creation order.
>
> I don't fully understand the meaning of the term "firing in alphabetic
> order" you mentioned earlier and "they're firing based on a textual sort
> of the OIDs assigned to the triggers". OIDs are integers. Why terms
> "textual" and "alphabetic" are used?  Did you actually referring them to
> the _names_ of triggers, rules, and FK triggers, instead of their OIDs?

Foreign key constraints are implemented internally with triggers.  Those
triggers are named after the foreign key that they serve, and that name
contains the OID that is apparently the only means of distinguishing
from others FK triggers (on the same table?).  The firing order of
foreign key is thus the firing order of the trigger, which is by OID (by
the OID their name contains).

I unfortunatly just broke my copy of Postgres so cannot show you an
example, but try looking at the names of the triggers inside your
database (yes, system catalog poking is a very interesting exercise).

--
Alvaro Herrera (<alvherre[a]atentus.com>)
"Las cosas son buenas o malas segun las hace nuestra opinion" (Lisias)


Re: Controling Rule's Firing Order

От
Дата:
Thank you! Alvaro and Stephan,

> The name of a foreign key trigger is a constant
> beginning followed by an oid.

Now I think I have found that FK trigger names look
like this:

RI_ConstraintTrigger_<OID>

> but you should be able to make triggers run
> before/after the foreign key trigger by picking
> names before/after the constant part of the
> fk trigger name.

Yes, this is the way for me to go. The last missing
better-have feature is the firing order among FK
triggers for master and detail tables:

- When the primary key of master record is to be
updated, the primary key of this master record is
updated before those of its child records.

- When the master record is to be deleted, its detail
records are first deleted.

Best Regards,

CN

--------------------------------------------------------
You too can have your own email address from Eurosport.
http://www.eurosport.com






Re: Controling Rule's Firing Order

От
Stephan Szabo
Дата:
On Mon, 26 Aug 2002 cnliou@eurosport.com wrote:

> Thank you! Alvaro and Stephan,
>
> > The name of a foreign key trigger is a constant
> > beginning followed by an oid.
>
> Now I think I have found that FK trigger names look
> like this:
>
> RI_ConstraintTrigger_<OID>
>
> > but you should be able to make triggers run
> > before/after the foreign key trigger by picking
> > names before/after the constant part of the
> > fk trigger name.
>
> Yes, this is the way for me to go. The last missing
> better-have feature is the firing order among FK
> triggers for master and detail tables:
>
> - When the primary key of master record is to be
> updated, the primary key of this master record is
> updated before those of its child records.

If you mean, upon an update of master record, the update occurs
before the referential action, this should already be true
since it's an after trigger.

> - When the master record is to be deleted, its detail
> records are first deleted.

Unless we've misread the spec (which is possible) the above
does not comply with the foreign key specification.  There
are disagreements about when the referential action should
occur, but the earliest anyone's found justification for
is upon marking a row for deletion the detail rows are marked
for deletion (we currently actually do it after this point
because we don't have an agreement as to what some of the phrases
mean).