Modified:
trunk/ChangeLog
trunk/driver/catalog.c
trunk/driver/myutil.h
trunk/driver/utility.c
trunk/test/my_catalog.c
Log:
SQLForeignKeys() did not properly escape wildcard characters in its
table name parameters when retrieving information. (Bug #27723)
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2007-05-11 17:10:27 UTC (rev 417)
+++ trunk/ChangeLog 2007-05-11 17:23:13 UTC (rev 418)
@@ -1,6 +1,8 @@
3.51.16
Functionality added or changed:
+ * SQLForeignKeys() did not properly escape wildcard characters in its
+ table name parameters when retrieving information. (Bug #27723)
* Calls to SQLSetPos() could cause the driver to incorrectly calculate the
length of some fields. (Bug #16917)
Modified: trunk/driver/catalog.c
===================================================================
--- trunk/driver/catalog.c 2007-05-11 17:10:27 UTC (rev 417)
+++ trunk/driver/catalog.c 2007-05-11 17:23:13 UTC (rev 418)
@@ -1849,8 +1849,8 @@
if (table && *table)
{
to= strmov(to, "LIKE '");
- /** @todo this is *wrong* -- we need to escape % and _ */
- to+= mysql_real_escape_string(mysql, to, (char *)table, table_length);
+ to+= myodbc_escape_wildcard(mysql, to, sizeof(buff) - (to - buff),
+ (char *)table, table_length);
to= strmov(to, "'");
}
Modified: trunk/driver/myutil.h
===================================================================
--- trunk/driver/myutil.h 2007-05-11 17:10:27 UTC (rev 417)
+++ trunk/driver/myutil.h 2007-05-11 17:23:13 UTC (rev 418)
@@ -162,6 +162,9 @@
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);
+
/* Functions used when debugging */
#ifdef MYODBC_DBG
void query_print(FILE *log_file,char *query);
Modified: trunk/driver/utility.c
===================================================================
--- trunk/driver/utility.c 2007-05-11 17:10:27 UTC (rev 417)
+++ trunk/driver/utility.c 2007-05-11 17:23:13 UTC (rev 418)
@@ -1188,3 +1188,111 @@
return TRUE;
return FALSE;
}
+
+
+/**
+ Escapes a string that may contain wildcard characters (%, _) and other
+ problematic characters (", ', \n, etc). Like mysql_real_escape_string() but
+ also including % and _.
+
+ @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
+
+*/
+ulong myodbc_escape_wildcard(MYSQL *mysql, char *to, ulong to_length,
+ const char *from, ulong length)
+{
+ CHARSET_INFO *charset_info= mysql->charset;
+ const char *to_start= to;
+ const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
+ my_bool overflow= FALSE;
+#ifdef USE_MB
+ my_bool use_mb_flag= use_mb(charset_info);
+#endif
+ for (end= from + length; from < end; from++)
+ {
+ char escape= 0;
+#ifdef USE_MB
+ int tmp_length;
+ if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
+ {
+ if (to + tmp_length > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ while (tmp_length--)
+ *to++= *from++;
+ from--;
+ continue;
+ }
+ /*
+ If the next character appears to begin a multi-byte character, we
+ escape that first byte of that apparent multi-byte character. (The
+ character just looks like a multi-byte character -- if it were actually
+ a multi-byte character, it would have been passed through in the test
+ above.)
+
+ Without this check, we can create a problem by converting an invalid
+ multi-byte character into a valid one. For example, 0xbf27 is not
+ a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
+ */
+ if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
+ escape= *from;
+ else
+#endif
+ switch (*from) {
+ case 0: /* Must be escaped for 'mysql' */
+ escape= '0';
+ break;
+ 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 '_':
+ escape= '_';
+ break;
+ case '%':
+ escape= '%';
+ break;
+ case '\032': /* This gives problems on Win32 */
+ escape= 'Z';
+ break;
+ }
+ if (escape)
+ {
+ if (to + 2 > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ *to++= '\\';
+ *to++= escape;
+ }
+ else
+ {
+ if (to + 1 > to_end)
+ {
+ overflow= TRUE;
+ break;
+ }
+ *to++= *from;
+ }
+ }
+ *to= 0;
+ return overflow ? (ulong)~0 : (ulong) (to - to_start);
+}
Modified: trunk/test/my_catalog.c
===================================================================
--- trunk/test/my_catalog.c 2007-05-11 17:10:27 UTC (rev 417)
+++ trunk/test/my_catalog.c 2007-05-11 17:23:13 UTC (rev 418)
@@ -1121,11 +1121,16 @@
/**
Bug #4518: SQLForeignKeys returns too many foreign key
+ Bug #27723: SQLForeignKeys does not escape _ and % in the table name arguments
+
+ The original test case was extended to have a table that would inadvertantly
+ get included because of the poor escaping.
*/
DECLARE_TEST(t_bug4518)
{
+ SQLCHAR buff[255];
- ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug4518_c, t_bug4518_c2, "
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug4518_c, t_bug4518_c2, t_bug4518ac, "
" t_bug4518_p");
ok_sql(hstmt, "CREATE TABLE t_bug4518_p (id INT PRIMARY KEY) ENGINE=InnoDB");
ok_sql(hstmt, "CREATE TABLE t_bug4518_c (id INT, parent_id INT,"
@@ -1140,15 +1145,28 @@
" t_bug4518_p(id)"
" ON DELETE SET NULL)"
" ENGINE=InnoDB");
+ ok_sql(hstmt, "CREATE TABLE t_bug4518ac (id INT, parent_id INT,"
+ " FOREIGN KEY (parent_id)"
+ " REFERENCES"
+ " t_bug4518_p(id)"
+ " ON DELETE SET NULL)"
+ " ENGINE=InnoDB");
ok_stmt(hstmt, SQLForeignKeys(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
NULL, 0, (SQLCHAR *)"t_bug4518_c", SQL_NTS));
- my_assert(1 == my_print_non_format_result(hstmt));
+ ok_stmt(hstmt, SQLFetch(hstmt));
+ is_str(my_fetch_str(hstmt, buff, 3), "t_bug4518_p", 11);
+ is_str(my_fetch_str(hstmt, buff, 4), "id", 2);
+ is_str(my_fetch_str(hstmt, buff, 7), "t_bug4518_c", 11);
+ is_str(my_fetch_str(hstmt, buff, 8), "parent_id", 9);
+ expect_stmt(hstmt, SQLFetch(hstmt), SQL_NO_DATA_FOUND);
+
ok_stmt(hstmt, SQLFreeStmt(hstmt,SQL_CLOSE));
- ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug4518_c, t_bug4518_c2, t_bug4518_p");
+ ok_sql(hstmt,
+ "DROP TABLE t_bug4518_c, t_bug4518_c2, t_bug4518ac, t_bug4518_p");
return OK;
}
| Thread |
|---|
| • Connector/ODBC 3.51 commit: r418 - in trunk: . driver test | jwinstead | 11 May |