From 20e0a501392c660467b013c4ef632b227035bdc3 Mon Sep 17 00:00:00 2001 From: Lawrin Novitsky Date: Sun, 2 Dec 2018 22:31:37 +0100 Subject: [PATCH] ODBC-203 The fix and the testcase. The problem was occured only with data fetched as SQL_C_WCHAR. That happened because for statemnt handdles after 1st one there wasn't STMT_ATTR_UPDATE_MAX_LENGTH attribute set, and getting data as a widestring depends on max_length. Also changed similar ODBC-169 testcase to test data values, and not only column and row count. Added to test framework optional automatic unicode connection(with SQLDriverConnectW) and statement allocation in that connection. --- ma_bulk.c | 2 +- ma_helper.c | 21 +++++- ma_helper.h | 1 + ma_statement.c | 17 ++--- test/basic.c | 2 +- test/catalog1.c | 2 +- test/catalog2.c | 2 +- test/info.c | 2 +- test/multistatement.c | 45 +++++++++--- test/tap.h | 158 ++++++++++++++++++++++++++++-------------- test/unicode.c | 73 ++++++++++++++++++- 11 files changed, 245 insertions(+), 80 deletions(-) diff --git a/ma_bulk.c b/ma_bulk.c index b6406ef4..9614ab2b 100644 --- a/ma_bulk.c +++ b/ma_bulk.c @@ -151,7 +151,7 @@ SQLRETURN MADB_SetBulkOperLengthArr(MADB_Stmt *Stmt, MADB_DescRecord *CRec, SQLL MaBind->length= MADB_REALLOC(MaBind->length, Stmt->Bulk.ArraySize*sizeof(long)); if (MaBind->length == NULL) { - return MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);; + return MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0); } } diff --git a/ma_helper.c b/ma_helper.c index 603a875e..bcf22a7e 100644 --- a/ma_helper.c +++ b/ma_helper.c @@ -38,6 +38,23 @@ void CloseMultiStatements(MADB_Stmt *Stmt) } +MYSQL_STMT* MADB_NewStmtHandle(MADB_Stmt *Stmt) +{ + static const my_bool UpdateMaxLength= 1; + MYSQL_STMT* stmt= mysql_stmt_init(Stmt->Connection->mariadb); + + if (stmt != NULL) + { + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength); + } + else + { + MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0); + } + + return stmt; +} + /* Required, but not sufficient condition */ BOOL QueryIsPossiblyMultistmt(MADB_QUERY *Query) { @@ -75,7 +92,7 @@ unsigned int GetMultiStatements(MADB_Stmt *Stmt, BOOL ExecDirect) while (p < Stmt->Query.RefinedText + Stmt->Query.RefinedLength) { - Stmt->MultiStmts[i]= i == 0 ? Stmt->stmt : mysql_stmt_init(Stmt->Connection->mariadb); + Stmt->MultiStmts[i]= i == 0 ? Stmt->stmt : MADB_NewStmtHandle(Stmt); MDBUG_C_PRINT(Stmt->Connection, "-->inited&preparing %0x(%d,%s)", Stmt->MultiStmts[i], i, p); if (mysql_stmt_prepare(Stmt->MultiStmts[i], p, (unsigned long)strlen(p))) @@ -88,7 +105,7 @@ unsigned int GetMultiStatements(MADB_Stmt *Stmt, BOOL ExecDirect) prepare "multi-statement". */ if (i == 0 && Stmt->Error.NativeError !=1295 /*ER_UNSUPPORTED_PS*/) { - Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb); + Stmt->stmt= MADB_NewStmtHandle(Stmt); if (mysql_stmt_prepare(Stmt->stmt, STMT_STRING(Stmt), (unsigned long)strlen(STMT_STRING(Stmt)))) { mysql_stmt_close(Stmt->stmt); diff --git a/ma_helper.h b/ma_helper.h index 82fb6940..e7829d95 100644 --- a/ma_helper.h +++ b/ma_helper.h @@ -20,6 +20,7 @@ #define _ma_helper_h_ void CloseMultiStatements(MADB_Stmt *Stmt); +MYSQL_STMT* MADB_NewStmtHandle(MADB_Stmt *Stmt); BOOL QueryIsPossiblyMultistmt(MADB_QUERY *Query); int SqlRtrim(char *StmtStr, int Length); unsigned int GetMultiStatements(MADB_Stmt *Stmt, BOOL ExecDirect); diff --git a/ma_statement.c b/ma_statement.c index 8c496e55..ce77822c 100644 --- a/ma_statement.c +++ b/ma_statement.c @@ -19,8 +19,6 @@ #include struct st_ma_stmt_methods MADB_StmtMethods; /* declared at the end of file */ -static my_bool UpdateMaxLength= 1; - /* {{{ MADB_StmtInit */ SQLRETURN MADB_StmtInit(MADB_Dbc *Connection, SQLHANDLE *pHStmt) @@ -36,7 +34,7 @@ SQLRETURN MADB_StmtInit(MADB_Dbc *Connection, SQLHANDLE *pHStmt) LOCK_MARIADB(Connection); - if (!(Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb)) || + if (!(Stmt->stmt= MADB_NewStmtHandle(Stmt)) || !(Stmt->IApd= MADB_DescInit(Connection, MADB_DESC_APD, FALSE)) || !(Stmt->IArd= MADB_DescInit(Connection, MADB_DESC_ARD, FALSE)) || !(Stmt->IIpd= MADB_DescInit(Connection, MADB_DESC_IPD, FALSE)) || @@ -46,7 +44,6 @@ SQLRETURN MADB_StmtInit(MADB_Dbc *Connection, SQLHANDLE *pHStmt) } MDBUG_C_PRINT(Stmt->Connection, "-->inited %0x", Stmt->stmt); - mysql_stmt_attr_set(Stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength); Stmt->PutParam= -1; Stmt->Methods= &MADB_StmtMethods; @@ -393,8 +390,7 @@ void MADB_StmtReset(MADB_Stmt *Stmt) { MDBUG_C_PRINT(Stmt->Connection, "-->closing %0x", Stmt->stmt); mysql_stmt_close(Stmt->stmt); - Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb); - mysql_stmt_attr_set(Stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength); + Stmt->stmt= MADB_NewStmtHandle(Stmt); MDBUG_C_PRINT(Stmt->Connection, "-->inited %0x", Stmt->stmt); } @@ -402,8 +398,7 @@ void MADB_StmtReset(MADB_Stmt *Stmt) else { CloseMultiStatements(Stmt); - Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb); - mysql_stmt_attr_set(Stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength); + Stmt->stmt= MADB_NewStmtHandle(Stmt); MDBUG_C_PRINT(Stmt->Connection, "-->inited %0x", Stmt->stmt); } @@ -474,8 +469,8 @@ SQLRETURN MADB_RegularPrepare(MADB_Stmt *Stmt) MDBUG_C_PRINT(Stmt->Connection, "mysql_stmt_close(%0x)", Stmt->stmt); mysql_stmt_close(Stmt->stmt); - Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb); - mysql_stmt_attr_set(Stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength); + Stmt->stmt= MADB_NewStmtHandle(Stmt); + UNLOCK_MARIADB(Stmt->Connection); MDBUG_C_PRINT(Stmt->Connection, "mysql_stmt_init(%0x)->%0x", Stmt->Connection->mariadb, Stmt->stmt); @@ -1082,7 +1077,7 @@ SQLRETURN MADB_StmtExecute(MADB_Stmt *Stmt, BOOL ExecDirect) } if (StatementNr > 0) { - Stmt->stmt= mysql_stmt_init(Stmt->Connection->mariadb); + Stmt->stmt= MADB_NewStmtHandle(Stmt); } else { diff --git a/test/basic.c b/test/basic.c index 8f51d1f6..d6413d98 100644 --- a/test/basic.c +++ b/test/basic.c @@ -1604,7 +1604,7 @@ ODBC_TEST(t_odbc139) CHECK_ENV_RC(Env, SQLAllocConnect(Env, &Hdbc)); CHECK_DBC_RC(Hdbc, SQLSetConnectAttr(Hdbc, SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER)"test", 4)); - Hstmt= DoConnect(Hdbc, NULL, NULL, NULL, 0, NULL, &Compression, NULL, NULL); + Hstmt= DoConnect(Hdbc, FALSE, NULL, NULL, NULL, 0, NULL, &Compression, NULL, NULL); Thread= CreateThread(NULL, 0, FireQueryInThread, Hstmt, 0, NULL); diff --git a/test/catalog1.c b/test/catalog1.c index c5204288..a762272c 100644 --- a/test/catalog1.c +++ b/test/catalog1.c @@ -769,7 +769,7 @@ ODBC_TEST(t_sqltables) } IS(AllocEnvConn(&Env, &hdbc1)); - Stmt1= DoConnect(hdbc1, NULL, NULL, NULL, 0, "mariadbodbc_sqltables", 0, NULL, NULL); + Stmt1= DoConnect(hdbc1, FALSE, NULL, NULL, NULL, 0, "mariadbodbc_sqltables", 0, NULL, NULL); FAIL_IF(Stmt1 == NULL, ""); OK_SIMPLE_STMT(Stmt1, "CREATE TABLE t1 (a int)"); diff --git a/test/catalog2.c b/test/catalog2.c index 09928d80..9dd9cedf 100644 --- a/test/catalog2.c +++ b/test/catalog2.c @@ -314,7 +314,7 @@ ODBC_TEST(t_bug50195) CHECK_ENV_RC(Env, SQLAllocConnect(Env, &hdbc1)); - hstmt1= DoConnect(hdbc1, my_dsn, "bug50195", "a", 0, NULL, NULL, NULL, NULL); + hstmt1= DoConnect(hdbc1, FALSE, my_dsn, "bug50195", "a", 0, NULL, NULL, NULL, NULL); if (hstmt1 == NULL) { diff --git a/test/info.c b/test/info.c index 706167cf..b9a2d1b7 100644 --- a/test/info.c +++ b/test/info.c @@ -736,7 +736,7 @@ ODBC_TEST(odbc143) is_num(Length, sizeof(SQLWCHAR)); AllocEnvConn(&Env, &Hdbc1); - Stmt1= DoConnect(Hdbc1, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL); + Stmt1= DoConnect(Hdbc1, FALSE, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL); FAIL_IF(Stmt1 == NULL, "Could not connect and/or allocate"); OK_SIMPLE_STMT(Stmt1, "SET @@SESSION.sql_mode='ANSI_QUOTES'"); diff --git a/test/multistatement.c b/test/multistatement.c index effb22e5..3f09b323 100644 --- a/test/multistatement.c +++ b/test/multistatement.c @@ -225,7 +225,7 @@ ODBC_TEST(t_odbc74) OK_SIMPLE_STMT(Stmt, "TRUNCATE TABLE odbc74"); AllocEnvConn(&Env, &hdbc1); - Stmt1= DoConnect(hdbc1, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL); + Stmt1= DoConnect(hdbc1, FALSE, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL); FAIL_IF(Stmt1 == NULL, "Could not connect and/or allocate"); OK_SIMPLE_STMT(Stmt1, "SET @@SESSION.sql_mode='NO_BACKSLASH_ESCAPES'"); @@ -508,12 +508,31 @@ ODBC_TEST(t_odbc177) ODBC_TEST(t_odbc169) { - SQLCHAR Query[][80]= {"SELECT 1 Col1; SELECT * from t_odbc169", "SELECT * from t_odbc169; SELECT * from t_odbc169 ORDER BY col1 DESC", + SQLCHAR Query[][80]= {"SELECT 1 Col1; SELECT * from t_odbc169", "SELECT * from t_odbc169 ORDER BY col1 DESC; SELECT col3, col2 from t_odbc169", "INSERT INTO t_odbc169 VALUES(8, 7, 'Row #4');SELECT * from t_odbc169"}; - unsigned int i, j= 0, ExpectedRows[]= {1, 3, 3, 3, 0, 4, 1}; + char Expected[][3][7]={ {"1", "", "" }, /* RS 1*/ + {"1", "2", "Row 1"}, /* RS 2*/ + {"3", "4", "Row 2"}, + {"5", "6", "Row 3"}, + {"5", "6", "Row 3"}, /* RS 3*/ + {"3", "4", "Row 2"}, + {"1", "2", "Row 1"}, + {"Row 1", "2" , ""}, /* RS 4*/ + {"Row 2", "4" , ""}, + {"Row 3", "6" , ""}, + + /* RS 5 is empty */ + {"1", "2", "Row 1" }, /* RS 6*/ + {"3", "4", "Row 2" }, + {"5", "6", "Row 3" }, + {"8", "7", "Row #4"} + }; + unsigned int i, RsIndex= 0, ExpectedRows[]= {1, 3, 3, 3, 0, 4, 1}; SQLLEN Rows, ExpRowCount[]= {0, 0, 0, 0, 1, 0, 0}; - SQLSMALLINT ColumnsCount, expCols[]= {1, 3, 3, 3, 0, 3, 1}; + SQLSMALLINT ColumnsCount, expCols[]= {1, 3, 3, 2, 0, 3, 1}; SQLRETURN rc; + SQLSMALLINT Column, Row= 0; + SQLCHAR ColumnData[MAX_ROW_DATA_LEN]={ 0 }; OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS t_odbc169"); @@ -527,14 +546,24 @@ ODBC_TEST(t_odbc169) do { CHECK_STMT_RC(Stmt, SQLRowCount(Stmt, &Rows)); - is_num(Rows, ExpRowCount[j]); + is_num(Rows, ExpRowCount[RsIndex]); CHECK_STMT_RC(Stmt, SQLNumResultCols(Stmt, &ColumnsCount)); - is_num(ColumnsCount, expCols[j]); + is_num(ColumnsCount, expCols[RsIndex]); - is_num(ma_print_result_getdata_ex(Stmt, FALSE), ExpectedRows[j]); + Rows= 0; + while (SQL_SUCCEEDED(SQLFetch(Stmt))) + { + for (Column= 0; Column < ColumnsCount; ++Column) + { + IS_STR(my_fetch_str(Stmt, ColumnData, Column + 1), Expected[Row][Column], strlen(Expected[Row][Column])); + } + ++Row; + ++Rows; + } + is_num(Rows, ExpectedRows[RsIndex]); rc= SQLMoreResults(Stmt); - ++j; + ++RsIndex; } while (rc != SQL_NO_DATA); CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE)); diff --git a/test/tap.h b/test/tap.h index d623d525..065669e1 100644 --- a/test/tap.h +++ b/test/tap.h @@ -129,7 +129,7 @@ static SQLWCHAR *wstrport; static unsigned long my_options= 67108866; -static SQLHANDLE Env, Connection, Stmt; +static SQLHANDLE Env, Connection, Stmt, wConnection, wStmt; static SQLINTEGER OdbcVer= SQL_OV_ODBC3; static unsigned int my_port= 3306; @@ -444,14 +444,50 @@ int my_print_non_format_result(SQLHSTMT Stmt) } +SQLINTEGER SqlwcsLen(SQLWCHAR *str) +{ + SQLINTEGER result= 0; + + if (str) + { + while (*str) + { + ++result; + ++str; + } + } + return result; +} + + +wchar_t *sqlwchar_to_wchar_t(SQLWCHAR *in) +{ + static wchar_t buff[2048]; + char *to= (char *)buff; + + if (sizeof(wchar_t) == sizeof(SQLWCHAR)) + return (wchar_t *)in; + else + { + size_t len= (SqlwcsLen(in) + 1)*sizeof(SQLWCHAR); + int error; + size_t buff_size= sizeof(buff); + + madbtest_convert_string(utf16, (char*)in, &len, utf32, to, &buff_size, &error); + } + + return buff; +} + /* Same as my_print_non_format_result_ex, but uses SQLGetData, to fetch values, and not bind buffers */ -int ma_print_result_getdata_ex(SQLHSTMT Stmt, BOOL CloseCursor) +int ma_print_result_getdata_exex(SQLHSTMT Stmt, BOOL CloseCursor, BOOL FetchAsWstr) { SQLRETURN rc; SQLUINTEGER nRowCount=0; SQLULEN pcColDef; SQLCHAR szColName[MAX_NAME_LEN + 1]; SQLCHAR szData[MAX_ROW_DATA_LEN]= {0}; + SQLWCHAR wData[MAX_ROW_DATA_LEN]= {0}; SQLSMALLINT nIndex, ncol= 0, pfSqlType, pcbScale, pfNullable; SQLLEN ind_strlen; @@ -476,9 +512,18 @@ int ma_print_result_getdata_ex(SQLHSTMT Stmt, BOOL CloseCursor) ++nRowCount; for (nIndex=0; nIndex< ncol; ++nIndex) { - rc= SQLGetData(Stmt, nIndex + 1, SQL_CHAR, szData, sizeof(szData), &ind_strlen); - mystmt_rows(Stmt, rc, -nIndex); - fprintf(stdout, "%s\t", szData); + if (FetchAsWstr != FALSE) + { + rc= SQLGetData(Stmt, nIndex + 1, SQL_C_WCHAR, wData, sizeof(wData), &ind_strlen); + mystmt_rows(Stmt, rc, -nIndex); + fprintf(stdout, "%ls\t", sqlwchar_to_wchar_t(wData)); + } + else + { + rc= SQLGetData(Stmt, nIndex + 1, SQL_C_CHAR, szData, sizeof(szData), &ind_strlen); + mystmt_rows(Stmt, rc, -nIndex); + fprintf(stdout, "%s\t", szData); + } } fprintf(stdout, "\n"); @@ -495,6 +540,11 @@ int ma_print_result_getdata_ex(SQLHSTMT Stmt, BOOL CloseCursor) } +int ma_print_result_getdata_ex(SQLHSTMT Stmt, BOOL CloseCursor) +{ + return ma_print_result_getdata_exex(Stmt, CloseCursor, FALSE); +} + int ma_print_result_getdata(SQLHSTMT Stmt) { return my_print_non_format_result_ex(Stmt, TRUE); @@ -616,7 +666,7 @@ const char *my_fetch_str(SQLHSTMT Stmt, SQLCHAR *szData, SQLUSMALLINT icol) SQLGetData(Stmt, icol, SQL_CHAR, szData, 1000, &nLen); /* If Null value - putting down smth meaningful. also that allows caller to better/(in more easy way) test the value */ - if (nLen < 0) + if (nLen == SQL_NULL_DATA) { strcpy(szData, "(Null)"); } @@ -697,8 +747,11 @@ int AllocEnvConn(SQLHANDLE *Env, SQLHANDLE *Connection) } +SQLWCHAR * str2sqlwchar_on_gbuff(const char *str, size_t len, MARIADB_CHARSET_INFO *from_cs, MARIADB_CHARSET_INFO *to_cs); + + /* Returns STMT handle for newly created connection, or NULL if connection is unsuccessful */ -SQLHANDLE DoConnect(SQLHANDLE Connection, +SQLHANDLE DoConnect(SQLHANDLE Connection, BOOL DoWConnect, const char *dsn, const char *uid, const char *pwd, unsigned int port, const char *schema, unsigned long *options, const char *server, const char *add_parameters) { @@ -718,10 +771,22 @@ SQLHANDLE DoConnect(SQLHANDLE Connection, schema ? schema : (const char*)my_schema, options ? *options : my_options, server ? server : (const char*)my_servername, add_parameters ? add_parameters : ""); - if(!SQL_SUCCEEDED(SQLDriverConnect(Connection, NULL, (SQLCHAR *)DSNString, SQL_NTS, (SQLCHAR *)DSNOut, 1024, &Length, SQL_DRIVER_NOPROMPT))) + if (DoWConnect == FALSE) { - odbc_print_error(SQL_HANDLE_DBC, Connection); - return NULL; + if (!SQL_SUCCEEDED(SQLDriverConnect(Connection, NULL, (SQLCHAR *)DSNString, SQL_NTS, (SQLCHAR *)DSNOut, 1024, &Length, SQL_DRIVER_NOPROMPT))) + { + odbc_print_error(SQL_HANDLE_DBC, Connection); + return NULL; + } + } + else + { + SQLWCHAR *DsnStringW= str2sqlwchar_on_gbuff(DSNString, strlen(DSNString) + 1, utf8, utf16); + if (!SQL_SUCCEEDED(SQLDriverConnectW(Connection, NULL, DsnStringW, SQL_NTS, NULL, 0, &Length, SQL_DRIVER_NOPROMPT))) + { + odbc_print_error(SQL_HANDLE_DBC, Connection); + return NULL; + } } if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, Connection, &stmt))) @@ -733,6 +798,7 @@ SQLHANDLE DoConnect(SQLHANDLE Connection, return stmt; } + int ODBC_Connect(SQLHANDLE *Env, SQLHANDLE *Connection, SQLHANDLE *Stmt) { *Env= NULL; @@ -740,12 +806,23 @@ int ODBC_Connect(SQLHANDLE *Env, SQLHANDLE *Connection, SQLHANDLE *Stmt) IS(AllocEnvConn(Env, Connection)); - *Stmt= DoConnect(*Connection, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL); + *Stmt= DoConnect(*Connection, FALSE, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL); return (*Stmt == NULL ? FAIL : OK); } +int ODBC_ConnectW(SQLHANDLE Env, SQLHANDLE *Connection, SQLHANDLE *Stmt) +{ + *Connection= NULL; + + FAIL_IF(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, Env, Connection)), "Couldn't allocate connection handle"); + + *Stmt= DoConnect(*Connection, TRUE, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL); + + return (*Stmt == NULL ? FAIL : OK); +} + void ODBC_Disconnect(SQLHANDLE Env, SQLHANDLE Connection, SQLHANDLE Stmt) { if (Stmt != NULL) @@ -770,7 +847,7 @@ SQLHANDLE ConnectWithCharset(SQLHANDLE *conn, const char *charset_name, const ch _snprintf(charset_clause, sizeof(charset_clause), "CHARSET=%s;%s", charset_name, add_parameters ? add_parameters : ""); - return DoConnect(*conn, NULL, NULL, NULL, 0, NULL, NULL, NULL, charset_clause); + return DoConnect(*conn, FALSE, NULL, NULL, NULL, 0, NULL, NULL, NULL, charset_clause); } @@ -824,9 +901,7 @@ int reset_changed_server_variables(void) } -SQLWCHAR * str2sqlwchar_on_gbuff(const char *str, size_t len, MARIADB_CHARSET_INFO *from_cs, MARIADB_CHARSET_INFO *to_cs); - -int run_tests(MA_ODBC_TESTS *tests) +int run_tests_ex(MA_ODBC_TESTS *tests, BOOL ProvideWConnection) { int rc, i=1, failed=0; const char *comment; @@ -866,6 +941,14 @@ int run_tests(MA_ODBC_TESTS *tests) fprintf(stdout, "HALT! Could not connect to the server\n"); return 1; } + if (ProvideWConnection && ODBC_ConnectW(Env, &wConnection, &wStmt) == FAIL) + { + odbc_print_error(SQL_HANDLE_DBC, wConnection); + ODBC_Disconnect(Env, wConnection, wStmt); + fprintf(stdout, "HALT! Could not connect to the server with Unicode function\n"); + return 1; + } + fprintf(stdout, "1..%d\n", tests_planned); while (tests->title) { @@ -909,6 +992,10 @@ int run_tests(MA_ODBC_TESTS *tests) return 0; } +int run_tests(MA_ODBC_TESTS *tests) +{ + return run_tests_ex(tests, FALSE); +} int get_show_value(int global, const char * show_type, const char * var_name) { @@ -1071,51 +1158,16 @@ SQLWCHAR * str2sqlwchar_on_gbuff(const char *str, size_t len, MARIADB_CHARSET_IN } -SQLINTEGER SqlwcsLen(SQLWCHAR *str) -{ - SQLINTEGER result= 0; - - if (str) - { - while (*str) - { - ++result; - ++str; - } - } - return result; -} - - -wchar_t *sqlwchar_to_wchar_t(SQLWCHAR *in) -{ - static wchar_t buff[2048]; - char *to= (char *)buff; - - if (sizeof(wchar_t) == sizeof(SQLWCHAR)) - return (wchar_t *)in; - else - { - size_t len= (SqlwcsLen(in) + 1)*sizeof(SQLWCHAR); - int error; - size_t buff_size= sizeof(buff); - - madbtest_convert_string(utf16, (char*)in, &len, utf32, to, &buff_size, &error); - } - - return buff; -} - #define LW(latin_str) latin_as_sqlwchar(latin_str, sqlwchar_buff) +/* wchar_t to SQLLWCHAR, used by both W and WW macros */ #define WL(A,B) (sizeof(wchar_t) == sizeof(SQLWCHAR) ? (SQLWCHAR*)A : str2sqlwchar_on_gbuff((char*)(A), (B+1)*sizeof(wchar_t), utf32, utf16)) -/* Wchar_t(utf32) to sqlWchar */ +/* Converting char const to sqlWchar */ #define WW(A) WL(L##A,wcslen(L##A)) -/* Pretty much the same as WW, but expects that L string */ +/* Converts wchar_t string into SQLWCHAR, const or variable */ #define W(A) WL(A,wcslen(A)) /** Helper for converting a (char *) to a (SQLWCHAR *) */ -/*#define WC(string) dup_char_as_sqlwchar((string))*/ /* Char(utf8) to slqWchar */ #define CW(str) str2sqlwchar_on_gbuff(str, strlen(str)+1, utf8, utf16) diff --git a/test/unicode.c b/test/unicode.c index 88dc5a45..bdd52470 100644 --- a/test/unicode.c +++ b/test/unicode.c @@ -1482,6 +1482,76 @@ ODBC_TEST(t_odbc72) return OK; } + +ODBC_TEST(t_odbc203) +{ + wchar_t Query[][80]= {L"SELECT 1 Col1; SELECT * from t_odbc203", L"SELECT * from t_odbc203 ORDER BY col1 DESC; SELECT col3, col2 from t_odbc203", + L"INSERT INTO t_odbc203 VALUES(8, 7, 'Row #4');SELECT * from t_odbc203"}; + wchar_t Expected[][3][7]={{L"1", L"", L""}, /* RS 1*/ + {L"1", L"2", L"Row 1"}, /* RS 2*/ + {L"3", L"4", L"Row 2"}, + {L"5", L"6", L"Row 3"}, + {L"5", L"6", L"Row 3"}, /* RS 3*/ + {L"3", L"4", L"Row 2"}, + {L"1", L"2", L"Row 1"}, + {L"Row 1", L"2" , L""}, /* RS 4*/ + {L"Row 2", L"4" , L""}, + {L"Row 3", L"6" , L""}, + + //{L"---", L"--", L"--"}, /* RS 5 - placeholder, that RS is empty */ + {L"1", L"2", L"Row 1"}, /* RS 6*/ + {L"3", L"4", L"Row 2"}, + {L"5", L"6", L"Row 3"}, + {L"8", L"7", L"Row #4"} + }; + unsigned int i, RsIndex= 0, ExpectedRows[]= {1, 3, 3, 3, 0, 4, 1}; + SQLLEN Rows, ExpRowCount[]= {0, 0, 0, 0, 1, 0, 0}; + SQLSMALLINT ColumnsCount, expCols[]= {1, 3, 3, 2, 0, 3, 1}; + SQLRETURN rc; + SQLSMALLINT Column, Row= 0; + SQLWCHAR ColumnData[MAX_ROW_DATA_LEN]= {0}; + + OK_SIMPLE_STMTW(wStmt, WW("DROP TABLE IF EXISTS t_odbc203")); + + OK_SIMPLE_STMTW(wStmt, WW("CREATE TABLE t_odbc203(col1 INT, col2 INT, col3 varchar(32) not null)")); + + OK_SIMPLE_STMTW(wStmt, WW("INSERT INTO t_odbc203 VALUES(1, 2, 'Row 1'),(3, 4, 'Row 2'), (5, 6, 'Row 3')")); + + for (i= 0; i < sizeof(Query)/sizeof(Query[0]); ++i) + { + OK_SIMPLE_STMTW(wStmt, W(Query[i])); + + do { + CHECK_STMT_RC(wStmt, SQLRowCount(wStmt, &Rows)); + is_num(Rows, ExpRowCount[RsIndex]); + CHECK_STMT_RC(wStmt, SQLNumResultCols(wStmt, &ColumnsCount)); + is_num(ColumnsCount, expCols[RsIndex]); + + Rows= 0; + while (SQL_SUCCEEDED(SQLFetch(wStmt))) + { + for (Column= 0; Column < ColumnsCount; ++Column) + { + IS_WSTR(my_fetch_wstr(wStmt, ColumnData, Column + 1, sizeof(ColumnData)), W(Expected[Row][Column]), wcslen(Expected[Row][Column])); + } + ++Row; + ++Rows; + } + is_num(Rows, ExpectedRows[RsIndex]); + + rc= SQLMoreResults(wStmt); + ++RsIndex; + } while (rc != SQL_NO_DATA); + + CHECK_STMT_RC(wStmt, SQLFreeStmt(wStmt, SQL_CLOSE)); + } + + OK_SIMPLE_STMTW(wStmt, WW("DROP TABLE t_odbc203")); + + return OK; +} + + MA_ODBC_TESTS my_tests[]= { {test_CONO1, "test_CONO1", NORMAL}, @@ -1511,6 +1581,7 @@ MA_ODBC_TESTS my_tests[]= {t_bug14363601, "t_bug14363601", NORMAL}, {t_odbc19, "test_issue_odbc19", NORMAL}, {t_odbc72, "odbc72_surrogate_pairs", NORMAL}, + {t_odbc203, "t_odbc203", NORMAL}, {NULL, NULL} }; @@ -1520,5 +1591,5 @@ int main(int argc, char **argv) int tests= sizeof(my_tests)/sizeof(MA_ODBC_TESTS) - 1; get_options(argc, argv); plan(tests); - return run_tests(my_tests); + return run_tests_ex(my_tests, TRUE); }