0

My table has a Trigger that stores current_timestamp into a field when the row in the table is updated.

When a row is first inserted it is inserted with a Created date equal to Current_Timestamp. It appears when the procedure inserts the created_date it is given the correct time for daylight savings time but the trigger is inserting the incorrect time.

So the records in question are showing a created date of '2018-03-11 03:13:53.392086000' and a modified date of '2018-03-11 02:13:53.392086000'.

To add to this, we use goldengate for replication and it is using '2018-03-11 03:13:53.392086000' as the audit timestamp and not '2018-03-11 02:13:53.392086000'

Why would a trigger show a time differently then goldengate and the insert? database version I am working with is Oracle 11.2.0.4.0.

Trigger that handles the insert modified time

create or replace trigger UT_INSERT before insert on MYTABLE
 REFERENCING NEW AS NEWROW OLD AS OLDROW FOR EACH ROW
 begin
    :NEWROW.MODIFIED_TIMESTAMP := CURRENT_TIMESTAMP;
 end;

Trigger for updated modified time

create or replace trigger UT_UPDATE before update on MYTABLE
 REFERENCING NEW AS NEWROW OLD AS OLDROW FOR EACH ROW
 begin
    :NEWROW.MODIFIED_TIMESTAMP := CURRENT_TIMESTAMP;
 end;
user3753693
  • 225
  • 1
  • 5
  • 13
  • **[edit]** your question and include the code of the trigger –  Jul 09 '18 at 19:28
  • What is the data type of column `MODIFIED_TIMESTAMP`? – Wernfried Domscheit Jul 09 '18 at 20:12
  • TIMESTAMP(6) is the datatype for all timestamps in my table – user3753693 Jul 09 '18 at 20:25
  • What is setting `created_date` - is that using `systimestamp` or `current_timestamp`? (I assume you know [the difference](https://stackoverflow.com/a/17925834/266304).) Are all the sessions doing insert/update inthe sametime zone? Are the columns plain timestamps, or with [local] time zone? – Alex Poole Jul 09 '18 at 21:14
  • The insert statement that is setting created_date is using Current_timestamp. All sessions are currently using a TZ offset of -05:00 and the sessiontimezone is America/Chicago. I did notice that DBTIMEZONE is set to a offset of 0:00. At first i thought it could be the issue causing weird values from the trigger but if I try `select current_timestamp, systimestamp from dual;` returns **2018-07-09 04.26.44.631014000 PM AMERICA/CHICAGO 2018-07-09 04.26.44.631009000 PM -05:00**. All Timestamps are timestamp(6) without timezone – user3753693 Jul 09 '18 at 21:28
  • Where does the insert procedure live? Is it a stored procedure in the db or some client side code in Forms or SQL script? Try using `systimestamp` in all instances as pointed out by @AlexPoole – Hauke Jul 10 '18 at 07:36

1 Answers1

2

The insert statement that is setting created_date is using Current_timestamp. All sessions are currently using a TZ offset of -05:00 and the sessiontimezone is America/Chicago.

That can't always be true. The only way to get the two values you have is for the insert to have been done with created_date set to systimestamp and for the session that issued that to have had it's session time zone set to -05:00, not to America/Chicago.

The reason that must be the case is that there was no 02:13 on March 11th because of the DST change:

select timestamp '2018-03-11 03:13:53.392086000 America/Chicago' from dual;

TIMESTAMP'2018-03-1103:13:53.392086000AMERICA
---------------------------------------------
2018-03-11 03:13:53.392086000 AMERICA/CHICAGO

select timestamp '2018-03-11 02:13:53.392086000 America/Chicago' from dual;

Error report -
SQL Error: ORA-01878: specified field not found in datetime or interval
01878. 00000 -  "specified field not found in datetime or interval"

select timestamp '2018-03-11 02:13:53.392086000 -5:00' from dual;

TIMESTAMP'2018-03-1102:13:53.3920860
------------------------------------
2018-03-11 02:13:53.392086000 -05:00

So assuming the column value was set from your trigger, which seems entirely reasonable, the session which did that must have been -05:00 to be able to have got the timestamp at 02:13; and the created_date must have been using systimestamp, where the server OS had the correct time zone of America/Chicago to pick up the DST change (ignore dbtimezone for this), to have got 03:13 at the same moment in time.

As long as the session time zone and server time zone are the same you won't see a discrepancy between using current_timestamp or systimestamp, but you can't always control how sessions are configured, so a mistake or deliberate time zone change can cause problems like this.

Unless you are specifically trying to record a user's local time for some reason (and then you should probably be using a timestamp data type that preserves the time zone), it's safer to always use systimestamp for all of the values you record; and if you're storing as a plain timestamp then it might be safer to always store UTC time.

(Changing to UTC now, particularly with existing data to worry about, probably isn't an option; and not sure how Golden Gate would handle that but seems like a common scenario. Something to think about for the future though. Changing to always use systimestamp ought to be fairly transparent, except that you have this and probably other discrepancies to worry about. Finding and changing all code that might do inserts could be an issue - but then you seem to have inconsistencies already).

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • What session parameters does a trigger use when it fires? Is it the user that created the trigger or the user that did the insert/update on the table to fire the trigger? – user3753693 Jul 10 '18 at 13:27
  • @user3753693 - the user that did the insert/update. Which is why you, as the trigger creator, have no control over how it will be called later - so should use things you can control like `systimestamp` and not things you can't like `current_timestamp`, or any NLS settings like date formats etc. – Alex Poole Jul 10 '18 at 13:56