I am dealing with two PostgreSQL installs at the same time: My local environment and the real remote server. Sadly the server has an old version (8.3.11) and my local environment is newer (9.4).
I don't have means to update the remote server at the moment, so I am converting a function that runs well in 9.4 (it uses RETURNS TABLE
) to a function that should be fine in 8.3.11 (it should use RETURNS SETOF
).
But while the local environment function works well and it gives good results, the remote one always yields no result (using the very same tables!)
So, are these two fully equivalent?
Newer function for local environment:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS TABLE (game_date date, is_home varchar, is_away varchar) AS $$
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = $1;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
END IF;
RETURN;
END
$$
LANGUAGE plpgsql;
And here the function I have modified to use SETOF
CREATE TYPE return_type AS
(game_date date,
is_home varchar,
is_away varchar);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE
_rec return_type;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = $1;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
END IF;
RETURN next _rec;
END
$$
LANGUAGE plpgsql;
It gives no error message at all, it runs ok, but it just yields no results (it always raises the exception message), so I am wondering whether there is something wrongly set up in the SETOF
query ...
Judging from the documentation, RETURN QUERY
doesn't set FOUND
in PostgreSQL 8.3. (The relevant documentation for PostgreSQL 9.1 is at http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS ; the corresponding statement does not appear in the corresponding PostgreSQL 8.3 documentation at http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS .) So your IF NOT FOUND
check isn't doing what you want.
To be honest, I'm not sure what the best way to accomplish this is in PostgreSQL 8.3. One option is to write something like this:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE _rec return_type;
has_rec boolean;
BEGIN
has_rec := false;
FOR _rec IN
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = $1
LOOP
has_rec := true;
RETURN NEXT _rec;
END LOOP;
IF NOT has_rec THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
END IF;
END
$$ LANGUAGE plpgsql;
(Disclaimer: not tested.)
PL/pgSQL does not set the special variable FOUND
for RETURN QUERY
in PostgreSQL 8.3 , yet. That was added with Postgres 8.4 .
But you still don't have to resort to more complex and expensive looping. You can use the other method GET DIAGNOSTICS _ct = ROW_COUNT;
, which is explained right next to FOUND
in the manual:
CREATE TYPE return_type AS ( ...);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS
$func$
DECLARE
_ct int;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name, p2.team_name
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = $1;
GET DIAGNOSTICS _ct = ROW_COUNT; -- number of returned rows.
IF _ct = 0 THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
END IF;
END
$func$ LANGUAGE plpgsql;
Also, your variable _rec return_type
and RETURN next _rec;
did not serve any purpose in your original version.
Now the function is equivalent. You can even use the same in Postgres 9.4.
Closely related answer:
Aside: Camel case identifiers like
are a bad idea in Postgres. Stick to legal lower case names. GetGamesOnDate
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.