Long integer is transformed when inserted in short

2019-01-07 00:12发布

I have a column of type integer with length 10:

`some_number` int(10) unsigned NOT NULL

Into this column I insert a number that is too long:

$some_number = 715988985123857;
$query = "INSERT INTO this_table SET some_number = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i', $some_number);
$stmt->execute();

When I look at what is in the table, the number is now:

2147483647

How and why did 715988985123857turn into 2147483647?
Why didn't it get truncated?
What is the mechanism behind this transformation, and can the resulting number be calculated with some formula?


I'm not looking for a solution. I just want to understand the specific number.

3条回答
Animai°情兽
2楼-- · 2019-01-07 00:16

http://dev.mysql.com/doc/refman/5.0/en/integer-types.html

The integer overflow will set the max allowed number in the DB as

2147483647

So you need bigint datatype for storing bigger integer

查看更多
Summer. ? 凉城
3楼-- · 2019-01-07 00:26

Well as far as i know, it doesn't have anything to do with PHP, bcx.

  • If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead.
  • Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.

So it will be the functionality of SQL which changes the value.

查看更多
孤傲高冷的网名
4楼-- · 2019-01-07 00:38

How and why did 715988985123857turn into 2147483647?
Why didn't it get truncated?
What is the mechanism behind this transformation, and can the resulting number be calculated with some formula?

The behavior depends on MySQL Strict SQL Mode setting:

Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE.

There is a chapter in MySQL manual explaining how MySQL handles out-of-range values: Out-of-Range and Overflow Handling:

[...] If no restrictive modes are enabled, MySQL clips the value to the appropriate endpoint of the range and stores the resulting value instead.

In case of Integer Type, the maximum value is:

  • 2147483647 for signed type
  • 4294967295 for unsigned type

Since your query did not throw error, but instead, the column got updated with max allowed value, you can assume that Strict SQL Mode is not enabled on your server. You can verify that by running:

SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;

None of them will contain STRICT_TRANS_TABLES nor STRICT_ALL_TABLES values (more about the values in MySQL man: sql_mode).
Take this example to test the different behaviors between modes:

mysql> create table test_sql_mode(id int);
mysql> set sql_mode = 'STRICT_TRANS_TABLES';
mysql> SELECT @@SESSION.sql_mode;
+---------------------+
| @@SESSION.sql_mode  |
+---------------------+
| STRICT_TRANS_TABLES |
+---------------------+
1 row in set (0.00 sec)

mysql> insert into test_sql_mode(id) value(123456789123456789);
ERROR 1264 (22003): Out of range value for column 'id' at row 1

mysql> select * from test_sql_mode;
Empty set (0.00 sec)

mysql> set sql_mode = '';
mysql> SELECT @@SESSION.sql_mode;
+--------------------+
| @@SESSION.sql_mode |
+--------------------+
|                    |
+--------------------+
1 row in set (0.00 sec)

mysql> insert into test_sql_mode(id) value(123456789123456789);
Query OK, 1 row affected, 1 warning (0.05 sec)

mysql> show warnings;
+-------+------+---------------------------------------------+
| Level | Code | Message                                     |
+-------+------+---------------------------------------------+
| Error | 1264 | Out of range value for column 'id' at row 1 |
+-------+------+---------------------------------------------+

mysql> select * from test_sql_mode;
+------------+
| id         |
+------------+
| 2147483647 |
+------------+
1 row in set (0.00 sec)

In short, with strict mode out-of-range value produces an error, without - the value gets adjusted to the allowed limit and a warning is produced.


As for this question:

can the resulting number be calculated with some formula?

I'm not aware of any simple and pure MySQL formula. You would have to check the data type and length:

select data_type, numeric_precision, numeric_scale
from information_schema.columns
where table_schema = "test_database"
and table_name = "test_sql_mode"
and column_name = "id"

...and based on that determine allowed limit.

Non-sql? Data validation (server- and client-side) is the solution.

查看更多
登录 后发表回答