Crea un handler HTTP personalizado definido mediante SQL, sin editar el archivo de configuración del servidor. Los handlers definidos mediante SQL son una alternativa a los handlers de la interfaz HTTP.
Sintaxis
CREATE HANDLER [IF NOT EXISTS] name [ON CLUSTER cluster]
[PROTOCOL protocol_name|ANY]
URL [PREFIX|REGEXP] '/path'
[METHODS (GET, POST)]
[TYPE query]
AS [SELECT|INSERT|...] ...Crea un handler con el name especificado. El nombre se utiliza para gestionar handlers mediante consultas SQL, en mensajes de diagnóstico y para ordenarlos.
Cláusulas
PROTOCOL— opcional. Si se especifica un nombre de protocolo, el controlador solo está activo para el protocolo componible indicado. De lo contrario, el controlador está activo en todos los endpoints HTTP: los puertos integradoshttp/httpsy todos los listeners de protocolo componible de tipo HTTP.PROTOCOL ANYselecciona explícitamente este comportamiento predeterminado; enALTER HANDLER, elimina una restricción de protocolo establecida previamente. Se puede hacer referencia a un protocolo llamado literalmenteanymediante comillas invertidas:PROTOCOL `any`.URL— obligatorio. Puede ser una URL exacta, unURL PREFIXo unURL REGEXP. Para las URL exactas y los prefijos, se comprueba si hay ambigüedad al crear o alterar el controlador y se genera una excepción si la hay. En el caso de las expresiones regulares, no se puede comprobar la ambigüedad. La URL se compara sin la cadena de consulta?ni el identificador de fragmento#. UnURL PREFIXse compara como una ruta base, en un límite de segmento de ruta — con la misma semántica que la reglaurl_prefixde los controladores definidos mediante configuración:URL PREFIX '/api/v1'coincide con/api/v1,/api/v1/y/api/v1/write, pero no con/api/v1beta. La/final del prefijo se ignora, por lo que'/api/v1/'y'/api/v1'se comportan igual.METHODS— opcional. La lista de métodos HTTP permitidos. De forma predeterminada, solo se permiteGET. Los métodos compatibles sonGET,POST,PUTyDELETE. Los métodos que modifican datos,POST,PUTyDELETE, pueden ejecutar consultas modificadoras; los métodos seguros, comoGETyHEAD, siempre se ejecutan en modoreadonly. Por lo tanto, un controlador cuya consulta modifica datos (por ejemplo,INSERTo DDL) debe permitir al menos un método de modificación; crear un controlador de este tipo únicamente con métodos de solo lectura (por ejemplo, elGETpredeterminado) genera una excepción. Las consultas cuyos efectos secundarios persisten en modoreadonlyconstituyen un caso especial:BACKUPyRESTOREtienen efectos secundarios duraderos; las sentencias que modifican la sesión,SET,SET ROLE,USE,BEGIN TRANSACTION,COMMIT,ROLLBACKySET TRANSACTION SNAPSHOT, cambian el estado de la sesión o de la transacción, que persiste entre solicitudes cuando se usasession_id; yCREATE TEMPORARY TABLE/CREATE TEMPORARY VIEWcrean un objeto que existe en la sesión. Sin embargo, el modoreadonlyde los métodos seguros no bloquea ninguna de ellas. Las mutaciones de una tabla temporal existente tampoco quedan bloqueadas por el modoreadonly, por lo que las consultas que puedan tener una tabla de este tipo como destino se tratan del mismo modo: unINSERTcuya tabla de destino no está calificada con una base de datos (un nombre no calificado puede resolverse como una tabla temporal de sesión), unDROP TEMPORARY TABLE, unDROP TABLE/TRUNCATE TABLEde una tabla no calificada con una base de datos y unALTERde una tabla no calificada con una base de datos (ALTER TEMPORARY TABLEes la misma sentencia). Un destino calificado con una base de datos nunca puede ser una tabla temporal, por lo que dichas consultas no están sujetas a esta regla. HTTP exige que los métodos seguros no tengan efectos secundarios (un controlador declarado paraGETtambién se sirve paraHEAD, donde se suprime el cuerpo de la respuesta y el efecto sería invisible). Por lo tanto, un controlador que ejecute una consulta de este tipo debe enumerar únicamente métodos de modificación; crearlo o modificarlo para incluir un método seguro genera una excepción. Se inspeccionan las sentencias compuestas: parastatement1 PARALLEL WITH statement2 ...yEXECUTE AS <user> <statement>, las reglas anteriores se aplican a las sentencias encapsuladas, ya que son las que se ejecutan (cada una con una copia del contexto del controlador, que conserva el modoreadonly). UnEXECUTE AS <user>sin sentencia hace que toda la sesión se ejecute como otro usuario, por lo que cuenta como una modificación de la sesión por sí mismo. Además, cualquier controladorEXECUTE AS, ya sea sin sentencia o encapsulando una sentencia, debe permitir al menos un método de modificación: la suplantación requiere el privilegioIMPERSONATE, que el modoreadonlyde los métodos seguros deniega.TYPE— opcional. Por ahora, el único tipo compatible esquery.AS— la consulta SQL que invocará este handler. La consulta puede parametrizarse. Durante la creación o modificación del handler, se analiza la corrección sintáctica de la consulta, pero no su semántica; por ejemplo, las tablas a las que hace referencia pueden no existir en el momento de crear el handler. Las cláusulasFORMATy similares pertenecen a la consulta, no a toda la sentenciaCREATE/ALTER. La consulta puede incluirse entre paréntesis para evitar ambigüedades. Una consultaINSERTno debe contener datos en línea después de la cláusulaVALUESoFORMAT: crear o modificar un handler de este tipo genera una excepción, ya que la carga útil en línea no puede conservarse en la definición del handler; los datos deben proporcionarse en el cuerpo HTTP (o calcularse mediante unINSERT ... SELECT). Una solicitud a un handler cuya consulta lee el cuerpo —unINSERTque toma sus datos del cuerpo o una consulta que utiliza el parámetro_request_body— debe declarar su longitud: una solicitud no fragmentada sin un encabezadoContent-Lengthrecibe la respuesta411 Length Required, ya que, de lo contrario, el cuerpo se leería hasta el final del flujo y una conexión interrumpida se aceptaría como una solicitud completa. Todos los métodos de dicho handler también deben incluir un cuerpo (POST,PUToDELETE): crearlo con un método seguro en la cláusulaMETHODS(por ejemplo, elGETpredeterminado) genera una excepción, porque un método seguro nunca proporciona un cuerpo de solicitud y la consulta leería silenciosamente uno vacío; unGETdeclarado también se sirve paraHEAD, por lo que mezclar métodos seguros y métodos con cuerpo mantendría accesibles esas invocaciones. UnINSERT ... SELECTno lee el cuerpo (sus datos proceden delSELECT), por lo que no está sujeto a estos requisitos, salvo que suSELECTlea de la función de tablainput, que recibe datos del cuerpo de la solicitud. UnINSERTque lee el cuerpo debe ser la propia consulta del handler:EXECUTE ASyPARALLEL WITHejecutan las sentencias que contienen sin el cuerpo de la solicitud, por lo que envolver uno en ellas se rechaza al crearlo en lugar de descartar silenciosamente cada carga. Una consulta que lee el cuerpo tampoco debe utilizar el parámetro_request_body: hay un único cuerpo de solicitud, y la vinculación de_request_bodylo consume antes de que la consulta lea sus datos de entrada, por lo que dicho handler se rechaza al crearlo en lugar de perder silenciosamente cada carga; utilice la propia entrada del cuerpo de la consulta o_request_body, pero no ambos. Los handlers que no leen el cuerpo no tienen este requisito; el cuerpo de una solicitud a dicho handler se ignora y nunca se añade a la consulta del handler. El texto de consulta almacenado vuelve a analizarse en el servidor con profundidad del analizador y retrocesos ilimitados cada vez que se recarga o invoca el handler, por lo que un handler creado en una sesión conmax_parser_depth/max_parser_backtracksaumentados sigue pudiendo cargarse e invocarse con los límites habituales de sesión.
Prioridad
Los handlers definidos en la configuración del servidor tienen prioridad sobre los definidos en SQL. Los handlers definidos en SQL se comparan en orden lexicográfico según sus nombres.
Parámetros
Los parámetros de consulta para consultas parametrizadas se proporcionan, al igual que en los handlers definidos mediante configuración, a partir de:
- parámetros de URL HTTP en la cadena de consulta, mediante la convención
param_<name>(por ejemplo,?param_id=42vincula{id:Type}); - grupos de captura con nombre en una
URL REGEXP(por ejemplo,URL REGEXP '/users/(?P<id>\d+)'vincula{id:Type}); - campos de formulario del cuerpo de la solicitud, para un handler cuya consulta declara parámetros: un cuerpo
application/x-www-form-urlencoded(por ejemplo,curl -d 'param_id=42') y los campos de un cuerpomultipart/form-datavinculan parámetros{name:Type}de la misma forma que los parámetros de URL en los métodos con cuerpoPOST,PUTyDELETE. Un parámetro presente tanto en la URL como en el cuerpo toma su valor de la URL. Un cuerpo analizado como formulario es consumido por la capa de handlers: no se pasa a la consulta como datos deINSERT. Un handler cuyo único uso del cuerpo es_request_bodyrecibe el cuerpo sin procesar en lugar de analizarlo como formulario; un handler que declara_request_bodyjunto con otros parámetros recibe ambos: se conserva una copia del cuerpo sin procesar en_request_body(sujeta ahttp_max_request_param_data_size) antes de analizar el cuerpo como formulario.
Los encabezados HTTP estándar de ClickHouse (como X-ClickHouse-Database, X-ClickHouse-User y X-ClickHouse-Key) se respetan como de costumbre al invocar un handler.
Las funciones currentHandler y currentRequestURL se pueden utilizar para personalizar el comportamiento de la consulta según el handler invocado y la URL de la solicitud.
Control de acceso
CREATE HANDLER, DROP HANDLER y ALTER HANDLER requieren los privilegios CREATE HANDLER, DROP HANDLER y ALTER HANDLER, respectivamente.
La lectura de la tabla system.handlers requiere el privilegio SHOW HANDLERS. Los secretos que puedan estar incluidos en la consulta de un handler se ocultan allí, a menos que el usuario también tenga permiso para ver secretos (consulte system.handlers).
La invocación de un handler no requiere ningún privilegio independiente, pero los privilegios se comprueban como de costumbre durante la invocación de la consulta y la autenticación funciona de la forma habitual. Para encapsular el acceso a determinadas consultas, cree una VIEW con SQL SECURITY DEFINER y defina un handler que seleccione de esa vista.
Almacenamiento
Los handler se guardan en un almacenamiento local o de Keeper, de forma similar a las colecciones con nombre, configurado en la sección query_rules_storage del archivo de configuración:
<query_rules_storage>
<type>local</type> <!-- or zookeeper -->
<path>/var/lib/clickhouse/handlers/</path>
</query_rules_storage>Con el almacenamiento Keeper, los handlers se sincronizan automáticamente en todas las réplicas, por lo que una cláusula ON CLUSTER explícita es redundante y haría que cada réplica intentara crear el mismo handler. Habilite la configuración ignore_on_cluster_for_replicated_handler_queries para que CREATE, ALTER y DROP HANDLER ignoren ON CLUSTER cuando el almacenamiento sea replicado, al igual que ignore_on_cluster_for_replicated_named_collections_queries.
ALTER HANDLER
ALTER HANDLER name
[PROTOCOL protocol_name|ANY]
[URL [PREFIX|REGEXP] '/path']
[METHODS (GET, POST)]
[TYPE query]
[AS SELECT ...]Reemplaza el handler por uno nuevo. La consulta ALTER solo puede incluir un subconjunto de cláusulas; por ejemplo, puede utilizarse únicamente para cambiar la URL o la consulta. Las cláusulas no especificadas conservan sus valores anteriores. PROTOCOL ANY elimina una restricción de protocolo existente, lo que vuelve a activar el handler en todos los endpoints HTTP.
DROP HANDLER
DROP HANDLER [IF EXISTS] nameElimina el handler con el nombre especificado.
Introspección
La tabla system.handlers enumera todos los handlers definidos en SQL. La tabla system.query_log registra, para cada consulta, el nombre del handler y la ruta de la solicitud HTTP (sin la cadena de consulta) en las columnas http_handler_name y http_request_url.
Ejemplo
CREATE HANDLER my_handler URL '/my_handler' AS SELECT version();$ curl 'http://localhost:8123/my_handler'Un handler parametrizado con una URL con formato Regexp:
CREATE HANDLER get_user URL REGEXP '/users/(?P<id>\d+)' AS SELECT * FROM users WHERE id = {id:UInt64};$ curl 'http://localhost:8123/users/42'CREATE HANDLER forma parte de la familia de sentencias CREATE y se relaciona con ALTER y DROP.