Вызов хранимой процедуры с несколькими наборами результатов с sqlsrv - нет ошибок при получении - PullRequest
0 голосов
/ 21 апреля 2020

Если я пытаюсь вызвать хранимую процедуру с несколькими наборами результатов в PHP с PHP драйвером для SQL сервера (расширение sqlsrv), я получаю наборы результатов, пока не произойдет ошибка, но не получу ошибку. Вот краткий пример:

Хранимая процедура:

CREATE PROCEDURE dbo.pr_testmultipleresult
AS
    BEGIN
        SET NOCOUNT ON;

        SELECT 1 AS result1;

        SELECT 2 AS result2;

        RAISERROR(
                     'This is an error' -- Message
                    ,16                 -- Severity,  
                    ,1                  -- State
                 );

        SELECT 3 AS result3;
    END;
GO

PHP код:

<?php
        $serverName = "localhost\SQL2012TEST";
        $connectionInfo = array("Database" => "TEST", "UID" => "", "PWD" => "");
        $conn = sqlsrv_connect($serverName, $connectionInfo);
        if ($conn === false) {
            die(print_r(sqlsrv_errors(), true));
        }
        $query = sqlsrv_query($conn, '{call dbo.pr_testmultipleresult}');
        if ($query === false) {
            die(print_r(sqlsrv_errors(), true));
        }
        do {

            while ($row = sqlsrv_fetch_array($query)) {
                // Loop through each result set and add to result array
                $result[] = $row;
            }
         } while (sqlsrv_next_result($query));

         echo "";
         \var_dump($result);
         echo "
";

Результат:

array(2) {
  [0]=>
  array(2) {
    [0]=>
    int(1)
    ["result1"]=>
    int(1)
  }
  [1]=>
  array(2) {
    [0]=>
    int(2)
    ["result2"]=>
    int(2)
  }
}

Если raiserror вызывается перед первым оператором select, я получаю сообщение об ошибке в sqlsrv. Но если перед raiserror есть только один выбор, я не получаю его в sqlsrv.

Нужно ли добавить конфигурацию, чтобы получить ошибки?

1 Ответ

0 голосов
/ 21 апреля 2020

Объяснение:

Когда хранимая процедура возвращает несколько наборов результатов, вам необходимо проверить на наличие ошибок результат вызова sqlsrv_query() и результат каждого вызова sqlsrv_next_result():

<code><?php

...

# T-SQL
$result = array();
$rc = 0;
$params = array(
    array(&$rc, SQLSRV_PARAM_OUT)
);

$query = sqlsrv_query($conn, 'EXEC ? = dbo.pr_testmultipleresult', $params);
if ($query === false) {
    echo "Error executing stored procedure.".print_r(sqlsrv_errors(), true)."<br>";
} else {
    while ($row = sqlsrv_fetch_array($query)) {
        $result[] = $row;
    }

    if (sqlsrv_next_result($query) === false) {
        echo "Error fetching a result set.".print_r(sqlsrv_errors(), true)."<br>";
    } else {
        while ($row = sqlsrv_fetch_array($query)) {
            $result[] = $row;
        }
    }   

    if (sqlsrv_next_result($query) === false) {
        echo "Error fetching a result set.".print_r(sqlsrv_errors(), true)."<br>";
    } else {
        while ($row = sqlsrv_fetch_array($query)) {
            $result[] = $row;
        }
    }   

    echo "<pre>";
    var_dump($result);
    echo "
"; sqlsrv_free_stmt ($ query);} # End sqlsrv_close ($ conn);?>

Результат:

Error fetching a result set.Array ( [0] => Array ( [0] => 42000 [SQLSTATE] => 42000 [1] => 50000 [code] => 50000 [2] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]This is an error [message] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]This is an error ) )
array(2) {
  [0]=>
  array(2) {
    [0]=>
    int(1)
    ["result1"]=>
    int(1)
  }
  [1]=>
  array(2) {
    [0]=>
    int(2)
    ["result2"]=>
    int(2)
  }
}

В качестве примечания, один доступная опция для настройки обработки ошибок и предупреждений - это sqlsrv_configure() функция, но я не думаю, что она полезна в этом конкретном случае c.

Необязательное решение:

Я предлагаю использовать следующий подход, который является возможным решением вашей проблемы (по крайней мере, я могу выполнить процедуру, получить все возможные наборы результатов и получить код состояния результата).

Вам необходимо изменить хранимую процедуру и использовать RETURN, чтобы безоговорочно выйти из процедуры и вернуть соответствующий статус. Также необходимо изменить оператор в сценарии PHP и использовать оператор EXEC ? = dbo.pr_testmultipleresult с выходным параметром для проверки статус, возвращенный из процедуры. Обратите внимание, что sqlsrv_query() возвращает результат выполнения оператора, а не результат выполнения хранимой процедуры.

Хранимая процедура:

ALTER PROCEDURE dbo.pr_testmultipleresult
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @return int
    SET @return = 0

    SELECT 1 AS result1;

    BEGIN TRY  
        SELECT 1 / 0 AS Result2
    END TRY  
    BEGIN CATCH  
        SET @return = -1
    END CATCH 

    SELECT 3 AS result3;

    RETURN @return
END;

PHP:

<?php
$server = 'server\instance';
$database = 'database';
$uid = 'username';
$pwd = 'password';

# Connection
$cinfo = array("Database" => $database, "UID" => $uid, "PWD" => $pwd);
$conn = sqlsrv_connect($server, $cinfo);
if ($conn === false) {
    die(print_r(sqlsrv_errors(), true));
}

# T-SQL
$result = array();
$rc = 0;
$params = array(
    array(&$rc, SQLSRV_PARAM_OUT)
);
$query = sqlsrv_query($conn, 'EXEC ? = dbo.pr_testmultipleresult', $params);
if ($query === false) {
    die(print_r(sqlsrv_errors(), true));
}
do {
    while ($row = sqlsrv_fetch_array($query)) {
        // Loop through each result set and add to result array
        $result[] = $row;
    }
} while (sqlsrv_next_result($query));

# Check result
if ($rc < 0) {
    echo "Result from stored procedure: ERROR";
} else {
    echo "Result from stored procedure: OK";
}   
echo "<br>"."Results:"."<br>";
echo print_r($result, true);

# End
sqlsrv_free_stmt($query);
sqlsrv_close($conn);
?>
...