Il TIME
i valori sono stati sempre memorizzati su 3 byte in MySQL. Ma il formato è cambiato su versione 5.6 .4
. Sospetto che questa non fosse la prima volta che cambiava. Ma l'altro cambiamento, se c'è stato, è avvenuto molto tempo fa e non ci sono prove pubbliche di ciò. La cronologia del codice sorgente di MySQL su GitHub inizia con la versione 5.5 (il commit più vecchio è di maggio 2008) ma il cambiamento che sto cercando è avvenuto da qualche parte intorno al 2001-2002 (MySQL 4 è stato lanciato nel 2003)
Il formato attuale, come descritto nella documentazione, utilizza 6 bit per secondi (possibili valori:0
a 63
), 6 bit per minuti, 10 bit per ore (valori possibili:0
a 1023
), 1 bit per segno (aggiungere i valori negativi degli intervalli già citati) e 1 bit è inutilizzato ed etichettato come "riservato per future estensioni".
È ottimizzato per lavorare con componenti temporali (ore, minuti, secondi) e non spreca molto spazio. Utilizzando questo formato è possibile memorizzare valori compresi tra -1023:59:59
e +1023:59:59
. Tuttavia MySQL limita il numero di ore a 838
, probabilmente per compatibilità con le versioni precedenti con applicazioni che sono state scritte tempo fa, quando penso che questo fosse il limite.
Fino alla versione 5.6.4, il TIME
anche i valori sono stati memorizzati su 3 byte e i componenti sono stati impacchettati come days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Questo formato è stato ottimizzato per lavorare con i timestamp (perché era, in effetti, un timestamp). Usando questo formato sarebbe possibile memorizzare valori nell'intervallo di circa -2330
a +2330
ore. Pur avendo a disposizione questa vasta gamma di valori, MySQL stava ancora limitando i valori a -838
a +838
ore.
C'era bug #11655
su MySQL 4. Era possibile restituire TIME
valori al di fuori del -838..+838
intervallo utilizzando SELECT
nidificato dichiarazioni. Non era una funzionalità ma un bug ed è stato corretto.
L'unico motivo per limitare i valori a questo intervallo e per modificare attivamente qualsiasi pezzo di codice che produce TIME
valori al di fuori era la compatibilità con le versioni precedenti.
Sospetto che MySQL 3 abbia utilizzato un formato diverso che, a causa del modo in cui i dati sono stati compressi, ha limitato i valori validi all'intervallo -838..+838
ore.
Esaminando l'attuale codice sorgente di MySQL Ho trovato questa formula interessante:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Ignoriamo per il momento il MAX
parte dei nomi usati sopra e ricordiamo solo che TIME_MAX_MINUTE
e TIME_MAX_SECOND
sono numeri compresi tra 00
e 59
. La formula concatena semplicemente ore, minuti e secondi in un unico numero intero. Ad esempio, il valore 170:29:45
diventa 1702945
.
Questa formula solleva la seguente domanda:dato che il TIME
i valori sono memorizzati su 3 byte con segno, qual è il massimo valore positivo che può essere rappresentato in questo modo?
Il valore che stiamo cercando è 0x7FFFFF
che in notazione decimale è 8388607
. Dalle ultime quattro cifre (8607
) devono essere letti come minuti (86
) e secondi (07
) e il loro valore massimo valido è 59
, il valore massimo che può essere memorizzato su 3 byte con segno utilizzando la formula sopra è 8385959
. Quale, come TIME
è +838:59:59
. Ta-da!
Indovina un po? Il frammento di C
il codice sopra elencato è stato estratto da questo:
/* Limits for the TIME data type */
#define TIME_MAX_HOUR 838
#define TIME_MAX_MINUTE 59
#define TIME_MAX_SECOND 59
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Sono sicuro che questo è il modo in cui MySQL 3 ha utilizzato per mantenere il TIME
valori internamente. Questo formato ha imposto la limitazione dell'intervallo e il requisito di compatibilità con le versioni precedenti ha propagato la limitazione ai nostri giorni.