Index: driver/results.c =================================================================== --- driver/results.c (revision 1078) +++ driver/results.c (working copy) @@ -533,12 +533,8 @@ if (pfSqlType) *pfSqlType= get_sql_data_type(stmt, field, NULL); if (pnColumnSize) - { - SQLULEN size= get_column_size(stmt, field, FALSE); - if ((stmt->dbc->flag & FLAG_COLUMN_SIZE_S32) && size > INT_MAX32) - size= INT_MAX32; - *pnColumnSize= size; - } + *pnColumnSize= get_column_size(stmt, field, FALSE); + if (pibScale) *pibScale= (SQLSMALLINT)myodbc_max(0, get_decimal_digits(stmt, field)); if (pfNullable) @@ -694,7 +690,16 @@ break; case SQL_DESC_LENGTH: - *NumericAttributePtr= get_column_size(stmt, field, TRUE); + { + /* + Always return signed length value to keep the compatibility with + unixODBC and iODBC + */ + SQLULEN col_len; + col_len= get_column_size(stmt, field, TRUE); + *NumericAttributePtr= (sizeof(SQLLEN) == 4) && + (col_len > INT_MAX32) ? INT_MAX32 : col_len; + } break; case SQL_COLUMN_LENGTH: @@ -776,8 +781,15 @@ case SQL_COLUMN_PRECISION: case SQL_DESC_PRECISION: - *(SQLINTEGER *)NumericAttributePtr= get_column_size(stmt, field, - FALSE); + { + /* + Always return signed length value to keep the compatibility with + unixODBC and iODBC + */ + SQLULEN col_len= get_column_size(stmt, field, FALSE); + *(SQLLEN *)NumericAttributePtr= (sizeof(SQLLEN) == 4) && + (col_len > INT_MAX32) ? INT_MAX32 : col_len; + } break; case SQL_COLUMN_SCALE: Index: driver/utility.c =================================================================== --- driver/utility.c (revision 1078) +++ driver/utility.c (working copy) @@ -559,7 +559,26 @@ } -/** +/** + Fill the column size buffer accordingly to size of SQLULEN + @param[in,out] buff + @param[in] stmt + @param[in] field + @param[in] actual If true, field->max_length is used instead of + field->length, to retrieve the actual length of + data in the field + + @return void +*/ +void fill_column_size_buff(char *buff, STMT *stmt, MYSQL_FIELD *field, + my_bool actual) +{ + sprintf(buff, (sizeof(SQLULEN) == 4 ? "%ld" : "%llu"), + get_column_size(stmt, field, actual)); +} + + +/** Get the column size (in characters) of a field, as defined at: http://msdn2.microsoft.com/en-us/library/ms711786.aspx @@ -571,12 +590,12 @@ @return The column size of the field */ -SQLLEN get_column_size(STMT *stmt __attribute__((unused)), MYSQL_FIELD *field, +SQLULEN get_column_size(STMT *stmt, MYSQL_FIELD *field, my_bool actual) { CHARSET_INFO *charset= get_charset(field->charsetnr, MYF(0)); unsigned int mbmaxlen= charset ? charset->mbmaxlen : 1; - SQLLEN length= actual ? field->max_length : field->length; + SQLULEN length= actual ? field->max_length : field->length; switch (field->type) { case MYSQL_TYPE_TINY: @@ -642,10 +661,11 @@ case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: - if (field->charsetnr == 63) - return length; - else - return length / mbmaxlen; + if (field->charsetnr != 63) + length= length / mbmaxlen; + + return (stmt->dbc->flag & FLAG_COLUMN_SIZE_S32) ? + (length > INT_MAX32 ? INT_MAX32 : length) : length; } return SQL_NO_TOTAL; Index: driver/catalog.c =================================================================== --- driver/catalog.c (revision 1078) +++ driver/catalog.c (working copy) @@ -824,7 +824,7 @@ } /* COLUMN_SIZE */ - sprintf(buff, "%ld", get_column_size(stmt, field, FALSE)); + fill_column_size_buff(buff, stmt, field, FALSE); row[6]= strdup_root(alloc, buff); /* BUFFER_LENGTH */ @@ -1496,7 +1496,7 @@ row[3]= strdup_root(alloc,buff); sprintf(buff,"%d",type); row[2]= strdup_root(alloc,buff); - sprintf(buff, "%ld", get_column_size(stmt, field, FALSE)); + fill_column_size_buff(buff, stmt, field, FALSE); row[4]= strdup_root(alloc,buff); sprintf(buff, "%ld", get_transfer_octet_length(stmt, field)); row[5]= strdup_root(alloc,buff); @@ -1572,7 +1572,7 @@ row[3]= strdup_root(alloc,buff); sprintf(buff,"%d",type); row[2]= strdup_root(alloc,buff); - sprintf(buff,"%ld", get_column_size(stmt, field, FALSE)); + fill_column_size_buff(buff, stmt, field, FALSE); row[4]= strdup_root(alloc,buff); sprintf(buff,"%ld", get_transfer_octet_length(stmt, field)); row[5]= strdup_root(alloc,buff); Index: driver/myutil.h =================================================================== --- driver/myutil.h (revision 1078) +++ driver/myutil.h (working copy) @@ -145,7 +145,7 @@ void translate_error(char *save_state,myodbc_errid errid,uint mysql_err); SQLSMALLINT get_sql_data_type(STMT *stmt, MYSQL_FIELD *field, char *buff); -SQLLEN get_column_size(STMT *stmt, MYSQL_FIELD *field, my_bool actual); +SQLULEN get_column_size(STMT *stmt, MYSQL_FIELD *field, my_bool actual); SQLLEN get_decimal_digits(STMT *stmt, MYSQL_FIELD *field); SQLLEN get_transfer_octet_length(STMT *stmt, MYSQL_FIELD *field); SQLLEN get_display_size(STMT *stmt, MYSQL_FIELD *field); Index: test/my_catalog.c =================================================================== --- test/my_catalog.c (revision 1078) +++ test/my_catalog.c (working copy) @@ -1205,6 +1205,81 @@ } +/** + Bug #12805: ADO failed to retrieve the length of LONGBLOB columns +*/ +DECLARE_TEST(t_bug12805) +{ + SQLHENV henv1; + SQLHDBC hdbc1; + SQLHSTMT hstmt1; + SQLULEN length; + + SET_DSN_OPTION(1 << 27); + + alloc_basic_handles(&henv1, &hdbc1, &hstmt1); + + ok_sql(hstmt1, "DROP TABLE IF EXISTS bug12805"); + ok_sql(hstmt1, "CREATE TABLE bug12805("\ + "id INT PRIMARY KEY auto_increment,"\ + "longimagedata LONGBLOB NULL)"); + + ok_stmt(hstmt1, SQLColumns(hstmt1, NULL, 0, NULL, 0, + (SQLCHAR *)"bug12805", SQL_NTS, + (SQLCHAR *)"longimagedata", SQL_NTS)); + + ok_stmt(hstmt1, SQLFetch(hstmt1)); + ok_stmt(hstmt1, SQLGetData(hstmt1, 7, SQL_C_ULONG, &length, + sizeof(SQLULEN), NULL)); + is_num(length, 2147483647); + ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); + + length= 0; + ok_sql(hstmt1, "SELECT * FROM bug12805"); + ok_stmt(hstmt1, SQLDescribeCol(hstmt1, 2, NULL, NULL, NULL, NULL, + &length, NULL, NULL)); + is_num(length, 2147483647); + + length= 0; + ok_stmt(hstmt1, SQLColAttribute(hstmt1, 2, SQL_DESC_PRECISION, NULL, 0, + NULL, &length)); + + is_num(length, 2147483647); + ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE)); + free_basic_handles(&henv1, &hdbc1, &hstmt1); + + /* Check without the 32-bit signed flag */ + ok_stmt(hstmt, SQLColumns(hstmt, NULL, 0, NULL, 0, + (SQLCHAR *)"bug12805", SQL_NTS, + (SQLCHAR *)"longimagedata", SQL_NTS)); + + ok_stmt(hstmt, SQLFetch(hstmt)); + ok_stmt(hstmt, SQLGetData(hstmt, 7, SQL_C_ULONG, &length, + sizeof(SQLULEN), NULL)); + is_num(length, 4294967295); + + ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE)); + + length= 0; + ok_sql(hstmt, "SELECT * FROM bug12805"); + ok_stmt(hstmt, SQLDescribeCol(hstmt, 2, NULL, NULL, NULL, NULL, + &length, NULL, NULL)); + is_num(length, 4294967295); + + length= 0; + ok_stmt(hstmt, SQLColAttribute(hstmt, 2, SQL_DESC_PRECISION, NULL, 0, + NULL, &length)); + + /* This length is always 2G */ + is_num(length, 2147483647); + ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE)); + ok_sql(hstmt, "DROP TABLE bug12805"); + + SET_DSN_OPTION(0); + return OK; +} + + BEGIN_TESTS ADD_TEST(my_columns_null) ADD_TEST(my_drop_table) @@ -1230,6 +1305,7 @@ ADD_TEST(t_bug32864) ADD_TEST(t_bug32989) ADD_TEST(t_bug33298) + ADD_TEST(t_bug12805) END_TESTS