如何用SQLFluff解析混合Jinja与Placeholder模板的SQL文件?
我正在使用SQLFluff v3.0.7作为代码库的代码检查工具(linter),代码库中SQL文件混合使用Jinja与Placeholder(${...}格式)两种模板语法。
当前使用的.sqlfluff配置文件如下:
[sqlfluff] templater = jinja dialect = redshift exclude_rules = AL01,AL04,AL05,AL06,AL07,AM01,AM02,AM03,AM04,AM07,CV01,CV02,CV03,CV04,CV05,CV06,CV07,CV08,CV09,CV10,CV11,LT01,LT03,LT05,LT07,LT08,LT12,LT13,RF01,RF02,RF03,RF04,RF05,RF06,ST01,ST02,ST03,ST06,ST07,ST08,TQ01,L009,L032 ignore = templating large_file_skip_byte_limit = 0 max_line_length = 0 processes = -1 [sqlfluff:templater:jinja:context] schema_name_d_mart=d_mart schema_name_b_vault = b_vault [sqlfluff:templater:placeholder] param_style = dollar [sqlfluff:templater:placeholder:context] schema_name_b_vault = b_vault schema_name_d_mart=d_mart
测试的混合模板SQL文件内容:
{% set schema_name_b_vault = "test_schema" %} SELECT val, val2 FROM ${schema_name_b_vault}.test ;
遇到的问题:
- 当
templater配置为jinja时,Jinja语句(第1行)可正常解析,但${schema_name_b_vault}占位符(第6行)报错:
== [sqlfiles_foldera/test_a.sql] FAIL
L: 6 | P: 1 | PRS | Line 6, Position 1: Found unparsable section: 'FROM
| ${schema_name_business_vault}.test'
L: 6 | P: 6 | LXR | Unable to lex characters: '${schema_n...'
WARNING: Parsing errors found and dialect is set to 'redshift'. Have you configured your dialect correctly?
- 当
templater配置为placeholder时,占位符语法可正常解析,但Jinja语句(第1行)报错。
需要找到能同时解析两种模板语法的方案。
方法1:自定义Jinja扩展统一处理占位符
SQLFluff的Jinja templater支持扩展,可编写扩展将${...}格式的占位符转换为Jinja语法,实现统一解析:
- 创建Python扩展文件(如
placeholder_extension.py):
from jinja2.ext import Extension import re class PlaceholderExtension(Extension): def preprocess(self, source, name, filename=None): # 将${var}替换为Jinja变量语法{{ var }} return re.sub(r"\$\{([^}]+)\}", r"{{ \1 }}", source)
- 在
.sqlfluff中配置该扩展:
[sqlfluff:templater:jinja] extensions = placeholder_extension.PlaceholderExtension
- 确保扩展文件在SQLFluff的Python搜索路径中(如放在项目根目录)。
配置完成后,Jinja templater会先转换占位符语法,再统一解析所有模板内容。
方法2:预处理SQL文件再检查
通过脚本提前将占位符转换为Jinja语法,再执行SQLFluff检查:
- 编写预处理脚本(如
preprocess_sql.py):
import re import os import subprocess def process_sql_file(file_path): with open(file_path, 'r') as f: content = f.read() # 替换占位符为Jinja语法 processed_content = re.sub(r"\$\{([^}]+)\}", r"{{ \1 }}", content) # 创建临时文件 temp_file = f"{file_path}.tmp" with open(temp_file, 'w') as f: f.write(processed_content) # 执行SQLFluff检查 subprocess.run(["sqlfluff", "lint", temp_file]) # 删除临时文件 os.remove(temp_file) # 遍历目标目录处理所有SQL文件 for root, _, files in os.walk("sqlfiles_foldera"): for file in files: if file.endswith(".sql"): process_sql_file(os.path.join(root, file))
运行该脚本即可完成混合模板文件的检查,无需修改SQLFluff核心配置。
方法3:临时应急——用Jinja raw标签忽略占位符
若仅需临时跳过解析错误,可在占位符周围添加Jinja的raw标签:
{% set schema_name_b_vault = "test_schema" %} SELECT val, val2 FROM {% raw %}${schema_name_b_vault}{% endraw %}.test ;
但此方法需修改所有SQL文件,维护成本高,仅适合短期应急。
内容的提问来源于stack exchange,提问作者Chris L

