首页 > 解决方案 > 对于 ALTER INDEX all ON tbl REORGANIZE 查询,sqlsrv_query 返回什么?为什么 sqlsrv_num_rows 返回 FALSE?

问题描述

我创建了一个拉取请求来Database\ResultInterface::getNumRows()向 CodeIgniter 4 添加一个函数。我所做的一些更改破坏了单元测试。具体来说,SQLSRV 表优化测试很麻烦,因为这个框架试图从 SQLSRV 响应中获取一个结果数组来响应这个表优化查询:

ALTER INDEX all ON db_job REORGANIZE

跟踪导致此问题的所有被调用代码也有点棘手,但这里有一个例外:

1) CodeIgniter\Database\Live\DbUtilsTest::testUtilsOptimizeDatabase
CodeIgniter\Database\Exceptions\DatabaseException: Error retrieving row count

/home/runner/work/CodeIgniter4/CodeIgniter4/system/Database/SQLSRV/Result.php:198
/home/runner/work/CodeIgniter4/CodeIgniter4/system/Database/BaseResult.php:193
/home/runner/work/CodeIgniter4/CodeIgniter4/system/Database/BaseUtils.php:177
/home/runner/work/CodeIgniter4/CodeIgniter4/tests/system/Database/Live/DbUtilsTest.php:105

剖析它,我们看到DBUtilsTest 第 105 行使用表名“db_job”调用BaseUtils::optimizeTable函数,并使用SQLSRV\Utils::optimizeTablevar 构造我在上面提供的查询。然后将此 sql 提供给一个 db 对象,该对象CodeIgniter\Database\SQLSRV\Connection::query()通过继承和各种函数调用来调用该 SQL,通过BaseConnection::query()该 SQL 将 sql 提供给该 sql,BaseConnection::simpleQuery该 sqlSQLSRV\Connection::execute最终将 sql 提供给该 sql,sqlsrv_query并通过该函数返回该函数的结果。调用栈。所以我想这让我想到了我的第一个问题:

问题 1:$stmt如果这个 ALTER 命令 a) 成功或 b) 失败,值是多少?

$stmt = sqlsrv_query($connID, 'ALTER INDEX all ON db_job REORGANIZE');

根据sqlsrv_query 文档,这个函数:

成功时返回语句资源,如果发生错误则返回 false。

无论该值返回到调用堆栈的第 625 行BaseConnection::query,如果成功,它将作为第二个参数存储$this->resultID并作为第二个参数提供给第 676 行的构造函数,该构造函数有效地返回new SQLSRV\Result($this->connID, $this->resultID)。需要明确的是,connID 指的是 SQLSRV 数据库连接,而 resultID 指的$stmt是上面的 sqlsrv_query 调用返回的任何值。

结果$query变量是此函数中 system\Database\SQLSRV\Result 的一个实例:

    public function optimizeTable(string $tableName)
    {
        if ($this->optimizeTable === false)
        {
            if ($this->db->DBDebug)
            {
                throw new DatabaseException('Unsupported feature of the database platform you are using.');
            }
            return false;
        }

        $query = $this->db->query(sprintf($this->optimizeTable, $this->db->escapeIdentifiers($tableName)));
        if ($query !== false)
        {
            $query = $query->getResultArray();
            return current($query);
        }

        return false;
    }

SQLSRV\Result 的实例不会为 false,因此代码将尝试SQLSRV\Result::getResultArray通过继承调用调用 which BaseResult::getResultArray。尝试从优化表的查询或任何类型的 ALTER 查询中获取结果数组似乎是错误的,但是 MySQL 服务器将返回一系列记录以响应 OPTIMIZE 查询。此外,我们刚刚运行的 sqlsrv_query 函数只是返回一些 sqlserver 语句或资源作为其结果。

我想这让我想到了第二个问题: 问题 2:如何从$stmtsqlsrv_query 的结果中判断上面的 ALTER 语句是否成功?

奇怪的是,这些特性以前都没有引起任何问题。问题似乎已经出现,因为我已经弃用了一个从未在旧 getResultArray 代码中设置过的未使用的 BaseResult::numRows 属性,并用新的 getNumRows 方法替换了它以及对它的所有引用。在我的新BaseResult::getResultArray 函数中,我们现在检查 getNumRows 而不是 numRows。这适用于 MySQLi、SQLite3 和 PostGreSQL,但在 SQLSRV 中会出现问题,因为上述ALTER 语句的$stmt结果被输入并返回,根据文档,这表示错误。这是函数的代码:sqlsrv_querysqlsrv_num_rowsfalseSQLSRV\Result::getNumRows

    public function getNumRows() : int
    {
        // $this->resultID contains the sqlsrv_query result of our ALTER statement
        // and $retval comes up false
        $retval = sqlsrv_num_rows($this->resultID); 
        if ($retval === false)
        {
            throw new DatabaseException('Error retrieving row count');
        }
        return intval($retval);
    }

这让我想到: 问题 3:尝试从 ALTER INDEX 查询的结果中获取结果或调用 sqlsrv_num_rows 是否有意义?

标签: phpsql-servercodeignitersqlsrvcodeigniter-4

解决方案


推荐阅读