Skip to main content
Crée un gestionnaire HTTP personnalisé défini en SQL, sans modifier le fichier de configuration du serveur. Les gestionnaires définis en SQL constituent une alternative aux gestionnaires de l’interface HTTP configurés via la configuration.

Syntaxe

Crée un gestionnaire avec un nom spécifié. Le nom est utilisé pour gérer les gestionnaires à l’aide de requêtes SQL, pour les messages de diagnostic et pour définir leur ordre.

Clauses

  • PROTOCOL — facultatif. Si un nom de protocole est spécifié, le gestionnaire est actif uniquement pour le protocole composable indiqué. Sinon, le gestionnaire est actif sur tous les endpoints HTTP : les ports http/https intégrés et chaque écouteur de protocole composable de type HTTP. PROTOCOL ANY sélectionne explicitement ce comportement par défaut ; dans ALTER HANDLER, il supprime une restriction de protocole définie précédemment. Un protocole littéralement nommé any peut être référencé à l’aide d’accents graves : PROTOCOL `any` .
  • URL — obligatoire. Peut prendre la forme d’une URL exacte, d’un URL PREFIX ou d’un URL REGEXP. Pour les URL exactes et les préfixes, l’ambiguïté est vérifiée lors de la création ou de la modification, et une exception est levée en cas d’ambiguïté. Pour les expressions régulières, l’ambiguïté ne peut pas être vérifiée. L’URL est mise en correspondance sans la chaîne de requête ? ni l’identifiant de fragment #. Un URL PREFIX est mis en correspondance comme un chemin de base, à la limite d’un segment de chemin — avec la même sémantique que la règle url_prefix des gestionnaires définis par la configuration : URL PREFIX '/api/v1' correspond à /api/v1, /api/v1/ et /api/v1/write, mais pas à /api/v1beta. Un / final dans le préfixe est ignoré ; '/api/v1/' et '/api/v1' se comportent donc de la même manière.
  • METHODS — facultatif. Liste des méthodes HTTP autorisées. Par défaut, seule GET est autorisée. Les méthodes prises en charge sont GET, POST, PUT et DELETE. Les méthodes de modification POST, PUT et DELETE peuvent exécuter des requêtes modifiant des données ; les méthodes sûres telles que GET et HEAD sont toujours exécutées en mode readonly. Par conséquent, un gestionnaire dont la requête modifie des données (par exemple INSERT ou DDL) doit autoriser au moins une méthode de modification : créer un tel gestionnaire avec uniquement des méthodes en lecture seule (par exemple GET, la valeur par défaut) lève une exception. Les requêtes dont les effets secondaires subsistent en mode readonly constituent un cas particulier : BACKUP et RESTORE ont des effets secondaires durables, les instructions modifiant la session SET, SET ROLE, USE, BEGIN TRANSACTION, COMMIT, ROLLBACK et SET TRANSACTION SNAPSHOT modifient un état de session ou de transaction qui persiste entre les requêtes lorsque session_id est utilisé, et CREATE TEMPORARY TABLE / CREATE TEMPORARY VIEW créent un objet qui existe pendant la session — pourtant, le mode readonly des méthodes sûres ne bloque aucune d’entre elles. Les mutations d’une table temporaire existante ne sont pas non plus bloquées par le mode readonly. Les requêtes susceptibles d’en cibler une sont donc traitées de la même manière : un INSERT dont la table cible n’est pas qualifiée par une base de données (un nom non qualifié peut désigner une table temporaire de session), un DROP TEMPORARY TABLE, un DROP TABLE / TRUNCATE TABLE sur une table non qualifiée par une base de données, et un ALTER sur une table non qualifiée par une base de données (ALTER TEMPORARY TABLE est la même instruction). Une cible qualifiée par une base de données ne peut jamais être une table temporaire ; ces requêtes ne sont donc pas soumises à cette règle. HTTP exige que les méthodes sûres soient exemptes d’effets secondaires (un gestionnaire déclaré pour GET répond également à HEAD, pour lequel le corps de la réponse est supprimé et l’effet serait invisible). Un gestionnaire exécutant une telle requête doit donc répertorier uniquement des méthodes de modification : le créer ou le modifier pour inclure une méthode sûre lève une exception. Les instructions composites sont examinées en profondeur : pour statement1 PARALLEL WITH statement2 ... et EXECUTE AS <user> <statement>, les règles ci-dessus s’appliquent aux instructions encapsulées, car ce sont elles qui sont exécutées (chacune dans une copie du contexte du gestionnaire, qui conserve le mode readonly). Un EXECUTE AS <user> seul fait exécuter toute la session sous un autre utilisateur ; il est donc lui-même considéré comme modifiant la session. De plus, tout gestionnaire EXECUTE AS — seul ou encapsulant une instruction — doit autoriser au moins une méthode de modification : l’impersonation nécessite le privilège IMPERSONATE, que le mode readonly des méthodes sûres refuse.
  • TYPE — facultatif. Le seul type actuellement pris en charge est query.
  • AS — la requête SQL qui sera exécutée par ce gestionnaire. La requête peut être paramétrée. Sa validité syntaxique est vérifiée lors de la création ou de la modification du gestionnaire, mais elle n’est pas analysée davantage : par exemple, les tables auxquelles elle fait référence peuvent être absentes au moment de la création du gestionnaire. Les clauses FORMAT et similaires appartiennent à la requête, et non à l’instruction CREATE/ALTER dans son ensemble. La requête peut être placée entre parenthèses pour lever toute ambiguïté. Une requête INSERT ne doit pas contenir de données en ligne après la clause VALUES ou FORMAT : la création ou la modification d’un tel gestionnaire lève une exception, car la charge utile en ligne ne peut pas être conservée dans la définition du gestionnaire ; les données doivent être fournies dans le corps HTTP (ou calculées par un INSERT ... SELECT). Une requête adressée à un gestionnaire dont la requête lit le corps — un INSERT qui obtient ses données depuis le corps, ou une requête utilisant le paramètre _request_body — doit déclarer sa longueur : une requête sans transfert fragmenté et sans en-tête Content-Length reçoit la réponse 411 Length Required, car le corps serait sinon lu jusqu’à la fin du flux et une connexion interrompue serait acceptée comme une requête complète. Toutes les méthodes d’un tel gestionnaire doivent également accepter un corps (POST, PUT ou DELETE) — le créer avec une méthode sûre dans la clause METHODS (par exemple, GET par défaut) lève une exception, car une méthode sûre ne fournit jamais de corps de requête et la requête lirait silencieusement un corps vide ; un GET déclaré est également pris en charge pour HEAD, de sorte que mélanger des méthodes sûres et des méthodes acceptant un corps rendrait ces invocations accessibles. Un INSERT ... SELECT ne lit pas le corps (ses données proviennent du SELECT) et n’est donc pas soumis à ces exigences — sauf si son SELECT lit depuis la fonction de table input, qui est alimentée par le corps de la requête. Un INSERT lisant le corps doit être la requête propre au gestionnaire : EXECUTE AS et PARALLEL WITH exécutent les instructions qu’ils englobent sans le corps de la requête ; l’encapsuler dans l’une de ces instructions est donc rejeté lors de la création, plutôt que d’ignorer silencieusement chaque téléversement. Une requête lisant le corps ne doit pas non plus utiliser le paramètre _request_body : il n’existe qu’un seul corps de requête, et la liaison de _request_body le consomme avant que la requête ne lise ses données d’entrée ; un tel gestionnaire est donc rejeté lors de la création, plutôt que de perdre silencieusement chaque téléversement — utilisez soit la propre entrée depuis le corps de la requête, soit _request_body, mais pas les deux. Les gestionnaires qui ne lisent pas le corps ne sont soumis à aucune exigence de ce type ; le corps d’une requête adressée à un tel gestionnaire est ignoré et n’est jamais ajouté à la requête du gestionnaire. Le texte de requête stocké est analysé de nouveau par le serveur avec une profondeur d’analyseur syntaxique et un nombre de retours arrière illimités chaque fois que le gestionnaire est rechargé ou exécuté ; ainsi, un gestionnaire créé dans une session avec max_parser_depth / max_parser_backtracks augmentés reste chargeable et exécutable avec les limites de session ordinaires.

