Забытый оператор присваивания "=" и банальное ": =" - PullRequest
41 голосов
/ 18 сентября 2011

Документация для 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-like "x = x + y". Это критика происходит несмотря на то, что C еще не был изобретен.

1972 - Деннис Ритчи изобретает мощное оружие, которое стреляет вперед и назад одновременно. Не удовлетворен количеством смертей и постоянные увечья от этого изобретения он изобретает С и Unix.

Ответы [ 4 ]

41 голосов
/ 04 октября 2011

В анализаторе PL / PgSQL оператор присваивания определяется как

assign_operator : '='
                | COLON_EQUALS
                ;

Это устаревшая функция, присутствующая в исходном коде с 1998 года, когда она была представлена ​​- как мы видим в PostgreSQL Git repo .

Начиная с версии 9.4 это официально документировано .

Эта особенность - наличие двух операторов для одной и той же вещи - была поднята в списке пользователей pgsql, и некоторые люди просили ее удалить, но она по-прежнему хранится в ядре, потому что на нее опирается справедливый корпус унаследованного кода.

Смотрите это сообщение от Тома Лейна (основного разработчика Pg) .

Итак, чтобы ответить на ваши вопросы прямо:

Разве я не нашел в документах какой-либо раздел, в котором упоминается и / или объясняется это?

Вы не нашли его, потому что он был недокументирован, что исправлено в версии 9.4.

Есть ли какие-либо известные последствия использования = вместо: =.

Нет никаких побочных последствий использования = , но вы должны использовать : = для назначения, чтобы сделать ваш код более читабельным и (как побочный эффект) более совместимым с PL /SQL.

Обновление: в редких случаях возможны побочные эффекты (см. Ответ Эрвина)


ОБНОВЛЕНИЕ: ответ обновлен благодаря вкладу Дэниела, Сэнди и других.

28 голосов
/ 25 февраля 2014

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);

Поскольку = является оператором равенства SQL, Postgres интерпретирует is_true = TRUE как выражение SQL в контексте оператора вызова и пытаетсяоценить его перед передачей результата как безымянный позиционный параметр .Ищет идентификатор is_true во внешней области видимости.Если это не может быть найдено:

ERROR:  column "is_true" does not exist

Это счастливый случай, и, к счастью, также общий.

Когда is_true может находится во внешней области видимости (и типы данных совместимы), is_true = TRUE является допустимым выражением с результатом boolean, который принимается функцией.Ошибка не возникает.Понятно, что это намерение программиста использовать SQL оператор равенства = ...

Этот SQL Fiddle демонстрирует эффект.

Очень трудно отлаживать, если вы не знаете о различии между = и :=.
Всегда используйте правильный оператор.


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 =>.:= все еще поддерживается для обратной совместимости.Но используйте стандартный оператор в новом коде, который не нужно запускать на очень старых версиях.

Это относится к присвоению именованных параметров в вызовах функций (область действия SQL), а не к оператору присваивания := в коде plpgsql, который остается неизменным.

2 голосов
/ 22 сентября 2011

Частичный ответ на мой вопрос:

Раздел PL / pgSQL Получение статуса результата показывает два примера с использованием специального синтаксиса:

GET DIAGNOSTICS variable = item [ , ... ]; 
GET DIAGNOSTICS integer_var = ROW_COUNT;

Я пробовал оба := и =, и они оба работают.

Но GET DIAGNOSTICS - это специальный синтаксис, поэтому можно утверждать, что это также не обычная операция присваивания PL / pgSQL.

1 голос
/ 22 сентября 2011

Чтение документации Postgresql 9:

На этой странице в качестве оператора присваивания указана "=" в таблице приоритетов операторов.

Но как ни странно эта страница (документация оператора присваивания) не упоминает об этом.

...