From c0b4358d8989aff556b3ab0c4deefd23137d0c9a Mon Sep 17 00:00:00 2001 From: Jake Wheat Date: Thu, 18 Feb 2016 20:37:12 +0200 Subject: [PATCH] parse functions whose name is a keyword --- Language/SQL/SimpleSQL/Parse.lhs | 134 +++++++++++++++----- tools/Language/SQL/SimpleSQL/ValueExprs.lhs | 9 ++ 2 files changed, 110 insertions(+), 33 deletions(-) diff --git a/Language/SQL/SimpleSQL/Parse.lhs b/Language/SQL/SimpleSQL/Parse.lhs index 23ab162..43df623 100644 --- a/Language/SQL/SimpleSQL/Parse.lhs +++ b/Language/SQL/SimpleSQL/Parse.lhs @@ -711,6 +711,7 @@ all the value expressions which start with an identifier > -- todo: work out how to left factor this > try (TypedLit <$> typeName <*> singleQuotesOnlyStringTok) > <|> multisetSetFunction +> <|> (try keywordFunction <**> app) > <|> (names <**> option Iden app) > where > -- this is a special case because set is a reserved keyword @@ -719,6 +720,70 @@ all the value expressions which start with an identifier > App [Name Nothing "set"] . (:[]) <$> > (try (keyword_ "set" *> openParen) > *> valueExpr <* closeParen) +> keywordFunction = +> let makeKeywordFunction x = if map toLower x `elem` keywordFunctionNames +> then return [Name Nothing x] +> else fail "" +> in unquotedIdentifierTok [] Nothing >>= makeKeywordFunction +> -- todo: this list should be in the dialects +> -- we should have tests to check these work +> -- we should have tests to check if they are used elsewhere, you +> -- get a keyword failure +> -- these are the names of functions which are also keywords +> -- so this identifier can only be used unquoted for a function application +> -- and nowhere else +> -- not sure if this list is 100% correct +> -- todo: make a corresponding list of reserved keywords which can be +> -- parsed as an identifier +> keywordFunctionNames = ["abs" +> ,"all" +> ,"any" +> ,"array_agg" +> ,"avg" +> ,"ceil" +> ,"ceiling" +> ,"char_length" +> ,"character_length" +> ,"coalesce" +> ,"collect" +> ,"contains" +> ,"convert" +> ,"corr" +> ,"covar_pop" +> ,"covar_samp" +> ,"count" +> ,"cume_dist" +> ,"grouping" +> ,"intersection" +> ,"ln" +> ,"max" +> ,"mod" +> ,"percent_rank" +> ,"percentile_cont" +> ,"percentile_disc" +> ,"power" +> ,"rank" +> ,"regr_avgx" +> ,"regr_avgy" +> ,"regr_count" +> ,"regr_intercept" +> ,"regr_r2" +> ,"regr_slope" +> ,"regr_sxx" +> ,"regr_sxy" +> ,"regr_syy" +> ,"row" +> ,"row_number" +> ,"some" +> ,"stddev_pop" +> ,"stddev_samp" +> ,"sum" +> ,"upper" +> ,"var_pop" +> ,"var_samp" +> ,"width_bucket" +> ] + === special @@ -2096,17 +2161,20 @@ The standard has a weird mix of reserved keywords and unreserved keywords (I'm not sure what exactly being an unreserved keyword means). +can't work out if aggregate functions are supposed to be reserved or +not, leave them unreserved for now + > reservedWord :: Dialect -> [String] > reservedWord d | diSyntaxFlavour d == ANSI2011 = > ["abs" -> --,"all" +> ,"all" > ,"allocate" > ,"alter" > ,"and" -> --,"any" +> ,"any" > ,"are" > ,"array" -> --,"array_agg" +> ,"array_agg" > ,"array_max_cardinality" > ,"as" > ,"asensitive" @@ -2114,7 +2182,7 @@ means). > ,"at" > ,"atomic" > ,"authorization" -> --,"avg" +> ,"avg" > ,"begin" > ,"begin_frame" > ,"begin_partition" @@ -2142,7 +2210,7 @@ means). > ,"close" > ,"coalesce" > ,"collate" -> --,"collect" +> ,"collect" > ,"column" > ,"commit" > ,"condition" @@ -2150,15 +2218,15 @@ means). > ,"constraint" > ,"contains" > ,"convert" -> --,"corr" +> ,"corr" > ,"corresponding" -> --,"count" -> --,"covar_pop" -> --,"covar_samp" +> ,"count" +> ,"covar_pop" +> ,"covar_samp" > ,"create" > ,"cross" > ,"cube" -> --,"cume_dist" +> ,"cume_dist" > ,"current" > ,"current_catalog" > --,"current_date" @@ -2225,7 +2293,7 @@ means). > ,"global" > ,"grant" > ,"group" -> --,"grouping" +> ,"grouping" > ,"groups" > ,"having" > ,"hold" @@ -2240,7 +2308,7 @@ means). > ,"int" > ,"integer" > ,"intersect" -> --,"intersection" +> ,"intersection" > ,"interval" > ,"into" > ,"is" @@ -2261,7 +2329,7 @@ means). > ,"localtimestamp" > ,"lower" > ,"match" -> --,"max" +> ,"max" > ,"member" > ,"merge" > ,"method" @@ -2304,9 +2372,9 @@ means). > ,"parameter" > ,"partition" > ,"percent" -> --,"percent_rank" -> --,"percentile_cont" -> --,"percentile_disc" +> ,"percent_rank" +> ,"percentile_cont" +> ,"percentile_disc" > ,"period" > ,"portion" > ,"position" @@ -2318,22 +2386,22 @@ means). > ,"primary" > ,"procedure" > ,"range" -> --,"rank" +> ,"rank" > ,"reads" > ,"real" > ,"recursive" > ,"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" @@ -2342,7 +2410,7 @@ means). > ,"right" > ,"rollback" > ,"rollup" -> --,"row" +> ,"row" > ,"row_number" > ,"rows" > ,"savepoint" @@ -2356,7 +2424,7 @@ means). > ,"set" > ,"similar" > ,"smallint" -> --,"some" +> ,"some" > ,"specific" > ,"specifictype" > ,"sql" @@ -2366,13 +2434,13 @@ means). > ,"sqrt" > --,"start" > ,"static" -> --,"stddev_pop" -> --,"stddev_samp" +> ,"stddev_pop" +> ,"stddev_samp" > ,"submultiset" > ,"substring" > ,"substring_regex" > ,"succeeds" -> --,"sum" +> ,"sum" > ,"symmetric" > ,"system" > ,"system_time" @@ -2407,8 +2475,8 @@ means). > --,"value" > ,"values" > ,"value_of" -> --,"var_pop" -> --,"var_samp" +> ,"var_pop" +> ,"var_samp" > ,"varbinary" > ,"varchar" > ,"varying" diff --git a/tools/Language/SQL/SimpleSQL/ValueExprs.lhs b/tools/Language/SQL/SimpleSQL/ValueExprs.lhs index d88695f..952b0e5 100644 --- a/tools/Language/SQL/SimpleSQL/ValueExprs.lhs +++ b/tools/Language/SQL/SimpleSQL/ValueExprs.lhs @@ -20,6 +20,7 @@ Tests for parsing value expressions > ,subqueries > ,aggregates > ,windowFunctions +> ,functionsWithReservedNames > ] > literals :: TestItem @@ -404,3 +405,11 @@ target_string > [("(a)", Parens (Iden [Name Nothing "a"])) > ,("(a + b)", Parens (BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"] (Iden [Name Nothing "b"]))) > ] + +> functionsWithReservedNames :: TestItem +> functionsWithReservedNames = Group "functionsWithReservedNames" $ map t +> ["abs" +> ,"char_length" +> ] +> where +> t fn = TestValueExpr ansi2011 (fn ++ "(a)") $ App [Name Nothing fn] [Iden [Name Nothing "a"]]