#include #include #include #include //"c:\programme\sdb\programs\incl\sqlext.h" /* Program shall demonstrate failure on select of an empty string from a "long unicode"-type column via ODBC "sqlod32w.dll", version 7.5.00.18 PREREQUISITES: ------------- - Unicode-enabled MaxDB of version 7.5.00.18 (i.e., _UNICODE = YES) - Default code set to unicode (i.e., DEFAULT_CODE = UNICODE) - Table with column of type "LONG UNICODE" (i.e., "CREATE TABLE test (val LONG UNICODE)" - ODBC-datasource with sqlod32w.dll "MaxDB (unicode)" ODBC-driver */ // CONNECT PARAMETERS... const char dbname[] = "dbname"; const char username[] = "dba"; const char password[] = "dba"; int main(int argc, char* argv[]) { SQLRETURN rc = SQL_SUCCESS; SQLHENV henv = 0; rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); SQLHDBC hdbc = 0; rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); rc = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0); rc = SQLConnect(hdbc, (SQLCHAR*)dbname, SQL_NTS, (SQLCHAR*)username, SQL_NTS, (SQLCHAR*)password, SQL_NTS); SQLHSTMT hStmtInsert, hStmtSelect, hStmtDelete; rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hStmtInsert); rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hStmtSelect); rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hStmtDelete); /* Insert empty string into column of type "LONG UNICODE" and select again. sInValue and sOutValue should both be empty strings but sOutValue isn't... Output string sOutValue is not NULL-terminated !! */ const SQLLEN MAX_STR_LEN = 256; SQLLEN MAX_STR_BUF = (MAX_STR_LEN+1)*sizeof(SQLWCHAR); SQLWCHAR *sInValue = new SQLWCHAR[MAX_STR_LEN+1]; SQLWCHAR *sOutValue = new SQLWCHAR[MAX_STR_LEN+1]; /* Try this, i.e. length of string = 0 and code will fail, i.e. sOutValue will not be NULL terminated ... */ //sInValue[0] = L'\0'; /* Try this, i.e. length of string > 0 and everything works fine, i.e., sOutValue will be NULL terminated ... */ sInValue[0] = 'a'; sInValue[1] = L'\0'; SQLLEN nIndIn = SQL_NTS; SQLLEN nIndOut; rc = SQLPrepare (hStmtInsert, (SQLCHAR*)"INSERT INTO test (val) VALUES (?)", SQL_NTS); rc = SQLBindParameter (hStmtInsert, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, MAX_STR_BUF, 0, sInValue, MAX_STR_BUF, &nIndIn); rc = SQLExecute( hStmtInsert) ; rc = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_COMMIT ); rc = SQLPrepare (hStmtSelect, (SQLCHAR*)"SELECT val FROM test", SQL_NTS); rc = SQLExecute (hStmtSelect); rc = SQLBindCol (hStmtSelect, 1, SQL_C_WCHAR, sOutValue, MAX_STR_BUF, &nIndOut); rc = SQLFetch(hStmtSelect); if (wcsncmp (sInValue, sOutValue, MAX_STR_LEN)) cout << "sInValue and sOutValue aren't equal" << endl; //if (wcslen(sOutValue) != wcslen(sInValue) ) // cout << "wcslen (sOutValue) was expected to be " << wcslen(sInValue) << " but is: " << wcslen (sOutValue) << endl; // delete value again ... rc = SQLExecDirect(hStmtDelete, (SQLCHAR*)"DELETE FROM test", SQL_NTS); rc = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_COMMIT ); rc = SQLFreeHandle(SQL_HANDLE_STMT, hStmtInsert); rc = SQLFreeHandle(SQL_HANDLE_STMT, hStmtSelect); rc = SQLFreeHandle(SQL_HANDLE_STMT, hStmtDelete); rc = SQLDisconnect(hdbc); rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc); rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); delete [] sInValue; delete [] sOutValue; return rc; }