Mysql
 sql >> база данни >  >> RDS >> Mysql

Защо максималното време на MySQL е 838:59:59?

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 вътрешно ценности. Този формат наложи ограничението на обхвата, а изискването за обратна съвместимост на следващите версии разпространи ограничението до наши дни.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Свързване към mySQL база данни с помощта на asp.net

  2. Генерирайте произволна LocalDate с java.time

  3. Ruby on Rails 3 не може да се свърже с локален MySQL сървър чрез сокет '/tmp/mysql.sock' на OSX

  4. php сървър ERR_CONNECTION_REFUSED

  5. Разработка на Rails - Не мога да се свържа с MySQL сървър на 'localhost' (10061)