How can I lock rows FOR UPDATE without returning data over the connection? I want to do something like this:

begin;
select * from foos where owner_id=123 and unread=true order by id for update;
update foos set unread=false where owner_id=123 and unread=true;
commit;


The goal is to avoid deadlock when two processes execute the UPDATE simultaneously. Problem described more here: Why am I getting a deadlock for a single UPDATE query?

In the statement where I acquire the lock, I don't need any info about the rows. I just want to lock those particular rows. Is there a way to do this (elegant or hacky) which tells postgres to not do any of the work of actually giving me the data?
About the goal to avoid deadlocks: see my answer to your related question:


Why am I getting a deadlock for a single UPDATE query?


About the question in the title:

You can use an empty SELECT list with a locking clause:

SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE;


Still locks all selected rows, but does not return any data. Still returns empty rows, though, so you still get a row count like usual.

Or, inspired by a_horse's comment:

SELECT count(*) AS locked_rows
FROM  (SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE) sub;


This way you get a single result row with the number of locked rows. (You can abort in case of 0 rows.) Rows are locked all the same. The SELECT list in the subquery can still be just empty (shortest, cheapest).

Aside: and unread=true is just a noisy, less efficient way of saying AND unread.

If unlocked can be NULL, consider to use unread IS NOT true in both statements.