TIME
wartości były zawsze przechowywane na 3 bajtach w MySQL. Ale format zmienił się w wersji 5.6 .4
. Podejrzewam, że to nie był pierwszy raz, kiedy to się zmieniło. Ale druga zmiana, jeśli była, miała miejsce dawno temu i nie ma na to publicznych dowodów. Historia kodu źródłowego MySQL na GitHub zaczyna się od wersji 5.5 (najstarsze zatwierdzenie pochodzi z maja 2008 r.), ale zmiana, której szukam, nastąpiła gdzieś w okolicach 2001-2002 (MySQL 4 został uruchomiony w 2003 r.)
Obecny format, zgodnie z opisem w dokumentacji, używa 6 bitów na sekundy (możliwe wartości:0
do 63
), 6 bitów na minuty, 10 bitów na godziny (możliwe wartości:0
do 1023
), 1 bit na znak (dodaj ujemne wartości wspomnianych już przedziałów) i 1 bit jest nieużywany i oznaczony jako „zarezerwowany na przyszłe rozszerzenia”.
Jest zoptymalizowany do pracy ze składnikami czasu (godziny, minuty, sekundy) i nie marnuje dużo miejsca. Przy użyciu tego formatu można przechowywać wartości między -1023:59:59
i +1023:59:59
. Jednak MySQL ogranicza liczbę godzin do 838
, prawdopodobnie dla wstecznej kompatybilności z aplikacjami, które zostały napisane jakiś czas temu, kiedy myślę, że to był limit.
Do wersji 5.6.4 TIME
wartości były również przechowywane na 3 bajtach, a komponenty były pakowane jako days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Ten format został zoptymalizowany do pracy ze znacznikami czasu (ponieważ w rzeczywistości był to znacznik czasu). Używając tego formatu, można by przechowywać wartości z zakresu około -2330
do +2330
godziny. Mając tak duży zakres dostępnych wartości, MySQL wciąż ograniczał wartości do -838
do +838
godziny.
Wystąpił błąd #11655
na MySQL 4. Można było zwrócić TIME
wartości poza -838..+838
zakres przy użyciu zagnieżdżonego SELECT
sprawozdania. To nie była funkcja, ale błąd i został naprawiony.
Jedynym powodem, aby ograniczyć wartości do tego zakresu i aktywnie zmieniać dowolny fragment kodu, który generuje TIME
wartości poza nią były zgodne z poprzednimi wersjami.
Podejrzewam, że MySQL 3 używał innego formatu, który ze względu na sposób pakowania danych ograniczył prawidłowe wartości do zakresu -838..+838
godzin.
Patrząc na aktualny kod źródłowy MySQL Znalazłem tę ciekawą formułę:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Na razie zignorujmy MAX
część nazw użytych powyżej i pamiętajmy tylko, że TIME_MAX_MINUTE
i TIME_MAX_SECOND
to liczby od 00
i 59
. Formuła po prostu łączy godziny, minuty i sekundy w jedną liczbę całkowitą. Na przykład wartość 170:29:45
staje się 1702945
.
Ta formuła rodzi następujące pytanie:biorąc pod uwagę, że TIME
wartości są przechowywane na 3 bajtach ze znakiem, jaka jest maksymalna dodatnia wartość, którą można przedstawić w ten sposób?
Szukana przez nas wartość to 0x7FFFFF
że w notacji dziesiętnej jest 8388607
. Od ostatnich czterech cyfr (8607
) należy odczytywać jako minuty (86
) i sekund (07
), a ich maksymalne poprawne wartości to 59
, największa wartość, która może być przechowywana na 3 bajtach ze znakiem przy użyciu powyższej formuły to 8385959
. Które, jak TIME
to +838:59:59
. Ta-da!
Zgadnij co? Fragment C
kod wymieniony powyżej został wyodrębniony z tego:
/* 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)
Jestem pewien, że w ten sposób MySQL 3 utrzymywał TIME
wartości wewnętrznie. Ten format narzucił ograniczenie zakresu, a wymóg kompatybilności wstecznej w kolejnych wersjach rozpropagował to ograniczenie do naszych czasów.