Priorité

Les gestionnaires définis dans la configuration du serveur sont prioritaires par rapport aux gestionnaires définis en SQL. Les gestionnaires définis en SQL sont associés dans l’ordre lexicographique de leurs noms.

Paramètres

Les paramètres de requête des requêtes paramétrées sont fournis, comme pour les gestionnaires définis dans la configuration, à partir des sources suivantes :
  • des paramètres d’URL HTTP dans la chaîne de requête, selon la convention param_<name> (par exemple, ?param_id=42 lie {id:Type}) ;
  • des groupes de capture nommés dans une URL REGEXP (par exemple, URL REGEXP '/users/(?P<id>\d+)' lie {id:Type}) ;
  • des champs de formulaire du corps de la requête, pour un gestionnaire dont la requête déclare des paramètres : un corps application/x-www-form-urlencoded (par exemple, curl -d 'param_id=42') et les champs d’un corps multipart/form-data lient les paramètres {name:Type} de la même manière que les paramètres d’URL, pour les méthodes acceptant un corps POST, PUT et DELETE. Un paramètre présent à la fois dans l’URL et dans le corps prend sa valeur dans l’URL. Un corps analysé comme un formulaire est consommé par la couche de gestionnaires : il n’est pas transmis à la requête en tant que données INSERT. Un gestionnaire dont la seule utilisation du corps est _request_body reçoit le corps brut au lieu qu’il soit analysé comme un formulaire ; un gestionnaire qui déclare _request_body avec d’autres paramètres reçoit les deux : une copie du corps brut, non analysé, est conservée dans _request_body (sous réserve de http_max_request_param_data_size) avant que le corps ne soit analysé comme un formulaire.
