@thekip
Php/C#/Js Developer

PHP DBLIB + Multiple Result Sets (SQL Server)?

Есть задача в которой необходимо подключиться к SQL Server 2005 из под php c фреймворком Yii и выполнить процедуру которая возвращает несколько наборов результатов сразу (2 селекта в процедуре).



Первая часть задачи была успешно решена, для подключения была использована связка FreeTDS + dblib.

Данные удалось получать и записывать, хоть и с определенными трудностями (кодировка).



Со второй задачей возникли проблемы. Что бы получить несколько наборов данных в php не достаточно просто выполнить запрос и пройтись по нему циклом. В таком случае оно вернет только первый набор данных.



Необходимо после прочтения каждого набора перейти к следующему с помощью:



$command->query()->nextResult(); //yii method<br>

Но проблема в том что dblib не имеет такого функционала, и при выполнении этой функции выкидывается Exception:



Driver does not support this function: driver does not support multiple rowsets


вот что на этот счет говорит автор:



Support for multiple result sets will be added as soon as I (or someone

else) get the time to do so.


Датируется это сообщение 2007 годом. Поддержка этой функциональности не появилась до сих пор.



Я начал копать в сторону других драйверов для MSSQL, есть решение с ODBC, но к сожалению оно тоже не подходит, т.к. Yii не имеет его поддержки в AR:

CDbConnection does not support reading schema for odbc database.


Вообщем у меня есть еще один вариант, это смотреть в сторону Windows машины, с драйвером Sqlsrv от майкрософта, но это довольно кардинальные меры.



Саму процедуру я не могу менять. Это ядро чужой системы, к которой у меня есть только рид онли доступ.



Кто ни будь сталкивался подобной проблемой и может знает как её решать? Может быть есть возможность как ни будь откинуть наборы и получить только один, или сразу поместить их в перменные и т.п.
  • Вопрос задан
  • 5369 просмотров
Пригласить эксперта
Ответы на вопрос 5
@thekip Автор вопроса
Php/C#/Js Developer
Вообщем проблему не решил, но продвинулся чуть дальше.

Возможно эта информация будет кому то полезна:

Что бы научить Yii работать через ODBC с mssql достаточно в конфигурации подключения к базе указать следующее:

#protected/config/main.php
'db'=>array(
                        'class'=>'CDbConnection', 
			'connectionString' => 'odbc:your dsn', 
                        'charset'=>'utf8',
                        'username'=>'username',
                        'password'=>pass',
                        'driverMap' => array(
                            'odbc' => 'CMssqlSchema'
                        )
		),

Таким образом мы скажем Yii, что за ODBC скрывается база, к которой нужно подключаться используя драйвер CMssqlSchema.

Но вот работать с несколькими резалт-сетами почему то так и не получается, функция PDOStatement::nextRowset ( ) (или её Yii аналог CDbDataReader::nextResult()) возвращает false (т.е. следующих результатов нет)

При этом драйвер sqlsrv.dll (который работает только из под Windows) с этим справляется прекрасно.
Ответ написан
Комментировать
@thekip Автор вопроса
Php/C#/Js Developer
Продолжу излагать свои находки:

Ковыряя просторы интернета, наткнулся на весьма интересный тред:
forums.famillecollet.com/viewtopic.php?id=434

В частности в нем идет обсуждения отсутствия поддержки nextRowset() в драйвере PDO_DBLIB. Итогом топика становится то, что в php 5.4 все таки добавили эту функцию.

«О слава Богам» — подумал я, и принялся тестировать (как раз с утра мы обновили версию php до 5.4)

Но не тут то было… Процедура нужная нам, возвращает 3 резалт сета, в первых двух идет скаляр, в третьем таблица и именно она мне и нужна.

Вообщем оно вернуло первые 2 результата (скаляра), а вместо третьего результата (таблицы) вывело пустой массив.

Собственно вопрос, какого черта, оно издевается надо мной что ли?
Ответ написан
Комментировать
@thekip Автор вопроса
Php/C#/Js Developer
Если кто то будет идти по моим стопам, то добавлю еще следующее:
Просто так заюзать функцию nextRowset() из PDO_DBLIB у меня не получилось, база вернула ответ:

SQLSTATE[HY000]: General error: 7405 General SQL Server error: Check messages from the SQL Server [7405] (severity 16)

Решение этой проблемы заключается в выполнении следующей команды:

 Yii::app()->db->createCommand('SET QUOTED_IDENTIFIER ON; SET ANSI_WARNINGS ON')->execute();

Но собственно основную проблему это не решает, в программу так и не приходят остальные резалт сеты.
Ответ написан
Комментировать
@thekip Автор вопроса
Php/C#/Js Developer
Вообщем вместе с нашим админом решили проблему. Рабочей оказалась связка FreeTDS + ODBC.
Для этого пришлось обновить freetds до последней версии 0.91 (пересобрав из исходников).

Собравшись, freetds засел не в стандартных путях, и поэтому пришлось подправить конфиг ODBC:

#/etc/odbcinst.ini
[FreeTDS]
Driver          = /usr/local/lib/libtdsodbc.so
Setup           = /usr/local/lib/libtdsodbc.so
CPTimeout               =
CPReusage               =
FileUsage               = 1
TDS Version             = 8.0
UsageCount              = 2


Ну и просто для справки сам конфиг подключения к MS SQL Server через ODBC:
#/etc/odbc.ini
[MS]
Driver = FreeTDS
Description = production_db
Trace = No
server = 
Port = 1433
Database = 
User = 
Password = 
TDS_Version = 8.0


В самом Yii потом подключаемся к ODBC так:
#protected/config/main.php
		'db'=>array(
			'connectionString' => 'odbc:MS', //MS это идентификатор конфигурации который мы задали в /etc/odbc.ini
                        'username'=>'логин',
                        'password'=>'пасс',
                        'driverMap' => array(
                            'odbc' => 'CMssqlSchema'
                        )
		),


Однако теперь словили другую проблему: кодировка.
В самом начале с ней тоже были проблемы, но они решались iconv(). Теперь же все что приходит от базы в кириллице, выводится абракадаброй. Причем понять что не так с кодировкой не получается, вывод представляет из себя что то вроде этого:

'???????\0xР№yв„–\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
Ответ написан
Комментировать
@tnz
Интересно пишете.
FreeTDS разве не однопоточный? В смысле что он не может выполнять несколько запросов одновременно.
С ним можно напрямую работать, минуя ODBC слой.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы