Мы выполняем этот запрос в Postgres 9.6.10 в управляемой облачной БД Google:
WITH update AS
(UPDATE cart SET loyalty = loyalty || jsonb_insert('{}', '{coupon}', loyalty#>'{scan_coupon}' || $1) WHERE id =
(SELECT id FROM cart WHERE id = $2 AND status = $3 and item_version = $4 FOR UPDATE) returning *)
SELECT * FROM updated
cart
- это таблица, в которой id
является первичным ключом. loyalty
- это столбец jsonb, а item_version
- функция, которая увеличивает некоторые операции, но ожидается, что до обновления item_version
произойдет несколько обновлений. status
является перечисляемым типом.
При очень параллельных обновлениях мы редко получаем следующую ошибку:
Cardinality_violation, file: "nodeSubplan.c", line: "1127", message: "more than one row returned by a subquery used as an expression", pg_code: "21000", routine: "ExecSetParamPlan", severity: "ERROR", unknown: "ERROR"
Я подтвердил, что $2
на самом деле является целым числом и указывает на существующую строку, а поскольку id
является первичным ключом, я не вижу, как это могло бы когда-либо возвращать более одной строки.
Является ли SELECT FOR UPDATE
ошибочным запросом? Как этот запрос может вернуть более одной строки, если id
является первичным ключом.