За последние 24 часа нас посетили 17456 программистов и 1707 роботов. Сейчас ищут 1789 программистов ...

(PHP/MSSQL) Как получить значение из хр проц по RETURN

Тема в разделе "MSSQL", создана пользователем uri, 12 май 2010.

  1. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Имеем след процедуру:

    Код (Text):
    1. CREATE PROCEDURE dbo.pr_TestSP
    2. AS
    3. /*
    4.     тестовая ХП - 1 рез набор данных и результат
    5. */
    6.  
    7. select 10
    8.  
    9.  
    10. RETURN 20
    Задача: Получить средствами PHP значение, возвращаемое по RETURN (в нашем случае 20)
     
  2. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    И в чем сложность?
     
  3. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    To Simpliest:

    Не понял Вас.

    Есть некий скрипт, который должен вызвать приведенную выше процедуру.

    Необходимо:
    а) получить результирующий набор (в нашем случае - это число 10)
    б) получить код возврата (в нашем случае - это число 20)

    Можно так:

    Код (Text):
    1. DECLARE @return_code INT
    2. EXEC @return_code = some_stored_procedure @param=123
    3. SELECT @return_code
    В принципе, в большинстве случаев должно устроить.
    Но могут возникнуть траблы при использование динамического SQL во вложенных хранимых процедурах.
    Например, если вышеуказанный кусок кода находится в хранимой процедуре, а сама some_stored_procedure использует динамический SQL.

    Для работы с MS SQL в проекте использую ф-ии mssql_xxxx.
    Вот у меня и возник вопрос, как у новичка PHP, имеются ли средства, позволяющие получить код возврата из хранимой процедуры.
     
  4. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    mssql_next_result() смотрели?
     
  5. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Смотрел. Но позвольте, причем здесь множественные результирующие наборы, для работы с которыми и предназначен mssql_next_result()?

    Еще раз повторюсь: мне надо (точнее хотелось бы) получить кроме данных еще и код возврата по RETURN без финта ушами, типа оболочки для вызова хранимой процедуры из хранимой процедуры.
     
  6. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    А как по вашему клиент должен получить ДВА результата от одной процедуры?
     
  7. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Да фиг его знает! Если б знал, не спрашивал бы.
    Вообще говоря, у MS SQL ЛЮБАЯ процедура даже без явного указания RETURN возвращает некое значение, при успешном выполнении - по умолчанию (если разработчик явно не указал RETURN) это 0, при ошибке - это не 0. В чем легко убедиться. Вот и возникла идея заюзать пользовательские ошибки, например, пришедшие некорректные параметры или ограничение в правах роли пользователя, возвратом некоего числового значения для последующего логгирования\либо чего-нибуть еще. А так как процедура может вернуть более 1 результирующего набора данных, то не хотелось бы привязываться к возврату кода ошибки через SELECT как еще один набор данных.

    Вот как-то так.
     
  8. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Если тут работает аналогично с php_mysqli, то результат будет всегда последним в независимости от числа SELECT внутри.

    Так что проблемы никакой не вижу.
     
  9. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Не знаю, как работает php_mysqli.

    На возможную проблему с динамическим SQL я указал выше.

    Еще одна проблема может возникнуть при использовании временных таблиц.
    Например, при вызове вложенных хранимых процедур можно в какой-то момент получить такое сообщение:

    Код (Text):
    1. Server: Msg 8164, Level 16, State 1, Procedure pr_TestSP2Res, Line 20
    2. An INSERT EXEC statement cannot be nested.
    Поэтому не хотелось плодить процедуры, вызывающие другие процедуры.
     
  10. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    uri
    Вам так сложно проверить что возвращает
    Для подобного запроса?
    Код (Text):
    1. EXECUTE dbo.pr_TestSP
    ?
     
  11. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Нет, мне не сложно это проверить.
    Возвращает Array ( [0] => 10 ).
    Код (Text):
    1.  
    2. <?php
    3. $link = mssql_connect("имя_моего_серера", "мой_логин", "мой_пароль");
    4. mssql_select_db("имя_моей_бд", $link);
    5.  
    6. $sql = 'exec dbo.pr_TestSP';
    7.  
    8. $rs = mssql_query($sql, $link);
    9. do {
    10.     while ($row = mssql_fetch_row($rs)) {
    11.                 print_r($row);
    12.     }
    13. } while (mssql_next_result($rs));
    14.  
    15.  
    16. mssql_free_result($rs);
    17. mssql_close($link);
    18. ?>
     
  12. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
  13. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Не вкурил про mssql_bind() :(

    Не пойму, где трабла:

    Код (Text):
    1. ...
    2. $conn=mssql_connect($cServer, $cLogin, $cPwd);
    3.  
    4. if ($conn) {
    5.     mssql_select_db($cDBName, $conn);
    6.  
    7.     $stmt=mssql_init($cProcName, $conn);
    8.  
    9.     mssql_bind($stmt, "RETVAL", &$val, SQLINT2);
    10.  
    11.    $result=mssql_execute($stmt);
    12.  
    13.     $arr=mssql_fetch_row($result);
    14.     print_r($arr);
    15.      echo("<br />"."RETVAL = $val"."<br />");
    16.  
    17.      mssql_close($conn);
    18. }
    19. else print("Нет коннекта к $cServer");
    20.  
    21. ...
    Возвращает в RETVAL 0 вместо 20.
     
  14. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    опять же - проверяй что выдает mssql_next_result() перед тем как вывести

     
  15. uri

    uri Активный пользователь

    С нами с:
    3 сен 2009
    Сообщения:
    43
    Симпатии:
    1
    Гран мерси Simpliest.

    Подитожу, может кому будет интересны мои изыскания.

    Имеем как минимум 2 варианта получения результата, возвращаемого по RETURN из процедуры.

    Приведу только наиболее важные фрагменты кода

    1) самый простой способ - формировать как еще один результирующий набор:

    Код (Text):
    1. ...
    2. // код процедуры pr_TestSP приведен в топике выше
    3. $sql = 'declare @nRes int exec @nRes = dbo.pr_TestSP  select @nRes as Res';
    4. // вместо  - $sql = 'exec dbo.pr_TestSP'; !!
    5.  
    6. $rs = mssql_query($sql, $link);
    7. // выводим записи активного набора данных
    8. do {
    9.     while ($row = mssql_fetch_row($rs)) {
    10.                 print_r($row);
    11.     }
    12. } while (mssql_next_result($rs));
    13.  
    14. ...
    Здесь используется чиcтый TSQL-код

    2) Используем mssql_execute()

    Код (Text):
    1. ...
    2.  
    3. // $conn - установленный коннект с нужной нам БД,
    4. // $cProcName - имя процедуры, у нас это - dbo.pr_TestSP
    5.     $stmt=mssql_init($cProcName, $conn);
    6.  
    7.     mssql_bind($stmt, "RETVAL", &$val, SQLINT2);
    8.  
    9.  
    10.     $result=mssql_execute($stmt);
    11.  
    12.     $arr=mssql_fetch_row($result);
    13.  
    14.     print_r($arr);
    15.  
    16.     while (mssql_next_result($result))
    17.     {
    18.       $arr1 =  mssql_fetch_row($result);
    19.  
    20.       print_r($arr1);
    21.      }
    22.       echo("<br />"."RETVAL = $val"."<br />");
    23.  
    24. ...
    Здесь с помощью mssql_bind() мы в $val будем ожидать результата

    P.S.: имеется 1 замечание по mssql_execute. Если вышеприведенный код преобразовать к виду
    Код (Text):
    1. ...
    2.  
    3.     $result=mssql_execute($stmt, TRUE);
    4. //// остальное закомментарил
    5.      echo("<br />"."RETVAL = $val"."<br />");
    6. ...
    сразу же получим интересующее нас значение.

    P.P.S.: К слову сказать, работа с OUTPUT-параметрами происходит аналогично.
    С помощью mssql_bind() связываем локальные перменные с OUTPUT-параметрами процедуры, указав им тип

    Немного преобразованный код из хелпа по ф-ии mssq_execute():

    Код (Text):
    1. ...
    2.  
    3. // ------- КОД тестовой процедуры -------------------
    4. // SET QUOTED_IDENTIFIER ON
    5. // GO
    6. // SET ANSI_NULLS ON
    7. // GO
    8. //
    9. // ALTER  PROCEDURE dbo.pr_TestSProc
    10. // (
    11. //    @sval varchar(50) OUTPUT,                  -- 1 выходной параметр
    12. //    @intval int OUTPUT,                                -- 2 выходной параметр
    13. //    @floatval decimal(6,4) OUTPUT            -- 3 выходной параметр
    14. // ) AS
    15. // /*
    16. //        тестовая процедура - 2 набора данных, 3 выходных параметра и значение по RETURN
    17. // */
    18. // if @intval is null
    19. //     select '@intval is null' as answer
    20. // else
    21. //     select '@intval is NOT null' as answer
    22. //
    23. //
    24. // select '1' = 1, '2' = 2, '3' = 3
    25. //
    26. // select 'aaaa'
    27. //
    28. // set @sval='Hello ' + @sval
    29. // set @intval=@intval+1
    30. // set @floatval=@floatval+1
    31. //
    32. // return 10
    33. //
    34. // GO
    35. // SET QUOTED_IDENTIFIER OFF
    36. // GO
    37. // SET ANSI_NULLS ON
    38. // GO
    39.  
    40. // --------------------------
    41.  
    42. $cProcName = 'dbo.pr_TestSProc';
    43.  
    44. $conn=mssql_connect($cServer, $cLogin, $cPwd);
    45.  
    46. if ($conn) {
    47.     mssql_select_db($cDBName,$conn);
    48.  
    49.     $stmt=mssql_init($cProcName,$conn);
    50.     mssql_bind($stmt,"RETVAL",&$val,SQLINT4);
    51.  
    52.     $ival=11;
    53.     $fval=2.1416;
    54.     $sval="Frank";
    55.  
    56.     mssql_bind($stmt,"@sval",&$sval,SQLVARCHAR,TRUE);
    57.     mssql_bind($stmt,"@intval",&$ival,SQLINT4,TRUE);
    58.     mssql_bind($stmt,"@floatval",&$fval,SQLFLT8,TRUE);
    59.  
    60.  
    61.     echo('<br />'.'Начальные значения: '.'<br />'.'$ival='.$ival.'; $fval='.$fval.'; $sval='.$sval.'; <br />');
    62.  
    63. // вернем только OUTPUT-параметры и значение по RETURN, за это отвечает второй параметр, имеющий значение TRUE
    64.     $result=mssql_execute($stmt, TRUE);
    65.  
    66. // в нашем случае - бесполезен, ибо наборы данных не возвращаются!
    67. //    $arr=mssql_fetch_row($result);
    68.  
    69.     print ("После вызова процедуры: " . $arr[0] . "<br>" );
    70.     print ("RETVAL = $val ; intval = $ival ; floatval = $fval ; string = $sval");
    71.  
    72.     mssql_close($conn);
    73. }
    74. else print("ooops!");
    75. ...
    P.P.P.S.: Хотелось бы узнать у знатоков (в плане самообразования) как то же самое проделать через ODBC\ADO
     
  16. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    то же самое - что?

    И PHP участвует в этом празднике жизни?
    Если да, то
    http://php.net/odbc

    Если нет, то скорее всего не подскажут. (те кто знают - заняты, а остальные тупо не знают и не способны разобраться).