Bug #24552 Driver fail SQL_DRIVER_COMPLETE, stack corruption SQL_DRIVER_NOPROMPT
Submitted: 23 Nov 2006 18:56 Modified: 5 Oct 2007 13:00
Reporter: Farid Zidan (Candidate Quality Contributor) Email Updates:
Status: Unsupported Impact on me:
None 
Category:Connector / ODBC Severity:S1 (Critical)
Version:5.00.09 OS:Windows (Windows 2000)
Assigned to: Jess Balint CPU Architecture:Any

[23 Nov 2006 18:56] Farid Zidan
Description:
This only happens if SQL_DRIVER_COMPLETE is used

    SQLSMALLINT cbConnStrOut = 0;

    const int   cbConnStrOutMax = 1024;
    TCHAR		szConnStrOut[ cbConnStrOutMax + 1 ];

	// mfz 11/3/06 MySQL V5 beta driver fails with SQL_DRIVER_COMPLETE but
	// succeeds with SQL_DRIVER_NOPROMPT
    rc = SQLDriverConnect( m_hdbc, 
                           hwnd,
                           ( SQLCHAR * ) szConnect, 
                           ( SQLSMALLINT ) strlen( szConnect ),
                           ( SQLCHAR * ) szConnStrOut, 
						   cbConnStrOutMax, 
						   &cbConnStrOut,
                           SQL_DRIVER_COMPLETE );

How to repeat:
Rpeatable
[24 Nov 2006 8:39] Tonci Grgin
Hi Farid and thanks for your problem report. Before we get into this deeper I would like to know if driver manager connection pooling was enabled? What's MySQL server version and host OS?

Can you please recheck all of relevant information needed to reproduce this problem and post it along with complete test case here.
[24 Nov 2006 14:14] Farid Zidan
Connect failure/stack corruption with SQL_DRIVER_COMPLTE/NOPROMPT

Attachment: TestDD.zip (application/x-zip-compressed, text), 57.96 KiB.

[24 Nov 2006 14:14] Farid Zidan
MySQL 5.0.19-nt via TCP/IP
MySQL Client Version 5.0.11 Windows 2k, 2x AMD Athlon 64X2 Dual Core 4600+ 2.8
MySQL Connector/ODBC v5 5.00.06.00

All running on same computer ( Windows 2000 ).  
I am attaching a test VS 2005 C++ project to demonstrate this issue. 
Correction: Driver does not crash if SQL_DRIVER_COMPLETE is used, it just fails to connect, however, if SQL_DRIVER_NOPROMPT is used I get a VS run time error that the driver corrupts the stack around the StringLength2Ptr parameter.
[24 Nov 2006 14:25] Tonci Grgin
Hi Farid. I will test on my XP x64.
You didn't tell me is driver manager connection pooling enabled in your tests?
[24 Nov 2006 14:41] Farid Zidan
Sorry. Pooling is disabled ( default ).
[27 Nov 2006 9:16] Tonci Grgin
Farid, this took some time to figure out... SQL_DRIVER_COMPLETE and SQL_DRIVER_NOPROMPT are mutually exclusive. First one tells to show connect dialog but second one suppress it. Now for the problems.

Consider my test case (working):
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

SQLHENV hEnv = SQL_NULL_HENV;
SQLHDBC hDbc = SQL_NULL_HDBC;

void myerror(SQLRETURN rc, SQLSMALLINT htype, SQLHANDLE handle)
{
  SQLRETURN lrc;

  if (rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO || rc == 100)
  {
    SQLCHAR	szSqlState[6],szErrorMsg[SQL_MAX_MESSAGE_LENGTH];
    SQLINTEGER	pfNativeError;
    SQLSMALLINT pcbErrorMsg;

    lrc= SQLGetDiagRec(htype, handle,1,
		       (SQLCHAR *)&szSqlState,
		       (SQLINTEGER *)&pfNativeError,
		       (SQLCHAR *)&szErrorMsg,
		       SQL_MAX_MESSAGE_LENGTH-1,
		       (SQLSMALLINT *)&pcbErrorMsg);
    printf("lrc returned %d\n", lrc);
    if (lrc == SQL_SUCCESS || lrc == SQL_SUCCESS_WITH_INFO || lrc == 100)
      printf("[%s][%d:%s]\n",szSqlState,pfNativeError,szErrorMsg);
  }
}

