Удивительные результаты для типов данных с модификатором типа

Обсуждая рекурсивное решение CTE для этого вопроса:

@ypercube наткнулся на удивительное исключение, которое заставляет нас исследовать обработку типа модификаторы. Мы обнаружили удивительное поведение.

1. Тип cast сохраняет модификатор типа в некоторых контекстах

Даже если не указано. Самый простой пример:

SELECT 'vc8'::varchar(8)::varchar

Можно ожидать, что varchar (без модификатора), по крайней мере, я бы это сделал. Но результат varchar(8) (с модификатором). Многие связанные случаи в скрипте ниже.

2. Конкатенация массива теряет модификатор типа в некоторых контекстах

Без необходимости, поэтому это заблуждается на противоположной стороне:

SELECT ARRAY['vc8']::varchar(8)[]
     , ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)

Первое выражение дает varchar(8)[], как ожидалось.
Но второй, после конкатенирования другого varchar(8), опускается только до varchar[] (без модификатора). Подобное поведение от array_append(), примеры в скрипте ниже.

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

3. Рекурсивный CTE требует, чтобы типы данных соответствовали точно

Учитывая эту упрощенную таблицу:

CREATE TABLE a (
  vc8  varchar(8)  -- with modifier
, vc   varchar     -- without  
);
INSERT INTO a VALUES  ('a',  'a'), ('bb', 'bb');

Пока этот rCTE работает для столбца varchar vc, он не работает для столбца varchar(8) vc8:

WITH RECURSIVE cte AS (
   (
   SELECT ARRAY[vc8] AS arr  -- produces varchar(8)[]
   FROM   a
   ORDER  BY vc8
   LIMIT 1
   )

   UNION ALL
   (
   SELECT a.vc8 || c.arr  -- produces varchar[] !!
   FROM   cte c
   JOIN   a ON a.vc8 > c.arr[1]
   ORDER  BY vc8
   LIMIT 1
   )
   )
TABLE  cte;
ОШИБКА: рекурсивный запрос «cte» столбец 1 имеет характерный характер, изменяющийся (8) [] в нерекурсивном выражении, но различающийся тип символа [] в целом
Подсказка: вывести вывод нерекурсивного термина в нужный тип. Должность: 103

Одним из быстрых способов решения проблемы было бы преобразование в text.

Простой UNION запрос не проявляет той же проблемы: он устанавливает для типа без модификатора, который гарантированно сохраняет всю информацию , Но rCTE более придирчив.

Кроме того, у вас не будет проблем с более часто используемым max(vc8) вместо ORDER BY /LIMIT 1, потому что max() и друзья соглашаются на text сразу (или соответствующий базовый тип без модификатора).

SQL Fiddle , демонстрирующий 3 вещи:

  1. Ряд примеров выражений, включая неожиданные результаты.
  2. Простой rCTE, который работает с varchar (без модификатора).
  3. Тот же rCTE, создающий исключение для varchar(n) (с модификатором).

Скрижаль для pg 9.3. Я получаю те же результаты локально для pg 9.4.4.

Я создал таблицы из демонстрационных выражений, чтобы показать точный тип данных, включая модификатор. Пока pgAdmin показывает эту информацию из коробки, она недоступна из sqlfiddle. Примечательно, что он также недоступен в psql (!). Это известный недостаток в psql, и возможное решение было обсуждался на pgsql-хакерах до - но пока не реализован. Это может быть одной из причин, по которым проблема еще не была обнаружена и исправлена.

На уровне SQL вы можете использовать pg_typeof() , чтобы получить тип (но не модификатор).

Вопросы

Вместе, 3 проблемы создают беспорядок.
Чтобы быть точным, вопрос 1. не задействован напрямую, но он разрушает кажущееся очевидное исправление с актом в не- -рекурсивный термин: ARRAY[vc8]::varchar[] или аналогичный, что добавляет к путанице.
Какой из этих элементов является ошибкой, сбой или просто, как это должно быть?
Я что-то пропустил или должен сообщить об ошибке?

11 голосов | спросил Erwin Brandstetter 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 26 Sep 2015 03:36:52 +0300 2015, 03:36:52

1 ответ


1

Это связано с атрибутами (определенными в pg_class и pg_attribute или динамически определяется из инструкции select), поддерживающей модификаторы (через ---- +: = 3 =: + ----), в то время как параметры функции нет. Модификаторы теряются при обработке через функции, и поскольку все операторы обрабатываются через функции, модификаторы теряются при обработке операторами.

Функции с выходными значениями или возвращаемые наборы записей или эквивалентные pg_attribute.atttypmod также не могут содержать модификаторы, включенные в определение. Однако таблицы, в которых returns table(...) будут сохраняться (на самом деле, вероятно, с помощью typecast) любые модификаторы, определенные для return setof <type> в type.

ответил Ziggy Crueltyfree Zeitgeister 29 AMpFri, 29 Apr 2016 11:07:31 +030007Friday 2016, 11:07:31

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132