powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Баг при работе с временными таблицами
15 сообщений из 15, страница 1 из 1
Баг при работе с временными таблицами
    #39205707
ln123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Столкнулся с интересной проблемой когда создание временной таблицы влияет на результаты возвращаемые функцией из другой таблицы. Проблему выявил на 9.5.1 х64 под Windows. Ниже код который демонстрирует наличие данной ошибки:

Открываем новую сессию и выполняем в ней следующий код:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
begin;
create table  tmp123 (id numeric);
create table  tmp222 (id numeric);
create function gettmp123()  RETURNS numeric AS
$BODY$
declare
  idv numeric;
  begin
    select coalesce(max(id),0) into idv from tmp123;
    return idv;
  end;
$BODY$
  LANGUAGE plpgsql VOLATILE ;

do
$$
begin 
create temporary table  tmp222 (id numeric) on commit  delete rows;
 raise notice 'Должно быть 0, результат %' , gettmp123();
 create temporary table  tmp123 (id numeric) on commit  delete rows;
 insert into tmp123 (id) values(1);
 raise notice 'Должно быть 1, результат %' , gettmp123();
end;
$$;

rollback;



Собственно при выполнении получался следующий результат:
Должно быть 0, результат 0
Должно быть 1, результат 0

Если убрать строку
create temporary table tmp222 (id numeric) on commit delete rows;
то результат будет
Должно быть 0, результат 0
Должно быть 1, результат 1

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

Мне кажется что данное поведение сервера это явный баг.
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205735
Lonepsycho
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123,

а тут точно баг постгреса? может проблема в том, что у вас по две таблицы существуют с одинаковыми именами?
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205752
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123,

А почему вы думаете что должно быть 1?
Командой insert into tmp123 (id) values(1); вы вставили в ВРЕМЕННУЮ таблицу (она имеет приоритет в search_path)
А хранимка работает с постоянной таблицей.
Так что все работает как ожидается.

В общем не делайте временные таблицы с именами постоянных и не будет проблем.

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205789
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123,

чтобы такого не происходило нужно явно указывать схему (public) таблиц в хранимке.

из документации :
Likewise, the current session's temporary-table schema, pg_temp_nnn, is always searched if it exists. It can be explicitly listed in the path by using the alias pg_temp. If it is not listed in the path then it is searched first (even before pg_catalog). However, the temporary schema is only searched for relation (table, view, sequence, etc) and data type names. It is never searched for function or operator names.
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205926
ln123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

В том то и дело что предполагается что хранимка будет работать со временной таблицей если такая будет создана т.к.
из документации:
"Existing permanent tables with the same name are not visible to the current session while the temporary table exists, unless they are referenced with schema-qualified names."

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

Собственно баг, в том что результат обращения к tmp123 зависит от того была ли ранее в сессии создана какая либо временная таблица в данном случае tmp222, а должен зависеть только от создания tmp123.

Кстати
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
begin;
create table  tmp123 (id numeric);
create table  tmp222 (id numeric);
create function gettmp123()  RETURNS numeric AS
$BODY$
declare
  idv numeric;
  begin
    select coalesce(max(id),0) into idv from tmp123;
    return idv;
  end;
$BODY$
  LANGUAGE plpgsql VOLATILE ;

do
$$
declare
  idv numeric;
begin 
create temporary table  tmp222 (id numeric) on commit  delete rows;
 raise notice 'Должно быть 0, результат %' , gettmp123();
 create temporary table  tmp123 (id numeric) on commit  delete rows;
 insert into tmp123 (id) values(1);
 select coalesce(max(id),0) into idv from tmp123;
 raise notice 'Результат прямого запроса %, результат функции %' , idv, gettmp123();
end;
$$;

rollback;



вернет
Результат прямого запроса 1, результат функции 0

То что запрос и функция выполняющая такой же запрос возвращают разные результаты это то же корректное поведение для СУБД?
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205929
ln123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexius,

В том то и дело что в моем примере база работает совсем не так как написано в той цитате что вы привели.

1. Временной таблицы нет функция возвращает 0 т.е. обращается к постоянной таблице
2. Временная таблица появилась и мы в нее вставили запись, а функция все равно возвращает 0 хотя должна обратится к вновь созданной временной таблице и вернуть 1
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205941
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123Alexius,

В том то и дело что в моем примере база работает совсем не так как написано в той цитате что вы привели.

