Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unnecessary UPDATE on PK col on upsert #2446

Open
steve-chavez opened this issue Aug 24, 2022 · 2 comments · May be fixed by #2535
Open

Unnecessary UPDATE on PK col on upsert #2446

steve-chavez opened this issue Aug 24, 2022 · 2 comments · May be fixed by #2535
Labels

Comments

@steve-chavez
Copy link
Member

From https://gitter.im/begriffs/postgrest?at=6302565ef4d7a323de64aa37

I have found that upserting {id: 42, comment: 'foo'} into

create table mytable (
  id bigserial primary key,
  comment text);

generates this following [pseudo]query

insert into mytable (id, comment) values (request.id, request.comment)
on conflict (id) do update id=excluded.id, comment=excluded.comment;

the do update id=excluded.id part is causing issues for me as i wanted to disallow updating the id once inserted so i through simple

GRANT select, insert(id, comment), update(comment) on mytable to api

would work.
With the above permissions and set up i can do INSERT followed by UPDATE as expected, but it turns out that i am getting 403 for upsert.

I tend to think this is a bug, as there is no real reason to include the do update id=excluded.id if the id is the default constraint. Or am i missing something?

@steve-chavez
Copy link
Member Author

This should be a matter of removing the onConflict [FieldName]

data MutateQuery
= Insert
{ in_ :: QualifiedIdentifier
, insCols :: S.Set FieldName
, insBody :: Maybe LBS.ByteString
, onConflict :: Maybe (PreferResolution, [FieldName])
, where_ :: [LogicTree]
, returning :: [FieldName]
}

From the EXCLUDED attributes here

mutateRequestToQuery :: MutateRequest -> SQL.Snippet
mutateRequestToQuery (Insert mainQi iCols body onConflct putConditions returnings) =
"WITH " <> normalizedBody body <> " " <>
"INSERT INTO " <> SQL.sql (fromQi mainQi) <> SQL.sql (if S.null iCols then " " else "(" <> cols <> ") ") <>
"SELECT " <> SQL.sql cols <> " " <>
SQL.sql ("FROM json_populate_recordset (null::" <> fromQi mainQi <> ", " <> selectBody <> ") _ ") <>
-- Only used for PUT
(if null putConditions then mempty else "WHERE " <> intercalateSnippet " AND " (pgFmtLogicTree (QualifiedIdentifier mempty "_") <$> putConditions)) <>
SQL.sql (BS.unwords [
maybe "" (\(oncDo, oncCols) ->
if null oncCols then
mempty
else
"ON CONFLICT(" <> BS.intercalate ", " (pgFmtIdent <$> oncCols) <> ") " <> case oncDo of
IgnoreDuplicates ->
"DO NOTHING"
MergeDuplicates ->
if S.null iCols
then "DO NOTHING"
else "DO UPDATE SET " <> BS.intercalate ", " (pgFmtIdent <> const " = EXCLUDED." <> pgFmtIdent <$> S.toList iCols)
) onConflct,
returningF mainQi returnings
])
where
cols = BS.intercalate ", " $ pgFmtIdent <$> S.toList iCols

@steve-chavez steve-chavez added the difficulty: beginner Pure Haskell task label Aug 26, 2022
@steve-chavez steve-chavez removed the difficulty: beginner Pure Haskell task label Oct 26, 2022
@steve-chavez
Copy link
Member Author

This also seems related to #1732

If we had the UPDATE(col1,col2) privileges on the schema cache, then we could run UPDATE SET only on the columns the role has privileges to.

That would solve this issue and with this we could also stop processing the JSON in Haskell code and only do it in SQL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

1 participant