pg_send_query_params 返回 TRUE 但失败

Posted

技术标签:

【中文标题】pg_send_query_params 返回 TRUE 但失败【英文标题】:pg_send_query_params Returns TRUE But Fails 【发布时间】:2012-09-04 22:41:51 【问题描述】:

我有一个 php 脚本,它在 Postgres 数据库中插入一行。它在我的测试服务器(Postgres 9.1)上运行良好,但在我的新共享主机(Postgres 8.4)上失败。

$query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3))";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));

$result 始终为 TRUE,但没有插入任何行。

我也试过了:

$result = pg_get_result($dbconn);

但经历了同样的行为。

按照下面@CraigRinger 的交易建议,我也尝试了这两种方法:

$query = "BEGIN;INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));COMMIT;";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));

pg_send_query($dbconn, "BEGIN;");
$query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
pg_send_query($dbconn, "COMMIT;");

仍然有同样的行为。

如果我在 phpPgAdmin 中运行 INSERT 查询,则会插入一行。我还可以在 PHP 脚本中从此查询中获取结果:

"SELECT relid FROM pg_stat_user_tables"

当 INSERT 查询结果为真但没有插入行时,这意味着什么?可能是什么问题,我该如何解决这个问题?

编辑

我可以使用 phpPgAdmin INSERT 行,然后使用 PHP 脚本 SELECT 这些行。

这是一个失败的完整 PHP 脚本(它被剥夺了在我的完整脚本中存在的 POST 收集和验证)。 rest.php 脚本仅包含连接变量和响应函数。这个rest.php 脚本适用于我的SELECT 脚本:

<?php
require "KLogger.php";
require "rest.php";

ini_set("error_reporting", E_ALL ^ E_NOTICE);
ini_set("display_errors", 0);
ini_set("log_errors", 1);

$log   = KLogger::instance(dirname(__FILE__), KLogger::DEBUG);
$log_id = "AM".time();
$log->logInfo($log_id . " *** " . $_SERVER['REMOTE_ADDR']);

$lat = '51.510199';
$lon = '-0.129654';
$rate = '10';
$is_happy = 't';

$dbconn = pg_connect("host=" . $host . " dbname=" . $db . " user=" . $user . " password=" . $pw);
if(!$dbconn)

    $log->logInfo($log_id . " No connection: " . pg_last_error());
    sendResponse(500, "Internal Server Error");

else

    $query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));";
    $result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
    if(!$result)
    
        $log->logInfo($log_id . " No Result: " . pg_last_error());
        sendResponse(500, "Internal Server Error");
    
    else
    
        $log->logInfo($log_id . " sendResponse(200)");
        sendResponse(200, "OK");
    

pg_close($dbconn);
?>

【问题讨论】:

你如何确定“没有插入行”? @CraigRinger:我正在使用 phpPgAdmin 浏览表格。 那么是什么让你确定 phpPgAdmin 没有错呢?从psql 尝试SELECT?您确定要连接到同一个数据库吗? @CraigRinger:我可以使用 phpPgAdmin 插入和选择一行。所以这个工具似乎还可以。 【参考方案1】:

此类问题的最常见原因是开放的、未提交的事务。

如果您BEGIN(或通过在数据库驱动程序中关闭自动提交来隐式执行此操作)然后做一些工作,只有完成工作的事务才能看到更改,直到它COMMITs。

如果是这种情况,则使用同一连接从同一脚本中立即进行后续查询将看到更改的行,但不会看到其他任何内容。

您也可以通过启用来检查:

log_statement = 'all'
log_line_prefix = 'db=%d pid=%p vtxid=%v txid=%x'

并通过查找具有BEGIN 且没有匹配COMMIT 的虚拟交易ID (vtxid) 来查找不匹配的交易。

如果您不能修改postgresql.conf,因为它是共享主机,您应该可以修改ALTER USER myuser SET log_statement = 'all';ALTER DATABASE mydatabase SET log_statement = 'all';。您不能在postgresql.conf 之外设置log_line_prefix,但您的主机可能已经有一个合理的设置。


另一种可能性 - 并且可能由版本差异解释 - 是您稍后通过使用 9.1 中可用的功能在事务中触发错误,而您没有检测到该错误。您之前的@​​987654332@ 成功,但是当后面的语句失败时,整个事务就会回滚。再次检查服务器日志以查看。


另一个常见原因是您使用脚本连接到的数据库与您在测试是否插入时连接的数据库不同。尝试SELECTing 在插入后您希望从脚本中插入的行。还值得通过您的管理工具创建一个虚拟表(在您的情况下似乎是 phpPgAdmin),然后测试以查看脚本是否可以看到虚拟表。

【讨论】:

我无权访问postgresql.conf。如果我在 phpPgAdmin 中运行您的 ALTER 语句,我会得到“权限被拒绝”。我尝试将 INSERT 语句包装在事务中,但没有更改(有关详细信息,请参阅我修改后的问题)。如果我在 phpPgAdmin 中运行 SQL INSERT 语句,它就可以工作。 INSERT 是我的 PHP 脚本中唯一的 SQL。请问您还有什么建议吗? @Polly 正如我所说,在INSERT 之后尝试SELECTing 以查看该脚本的运行是否在插入新数据后立即看到新数据。至于permission denied,我猜您并没有以数据库所有者(对于数据库级别的一级)或超级用户或createuser 用户(对于一级用户)的身份运行它们 @Polly 另外:你能用你的脚本和你的测试连接到不同的数据库吗?查看更新的答案。 phpPgAdmin 和我的脚本都使用相同的主机和数据库名。如果我在INSERT 之后立即SELECT,则不会返回任何行。如果我使用不正确的密码,我将无法连接。但是,如果我使用无效的表名,我不会出错!我试图插入的表是在 phpPgAdmin 中创建的。 另外,如果我用 phpPgAdmin INSERT 一行,我可以在我的脚本中 SELECT 它。

以上是关于pg_send_query_params 返回 TRUE 但失败的主要内容,如果未能解决你的问题,请参考以下文章

返回空 T [重复]

返回 IEnumerable<T> 与 IQueryable<T>

返回 IEnumerable<T> 与 IQueryable<T>

为啥我不能返回一个通用的 'T' 来满足 Partial<T>?

我从只返回 Task 而不是 Task<T> 的方法返回啥?

Java之泛型<T> T与T的用法