Mysql
 sql >> Base de données >  >> RDS >> Mysql

Pourquoi la limite de temps maximale de MySQL est-elle de 838:59:59 ?

Le TIME les valeurs étaient toujours stockées sur 3 octets dans MySQL. Mais le format a changé sur version 5.6 .4 . Je soupçonne que ce n'était pas la première fois qu'il a changé. Mais l'autre changement, s'il y en a eu un, s'est produit il y a longtemps et il n'y a aucune preuve publique de cela. L'historique du code source MySQL sur GitHub commence avec la version 5.5 (le commit le plus ancien date de mai 2008) mais le changement que je recherche s'est produit vers 2001-2002 (MySQL 4 a été lancé en 2003)

Le format actuel, tel que décrit dans la documentation, utilise 6 bits pour les secondes (valeurs possibles :0 à 63 ), 6 bits pour les minutes, 10 bits pour les heures (valeurs possibles :0 à 1023 ), 1 bit pour le signe (ajoutez les valeurs négatives des intervalles déjà mentionnés) et 1 bit est inutilisé et étiqueté "réservé pour les extensions futures".

Il est optimisé pour travailler avec des composants de temps (heures, minutes, secondes) et ne gaspille pas beaucoup d'espace. En utilisant ce format, il est possible de stocker des valeurs entre -1023:59:59 et +1023:59:59 . Cependant MySQL limite le nombre d'heures à 838 , probablement pour la rétrocompatibilité avec des applications qui ont été écrites il y a quelque temps, alors que je pense que c'était la limite.

Jusqu'à la version 5.6.4, le TIME les valeurs étaient également stockées sur 3 octets et les composants étaient compressés en days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds . Ce format a été optimisé pour travailler avec des horodatages (car il s'agissait en fait d'un horodatage). En utilisant ce format, il serait possible de stocker des valeurs dans la plage d'environ -2330 au +2330 les heures. Tout en ayant cette large gamme de valeurs disponibles, MySQL limitait toujours les valeurs à -838 au +838 les heures.

Il y avait un bug #11655 sur MySQL 4. Il était possible de retourner TIME valeurs en dehors de -838..+838 plage en utilisant SELECT imbriqué déclarations. Ce n'était pas une fonctionnalité mais un bogue et il a été corrigé.

La seule raison de limiter les valeurs à cette plage et de modifier activement tout morceau de code qui produit TIME les valeurs en dehors de cela étaient la rétrocompatibilité.

Je soupçonne que MySQL 3 a utilisé un format différent qui, en raison de la façon dont les données ont été emballées, a limité les valeurs valides à la plage -838..+838 heures.

En regardant dans le le code source de MySQL J'ai trouvé cette formule intéressante :

#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)

Ignorons pour le moment le MAX partie des noms utilisés ci-dessus et retenons seulement que TIME_MAX_MINUTE et TIME_MAX_SECOND sont des nombres entre 00 et 59 . La formule concatène simplement les heures, les minutes et les secondes en un seul nombre entier. Par exemple, la valeur 170:29:45 devient 1702945 .

Cette formule pose la question suivante :étant donné que le TIME les valeurs sont stockées sur 3 octets avec signe, quelle est la valeur positive maximale qui peut être représentée de cette façon ?

La valeur que nous recherchons est 0x7FFFFF qui en notation décimale est 8388607 . Depuis les quatre derniers chiffres (8607 ) doit être lu comme des minutes (86 ) et secondes (07 ) et leurs valeurs valides maximales sont 59 , la plus grande valeur pouvant être stockée sur 3 octets avec signe en utilisant la formule ci-dessus est 8385959 . Qui, comme TIME est +838:59:59 . Ta-da !

Devinez quoi? Le fragment de C le code listé ci-dessus a été extrait de ceci :

/* 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)

Je suis sûr que c'est ainsi que MySQL 3 gardait le TIME valeurs en interne. Ce format a imposé la limitation de la gamme, et l'exigence de rétrocompatibilité sur les versions ultérieures a propagé la limitation à nos jours.