语法
name 创建处理程序。该名称用于通过 SQL 查询管理处理程序、生成诊断消息以及确定处理程序的顺序。
子句
PROTOCOL— 可选。如果指定了协议名称,处理程序仅对指定的可组合协议生效。否则,处理程序会在所有 HTTP 端点上生效:内置的http/https端口,以及每个 HTTP 类型的可组合协议侦听器。PROTOCOL ANY显式指定后一种默认行为;在ALTER HANDLER中,它会移除此前设置的协议限制。名称恰为any的协议可使用反引号引用:PROTOCOL `any`。URL— 必填。可以是精确 URL、URL PREFIX或URL REGEXP。对于精确 URL 和前缀,会在创建或修改时检查是否存在歧义;如有歧义,则抛出异常。对于 regexp,无法检查歧义。匹配 URL 时会忽略?查询字符串和#片段标识符。URL PREFIX会作为基路径在路径段边界处匹配——其语义与通过配置定义的处理程序中的url_prefix规则相同:URL PREFIX '/api/v1'匹配/api/v1、/api/v1/和/api/v1/write,但不匹配/api/v1beta。前缀末尾的/会被忽略,因此'/api/v1/'和'/api/v1'的行为相同。METHODS— 可选。允许的 HTTP 方法列表。默认为仅允许GET。支持的方法包括GET、POST、PUT和DELETE。会修改数据的方法POST、PUT和DELETE可执行修改数据的查询;GET和HEAD等安全方法始终以readonly模式执行。因此,执行修改数据查询 (例如INSERT或 DDL) 的处理程序必须允许至少一种修改方法——若仅使用只读方法 (例如默认的GET) 创建此类处理程序,将抛出异常。副作用可在readonly模式下保留的查询属于特殊情况:BACKUP和RESTORE具有持久性副作用;使用session_id时,修改会话的语句SET、SET ROLE、USE、BEGIN TRANSACTION、COMMIT、ROLLBACK和SET TRANSACTION SNAPSHOT会更改跨请求持续保留的会话或事务状态;CREATE TEMPORARY TABLE/CREATE TEMPORARY VIEW会创建仅存在于会话中的对象——但安全方法的readonly模式不会阻止其中任何一种。readonly模式同样不会阻止对现有临时表的修改,因此可能以临时表为目标的查询也按相同方式处理:目标表未使用数据库限定的INSERT(未限定名称可能解析为会话临时表) 、DROP TEMPORARY TABLE、对未使用数据库限定的表执行的DROP TABLE/TRUNCATE TABLE,以及对未使用数据库限定的表执行的ALTER(ALTER TEMPORARY TABLE是相同的语句) 。使用数据库限定的目标不可能是临时表,因此此类查询不受此规则约束。HTTP 要求安全方法不得产生副作用 (声明为GET的处理程序也会处理HEAD请求,此时响应正文会被抑制,副作用将不可见) 。因此,执行此类查询的处理程序必须仅列出修改方法——创建或修改该处理程序时如包含安全方法,将抛出异常。会深入检查复合语句:对于statement1 PARALLEL WITH statement2 ...和EXECUTE AS <user> <statement>,上述规则适用于其包装的语句,因为实际执行的是这些语句 (每个语句都在处理程序上下文的副本中运行,该副本会保留readonly模式) 。不带语句的EXECUTE AS <user>会使整个会话以另一用户身份运行,因此它本身会修改会话。此外,任何EXECUTE AS处理程序——无论是不带语句还是包装语句——都必须允许至少一种修改方法:身份模拟需要IMPERSONATE权限,而安全方法的readonly模式会拒绝该权限。TYPE— 可选。目前唯一支持的类型是query。AS— 此处理程序将调用的 SQL 查询。该查询可以参数化。在创建或修改处理程序时,会对查询进行语法解析以检查其正确性,但不会进行语义分析——例如,创建处理程序时,查询所引用的表可能尚不存在。FORMAT及类似子句属于查询本身,而不属于整个CREATE/ALTER语句。为消除歧义,可将查询置于括号中。INSERT查询的VALUES或FORMAT子句后不得包含内联数据——创建或修改此类处理程序会引发异常,因为内联载荷无法保留在处理程序定义中;数据应通过 HTTP 请求正文提供 (或由INSERT ... SELECT计算) 。对于处理程序查询会读取请求正文的请求——即从正文获取数据的INSERT,或使用_request_body参数的查询——必须声明正文长度:不含Content-Length请求头的非分块请求将收到411 Length Required响应,因为否则正文会一直读取到 stream 结束,连接中断也会被视为完整请求。此类处理程序的每种方法也必须是可携带请求正文的方法 (POST、PUT或DELETE) ——如果在METHODS子句中使用安全方法创建处理程序 (例如默认的GET) ,将引发异常,因为安全方法绝不会提供请求正文,查询会在不知不觉中读取空正文;声明GET后也会为HEAD提供服务,因此混用安全方法和可携带请求正文的方法会使这些调用仍然可达。INSERT ... SELECT不读取请求正文 (其数据来自SELECT) ,因此不受这些要求约束——除非其SELECT从由请求正文提供数据的input表函数读取。读取请求正文的INSERT必须是处理程序自身的查询:EXECUTE AS和PARALLEL WITH在运行其封装的语句时不会使用请求正文,因此在创建时将此类查询封装在其中会被拒绝,以避免悄然丢弃每次上传的数据。读取请求正文的查询也不得使用_request_body参数:请求正文只有一个,绑定_request_body会在查询读取输入数据前将其消耗,因此此类处理程序会在创建时被拒绝,以避免悄然丢失每次上传的数据——请使用查询自身的正文输入或_request_body,不要同时使用两者。不读取请求正文的处理程序没有此类要求;对此类处理程序的请求正文会被忽略,绝不会追加到处理程序的查询中。每次重新加载或调用处理程序时,服务器都会以无限制的解析器深度和回溯次数重新解析存储的查询文本,因此,在提高max_parser_depth/max_parser_backtracks的会话中创建的处理程序,在普通会话限制下仍可加载和调用。
优先级
参数
- 查询字符串中的 HTTP URL 参数,使用
param_<name>命名约定 (例如,?param_id=42绑定{id:Type}) ; URL REGEXP中的命名捕获组 (例如,URL REGEXP '/users/(?P<id>\d+)'绑定{id:Type}) ;- 对于查询中声明了参数的 处理程序,请求正文中的表单字段:在携带正文的
POST、PUT和DELETE方法中,application/x-www-form-urlencoded正文 (例如,curl -d 'param_id=42') 和multipart/form-data正文中的字段均会像 URL 参数一样绑定{name:Type}参数。若某个参数同时出现在 URL 和正文中,则以 URL 中的值为准。被解析为表单的正文会由 处理程序 层消费,不会作为INSERT数据传递给查询。如果 处理程序 对正文的唯一用途是_request_body,则会获得原始正文,而不会进行表单解析;如果 处理程序 除了其他参数外还声明了_request_body,则两者都会获得——在将正文解析为表单前,原始未解析正文的副本会保存在_request_body中 (受http_max_request_param_data_size限制) 。
X-ClickHouse-Database、X-ClickHouse-User、X-ClickHouse-Key) 仍会照常生效。
函数 currentHandler 和 currentRequestURL 可用于根据调用的 处理程序 和请求 URL 自定义查询行为。
访问控制
CREATE HANDLER、DROP HANDLER 和 ALTER HANDLER 分别需要 CREATE HANDLER、DROP HANDLER 和 ALTER HANDLER 授权。
读取 system.handlers 表需要 SHOW HANDLERS 授权。处理程序查询中可能嵌入的 secret 会在该表中被掩码,除非用户还获准查看 secret (请参阅 system.handlers) 。
调用处理程序无需额外授权,但在执行查询时仍会照常检查授权,并按常规进行身份验证。若要封装对特定查询的访问,请创建一个使用 SQL SECURITY DEFINER 的 VIEW,并定义一个从该视图中查询的处理程序。
存储
query_rules_storage 部分中进行配置:
ON CLUSTER 子句不仅多余,还会导致每个副本都尝试创建同一个 处理程序。启用 ignore_on_cluster_for_replicated_handler_queries 设置后,当存储已启用复制时,CREATE、ALTER 和 DROP HANDLER 会忽略 ON CLUSTER,其行为与 ignore_on_cluster_for_replicated_named_collections_queries 一致。
ALTER HANDLER
ALTER 查询只能包含部分子句;例如,可仅更改 URL 或查询。未指定的子句将保留原有值。PROTOCOL ANY 会移除现有的协议限制,使 处理程序 再次在所有 HTTP 端点上生效。
DROP HANDLER
内部信息
system.handlers 表列出所有通过 SQL 定义的处理程序。system.query_log 表在 http_handler_name 和 http_request_url 列中记录每个查询对应的处理程序名称及 HTTP 请求路径 (不含查询字符串) 。
示例
CREATE HANDLER 是 CREATE 语句家族的一部分,与 ALTER 和 DROP 相关。