TIME
hodnoty byly v MySQL vždy uloženy na 3 bytech. Formát se však změnil ve verze 5.6 .4
. Tuším, že to nebylo poprvé, kdy se to změnilo. Ale ta druhá změna, pokud nějaká byla, se stala už dávno a neexistuje o ní žádný veřejný důkaz. Historie zdrojového kódu MySQL na GitHubu začíná verzí 5.5 (nejstarší commit je z května 2008), ale ke změně, kterou hledám, došlo někde kolem roku 2001-2002 (MySQL 4 byla spuštěna v roce 2003)
Aktuální formát, jak je popsán v dokumentaci, používá 6 bitů na sekundy (možné hodnoty:0
až 63
), 6 bitů pro minuty, 10 bitů pro hodiny (možné hodnoty:0
na 1023
), 1 bit pro znaménko (přičtěte záporné hodnoty již zmíněných intervalů) a 1 bit je nepoužitý a označený jako "rezervováno pro budoucí rozšíření".
Je optimalizován pro práci s časovými složkami (hodiny, minuty, sekundy) a nezabírá mnoho místa. Pomocí tohoto formátu je možné ukládat hodnoty mezi -1023:59:59
a +1023:59:59
. MySQL však omezuje počet hodin na 838
, pravděpodobně kvůli zpětné kompatibilitě s aplikacemi, které byly napsány před chvílí, kdy si myslím, že toto byl limit.
Do verze 5.6.4 TIME
hodnoty byly také uloženy na 3 bytech a komponenty byly zabaleny jako days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Tento formát byl optimalizován pro práci s časovými razítky (protože se ve skutečnosti jednalo o časové razítko). Pomocí tohoto formátu by bylo možné ukládat hodnoty v rozsahu přibližně -2330
na +2330
hodin. I když byl k dispozici tento velký rozsah hodnot, MySQL stále omezovalo hodnoty na -838
na +838
hodin.
Vyskytla se chyba č. 11655
na MySQL 4. Bylo možné vrátit TIME
hodnoty mimo -838..+838
rozsah pomocí vnořeného SELECT
prohlášení. Nebyla to funkce, ale chyba a byla opravena.
Jediný důvod k omezení hodnot na tento rozsah a k aktivní změně jakékoli části kódu, která vytváří TIME
hodnoty mimo to byla zpětná kompatibilita.
Mám podezření, že MySQL 3 používal jiný formát, který kvůli způsobu sbalení dat omezil platné hodnoty na rozsah -838..+838
hodin.
Nahlédnutím do aktuálního zdrojového kódu MySQL Našel jsem tento zajímavý vzorec:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
V tuto chvíli ignorujme MAX
část jmen použitých výše a pamatujme si pouze to TIME_MAX_MINUTE
a TIME_MAX_SECOND
jsou čísla mezi 00
a 59
. Vzorec pouze zřetězí hodiny, minuty a sekundy do jediného celého čísla. Například hodnota 170:29:45
se změní na 1702945
.
Tento vzorec vyvolává následující otázku:vzhledem k tomu, že TIME
hodnoty jsou uloženy na 3 bytech se znaménkem, jaká je maximální kladná hodnota, která může být tímto způsobem znázorněna?
Hodnota, kterou hledáme, je 0x7FFFFF
že v desítkovém zápisu je 8388607
. Od posledních čtyř číslic (8607
) je třeba číst jako minuty (86
) a sekundy (07
) a jejich maximální platné hodnoty jsou 59
, největší hodnota, kterou lze uložit na 3 bajty se znaménkem pomocí výše uvedeného vzorce, je 8385959
. Což jako TIME
je +838:59:59
. Ta-da!
Hádej co? Fragment C
kód uvedený výše byl extrahován z tohoto:
/* 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)
Jsem si jistý, že takhle MySQL 3 udržovala TIME
hodnoty vnitřně. Tento formát ukládal omezení rozsahu a požadavek na zpětnou kompatibilitu u následujících verzí toto omezení rozšířil až do dnešních dnů.