【问题标题】:PHP cannot retrieve [result code] and [output parameter] assigned in the BEGIN CATCH... END CATCH block of SQL server 2016 stored procedurePHP 无法检索 SQL Server 2016 存储过程的 BEGIN CATCH...END CATCH 块中分配的 [结果代码] 和 [输出参数]
【发布时间】:2019-01-01 09:24:22
【问题描述】:

我有一个简单的表和一个存储过程,如下所示:

CREATE TABLE dbo.Test
(
    TestTime DATETIME
)

INSERT INTO dbo.Test (TestTime)
VALUES('2018-12-21T13:25:45')

CREATE PROCEDURE dbo.TestProc
@pErrorMsg NVARCHAR(512) OUTPUT
AS
BEGIN
    DECLARE @result INTEGER
    SET @result = 0
    SET @pErrorMsg = N'OK';
    BEGIN TRY
        UPDATE dbo.Test
        SET TestTime = '2018-12-21T13:25:45a' -- wrong time value to raise error!
        WHERE TestTime = '2018-12-21T13:25:45'
    END TRY
    BEGIN CATCH
        SET @pErrorMsg = ERROR_MESSAGE()
        SET @result = 1
    END CATCH

    RETURN @result
END

--Test the proc, and it seems to work fine:
BEGIN
  DECLARE @res INTEGER
  SET @res = 0
  DECLARE @errMsg NVARCHAR(128)

  EXEC @res = dbo.TestProc @errMsg OUTPUT
  SELECT @res AS Result, @errMsg AS ErrorMsg
END

存储过程可以返回错误代码以及我在 CATCH 块中分配的 ERROR_MESSAGE()。

结果 |错误消息

1 |从字符串转换日期和/或时间时转换失败。

我的php代码:

$sql = "{? = call dbo.TestProc(?)}";

$res = 123;
$errorMsg = utf8_encode("abcd1234");

$paramRes = array(&$res, SQLSRV_PARAM_OUT, SQLSRV_PHPTYPE_INT);
$paramErrorMsg = array(&$errorMsg, SQLSRV_PARAM_OUT);
$params = array($paramRes, $paramErrorMsg);

$affectedRows = 0;

$conn = sqlsrv_connect(<your_server>, <your_credential>);
$stmt = sqlsrv_query($conn, $sql, $params);
$affectedRows = sqlsrv_rows_affected($stmt);  // this works well

$nxtRes = sqlsrv_next_result($stmt);  //  This asks the sql driver to update the result code and output parameter variables

echo "</br>result code=" . strval($res) . ", error msg=" . $errorMsg . "</br>"

问题是,如果我修改存储过程以便它可以成功更新数据,我的 php 代码可以捕获返回代码 (0) 和错误消息 (“OK”),但如果我只保留存储过程如上所述,我的 php 代码无法捕获这些东西。

之前有同样问题的人能给我一些提示吗? 谢谢。 我为 SQL 服务器使用 php7 和 MS PHP 驱动程序 5.2。

【问题讨论】:

  • 在 CATCH 块中使用 THROW 将错误推送到调用代码

标签: php sql-server stored-procedures try-catch


【解决方案1】:

我有类似的问题,我建议如下:

  • 始终将SET NOCOUNT ON 放在存储过程的开头。
  • sqlsrv_query() 获取所有结果集。 INSERTUPDATEDELETE 语句还会返回受影响的行数作为结果集(当 SET NOCOUNTOFF 时),而不仅仅是 SELECT 语句。

我通常这样获取结果:

<?php

...
do {
    # Fetch data, if it's a SELECT statement
    #while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
    #}
    $affected = sqlsrv_rows_affected($stmt);
} while (sqlsrv_next_result($stmt));
...
?>

我已经复制了您的测试用例,SET NOCOUNT ON 有效。我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 2017-07-20
    相关资源
    最近更新 更多