List:Commits« Previous MessageNext Message »
From:jwinstead Date:May 11 2007 5:23pm
Subject:Connector/ODBC 3.51 commit: r418 - in trunk: . driver test
View as plain text  
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 testjwinstead11 May