Я создал функцию, которая теоретически должна возвращать true при успешной смене пароля и false - наоборот.

Функция определяется как:

CREATE OR REPLACE FUNCTION database."changePassword"(username character varying, newpassword character varying, oldpassword character varying) RETURNS boolean AS
$BODY$
UPDATE database.users SET hash = MD5($2) WHERE (username = $1 AND hash = MD5($3));
SELECT EXISTS(SELECT 1 FROM datsabase.users WHERE username = $1 AND hash = MD5($2))
$BODY$
LANGUAGE sql VOLATILE NOT LEAKPROOF
COST 100;

Проблема в том, что когда я вызываю такую ​​функцию, как SELECT database."changePassword"('usrNm', 'newPassword', 'oldOne');, сначала я получаю истинное значение, как и ожидалось, и значение в базе данных изменяется.

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

Я делаю что-то неправильно?

Версия PostgreSQL - 9.3.1.
Я вызвал функцию из интерфейса pgAdmin и из PHP-скрипта, та же проблема.

0
Denis Kralj 24 Дек 2013 в 01:45

2 ответа

Лучший ответ

Если вы хотите узнать, был ли изменен какой-либо пароль, вы можете просто вернуть специальную переменную FOUND в такой функции plpgsql (упрощенная с вводом из @Pavel):

CREATE OR REPLACE FUNCTION database."changePassword"(
    username character varying
   ,newpassword character varying
   ,oldpassword character varying
) RETURNS boolean AS
$func$
BEGIN

UPDATE database.users
SET    hash = MD5($2)
WHERE  username = $1
AND    hash = MD5($3);

RETURN FOUND;

END 
$func$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;

Или, что проще, используйте предложение RETURNING. Это также будет работать с простой функцией sql:

CREATE OR REPLACE FUNCTION database."changePassword"(
    username character varying
   ,newpassword character varying
   ,oldpassword character varying
) RETURNS boolean AS
$func$

UPDATE database.users
SET    hash = MD5($2)
WHERE  username = $1
AND    hash = MD5($3)
RETURNING TRUE;

$func$
LANGUAGE sql VOLATILE NOT LEAKPROOF;

Если ни одна строка не обновляется, ничего не возвращается. В противном случае вы получите TRUE.

2
Erwin Brandstetter 23 Дек 2013 в 22:40

Возвращаемое значение функции является результатом оператора SELECT. Результат верен, когда сохраненный хэш пользователя совпадает с хешем второго параметра (newpassword). Когда пароль изменяется на новый пароль, эта проверка всегда проходит успешно, и функция возвращает истину для того же параметра, несмотря на то, что оператор обновления не обновляет ни одну строку после второго вызова. Вам следует изменить свою логику и вместо того, чтобы запрашивать подходящего пользователя и пароль, проверять, обновляется ли какая-либо строка или нет.

1
Mohammad Dehghan 23 Дек 2013 в 22:04