Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / PostgreSQL Новый топик    Ответить
 Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
В таблице table имеется поле field типа int2[] с индексом GIN(array_ops).
Выполняем следующий поисковый запрос:
SELECT ... FROM "table" WHERE field OPERATOR(pg_catalog.&&) ARRAY[8];
-- SQL Error [42883]: ОШИБКА: оператор не существует: smallint[] pg_catalog.&& integer[]
Здесь вместо && указывается OPERATOR(pg_catalog.&&) по следующим причинам:
1) в схеме public установлено расширение intarray с одноимённым оператором int4[] && int4[].
2) нетипизированный массив-литерал ARRAY[8] по умолчанию приводится к int4[]/int8[] (в данном случае к int4[]) => применяется оператор int4 && int4 от расширения intarray => GIN-индекс (созданный для типа int2[]), не применяется.

Вопросы:
1) Почему нетипизированный массив-литерал всегда приводится к int4/int8 ?
Более корректная логика: приведение нетипизированного массива-литерала к типу парного типизированного операнда (в данном случае = int2[]).

2) Как на уровне приложения (формирующего запрос к БД) решить проблему типизации массива-литерала ?
В общем случае приложение знает только общие типы данных полей (строковое, целочисленное, вещественное, булево, массив и т.д.), но не знает и не должно знать конкретного SQL-типа (int2[], int4[] и т.д.). Как в этом случае приложению сформировать корректный (работающий) запрос ?

3) Если оба оператора (стандартный anyarray && anyarray и int4[] && int4[] от intarray) будут находиться в одной схеме, то как можно будет явно указать, какой оператор должен использоваться ? OPERATOR(???.&&)

P.S. Кто знает, где в справке описывается конструктор OPERATOR(...) ? Поиск как всегда не работает.

Сообщение было отредактировано: 11 апр 21, 14:08
11 апр 21, 14:09    [22307232]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Maxim Boguk
Member

Откуда: Melbourne, Австралия
Сообщений: 4719
Cyrax_02
В таблице table имеется поле field типа int2[] с индексом GIN(array_ops).
Выполняем следующий поисковый запрос:
SELECT ... FROM "table" WHERE field OPERATOR(pg_catalog.&&) ARRAY[8];
-- SQL Error [42883]: ОШИБКА: оператор не существует: smallint[] pg_catalog.&& integer[]
Здесь вместо && указывается OPERATOR(pg_catalog.&&) по следующим причинам:
1) в схеме public установлено расширение intarray с одноимённым оператором int4[] && int4[].
2) нетипизированный массив-литерал ARRAY[8] по умолчанию приводится к int4[]/int8[] (в данном случае к int4[]) => применяется оператор int4 && int4 от расширения intarray => GIN-индекс (созданный для типа int2[]), не применяется.

Вопросы:
1) Почему нетипизированный массив-литерал всегда приводится к int4/int8 ?
Более корректная логика: приведение нетипизированного массива-литерала к типу парного типизированного операнда (в данном случае = int2[]).

2) Как на уровне приложения (формирующего запрос к БД) решить проблему типизации массива-литерала ?
В общем случае приложение знает только общие типы данных полей (строковое, целочисленное, вещественное, булево, массив и т.д.), но не знает и не должно знать конкретного SQL-типа (int2[], int4[] и т.д.). Как в этом случае приложению сформировать корректный (работающий) запрос ?

3) Если оба оператора (стандартный anyarray && anyarray и int4[] && int4[] от intarray) будут находиться в одной схеме, то как можно будет явно указать, какой оператор должен использоваться ? OPERATOR(???.&&)

P.S. Кто знает, где в справке описывается конструктор OPERATOR(...) ? Поиск как всегда не работает.



1)потому что определение типов вводных данных производится задолго ДО ТОГО КАК смотрим какой там тип на другой стороне (и даже до того как он может быть хотя бы теоретически быть известным)...
более того ваша идея полностью ломает возможность использования/создания операторов int2+int8 например
ну и как вы предлагаете тогда определять типы в конструкции 1+100000000 в вашей парадигме?


