Reputation: 1084
I'm trying to write a simple procedure that will work like a queue - lock records (10 minutes)
, and return those locked records.
CREATE OR REPLACE FUNCTION select_queue(
i_limit integer,
i_sessionid text)
RETURNS RECORD AS
$BODY$
declare match_ret record;
BEGIN
SELECT userid,date,description INTO match_ret FROM table
WHERE (lock_session IS NULL AND lock_date IS NULL) OR lock_date < NOW() - INTERVAL '10 MINUTE' LIMIT i_limit FOR UPDATE;
UPDATE table SET lock_session=i_sessionid, lock_date=NOW() WHERE userid=match_ret.userid;
RETURN match_ret;
END;
$BODY$
LANGUAGE plpgsql
I'm a MySQL user and things aren't working as I would expect them to. Any help will be appreciated.
Upvotes: 0
Views: 3397
Reputation: 1084
After one day with PostgresSQL, this is what i've created:
CREATE OR REPLACE FUNCTION api.get_user_photo(
IN i_limit integer,
IN i_sessionid text,
IN i_main integer,
OUT list refcursor,
OUT elapsed real,
OUT all_count integer,
OUT userids bigint[])
RETURNS record AS
$BODY$
DECLARE
_tstart timestamp with time zone;
_max_date timestamp with time zone;
_ids bigint[];
_locked integer;
BEGIN
_tstart = clock_timestamp();
_max_date = NOW() - INTERVAL '5 MINUTE';
-- check for already locked photo
SELECT count(1) INTO _locked FROM core.user_photos
WHERE lock_sessionid=i_sessionid;
IF _locked <> 0 THEN
i_limit = i_limit - _locked;
END IF;
UPDATE core.user_photos
SET lock_sessionid=i_sessionid, lock_date=NOW()
WHERE id in (
SELECT id FROM core.user_photos
WHERE (lock_sessionid IS NULL AND lock_date IS NULL AND main=i_main)
OR (lock_date < _max_date AND main=i_main)
LIMIT i_limit
);
-- Count locked records
SELECT count(1) INTO all_count
FROM core.user_photos
WHERE lock_sessionid=i_sessionid;
-- Get unique ids
SELECT array_agg(distinct userid) INTO userids
FROM core.user_photos
WHERE lock_sessionid=i_sessionid;
-- Get locked photo
OPEN list FOR
SELECT id AS moderation_id,userid,description,md5,ext,transform,main_moderation,moderation,desc_moderation
FROM core.user_photos
WHERE lock_sessionid=i_sessionid;
elapsed := EXTRACT('epoch' FROM clock_timestamp() - _tstart)::real;
RETURN;
END
$BODY$
LANGUAGE plpgsql
Upvotes: 0
Reputation: 45900
using RETURNS RECORD
(unknown record) is not practical. Use a OUT
variables instead. Next - you modify i_limit
rows, but you return only one value. Maybe you want to return all.:
CREATE OR REPLACE FUNCTION select_queue(i_limit int,i_sessionid text,
OUT o_userid int, OUT o_date, o_desc text)
RETURNS SETOF RECORD AS $$
DECLARE _row_id int;
BEGIN
FOR _row_id, o_userid, o_date, o_desc IN
SELECT row_id, userid,date,description
FROM table
WHERE (lock_session IS NULL AND lock_date IS NULL)
OR lock_date < NOW() - INTERVAL '10 MINUTE'
LIMIT i_limit FOR UPDATE
LOOP
UPDATE table SET lock_session=i_sessionid, lock_date=NOW()
WHERE row_id = _row_id;
RETURN NEXT;
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;
You can call this function with SELECT
:
SELECT * FROM select_queue(10, 'safdsdfsfds');
Upvotes: 1