行号0超出范围0 ..- 1 LIBPQ

时间:2015-04-09 13:52:14

标签: c++ postgresql std libpq libpqxx

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'

唯一的问题是,如果传递的查询参数不在数据库中,则会引发运行时错误。如果提供数据库中的确切查询参数,则会正常执行。

2 个答案:

答案 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”乍一看是误报。