使用pqxx库从数据库提取用户名触发C++ xstring报错如何解决
报错根因
你触发xstring报错的直接原因是LoginUser函数内的SQL拼接逻辑存在严重错误:
- 代码里写的
'user'是C++多字节字符字面量,会被编译器处理为int类型,你把SQL字符串常量的指针与这个int值相加,相当于直接访问了字符串后方的非法内存,std::string构造时触发内存越界才会抛出xstring相关错误。 - 你没有用传入的
user参数拼接SQL,反而用了固定的字符字面量,就算不崩也查不到正确数据。 - 现有直接拼接SQL的写法还存在SQL注入风险,且需要手动处理字符串转义、引号包裹等逻辑,非常容易出错。
修正后的实现代码
1. 登录功能修正(含数据读取逻辑)
void DBUser::LoginUser(std::string const& user, std::string const& pw) { pqxx::work worker(*DBLink::GetInstance()); try { // 使用pqxx参数化查询,$1对应第一个传入参数,自动处理类型转义和引号 pqxx::result query_res = worker.exec_params( "SELECT username, password FROM users WHERE username = $1", user ); worker.commit(); // 读取结果逻辑 if (query_res.empty()) { throw std::runtime_error("用户名不存在"); } // 取第一行结果,通过字段名读取值并转为std::string std::string db_username = query_res[0]["username"].as<std::string>(); std::string db_encrypted_pw = query_res[0]["password"].as<std::string>(); // 后续密码校验逻辑:加密传入的pw后和db_encrypted_pw对比即可 } catch (const std::exception& e) { worker.abort(); throw; } }
2. 创建用户功能修正(避免SQL注入)
void DBUser::CreateUser(std::string const& user, std::string const& pw) { pqxx::work worker(*DBLink::GetInstance()); try { std::string encrypted_pw = worker.conn().encrypt_password(user, pw, "md5"); // 参数化插入,不需要手动拼接字符串处理引号 worker.exec0( "INSERT INTO users (username, password) VALUES ($1, $2)", user, encrypted_pw ); worker.commit(); } catch (const std::exception& e) { worker.abort(); throw; } }
pqxx读取查询结果的常用规则
pqxx::result是查询返回的结果集容器:- 调用
empty()可判断是否有返回数据 - 调用
size()可获取返回的行数
- 调用
- 访问具体行:通过下标
result[行号]即可拿到pqxx::row对象,行号从0开始计数 - 读取行内字段支持两种方式:
- 按字段名读取:
row["字段名"].as<目标类型>() - 按字段位置读取:
row[字段下标].as<目标类型>(),下标从0开始计数
- 按字段名读取:
- 如果你确定查询只会返回一行数据,可以直接用
exec1代替exec_params,直接拿到pqxx::row对象,不需要自己从result里取第一行。
内容的提问来源于stack exchange,提问作者Vasile Mihai
相关产品推荐
相关产品推荐

