MFC Access Violation
November 25, 2006 3:26 PM   RSS feed for this thread Subscribe

Why does executing a SQL query via MFC's CDatabase class always result in an access violation?

I log data to a remote MySQL database via MySQL Connector/ODBC 3.51. Every time I call CDatabase::ExecuteSQL(), I get an access violation logged to Visual Studio's debug window:

First-chance exception at 0x7c809eb2 in DBTester.exe: 0xC0000005: Access violation reading location 0x00000005.

The deepest I can trace is CDatabase::OnSetOptions(), when it calls SQLSetStmtOption() on SQL_QUERY_TIMEOUT. The comment above that call says "Ignore failure." Unfortunately, the failure is not ignored. I get a debug message every time that line is executed despite the try block around CDatabase.ExecuteSQL(). The data is successfully logged to the database, but the error is polluting my output window, makeing it much harder to debug more important issues.


1. Is there a way to fix the error?
2. If not, can I make it go away somehow?
posted by b1tr0t to computers & internet (12 comments total)
Just guessing, but did you try calling SetQueryTimeout first?
posted by sfenders at 5:27 PM on November 25, 2006


Can you paste your code, from the Open(Ex) to Close? Use a pastebot because AskMe doesn't work well with code.
posted by sbutler at 5:44 PM on November 25, 2006


sfenders - I tried that, and it didn't make any difference.

sbutler: here you go.
posted by b1tr0t at 6:10 PM on November 25, 2006


a) is there anything wrong with using NOW()?
b) Is your program compiled with UNICODE defined? If so, then ExecuteSQL expects a wide string.

Can you try this code?
posted by sbutler at 7:06 PM on November 25, 2006


Two followups:

1) Insert the obviously missing Format() in the catch block.
2) For shits and giggles, check to make sure that "this" isn't NULL.
posted by sbutler at 7:13 PM on November 25, 2006


1. NOW() will give the current time on the SQL machine, and it won't give it down to the millisecond. I'm storing data ten times per second, so I need more precision than NOW() supports. If I used NOW() combined with the local ms delta, my times would quickly go out of sync.

2. UNICODE isn't defined. To be sure, I changed the char to a WCHAR and otherwise switched over to wide APIs. The program failed badly. To be doubly sure, I #undef'd UNICODE in stdafx.h above where I included afxdb.h, and reverted the code back to narrow APIs. No change from my original failure.

3. I tried the supplied code, but the failure remains the same.

4. What obviously missing Format() in the catch block? CException doesn't have a Format() member function.

5. I checked, "this" isn't null. within the scope of the CDBTesterDlg class, "this" isn't null. Within the CDatabase calls, "this" is still not null.



Unicode is a good guess, but the SQL string is making its way into the remote MySQL server, and the data shows up there.
posted by b1tr0t at 7:49 PM on November 25, 2006


Hmm... I'm stumped. Could you set a breakpoint and check the value of "this" inside the call? The more I think about it, the more this looks like your calling doDB off a deallocated object.

In C++, statically-bound functions will run off NULL/deallocated objects just fine, until you hit a point where it accesses an instance variable. In your example, this first occurs with the ExecuteSQL statement. But if *that* is also a statically-bound function, then the error will occur further inside. I'm guessing that the first time ExecuteSQL uses an instance variable is when it sets the statement timeout. If the connection object comes from some static pool, then that would explain why the statement executes yet you still get the access error.

Anyway, that's just my best guess. CDatabase certainly shouldn't be throwing access violations, so you have a problem somwhere. I just can't tell where it is from the code snippet.
posted by sbutler at 8:02 PM on November 25, 2006


(I take that back. It first occurs with the IsOpen call. But it's still my best guess.)
posted by sbutler at 8:04 PM on November 25, 2006


m_dbDB, the CDatabase member element, is a static member, so it can't be NULL. In a different program, I use dynamically allocated CDatabase objects, and see the same problem.

The first lines of CDatabase::ExecuteSQL() are:
ASSERT_VALID(this);
ASSERT(AfxIsValidString(lpszSQL));


To be sure, I've traced inside several times into ExecuteSQL().

I tried one more time, and discovered something interesting. ExectueSQL() calls OnSetOptions(). After OnSetOptions() does some sanity checking, it executes the following line:

AFX_SQL_SYNC(::SQLSetStmtOption(hstmt, SQL_QUERY_TIMEOUT,m_dwQueryTimeout));

The value of m_dwQueryTimeout is 0x5, which is exactly the value of the address listed in the error. Before I called SetQueryTimeout(), the error pointer was 0xf, which corresponds to the default timeout of 15 seconds.

According to MSDN, m_dwQueryTimeout should be a pointer to a param, not a literal param. It looks like Microsoft got this one wrong, but then everyone should see this error.
posted by b1tr0t at 8:44 PM on November 25, 2006


Hrmm... I looked through the MySQL OBDC 5 code (I know: not the version you're using) and it ultimately just casts the SQLPOINTER to an SQLUINTEGER. So I'm not sure that's your problem. Unless the symantics changed between 3 and 5.

See setStmtAttr and setQueryTimeout in MStatement.cpp.
posted by sbutler at 9:09 PM on November 25, 2006


After thinking a bit more about the problem, I found an MSDN reference to FoxPro not supporting the SQL_QUERY_TIMEOUT option. MySQL isn't FoxPro, but it is failing in the vicinity of this constant, so I changed the value passed into SetQueryTimeout() to 0.

The failures are gone.
posted by b1tr0t at 11:59 PM on November 25, 2006


Hey, woo hoo :) Bugs like this drive me nuts... glad you finally figured it out.
posted by sbutler at 12:02 AM on November 26, 2006


« Older I used to be a devoted catholi...   |   I want to fall in love (with B... Newer »
This thread is closed to new comments.