Numbers in Drupal
...may not be exactly as you expect them to be...
I became curious about numbers in Drupal after entering a number with many decimal places and finding that Drupal gave me an error. I’m keeping this running notebook of things I’ve tried and/or discovered.
Thundernumber
Let’s start by generating a number that’s sufficiently large, that we can tweak in our explorations. One hundred digits should do! Here’s some Python to generate a hundred-digit number (let’s call it our thundernumber, after the hundred-letter thunderwords in James Joyce’s Finnegan’s Wake):
$ python3
>>> thundernumber = ""
>>> for x in "1234567890":
... thundernumber += x + "234567890"
...
>>> thundernumber
'12345678902234567890323456789042345678905234567890
62345678907234567890823456789092345678900234567890'
>>> len(thundernumber)
100
The Mystery of the Minimum and Maximum Integer Values
Let’s make a new Content Type, with a bunch of varied number fields. We’ll call it “Numbers”:
Let’s get rid of the “body” field and add some number fields.
First, let’s create a field called integer
. We’ll set
its maximum value to our thundernumber and its minimum to its
negative
We can do this without an error, but when we try to edit the field again, something unusual has happened:
The maximum has been changed from our thundernumber to
9223372036854775807
, and the minimum is now
-9223372036854775808
.
>>> 9223372036854775807 + (-9223372036854775808)
-1
Huh. I’m guessing that Drupal has provided the maximum and minimum values allowable by MySQL, the database running under the hood. If this is the case, how many unique integers can this represent?
>>> 9223372036854775808 * 2
18446744073709551616
This should account for all the negative integers, plus all of the positive integers, plus 0. I’m curious whether this is a large power of two. The first prime factorization calculator Google turned up cannot handle numbers this big, so let’s check if this is the case ourselves by dividing this number by two as many times as we can:
min_to_max = 18446744073709551616
quotients = [min_to_max]
while min_to_max > 1:
div, mod = divmod(min_to_max, 2)
quotients.append(div)
if mod != 0:
print("not divisible by 2!")
break
min_to_max = div
print(f"{quotients=}, {len(quotients)=}")
It outputs:
quotients=[18446744073709551616, 9223372036854775808, 4611686018427387904, 2305843009213693952, 1152921504606846976, 576460752303423488, 288230376151711744, 144115188075855872, 72057594037927936, 36028797018963968, 18014398509481984, 9007199254740992, 4503599627370496, 2251799813685248, 1125899906842624, 562949953421312, 281474976710656, 140737488355328, 70368744177664, 35184372088832, 17592186044416, 8796093022208, 4398046511104, 2199023255552, 1099511627776, 549755813888, 274877906944, 137438953472, 68719476736, 34359738368, 17179869184, 8589934592, 4294967296, 2147483648, 1073741824, 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1], len(quotients)=65
Just to check we’ve done this right,
>>> 2**64 # quotients includes 1, so we need to raise 2 to the 64
>>> # instead of to the 65
18446744073709551616
Okay! So it looks like Drupal is using 64-bit signed integers. And
a quick google search confirms that 9223372036854775807
and
-9223372036854775808
are in fact the maximum and minimum
values that can be stored in a 64-bit signed integer. In a perfect
world, I feel that Drupal would give you a warning if you tried to enter
a number beyond these values, but at least it makes some sort of
sense.
Given that there are minimum and maximum values for the minimum and maximum fields themselves, I’m curious about what happens if you make a field without setting a minimum or maximum value, and then try to enter a larger number in that field. The help text on the Maximum field says “leave blank for no maximum”—is there actually no maximum?
Let’s create a new Integer field on our Numbers content type. Let’s call it “unlimited integer”
If I try to create a new Numbers node and try to enter our thundernumber in the “unlimited integer” field, there are three things I can imagine happening:
- Drupal gives us an error message
- Drupal accepts the value, and the database stores it faithfully
- Drupal accepts the value, but the database stores the maximum possible value for a 64-bit signed integer
Let’s find out!
Huh. So Drupal gives us an error message, but the message doesn’t mention a maximum or minimum value. I’m guessing that, according to MySQL, an integer greater than the largest possible 64-bit signed integer is not of the same “primitive type” as a 64-bit integer, and that Drupal simply passes the MySQL error message along to the user. Understandable, but not ideal!
To test the theory that this is a 64-bit signed integer thing, I
tried saving 9223372036854775807
into our “unlimited
integer” field - it saves just fine. But
9223372036854775808
? “This value should be of the correct
primitive type.”
Further, to test the theory that this is an error message being passed from the database, we should check what happens when a user enters a value beyond the configured minimum and maximum. If we create an integer field (let’s call it “million integer”), with a maximum of 1000000, what happens when we try to save a larger number into that field? Do we get the same kind of error message?
So that settles it. Drupal catches values that don’t fit within the minimum-maximum range and displays its own little pop-up error messages when it does. But if there is no minimum or maximum set, it will attempt to send any number to the database. And when the database complains that some number cannot be saved into a 64-bit signed integer field, Drupal simply echoes the database’s complaint.
Posted: Jun 07, 2024. Last updated: Jun 10, 2024.