Index: driver/catalog.c =================================================================== --- driver/catalog.c (revision 530) +++ driver/catalog.c (working copy) @@ -202,7 +202,8 @@ @param[in] table_length Length of table name, or @c SQL_NTS @param[in] wildcard Whether the table name is a wildcard - @return Result of SHOW TABLE STATUS + @return Result of SHOW TABLE STATUS, or NULL if there is an error + or empty result (check mysql_errno(&stmt->dbc->mysql) != 0) */ static MYSQL_RES *mysql_table_status(STMT *stmt, SQLCHAR *catalog, @@ -234,7 +235,7 @@ But it will never match anything, so bail out now. */ if (table && wildcard && !*table) - return 0; + return NULL; if (table && *table) { @@ -249,7 +250,7 @@ MYLOG_QUERY(stmt, buff); if (mysql_query(mysql,buff)) - return 0; + return NULL; return mysql_store_result(mysql); } @@ -343,11 +344,9 @@ stmt->result= mysql_list_dbs(&stmt->dbc->mysql,TableQualifier); pthread_mutex_unlock(&stmt->dbc->lock); - if ( !stmt->result ) + if (!stmt->result) { - MYODBCDbgError( "%d", mysql_errno(&stmt->dbc->mysql) ); - MYODBCDbgError( "%s", mysql_error(&stmt->dbc->mysql) ); - goto empty_set; + MYODBCDbgReturnReturn(handle_connection_error(stmt)); } stmt->order = SQLTABLES_qualifier_order; @@ -428,10 +427,16 @@ szTableName, cbTableName, TRUE); pthread_mutex_unlock(&stmt->dbc->lock); - if (!result) + if (!result && mysql_errno(&stmt->dbc->mysql)) { - MYODBCDbgError("%d", mysql_errno(&stmt->dbc->mysql)); - MYODBCDbgError("%s", mysql_error(&stmt->dbc->mysql)); + /* unknown DB will return empty set from SQLTables */ + switch (mysql_errno(&stmt->dbc->mysql)) + { + case ER_BAD_DB_ERROR: + goto empty_set; + default: + MYODBCDbgReturnReturn(handle_connection_error(stmt)); + } } } @@ -443,10 +448,9 @@ szTableName, cbTableName, TRUE); pthread_mutex_unlock(&stmt->dbc->lock); - if (!sys_result) + if (!sys_result && mysql_errno(&stmt->dbc->mysql)) { - MYODBCDbgError("%d", mysql_errno(&stmt->dbc->mysql)); - MYODBCDbgError("%s", mysql_error(&stmt->dbc->mysql)); + MYODBCDbgReturnReturn(handle_connection_error(stmt)); } } @@ -784,8 +788,11 @@ res= mysql_table_status(stmt, szCatalog, cbCatalog, szTable, cbTable, TRUE); pthread_mutex_unlock(&stmt->dbc->lock); - /** @todo handle errors correctly, see bug #26934 */ - if (!res) + if (!res && mysql_errno(&stmt->dbc->mysql)) + { + MYODBCDbgReturnReturn(handle_connection_error(stmt)); + } + else if (!res) goto empty_set; stmt->result= res; @@ -1978,9 +1985,12 @@ szFkTableName, cbFkTableName, FALSE))) { - MYODBCDbgError("%d", mysql_errno(&stmt->dbc->mysql)) - MYODBCDbgError("%s", mysql_error(&stmt->dbc->mysql)); - pthread_mutex_unlock(&stmt->dbc->lock); + pthread_mutex_unlock(&stmt->dbc->lock); + if (mysql_errno(&stmt->dbc->mysql)) + { + MYODBCDbgReturnReturn(handle_connection_error(stmt)); + } + else goto empty_set; } pthread_mutex_unlock(&stmt->dbc->lock); Index: driver/myutil.h =================================================================== --- driver/myutil.h (revision 530) +++ driver/myutil.h (working copy) @@ -100,6 +100,7 @@ ulong *offset); SQLRETURN set_dbc_error(DBC FAR *dbc, char *state,const char *message,uint errcode); SQLRETURN set_stmt_error(STMT *stmt, char *state,const char *message,uint errcode); +SQLRETURN handle_connection_error(STMT *stmt); void translate_error(char *save_state,myodbc_errid errid,uint mysql_err); int unireg_to_sql_datatype(STMT FAR *stmt, MYSQL_FIELD *field, char *buff, ulong *transfer_length,ulong *precision, Index: driver/error.c =================================================================== --- driver/error.c (revision 530) +++ driver/error.c (working copy) @@ -329,6 +329,28 @@ } +/** + Handle a connection-related error. + + @param[in] stmt Statement +*/ +SQLRETURN handle_connection_error(STMT *stmt) +{ + unsigned int err= mysql_errno(&stmt->dbc->mysql); + switch (err) { + case CR_SERVER_GONE_ERROR: + case CR_SERVER_LOST: + return set_stmt_error(stmt, "08S01", mysql_error(&stmt->dbc->mysql), err); + case CR_OUT_OF_MEMORY: + return set_stmt_error(stmt, "HY001", mysql_error(&stmt->dbc->mysql), err); + case CR_COMMANDS_OUT_OF_SYNC: + case CR_UNKNOWN_ERROR: + default: + return set_stmt_error(stmt, "HY000", mysql_error(&stmt->dbc->mysql), err); + } +} + + /* @type : myodbc3 internal @purpose : sets the error information to appropriate handle. Index: test/my_catalog.c =================================================================== --- test/my_catalog.c (revision 530) +++ test/my_catalog.c (working copy) @@ -82,24 +82,6 @@ } -void check_sqlstate(SQLHSTMT hstmt,SQLCHAR *sqlstate) -{ - SQLCHAR sql_state[6]; - SQLINTEGER err_code=0; - SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH]={0}; - SQLSMALLINT err_len=0; - - memset(err_msg,'C',SQL_MAX_MESSAGE_LENGTH); - SQLGetDiagRec(SQL_HANDLE_STMT,hstmt,1, - (SQLCHAR *)&sql_state,(SQLINTEGER *)&err_code, - (SQLCHAR*)&err_msg, SQL_MAX_MESSAGE_LENGTH-1, - (SQLSMALLINT *)&err_len); - - printMessage("\n\t ERROR: %s\n",err_msg); - printMessage("\n SQLSTATE (expected:%s, obtained:%s)\n",sqlstate,sql_state); - myassert(strcmp(sql_state,sqlstate)==0); - -} #define TODBC_BIND_CHAR(n,buf) SQLBindCol(hstmt,n,SQL_C_CHAR,&buf,sizeof(buf),NULL); @@ -218,6 +200,14 @@ rc = SQLFreeStmt(hstmt, SQL_CLOSE); mystmt(hstmt,rc); + /* unknown table should be empty */ + rc = SQLTables(hstmt,"my_all_db_test%",SQL_NTS,NULL,0,"xyz",SQL_NTS,NULL,0); + mystmt(hstmt,rc); + + assert(0 == my_print_non_format_result(hstmt)); + rc = SQLFreeStmt(hstmt, SQL_CLOSE); + mystmt(hstmt,rc); + rc = SQLExecDirect(hstmt, "DROP DATABASE my_all_db_test1", SQL_NTS); mystmt(hstmt,rc); rc = SQLExecDirect(hstmt, "DROP DATABASE my_all_db_test2", SQL_NTS); @@ -1062,6 +1052,30 @@ return OK; } +/** + Bug #26934: SQLTables behavior has changed +*/ +DECLARE_TEST(t_bug26934) +{ + HENV henv1; + HDBC hdbc1; + HSTMT hstmt1; + + alloc_basic_handles(&henv1, &hdbc1, &hstmt1); + + ok_sql(hstmt1, "SET @@wait_timeout = 1"); + sleep(2); + expect_stmt(hstmt1, SQLTables(hstmt1, "%", 1, NULL, SQL_NTS, NULL, SQL_NTS, + NULL, SQL_NTS), SQL_ERROR); + if (check_sqlstate(hstmt1, "08S01") != OK) + return FAIL; + + free_basic_handles(&henv1, &hdbc1, &hstmt1); + + return OK; +} + + BEGIN_TESTS ADD_TEST(my_columns_null) ADD_TEST(my_drop_table) @@ -1081,6 +1095,7 @@ ADD_TEST(bug15713) ADD_TEST(t_bug28316) ADD_TEST(bug8860) + ADD_TEST(t_bug26934) END_TESTS Index: test/my_error.c =================================================================== --- test/my_error.c (revision 530) +++ test/my_error.c (working copy) @@ -23,23 +23,6 @@ #include "odbctap.h" -int check_sqlstate(SQLHDBC hdbc, SQLHSTMT hstmt, char *sqlstate) -{ - SQLCHAR sql_state[6]; - SQLINTEGER err_code= 0; - SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH]= {0}; - SQLSMALLINT err_len= 0; - - memset(err_msg, 'C', SQL_MAX_MESSAGE_LENGTH); - SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sql_state, &err_code, err_msg, - SQL_MAX_MESSAGE_LENGTH - 1, &err_len); - - is_str(sql_state, (SQLCHAR *)sqlstate, 5); - - return OK; -} - - DECLARE_TEST(t_odbc3_error) { SQLHENV henv1; @@ -63,14 +46,14 @@ ok_con(hdbc1, SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1)); expect_sql(hstmt1, "SELECT * FROM non_existing_table", SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "42S02") != OK) + if (check_sqlstate(hstmt1, "42S02") != OK) return FAIL; ok_sql(hstmt1, "DROP TABLE IF EXISTS t_error"); ok_sql(hstmt1, "CREATE TABLE t_error (id INT)"); expect_sql(hstmt1, "CREATE TABLE t_error (id INT)", SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "42S01") != OK) + if (check_sqlstate(hstmt1, "42S01") != OK) return FAIL; ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); @@ -78,7 +61,7 @@ expect_stmt(hstmt1, SQLSetStmtAttr(hstmt1, SQL_ATTR_FETCH_BOOKMARK_PTR, (SQLPOINTER)NULL, 0), SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "HYC00") != OK) + if (check_sqlstate(hstmt1, "HYC00") != OK) return FAIL; ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); @@ -118,14 +101,14 @@ ok_con(hdbc1, SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1)); expect_sql(hstmt1, "SELECT * FROM non_existing_table", SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "S0002") != OK) + if (check_sqlstate(hstmt1, "S0002") != OK) return FAIL; ok_sql(hstmt1, "DROP TABLE IF EXISTS t_error"); ok_sql(hstmt1, "CREATE TABLE t_error (id INT)"); expect_sql(hstmt1, "CREATE TABLE t_error (id INT)", SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "S0001") != OK) + if (check_sqlstate(hstmt1, "S0001") != OK) return FAIL; ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); @@ -133,7 +116,7 @@ expect_stmt(hstmt1, SQLSetStmtAttr(hstmt1, SQL_ATTR_FETCH_BOOKMARK_PTR, (SQLPOINTER)NULL, 0), SQL_ERROR); - if (check_sqlstate(hdbc1, hstmt1, "S1C00") != OK) + if (check_sqlstate(hstmt1, "S1C00") != OK) return FAIL; ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); @@ -265,7 +248,7 @@ /* Now check that the connection killed returns the right SQLSTATE */ expect_sql(hstmt2, "SELECT connection_id()", SQL_ERROR); - return check_sqlstate(hdbc2, hstmt2, "08S01"); + return check_sqlstate(hstmt2, "08S01"); } Index: test/include/odbctap.h =================================================================== --- test/include/odbctap.h (revision 530) +++ test/include/odbctap.h (working copy) @@ -349,6 +349,23 @@ } while (0); +int check_sqlstate(SQLHSTMT hstmt, char *sqlstate) +{ + SQLCHAR sql_state[6]; + SQLINTEGER err_code= 0; + SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH]= {0}; + SQLSMALLINT err_len= 0; + + memset(err_msg, 'C', SQL_MAX_MESSAGE_LENGTH); + SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sql_state, &err_code, err_msg, + SQL_MAX_MESSAGE_LENGTH - 1, &err_len); + + is_str(sql_state, (SQLCHAR *)sqlstate, 5); + + return OK; +} + + /** */ static void print_diag(SQLRETURN rc, SQLSMALLINT htype, SQLHANDLE handle, @@ -418,8 +435,8 @@ { SQLRETURN rc; - rc= SQLEndTran(SQL_HANDLE_DBC, *hdbc, SQL_COMMIT); - mycon(*hdbc, rc); + /* We don't care if this succeeds, the connection may have gone away. */ + (void)SQLEndTran(SQL_HANDLE_DBC, *hdbc, SQL_COMMIT); rc= SQLFreeStmt(*hstmt, SQL_DROP); mystmt(*hstmt,rc); Index: MYODBC_MYSQL.h =================================================================== --- MYODBC_MYSQL.h (revision 530) +++ MYODBC_MYSQL.h (working copy) @@ -13,6 +13,7 @@ #include #include #include +#include #if MYSQL_VERSION_ID < MIN_MYSQL_VERSION error "MyODBC need a newer version of the MYSQL client library to compile"