1. Временной таблицы нет функция возвращает 0 т.е. обращается к постоянной таблице
2. Временная таблица появилась и мы в нее вставили запись, а функция все равно возвращает 0 хотя должна обратится к вновь созданной временной таблице и вернуть 1

Функция парсится при первом вызове и далее как оно таблицы разрезолвила так они и останутся.
Если вам надо другое поведение - используйте EXECUTE вместо просто SELECT в хранимке.
Но тогда это будет медленнее так как теряется главный смысл хранимок - запросы не парсятся и не планируются на каждый вызов а только 1 раз.

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205954
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Bogukln123Alexius,

В том то и дело что в моем примере база работает совсем не так как написано в той цитате что вы привели.

1. Временной таблицы нет функция возвращает 0 т.е. обращается к постоянной таблице
2. Временная таблица появилась и мы в нее вставили запись, а функция все равно возвращает 0 хотя должна обратится к вновь созданной временной таблице и вернуть 1

Функция парсится при первом вызове и далее как оно таблицы разрезолвила так они и останутся.
Если вам надо другое поведение - используйте EXECUTE вместо просто SELECT в хранимке.
Но тогда это будет медленнее так как теряется главный смысл хранимок - запросы не парсятся и не планируются на каждый вызов а только 1 раз.

--
Maxim Boguk
www.postgresql-consulting.ru
если бы это было так, то при первом вызове, если закомментировать только создание -- был бы 0 всегда.

но "разборы" видимо инвалидизируются, при изменении серч--паса сеанса. и производятся снова. Поэтому, если в момент разбора при первом появлении темповой директории (любого темпового объекта), -- там уже есть табличка tmp123-- то "в плане" будет именно она (хотя и не совсем).

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
begin;
create table  tmp123 (id numeric);
create table  tmp222 (id numeric);
create function gettmp123()  RETURNS numeric AS
$BODY$
declare
  idv numeric;
  begin
    select coalesce(max(id),0) into idv from tmp123;
    return idv;
  end;
$BODY$
  LANGUAGE plpgsql VOLATILE ;
--create temporary table  tmp222 (id numeric) on commit  drop;
--DROP  table  IF EXISTS tmp222 ;
do
$$
begin 
	raise notice 'Должно быть 0, результат %' , gettmp123();
--	create temporary table  tmp222 (id numeric) on commit  drop;
	raise notice 'Должно быть 0, результат %' , gettmp123();
	create temporary table  tmp123 (id numeric) on commit  drop;
	insert into tmp123 (id) values(1);
	raise notice 'Должно быть 1, результат %' , gettmp123();
	DROP  table  IF EXISTS tmp123 ;
	raise notice 'Должно быть 1, результат %' , gettmp123();
	-- не упали с ошибкой !!! => при дропе инвалидизация происходит
end;
$$;

rollback;



т.е. все эти трюки с неявными серч пасами в ф--ях я уже лет 10 как обхожу стороной.
хотя ТС формально прав -- пж тут лажает по--полной.

а вообще тема своевременной инвалидизации в пж вечна. ещё недавно [~~7.2--7.3] "дроп индекс" требовал переоткрытия сеансов.
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39205990
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

Да согласен поведение хреновое.

Надо придумать как из этого при наличии TEMP привелегий на базе security hole сообразить для частичного обхода/обмана security definer функций.

Например в варианте использования базы через pgbouncer в transaction pooling без server reset query (а это рекомендуемый режим) подсунуть чужим сессиям временную таблицу users совпадающую по имени и структуре с той где пароли хранятся (можно сделать эту временную таблицу несколько раз так чтобы наверняка в большей части активных Backend процессов эта временная таблица жила).

А дальше уже открываются интересные возможности (от просмотра случайно записанных в нее md5 которые не видны через security definer access функцию) до подсовывания левых реквизитов в эти временные таблицы чтобы залогинится где то с чужими полномочиями. Главное чтобы эта хранимка вызывалась не очень часто и тогда есть шансы что она подцепит временную таблицу с левыми данными при первой компиляции (ну или она почему то execute использует и тогда оно просто гарантированно выстрелит).

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206090
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123Alexius,

В том то и дело что в моем примере база работает совсем не так как написано в той цитате что вы привели.


