Index: driver/utility.c =================================================================== --- driver/utility.c (revision 1012) +++ driver/utility.c (working copy) @@ -1425,18 +1425,19 @@ /** Escapes a string that may contain wildcard characters (%, _) and other problematic characters (", ', \n, etc). Like mysql_real_escape_string() but - also including % and _. + also including % and _. Can be used with an identifier by passing escape_id. @param[in] mysql Pointer to MYSQL structure @param[out] to Buffer for escaped string @param[in] to_length Length of destination buffer, or 0 for "big enough" @param[in] from The string to escape @param[in] length The length of the string to escape + @param[in] escape_id Escaping an identifier that will be quoted */ -ulong myodbc_escape_wildcard(MYSQL *mysql __attribute__((unused)), - char *to, ulong to_length, - const char *from, ulong length) +ulong myodbc_escape_string(MYSQL *mysql __attribute__((unused)), + char *to, ulong to_length, + const char *from, ulong length, int escape_id) { const char *to_start= to; const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length); @@ -1458,7 +1459,7 @@ break; } while (tmp_length--) - *to++= *from++; + *to++= *from++; from--; continue; } @@ -1478,34 +1479,34 @@ else #endif switch (*from) { - case 0: /* Must be escaped for 'mysql' */ + case 0: /* Must be escaped for 'mysql' */ escape= '0'; break; - case '\n': /* Must be escaped for logs */ + case '\n': /* Must be escaped for logs */ escape= 'n'; break; case '\r': escape= 'r'; break; case '\\': - escape= '\\'; - break; case '\'': - escape= '\''; - break; - case '"': /* Better safe than sorry */ - escape= '"'; - break; + case '"': /* Better safe than sorry */ case '_': - escape= '_'; - break; case '%': - escape= '%'; + escape= *from; break; - case '\032': /* This gives problems on Win32 */ + case '\032': /* This gives problems on Win32 */ escape= 'Z'; break; } + /* if escaping an id, only handle back-tick */ + if (escape_id) + { + if (*from == '`') + escape= *from; + else + escape= 0; + } if (escape) { if (to + 2 > to_end) Index: driver/catalog.c =================================================================== --- driver/catalog.c (revision 1012) +++ driver/catalog.c (working copy) @@ -280,7 +280,8 @@ if (catalog && *catalog) { to= strmov(to, "FROM `"); - to+= mysql_real_escape_string(mysql, to, (char *)catalog, catalog_length); + to+= myodbc_escape_string(mysql, to, sizeof(buff) - (to - buff), + (char *)catalog, catalog_length, 1); to= strmov(to, "` "); } @@ -298,8 +299,8 @@ if (wildcard) to+= mysql_real_escape_string(mysql, to, (char *)table, table_length); else - to+= myodbc_escape_wildcard(mysql, to, sizeof(buff) - (to - buff), - (char *)table, table_length); + to+= myodbc_escape_string(mysql, to, sizeof(buff) - (to - buff), + (char *)table, table_length, 0); to= strmov(to, "'"); } @@ -611,17 +612,20 @@ { char buff[255]; char *select, *to; + size_t select_len; unsigned long *lengths; /* Get a list of column names that match our criteria. */ to= strmov(buff, "SHOW COLUMNS FROM `"); if (cbCatalog) { - to+= mysql_real_escape_string(mysql, to, (char *)szCatalog, cbCatalog); + to+= myodbc_escape_string(mysql, to, sizeof(buff) - (to - buff), + (char *)szCatalog, cbCatalog, 1); to= strmov(to, "`.`"); } - to+= mysql_real_escape_string(mysql, to, (char *)szTable, cbTable); + to+= myodbc_escape_string(mysql, to, sizeof(buff) - (to - buff), + (char *)szTable, cbTable, 1); to= strmov(to, "`"); if (cbColumn) @@ -643,9 +647,8 @@ pthread_mutex_unlock(&dbc->lock); /* Build a SELECT ... LIMIT 0 to get the field metadata. */ - if (!(select= (char *)my_malloc(sizeof(char) * (ulong)result->row_count * - (NAME_LEN + 1) + NAME_LEN * 2, - MYF(0)))) + select_len = (ulong)result->row_count * (NAME_LEN + 1) + NAME_LEN * 2; + if (!(select= (char *)my_malloc(select_len, MYF(0)))) { set_mem_error(mysql); return NULL; @@ -656,7 +659,8 @@ { to= strmov(to, "`"); lengths= mysql_fetch_lengths(result); - to+= mysql_real_escape_string(mysql, to, row[0], lengths[0]); + to+= myodbc_escape_string(mysql, to, select_len - (to - select), + (char *)row[0], lengths[0], 1); to= strmov(to, "`,"); } *(--to)= '\0'; @@ -664,11 +668,13 @@ to= strmov(to, " FROM `"); if (cbCatalog) { - to+= mysql_real_escape_string(mysql, to, (char *)szCatalog, cbCatalog); + to+= myodbc_escape_string(mysql, to, select_len - (to - select), + (char *)szCatalog, cbCatalog, 1); to= strmov(to, "`.`"); } - to+= mysql_real_escape_string(mysql, to, (char *)szTable, cbTable); + to+= myodbc_escape_string(mysql, to, select_len - (to - select), + (char *)szTable, cbTable, 1); to= strmov(to, "` LIMIT 0"); mysql_free_result(result); Index: driver/myutil.h =================================================================== --- driver/myutil.h (revision 1012) +++ driver/myutil.h (working copy) @@ -215,8 +215,8 @@ int myodbc_casecmp(const char *s, const char *t, uint len); my_bool reget_current_catalog(DBC FAR *dbc); -ulong myodbc_escape_wildcard(MYSQL *mysql, char *to, ulong to_length, - const char *from, ulong length); +ulong myodbc_escape_string(MYSQL *mysql, char *to, ulong to_length, + const char *from, ulong length, int escape_id); /* Functions used when debugging */ void query_print(FILE *log_file,char *query); Index: test/my_catalog.c =================================================================== --- test/my_catalog.c (revision 1012) +++ test/my_catalog.c (working copy) @@ -1129,6 +1129,31 @@ } +/* + Bug #32989 - Crystal Reports fails if a field has a single quote +*/ +DECLARE_TEST(t_bug32989) +{ + SQLCHAR name[20]; + SQLLEN len; + + ok_sql(hstmt, "drop table if exists t_bug32989"); + ok_sql(hstmt, "create table t_bug32989 (`doesn't work` int)"); + + ok_stmt(hstmt, SQLColumns(hstmt, "test", SQL_NTS, NULL, 0, + "t_bug32989", SQL_NTS, NULL, 0)); + ok_stmt(hstmt, SQLFetch(hstmt)); + + ok_stmt(hstmt, SQLGetData(hstmt, 4, SQL_C_CHAR, name, 20, &len)); + is_num(len, 12); + is_str(name, "doesn't work", 13); + ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE)); + + ok_sql(hstmt, "drop table if exists t_bug32989"); + return OK; +} + + BEGIN_TESTS ADD_TEST(my_columns_null) ADD_TEST(my_drop_table) @@ -1151,6 +1176,7 @@ ADD_TEST(t_bug26934) ADD_TEST(t_bug29888) ADD_TEST(t_bug14407) + ADD_TEST(t_bug32989) END_TESTS