=== modified file 'ChangeLog' --- ChangeLog 2010-03-01 22:45:48 +0000 +++ ChangeLog 2010-03-07 19:42:50 +0000 @@ -8,6 +8,7 @@ Bugs fixed: * If NO_BACKSLASH_ESCAPES mode is used on a server, escaping binary data can lead to server query parsing errors. (Bug #49029) + * SQLPrimaryKeys returns mangled strings. (Bug #36441) ---- === modified file 'driver/catalog.c' --- driver/catalog.c 2010-01-31 00:29:06 +0000 +++ driver/catalog.c 2010-03-07 09:45:00 +0000 @@ -838,6 +838,7 @@ stmt->result->row_count= rows; mysql_link_fields(stmt, SQLCOLUMNS_fields, SQLCOLUMNS_FIELDS); + return SQL_SUCCESS; empty_set: @@ -1542,6 +1543,8 @@ const uint SQLPRIM_KEYS_FIELDS= array_elements(SQLPRIM_KEYS_fields); +const long SQLPRIM_LENGTHES[]= {0, 0, 1, 5, 4, -7}; + char *SQLPRIM_KEYS_values[]= { NULL,"",NULL,NULL,0,NULL }; @@ -1586,13 +1589,23 @@ } pthread_mutex_unlock(&stmt->dbc->lock); stmt->result_array= (char**) my_malloc(sizeof(char*)*SQLPRIM_KEYS_FIELDS* - (ulong) stmt->result->row_count, - MYF(MY_ZEROFILL)); + (ulong) stmt->result->row_count, + MYF(MY_ZEROFILL)); if (!stmt->result_array) { set_mem_error(&stmt->dbc->mysql); return handle_connection_error(stmt); } + + stmt->lengths= (unsigned long*) my_malloc( sizeof(long)*SQLPRIM_KEYS_FIELDS* + (ulong) stmt->result->row_count, + MYF(MY_ZEROFILL)); + if (!stmt->lengths) + { + set_mem_error(&stmt->dbc->mysql); + return handle_connection_error(stmt); + } + row_count= 0; data= stmt->result_array; while ( (row= mysql_fetch_row(stmt->result)) ) @@ -1600,8 +1613,11 @@ if ( row[1][0] == '0' ) /* If unique index */ { if ( row_count && !strcmp(row[3],"1") ) - break; /* Allready found unique key */ - row_count++; + break; /* Already found unique key */ + + fix_row_lengthes(stmt, SQLPRIM_LENGTHES, row_count, SQLPRIM_KEYS_FIELDS); + + ++row_count; data[0]= data[1]=0; data[2]= row[0]; data[3]= row[4]; @@ -1613,6 +1629,7 @@ stmt->result->row_count= row_count; mysql_link_fields(stmt,SQLPRIM_KEYS_fields,SQLPRIM_KEYS_FIELDS); + return SQL_SUCCESS; } === modified file 'driver/driver.h' --- driver/driver.h 2010-01-31 00:29:06 +0000 +++ driver/driver.h 2010-03-04 18:39:15 +0000 @@ -394,6 +394,8 @@ STMT_OPTIONS stmt_options; char *table_name; char *query,*query_end; + unsigned long *lengths; /* used to set lengths if we shuffle field values + of the resultset of auxiliary query or if we fix_fields. */ /* We save a copy of the original query before we modify it for 'WHERE CURRENT OF' cursor handling. === modified file 'driver/handle.c' --- driver/handle.c 2010-01-31 00:29:06 +0000 +++ driver/handle.c 2010-03-04 13:58:28 +0000 @@ -443,11 +443,13 @@ x_free(stmt->fields); x_free(stmt->array); x_free(stmt->result_array); + x_free(stmt->lengths); stmt->result= 0; stmt->fake_result= 0; stmt->fields= 0; stmt->array= 0; stmt->result_array= 0; + stmt->lengths= 0; stmt->current_values= 0; /* For SQLGetData */ stmt->fix_fields= 0; stmt->affected_rows= 0; === modified file 'driver/results.c' --- driver/results.c 2010-01-31 00:29:06 +0000 +++ driver/results.c 2010-03-07 19:30:12 +0000 @@ -1345,8 +1345,23 @@ stmt->ird->array_status_ptr[i]= SQL_ROW_SUCCESS; if (!stmt->fix_fields) - fill_ird_data_lengths(stmt->ird, mysql_fetch_lengths(stmt->result), - stmt->result->field_count); + { + /* lengths contains lengths for all rows. Alternate use could be + filling ird buffers in the (fix_fields) function. In this case + lengths could contain just one array with rules for lengths + calculating(it can work out in many cases like in catalog functions + there some fields from results of auxiliary query are simply mixed + somehow and constant fields added ). + Another approach could be using of "array" and "order" arrays + and special fix_fields callback, that will fix array and set + lengths in ird*/ + if (stmt->lengths) + fill_ird_data_lengths(stmt->ird, stmt->lengths + cur_row*stmt->result->field_count, + stmt->result->field_count); + else + fill_ird_data_lengths(stmt->ird, mysql_fetch_lengths(stmt->result), + stmt->result->field_count); + } res= fill_fetch_buffers(stmt, values, i); cur_row++; } === modified file 'driver/utility.c' --- driver/utility.c 2010-01-31 00:29:06 +0000 +++ driver/utility.c 2010-03-07 19:19:17 +0000 @@ -81,6 +81,39 @@ /** +Fills STMT's lengths array for given row. Makes use of mysql_link_fields a bit +less terrible. + +@param[in,out] stmt The statement to modify +@param[in] fix_rules Describes how to calculate lengths. For each element value + N > 0 - length is taken of field #N from original results + (counting from 1) + N <=0 - constant length (-N) +@param[in] row Row for which to fix lengths +@param[in] field_count The number of fields +*/ +void fix_row_lengthes(STMT *stmt, const long* fix_rules, uint row, uint field_count) +{ + unsigned long* orig_lengths, *row_lengths; + uint i; + + if (stmt->lengths == NULL) + return; + + row_lengths= stmt->lengths + row*field_count; + orig_lengths= mysql_fetch_lengths(stmt->result); + + for (i= 0; i < field_count; ++i) + { + if (fix_rules[i] > 0) + row_lengths[i]= orig_lengths[fix_rules[i] - 1]; + else + row_lengths[i]= -fix_rules[i]; + } +} + + +/** Figure out the ODBC result types for each column in the result set. @param[in] stmt The statement with result types to be fixed. === modified file 'test/my_catalog.c' --- test/my_catalog.c 2010-01-31 00:29:06 +0000 +++ test/my_catalog.c 2010-03-07 18:54:32 +0000 @@ -346,7 +346,7 @@ ok_sql(hstmt, "drop table if exists t_catalog"); - ok_sql(hstmt,"create table t_catalog(a tinyint, b char(4))"); + ok_sql(hstmt,"create table t_catalog(abc tinyint, bcdefghijklmno char(4), uifield int unsigned not null)"); ok_stmt(hstmt, SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR *)"t_catalog", 9, NULL, 0)); @@ -356,7 +356,7 @@ printMessage("total columns: %d", ncols); myassert(ncols == 18); - myassert(myresult(hstmt) == 2); + myassert(myresult(hstmt) == 3); SQLFreeStmt(hstmt, SQL_UNBIND); SQLFreeStmt(hstmt, SQL_CLOSE); @@ -1443,7 +1443,59 @@ } +DECLARE_TEST(t_bug36441) +{ +#define BUF_LEN 24 + + const SQLCHAR key_column_name[][14]= {"pk_for_table1", "c1_for_table1"}; + + SQLCHAR catalog[BUF_LEN], schema[BUF_LEN], table[BUF_LEN], column[BUF_LEN]; + SQLINTEGER catalog_len, schema_len, table_len, column_len; + SQLCHAR keyname[BUF_LEN]; + SQLSMALLINT key_seq, i; + SQLINTEGER keyname_len, key_seq_len; + + ok_sql(hstmt, "drop table if exists t_bug36441_0123456789"); + ok_sql(hstmt, "create table t_bug36441_0123456789(" + "pk_for_table1 integer not null auto_increment," + "c1_for_table1 varchar(128) not null unique," + "c2_for_table1 binary(32) null," + "unique_key int unsigned not null unique," + "primary key(pk_for_table1, c1_for_table1))"); + + ok_stmt(hstmt, SQLPrimaryKeys(hstmt, NULL, SQL_NTS, NULL, SQL_NTS, "t_bug36441_0123456789", SQL_NTS)); + + ok_stmt(hstmt, SQLBindCol(hstmt, 1, SQL_C_CHAR , catalog, sizeof(catalog), &catalog_len)); + ok_stmt(hstmt, SQLBindCol(hstmt, 2, SQL_C_CHAR , schema , sizeof(schema) , &schema_len)); + ok_stmt(hstmt, SQLBindCol(hstmt, 3, SQL_C_CHAR , table , sizeof(table) , &table_len)); + ok_stmt(hstmt, SQLBindCol(hstmt, 4, SQL_C_CHAR , column , sizeof(column) , &column_len)); + ok_stmt(hstmt, SQLBindCol(hstmt, 5, SQL_C_SHORT,&key_seq, sizeof(key_seq), &key_seq_len)); + ok_stmt(hstmt, SQLBindCol(hstmt, 6, SQL_C_CHAR , keyname, sizeof(keyname), &keyname_len)); + + for(i=0; i < 2; ++i) + { + ok_stmt(hstmt, SQLFetch(hstmt)); + + is_num(catalog_len, SQL_NULL_DATA); + is_num(schema_len, SQL_NULL_DATA); + is_str(table, "t_bug36441_0123456789", 3); + is_str(column, key_column_name[i], 4); + is_num(key_seq, i+1); + is_str(keyname, "PRIMARY", 6); + } + + expect_stmt(hstmt, SQLFetch(hstmt), SQL_NO_DATA); + + ok_sql(hstmt, "drop table if exists t_bug36441_0123456789"); + + return OK; + +#undef BUF_LEN +} + + BEGIN_TESTS + ADD_TEST(my_columns_null) ADD_TEST(my_drop_table) ADD_TEST(my_table_dbs) @@ -1473,6 +1525,7 @@ ADD_TEST(t_bug30770) ADD_TEST(t_bug36275) ADD_TEST(t_bug39957) + ADD_TEST(t_bug36441) END_TESTS