MySQL Connector C / C API - 使用特殊字符进行查询

时间:2016-12-23 16:13:13

标签: mysql c mysql-connector

我是一个C程序我有一个函数,它接受一个域名参数:

void db_domains_query(char *name);

使用mysql_query()我测试域名是否存在于数据库中。如果不是这样,我插入新的域名:

...
char *query[400];

sprintf(query, "SELECT Id, DomainName FROM domains WHERE domainName LIKE '%s'", name);
if (mysql_query(con, query))
finish_with_error(con);

MYSQL_RES *result = mysql_store_result(con);
    if (result == NULL)
        finish_with_error(con);

    MYSQL_ROW row;
    if ((row = mysql_fetch_row(result)))
        printf("Element exists : %s %s\n", row[0], row[1]);
    else
        printf("Element %s doesn't found\n", name);
        // Then insert the new domain name ...

如果 name 仅包含“普通字符”,则此部分代码可以正常工作。但是,对于包含“特殊字符”的域名,查询似乎不正确,即使它们位于数据库中,例如:

  • name = undaben.de:Element exists : 100 undaben.de
  • name =®here.com:Element ®here.com is not found.
  • name =§travel.us:Element §travel.us is not found.

    表格的摘录:

    +-----+--------------+ | id | domainname | +-----+--------------+ | 100 | undaben.de | | 162 | §travel.us | | 197 | ®here.com | +-----+--------------+

字段 domainname 的排序规则是utf8_unicode_ci。 那么如何将包含“特殊”域名的所有域名传递给mysql_query呢?

2 个答案:

答案 0 :(得分:0)

我建议您避免使用C API,除非您有令人信服的理由使用它。 C ++ API更有用。

您正在查询字符串中嵌入参数。这有许多问题,包括安全风险。如果你坚持这种方法,为了防止参数搞乱你的查询问题,你需要确保一些事情:

  • 确保您的数据编码与MySQL客户端连接的编码匹配(这可能与您的数据库编码不同)。如果您的连接设置为UTF-8,那么当用作sprintf函数的输入时,您需要确保特殊字符(如©)也以UTF-8编码。
  • 您还需要保护其他SQL转义字符(例如')。为此,您可以使用mysql_real_escape_string中提到的 sql = "select count(*) from addresses where id = ?"; // Open Database openDB(&conn); // Allocate statement handler stmt = mysql_stmt_init(conn); if (stmt == NULL) { print_error(conn, "Could not initialize statement handler"); return; } // Prepare the statement if (mysql_stmt_prepare(stmt, sql, strlen(sql)) != 0) { print_stmt_error(stmt, "Could not prepare statement"); return; } // Initialize the result column structures memset (param, 0, sizeof (param)); /* zero the structures */ memset (result, 0, sizeof (result)); /* zero the structures */ // Init param structure // Select param[0].buffer_type = MYSQL_TYPE_LONG; param[0].buffer = (void *) &myId; param[0].is_unsigned = 0; param[0].is_null = 0; param[0].length = 0; // Result result[0].buffer_type = MYSQL_TYPE_LONG; result[0].buffer = (void *) &myNumAddresses; result[0].is_unsigned = 0; result[0].is_null = &is_null[0]; result[0].length = 0; // Bind param structure to statement if (mysql_stmt_bind_param(stmt, param) != 0) { print_stmt_error(stmt, "Could not bind parameters"); return; } // Bind result if (mysql_stmt_bind_result(stmt, result) != 0) { print_stmt_error(stmt, "Could not bind results"); return; } // Set bind parameters myId = id; // Execute!! if (mysql_stmt_execute(stmt) != 0) { print_stmt_error(stmt, "Could not execute statement"); return; } if (mysql_stmt_store_result(stmt) != 0) { print_stmt_error(stmt, "Could not buffer result set"); return; } // Init data (*numAddresses) = 0; // Fetch if(mysql_stmt_fetch (stmt) == 0){ (*numAddresses) = myNumAddresses; } // Deallocate result set mysql_stmt_free_result(stmt); /* deallocate result set */ // Close the statement mysql_stmt_close(stmt); // Close Database closeDB(conn); 功能。

但是,您很可能正在使用准备好的声明来解决这些问题。您仍然需要确保输入数据编码与客户端连接的编码匹配,但其他所有内容都应该更容易处理。

我使用C API粘贴参数化查询的示例,其中包含预编译的语句(例如来自Efficiently escaping quotes in C before passing to mysql_query)。请注意,该示例适用于整数,而不是字符串,您需要适应您的用例。

eb labs cleanup-versions --num-to-leave=some_value

同样,如果你可以使用其他一些客户端库(比如C ++客户端),你的代码会更短,更易读。

答案 1 :(得分:0)

我的不好,因为@jjmontes提到似乎发送的字符串是在'latin1'中编码的。

在执行查询之前使用函数mysql_set_character_set(conn, "utf8")解决了这个问题。 现在,我将尝试使用预备语句而不是查询字符串。

再次感谢!