Проверить арифметические переполнения в вычисляемых столбцах? - PullRequest
0 голосов
/ 21 декабря 2009

В нашем приложении мы собираемся позволить пользователям вводить арифметические выражения (+ - * /), используя другие столбцы базы данных для чисел, которые затем будут анализироваться приложением и записываться в базу данных как вычисляемый столбец.

Однако существуют проблемы, которые позволяют пользователям создавать выражения, которые могут вызвать исключения при select * таблице, такие как деление на ноль, арифметическое переполнение и другие возможные варианты, с которыми я еще не сталкивался ( хотя я думаю вот и все).

Наличие в базе данных исключения на select * было бы абсолютно разрушительным. Я предпочел бы попытаться переписать их выражение во что-то, что изящно потерпит неудачу, если у них есть подверженные ошибкам данные.

Для деления на ноль решение довольно простое:

add [Col] as case {divisor} when 0 then N'DIVIDE-BY-ZERO' else {expression} end

Мой вопрос: что я могу сделать для арифметического переполнения? Отображение пустых или явно неверных данных в столбце не будет проблемой, но выдает исключения.

Ответы [ 4 ]

1 голос
/ 21 декабря 2009

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

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

Если вы уже анализируете выражение, я бы скомпилировал его и на стороне клиента и обработал ошибку построчно.

Перехват исключения с использованием TRY / CATCH - это сценарий «все или ничего», а не построчно.

1 голос
/ 22 декабря 2009

Мне неприятно видеть, что вы принимаете ответ, который на самом деле не приближает вас к вашей цели.

В качестве отдельного ответа, который может вам немного помочь, вы можете заставить вычисляемые столбцы вызывать (детерминированный) скалярный UDF.

См., Например, здесь

Так что, если вы собираетесь создать вычисляемый столбец, сделайте так, чтобы он передавал столбцы сгенерированному UDF (или нескольким UDF) и выполнял там работу. В скалярной UDF у вас может быть много кода для решения проблем, но вы все равно не можете использовать TRY/CATCH. То, что вы можете сделать в своем скалярном UDF - это ловить случаи и возвращать соответствующие ответы (вероятно, всплывают NULL).

Но производительность будет очень плохой для скалярных UDF (не уверен насчет непостоянных встроенных вычисляемых столбцов по сравнению с UDF, мы в основном используем постоянные), так что вы можете серьезно подумать о том, чтобы сделать столбец постоянным, который затем будет использовать пространство в базе данных и сделает вставки и обновления немного медленнее. Это большой компромисс.

0 голосов
/ 23 декабря 2009

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

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

0 голосов
/ 21 декабря 2009

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

В случае исключений вы можете вернуть бессмысленный набор результатов, который совместим с исходным заданным пользователем:

begin try
    select exp(999)
end try
begin catch
    select 1
end catch 
...