后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载prql-dotnet包内命名prql-net是 PRQL 官方仓库中为 .NET 生态提供的编译器绑定它通过一个静态的PrqlCompiler类把 PRQL 查询转译为 SQL并以net10.0目标框架交付。本文将围绕该绑定的官方文档见 dotnet.md 与 README.md完整讲解其安装部署、四个核心编译 API、编译选项与结果模型并结合仓库源码剖析其背后的 P/Invoke 调用链与内存管理机制帮助你直接在 .NET 应用中集成 PRQL 编译能力。一、prql-dotnet 是什么项目定位与当前状态根据官方文档prql-net以net10.0为目标框架提供 PRQL 的 .NET 绑定核心入口是静态类PrqlCompiler它提供四个方法方法作用输出Compile将 PRQL 字符串一次性编译为 SQL 字符串SQL 文本PrqlToPl将 PRQL 解析为 PL管道语言层AST 的 JSONPL ASTJSONPlToRq解析变量引用、校验函数调用、确定 frame将 PL 转为 RQ关系查询层ASTRQ ASTJSONRqToSql将 RQ AST 转译为 SQL 字符串SQL 文本这 4 个方法共同覆盖了 PRQL 编译管线的完整阶段PL → RQ → SQL每个方法都返回一个携带Output字符串与Messages消息集合的Result对象。需要特别注意的是其成熟度官方文档明确说明它仍处于早期阶段early stage尚未发布到 NuGet当前版本号为0.1.0。在 bindings 总览文档 中.NET 绑定与 PHP 一起被归类为Nascent萌芽期层级——即正在开发中可能尚未完全可用区别于 Java、Elixir、prqlc-c 的 Unsupported 层级以及 JavaScript、Python、R、Rust 的 Supported 层级。因此在生产环境采用前应充分评估其成熟度并欢迎通过贡献来完善它。二、安装与运行环境准备2.1 目标框架要求项目工程文件 PrqlCompiler.csproj 中明确配置TargetFrameworknet10.0/TargetFramework ImplicitUsingsenable/ImplicitUsings Nullableenable/Nullable AllowUnsafeBlockstrue/AllowUnsafeBlocks即该绑定面向 .NET 10net10.0要求你的项目同样基于 .NET 10 或以上版本并开启隐式 using 与可空引用类型。2.2 原生库部署libprqlc_c 的动态加载这是整个绑定最关键的部署步骤。文档明确指出编译时libprqlc_c库是**在运行时被动态导入dynamically imported**的因此你需要根据操作系统把对应的原生动态库放到项目的bin输出目录中与PrqlCompiler.dll及其余编译产物放在一起Linuxlibprqlc_c.somacOSlibprqlc_c.dylibWindowslibprqlc_c.dll典型路径为{your_project}/bin/Debug/net10.0/Release 构建则对应bin/Release/net10.0/。从源码看库名常量定义在 PrqlCompiler.csprivate const string LibraryName libprqlc_c;而在 csproj 中三个平台的动态库均被配置为最新时复制到输出目录None Updatelibprqlc_c.dll CopyToOutputDirectoryPreserveNewest/CopyToOutputDirectory /None None Updatelibprqlc_c.dylib CopyToOutputDirectoryPreserveNewest/CopyToOutputDirectory /None None Updatelibprqlc_c.so CopyToOutputDirectoryPreserveNewest/CopyToOutputDirectory /None这意味着如果你通过源码构建本项目把对应平台的libprqlc_c动态库文件放进项目目录与 csproj 同级的约定位置构建时便会自动复制到输出目录如果你以手工方式集成则需要自行完成上述文件放置。缺少该动态库时运行时LibraryImport将无法解析符号调用编译方法会直接失败。2.3 包元数据虽然尚未发布到 NuGetcsproj 中已经预留了完整的打包信息PackageIdPrql.Compiler、PackageVersion0.1.0、PackageLicenseExpressionApache-2.0、标签prql;sql等说明发布通道的准备工作已在推进中。当前阶段集成方式以源码引用或本地构建为主。三、快速上手第一个编译调用官方文档给出的最小可用示例如下它演示了如何编译一条最简单的 PRQL 查询并打印结果using Prql.Compiler; var options new PrqlCompilerOptions { Format false, SignatureComment false, }; var result PrqlCompiler.Compile(from employees, options); Console.WriteLine(result.Output);在测试代码 CompilerTest.cs 中可以验证其输出当Format false、SignatureComment false时Compile(from employees, ...)恰好得到SELECT * FROM employees。也就是说PRQL 的from employees会被转译为对employees表的全量选择输出直接可被数据库执行。如果你不需要自定义选项也可以使用单参数重载PrqlCompiler.Compile(from employees)此时内部会以默认选项Formattrue、SignatureCommenttrue编译。四、编译 API 全景单步编译与分段管线PrqlCompiler的四个方法分别对应 PRQL 编译器管线的不同阶段。理解它们的关系是进阶使用的前提。4.1 Compile一步到位public static Result Compile(string prqlQuery); public static Result Compile(string prqlQuery, PrqlCompilerOptions options);这是最常用的入口输入 PRQL 源字符串输出 SQL。从 C 层实现看prqlc-c 的 compile 函数 本质上是prql_to_pl→pl_to_rq→rq_to_sql三个阶段的串联封装without converting to JSON between each of the functions因此Compile与手动分段调用的结果在语义上完全一致。4.2 分段 APIPrqlToPl / PlToRq / RqToSql当需要调试、二次加工或观测中间表示时可以逐段调用// 1) PRQL - PL AST (JSON) var pl PrqlCompiler.PrqlToPl(let a (from employees | take 10)\n\nfrom a | select {first_name}); // 2) PL AST - RQ AST (JSON) var rq PrqlCompiler.PlToRq(pl.Output); // 3) RQ AST - SQL var sql PrqlCompiler.RqToSql(rq.Output, new PrqlCompilerOptions());每段输出均为 JSON 文本PL/RQ AST或 SQL 文本输入输出皆为字符串链路清晰。测试 TestOtherFunctions 使用包含let变量定义与take、select管道的查询验证了这条链路分段调用PrqlToPl→PlToRq→RqToSql与直接Compile得到的Output与Messages完全一致证明分段 API 与整体 API 结果等价。4.3 参数与异常约定从 PrqlCompiler.cs 的 XML 注释与参数校验代码可以看出统一的约定prqlQuery为 null 或空字符串时抛出ArgumentExceptionParamName为prqlQueryoptions为 null 时抛出ArgumentNullExceptionPlToRq的空参数名为plJsonRqToSql为rqJson编译错误不会以异常形式抛出而是进入Result.Messages详见下文。对应测试 CompilerTest.cs 对以上每种异常场景都有回归覆盖包括Compile()、PrqlToPl()、PlToRq()、RqToSql(, ...)等。五、编译选项 PrqlCompilerOptions 详解PrqlCompilerOptions定义在 PrqlCompilerOptions.cs是一个 C# record共三个属性属性类型默认值说明Formatbooltrue是否将生成的 SQL 字符串交给格式化器处理拆分多行、美化缩进与空格Targetstring?null编译目标与方言dialectSignatureCommentbooltrue是否在生成的 SQL 之后追加编译器签名注释5.1 FormatSQL 格式化默认为true。测试中为了获得紧凑可断言的输出通常显式关闭var options new PrqlCompilerOptions { Format false, SignatureComment false };C 层 Options 结构体 中对应的format字段注释为Pass generated SQL string through a formatter that splits it into multiple lines and prettifies indentation and spacing即格式化只影响 SQL 的外观排版不影响语义。5.2 Target方言目标默认null。C 层注释说明其默认行为Default to sql.any, which uses target argument from the query header to determine the SQL dialect——即null时由查询头部的target参数决定方言。显式指定时可使用类似sql.mssql的值测试中正是通过Target sql.mssql将 PRQL 编译为 SQL Server 方言的 SQLSELECT * FROM employees。如果你面向其他数据库如 PostgreSQL、DuckDB、ClickHouse 等可参考仓库中 dialect 相关实现 所支持的方言命名并通过Target指定。5.3 SignatureComment签名注释默认为true即在生成的 SQL 末尾追加一行形如-- Generated by PRQL compiler version x.y.z的注释便于追踪 SQL 来源。若需要将输出原样交给下游如做快照对比或逐字执行可关闭此项。5.4 选项如何跨越 FFI 边界在 NativePrqlCompilerOptions.cs 中托管选项会被转换为与 C 结构体Options内存布局一致的原生结构体LayoutKind.Sequential其中bool转为byteTarget字符串通过Marshal.StringToCoTaskMemUTF8转成 UTF-8 指针并在finally块中用Marshal.FreeCoTaskMem释放见 PrqlCompiler.cs避免内存泄漏。六、结果模型Output 与 Messages所有方法都返回Result见 Result.cs它由两个公开成员组成Outputstring编译器输出。成功时为 SQLCompile/RqToSql或 AST 的 JSONPrqlToPl/PlToRq失败时通常为空字符串。MessagesIReadOnlyCollectionMessage错误、警告与 lint 消息集合。编译失败的信息都在这里而不是抛出异常。6.1 Message 结构每个Message见 Message.cs包含六个字段字段类型说明KindMessageKind消息类型Error/Warning/Lint当前仅Error被实现Codestring?机器可读的错误标识符可能为 nullReasonstring错误的纯文本说明Hintstring?修复建议可能为 nullSpanSpan?错误在源文件中的字符偏移区间可能为 nullDisplaystring?带标注的代码片段含原因与提示可能为 nullLocationSourceLocation?错误在源文件中的行列号可能为 null其中Span是readonly record struct Span(ulong Start, ulong End)见 Span.cs以字符为单位表示偏移SourceLocation是readonly record struct SourceLocation(ulong StartLine, ulong StartCol, ulong EndLine, ulong EndCol)见 SourceLocation.cs表示行列范围。这两个结构体与 C 层 Span / SourceLocation 一一对应且源注释注明Make sure to keep in sync with prqlc::Span。6.2 错误处理实战测试 Compile_ReportsErrorMessages 展示了错误场景查询from employees | unknown_function col中unknown_function未定义编译后var result PrqlCompiler.Compile(query); // result.Messages 非空 var message result.Messages.First(); Assert.Equal(MessageKind.Error, message.Kind); Assert.False(string.IsNullOrEmpty(message.Reason)); Assert.NotNull(message.Span); Assert.NotNull(message.Location); Assert.False(string.IsNullOrEmpty(message.Display));可见错误消息会携带Span、Location、Display标注了出处的代码片段等丰富诊断信息可直接用于在编辑器或日志中定位问题。6.3 原生内存的自动释放值得注意的实现细节Result的构造函数在读完Output与所有Message后会调用ResultDestroyExternP/Invoke 到 C 层的result_destroy见 Result.cs释放原生层分配的内存且这一调用位于finally块中保证异常路径也不会泄漏。C 层 result_destroy 的文档要求每个返回CompileResult的调用恰好调用一次result_destroy不得手动释放任何字段.NET 端正是按此契约实现的。七、源码级原理P/Invoke 与 FFI 调用链从 PrqlCompiler.cs 可以看到四个原生导出函数通过LibraryImport源码生成的高性能 P/Invoke绑定[LibraryImport(LibraryName, EntryPoint compile, StringMarshalling StringMarshalling.Utf8)] private static partial NativeResult CompileExtern(string prqlQuery, ref NativePrqlCompilerOptions options); [LibraryImport(LibraryName, EntryPoint prql_to_pl, StringMarshalling StringMarshalling.Utf8)] private static partial NativeResult PrqlToPlExtern(string prqlQuery); [LibraryImport(LibraryName, EntryPoint pl_to_rq, StringMarshalling StringMarshalling.Utf8)] private static partial NativeResult PlToRqExtern(string plJson); [LibraryImport(LibraryName, EntryPoint rq_to_sql, StringMarshalling StringMarshalling.Utf8)] private static partial NativeResult RqToSqlExtern(string rqJson, ref NativePrqlCompilerOptions options);几个关键设计点统一采用StringMarshalling.Utf8。测试 Compile_HandlesNonAsciiInput 专门验证了这一点查询from employees | filter name Café编译后输出中仍保留Café。测试注释指出默认的DllImportANSI 封送会静默损坏非 ASCII 字节而LibraryImport UTF-8 封送可以正确往返——因此在查询中直接使用中文、法文等非 ASCII 文本是安全的。调用链与 C 层一一对应。compile对应 C 层的 compile 函数它内部串联了prqlc::prql_to_pl、prqlc::pl_to_rq、prqlc::rq_to_sql三个 Rust 函数prql_to_pl在 C 层还会经过json::from_pl序列化pl_to_rq先json::to_pl反序列化再json::from_rq序列化rq_to_sql先json::to_rq反序列化。整个调用链最终落到prqlccrate 的编译器核心。返回值的内存布局。NativeResult见 NativeResult.cs与 C 层 CompileResult 结构一致Output指针、Messages指针与MessagesLen长度。Result构造函数遍历消息数组逐个将NativeMessage反序列化为托管Message并处理了可空字符串PtrToUtf8StringIndirect解引用二级指针与可空结构体指针IntPtr.Zero判定等边界情况。八、版本状态与路线图官方 README 的 TODO 部分交代了版本策略当前版本停在0.1.0是因为 prqlc-c 尚未更新到最新的编译器 API一旦 prqlc-c 跟进最新 API.NET 绑定的版本号就可以与整个 PRQL 项目的主版本对齐。因此使用本绑定时有两点预期管理绑定版本0.1.0与 PRQL 编译器版本目前不同步两者 API 的对应关系以 prqlc-c 的导出为准由于处于 Nascent 阶段未来 API 可能存在破坏性变更例如Message字段、选项结构、方法签名等升级时建议对照 CHANGELOG.md 与绑定源码确认差异。九、深入阅读相关文件索引官方绑定文档dotnet.md即本文主题文档内容由 README.md 引入绑定层级总览bindings/README.md托管 API 实现PrqlCompiler.cs、PrqlCompilerOptions.cs、Result.cs、Message.cs数据模型Span.cs、SourceLocation.cs、MessageKind.cs工程与打包配置PrqlCompiler.csproj、解决方案 prql-net.sln测试用例CompilerTest.csC FFI 层libprqlc_c的来源prqlc-c/src/lib.rs配套头文件 prqlc.h 与 prqlc.hppPRQL 编译器核心PL/RQ/方言prqlc/src 下的ir/pl、ir/rq与sql模块结语prql-dotnet 为 .NET 开发者打开了一条通往 PRQL 编译能力的通道无论你是想一步编译得到 SQL还是想通过PrqlToPl→PlToRq→RqToSql的分段管线观测和加工中间 ASTPrqlCompiler都提供了简洁一致的 API 与结构化的诊断消息。部署时只需牢记把对应平台的libprqlc_c动态库放到输出目录这一关键前提并理性看待其 0.1.0 版本与 Nascent 阶段的状态。随着 prqlc-c 跟上最新 API这个绑定将很快与 PRQL 主版本对齐值得持续关注与贡献。赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐PRQL PHP 绑定指南使用 prql-php 通过 FFI 将 PRQL 编译为 SQLPRQL PHP 绑定指南使用 prql php 通过 FFI 将 PRQL 编译为 SQL prql php 是 PRQL 编译器在 PHP 生态中的官方绑后端使用 prql-php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL使用 prql php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL PRQLPipelined Relational Que后端PRQL Python 绑定prqlc完整指南安装、编译 API 与调试用法PRQL Python 绑定prqlc完整指南安装、编译 API 与调试用法 PRQLPipelined Relational Query Langua后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?