diff --git a/Language/SQL/SimpleSQL/Parser.lhs b/Language/SQL/SimpleSQL/Parser.lhs
index 53d1eac..09ccff4 100644
--- a/Language/SQL/SimpleSQL/Parser.lhs
+++ b/Language/SQL/SimpleSQL/Parser.lhs
@@ -846,10 +846,35 @@ if there are no value exprs
 >                      <*> (optionMaybe orderBy))
 >   where
 >     makeApp i (SQDefault,es,Nothing) = App i es
->     makeApp i (d,es,od) = AggregateApp i d es (fromMaybe [] od)
+>     makeApp i (d,es,od) = AggregateApp i d es (fromMaybe [] od) Nothing
 
 > app :: [Name] -> Parser ValueExpr
-> app n = aggOrApp n >>= optionSuffix windowSuffix
+> app n = aggOrApp n >>= \a -> choice
+>         [windowSuffix a
+>         ,filterSuffix a
+>         ,withinGroupSuffix a
+>         ,return a]
+
+> filterSuffix :: ValueExpr -> Parser ValueExpr
+> filterSuffix (App nm es) =
+>     filterSuffix (AggregateApp nm SQDefault es [] Nothing)
+> filterSuffix agg@(AggregateApp {}) =
+>     filterSuffix' agg
+> filterSuffix _ = fail ""
+
+> filterSuffix' :: ValueExpr -> Parser ValueExpr
+> filterSuffix' agg =
+>     keyword_ "filter" >>
+>     rep <$> parens(keyword_ "where" *> (Just <$> valueExpr))
+>   where
+>     rep f = agg {aggFilter = f}
+
+
+
+> withinGroupSuffix :: ValueExpr -> Parser ValueExpr
+> withinGroupSuffix (App nm es) = keywords_ ["within", "group"] >>
+>     AggregateAppGroup nm es <$> parens orderBy
+> withinGroupSuffix _ = fail ""
 
 ==== window suffix
 
@@ -1934,11 +1959,11 @@ means).
 > reservedWord :: [String]
 > reservedWord =
 >     ["add"
->     ,"all"
+>     --,"all"
 >     ,"allocate"
 >     ,"alter"
 >     ,"and"
->     ,"any"
+>     --,"any"
 >     ,"are"
 >     ,"array"
 >     ,"as"
@@ -2101,15 +2126,15 @@ means).
 >     ,"ref"
 >     ,"references"
 >     ,"referencing"
->     ,"regr_avgx"
->     ,"regr_avgy"
->     ,"regr_count"
->     ,"regr_intercept"
->     ,"regr_r2"
->     ,"regr_slope"
->     ,"regr_sxx"
->     ,"regr_sxy"
->     ,"regr_syy"
+>     --,"regr_avgx"
+>     --,"regr_avgy"
+>     --,"regr_count"
+>     --,"regr_intercept"
+>     --,"regr_r2"
+>     --,"regr_slope"
+>     --,"regr_sxx"
+>     --,"regr_sxy"
+>     --,"regr_syy"
 >     ,"release"
 >     ,"result"
 >     ,"return"
@@ -2130,7 +2155,7 @@ means).
 >     --,"set"
 >     ,"similar"
 >     ,"smallint"
->     ,"some"
+>     --,"some"
 >     ,"specific"
 >     ,"specifictype"
 >     ,"sql"
@@ -2166,8 +2191,8 @@ means).
 >     ,"using"
 >     --,"value"
 >     ,"values"
->     ,"var_pop"
->     ,"var_samp"
+>     --,"var_pop"
+>     --,"var_samp"
 >     ,"varchar"
 >     ,"varying"
 >     ,"when"
diff --git a/Language/SQL/SimpleSQL/Pretty.lhs b/Language/SQL/SimpleSQL/Pretty.lhs
index 717b1a3..363a239 100644
--- a/Language/SQL/SimpleSQL/Pretty.lhs
+++ b/Language/SQL/SimpleSQL/Pretty.lhs
@@ -52,7 +52,7 @@ which have been changed to try to improve the layout of the output.
 
 > valueExpr (App f es) = names f <> parens (commaSep (map valueExpr es))
 
-> valueExpr (AggregateApp f d es od) =
+> valueExpr (AggregateApp f d es od fil) =
 >     names f
 >     <> parens ((case d of
 >                   Distinct -> text "distinct"
@@ -60,6 +60,15 @@ which have been changed to try to improve the layout of the output.
 >                   SQDefault -> empty)
 >                <+> commaSep (map valueExpr es)
 >                <+> orderBy od)
+>     <+> me (\x -> text "filter"
+>                   <+> parens (text "where" <+> valueExpr x)) fil
+
+> valueExpr (AggregateAppGroup f es od) =
+>     names f
+>     <> parens (commaSep (map valueExpr es))
+>     <+> if null od
+>         then empty
+>         else text "within group" <+> parens(orderBy od)
 
 > valueExpr (WindowApp f es pb od fr) =
 >     names f <> parens (commaSep $ map valueExpr es)
diff --git a/Language/SQL/SimpleSQL/Syntax.lhs b/Language/SQL/SimpleSQL/Syntax.lhs
index 508d80d..c92aab0 100644
--- a/Language/SQL/SimpleSQL/Syntax.lhs
+++ b/Language/SQL/SimpleSQL/Syntax.lhs
@@ -78,6 +78,13 @@
 >       ,aggDistinct :: SetQuantifier -- ^ distinct
 >       ,aggArgs :: [ValueExpr]-- ^ args
 >       ,aggOrderBy :: [SortSpec] -- ^ order by
