BEGIN TRY и EXECUTE ошибка динамического простого запроса

когда я выполняю прикрепленный запрос, я получаю сообщение об ошибке:

Сообщение 0, уровень 11, состояние 0, строка 0 Произошла серьезная ошибка в текущей команде. Результаты, если таковые имеются, должны быть отброшены.

Когда try-catch закомментирован, он работает, как и при использовании другого столбца. Когда раздел удаляется, он также работает.

Может ли кто-нибудь сказать, где здесь корень ошибки или это какая-то ошибка сервера sql?

Запрос:

BEGIN TRY 
    DECLARE  @vSqlCmd NVARCHAR(MAX) = N'
    SELECT TOP 1 V = d.collation_name, C = COUNT(1) OVER (PARTITION BY d.collation_name)
    FROM sys.all_columns d;';
    SELECT @vSqlCmd;

    EXECUTE (@vSqlCmd);
END TRY
BEGIN CATCH
    PRINT 'CATCH!!!';

    THROW;
END CATCH

person skk    schedule 18.02.2020    source источник
comment
Это больше похоже на проблему на сервере, а не на SQL. Какая версия SQL Server (укажите номер сборки). Как часто вы проверяете базу данных на наличие таких вещей, как повреждение?   -  person Larnu    schedule 18.02.2020
comment
Зачем использовать здесь динамический оператор? Ничего динамичного в этом нет.   -  person Larnu    schedule 18.02.2020
comment
Это ошибка. Отправьте отзыв здесь: feedback.azure.com/forums/908035-sql-server.   -  person David Browne - Microsoft    schedule 18.02.2020
comment
@Larnu - это не повреждение базы данных. Его легко воспроизвести, по крайней мере, в 2017 году или выше (не уверен, что в точной версии были добавлены проблемные строки PDW)   -  person Martin Smith    schedule 19.02.2020
comment
Спасибо за ваш вклад! Я тестировал этот образец на 3-х экземплярах — мин. SQL 2012 (13.0.5366) — все выдавали одну и ту же ошибку. Цель этой части запроса незначительна, она подготовлена ​​только для этого поста из более крупного решения, но спасибо за отступление и небольшой гневный пост ;-).   -  person skk    schedule 20.02.2020


Ответы (1)


Это ошибка. Я сообщил об этом здесь

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

Следующий запрос возвращает два object_id -103085222 и -593

SELECT object_id ,name
FROM sys.system_columns
where system_type_id in (35,99,167,175,231,239) and collation_name IS NULL

Они относятся к объектам ниже

+------------+----------------------------------+
|     id     |               name               |
+------------+----------------------------------+
| -103085222 | pdw_nodes_pdw_physical_databases |
|       -593 | pdw_table_mappings               |
+------------+----------------------------------+

По какой-то причине оба из них имеют строковый столбец (называемый physical_name), для которого SQL Server не может разрешить сопоставление. Поскольку эти объекты относятся только к Parallel Data Warehouse и даже не существуют должным образом в других версиях продукта, обычно это не проблема.

sys.all_columns ссылается на представление sys.system_columns, в котором для collation_name используется следующее выражение: convert(sysname, ColumnPropertyEx(object_id, name, 'collation'))

Более простой случай, который воспроизводит проблему:

BEGIN TRY
    SELECT columnpropertyex(-593, 'physical_name', 'collation')
END TRY
BEGIN CATCH
END CATCH 

Or

SET XACT_ABORT ON;
SELECT columnpropertyex(-593, 'physical_name', 'collation')

Оба возвращаются

Сообщение 0, уровень 11, состояние 0, строка 33

В текущей команде произошла серьезная ошибка. Результаты, если таковые имеются, должны быть отброшены.

При запуске за пределами блока TRY возвращается NULL (когда XACT_ABORT отключено). За кулисами он выдает исключение, которое обрабатывается внутри, и конечный пользователь не знает об этом. Стек вызовов при возникновении исключения показывает, что функция GetColumnCollate в конечном итоге использует алгебраизатор для попытки разрешить столбец, и в конечном итоге она терпит неудачу в CAlgTableMetadata::RaiseBadTableException (возможно, поскольку где-то отсутствует определение связанного объекта).

введите здесь описание изображения

При запуске в контексте TRY ... CATCH или с XACT_ABORT ON что-то идет не так с битом, который должен молча игнорировать ошибку и возвращать NULL. Вставка повторяющегося ключа в индекс с ignore_dup_key ON также вызывает внутреннюю ошибку, которая игнорируется, но не вызывает такой же проблемы.

Таким образом, один из способов решения проблемы — заключить ссылку на collation_name в выражение CASE, чтобы оно никогда не оценивалось для этих двух проблемных object_id при запуске внутри блока TRY.

  BEGIN TRY 
    DECLARE  @vSqlCmd NVARCHAR(MAX) = N'
    SELECT TOP 1 V = ca.safe_collation_name, C = COUNT(1) OVER (PARTITION BY ca.safe_collation_name)
    FROM sys.all_columns d
    CROSS APPLY (SELECT CASE WHEN object_id NOT IN (-593,-103085222) THEN collation_name END) ca(safe_collation_name);
    ';
    SELECT @vSqlCmd;

    EXECUTE (@vSqlCmd);
END TRY
BEGIN CATCH
    PRINT 'CATCH!!!';

    THROW;
END CATCH

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

person Martin Smith    schedule 18.02.2020
comment
Я подозреваю, что проблема заключается либо в отсутствующем, либо в неправильном значении collation_id в скрытой базе данных [mssqlsystemresource] для этого конкретного столбца этих двух конкретных объектов (т. е. идентификаторов -593 и -103085222). (Я добавил это и некоторую дополнительную информацию для ссылки на этот элемент обратной связи). - person Solomon Rutzky; 22.04.2020