Синтаксическая ошибка при выполнении пакета инструкций через PDO, но нормально через SSMS

#php #sql #sql-server #tsql #pdo

#php #sql #sql-сервер #tsql #pdo

Вопрос:

Я пишу код для создания базы данных MSSQL с нуля, используя PHP PDO. Я создал базу данных, и теперь мне нужно выполнить кучу инструкций, загруженных из файла .SQL, Для создания таблиц, данных и т. Д. Первые несколько строк

 EXEC sp_dbcmptlevel 'myDbName', 120
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
BEGIN
EXEC [myDbName].[dbo].[sp_fulltext_database] @action = 'enable'
END
GO
ALTER DATABASE [myDbName] SET ANSI_NULL_DEFAULT OFF 
GO
EXEC sp_dbcmptlevel 'myDbName', 120

...
  

Если я запускаю .SQL-файл непосредственно в SSMS, он работает отлично. Если я загружу его и выполню через PHP PDO, я получу

 Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: [Microsoft][ODBC Driver 11 for SQL Server][SQL Server]Incorrect syntax near 'GO'.' in ...
  

Глядя на профилировщик, мой запрос предваряется / оборачивается

 declare @p1 int
set @p1=NULL
exec sp_prepexec @p1 output,NULL,N'EXEC sp_dbcmptlevel ''myDbName', 120
...
  

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

 $db = new PDO('sqlsrv:Server='.$serverName.';Database='.$databaseName, $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8);
$db->prepare($mySqlScript)->execute();
  

Как я могу исправить синтаксическую ошибку, чтобы выполнить весь набор команд, загружаемых PHP из файла SQL?

Ответ №1:

Вы должны были разделить свой скрипт с помощью предложения «GO» на несколько инструкций, а затем запускать их один за другим.

Что-то вроде:

 $script = file_get_contents('script.sql');
$statements = explode( 'GO', $script );
foreach( $statements as $statement ) {
  // here execute the $statement
  $sth = $dbh->prepare($statement);
  $sth->execute();
}
  

Это то, что SSMS делает внутренне, разбивает инструкции на «GO» перед их выполнением.

Комментарии:

1. Отлично, спасибо. Это приходило мне в голову как хак, но не как требуемый способ. Знаете ли вы, в чем причина невозможности выгрузить весь скрипт? Я бы подумал, что из-за проблем с производительностью было бы лучше иметь возможность обрабатывать все за один раз.

2. Вероятно, это не было одной из целей библиотеки, и это поведение достаточно легко реализовать, поэтому нам пришлось с ним справиться. Вы можете закодировать его как function execScript( $scriptPath ) { // Do the split and the execution } и в своем коде обрабатывать его так, как если бы он был частью исходной библиотеки. Это то, что библиотека будет делать (более или менее) любым способом.