diff --git a/CHANGELOG.md b/CHANGELOG.md index 249ea21d2..d29994422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #1070, Fix HTTP status responses for upserts - @taimoorzaeem + `PUT` returns `201` instead of `200` when rows are inserted + `POST` with `Prefer: resolution=merge-duplicates` returns `200` instead of `201` when no rows are inserted + - #3019, Transaction-Scoped Settings are now shown clearly in the Postgres logs - @laurenceisla + + Shows `set_config('pgrst.setting_name', $1)` instead of `setconfig($1, $2)` + + Does not apply to role settings and `app.settings.*` ### Changed diff --git a/src/PostgREST/Query.hs b/src/PostgREST/Query.hs index 8058cb81a..16ed0c2a9 100644 --- a/src/PostgREST/Query.hs +++ b/src/PostgREST/Query.hs @@ -47,8 +47,9 @@ import PostgREST.Plan (CallReadPlan (..), import PostgREST.Plan.MutatePlan (MutatePlan (..)) import PostgREST.Query.SqlFragment (escapeIdentList, fromQi, intercalateSnippet, - setConfigLocal, - setConfigLocalJson) + setConfigWithConstantName, + setConfigWithConstantNameJSON, + setConfigWithDynamicName) import PostgREST.Query.Statements (ResultSet (..)) import PostgREST.SchemaCache (SchemaCache (..)) import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..), @@ -239,17 +240,17 @@ setPgLocals AppConfig{..} claims role roleSettings req = lift $ ("select " <> intercalateSnippet ", " (searchPathSql : roleSql ++ roleSettingsSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql)) HD.noResult configDbPreparedStatements where - methodSql = setConfigLocal ("request.method", iMethod req) - pathSql = setConfigLocal ("request.path", iPath req) - headersSql = setConfigLocalJson "request.headers" (iHeaders req) - cookiesSql = setConfigLocalJson "request.cookies" (iCookies req) - claimsSql = [setConfigLocal ("request.jwt.claims", LBS.toStrict $ JSON.encode claims)] - roleSql = [setConfigLocal ("role", role)] - roleSettingsSql = setConfigLocal <$> roleSettings - appSettingsSql = setConfigLocal <$> (join bimap toUtf8 <$> configAppSettings) + methodSql = setConfigWithConstantName ("request.method", iMethod req) + pathSql = setConfigWithConstantName ("request.path", iPath req) + headersSql = setConfigWithConstantNameJSON "request.headers" (iHeaders req) + cookiesSql = setConfigWithConstantNameJSON "request.cookies" (iCookies req) + claimsSql = [setConfigWithConstantName ("request.jwt.claims", LBS.toStrict $ JSON.encode claims)] + roleSql = [setConfigWithConstantName ("role", role)] + roleSettingsSql = setConfigWithDynamicName <$> roleSettings + appSettingsSql = setConfigWithDynamicName <$> (join bimap toUtf8 <$> configAppSettings) searchPathSql = let schemas = escapeIdentList (iSchema req : configDbExtraSearchPath) in - setConfigLocal ("search_path", schemas) + setConfigWithConstantName ("search_path", schemas) -- | Runs the pre-request function. runPreReq :: AppConfig -> DbHandler () diff --git a/src/PostgREST/Query/SqlFragment.hs b/src/PostgREST/Query/SqlFragment.hs index 2706cf1ef..94cafa956 100644 --- a/src/PostgREST/Query/SqlFragment.hs +++ b/src/PostgREST/Query/SqlFragment.hs @@ -33,8 +33,9 @@ module PostgREST.Query.SqlFragment , unknownEncoder , intercalateSnippet , explainF - , setConfigLocal - , setConfigLocalJson + , setConfigWithConstantName + , setConfigWithDynamicName + , setConfigWithConstantNameJSON , escapeIdent , escapeIdentList ) where @@ -484,14 +485,23 @@ explainF fmt opts snip = fmtPlanFmt PlanJSON = "FORMAT JSON" -- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL. -setConfigLocal :: (ByteString, ByteString) -> SQL.Snippet +setConfigLocal :: (SQL.Snippet, ByteString) -> SQL.Snippet setConfigLocal (k, v) = - "set_config(" <> unknownEncoder k <> ", " <> unknownEncoder v <> ", true)" + "set_config(" <> k <> ", " <> unknownEncoder v <> ", true)" + +-- | For when the settings are hardcoded and not parameterized +setConfigWithConstantName :: (SQL.Snippet, ByteString) -> SQL.Snippet +setConfigWithConstantName (k, v) = setConfigLocal ("'" <> k <> "'", v) + +-- | For when the settings need to be parameterized +setConfigWithDynamicName :: (ByteString, ByteString) -> SQL.Snippet +setConfigWithDynamicName (k, v) = + setConfigLocal (unknownEncoder k, v) -- | Starting from PostgreSQL v14, some characters are not allowed for config names (mostly affecting headers with "-"). -- | A JSON format string is used to avoid this problem. See https://github.com/PostgREST/postgrest/issues/1857 -setConfigLocalJson :: ByteString -> [(ByteString, ByteString)] -> [SQL.Snippet] -setConfigLocalJson prefix keyVals = [setConfigLocal (prefix, gucJsonVal keyVals)] +setConfigWithConstantNameJSON :: SQL.Snippet -> [(ByteString, ByteString)] -> [SQL.Snippet] +setConfigWithConstantNameJSON prefix keyVals = [setConfigWithConstantName (prefix, gucJsonVal keyVals)] where gucJsonVal :: [(ByteString, ByteString)] -> ByteString gucJsonVal = LBS.toStrict . JSON.encode . HM.fromList . arrayByteStringToText