-
Notifications
You must be signed in to change notification settings - Fork 11k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[6.x] Fix can't insert float into MySQL with PHP 7.3 #31100
Conversation
When inserting a float value into MySQL via the Illuminate\Database package when using at least PHP 7.3, the value is converted to an int. The bug has been reported a few times before: * laravel#30435 * illuminate/database#246 PR laravel#16069 introduced logic to the MySQLConnection that cast floats to ints to address a comparison problem with JSON columns, which was reported in issue laravel#16063. This does not seem to cause a problem with PHP 7.1 and below but causes the float to lose it's decimal places when using PHP 7.3. I have not tested with PHP 7.2. Given we have the following MySQL table: ``` CREATE TABLE `zip_codes` ( `zip_code` varchar(255) NOT NULL, `latitude` decimal(15,10) NOT NULL, `longitude` decimal(15,10) NOT NULL ) ``` When we execute the following using Artisan Tinker: ```php DB::table('zip_codes')->delete(); // Using the same values $lat = -0.2; $lon = 0; $sql = 'INSERT INTO zip_codes (latitude, longitude, zip_code) VALUES (:lat, :long, :zip)'; // We insert the first by using PDO directly $values = [':lat' => $lat, ':long' => $lon, ':zip' => 1]; DB::connection()->getPdo()->prepare($sql)->execute($values); // Then the second by using Eloquent DB::table('zip_codes')->insert(['latitude' => $lat, 'longitude' => $lon, 'zip_code' => 2]); // Then pull them both. DB::table('zip_codes')->get(); ``` Then we should see both records with -0.2 as the latitude. But only the first has the value, and the second row is zero.
This comment is relevant to this PR: #23850 (comment) |
It seems as if the emulated prepared statements were broken prior to PHP 7.2, and that's why the What is the policy regarding logic that is required to work around a bug with a specific PHP version? Do we do a PHP version check in the code and apply the check conditionally? |
Laravel 6.x already requires PHP 7.2 or higher. |
OK, so it's an easy choice for Laravel 6.x. But what about the LTS: 5.5? |
Laravel 5 stopped receiving bug fixes when Laravel 6 was released. This included 5.5 LTS. |
Laravel 5.5 LTS will continue to get security fixes until the end of August this year. Laravel 6 is the new LTS release. |
So we are expecting just deleting code to cause absolutely no problems? 🤔 |
We will need tests verifying this does break what it was intended to fix regarding JSON comparison. Do we have those? |
Are you using emulate prepares? |
Yes, I am expecting that. The code was added to address a problem with PDO emulated prepared statements prior to PHP 7.2, I do not believe it is required any longer. The code being deleted was added by #16069. That was merged without requiring tests to confirm there was a problem and that the PR resolved it. I would normally write tests for my PR, but I took that as a precedence to indicate that this situation does not require a test. I will have to look into writing tests. Yes, I am using emulated prepares. |
We will definitely want tests on this to confirm the problem fixed by #16069 is fixed before merging this. |
Do any of your existing test environments have access to a real MySQL database? |
Yes, the unit tests on travis run against a real mysql database. |
The only reference I can find to a MySQL connection in the test code is |
Nevermind, I found it. https://docs.travis-ci.com/user/database-setup/#mysql |
2b48ee7
to
9bff3da
Compare
I'm getting an error in my test that I don't know how to resolve: I based my tests off of Thanks in advance for any help. |
It's because you are trying to resolve config from the container before the app has booted or after it's been cleared out. |
Replace
|
It's important you call the parent method after, since it clears the container out. |
Thanks so much! 🙏 I think it's working now. |
@taylorotwell I've added tests. Please let me know if you need anything else. |
Does this test fail without your changes? |
* Update Laravel core files Fix app/Http/Kernel.php * Use RouteServiceProvider::HOME * Sync Laravel default config files * Update composer dependencies to Laravel 6 * fix resources/lang/en/validation.php * Manually fixing tests required by travis, fails locally??? * Update wpb/string-blade-compiler * Add new viewany() authorization policies * Update minimum PHP version to 7.2 * Re-generate our json test-dumps Due to: laravel/framework#16069 laravel/framework#31100 * update truenas data * fix truenas Co-authored-by: Laravel Shift <[email protected]> Co-authored-by: Tony Murray <[email protected]>
Problem
When inserting a float value into MySQL via the Illuminate\Database package when using at least PHP 7.3, the value is converted to an int.
The bug has been reported a few times before:
Cause
PR #16069 introduced logic to the MySQLConnection that cast floats to ints to address a comparison problem with JSON columns, which was reported in issue #16063. This does not seem to cause a problem with PHP 7.1 and below but causes the float to lose it's decimal places when using PHP 7.3. I have not tested with PHP 7.2.
Bug Reproduction
Given we have the following MySQL table:
When we execute the following using Artisan Tinker:
Then we should see both records with -0.2 as the latitude. But only the first has the value, and the second row is zero.