Сохраненная процедура не возвращает данные

Я нахожусь в процессе передачи сценария с (прекращенного) сервера Windows на наш Linux. Одним из сценариев, которые мне нужно передать, является соединение с MSSQL -server.

Установлено соединение с сервером, и я могу получать "обычные" данные из любой из таблиц, но когда я выполняю хранимую процедуру, я не получаю ни одной из требуемых данных. Процедура просто возвращает false при выполнении.

Тестирование подготовленного оператора для ошибок с помощью $stmt->errorInfo() не показывает мне никакой соответствующей информации, оно просто возвращает код ошибки 00000, который должен указывать все (должен) работать нормально.

Array
(
    [0] => 00000
    [1] => 0
    [2] => (null) [0] (severity 0) [(null)]
    [3] => 0
    [4] => 0
)

PHP

$con = new \PDO('dblib:charset=UTF-8;host=freedts;dbname=database', 'user', 'password');
/** ------------------------------------------------------**/
$sql = 'SELECT * FROM prgroepen';
$stmt = $con->prepare($sql);
if ($stmt) {
    try {
        $stmt->execute();
        $data = $stmt->fetch(\PDO::FETCH_ASSOC);
        if ($data) echo '<pre>'.print_r($data, true).'</pre>';
        else var_dump($data);

    }catch(\Exception $e) {
        echo $e->getMessage();
    }
}

/** ------------------------------------------------------**/
$SP = <<<SQL
    DECLARE @return_value int,
            @soort nvarchar(1),
            @dagen money

    EXEC    @return_value = [dbo].[web_voorraadstatus] @produkt = N'ABEC24_9002', @aantal = 1, @soort = @soort OUTPUT, @dagen = @dagen OUTPUT
    SELECT  @soort as N'@soort', @dagen as N'@dagen'
SQL;

$stmt = $con->prepare($SP);
if ($stmt) {
    try {
        $stmt->execute();
        $data = $stmt->fetch(\PDO::FETCH_ASSOC);
        if ($data) echo '<pre>'.print_r($data, true).'</pre>';
        else var_dump($data);

    }catch(\Exception $e) {
        echo $e->getMessage();
    }
}

выход

Array
(
    [kode] => A
    [omschrijving] => ACCESSOIRE DISPLAYS
    [aeenheid] => ST
    [agb] => 604006
    [veenheid] => ST
    [vgb] => 700011
    [coefaank] => 
    [coefverk] => 
    [internet] => 1
    [foto] => #\\serverpc\fws$\GROEPEN\A.jpg#
    [vader] => 
    [produkt_niveau] => 0
    [bs_kode] => 
    [bs_vader] => 
    [web_volgorde] => 6
    [pdfcataloog] => 
)

bool(false) 

Я также пытался назвать SP по-разному, но безрезультатно. Тот же самый код отлично работает на сервере Windows, с той лишь разницей, что сервер Windows использует sqlsrv -driver

/** ============================== **/
/*  @produkt as nvarchar(15),
/*  @aantal as money,
/*  @soort as nvarchar(1) output,
/*  @dagen as money output
/** ============================== **/
$stmt = $con->prepare('execute web_voorraadstatus ?, ?, ?, ?');

$stmt->bindParam(1, $produkt, PDO::PARAM_STR);
$stmt->bindParam(2, $aantal, PDO::PARAM_STR);
$stmt->bindParam(3, $soort, PDO::PARAM_STR, 1);
$stmt->bindParam(4, $dagen, PDO::PARAM_STR, 10);

var_dump($stmt->execute()); # true
var_dump($soort, $dagen);   # NULL, NULL

Итак, dblib действительно может выполнять хранимые процедуры и извлекать возвращаемые им данные?

note: клиентская кодировка уже установлена в UTF-8 в FreeDTS конфигурации FreeDTS


Вот часть из журнала freeDTS, кажется, я получаю данные от MSSQL -server просто отлично?

dblib.c:4639:dbsqlok(0x7fcfd8acc530)
dblib.c:4669:dbsqlok() not done, calling tds_process_tokens()
token.c:540:tds_process_tokens(0x7fcfd78d7bd0, 0x7ffe281bec38, 0x7ffe281bec3c, 0x6914)
util.c:156:Changed query state from PENDING to READING
net.c:555:Received header
0000 04 01 00 5c 00 37 01 00-                        |...\.7..|

net.c:609:Received packet
0000 04 01 00 5c 00 37 01 00-79 00 00 00 00 fe 01 00 |...\.7.. y.......|
0010 e0 00 00 00 00 00 81 02-00 00 00 21 00 e7 02 00 |........ ...!....|
0020 09 04 d0 00 34 06 40 00-73 00 6f 00 6f 00 72 00 |[email protected] s.o.o.r.|
0030 74 00 00 00 21 00 6e 08-06 40 00 64 00 61 00 67 |t...!.n. [email protected]|
0040 00 65 00 6e 00 d1 02 00-56 00 08 00 00 00 00 90 |.e.n.... V.......|
0050 d0 03 00 fd 10 00 c1 00-01 00 00 00             |........ ....|

Ответ 1

Я мог ошибаться, но я думаю, что это стандартное поведение DBLIB и FreeTDS, поскольку у них есть одно утверждение для правила подключения.

Для обхода открытого объекта соединения для каждого оператора - убедитесь, что вы закроете курсор после каждой выборки.

$stmt->closeCursor();

sqlsrv на Windows не имеет такого поведения, следовательно, разные результаты на разных платформах.

Ответ 2

Если вас устраивает версия PHP и FreeTDS, в зависимости от ваших требований к производительности может возникнуть какая-то проблема.

В широких мазках;

  1. Создание представления на основе хранимой процедуры
  2. запросить представление
  3. отбросить представление

В этом потоке MSDN обсуждается несколько разных подходов: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/75a686f0-2192-4c6c-bdb8-04c074b916fc/create-view-from-stored-procedure? форум = transactsql

В частности:

declare @sql_String nvarchar(4000)
set @sql_String = N'
create view dbo.Whatever as
select ''Hello World'' as Hello_World'

exec sp_executeSql @sql_String

Ответ 3

  • Попробуйте запустить SQL Profiler на SQL Server и посмотреть, что работает, и если оно генерирует какие-либо предупреждения/ошибки.

  • Не могли бы вы попытаться выполнить свой SP, как показано ниже?

    SELECT CAST (soort AS NVARCHAR (1)) как N '@soort', CAST (dagen AS MONEY) как N '@dagen'

    FROM OPENQUERY ([имя_сервера],

    'DECLARE @return_value int, @soort nvarchar (1), @dagen money

    EXEC @return_value = db_name. [Dbo]. [Web_voorraadstatus] @produkt = N''ABEC24_9002 '', @aantal = 1, @soort = @soort OUTPUT, @dagen = @dagen OUTPUT

    SELECT @soort как N''soort '', @dagen как N''dagen ''

    ")

server_name - это то, что показано в

select name
from sys.servers
where server_id = 0