My initial guess would be based on the trigger's flow. Why ?
According to the Book
Chapter 11 Page 251 Paragraph 3 says the following:
The most significant difference between BEFORE
and AFTER
triggers is that in an AFTER
you are not able to modify the values about to be inserted into or updated with the table in question -- the DML has executed, and it is too late to try to change what the DML is going to do.
From the this statement, this is what I understand: Since the DML is executed and the DML is still spoken of in the future imperfect tense (I am not an English teacher), the new values are really not available to be read in a SELECT
since the trigger is not done.
In your case, you are doing an AFTER UPDATE
on phpbb_rathermenacing.phpbb_bbdkp_memberlist
. With the trigger being 99.99999999% done, you are attempting to do the following in the third clause of the IF statement:
((select min(m.member_rank_id)
from phpbb_bbdkp_memberlist m
WHERE m.phpbb_user_id = NEW.phpbb_user_id AND
m.member_guild_id = NEW.member_guild_id AND
m.member_id != NEW.member_id) >= new.member_rank_id OR
(select count(m.member_rank_id)
from phpbb_bbdkp_memberlist m
WHERE m.phpbb_user_id = NEW.phpbb_user_id AND
m.member_guild_id = NEW.member_guild_id AND
m.member_id != NEW.member_id) = 0)
You are asking for the count and state of the table phpbb_bbdkp_memberlist
that has not yet been changed. Regardless of the Storage Engine, I am very sure you will never get a response because the trigger has to finish in order for the Storage Engine to even think about posting changes to disk.
I have two old posts where I discuss why a trigger is no place for business intelligence:
SUGGESTIONS
- Make that trigger a stored procedure
- Remove the
AFTER UPDATE
trigger
- Run the stored procedure after the
UPDATE
in your application.
Aha! I've found the answer. Talk about an edge case.
First, I found this post from 2007, where someone says:
...the AFTER trigger for synchronizing the CTXCAT index on [column] is
not firing (since my update statement does not include the indexed
column).
...
Oracle, would it not be better to generate the CTXCAT
trigger to examine the :old and :new values in the indexed column,
rather than using a check on (if updating([column]))?
Over a year later, someone replied:
I fixed this issue by adding additional UPDATING (first_name and
last_name) conditions in the DR$table_name trigger.
Here is part of the modified trigger.
if (inserting or updating('LAST_NAME_FIRST') or updating('FIRST_NAME')
or updating('LAST_NAME')) then reindex := TRUE;
Hm, so the CTXCAT index uses a trigger to know when it needs to update the index for a particular entry. All I need to do is tweak the trigger and recompile it so it does what I want.
To get the content of the trigger:
SELECT text
FROM user_source
WHERE name = 'DR$NAMES_IDXTC'
AND type = 'TRIGGER'
ORDER BY line;
I copied this into Sublime, prettified it, and found this (simplified):
TRIGGER "TEST"."DR$NAMES_IDXTC" AFTER
INSERT
OR
UPDATE ON "TEST"."NAMES"
FOR EACH ROW DECLARE REINDEX boolean := FALSE;
BEGIN
IF (inserting
OR updating('COMPOUND_NAME')
OR :new."COMPOUND_NAME" <> :old."COMPOUND_NAME") THEN REINDEX := TRUE;
END IF;
...
END;
You can see that the 12c Oracle Text version's AFTER trigger does actually compare the :new
and :old
values of the indexed column to see if it needs to update--not the case back in 2008.
So...if I'm updating the :new
value in my BEFORE trigger, that should be reflected in the AFTER trigger, and the comparison would kick off an update to the index. What gives?
Well, here are the two SQL statements I was using:
update test.names set
first_name = 'Skye',
last_name = 'Fillingim'
where ... ;
update test.names set
first_name = null,
last_name = null
where ... ;
(Slightly different than what I said in my question, I apologize.)
The effect here is that, each time I used one of these statements, either the :old.compound_name
or :new.compound_name
would be null. So when we get to this condition:
OR :new."COMPOUND_NAME" <> :old."COMPOUND_NAME"
We are doing an equality comparison against a null, which evaluates to UNKNOWN. Hence, no index update.
This is actually an extreme edge case, because you have to be indirectly modifying :new.column
via a trigger, and either :new
or :old
must be null. I would never have discovered it it I hadn't used those exact SQL statements.
So, we have a slight update to the trigger:
IF (inserting
OR updating('COMPOUND_NAME')
OR :new."COMPOUND_NAME" <> :old."COMPOUND_NAME"
OR (:new."COMPOUND_NAME" IS NULL AND :old."COMPOUND_NAME" IS NOT NULL)
OR (:new."COMPOUND_NAME" IS NOT NULL AND :old."COMPOUND_NAME" IS NULL)
) THEN REINDEX := TRUE;
And then just stick CREATE OR REPLACE
in front of the old trigger, recompile it, and everything works perfectly.
Best Answer
Adjust the trigger's syntax
or if the trigger is to have multiple lines, do this