Re: [SQL] Are PL/pgSQL calls atomic?
От | Mark Wright |
---|---|
Тема | Re: [SQL] Are PL/pgSQL calls atomic? |
Дата | |
Msg-id | 002501beadd0$0bab96b0$c62812ac@markw_compaq обсуждение исходный текст |
Список | pgsql-sql |
Jan Wieck <wieck@debis.com> wrote: |Mark Wright asked: | |> |> If I call a PL/pgSQL function, and another client makes the same call, does |> the second client have to wait for the first to complete execution before it |> begins? If not, is there some sort of mechanism I can use to prevent more |> than one call to a function from happening at the same time (something like |> a mutex in Win32). |> |> I need to select a row and then mark it as unavailable for other clients to |> use. The table looks like: |> create table xyz (id serial, status char default 'N', ...); |> |> My function finds a row by doing: |> select id into my_id_variable from xyz where id |> = (select min(id) from xyz where status = 'N'); |> |> and then marks that row as unavailable by setting status: |> update xyz set status = 'Y' where id = my_id_variable; |> |> Obviously, if a second client calls this function before the UPDATE takes |> place, it will pick up the same row as the first client, causing rending of |> hair and gnashing of teeth. |> |> How do I prevent this? [very helpful discussion deleted] | | What you could do (if the number of rows with status = 'N' | isn't high) is the following: | | CREATE FUNCTION my_func .... AS ' | DECLARE | xyz_rec RECORD; | BEGIN | FOR xyz_rec IN SELECT * FROM xyz WHERE status = ''N'' | ORDER BY id FOR UPDATE OF xyz | LOOP | -- If more changes in xyz are to be made than just setting | -- status to Y, do them all in one UPDATE. The record is | -- locked now and the lock will release only when our entire | -- transaction commits or rolls back - not when we update it. | | UPDATE xyz SET status = ''Y'' WHERE id = xyz_rec.id; | ... | | -- Now we return from inside the loop at the first | -- row processed. This ensures we will process one | -- row at max per call. | RETURN _whatever_my_func_returns_; | END LOOP; | | -- If we reach here, we did not find any row (left) with | -- status N. Hmmm - is this an error or not? | | RAISE ERROR ''no (more) xyz rows with status N found''; | END;' LANGUAGE 'plpgsql'; | | | Why it's important that the number of rows having status = | 'N' isn't very big is because at the FOR xyz_rec IN time all | of them are fetched into memory, even if the loop will break | at the first one got. Any off-the-cuff estimates for what 'too many' is? I would have anywhere from 1 to 20 sessions executing the function, the number of rows should be less than 10,000, and I'll be running this on a small to mid-range Pentium linux box. --- Mark Wright mwright@pro-ns.net mark_wright@datacard.com
В списке pgsql-sql по дате отправления: