// == HEADER FILES == #include "stdafx.h" #ifdef WIN32 #include #include #endif // WINDOWS #include #include #include "myClock.h" // == GLOBAL VARIABLES == // == PROTOTYPES == static int checkRC(RETCODE, char *, SQLHANDLE, SQLHANDLE, SQLHANDLE); static RETCODE dropTables(SQLHANDLE, SQLHANDLE); static RETCODE createTables(SQLHANDLE, SQLHANDLE); static RETCODE doArrayInsert(SQLHANDLE); static RETCODE doArrayInsert2(); static RETCODE doExtendedArrayFetch(SQLHANDLE, SQLINTEGER); static RETCODE doExtendedArrayFetch2(SQLINTEGER); // == DEFINES == #define MAX_CONNECT_STRING (1024) #define TREAT_SUCCESS_WITH_INFO_FATAL (1) #define chkRC(errorMsg) { \ RETCODE __rc; \ if ((__rc = checkRC (rc, errorMsg, henv, hdbc, hstmt)) != SQL_SUCCESS) { \ if (!(__rc == SQL_SUCCESS_WITH_INFO && TREAT_SUCCESS_WITH_INFO_FATAL)) { \ goto exit; \ } \ } \ if (0) wprintf (L"[INFO]: %s is successful.\n", errorMsg); \ } // == FUNCTIONS == static int checkRC(RETCODE retCode, char *msgString, SQLHANDLE henv, SQLHANDLE hdbc, SQLHANDLE hstmt) { RETCODE rc = SQL_SUCCESS; SQLSMALLINT handleType = (hstmt != NULL ? SQL_HANDLE_STMT : (hdbc != NULL ? SQL_HANDLE_DBC : SQL_HANDLE_ENV)); SQLHANDLE handle = (hstmt != NULL ? hstmt : (hdbc != NULL ? hdbc : henv)); SQLWCHAR sqlState[6], msg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER nativeError; SQLSMALLINT recNum = 1; SQLSMALLINT msgLen; if (retCode == SQL_SUCCESS) { return rc; } if (handle == NULL) { rc = SQL_ERROR; return rc; } while ((rc = SQLGetDiagRec(handleType, handle, recNum, sqlState, &nativeError, msg, sizeof(msg), &msgLen)) != SQL_NO_DATA) { wprintf(L"ERROR: %s", msgString); wprintf(L" [NativeError: %d, SQLSTATE: %s, errorMsg: %s]\n", nativeError, sqlState, msg); recNum++; } return retCode; } SQLWCHAR sConnectStrings[2][MAX_CONNECT_STRING] = { L"Driver=MySQL ODBC 5.3 Unicode Driver;Server=xxxxx;Database=xxxxx;Port=3306;USER=xxxxxx;PASSWORD=xxxxx;stmt=set time_zone = '+00:00';Charset=utf8;OPTION=3" // crash with 5.3.7 //L"Driver=MySQL ODBC 5.2 Unicode Driver;Server=xxxxx;Database=xxxxx;Port=3306;USER=xxxxxx;PASSWORD=xxxxx;stmt=set time_zone = '+00:00';Charset=utf8;OPTION=3" // works with 5.2.7 }; // == MAIN ENTRY FUNCTION == int main(int argc, _TCHAR* argv[]) { // -- Define variables -- RETCODE rc = SQL_SUCCESS; SQLHANDLE hdbc, hstmt; static SQLHANDLE henv; SQLWCHAR sDriverName[128], sDriverVersion[128]; SQLWCHAR sConnectStringOut[MAX_CONNECT_STRING]; SQLSMALLINT lenConnectString = MAX_CONNECT_STRING; SQLSMALLINT lenConnectStringOut = MAX_CONNECT_STRING; henv = hdbc = hstmt = NULL; // -- Allocate environment handle -- rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); chkRC("SQLAllocHandle(SQL_HANDLE_ENV)"); // -- Set ODBC Version -- rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); chkRC("SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)"); // -- Allocate database handle -- rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); chkRC("SQLAllocHandle(SQL_HANDLE_DBC)"); // -- Connect to the database -- rc = SQLDriverConnect(hdbc, NULL, sConnectStrings[0], lenConnectString, sConnectStringOut, lenConnectStringOut, &lenConnectStringOut, SQL_DRIVER_NOPROMPT); chkRC("SQLDriverConnect()"); rc = SQLSetConnectAttr(hdbc, SQL_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS); chkRC("SQLSetConnectAttr()"); rc = SQLGetInfo(hdbc, SQL_DRIVER_NAME, sDriverName, sizeof(sDriverName), NULL); chkRC("SQLGetInfo(SQL_DRIVER_NAME)"); rc = SQLGetInfo(hdbc, SQL_DRIVER_VER, sDriverVersion, sizeof(sDriverVersion), NULL); chkRC("SQLGetInfo(SQL_DRIVER_VER)"); wprintf(L"=== Driver Name: [%s], Version: [%s] ===\n", sDriverName, sDriverVersion); // -- Perform database operations -- dropTables(henv, hdbc); createTables(henv, hdbc); // -- Disconnect the database -- rc = SQLDisconnect(hdbc); chkRC("SQLDisconnect()"); // -- Deallocate database handle -- rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); chkRC("SQLFreeHandle(SQL_HANDLE_DBC)"); // -- Deallocate environment handle -- rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); chkRC("SQLFreeHandle(SQL_HANDLE_ENV)"); #define THREADED 1 #ifdef THREADED { std::thread reader(doExtendedArrayFetch2, 2); std::thread writer(doArrayInsert2); reader.join(); writer.join(); } #else // THREADED doExtendedArrayFetch2(2); doArrayInsert2(); #endif // THREADED exit: return rc; } static RETCODE dropTables(SQLHANDLE henv, SQLHANDLE hdbc) { RETCODE rc = SQL_SUCCESS; SQLHANDLE hstmt; // -- Allocate statement handle -- rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); chkRC("SQLAllocHandle(SQL_HANLDE_STMT)"); // -- Execute DROP TABLE statement -- rc = SQLExecDirect(hstmt, L"DROP TABLE mySQL_Crash2_tgt", SQL_NTS); chkRC("SQLExecDirect(DROP TABLE)"); // -- Deallocate statement handle -- rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); chkRC("SQLFreeHandle(SQL_HANDLE_STMT)"); exit: return rc; } static RETCODE createTables(SQLHANDLE henv, SQLHANDLE hdbc) { RETCODE rc = SQL_SUCCESS; SQLHANDLE hstmt; SQLWCHAR sqlStatement[256]; // -- Allocate statement handle -- rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); chkRC("SQLAllocHandle(SQL_HANLDE_STMT)"); // -- Execute CREATE TABLE statement -- wsprintf(sqlStatement, L"CREATE TABLE mySQL_Crash2_tgt (c1 varchar(100))"); rc = SQLExecDirect(hstmt, sqlStatement, SQL_NTS); chkRC("SQLExecDirect(CREATE TABLE)"); // -- Deallocate statement handle -- rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); chkRC("SQLFreeHandle(SQL_HANDLE_STMT)"); exit: return rc; } #define MAX_ARRAY_SIZE (1) #define MAX_NROWS (MAX_ARRAY_SIZE * 40000) static RETCODE doArrayInsert2() { RETCODE rc = SQL_SUCCESS; SQLVARCHAR arrC1[100 + 1]; SQLLEN indC1; strcpy_s((char *)arrC1, 101, "Rxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx100"); indC1 = 1; SQLWCHAR sConnectStringOut[MAX_CONNECT_STRING]; SQLSMALLINT lenConnectString = MAX_CONNECT_STRING; SQLSMALLINT lenConnectStringOut = MAX_CONNECT_STRING; static SQLHANDLE henv, hdbc, hstmt; henv = hdbc = hstmt = NULL; // -- Allocate environment handle -- rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); chkRC("SQLAllocHandle(SQL_HANDLE_ENV)"); // -- Set ODBC Version -- rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); chkRC("SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)"); // -- Allocate database handle -- rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); chkRC("SQLAllocHandle(SQL_HANDLE_DBC)"); rc = SQLDriverConnect(hdbc, NULL, sConnectStrings[0], lenConnectString, sConnectStringOut, lenConnectStringOut, &lenConnectStringOut, SQL_DRIVER_NOPROMPT); chkRC("SQLDriverConnect()"); // -- Allocate statement handle -- rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); chkRC("SQLAllocHandle(SQL_HANLDE_STMT)"); rc = SQLPrepare(hstmt, L"insert into mySQL_Crash2_tgt values (?)", SQL_NTS); chkRC("SQLPrepare(INSERT INTO)"); for (int i = 0; i < MAX_NROWS / MAX_ARRAY_SIZE; i++) { rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 100, 0, &arrC1, 101, NULL); chkRC("SQLBindParameter(C1)"); rc = SQLExecute(hstmt); chkRC("SQLExecute()"); if ((i % 1000) == 0) { wprintf(L"I"); if ((i % 100000) == 0) { wprintf(L"\n"); } } } wprintf(L"Insert elapsed time: %d [thread-id: %d]\n", 0, GetCurrentThreadId()); // -- Deallocate statement handle -- rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); chkRC("SQLFreeHandle(SQL_HANDLE_STMT)"); rc = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT); chkRC("SQLEndTran(SQL_COMMIT)"); rc = SQLDisconnect(hdbc); chkRC("SQLDisconnect()"); // -- Deallocate database handle -- rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); chkRC("SQLFreeHandle(SQL_HANDLE_DBC)"); // -- Deallocate environment handle -- rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); chkRC("SQLFreeHandle(SQL_HANDLE_ENV)"); exit: return rc; } /* mysql> CREATE TABLE mySQL_Crash2 (c1 varchar(100)); Query OK, 0 rows affected (0.01 sec) mysql> insert into mySQL_Crash2 values ('Rxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx100'); Query OK, 1 row affected (0.00 sec) mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 8 rows affected (0.00 sec) Records: 8 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 16 rows affected (0.01 sec) Records: 16 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 32 rows affected (0.01 sec) Records: 32 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 64 rows affected (0.01 sec) Records: 64 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 128 rows affected (0.01 sec) Records: 128 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 256 rows affected (0.01 sec) Records: 256 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 512 rows affected (0.01 sec) Records: 512 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 1024 rows affected (0.01 sec) Records: 1024 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 2048 rows affected (0.03 sec) Records: 2048 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 4096 rows affected (0.04 sec) Records: 4096 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 8192 rows affected (0.11 sec) Records: 8192 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 16384 rows affected (0.16 sec) Records: 16384 Duplicates: 0 Warnings: 0 mysql> insert into mySQL_Crash2 select * from mySQL_Crash2; Query OK, 32768 rows affected (0.37 sec) Records: 32768 Duplicates: 0 Warnings: 0 */ static RETCODE doExtendedArrayFetch2(SQLINTEGER fetchArraySize) { SQLULEN nRowsFetched; SQLUSMALLINT *statusArr; SQLRETURN rc = SQL_SUCCESS; SQLWCHAR *arrC1; SQLLEN *indC1; SQLULEN nTotalRowsFetched = 0; LONGLONG mallocTime, preFetchTime, fetchTime, postFetchTime, freeTime; int numSQLFetch = 1; SQLWCHAR sConnectStringOut[MAX_CONNECT_STRING]; SQLSMALLINT lenConnectString = MAX_CONNECT_STRING; SQLSMALLINT lenConnectStringOut = MAX_CONNECT_STRING; static SQLHANDLE henv, hdbc, hstmt; henv = hdbc = hstmt = NULL; // -- Allocate environment handle -- rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); chkRC("SQLAllocHandle(SQL_HANDLE_ENV)"); // -- Set ODBC Version -- rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0); chkRC("SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)"); // -- Allocate database handle -- rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); chkRC("SQLAllocHandle(SQL_HANDLE_DBC)"); rc = SQLDriverConnect(hdbc, NULL, sConnectStrings[0], lenConnectString, sConnectStringOut, lenConnectStringOut, &lenConnectStringOut, SQL_DRIVER_NOPROMPT); chkRC("SQLDriverConnect()"); arrC1 = (SQLWCHAR *)malloc(fetchArraySize * sizeof(SQLWCHAR) * 101); indC1 = (SQLLEN *)malloc(fetchArraySize * sizeof(SQLLEN)); statusArr = (SQLUSMALLINT *)malloc(fetchArraySize * sizeof(SQLUSMALLINT)); memset(arrC1, 0, sizeof(SQLWCHAR) * 101 * fetchArraySize); memset(indC1, 0, sizeof(SQLLEN)*fetchArraySize); // -- Allocate statement handle -- rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); chkRC("SQLAllocHandle(SQL_HANLDE_STMT)"); SQLSetStmtAttr(hstmt, SQL_ROWSET_SIZE, (SQLPOINTER)fetchArraySize, SQL_IS_INTEGER); chkRC("SQLSetStmtAttr(SQL_ROWSET_SIZE)"); // -- Bind each columns of the SELECT's projection list -- SQLBindCol(hstmt, 1, SQL_C_WCHAR, (SQLPOINTER)arrC1, 101 * 2, indC1); chkRC("SQLBind(arrC1)"); // -- Execute the SELECT statement now -- SQLExecDirect(hstmt, L"SELECT * FROM mySQL_Crash2", SQL_NTS); chkRC("SQLExecDirect(SELECT)"); // -- For a single row, use SQLFetch() instead of SQLExtendedFetch() while ((fetchArraySize == 1 && ((rc = SQLFetch(hstmt)) != SQL_NO_DATA)) || (fetchArraySize > 1 && ((rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 0, &nRowsFetched, statusArr)) != SQL_NO_DATA))) { nTotalRowsFetched += (fetchArraySize == 1) ? 1 : nRowsFetched; numSQLFetch++; if ((numSQLFetch % 1000) == 0) { wprintf(L"."); if ((numSQLFetch % 100000) == 0) { wprintf(L"\n"); } } //Sleep(1); } if ((numSQLFetch % 100000) != 0) { wprintf(L"\n"); } // -- Deallocate statement handle -- rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); chkRC("SQLFreeHandle(SQL_HANDLE_STMT)"); wprintf(L"Fetch elapsed time: %d [thread-id: %d]\n", 0, GetCurrentThreadId()); rc = SQLDisconnect(hdbc); chkRC("SQLDisconnect()"); // -- Deallocate database handle -- rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); chkRC("SQLFreeHandle(SQL_HANDLE_DBC)"); // -- Deallocate environment handle -- rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); chkRC("SQLFreeHandle(SQL_HANDLE_ENV)"); exit: return rc; }