query = "select * results where id = '";
query.append(ID);
query.append("'");
res = PQexec(conn, query.c_str());
执行此语句后,我收到以下错误。
row number 0 is out of range 0..-1
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
但是,当我在postgresql中运行相同的查询时,它没有任何问题。
select * from results where id = 'hello'
唯一的问题是,如果传递的查询参数不在数据库中,则会引发运行时错误。如果提供数据库中的确切查询参数,则会正常执行。
答案 0 :(得分:2)
这是两个单独的错误,而不是一个错误。这个错误:
row number 0 is out of range 0..-1
来自libpq
,但是会在此处未显示的代码进行报告。
错误:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
不是来自PostgreSQL,而是来自你的C ++运行时。
我无法确切地说出它的来源。你应该在调试器下运行该程序来告诉它。但是如果我不得不猜测,根据显示的代码,我会说ID
为空,所以:
query.append(ID);
因此正在中止该计划。
另外,您的代码显示了非常不安全的做法,您可以通过字符串连接来编写SQL。这使SQL injection exploits变得容易。
想象一下,如果您的“ID”变量被恶意用户设置为';DROP TABLE results;--
会发生什么。
不要通过附加字符串将用户提供的值插入SQL。
而是通过PQexecParams
使用绑定参数。它看起来很复杂,但大多数参数对于简单用途都是可选的。假设ID
是非空std::string
,您的查询版本将如下所示:
PGresult res;
const char * values[1];
values[0] = ID.c_str();
res = PQexecParams("SELECT * FROM results WHERE id = $1",
1, NULL, values, NULL, NULL, 0);
如果需要处理空值,则需要另一个参数;见the documentation。
答案 1 :(得分:0)
也许,有点太晚了,但只想放入我的5美分。
这些天也出现了这个错误,其中包含一个非常简单的存储过程:
CREATE OR REPLACE FUNCTION selectMsgCounter()
RETURNS text AS
$BODY$
DECLARE
msgCnt text;
BEGIN
msgCnt:= (SELECT max(messageID)::text from messages);
RETURN 'messageCounter: ' || msgCnt;
END
$BODY$
LANGUAGE plpgsql STABLE;
进行了一些调试:
if (PQntuples(res)>=1)
{
char* char_result=(char*) realloc(NULL,PQgetlength(res, 0,0)*sizeof(char));
strcpy( char_result,PQgetvalue(res, 0, 0));
bool ok=true;
messageCounter=QString(char_result).remove("messageCounter: ").toULongLong(&ok);
if (!ok) messageCounter=-1;
qDebug()<<"messageCounter: " << messageCounter;
free(char_result);
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
else
{
fprintf(stderr, "storedProcGetMsgCounter Connection Error: %s",
PQerrorMessage(myConn));
PQclear(res);
PQfinish(myConn); // or do call destructor later?
myConn=NULL;
}
原来,存储过程的所有者不是我用来登录的凭据。 所以 - 至少 - 在我的情况下,这个错误“行号0超出范围0 ..- 1”乍一看是误报。