2)"В общем случае приложение знает только общие типы данных полей" - приложение должно знать и учитывать и в нормальной ситуации ПРИНУДИТЕЛЬНО всегда приводить к нужным типам... автоприведение типов вообще минное поле...
вот сколько должно быть field1(тип int4)+ 0.03 ? а сколько должно быть 2/5 ?
автор запросов должен знать типы полей и приводить литералы к нужным типам (ORM кстати основные это умеют и делают)
для типовых случаев типа '+' есть просто операторы для всех вероятных сочетаний (для целочисленных все 9 операторов по матрице smallint/int/bigint)
для array[] && операторов просто не сделали такие наборы... поэтому там надо руками приводить.



3)на этот вопрос читайте ответ тут вот: https://www.postgresql.org/docs/13/typeconv-oper.html
в части "Look for the best match."
ну и в одну схему вы их не засунете в данном случае
потому что один системный и жить ему всегда в pg_catalog
а второй из extension и жить ему где угодно КРОМЕ pg_catalog


4)OPERATOR - служебная конструкция чем меньше вы ее используете тем лучше )).




--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

Сообщение было отредактировано: 11 апр 21, 15:19
11 апр 21, 15:22    [22307247]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Maxim Boguk
1) потому что определение типов вводных данных производится задолго ДО ТОГО КАК смотрим какой там тип на другой стороне (и даже до того как он может быть хотя бы теоретически быть известным)...
Определение типа нетипизированного операнда можно отложить до соответствующего момента, либо тип нетипизированного операнда пересмотреть в соответствующий момент. Это уже вопрос реализации, а не логики. Логика первостепенна.

Maxim Boguk
более того ваша идея полностью ломает возможность использования/создания операторов int2+int8 например
ну и как вы предлагаете тогда определять типы в конструкции 1+100000000 в вашей парадигме?

...вот сколько должно быть field1(тип int4)+ 0.03 ? а сколько должно быть 2/5 ?
Логика "приведение типа нетипизированного литерала к совместимому типу парного типизированного операнда" к вашим примерам неприменима (в первом примере с обоих сторон - типизированные операнды, во втором примере типы несовместимы). А вот к сабжевому примеру - применима.

Maxim Boguk
приложение должно знать и учитывать и в нормальной ситуации ПРИНУДИТЕЛЬНО всегда приводить к нужным типам... автоприведение типов вообще минное поле... Автор запросов должен знать типы полей и приводить литералы к нужным типам (ORM кстати основные это умеют и делают)

Насколько я себе представляю, все ORM в составе фреймворков как раз и реализуют то самое автоприведение типов литералов. А если ORM базируется на надстройках типа php-ного PDO, то это самое приведение реализуется на самом примитивном уровне (целое, строка, булево и, возможно, вещественное).

Допустим, в БД для некоторого поля мы изменили тип поля с int2 на int4. В этом случае потребуется изменить тип приведения во всех связанных запросах по всему коду приложения. Таких мест может быть и 10, и 100, и 1000. И менять придётся вручную (IDE-рефакторинг не поможет). Если же автоприведение всё-таки реализуется на уровне ORM, то чем оно принципиально отличается от автоприведения, реализуемого на уровне СУБД ? На уровне СУБД автоприведение всегда будет надёжнее и безопаснее.

P.S. Даже в самом PostgreSQL функция format предусматривает только строковые литералы и литералы массивов (%L). Числа представляются как строковые литералы.

Сообщение было отредактировано: 11 апр 21, 17:57
11 апр 21, 17:56    [22307273]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
автор
P.S. Даже в самом PostgreSQL функция format предусматривает только строковые литералы и литералы массивов (%L). Числа представляются как строковые литералы.
Хотел написать так: "В PostgreSQL функция format числовые литералы представляет как строковые (%L)".
11 апр 21, 18:08    [22307276]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Melkij
Member

