TIME
стойностите винаги се съхраняват на 3 байта в MySQL. Но форматът се промени на версия 5.6 .4
. Подозирам, че това не беше първият път, когато се промени. Но другата промяна, ако е имало такава, се е случила отдавна и няма публични доказателства за нея. Историята на изходния код на MySQL в GitHub започва с версия 5.5 (най-старият комит е от май 2008 г.), но промяната, която търся, се случи някъде около 2001-2002 г. (MySQL 4 беше пуснат през 2003 г.)
Текущият формат, както е описано в документацията, използва 6 бита за секунди (възможни стойности:0
до 63
), 6 бита за минути, 10 бита за часове (възможни стойности:0
до 1023
), 1 бит за знак (добавете отрицателните стойности на вече споменатите интервали) и 1 бит е неизползван и е обозначен като „резервиран за бъдещи разширения“.
Оптимизиран е за работа с времеви компоненти (часове, минути, секунди) и не губи много място. Използвайки този формат, е възможно да съхранявате стойности между -1023:59:59
и +1023:59:59
. Въпреки това MySQL ограничава броя часове до 838
, вероятно за обратна съвместимост с приложения, които бяха написани преди време, когато мисля, че това беше границата.
До версия 5.6.4, TIME
стойностите също бяха съхранени на 3 байта и компонентите бяха опаковани като days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds
. Този формат беше оптимизиран за работа с времеви печати (защото всъщност беше времеви печат). Използването на този формат би било възможно да се съхраняват стойности в диапазона от около -2330
до +2330
часа. Въпреки че разполагаше с този голям диапазон от стойности, MySQL все още ограничаваше стойностите до -838
до +838
часа.
Имаше бъг №11655
на MySQL 4. Беше възможно да се върне TIME
стойности извън -838..+838
диапазон с помощта на вложен SELECT
изявления. Това не беше функция, а грешка и беше отстранена.
Единствената причина да ограничите стойностите до този диапазон и активно да промените всяка част от кода, която произвежда TIME
стойности извън него беше обратна съвместимост.
Подозирам, че MySQL 3 използва различен формат, който поради начина, по който данните бяха опаковани, ограничи валидните стойности до диапазона -838..+838
часа.
Като разгледате текущия изходния код на MySQL Намерих тази интересна формула:
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
Нека игнорираме за момента MAX
част от използваните по-горе имена и нека запомним само това TIME_MAX_MINUTE
и TIME_MAX_SECOND
са числа между 00
и 59
. Формулата просто обединява часовете, минутите и секундите в едно цяло число. Например стойността 170:29:45
става 1702945
.
Тази формула повдига следния въпрос:като се има предвид, че TIME
Стойностите се съхраняват на 3 байта със знак, каква е максималната положителна стойност, която може да бъде представена по този начин?
Стойността, която търсим, е 0x7FFFFF
това в десетичния запис е 8388607
. Тъй като последните четири цифри (8607
) трябва да се чете като минути (86
). ) и секунди (07
). ) и техните максимални валидни стойности са 59
, най-голямата стойност, която може да бъде съхранена на 3 байта със знак, като се използва формулата по-горе, е 8385959
. Което, като TIME
е +838:59:59
. Та-да!
Познай какво? Фрагментът на C
кодът, изброен по-горе, е извлечен от това:
/* 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)
Сигурен съм, че това е начинът, по който MySQL 3 използваше TIME
вътрешно ценности. Този формат наложи ограничението на обхвата, а изискването за обратна съвместимост на следващите версии разпространи ограничението до наши дни.