int main(void)
{
	int rc, nPrompt = 0;
	long timeout = 30;
	SQLCHAR     connOut[255]; /* buffer for connection output */
	SQLSMALLINT szConnOut; /* num bytes returned in connOut */
	SQLRETURN res;

	SQLCHAR connString[256] = "DRIVER={MySQL Connector/ODBC v5};SERVER=localhost;UID=root;PWD=;Database=test;"; // Driver

    SQLAllocEnv(&hEnv);
	rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_NTS);
    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  	    myerror(rc, SQL_HANDLE_ENV, hEnv);

	SQLAllocConnect(hEnv, &hDbc);
	//SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, &timeout, sizeof(timeout) );

	res = SQLDriverConnect(hDbc, GetDesktopWindow(), connString, SQL_NTS, connOut, 255, &szConnOut, SQL_DRIVER_COMPLETE);// || nPrompt);
		
	if ( ((res) != SQL_SUCCESS) ) 
	    myerror(res, 2, hDbc);

	res= SQLDisconnect(hDbc);
	res =SQLFreeConnect(hDbc);
	res =SQLFreeEnv(hEnv);
	return 0;
}
If you change ";UID=root;" to ";USER=root;", you'll get error reported, but (from our sources and ODBC v3 specs) you should use UID:
    /*!
        \internal MYODBC RULE
        In this context - we need the following attributes to connect;
            - DSN || DRIVER
            - SERVER
            *- UID*
            - PWD
            - DATABASE
        These are not strictly required but we ask for them all - favouring the idea of discovering most common connection information. The caller still has the option of providing the attribute with no value. If the value is required - the connect will fail.
    */
If you add user "ODBC" to your MySQL server, even your code will work! This means, by my opinion, that:
  - MyODBC 5 did not recognize USER keyword
  - Default mechanism was triggered, displaying connect screen as for SQL_DRIVER_COMPLETE flag
  - Data from connect screen is wrongly recognized causing Connect to try with default "ODBC" user which is missing (From SQLConnect manual: If the value is not set in the connection string and the user makes no assignment in the dialog box, the driver uses the default.)...
So this should be a bug report about *not getting* correct connect info from connect dialog when connect string is wrong...

You have made yet another error by not passing correct window handle, thus you didn't get connection dialog which lead you to wrong conclusions:
  SQLDriverConnect must be given a valid WindowHandle when any DriverCompletion value requires (or could require) the display of the driver's connection dialog box. An invalid handle returns SQL_ERROR. And you do require it since "USER" keyword is unrecognized.

Now for the heap corruption: HEAP[testprg.exe]: Invalid Address specified to RtlFreeHeap( 01860000, 01E246C8 ) Windows has triggered a breakpoint in testprg.exe.

# SQL_DRIVER_COMPLETE or SQL_DRIVER_COMPLETE_REQUIRED: If the connection string contains enough information, and that information is correct, the driver connects to the data source and copies *InConnectionString to *OutConnectionString. If any information is missing or incorrect, the driver takes the same actions as it does when DriverCompletion is SQL_DRIVER_PROMPT, except that if DriverCompletion is SQL_DRIVER_COMPLETE_REQUIRED, the driver disables the controls for any information not required to connect to the data source.

My guess is that corruption happens in 
"the driver connects to the data source and copies  *InConnectionString to *OutConnectionString." 
and is expected after so much incorrect info provided to Connect function.

Conclusion:
 - This could be feature request to support "USER" as well as "UID" keyword
 - This could be a bug in that closing connection options screen wrong values are passed to SQLDriverConnect when initial connect string contains wrong keyword

I will have to consult more.
[27 Nov 2006 14:34] Farid Zidan
Thanks for the info. My application uses SQL_DRIVER_COMPLETE exclusivley. The bug as I see is that since I am providing all the connection info in my connect string ( database name is already set in the data source setup ):

const char *szConnect = "DSN=MY_DSN;UID=root;PWD=root";

The driver should connect successfully using SQL_DRIVER_COMPLETE.

I was using SQL_DRIVER_NOPROMPT just as an illustration that the connection string has all the info the driver requires for establishing a successful connection.

The stack error when establishing the connection is due to the driver hard coding cbConnStrOut parameter as a pointer to long instead of ODBC spec which says it has to be merely a pointer to SQLSMALLINT.  I can eliminate the stack error by declaring cbConnStrOut as SQLINTEGER and then casting it as (SQLSMALLINT * ) in the connect call.

    // attempt connection
    //SQLSMALLINT cbConnStrOut;
    SQLINTEGER	cbConnStrOut;
    const int   cbConnStrOutMax = 1024;
    char        szConnStrOut[ cbConnStrOutMax + 1 ];
    
    rc = SQLDriverConnect( hdbc, 
                           NULL, // hwnd,
                           ( SQLCHAR * ) szConnect, 
                           ( SQLSMALLINT ) strlen( szConnect ),
                           ( SQLCHAR * ) szConnStrOut, 
						   cbConnStrOutMax, 
						   (SQLSMALLINT *) &cbConnStrOut,
                           /*SQL_DRIVER_COMPLETE*/ SQL_DRIVER_NOPROMPT);
[27 Nov 2006 15:27] Jess Balint
This stack corruption issue was explicitly fixed in 5.00.09 beta 4. If this is still a problem we need to look into it again.

Farid - Please verify that you definitely using the latest beta release by checking the driver version in the ODBC data source administrator.
[27 Nov 2006 15:46] Farid Zidan
Updated to the latest 5.00.09 beta driver. Verified stack corruption issue is fixed.

Also verified that SQL_DRIVER_COMPLETE still fails
[28 Nov 2006 7:09] Tonci Grgin
Farid, thanks for your input and your interest in MySQL! As you have seen, I've escalated this problem and it should be fixed as soon as possible.
[5 Oct 2007 13:00] Tonci Grgin
5.0 branch had been discontinued. Please use 3.51 or 5.1 alpha.