Description:
I am using Microsoft's DataGrid control with VB6 to bind directly to an MySQL database table. When I issue an Refresh call, the control returns with a "Catastrophic failure". This is VB6's nice way of saying a access violation occurred.
My connection string is:
Provider=MSDASQL.1;Persist Security Info=False;User ID=root;Extended
Properties="DATABASE=TSInsert;DSN=MySQL3;OPTION=256;
PORT=0;SERVER=xfiles2000;UID=root";Initial Catalog=TSInsert
I built a debug version of the 3.51.11 ODBC driver and found that Microsoft's DataGrid control is issuing a call to SQLGetConnectAttr() with a valid hdbc, but the handle has not been connected yet to the database. So internally to the ODBC driver, the mysql_send_query function attempts to use the macro simple_command, but it crashes because the hdbc->mysql->methods struct member variable is zero. So the macro causes an access violation. Clearly the DataView control should not try to call this, BUT the MySQL ODBC driver should be tolerant and return an ODBC error instead of causing an access violation.
Appended Below is the stack trace.
Note that if I remove the "Initial Catalog=TSInsert" text from the connection string, the Microsoft DataGrid control does not make the call that causes the crash. My application is generic so the user sets the connection string and I have no way of easily knowing to remove this token for specifically MySQL.
Scott Richardson
National Instruments
> myodbc3.dll!mysql_send_query(st_mysql * mysql=0x0019ffb4, const char * query=0x05afe784, unsigned long length=0x00000011) Line 2444 C
myodbc3.dll!mysql_real_query(st_mysql * mysql=0x0019ffb4, const char * query=0x05afe784, unsigned long length=0x00000011) Line 2455 + 0x11 C
myodbc3.dll!odbc_stmt(tagDBC * dbc=0x0019ffb0, const char * query=0x05afe784) Line 54 + 0x2d C
myodbc3.dll!reget_current_catalog(tagDBC * dbc=0x0019ffb0) Line 914 + 0xe C
myodbc3.dll!get_con_attr(void * hdbc=0x0019ffb0, long Attribute=0x0000006d, void * ValuePtr=0x0012d644, long BufferLength=0x00000101, long * StringLengthPtr=0x0012d63c) Line 480 + 0x9 C
myodbc3.dll!SQLGetConnectAttr(void * hdbc=0x0019ffb0, long Attribute=0x0000006d, void * ValuePtr=0x0012d644, long BufferLength=0x00000101, long * StringLengthPtr=0x0012d63c) Line 906 + 0x19 C
odbc32.dll!_ToAnsi_SQLGetConnectAttr@20() + 0xa6
odbc32.dll!CConnectOptions::SaveDefaultConnAttr() + 0x694a
odbc32.dll!_SetQueuedAttr@8() - 0xa1
odbc32.dll!_TraceSQLBrowseConnectW@24() - 0x15fb8
odbc32.dll!_SQLInternalDriverConnectW@36() + 0x1a
odbc32.dll!_SQLDriverConnectW@32() - 0x5cc6
msdasql.dll!CODBCHandle::DriverConnect() + 0x22
msdasql.dll!CODBCHandle::OHDriverConnect() + 0x7b
msdasql.dll!CHdbcNode::DriverConnect() + 0x22
msdasql.dll!CImpIDBInitialize::Initialize() + 0x125
oledb32.dll!CDBInitialize::DoInitialize() + 0x33
oledb32.dll!CDBInitialize::Initialize() + 0x43
oledb32.dll!CDCMPool::CreateResource() + 0x18e
comsvcs.dll!CHolder::SafeDispenserDriver::CreateResource() + 0x25
comsvcs.dll!CHolder::AllocResource() + 0x2bd
oledb32.dll!CDCMPool::DrawResource() + 0x94
oledb32.dll!CDCMPoolManager::DrawResource() + 0xa9bf
oledb32.dll!CDPO::Initialize() + 0xb2
msado15.dll!_ConnectAsync() + 0x75
msado15.dll!ConnectAsync() + 0x1b
msado15.dll!CConnection::Open() - 0xa70b
msadodc.ocx!24e75d05()
msadodc.ocx!24e75b8c()
msadodc.ocx!24e760b0()
msadodc.ocx!24e75568()
oleaut32.dll!_DispCallFunc@32() + 0xc3
oleaut32.dll!CTypeInfo2::Invoke() + 0x20c
msadodc.ocx!24e7f578()
msadodc.ocx!24e73031()
MSVBVM60.DLL!OLECTL::Invoke() + 0x16a
MSVBVM60.DLL!_SafeInvoke@36() + 0x68
MSVBVM60.DLL!_ExLateId@24() + 0x64
MSVBVM60.DLL!___vbaLateIdCall() + 0x1a
DatabaseView.exe!frmDataView::Update() Line 398 + 0x2c BASIC
How to repeat:
Create a VB6 app with a DataGrid and ADODC control. Use the following code:
Private Sub Form_Load()
Adodc1.CommandType = adCmdTable
Adodc1.ConnectionString = "Provider=MSDASQL.1;Persist Security Info=False;User ID=root;Extended Properties=""DATABASE=TSInsert;DSN=MySQL3;OPTION=256;PORT=0;SERVER=xfiles2000;UID=root"";Initial Catalog=TSInsert"
Adodc1.RecordSource = "mytable"
Set DataGrid1.DataSource = Adodc1
Adodc1.Refresh
End Sub
Suggested fix:
To validate a possible fix to this problem, I changed the macro...
...from:
#define simple_command(mysql, command, arg, length, skip_check) \
(!mysql || !mysql->methods) ? -1 : \
(*(mysql)->methods->advanced_command)(mysql, command, \
NullS, 0, arg, length, skip_check)
...to:
#define simple_command(mysql, command, arg, length, skip_check) \
(*(mysql)->methods->advanced_command)(mysql, command, \
NullS, 0, arg, length, skip_check)
...and the catastrophic error no longer occurs and the table is displayed properly. The fix to the MySQL ODBC driver could also be implemented by adding a IsValid() function to all entry points that confirm that a handle is valid and connected to the database.