+>       ,aggFilter :: Maybe ValueExpr -- ^ filter
+>       }
+>       -- | aggregates with within group
+>     | AggregateAppGroup
+>       {aggName :: [Name] -- ^ aggregate function name
+>       ,aggArgs :: [ValueExpr] -- ^ args
+>       ,aggGroup :: [SortSpec] -- ^ within group
 >       }
 >       -- | window application, which adds over (partition by a order
 >       -- by b) to regular function application. Explicit frames are
diff --git a/tools/Language/SQL/SimpleSQL/SQL2003.lhs b/tools/Language/SQL/SimpleSQL/SQL2003.lhs
index e595e29..f140287 100644
--- a/tools/Language/SQL/SimpleSQL/SQL2003.lhs
+++ b/tools/Language/SQL/SimpleSQL/SQL2003.lhs
@@ -46,6 +46,7 @@ large amount of the SQL.
 >     ,uniquePredicate
 >     ,matchPredicate
 >     ,collateClause
+>     ,aggregateFunctions
 >     ,sortSpecificationList
 >     ]
 
@@ -3051,7 +3052,73 @@ Specify a value computed from a collection of rows.
 
 <inverse distribution function type>    ::=   PERCENTILE_CONT | PERCENTILE_DISC
 
-TODO: aggregate functions
+> aggregateFunctions :: TestItem
+> aggregateFunctions = Group "aggregate functions" $ map (uncurry TestValueExpr) $
+>     [("count(*)",App [Name "count"] [Star])
+>     ,("count(*) filter (where something > 5)"
+>      ,AggregateApp [Name "count"] SQDefault [Star] [] fil)
+
+gsf
+
+>     ,("count(a)",App [Name "count"] [Iden [Name "a"]])
+>     ,("count(distinct a)"
+>      ,AggregateApp [Name "count"]
+>                    Distinct
+>                    [Iden [Name "a"]] [] Nothing)
+>     ,("count(all a)"
+>      ,AggregateApp [Name "count"]
+>                    All
+>                    [Iden [Name "a"]] [] Nothing)
+>     ,("count(all a) filter (where something > 5)"
+>      ,AggregateApp [Name "count"]
+>                    All
+>                    [Iden [Name "a"]] [] fil)
+>     ] ++ concatMap mkSimpleAgg
+>          ["avg","max","min","sum"
+>          ,"every", "any", "some"
+>          ,"stddev_pop","stddev_samp","var_samp","var_pop"
+>          ,"collect","fusion","intersection"]
+
+bsf
+
+>     ++ concatMap mkBsf
+>          ["COVAR_POP","COVAR_SAMP","CORR","REGR_SLOPE"
+>           ,"REGR_INTERCEPT","REGR_COUNT","REGR_R2"
+>           ,"REGR_AVGX","REGR_AVGY"
+>           ,"REGR_SXX","REGR_SYY","REGR_SXY"]
+
+osf
+
+>     ++
+>     [("rank(a,c) within group (order by b)"
+>      ,AggregateAppGroup [Name "rank"]
+>           [Iden [Name "a"], Iden [Name "c"]]
+>           ob)]
+>     ++ map mkGp ["dense_rank","percent_rank"
+>                 ,"cume_dist", "percentile_cont"
+>                 ,"percentile_disc"]
+
+>   where
+>     fil = Just $ BinOp (Iden [Name "something"]) [Name ">"] (NumLit "5")
+>     ob = [SortSpec (Iden [Name "b"]) DirDefault NullsOrderDefault]
+>     mkGp nm = (nm ++ "(a) within group (order by b)"
+>               ,AggregateAppGroup [Name nm]
+>                [Iden [Name "a"]]
+>                ob)
+
+>     mkSimpleAgg nm =
+>         [(nm ++ "(a)",App [Name nm] [Iden [Name "a"]])
+>         ,(nm ++ "(distinct a)"
+>          ,AggregateApp [Name nm]
+>                        Distinct
+>                        [Iden [Name "a"]] [] Nothing)]
+>     mkBsf nm =
+>         [(nm ++ "(a,b)",App [Name nm] [Iden [Name "a"],Iden [Name "b"]])
+>         ,(nm ++"(a,b) filter (where something > 5)"
+>           ,AggregateApp [Name nm]
+>                         SQDefault
+>                         [Iden [Name "a"],Iden [Name "b"]] [] fil)]
+
 
 == 10.10 <sort specification list> (p515)
 
diff --git a/tools/Language/SQL/SimpleSQL/ValueExprs.lhs b/tools/Language/SQL/SimpleSQL/ValueExprs.lhs
index 4a9adfc..523dc70 100644
--- a/tools/Language/SQL/SimpleSQL/ValueExprs.lhs
+++ b/tools/Language/SQL/SimpleSQL/ValueExprs.lhs
@@ -331,13 +331,13 @@ target_string
 
 >     ,("sum(a order by a)"
 >     ,AggregateApp [Name "sum"] SQDefault [Iden [Name "a"]]
->                   [SortSpec (Iden [Name "a"]) DirDefault NullsOrderDefault])
+>                   [SortSpec (Iden [Name "a"]) DirDefault NullsOrderDefault] Nothing)
 
 >     ,("sum(all a)"
->     ,AggregateApp [Name "sum"] All [Iden [Name "a"]] [])
+>     ,AggregateApp [Name "sum"] All [Iden [Name "a"]] [] Nothing)
 
 >     ,("count(distinct a)"
->     ,AggregateApp [Name "count"] Distinct [Iden [Name "a"]] [])
+>     ,AggregateApp [Name "count"] Distinct [Iden [Name "a"]] [] Nothing)
 >     ]
 
 > windowFunctions :: TestItem