#postgresql #random
Вопрос:
У меня есть этот код, который предназначен для создания функции Lorem Ipsum для заполнения данных в хранилище данных. Я намеренно сократил количество слов для простоты.
create or replace function lipsum_word (
_useInitCap boolean default false
)
returns varchar
immutable language plpgsql as $
declare
_word varchar;
_words constant varchar[] = '{"abbas", "abbatia", "abbatis", "abduco", "abeo", "volatilis:", "volens", "volo", "volpes", "voltur", "volturius", "volubilis", "volubiliter", "voluntarius", "voluntas", "volup", "vulticulus", "vultuosus", "vultur", "vulturius", "vultus", "vulva", "werumensium", "winged", "wreck", "xiphias"}';
begin
_word = _words[random() * array_length(_words, 1)];
if _useInitCap then
_word = initcap(_word);
end if;
return _word;
end
$;
create or replace function lipsum_sentence (
_wordCount int default 5,
_useInitCap boolean default false,
_useFinalDot boolean default true
)
returns varchar
immutable language plpgsql as $
declare
_sentence varchar;
begin
_sentence = lipsum_word();
if _useInitCap then
_sentence = initcap(_sentence);
end if;
for i in 1 .. _wordCount - 1 loop
_sentence = _sentence || ' ' || lipsum_word();
end loop;
if _useFinalDot then
_sentence = _sentence || '.';
end if;
return _sentence;
end
$;
Код действителен, но lipsum_word()
вызов внутри for-in
цикла работает неправильно, так как возвращаемые значения примерно такие
select lipsum_word();
select lipsum_word('true');
select lipsum_sentence();
select lipsum_sentence(8, false, true);
lipsum_word
-------------
volturius
(1 row)
lipsum_word
-------------
Vultus
(1 row)
lipsum_word
-------------
abbatis
(1 row)
lipsum_sentence
------------------------------------------
werumensium winged winged winged winged.
(1 row)
lipsum_sentence
-----------------------------------------------------------------------------
werumensium winged winged winged winged winged winged winged winged winged.
(1 row)
lipsum_sentence
--------------------------------------------------------
Werumensium winged winged winged winged winged winged.
(1 row)
lipsum_sentence
---------------------------------------------------------------
werumensium winged winged winged winged winged winged winged.
(1 row)
slim:watson-dw-v1.0.15 coterobarros$ ./runlipsum
Password for user postgres:
lipsum_word
-------------
abbatia
(1 row)
lipsum_word
-------------
Vulturius
(1 row)
lipsum_sentence
---------------------------------------------------------
winged voluntarius voluntarius voluntarius voluntarius.
(1 row)
lipsum_sentence
---------------------------------------------------------------------------------------------
winged voluntarius voluntarius voluntarius voluntarius voluntarius voluntarius voluntarius.
(1 row)
Что касается запасных вызовов lorem_word()
, то функция работает нормально. Я также протестировал raise notice 'random'
внутреннюю lorem_word
функцию, чтобы узнать, что цикл не вызывает ее только один раз.
Есть идеи по поводу такого поведения?
Ответ №1:
Объявите lipsum_word
как VOLATILE
вместо IMMUTABLE
. Смотрите документы о волатильности функций; ни STABLE
то, ни IMMUTABLE
другое не будет работать для функций, которые могут законно возвращать разные результаты для одинаковых вызовов.
Комментарии:
1. Поэтому, что интересно, для неизменяемой функции компилятор избегает ее вызова и сохраняет последнее значение для идентичного набора параметров.