diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py index 19a87235de..a9f6a091f6 100644 --- a/sqlglot/expressions.py +++ b/sqlglot/expressions.py @@ -59,6 +59,7 @@ def __new__(cls, clsname, bases, attrs): SQLGLOT_META = "sqlglot.meta" +SQLGLOT_ANONYMOUS = "sqlglot.anonymous" TABLE_PARTS = ("this", "db", "catalog") COLUMN_PARTS = ("this", "table", "db", "catalog") diff --git a/sqlglot/parser.py b/sqlglot/parser.py index 6e70fa1c1a..4cbaf89a91 100644 --- a/sqlglot/parser.py +++ b/sqlglot/parser.py @@ -5361,6 +5361,16 @@ def _parse_function_call( alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS args = self._parse_csv(lambda: self._parse_lambda(alias=alias)) + post_func_comments = self._curr and self._curr.comments + if known_function and post_func_comments: + # If the user-inputted comment "/* sqlglot.anonymous */" is following the function + # call we'll construct it as exp.Anonymous, even if it's "known" + if any( + comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS) + for comment in post_func_comments + ): + known_function = False + if alias and known_function: args = self._kv_to_prop_eq(args) diff --git a/tests/test_parser.py b/tests/test_parser.py index 1bf951a65b..20967b9de0 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -888,3 +888,15 @@ def test_drop_column(self): ast = parse_one("ALTER TABLE tbl DROP COLUMN col") self.assertEqual(len(list(ast.find_all(exp.Table))), 1) self.assertEqual(len(list(ast.find_all(exp.Column))), 1) + + def test_udf_meta(self): + ast = parse_one("YEAR(a) /* sqlglot.anonymous */") + self.assertIsInstance(ast, exp.Anonymous) + + # Meta flag is case sensitive + ast = parse_one("YEAR(a) /* sqlglot.anONymous */") + self.assertIsInstance(ast, exp.Year) + + # Incomplete or incorrect anonymous meta comments are not registered + ast = parse_one("YEAR(a) /* sqlglot.anon */") + self.assertIsInstance(ast, exp.Year)