Забытый оператор присваивания "=" и банальное ":="
Документация для PL/pgSQL гласит, что объявление и присвоение переменных выполняется с :=
, Но простой, короткий и современный (см. Сноску) =
Кажется, работает как ожидалось:
CREATE OR REPLACE FUNCTION foo() RETURNS int AS $$
DECLARE
i int;
BEGIN
i = 0;
WHILE NOT i = 25 LOOP
i = i + 1;
i = i * i;
END LOOP;
RETURN i;
END;
$$ LANGUAGE plpgsql;
> SELECT foo();
25
Обратите внимание, что Pl/pgSQL может четко различать присваивание и сравнение, как показано в строке
WHILE NOT i = 25 LOOP
Итак, вопросы:
- Разве я не нашел в документах какой-либо раздел, в котором упоминается и / или объясняется это?
- Есть ли какие-либо известные последствия использования
=
вместо:=
?
Изменить / Сноска:
Пожалуйста, возьмите "более современную" часть с подмигиванием, как в "Краткой, неполной и в основном неправильной истории языков программирования":
1970 - Никлаус Вирт создает Паскаль, процедурный язык. Критики немедленно осуждают Паскаль, потому что он использует синтаксис "x:= x + y" вместо более знакомого C-подобного "x = x + y". Эта критика происходит несмотря на то, что C еще не был изобретен.
1972 - Деннис Ритчи изобрел мощное оружие, которое стреляет и вперед, и назад одновременно. Не удовлетворенный количеством смертей и увечий от этого изобретения, он изобретает C и Unix.
4 ответа
В анализаторе PL/PgSQL оператор присваивания определяется как
assign_operator : '='
| COLON_EQUALS
;
Это устаревшая функция, присутствующая в исходном коде с 1998 года, когда он был представлен - как мы видим в репозитории PostgreSQL Git.
Начиная с версии 9.4, это официально задокументировано.
Эта особенность - наличия двух операторов для одной и той же вещи - была поднята в списке пользователей pgsql, и некоторые люди просили ее удалить, но она по-прежнему сохраняется в ядре, потому что на нее опирается справедливый корпус унаследованного кода.
Смотрите это сообщение от Тома Лейна (основной разработчик Pg).
Итак, чтобы ответить на ваши вопросы прямо:
Разве я не нашел в документах какой-либо раздел, в котором упоминается и / или объясняется это?
Вы не нашли его, потому что он был недокументирован, что исправлено в версии 9.4.
Есть ли какие-либо известные последствия использования = вместо:=.
Побочных последствий использования = нет, но вы должны использовать : = для присваивания, чтобы сделать ваш код более читабельным и (как побочный эффект) более совместимым с PL/SQL.
Обновление: в редких случаях возможны побочные эффекты (см. Ответ Эрвина)
ОБНОВЛЕНИЕ: ответ обновлен благодаря вкладу Дэниела, Сэнди и других.
Q1
Наконец, это было добавлено в официальную документацию с Postgres 9.4:
Присвоение значения переменной PL/pgSQL записывается так:
variable { := | = } expression;
[...] Равен (
=
) можно использовать вместо PL/SQL-совместимого:=
,
Q2
Есть ли какие-либо известные последствия использования
=
вместо:=
?
Да, у меня был случай с серьезными последствиями: вызов функции с именованными параметрами - это связано, но не совсем то же самое.
Строго говоря, различие в этом случае сделано в коде SQL. Но это академическое отличие от ничего не подозревающего программиста. 1
Рассмотрим функцию:
CREATE FUNCTION f_oracle(is_true boolean = TRUE) -- correct use of "="
RETURNS text AS
$func$
SELECT CASE $1
WHEN TRUE THEN 'That''s true.'
WHEN FALSE THEN 'That''s false.'
ELSE 'How should I know?'
END
$func$ LANGUAGE sql;
В сторону: обратите внимание на правильное использование =
в определении функции. Это часть CREATE FUNCTION
синтаксис - в стиле присваивания SQL. 2
Вызов функции с именованной нотацией:
SELECT * FROM f_oracle(is_true := TRUE);
Postgres идентифицирует :=
как параметризация и все хорошо. Однако:
SELECT * FROM f_oracle(is_true = TRUE);
поскольку =
Postgres интерпретирует оператор равенства SQL is_true = TRUE
как выражение SQL в контексте вызывающего оператора и пытается оценить его перед передачей результата в качестве безымянного позиционного параметра. Ищет идентификатор is_true
во внешнем объеме. Если это не может быть найдено:
ERROR: column "is_true" does not exist
Это счастливый случай и, к счастью, тоже обычный.
когда is_true
можно найти во внешней области видимости (и типы данных совместимы), is_true = TRUE
является допустимым выражением с boolean
результат, который принимается функцией. Ошибка не возникает. Понятно, что это намерение программиста использовать оператор равенства SQL =
...
Эта скрипта SQL демонстрирует эффект.
Очень трудно отлаживать, если вы не знаете о разнице между =
а также :=
,
Всегда используйте правильный оператор.
1 При использовании именованных обозначений в вызовах функций, только :=
является правильным оператором присваивания. Это относится к функциям всех языков, не только PL/pgSQL, вплоть до pg 9.4. Увидеть ниже.
2 можно использовать =
(или же DEFAULT
) определить значения по умолчанию для параметров функции. Это никак не связано с проблемой. Это просто замечательно близко к неправильному варианту использования.
Postgres 9.0 - 9.4: переход от :=
в =>
Стандарт SQL для присвоения именованных параметров функции =>
(и Oracle PL / SQL использует его. Postgres не может сделать то же самое, так как оператор ранее не был зарезервирован, поэтому он использует оператор присваивания PL/pgSQL :=
вместо. С выпуском Postgres 9.0 использование =>
для других целей не рекомендуется. За заметки о выпуске:
Не рекомендуется использовать => в качестве имени оператора (Роберт Хаас)
Будущие версии PostgreSQL, вероятно, будут полностью отклонять это имя оператора, чтобы поддерживать стандартную запись SQL для параметров именованных функций. На данный момент это все еще разрешено, но при определении такого оператора выдается предупреждение.
Если вы должны использовать =>
для чего-то еще, прекратите и воздержитесь. Это сломается в будущем.
Postgres 9.5: использование =>
сейчас
Начиная с этого выпуска, стандартный оператор SQL =>
используется. :=
все еще поддерживается для обратной совместимости. Но используйте стандартный оператор в новом коде, который не нужно запускать на очень старых версиях.
- Документировано в руководстве, глава Использование именованных обозначений.
- Вот коммит с объяснением в GIT.
Это относится к присвоению именованных параметров в вызовах функций (область SQL), а не к оператору присваивания :=
в коде plpgsql, который остается неизменным.
Частичный ответ на мой собственный вопрос:
В разделе PL/pgSQL Получение статуса результата показаны два примера с использованием специального синтаксиса:
GET DIAGNOSTICS variable = item [ , ... ];
GET DIAGNOSTICS integer_var = ROW_COUNT;
Я пробовал оба :=
а также =
и они работают оба.
Но GET DIAGNOSTICS
Это специальный синтаксис, поэтому можно утверждать, что это также не обычная операция присваивания PL/pgSQL.
Чтение документации Postgresql 9:
На этой странице "=" указан как оператор присваивания в таблице приоритета операторов.
Но странно, что эта страница (документация оператора присваивания) не упоминает об этом.