Невнимательно прочитал. Действительно неочевидное поведение получается. Сделал для наглядности функцию, возвращающую имя схемы таблицы tmp123:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
begin;
create table tmp123 (id numeric);
insert into tmp123 (id) values(1);

create or replace function show_table_schema() returns text as $$
declare res text;
begin
    select (select nspname from pg_namespace where oid = (select relnamespace from pg_class where oid = tmp123.tableoid)) into res from tmp123 limit 1;
    return res;
end;
$$
  LANGUAGE plpgsql VOLATILE ;

--
create temp table tmp234(id numeric);

select show_table_schema();

create temp table tmp123(id numeric);
insert into tmp123 (id) values(1);

select show_table_schema();


--при смене search_path на public ничего не меняется, временная таблица не подхватывается
set search_path to public;

select show_table_schema();

rollback;
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206409
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123,

проблема налицо

можете пока заткнуть это таким лайф--хаком:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
begin;
create table  tmp123 (id numeric);
create table  tmp222 (id numeric);
create function reload_gettmp123() RETURNS void AS
$ff$
create OR REPLACE function gettmp123()  RETURNS numeric AS
$BODY$
declare
  idv numeric;
  begin
    select coalesce(max(id),0) into idv from tmp123;
    return idv;
  end;
$BODY$
  LANGUAGE plpgsql VOLATILE ;
$ff$
LANGUAGE sql VOLATILE ;

SELECT reload_gettmp123(); --load

do
$$
begin 
create temporary table  tmp222 (id numeric) on commit  delete rows;
 raise notice 'Должно быть 0, результат %' , gettmp123();
 create temporary table  tmp123 (id numeric) on commit  delete rows;
 PERFORM  reload_gettmp123(); --re load
 insert into tmp123 (id) values(1);
 raise notice 'Должно быть 1, результат %' , gettmp123();
end;
$$;

rollback;




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

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

но это проблема только иммутабных ф--ий
[по чесноку вызов имутабной либо должен лочить определение ф--ии до конца сеанса, либо реализация кеша должна включать в ключи версию xmin из pg_proc. второе было бы удобнее]
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206518
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

По моему куда проще как я предложил вместо:
select coalesce(max(id),0) into idv from tmp123;
написать
EXECUTE 'select coalesce(max(id),0) into idv from tmp123' INTO idv;
тогда будет требуемое автору поведение.

--
Maxim Boguk
www.postgresql-consulting.ru
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206627
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

согласен, с одним но
-- люди б.м. бьются за скорость
по крайней мере всякую маргинальщину заюзали
а для скорости лучше снизить число синтаксических разборов=>
сделать одну точечную инвалидизацию там, где пж лажает унутре
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206677
ln123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На самом деле обходной путь довольно простой в начале сессии (до вызова любой функции получающей данные) создать все временные таблицы, правда отсутствие логон триггеров осложняет эту задачу, но все равно задача решаема.

Я честно говоря писал на форум в надежде что кто-нибудь из российских разработчиков признает наличие данной проблемы и возьмется за ее решение, т.к. на самом деле бага очень неприятная когда такая ошибка случается в недрах более менее сложной системы найти причину очень сложно. У меня кстати та проблема из-за которой я начал копать, на 9.4 не проявляется, хотя мой тестовый код одинаково лажает и на 9.5 и на 9.4

Хотя судя по наличию в TODO пункта "Allow temporary tables to exist as empty by default in all sessions " да же если я напишу bug-report то на него забьют :(
...
Рейтинг: 0 / 0
Баг при работе с временными таблицами
    #39206971
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ln123,

вы так говорите, как будто это что-то плохое, как будто вы не делаете маргинальнейших ужимок, сам смысл которых сомнителен

хотите странного -- имеете право. но странным оно от этого быть не перестаёт

как макс выше писал -- сама возможность перекрыть таблицу одноимённой времянкой -- более чем сомнительна с т.з. дырок в безопасности. надо много думать -- то ли отказаться от странного в пользу защиты, то ли там дырка кажущаяся -- а фичи -- явные [странные]. и тогда надо чинить (не только при смене сеч-паса или дропе таблички инвалидизировать "планы", но и при появлении одноимённых объектов (какую--то структуру, завязанную на имена, и указывающую на разобранные тела ф-й придётся держать в памяти)).


т.ч. вы напишите репорт, не ленитесь. кому то на глаза да попадётся
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Баг при работе с временными таблицами
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]