diff --git a/sqlmesh/core/macros.py b/sqlmesh/core/macros.py index 9370bffdeb..e7f99f24bf 100644 --- a/sqlmesh/core/macros.py +++ b/sqlmesh/core/macros.py @@ -647,10 +647,10 @@ def substitute( node: exp.Expr, args: t.Dict[str, exp.Expr] ) -> exp.Expr | t.List[exp.Expr] | None: if isinstance(node, (exp.Identifier, exp.Var)): + name = node.name.lower() + if name in args: + return args[name].copy() if not isinstance(node.parent, exp.Column): - name = node.name.lower() - if name in args: - return args[name].copy() if name in evaluator.locals: return exp.convert(evaluator.locals[name]) if SQLMESH_MACRO_PREFIX in node.name: diff --git a/tests/core/test_macros.py b/tests/core/test_macros.py index e37a7ec05b..0135cd8ca5 100644 --- a/tests/core/test_macros.py +++ b/tests/core/test_macros.py @@ -618,6 +618,20 @@ def test_ast_correctness(macro_evaluator): "SELECT * FROM (VALUES ((1, 2), (2, 3), (3, 4))) AS v", {}, ), + # Lambda parameter name matches the column identifier inside a Column expression + # (e.g. schema.product where 'product' is both the lambda arg and the column name). + # Lambda args must take precedence over the Column-context guard so that the param + # is substituted correctly (regression test for GitHub issue #5582). + ( + "SELECT @EACH([a, b, c], product -> schema.product)", + "SELECT schema.a, schema.b, schema.c", + {}, + ), + ( + "SELECT @EACH([x, y], col -> tbl.col)", + "SELECT tbl.x, tbl.y", + {}, + ), ], ) def test_macro_functions(macro_evaluator: MacroEvaluator, assert_exp_eq, sql, expected, args):