I spent some time yesterday debugging a crashing console application – a proof of concept for a wrapper library I’m writing around an Oracle database. I had successfully read values from the DB – writing that code took all of five minutes – and then tried a MERGE statement.
(Side note: this is the first time I’ve written a merge statement. In fact, while I did know of MySQL’s “REPLACE INTO”, I had no idea that such a thing existed.)
I played around with the statement in TOAD for a while, to make sure it was correctly written, typed it into my editor, added parameter placeholders, added the arguments for the parameters and ran the application. It flashed on the screen and then disappeared.
Which was a bit weird, seeing as it ended with a Console.ReadLine() call. I re-ran the app just to make sure I didn’t accidentally press anything, and the same thing happened. Meanwhile, looking at the results on the TOAD side of things, the value was definitely updated.
I was a bit tired, so it took me a while to notice that the process exit code was 0x80000003 – nonzero, so some sort of error was being reported. Still, even asking the debugger to break on all Win32 errors yielded nothing. And between the statement being executed and the crash, ProcMon reported that all operations the application performed were successful.
I was too tired to make sense of it, so I went home and took a fresh set of eyes with me today. I began to narrow the issue down to a single parameter. At which point I began to get NRE’s instead of crashes. And the stack traces contained references to the special handling of DateTime parameters.
I was doing this:
command.Parameters.Add(new OracleParameter("curdate", DateTime.Now));
Figuring that DateTimes were a special case, I chose this constructor overload instead:
command.Parameters.Add(new OracleParameter("curdate", OracleDbType.Date, DateTime.Now, ParameterDirection.Input));
After which I re-ran the app, and like magic, everything worked.
Now, realizing that Oracle has more than one way of representing the data contained in a System.DateTime, I understand how there might be a code path or two dedicated for the handling of DateTimes. What I don’t get is that it’s possible for the most common overload of the OracleParameter constructor to result in not an exception, but a full-on application crash.
Anyway, I hope this post saves someone else the trouble.