PostgreSQL версии 14
У меня есть запрос, который при запуске из pgAdmin ведет себя иначе, чем при запуске из PHP.
SELECT * FROM UNNEST('{1,2,3,4,5}'::integer[] - '{2,4}'::integer[])
Когда я запускаю это из pgAdmin, все работает нормально. Когда я передаю его через PHP с помощью PDO, я получаю ОШИБКА: оператор не существует: целое число[] - целое число[].
Этот оператор массива предоставляется модулем intarray. CREATE EXTENSION intarray сообщает мне, что расширение уже установлено. Это похоже на то, что модуль intarray по какой-то причине недоступен для процесса PHP.
Может ли кто-нибудь указать мне правильное направление относительно того, что здесь может происходить?
Где находится php-код, который вызывает ошибку?
Возможно, это ограничение PDO по сравнению с драйвером pg_*.
@AdrianKlaver: Та же база данных, но другой пользователь. Один с меньшим количеством разрешений. Я попробую запустить от имени этого пользователя и посмотреть, смогу ли я повторить. u_mulder: Этот код работает нормально уже много лет. Только эта ситуация является проблемой, поэтому я не думаю, что это общая проблема PHP, если только, как предполагает Алекс Ховански, это не особенность PDO.
Я попытался сделать пользователя суперпользователем. Никаких изменений.
Ошибка довольно специфична: проблема связана с оператором -
для массивов, который предоставляется intarray
. Я не понимаю, как может быть что-то еще, кроме того, что intarray
не установлен или недоступен. В psql
что означает \dx
возврат на продление. Также проверьте журнал Postgres для получения дополнительной информации.
Я готов поспорить, что intarray
установлен просто в пространство имен, которое не отображается в вашей search_path
/current_schema(true) , когда вы запускаете тесты из приложения PHP. Вы можете проверить, где он находится, и либо добавить схему в путь поиска, либо добавить квалификацию схемы оператора с помощью operator().
Посмотрите эту скрипку.
@Zegarek: БИНГО!!! intarray является общедоступным, и существует код, явно устанавливающий путь поиска к определенной схеме без включения public. Пожалуйста, опубликуйте это как ответ, чтобы я мог принять его.
Согласно комментарию @Adrian Klaver, полезно сначала подтвердить, что ваше PHP-приложение и клиент, с которым вы запускали тесты, оба подключаются к одному и тому же кластеру и на нем есть одна и та же база данных, которая установили intarray
. Несколько экземпляров, работающих на одном хосте или за установленными на нем туннелями, опечатки в имени базы данных или номере порта могут скрыть тот факт, что вы имеете дело с разными, несовпадающими базами данных.
Поскольку вы можете подтвердить, что это не так, моя ставка будет заключаться в том, что intarray
установлен только в пространстве имен, которое не отображается в вашем search_path
/ current_schemas(true), когда вы запускаете тесты из приложения PHP.
Вы можете проверить, где это: демо на db<>fiddle
create schema some_other_schema;
create extension intarray schema some_other_schema;
select extname,extnamespace::regnamespace from pg_extension;
select e.extnamespace::regnamespace
, p.oprnamespace::regnamespace
, e.extname
, p.oid::regoperator
, p.oprname
, p.oprcode::regprocedure
from pg_catalog.pg_operator as p
join pg_catalog.pg_depend as d on (d.objid = p.oid)
join pg_catalog.pg_extension as e on (d.refobjid = e.oid)
where e.extname='intarray'
and p.oprname='-';
Как только вы убедитесь, где он находится, добавьте квалификацию схемы оператора с помощью operator() :
select array[1,2] operator(some_other_schema.-) array[2,3];
Или добавьте схему в search_path
:
select set_config( 'search_path'
,'some_other_schema, '
||current_setting('search_path')
,false);
Это позволяет пропустить квалификацию схемы оператора:
select array[1,2] - array[2,3];
Стоит отметить, что вопреки тому, что следует из названия расширения, intarray
int[] - int[]
вычитает множества, а не массивы. Перед вычитанием оба операнда будут отсортированы и дедуплицированы. Станет немного яснее, если вы проверите, что вариант -
, вычитающий все остальное int[]
, называется intset_subtract
, а вариант, вычитающий один элемент, называется intarray_del_elem
и не выполняет молчание uniq(sort())
.
Этот ответ решил мою проблему. intarray установлен публично, и мой путь поиска в PHP не включал public. Спасибо!!!!
Лучше всего предположить, что база данных, к которой вы подключаетесь с помощью кода PHP, отличается от той, к которой вы подключаетесь в pgAdmin4. Проверьте это, проверив журнал Postgres.