diff --git a/CHANGELOG.md b/CHANGELOG.md index 532c23749..56a3d3d8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #2858, Performance improvements when calling RPCs via GET using indexes in more cases - @wolfgangwalther - #3560, Log resolved host in "Listening on ..." messages - @develop7 +### Fixed + + - #3693, Prevent spread embedding to allow aggregates when they are disabled - @laurenceisla + ### Changed - #2052, Dropped support for PostgreSQL 9.6 - @wolfgangwalther diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 4718b05ed..8f9323f46 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -332,8 +332,8 @@ readPlan qi@QualifiedIdentifier{..} AppConfig{configDbMaxRows, configDbAggregate in mapLeft ApiRequestError $ treeRestrictRange configDbMaxRows (iAction apiRequest) =<< - validateAggFunctions configDbAggregates =<< hoistSpreadAggFunctions =<< + validateAggFunctions configDbAggregates =<< addRelSelects =<< addNullEmbedFilters =<< validateSpreadEmbeds =<< @@ -721,8 +721,7 @@ hoistIntoRelSelectFields _ r = r validateAggFunctions :: Bool -> ReadPlanTree -> Either ApiRequestError ReadPlanTree validateAggFunctions aggFunctionsAllowed (Node rp@ReadPlan {select} forest) - | aggFunctionsAllowed = Node rp <$> traverse (validateAggFunctions aggFunctionsAllowed) forest - | any (isJust . csAggFunction) select = Left AggregatesNotAllowed + | not aggFunctionsAllowed && any (isJust . csAggFunction) select = Left AggregatesNotAllowed | otherwise = Node rp <$> traverse (validateAggFunctions aggFunctionsAllowed) forest addFilters :: ResolverContext -> ApiRequest -> ReadPlanTree -> Either ApiRequestError ReadPlanTree diff --git a/test/spec/Feature/Query/AggregateFunctionsSpec.hs b/test/spec/Feature/Query/AggregateFunctionsSpec.hs index 5030fa3f2..7c8025d58 100644 --- a/test/spec/Feature/Query/AggregateFunctionsSpec.hs +++ b/test/spec/Feature/Query/AggregateFunctionsSpec.hs @@ -166,3 +166,25 @@ disallowed = }|] { matchStatus = 400 , matchHeaders = [matchContentTypeJson] } + + it "prevents the use of aggregates on embedded relationships" $ + get "/projects?select=name,project_invoices(invoice_total.sum())" `shouldRespondWith` + [json|{ + "hint":null, + "details":null, + "code":"PGRST123", + "message":"Use of aggregate functions is not allowed" + }|] + { matchStatus = 400 + , matchHeaders = [matchContentTypeJson] } + + it "prevents the use of aggregates on spread embeds" $ + get "/project_invoices?select=...projects(id.count())" `shouldRespondWith` + [json|{ + "hint":null, + "details":null, + "code":"PGRST123", + "message":"Use of aggregate functions is not allowed" + }|] + { matchStatus = 400 + , matchHeaders = [matchContentTypeJson] }