3

我想我可能在这里遗漏了一些非常明显的东西,但是我已经为此苦苦挣扎了太久,而且我的 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);
4

4 回答 4

1

这里有两个问题,一个是构造一个包含您想要的查询的字符串,另一个是将该字符串作为参数传递给函数。

我的建议是尽可能保持“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);

成员函数返回一个指向以 null 结尾的c_str()数组(即 C 风格的字符串)的指针,但该指针的类型为const wchar_t*; 也就是说,这个 C 风格的字符串的内容不能被修改。

SQLWCHAR*这是一个问题,因为wchar_t*; 它不承诺不处理数据。这就是为什么我包含const_cast, 以constc_str()值中删除 。

这不是您通常想要做的事情。 const_cast可以说是最可怕的演员阵容,因为您直接打开了未定义行为的大门,因为修改 const 对象是 UB:

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) 太强大了,不安全。

于 2013-03-11T00:20:44.803 回答
1

我建议你准备一个参数化的查询字符串。看这里

如果您每次都只是简单地连接字符串来构建一个新查询,那么您的网站可能会受到 SQL 注入攻击

于 2013-03-11T02:19:27.490 回答
0

您可以通过以下方式简单地做到这一点:

你可以这样做

   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 等。

于 2015-08-18T15:44:50.770 回答
0

谢谢野兽。如果您正在记录两个或更多数据,则可以如下使用。

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());

我好几天都解决不了这个问题。现在问题解决了。

于 2021-11-25T22:06:05.330 回答