Introduzione
Nell’ambito di un complesso progetto rivolto alla pubblicazione di contenuti multimediali che usa Drupal 9/10 come piattaforma di presentazione, ho avuto la necessità di caricare manualmente dei “nodi” che in realtà erano miei contenuti raccolti da numerose query eseguite su Microsoft Sql Server e Oracle. Per non farci mancare niente questi DB erano molto vecchi e, per non farci mancare proprio niente, altri dati li ho recuperati da vecchi FileMaker.
Drupal vuole un UUID e, se non glielo dai, lo calcola da solo. Potevo dargli in pasto circa 45000 nodi e farglieli battezzare con un UUID di suo piacimento? Se poi avessi avuto bisogno di ritrovare un tal record del tal database nel nuovo sistema, ad esempio per aggiornarlo programmaticamente? Con la lanterna?
Soluzione
La soluzione era quella di dare a Drupal l’UUID già compilato, in modo tale che non se lo dovesse inventare e che io ne rimanessi il gestore, con una tabella di origine in cui il UUID corrisponde a quello finale.
Il calcolo dell’UUID v5
Come spesso avviene nell’open source, qualcuno (grazie https://gist.github.com/merkushin) aveva già fatto il lavoro sporco e scritto una magnifica query per calcolare l’UUID5 in modo random. Sono partito da qui:
https://gist.github.com/merkushin/f4845b7f7522fa0a9a8ab70d74485a39
ma poi ho dovuto trovare il modo di mantenere sempre uguale il risultato; cioè, se avessi eseguito il calcolo dell’UUID di una tal record anche fra 10 anni, per update o altro, il risultato doveva essere lo stesso (per quello specifico record solamente, bisogna ricordare che UUID deve essere univoco o sono dolori). Quindi ho elaborato una funzione di MySql e cambiato il tipo risultante in varchar e messo tutto in minuscolo.
CREATE DEFINER=`root`@`%` FUNCTION `uuid_v5`(ns CHAR(36), name VARCHAR(2000)) RETURNS varchar(255) CHARSET utf8
BEGIN
SET @ns_bin = uuid_to_bin(ns);
SET @prehash_value = CONCAT(@ns_bin, name);
SET @hashed_value = SHA1(@prehash_value);
SET @time_hi = MID(@hashed_value, 13, 4);
SET @time_hi = CONV(@time_hi, 16, 10) & 0x0fff;
SET @time_hi = @time_hi & ~(0xf000);
SET @time_hi = @time_hi | (5 << 12);
SET @clock_seq_hi = MID(@hashed_value, 17, 2);
SET @clock_seq_hi = CONV(@clock_seq_hi, 16, 10);
SET @clock_seq_hi = @clock_seq_hi & 0x3f;
SET @clock_seq_hi = @clock_seq_hi & ~(0xc0);
SET @clock_seq_hi = @clock_seq_hi | 0x80;
SET @time_low = LEFT(@hashed_value, 8);
SET @time_mid = MID(@hashed_value, 9, 4);
SET @time_hi_and_version = lpad(conv(@time_hi, 10, 16), 4, '0');
SET @clock_seq_hi_and_reserved = lpad(conv(@clock_seq_hi, 10, 16), 2, '0');
SET @clock_seq_low = MID(@hashed_value, 19, 2);
SET @node = lpad(MID(@hashed_value, 21, 12), 12, '0');
SET @clock_seq = CONCAT(@clock_seq_hi_and_reserved, @clock_seq_low);
SET @uuid_str = CONCAT_WS('-', @time_low, @time_mid, @time_hi_and_version, @clock_seq, @node);
RETURN LOWER(@uuid_str);
END
La funzione prenderà in parametri due valori: il primo è un UUID (certo, così ho una “firma”) che ho cambiato a seconda della categoria di opere inserite (per evitare collisioni tra opere aventi lo stesso numero di catalogo); la seconda è l’indice del nodo, in pratica il numero di catalogo. Bene, ora restava solo la query (ovviamente pubblico solo la parte rilevante):
SELECT
uuid_v5('09b3c5b2-d762-5d44-9868-f588f09364f8', nid) as uid5, CCID
FROM Cinquecentine
Ecco, ora per ogni record della tabella cinquecentine si calcola il valore del campo UUID “personalizzato” e controllato.