diff --git a/CHANGELOG.md b/CHANGELOG.md index a8248ca7b..f3647e2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #1242, Fix embedding a view having a select in a where - @steve-chavez - #1238, Fix PostgreSQL to OpenAPI type mappings for numeric and character types - @fpusch - #1265, Fix query generated on bulk upsert with an empty array - @qu4tro +- #1273, Fix RPC ignoring unknown arguments by default - @steve-chavez ## [5.2.0] - 2018-12-12 diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index ce42322fe..b8427585d 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -282,9 +282,8 @@ app dbStructure proc cols conf apiRequest = Left errorResponse -> return errorResponse Right ((q, cq), bField) -> do let singular = contentType == CTSingularJSON - specifiedPgArgs = filter ((`S.member` cols) . pgaName) $ maybe [] pdArgs proc row <- H.statement (toS $ pjRaw pJson) $ - callProc qi specifiedPgArgs returnsScalar q cq shouldCount + callProc qi (specifiedProcArgs cols proc) returnsScalar q cq shouldCount singular (iPreferSingleObjectParameter apiRequest) (contentType == CTTextCSV) (contentType == CTOctetStream) bField diff --git a/src/PostgREST/Types.hs b/src/PostgREST/Types.hs index fa4ccd205..a9a24033a 100644 --- a/src/PostgREST/Types.hs +++ b/src/PostgREST/Types.hs @@ -111,6 +111,17 @@ findProc qi payloadKeys paramsAsSingleObject allProcs = else payloadKeys `S.isSubsetOf` S.fromList (pgaName <$> pdArgs x)) ) <$> procs +{-| + Search the procedure parameters by matching them with the specified keys. + If the key doesn't match a parameter, a parameter with a default type "text" is assumed. +-} +specifiedProcArgs :: S.Set FieldName -> Maybe ProcDescription -> [PgArg] +specifiedProcArgs keys proc = + let + args = maybe [] pdArgs proc + in + (\k -> fromMaybe (PgArg k "text" True) (find ((==) k . pgaName) args)) <$> S.toList keys + type Schema = Text type TableName = Text type SqlQuery = Text @@ -378,7 +389,10 @@ instance Ord PgVersion where -- | Tells the minimum PostgreSQL version required by this version of PostgREST minimumPgVersion :: PgVersion -minimumPgVersion = PgVersion 90400 "9.4" +minimumPgVersion = pgVersion94 + +pgVersion94 :: PgVersion +pgVersion94 = PgVersion 90400 "9.4" pgVersion95 :: PgVersion pgVersion95 = PgVersion 90500 "9.5" diff --git a/test/Feature/RpcSpec.hs b/test/Feature/RpcSpec.hs index c3752b660..00d06a114 100644 --- a/test/Feature/RpcSpec.hs +++ b/test/Feature/RpcSpec.hs @@ -13,8 +13,10 @@ import Network.Wai (Application) import Protolude hiding (get) -spec :: SpecWith Application -spec = +import PostgREST.Types (PgVersion, pgVersion95) + +spec :: PgVersion -> SpecWith Application +spec actualPgVersion = describe "remote procedure call" $ do context "a proc that returns a set" $ do it "returns paginated results" $ do @@ -77,6 +79,21 @@ spec = it "should fail with 404 on unknown proc args" $ do get "/rpc/sayhello" `shouldRespondWith` 404 get "/rpc/sayhello?any_arg=value" `shouldRespondWith` 404 + it "should not ignore unknown args and fail with 404" $ + get "/rpc/add_them?a=1&b=2&smthelse=blabla" `shouldRespondWith` + let + message :: Text + message + | actualPgVersion < pgVersion95 = "function test.add_them(a := integer, b := integer, smthelse := text) does not exist" + | otherwise = "function test.add_them(a => integer, b => integer, smthelse => text) does not exist" + in [json| { + "code": "42883", + "details": null, + "hint": "No function matches the given name and argument types. You might need to add explicit type casts.", + "message": #{message} } |] + { matchStatus = 404 + , matchHeaders = [matchContentTypeJson] + } it "works when having uppercase identifiers" $ do get "/rpc/quotedFunction?user=mscott&fullName=Michael Scott&SSN=401-32-XXXX" `shouldRespondWith` diff --git a/test/Main.hs b/test/Main.hs index 8f9a6797b..897bdf38d 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -87,7 +87,7 @@ main = do , ("Feature.InsertSpec" , Feature.InsertSpec.spec actualPgVersion) , ("Feature.JsonOperatorSpec" , Feature.JsonOperatorSpec.spec actualPgVersion) , ("Feature.QuerySpec" , Feature.QuerySpec.spec) - , ("Feature.RpcSpec" , Feature.RpcSpec.spec) + , ("Feature.RpcSpec" , Feature.RpcSpec.spec actualPgVersion) , ("Feature.RangeSpec" , Feature.RangeSpec.spec) , ("Feature.SingularSpec" , Feature.SingularSpec.spec) , ("Feature.StructureSpec" , Feature.StructureSpec.spec)