Les en-têtes HTTP ClickHouse standard (tels que X-ClickHouse-Database, X-ClickHouse-User, X-ClickHouse-Key) sont respectés comme d’habitude lors de l’appel d’un gestionnaire. Les fonctions currentHandler et currentRequestURL peuvent être utilisées pour personnaliser le comportement de la requête selon le gestionnaire appelé et l’URL de la requête.

Contrôle d’accès

CREATE HANDLER, DROP HANDLER et ALTER HANDLER requièrent respectivement les privilèges CREATE HANDLER, DROP HANDLER et ALTER HANDLER. La lecture de la table system.handlers requiert le privilège SHOW HANDLERS. Les secrets pouvant être intégrés à la requête d’un gestionnaire y sont masqués, à moins que l’utilisateur ne soit également autorisé à les consulter (voir system.handlers). L’appel d’un gestionnaire ne requiert aucun privilège distinct, mais les privilèges sont vérifiés comme d’habitude lors de l’exécution de la requête, et l’authentification fonctionne normalement. Pour encapsuler l’accès à certaines requêtes, créez une VIEW avec SQL SECURITY DEFINER et définissez un gestionnaire qui effectue un SELECT sur cette vue.

Stockage

Les gestionnaires sont enregistrés dans un stockage local ou Keeper, à l’instar des collections nommées, configuré dans la section query_rules_storage du fichier de configuration :
Avec le stockage Keeper, les gestionnaires sont automatiquement synchronisés sur l’ensemble des répliques. Une clause ON CLUSTER explicite est donc redondante et conduirait chaque réplique à tenter de créer le même gestionnaire. Activez le paramètre ignore_on_cluster_for_replicated_handler_queries afin que CREATE, ALTER et DROP HANDLER ignorent ON CLUSTER lorsque le stockage est répliqué, comme ignore_on_cluster_for_replicated_named_collections_queries.

ALTER HANDLER

Remplace le gestionnaire par un nouveau. La requête ALTER ne peut inclure qu’un sous-ensemble de clauses. Elle peut, par exemple, servir à modifier uniquement l’URL ou la requête. Les clauses non spécifiées conservent leurs valeurs précédentes. PROTOCOL ANY supprime une restriction de protocole existante et rend le gestionnaire à nouveau actif sur tous les endpoints HTTP.

DROP HANDLER

Supprime le gestionnaire portant le nom spécifié.

Introspection

La table system.handlers répertorie tous les gestionnaires définis en SQL. La table system.query_log enregistre, pour chaque requête, le nom du gestionnaire ainsi que le chemin de la requête HTTP (sans la chaîne de requête) dans les colonnes http_handler_name et http_request_url.

Exemple

Un gestionnaire paramétré avec une URL d’expression régulière :
CREATE HANDLER fait partie de la famille d’instructions CREATE et est lié à ALTER et DROP.
Dernière modification le 27 août 2026