Откуда: Санкт-Петербург
Сообщений: 1285
Cyrax_02
Кто знает, где в справке описывается конструктор OPERATOR(...)

https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH
11 апр 21, 18:34    [22307278]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Как оказалось, в PostgreSQL озвученная логика "приведение типа нетипизированного литерала к совместимому типу парного типизированного операнда" уже реализована:
https://www.postgresql.org/docs/13/typeconv-oper.html
If one argument of a binary operator invocation is of the unknown type, then assume it is the same type as the other argument for this check. Invocations involving two unknown inputs, or a unary operator with an unknown input, will never find a match at this step.
А почему это самое автоприведение не работало в сабжевом запросе - потому что с обоих сторон были указаны типизированные операнды. ARRAY[8] - это не нетипизированный литерал, а выражение-конструктор, возвращающее типизированный литерал типа int4[] или int8[]. Нетипизированный литерал массива (с типом данных "unknown") - это строка '{8}':

SELECT ... FROM "table" WHERE field OPERATOR(pg_catalog.&&) '{8}';
-- OK (нетипизированный литерал массива '{8}' автоматически приводится к типу левого операнда int2[])

P.S
.Только вот оператор здесь по-прежнему необходимо указывать со схемой - иначе для int2[] && unknown PostgreSQL не сможет выбрать оператор между int4[] && int4[] и anyarray && anyarray.

Сообщение было отредактировано: 11 апр 21, 18:42
11 апр 21, 18:46    [22307280]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Да, оно самое:
https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH
If you need to write a qualified operator name in an expression, there is a special provision: you must write
OPERATOR(schema.operator)
This is needed to avoid syntactic ambiguity. An example is:
SELECT 3 OPERATOR(pg_catalog.+) 4;
Значит, только по имени схемы можно обращаться. По имени расширения нельзя.
11 апр 21, 18:57    [22307283]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Maxim Boguk
Member

Откуда: Melbourne, Австралия
Сообщений: 4719
Cyrax_02,

То что вы хотите в PG решается не через умное приведение типов (оно там и так слишком умное с моей т.з) а через заведение совместимых операторов на все очевидно совместимые комбинации.

В данном случае проблема в отсутствии оператора smallint[] && integer[] (и вообще в отсутствии cross-compatible-type операций на массивах).
в принципе мы его вполне себе можете сами описать я думаю и разместить в схеме public
и даже GIN поддержку наверное можно будет без С хакинга вставить (но тут я уже не уверен проверять надо).

Равно как и + в случае smallint_var + bigint_constant не занимается попыткой угадать типы чтобы + совместимый был
а просто использует smallint+bigint оператор заданный в системе.

Вот вам прототип если очень хочется покопать:
mboguk=# select ARRAY[100]::int[] && ARRAY[8]::smallint[];
ERROR:  operator does not exist: integer[] && smallint[]
LINE 1: select ARRAY[100]::int[] && ARRAY[8]::smallint[];
                                 ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
mboguk=# CREATE OR REPLACE FUNCTION int4_int2_overlap(int[], smallint[])
RETURNS boolean
AS
$BODY$
    SELECT pg_catalog.arrayoverlap($1, $2::int[]);
$BODY$
LANGUAGE SQL;
CREATE FUNCTION
mboguk=# CREATE OPERATOR && (
    FUNCTION = int4_int2_overlap,
    LEFTARG = int[],
    RIGHTARG = smallint[]
);
CREATE OPERATOR
mboguk=# select ARRAY[100]::int[] && ARRAY[8]::smallint[];
 ?column? 
----------
 f
(1 row)



--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
11 апр 21, 19:10    [22307286]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Значит, операторы всё-таки разрешает создавать на уровне SQL (базовые типы - нет).
В любом случае операторы на уровне SQL будут работать очень медленно. А это критично при выполнении запросов.
А писать на C более трудоёмко + придётся постоянно поддерживать работоспособность от версии к версии.

