0
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'

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

4

2 回答 2

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 注入漏洞利用变得容易。

想象一下,如果您的“ID”变量被';DROP TABLE results;--恶意用户设置为会发生什么。

不要通过附加字符串将用户提供的值插入 SQL。

相反,使用绑定参数通过PQexecParams. 它看起来很复杂,但大多数参数对于简单的使用都是可选的。您的查询的版本,假设它ID是一个非 null 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);

如果您需要处理空值,则需要另一个参数;请参阅文档

于 2015-04-10T01:18:49.717 回答
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”乍一看是误报。

于 2015-09-20T11:22:57.447 回答