PostgreSQL: функция обновления возвращает логическое значение

Является ли функция ниже хорошей?

CREATE FUNCTION password_set(bigint, char) RETURNS boolean AS $$
   UPDATE users SET password = $2 WHERE id = $1 RETURNING TRUE;
$$ LANGUAGE SQL;

Он возвращает TRUE, когда UPDATE устанавливает password, и NULL (вместо FALSE), когда UPDATE не устанавливает password.

Я думаю, что это будет работать для всех намерений и целей, но вы думаете, что это нормально?

Если нет, как бы вы изменили функцию, чтобы она возвращала FALSE (вместо NULL), если UPDATE не устанавливает password?


person ma11hew28    schedule 14.04.2014    source источник
comment
Является ли id УНИКАЛЬНЫМ или может быть несколько затронутых строк? Кроме того, ваша версия Postgres?   -  person Erwin Brandstetter    schedule 15.04.2014


Ответы (2)


Прежде всего, вы не хотите использовать тип данных char. Это синоним character(1) и совершенно неправильно для передачи текста «пароль». Любая строка будет усечена до первого символа. Согласно документации:

Обозначения varchar(n) и char(n) являются псевдонимами для character varying(n) и character(n) соответственно. character без спецификатора длины эквивалентно character(1).

Далее, что не так с функцией, возвращающей TRUE или NULL?

Если вам действительно нужно вернуть TRUE/FALSE, ваша идея с использованием CTE, изменяющий данные, работает. Однако код вводит в заблуждение. Вы делаете вид, что TRUE в финальном SELECT имеет значение, но это не так:

CREATE FUNCTION password_set(bigint, text)
  RETURNS boolean AS
$func$
   WITH u AS (UPDATE users SET password = $2 WHERE id = $1 RETURNING 1)
   SELECT EXISTS (SELECT * FROM u)
$func$ LANGUAGE sql;

EXISTS учитывает, только если строка вернулся. Не имеет значения, пишете ли вы NULL, или FALSE, или TRUE, или *, или 'foo', или что-то еще. Функция, возвращающая TRUE, только говорит нам, что UPDATE вернула одну или несколько строк.

Альтернативой может быть функция PL/pgSQL, использующая специальная переменная FOUND:

CREATE OR REPLACE FUNCTION password_set(bigint, text)
  RETURNS boolean AS
$func$
BEGIN
   UPDATE users SET password = $2 WHERE id = $1;

   IF FOUND THEN
      RETURN TRUE;
   ELSE
      RETURN FALSE;
   END IF;
END
$func$ LANGUAGE plpgsql;

Чуть быстрее и, наверное, понятнее. Или, как прокомментировал @pozs, поскольку мы возвращаемся boolean в любом случае в данном случае просто:

   RETURN FOUND;
person Erwin Brandstetter    schedule 15.04.2014
comment
Возможно, RETURN FOUND будет более понятным, так как FOUND уже является BOOLEAN переменной. - person pozs; 15.04.2014

Если просто добавить SETOF перед boolean, то вместо 1 строки с ячейкой NULL функция вернет 0 строк.

В противном случае вы можете попробовать:

CREATE FUNCTION password_set(bigint, char) RETURNS boolean AS $$
   WITH u AS (UPDATE users SET password = $2 WHERE id = $1 RETURNING TRUE)
   SELECT EXISTS (SELECT TRUE FROM u);
$$ LANGUAGE SQL;
person ma11hew28    schedule 14.04.2014
comment
В вашем образце нет SETOF. - person alphadogg; 11.06.2015