На данный момент более приемлемым выглядит вариант указания оператора через схему OPERATOR(pg_catalog.&&) + автоприведение типов. Можно прописать константой в ORM или Query Builder'е и использовать в приложении вместо "&&".

Сообщение было отредактировано: 11 апр 21, 19:19
11 апр 21, 19:26    [22307289]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Maxim Boguk
Member

Откуда: Melbourne, Австралия
Сообщений: 4719
Cyrax_02
Значит, операторы всё-таки разрешает создавать на уровне SQL (базовые типы - нет).
В любом случае операторы на уровне SQL будут работать очень медленно. А это критично при выполнении запросов.
А писать на C более трудоёмко + придётся постоянно поддерживать работоспособность от версии к версии.

На данный момент более приемлемым выглядит вариант указания оператора через схему OPERATOR(pg_catalog.&&).
Можно прописать константой в ORM или Query Builder'е и использовать в пользовательском коде вместо "&&".


Да и типы тоже позволяет на самом деле.
https://www.postgresql.org/docs/13/sql-createtype.html

PS: а что вы под базовыми типами понимаете?

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
11 апр 21, 19:29    [22307290]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Maxim Boguk
PS: а что вы под базовыми типами понимаете?

https://www.postgresql.org/docs/13/sql-createtype.html#id-1.9.3.94.5.8
Для базовых типов функции ввода/вывода на SQL были запрещены в последних версиях PostgreSQL.
11 апр 21, 19:37    [22307292]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Maxim Boguk
Member

Откуда: Melbourne, Австралия
Сообщений: 4719
Cyrax_02
Maxim Boguk
PS: а что вы под базовыми типами понимаете?

https://www.postgresql.org/docs/13/sql-createtype.html#id-1.9.3.94.5.8
Для базовых типов функции ввода/вывода на SQL были запрещены в последних версиях PostgreSQL.


Смысл реализации скалярных типов без поддержки на уровне С кода - от меня ускользает.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
11 апр 21, 19:59    [22307293]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Maxim Boguk
Смысл реализации скалярных типов без поддержки на уровне С кода - от меня ускользает.
То же самое относится и к написанным вами выше функции и оператору на уровне SQL.
И операторы, и ввод/вывод базовых типов одинаково критичны при выполнении запросов.

Сообщение было отредактировано: 11 апр 21, 20:00
11 апр 21, 20:03    [22307294]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Cyrax_02
Member

Откуда:
Сообщений: 1462
Cyrax_02
ARRAY[8] - это не нетипизированный литерал, а выражение-конструктор, возвращающее типизированный литерал типа int4[] или int8[].
Правильно так:
ARRAY[8] - это не нетипизированный литерал, а выражение-конструктор, возвращающее типизированный массив типа int4[].

Maxim Boguk
ну и в одну схему вы их не засунете в данном случае
потому что один системный и жить ему всегда в pg_catalog
а второй из extension и жить ему где угодно КРОМЕ pg_catalog
Например, устанавливаем два расширения в схему public. Каждое из них создаёт свой оператор &&.
Как в этом случае указать, какой именно оператор должен применяться ?
12 апр 21, 17:03    [22307756]     Ответить | Цитировать Сообщить модератору
 Re: Нетипизированный массив-литерал не приводится к типу второго операнда  [new]
Melkij
Member

Откуда: Санкт-Петербург
Сообщений: 1285
Cyrax_02
Например, устанавливаем два расширения в схему public. Каждое из них создаёт свой оператор &&.
Как в этом случае указать, какой именно оператор должен применяться ?

А как такое может произойти?
"pg_operator_oprname_l_r_n_index" UNIQUE, btree (oprname, oprleft, oprright, oprnamespace)
ну а если сами сломаете это ограничение уникальности - то приключения за свой счёт.
12 апр 21, 17:39    [22307787]     Ответить | Цитировать Сообщить модератору
Все форумы / PostgreSQL Ответить