Presto DESCRIBE INPUT 语句详解:查看预处理语句的参数位置与类型 大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载DESCRIBE INPUT 是 Presto当前仓库为 Trino 前身 Facebook Presto 官方代码库中用于检视**预处理语句Prepared Statement**输入参数的 SQL 命令它返回每个?占位符在语句中的位置Position以及推断出的数据类型Type。本文基于官方文档 describe-input.rst 展开并结合解析器、分析器与集成测试源码讲解语法、执行原理、类型推断规则与典型使用场景帮助你掌握参数化查询的调试与排查方法。一、Synopsis语法结构DESCRIBE INPUT 的语法非常简单DESCRIBE INPUT statement_namestatement_name是当前会话session内已通过 PREPARE 保存的预处理语句名称大小写敏感。语句执行后返回两列Position参数在语句中从左到右的从 0 开始的位置序号和Type该位置参数被推断出的数据类型。从 SqlBase.g4 的语法规则可以看到DESCRIBE INPUT identifier与DESCRIBE OUTPUT identifier是并列的语法分支而DESCRIBE qualifiedName/DESC qualifiedName则被解析为showColumns因此DESCRIBE INPUT 与 DESCRIBE TABLE 是两条完全不同的语句——前者描述预处理语句的参数后者展示表的列信息使用时不要混淆。在语法树层面该语句由 DescribeInput.java 这个 AST 节点表示它仅持有一个Identifier name预处理语句名。AstBuilder在 visitDescribeInput 中完成从语法树到 AST 节点的转换。二、Description功能说明与核心语义DESCRIBE INPUT 列出预处理语句的所有输入参数包括每个参数的位置和类型。无法确定类型的参数在输出中显示为unknown。核心语义要点只描述参数不执行查询DESCRIBE INPUT 只对预处理语句做语法解析与语义分析不会真正执行查询也不会访问数据。位置从 0 开始计数语句中从左到右出现的第一个?位置为 0第二个为 1依此类推。类型推断基于语义分析参数的最终类型由分析器Analyzer根据参数在语句中的上下文推断得出推断不出来的显示为unknown。实现原理从重写规则到查询结果DESCRIBE INPUT 并非由引擎单独执行而是通过语句重写Statement Rewrite机制转换为一个普通的查询语句。核心实现在 DescribeInputRewrite.java其visitDescribeInput处理流程如下从当前会话中取出名为statement_name的预处理语句 SQL 文本session.getPreparedStatement(...)用SqlParser对该 SQL 重新解析得到内部语句用Analyzer对语句做语义分析并校验表的访问权限checkAccessPermissionsForTablesAndColumns调用ParameterExtractor.getParameters(statement)收集语句中所有Parameter节点对每个参数调用createDescribeInputRow通过queryAnalysis.getCoercion(parameter)取出推断类型若为null则回退为UNKNOWN类型构造一个形如SELECT Position, Type FROM (VALUES ...) AS Parameter Input(Position, Type) ORDER BY Position的查询返回结果。关键代码逻辑节选// DescribeInputRewrite.java ListParameter parameters getParameters(statement); Row[] rows parameters.stream() .map(parameter - createDescribeInputRow(parameter, analysis)) .toArray(Row[]::new); ... private static Row createDescribeInputRow(Parameter parameter, Analysis queryAnalysis) { Type type queryAnalysis.getCoercion(parameter); if (type null) { type UNKNOWN; } return row( new LongLiteral(Integer.toString(parameter.getPosition())), new StringLiteral(type.getTypeSignature().getBase())); }注意最后一步没有参数时重写逻辑会构造一行(NULL, NULL)并用LIMIT 0截断从而输出 0 rows对应文档示例中的空结果集有参数时则按Position升序排序输出。三、Examples官方示例逐行解析示例一带三个参数的查询先准备一个带三个?占位符的预处理语句PREPARE my_select1 FROM SELECT ? FROM nation WHERE regionkey ? AND name ?;再查看它的输入参数DESCRIBE INPUT my_select1;输出Position | Type -------------------- 0 | unknown 1 | bigint 2 | varchar (3 rows)结果解读Position 0SELECT ?中的参数。由于它是投影列且没有与其他值比较、参与运算分析器无法推断其具体类型因此显示为unknown。Position 1regionkey ?中的参数。regionkey列的类型为bigint参数与列比较时被强制推断为bigint。Position 2name ?中的参数。name列的类型为varchar参数随之被推断为varchar。这正是参数类型推断的典型行为参数的最终类型取决于它所在表达式的上下文列类型、运算符、函数签名等无法推断时回退为unknown。示例二无参数的查询PREPARE my_select2 FROM SELECT * FROM nation; DESCRIBE INPUT my_select2;输出Position | Type ----------------- (0 rows)语句中没有?占位符因此结果为空0 行不会报错。四、与 EXECUTE / DEALLOCATE 的配合使用DESCRIBE INPUT 通常与 PREPARE / EXECUTE / DEALLOCATE 组成完整的预处理语句生命周期PREPARE定义语句并保存参数占位符见 prepare.rstDESCRIBE INPUT检视参数位置与类型EXECUTE ... USING按位置传入实际参数值执行见 execute.rstDEALLOCATE PREPARE释放语句见 deallocate-prepare.rst。例如对示例一中的my_select1可以用 EXECUTE 补全参数EXECUTE my_select1 USING x, 1, abc;等价于SELECT x FROM nation WHERE regionkey 1 AND name abc;注意参数数量必须匹配EXECUTE 传入的参数个数与 DESCRIBE INPUT 列出的位置数不一致时引擎会抛出类似Incorrect number of parameters: expected 3 but found N的运行时错误该行为在 AbstractTestQueries.java 中有对应测试断言。五、源码佐证集成测试验证的行为细节仓库中的 AbstractTestQueries.java 提供了 DESCRIBE INPUT 的完整测试用例可以印证文档示例并补充边界行为测试方法预处理语句期望结果testDescribeInputSELECT ? FROM nation WHERE nationkey ? and name ?(0, unknown)、(1, bigint)、(2, varchar)testDescribeInputWithAggregationSELECT count(*) ? FROM nation(0, bigint)testDescribeInputNoParametersSELECT * FROM nation空结果0 行testDescribeInputNoSuchQuery引用不存在的名称my_query报错Prepared statement not found: my_query这些测试揭示的额外行为细节参数出现在聚合表达式中也能推断类型count(*) ?中?与count(*)bigint做加法被推断为bigint说明推断逻辑适用于任意表达式上下文不限于列比较。引用不存在的预处理语句会报错错误信息为Prepared statement not found: my_query且发生在分析阶段visitDescribeInput中session.getPreparedStatement(...)抛出异常。空参数场景下输出行的真实列类型为UNKNOWN/UNKNOWN但对外表现为 0 行通过LIMIT 0实现。此外如果你需要对比查看预处理语句的输出列信息可以使用配套的 DESCRIBE OUTPUT 语句。六、使用注意事项DESCRIBE INPUT 只能用于当前会话内已 PREPARE 的语句会话结束或执行 DEALLOCATE PREPARE 后语句不存在会报Prepared statement not found。结果是尽力而为的类型推断unknown不代表出错只表示该参数的类型在语义分析阶段无法确定例如仅出现在投影列、无任何运算或比较上下文的参数。实际 EXECUTE 时仍可按任意类型传入值引擎会在执行时按需解析。DESCRIBE INPUT 与 DESCRIBE TABLE 不要混淆DESCRIBE tbl或DESC tbl是展示表结构只有带INPUT关键字、后跟标识符时才是本语句。与 PREPARE 一样如果携带大量预处理语句导致 HTTP 请求头超限可能遇到Request Header Fields Too Large错误相关排查建议见 prepare.rst 与文档的 Troubleshooting 章节。延伸阅读PREPARE创建预处理语句EXECUTE执行预处理语句并传入参数DESCRIBE OUTPUT查看预处理语句的输出列信息DEALLOCATE PREPARE释放预处理语句DescribeInputRewrite.javaDESCRIBE INPUT 的重写实现SqlBase.g4语法定义AbstractTestQueries.java集成测试用例赞分享大数据数据库后端【免费下载链接】prestoThe official home of the Presto distributed SQL query engine for big data项目地址https://gitcode.com/gh_mirrors/pre/presto点击查看免费下载相关推荐Presto EXECUTE 语句详解预备语句的参数绑定、执行语义与源码级原理Presto EXECUTE 语句详解预备语句的参数绑定、执行语义与源码级原理 本文以 Presto 官方文档中 EXECUTE https://link.g大数据数据库后端Presto DESCRIBE OUTPUT 语句完全指南解析预编译语句的输出列结构Presto DESCRIBE OUTPUT 语句完全指南解析预编译语句的输出列结构 导读 DESCRIBE OUTPUT 是 Presto 中用于查看 预编大数据数据库后端DuckDB预处理语句如何利用参数化查询提升10倍性能的终极指南 DuckDB预处理语句如何利用参数化查询提升10倍性能的终极指南 DuckDB是一款高性能的嵌入式OLAP数据库管理系统以其卓越的查询速度和轻量级架构数据库OLAP嵌入式数据库数据分析上一篇现代企业库存管理的三大挑战与InvenTree的解决方案下一篇终极指南CredSniper - 高级安全的网络钓鱼模拟工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考