10.1. Обзор#

10.1. Обзор

10.1. Обзор #

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

Сканер/парсер Tantor BE разделяет лексические элементы на пять основных категорий: целые числа, нецелые числа, строки, идентификаторы и ключевые слова. Константы большинства нечисловых типов сначала классифицируются как строки. Определение языка SQL позволяет указывать имена типов с помощью строк, и этот механизм может быть использован в Tantor BE для правильного запуска парсера. Например, запрос:

SELECT text 'Origin' AS "label", point '(0,0)' AS "value";

 label  | value
--------+-------
 Origin | (0,0)
(1 row)

имеет две литеральные константы типа text и point. Если тип не указан для строковой литеральной константы, то сначала ей присваивается тип-заполнитель unknown, который будет разрешен на более поздних этапах, как описано ниже.

Существуют четыре основных конструкции SQL, требующих отдельных правил преобразования типов в парсере Tantor BE:

Function calls

Большая часть системы типов Tantor BE основана на богатом наборе функций. Функции могут иметь один или несколько аргументов. Поскольку Tantor BE позволяет перегрузку функций, только имя функции само по себе не уникально идентифицирует функцию, которую нужно вызвать; парсер должен выбрать правильную функцию на основе типов данных переданных аргументов.

Operators

Tantor BE позволяет использовать выражения с префиксными (одноаргументными) операторами, а также инфиксными (двухаргументными) операторами. Как и функции, операторы могут быть перегружены, поэтому возникает та же проблема выбора правильного оператора.

Value Storage

SQL INSERT и UPDATE операторы помещают результаты выражений в таблицу. Выражения в операторе должны соответствовать и, возможно, преобразовываться в типы целевых столбцов.

UNION, CASE, and related constructs

Поскольку все результаты запроса из объединенного оператора SELECT должны появляться в одном наборе столбцов, типы результатов каждого предложения SELECT должны быть сопоставлены и преобразованы в единый набор. Аналогично, выражения результата конструкции CASE должны быть преобразованы в общий тип, чтобы выражение CASE в целом имело известный тип вывода. Некоторые другие конструкции, такие как ARRAY[] и функции GREATEST и LEAST, также требуют определения общего типа для нескольких подвыражений.

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

Дополнительный эвристический алгоритм, предоставляемый парсером, позволяет улучшить определение правильного поведения приведения типов среди групп типов, имеющих неявные приведения. Типы данных разделены на несколько основных категорий типов, включая boolean, numeric, string, bitstring, datetime, timespan, geometric, network и пользовательский типы. (См. список в таблице Таблица 50.65; но также возможно создание пользовательских категорий типов). В каждой категории может быть один или несколько предпочтительных типов, которые предпочтительны при выборе возможных типов. С тщательным выбором предпочтительных типов и доступных неявных приведений можно обеспечить разрешение неоднозначных выражений (с несколькими возможными вариантами разбора) в полезном виде.

Все правила преобразования типов разработаны с учетом нескольких принципов:

  • Неявные преобразования никогда не должны иметь неожиданных или непредсказуемых результатов.

  • В парсере или исполнителе не должно быть никакой дополнительные издержки, если запрос не требует неявного преобразования типов. То есть, если запрос правильно сформирован и типы уже совпадают, то запрос должен выполняться без дополнительных затрат времени в парсере и без введения лишних неявных вызовов преобразования в запросе.

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