ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PRQL Target 与 Version 编译目标与版本机制详解:从 SQL 方言选择到版本控制

PRQL Target 与 Version 编译目标与版本机制详解:从 SQL 方言选择到版本控制 后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载导读PRQLPipelined Relational Query Language是一门面向数据转换的现代语言它最终会被编译为 SQL。为了让同一份 PRQL 查询能够适配不同的数据库PRQL 在查询头部提供了prql target:指令用于指定 SQL 方言同时通过prql version:指令声明查询所使用的语言版本。本文将基于官方文档 web/book/src/project/target.md 并结合 prqlc 编译器源码系统讲解 Target编译目标与 Version版本两大机制如何声明方言、哪些方言受支持、编译器参数与查询头部的优先级关系以及版本声明如何保护你的查询免受编译器升级的影响。Target查询头部的方言声明PRQL 允许在查询的最顶部声明目标方言target dialect编译器会据此生成对应数据库特有的 SQL 风味。声明语法是prql target:sql.dialect位于查询第一行例如prql target:sql.postgres from employees sort age take 10上述查询会被编译为 PostgreSQL 风格的 SQL。同样的查询只需把方言换成 SQL Serverprql target:sql.mssql from employees sort age take 10编译器就会输出适配 MSSQL 的SELECT TOP 10之类的写法。从源码看 Target 的解析链路从源码层面看target:是查询头部query header的一部分由 prqlc-parser/src/parser/stmt.rs 中的keyword(prql)解析得到随后在语义分析阶段被解析进 PL AST 的def节点。在 semantic/mod.rs 的测试用例中可以看到prql target:sql.mssql version:0会被解析为def: version: ^0 other: target: sql.mssqltarget与version属于同一头部header的两个字段二者语法结构相同都形如prql 字段:值。编译器的Target类型定义在 prqlc/src/lib.rspub enum Target { /// 当为 None 时方言从查询头部的 target 字段中提取 Sql(Optionsql::Dialect), }Target的FromStr实现lib.rs会识别sql.前缀sql.any被转换为Sql(None)其余字符串则尝试匹配Dialect枚举匹配失败会抛出Reason::NotFound错误命名空间为target。这也意味着方言名拼写错误会在编译期直接报错而不是静默地回退到通用 SQL。方言支持矩阵根据 target.md 的说明方言分为受支持Supported与不受支持Unsupported两个等级这一分级在 prqlc/src/sql/dialect.rs 的Dialect::support_level()方法中有直接对应。受支持的方言Supported受支持方言尽可能支持全部 PRQL 语言特性每次提交都会运行测试项目组会尽力修复 bug。当前列表为sql.clickhousesql.duckdbsql.generic—— 文档脚注特别说明虽然不存在一个名为 generic 的真实数据库来测试它但它仍被视作受支持方言。它对应 dialect.rs 中与Ansi共用一个GenericDialecthandler 的Generic枚举项也是Dialect的#[default]项。sql.mysqlsql.postgressql.redshiftsql.sqlite从Dialect枚举dialect.rs可以看到Generic被标注为默认值这与Options::default()中target: Target::Sql(None)lib.rs一致——当查询头部和编译器参数都没有指定方言时PRQL 默认走通用 SQL 路径。不受支持的方言Unsupported不受支持方言在编译器中已有实现但测试覆盖很少甚至没有部分功能可能存在缺口项目欢迎社区贡献补齐测试或新增方言sql.mssqlsql.ansisql.bigquerysql.snowflakesql.oracle—— 非常早期目前只保证标识符加引号以适应 Oracle 的大小写折叠规则将take编译为OFFSET ... FETCH FIRST而非LIMITtext.contains使用||而非CONCAT。其余大多数语言特性回退到通用 SQL在 Oracle 上可能无法正确执行。上述源码注释中关于 Oracle 的描述与文档一致OracleDialect实现了use_fetch用OFFSET n ROWS FETCH FIRST n ROWS ONLY做行数限制、IdentQuotingStyle::AlwaysQuoted始终加引号以及table_alias_uses_as() - falseOracle 的表别名不允许AS关键字见 dialect.rs。方言底层实现DialectHandler 特性方言差异在编译器中通过DialectHandlertrait 来抽象dialect.rs。Dialect枚举通过handler()方法dialect.rs分派到具体的 handler 结构体例如MsSqlDialect、PostgresDialect、OracleDialect等Ansi与Generic共用GenericDialect。该 trait 暴露了一系列可覆写的行为钩子决定了每个方言的 SQL 生成差异例如钩子方法默认行为典型覆写use_fetch()false使用LIMITMSSQL、Oracle 返回true改用FETCH子句ident_quote()双引号MySQL、ClickHouse 用反引号ident_quoting_style()条件引号Snowflake、Oracle 用AlwaysQuoted始终引号has_concat_function()true使用CONCATRedshift、SQLite 返回false回退到||运算符set_ops_distinct()trueSQLite、MSSQL、Snowflake 返回falseexcept_all()/intersect_all()trueSQLite、MSSQL、DuckDB 返回falsesupports_distinct_on()falsePostgres、ClickHouse、DuckDB 返回truestars_in_group()trueSQLite 返回falsetranslate_chrono_item()默认报错日期格式化需要方言支持Postgres/MySQL/MSSQL/ClickHouse/DuckDB/BigQuery/Redshift 各自实现table_alias_uses_as()trueOracle 返回falserequires_order_by_in_window_function()falseSnowflake 返回trueROW_NUMBER()等排名函数要求 ORDER BY文件头注释dialect.rs说明了设计原则优先面向通用方言生成只有通用方言不支持如 MSSQL 没有LIMIT或方言专属实现性能更优时才引入方言差异相应地生成的 SQL 可能偏冗长但换来了更简单的翻译器。例如chrono_item_to_strftimedialect.rs负责把 chrono 日期格式串转回 strftime 表示Postgres 的translate_chrono_itemdialect.rs则把 PRQL 的%Y、%m等规格映射到 PostgreSQL 的YYYY、MM等格式并处理字面量转义。每个方言 handler 的具体差异都可以在上述源码中找到对应实现是理解为什么同一 PRQL 在不同数据库输出不同 SQL的最佳入口。Target 优先级编译器参数 查询头部一个查询的编译目标由两个来源决定查询头部的prql target:声明以及传给编译器的 target 参数。编译器参数优先于查询头部声明。例如下面的 shell 命令查询内部声明了sql.generic但prqlc compile命令通过--target选项指定了sql.duckdb此时sql.duckdb胜出输出的 SQL 基于 DuckDB 方言echo prql target:sql.generic from foo | prqlc compile --target sql.duckdb在 prqlc/src/cli/mod.rs 中compile子命令的--target参数定义如下/// Target to compile to #[arg(short, long, default_value sql.any, env PRQLC_TARGET)] target: String,默认值正是文档中提到的特殊 targetsql.any同时支持通过环境变量PRQLC_TARGET注入对 CI 场景很实用。sql.any让查询头部说了算如果希望编译器尊重查询头部声明的方言就需要在编译器选项中显式传入特殊值sql.anyecho prql target:sql.generic from foo | prqlc compile --target sql.any从 lib.rs 的FromStr实现可以看到sql.any会被解析为Target::Sql(None)而Sql(None)的语义正是方言从查询头部提取。换言之sql.any不是某种任意数据库而是由查询决定的占位符。由于--target的默认值就是sql.any所以默认情况下查询头部总是生效的只有当你显式传入某个具体方言时它才会覆盖查询头部。Target::names()lib.rs会生成sql.any加上所有sql.dialect组成的列表CLI 的prqlc list-targets命令即用于展示所有可用编译目标名见 cli/mod.rs可以通过它确认当前版本支持的全部方言。各语言绑定中的 Target 设置除 CLI 外各语言绑定也把 Target 作为公开 API 暴露。例如 Python 绑定 prqlc/bindings/prqlc-python/src/lib.rs 与 C 绑定 prqlc/bindings/prqlc-c/src/lib.rs 中都出现sql.any/ 方言字符串的处理Rust 侧则可以直接用类型安全的枚举参考 lib.rs 的 doctestuse prqlc::{compile, Options, Target, sql::Dialect}; let prql from employees | select {name,age}; let opts Options::default() .with_target(Target::Sql(Some(Dialect::SQLite))) .with_signature_comment(false) .with_format(false); let sql compile(prql, opts).unwrap();Options的默认值为format: true、target: Target::Sql(None)、signature_comment: truelib.rswith_target链式方法可覆盖目标方言。Version查询版本声明PRQL 允许在查询头部声明语言版本prql version:0.13.14 from employees这个版本声明有两个作用其中第一个已经实现第二个是 PRQL 1.0 的门槛特性编译器版本下限检查已实现如果编译器版本比查询声明的版本更旧编译器会直接报错。这避免了查询用了语言新特性、而编译器尚未升级时产生的令人困惑的错误——与其等编译结果莫名其妙地出错不如一开始就明确提示版本不匹配。按主版本编译规划中未实现编译器将为查询的主版本编译。这允许语言持续演进而不破坏存量查询也无需用户同时安装多个版本的编译器。这是 PRQL 1.0 的 gating 特性。关于版本检查从语义分析层的测试可以印证在 semantic/mod.rs 中version:foo非合法版本字符串和version:25这类会被拒绝的用例以及未知方言target:sql.yah的用例都会在parse_resolve_and_lower阶段直接返回错误说明 header 中的非法值与非法方言一样会触发编译期报错。在 PRQL 中查询编译器版本当前正在使用的编译器版本可以通过 PRQL 标准库中的特殊函数std.prql.version获取。将函数结果放进一个数组字面量即可查询[{version prql.version}]这个用法在集成测试 prqlc/tests/integration/sql.rs 中有直接验证测试还展示了它的派生用法derive y std.prql.version。注意std.prql.version返回的是编译器版本与查询头部声明的version:是两回事前者是运行时读取当前编译器后者是查询作者声明的最低可用版本契约。实战完整使用组合综合以上机制一个典型的跨数据库工作流是在查询头部写清楚它依赖的方言与版本作为查询的元数据然后在编译时通过 CLI 参数覆盖目标数据库。例如# 查询头部声明 generic但实际编译给 DuckDB 执行 cat EOF | prqlc compile --target sql.duckdb prql target:sql.generic version:0.13.14 from employees sort age take 10 EOF # 列出当前编译器支持的所有 target prqlc list-targets # 通过环境变量指定 target适合脚本/CI PRQLC_TARGETsql.postgres prqlc compile query.prql注意事项若--target未指定默认sql.any以查询头部的prql target:为准若指定了具体方言则以参数为准。方言名必须与 dialect.rs 中的Dialect枚举ansi、bigquery、clickhouse、duckdb、generic、mssql、mysql、oracle、postgres、redshift、sqlite、snowflake一致拼写错误会在编译期报错。使用std.prql.version可以读取当前编译器版本用于诊断版本不匹配问题。生成 SQL 时会附带一行包含 PRQL 编译器版本信息的签名注释Options::signature_comment默认为true可用--hide-signature-comment关闭见 cli/mod.rs。相关资源本文主题的官方文档web/book/src/project/target.md方言枚举与DialectHandler特性定义prqlc/prqlc/src/sql/dialect.rsTarget、Options与compile入口prqlc/prqlc/src/lib.rsCLIcompile子命令与--target参数prqlc/prqlc/src/cli/mod.rs查询头部解析prql关键字prqlc/prqlc-parser/src/parser/stmt.rsHeader 解析与版本校验测试prqlc/prqlc/src/semantic/mod.rsstd.prql.version使用示例prqlc/prqlc/tests/integration/sql.rs各语言绑定对 target 的封装prqlc/bindings赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐phar-io/version版本解析机制详解phar io/version版本解析机制详解 本文深入解析了phar io/version库的版本解析机制重点介绍了Version类的结构与设计、版本字符串开发工具终极Mermaid在线编辑器如何零代码创建专业图表可视化终极Mermaid在线编辑器如何零代码创建专业图表可视化 Mermaid Live Editor是一款功能强大的在线图表编辑器让您无需编写复杂代码就能创建流前端开发者工具数据可视化RedisInsight Windows 安装指南装完就连上库RedisInsight Windows 安装指南装完就连上库 如果你不想逐条敲命令去查 Redis 数据RedisInsight 是官方推出的可视化 Re数据库客户端桌面应用后端前端数据可视化上一篇网盘下载总是慢半拍聊聊直链下载助手这个免费小工具下一篇D3KeyHelper暗黑3技能连点器零基础实战指南三十分钟让我的法师自己转起来创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表