From 22927a2930190d50d290fe35345ae7132842c58a Mon Sep 17 00:00:00 2001 From: Tallagrand Thierry Date: Sat, 5 Sep 2026 03:15:15 +0200 Subject: [PATCH] Transtypage des parametres : aucun UPDATE de session n'aboutissait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `operator is not unique: unknown * unknown`. node-postgres envoie ses parametres SANS type ; multiplier deux d'entre eux ne permet pas a PostgreSQL de choisir un operateur. Et contrairement a ce que j'ai d'abord annonce, ce n'est pas l'ajout de la part reseau qui a casse la ligne : les DEUX lignes en souffraient. La premiere version du detecteur de session n'a jamais reussi un seul UPDATE — la session enregistree a 02:56 affichait 0,000 kWh avec fin = debut, seul l'INSERT avait abouti. Verifie en rejouant les trois formes contre la vraie base : l'ancienne echoue, la nouvelle passe. Lecon consignee dans le README : l'essai a blanc remplace l'envoi a la base par un compteur, donc il valide la logique et JAMAIS le SQL. Une erreur de typage y est invisible par construction. D'ou la regle — tout parametre entrant dans un calcul porte son ::float8 — et l'obligation de lire le journal du conteneur apres chaque deploiement du service. Tableaux : 53/53 depuis que la colonne existe. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ --- deploy/historisation/README.md | 23 +++++++++++++++++++++++ tools/historise-evcs.mjs | 13 +++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/deploy/historisation/README.md b/deploy/historisation/README.md index 09c69f1..089059b 100644 --- a/deploy/historisation/README.md +++ b/deploy/historisation/README.md @@ -279,3 +279,26 @@ quel tableau de bord en crée une copie personnelle et modifiable. Il ne **stocke** rien : il interroge les deux bases à la demande. Le perdre ne perd aucune mesure. Il n'écrit rien non plus — sa connexion PostgreSQL utilise le rôle `evcs_lecture`, en lecture seule. + +### ⚠️ Ce que `--dry-run` ne peut pas vérifier + +L'essai à blanc remplace l'envoi à la base par un compteur : il valide la +logique, jamais le SQL. Une erreur de typage passe donc inaperçue. + +C'est arrivé le 05/09 : `energie_kwh + $3 * $4 / 3600000.0` échouait sur +`operator is not unique: unknown * unknown`, parce que node-postgres envoie ses +paramètres **sans type** et que PostgreSQL ne sait alors pas quel opérateur `*` +choisir. Aucun `UPDATE` de session n'a abouti pendant vingt minutes, et cela ne +s'est vu qu'au journal du conteneur. + +**Règle : tout paramètre entrant dans un calcul porte son `::float8`.** + +**Et après tout déploiement du service :** + +```bash +sudo docker compose restart historisation +sudo docker compose logs --tail=5 historisation +``` + +Une ligne `cycle en echec` vaut arrêt immédiat. Une ligne +`mesures=… session=…` vaut confirmation. diff --git a/tools/historise-evcs.mjs b/tools/historise-evcs.mjs index 4fd261c..85abb36 100644 --- a/tools/historise-evcs.mjs +++ b/tools/historise-evcs.mjs @@ -418,8 +418,17 @@ async function ecrireSession(sql, client, st) { await sql( `UPDATE session_charge SET fin = $2, - energie_kwh = energie_kwh + $3 * $4 / 3600000.0, - energie_reseau_kwh = energie_reseau_kwh + $8 * $3 * $4 / 3600000.0, + -- Transtypages EXPLICITES, sur TOUS les parametres. + -- node-postgres envoie ses parametres sans type ; multiplier deux + -- d'entre eux fait echouer PostgreSQL sur « operator is not unique: + -- unknown * unknown ». Les DEUX lignes en souffraient — la premiere + -- version de ce code n'a jamais reussi un seul UPDATE, ce qui ne + -- s'est vu qu'au journal du conteneur : l'essai a blanc court-circuite + -- l'envoi a la base et ne peut donc rien valider de ce genre. + -- REGLE : tout parametre entrant dans un calcul porte son ::float8. + energie_kwh = energie_kwh + $3::float8 * $4::float8 / 3600000.0, + energie_reseau_kwh = energie_reseau_kwh + + $8::float8 * $3::float8 * $4::float8 / 3600000.0, p_max_w = GREATEST(coalesce(p_max_w, 0), $3), courant_max_a = GREATEST(coalesce(courant_max_a, 0), coalesce($5, 0)), consigne_max_a = GREATEST(coalesce(consigne_max_a, 0), coalesce($6, 0)),