c++和MySQL -如何在我的查询中包含变量
C++ and MySQL - how to include variable in my query?
我想我可能在这里错过了一些非常明显的东西,但我已经在这方面挣扎了太长时间,我的c++已经生锈了(10年多)
下面的代码可以正常工作,但是我需要能够将一个变量传递到查询lname。如果我在字符串或字符数组中构建查询,我会得到一个错误,它与SQLWCHAR*
参数类型不兼容我知道下面的代码很容易受到sql注入的攻击,但这是一个孤立的系统上的一次性攻击,所以我真的在寻找简单性比什么都重要…
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT sql_hStmt;
SQLRETURN ret;
SQLWCHAR outstr[1024];
SQLSMALLINT outstrlen;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
ret = SQLDriverConnect(dbc, NULL, L"DSN=myDSN", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &sql_hStmt);
SQLWCHAR* SQL = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, SQL, SQL_NTS);
SQLFetch(sql_hStmt);
这里有两个问题,一个是构造包含所需查询的字符串,另一个是将该字符串作为参数传递给函数。
我的建议是尽可能保持"c++",直到你达到这些C的边界。所以我们应该使用std::wstring
来处理字符串,直到它需要一个c风格的字符串:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(statementText.c_str()), SQL_NTS);
c_str()
成员函数返回指向以空结束的数组(即c风格的字符串)的指针,但该指针的类型为const wchar_t*
;也就是说,这个c风格字符串的内容不能被修改。
这是一个问题,因为SQLWCHAR*
只是wchar_t*
;它并没有承诺不去管数据。这就是为什么我包括const_cast
,从c_str()
值中删除const
。
这通常不是您想要做的事情。 const_cast
可以说是最可怕的类型转换,因为您直接打开了未定义行为的大门,因为修改const对象是不可能的:
const int x = 0;
const int* p = &x; // anyone using this pointer can't modify x
int* bad = const_cast<int*>(p); // but this one is not so good
*bad = 5; // undefined behavior
这里没问题的原因是,SQLExecDirect
实际上并没有修改它传递的字符串;它只是一个实现错误,没有使用const,所以把它去掉是可以的。(缺少const的错误在c语言中很常见)
如果你真的需要一个可以修改的缓冲区,那么从当前版本的c++ (c++ 11)开始,你可以安全地做到:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, &statementText[0], SQL_NTS);
取第一个元素的地址,它本身在一个以null结尾的数组中;另一个c风格字符串。这一次,我们有一个可修改的数组;类型已经匹配。
(我之所以注意到这在c++ 11中是可以的,是因为在技术上在以前的版本c++ 03中,这种行为没有得到保证。这实际上是有意为之,但标准中的一个措辞错误使其并非如此。从实际角度讲,无论哪种方式都可以。
你想用哪一个取决于你。有些人会认为只要一直使用&str[0]
,所以我们肯定没有UB,我会认为记录你的意图和信念,即函数不会修改字符串并抛弃const,但最终以const的心态进行操作。如果发生了不好的事情,你很容易就能从const中解脱出来,而不是后悔当初没戴上它。
需要注意的一件重要的事情是,所有这些返回的指针(str.c_str()
或&str[0]
)只有在str
对象本身是活的并且没有被修改的情况下才有效。
const wchar_t* get_query()
{
std::wstring result = /* build query */;
// oops, this pointer stops being meaningful when result stops existing!
return result.c_str();
}
有了这些,构建这些字符串就很容易了。我们有
std::wstringstream
:
std::wstringstream ss;
ss << "this is basically an expanding buffer that accepts anything std::wcout will";
ss << std::endl;
ss << "this includes integers " << 5 << " and other stream-insertable types";
你可能想要这样写:
std::wstring build_query(const std::wstring& name)
{
// you can provide a starting string
std::wstringstream result(L"select * from DB.employees where lname=");
result << "'" << name << "'";
return result.str(); // this captures the buffer as a C++ string
}
// Remember, this would be bad!
//
// SQLWCHAR* SQL = const_cast<SQLWCHAR*>(build_query(L"Smith").c_str());
//
// Because the C++ string returned by build_query is temporary;
// it stops existing at the end of this full expression,
// so SQL would be a bad pointer. This is right:
std::wstring SQL = build_query(L"Smith");
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS);
希望对你有帮助。
此外,除了宏之外,我会避免使用全大写的标识符,因为阅读c++代码的人绝对希望这些名称是宏。此外,我在示例代码中使用了c++风格的强制转换;你也应该这样做。c风格的强制转换((type)value
)太过强大而不安全。
我建议你准备一个参数化的查询字符串。看到
如果您每次都简单地连接字符串来构建一个新的查询,您可能会使您的站点容易受到SQL注入攻击
您可以这样做:
你可以通过
int var = 10;
string str = to_string(var);
string requete="INSERT INTO stat(temps) VALUES ("";
requete += str;
requete += "")";
mysql_query(&mysql,requete.c_str());
只需在mySql中指定字段的类型为int, double, float等。
感谢野兽。如果要记录两个或多个数据,可以按如下方式使用。
int state;
string mesafe = to_string(getdata1);
string aci = to_string(getdata2);
string query = "INSERT INTO tarama (mesafe,aci) VALUES ("";
query += mesafe;
query += "","";
query += aci;
query += "")";
qstate = mysql_query(conn, query.c_str());
我好几天都没能解决这个问题。现在问题解决了
- Mongodb c++驱动程序:如何查询元素的数组
- 我的神经网络不起作用 [XOR 问题]
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- cmake在我的项目中所需的所有静态库都不成功
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 0-1背包代码中的错误.我的代码中有什么错误
- 当我的阵列太大时出现分段错误
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 如何查询以确定我的 MacOS/X 应用程序是否处于应用程序午睡模式?
- 似乎无法逃脱我发送到我的 sqlite3 db 的查询,不知道为什么
- C sqlite3插入或替换查询我认为是错误的
- C++ SQLite 查询只工作一次。我的代码有什么问题?
- 来自新手用户的共享指针查询.我下面的代码在使用带有成员共享指针的类容器时崩溃
- 为什么 SQLite 不允许我查询特定的 ATTACHED 数据库?
- c++和MySQL -如何在我的查询中包含变量