The other day, I was investigating an issue in our process that takes a list of users and (effectively) merges them into the database. As part of that, I was trying to understand how the whole process worked.
This is the basic structure of the table:
Name Null? Type ------------- -------- ---------------------------- ID NOT NULL NUMBER(12) LOGIN_NAME VARCHAR2(25) CREATED DATE LAST_UPDATED DATE
I could see data in the table:
ID LOGIN_NAME CREATED LAST_UPDATED ----- ---------- ------------------- ------------------- 1451 user_1451 06/08/2008 00:10:54 10/10/2008 01:01:34 1452 user_1452 07/08/2008 00:11:18 23/02/2009 15:23:53 1453 user_1453 12/08/2008 00:09:51 04/07/2012 03:09:08 1454 user_1454 14/08/2008 00:09:58 10/06/2009 05:28:24
And this is the code that actually inserts the user information (I’ve removed the updates from this, as they’re not relevant to my mystery!):
PROCEDURE SynchroniseUsers (pUserList user_info_tab) IS BEGIN INSERT INTO USERS (ID, LOGIN_NAME) SELECT ID_SEQ.Nextval, theUsers.column_value FROM THE (SELECT CAST(l_userTable AS VARCHARTAB) FROM dual) theUsers WHERE NOT EXISTS (SELECT /*+ index(U USERS_LOGIN) */ 1 FROM USERS U WHERE U.login_name = theUsers.column_value); END; /
“Hmm,” I thought, “I can’t see where the CREATED or LAST_UPDATED columns are being updated.” So, I hunted through the rest of the code in the package – there was an UPDATE of the LAST_UPDATED column elsewhere, so I wasn’t concerned about that, but I could not find any mention of where the CREATED column was being updated.
“Aha! Must be in a trigger!” … alas, no.
I was absolutely stumped; by now, I’ve spent the best part of 30 mins trying to work out where this column gets updated (the code involved is not the best code on the planet, as I’m sure you can judge from the above procedure!). Eventually, after staring at it some more and scratching my head, it hit me: default column values *smacks forehead*
Sure enough, when I go into the table structure:
CREATE TABLE USERS ( ID NUMBER(12) NOT NULL, LOGIN_NAME VARCHAR2(25 BYTE), CREATED DATE DEFAULT SYSDATE, -- here is the culprit! LAST_UPDATED DATE );
If whoever had designed this
pile of… code had included the CREATED column in the INSERT statement in the first place, I wouldn’t have had to waste my time trying to work out what the heck was going on! That is why you should always be explicit in your coding habits – sure, have default values so that things don’t slip through the cracks, but make sure the table is well designed and that any code doing inserts, updates, etc has ALL the necessary columns included.
Don’t rely on the side effects of doing things automagically, it just leads to maintenance headaches!