MySQL upgrade causing unexpected results on simple WHERE clauses - php

I'm upgrading my Laravel app to use MySQL 8.0.23 from 8.0.20, and I see an issue with WHERE clauses that produce unexpected results.
SELECT * FROM guilds
WHERE platform_id = 1
AND platform_server_id = '407254666900930563';
Running ^ directly on the MySQL server produces the record I'm looking for (regardless of whether 40725... is an int or a string). However, using it through Laravel's Eloquent Query Builder, it is not finding the record. Here's the eloquent code.
// Won't find it if it's a string, will if it's an int
$serverId = '407254666900930563';
Server::where('platform_id', 1)
->where('platform_server_id', $serverId)
->first()
The data is here:
I've verified in the DB that platform_id does indeed = 1 (verified by running the SQL directly).
Here's my MySQL config on the Laravel side.
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
'modes' => [
/**
* Disabled because of a group by we need
*/
//'ONLY_FULL_GROUP_BY',
'STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_ENGINE_SUBSTITUTION',
]
I've looked through MySQL changelogs and am not seeing what could be causing this. Does anyone have any ideas about what I should investigate?
CREATE TABLE statement is:
CREATE TABLE `guilds` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`platform_id` bigint unsigned NOT NULL,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`platform_server_id` bigint unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `guilds_platform_id_platform_server_id_unique` (`platform_id`,`platform_server_id`),
KEY `guilds_platform_server_id_index` (`platform_server_id`),
) ENGINE=InnoDB AUTO_INCREMENT=691420 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

I would suggest 2 ways to try, in both cases I recommend you to use the where array syntax because is more flexible:
Model query
Server::where([
'platform_id'=> 1,
'platform_server_id' => $serverId
])->first();
Or more explicit "where"
Server::where([
['platform_id', '=', 1],
['platform_server_id', '=', $serverId]
)->first();
DB query builder
// table 'servers' or 'guilds', as I see above
DB::table('guilds')->where([
'platform_id'=> 1,
'platform_server_id' => $serverId
])->first();
Or more explicit "where"
// table 'servers' or 'guilds', as I see above
DB::table('guilds')->where([
['platform_id', '=', 1],
['platform_server_id', '=', $serverId]
])->first();
Extra suggestions
Mysql changelog
Here I found the mysql 8.0.23 changelog for you to check.
Laravel Tinker you can use the command php artisan tinker, that allows you to "write pure" code in the terminal and execute it, you can try the queries I mentioned above and also try other without refactoring your code.
Copy and paste this to try: Server::where([['platform_id', '=', 1],['platform_server_id', '=', 407254666900930563])->first();

These don't look the same:
407254666900930563
Is platform_server_id a BIGINT or a VARCHAR?
Also, I see inconsistencies in quoting the value.
Here's a guess: When Laravel runs the query without quotes, it sees a number, converts it to DOUBLE. But a Double cannot hold more than about 16 significant digits. You seem to need all 18.
Please use the real numbers -- BIGINT also has a limitation that these numbers are close to.
Please provide SHOW CREATE TABLE; there are other details that may be relevant.

A few months ago we had to add "doctrine/dbal" to our "require" list in composer.json to fix some strange stuff. You could try that by running this:
composer require doctrine/dbal

The declaration of the id and the query you use is confused.
The platform_server_id in the create table statement is bigint, but you try to compare with a string or as you mentioned integer:
`platform_server_id` bigint unsigned NOT NULL
$serverId = '407254666900930563';
Server::where('platform_id', 1)
You can not compare these values directly without conversion as you see in this answer:
https://stackoverflow.com/a/72072468/7996624

Related

TYPO3 10.4 error #1470230767 "Out of range value for column 'crdate' at row 1"

I have got this error while I am trying to edit frontend user account. It tries to save 'crdate' as -3600 when it is
crdate int(11) unsigned DEFAULT '0' NOT NULL,
'crdate' => [
'exclude' => 1,
'label' => 'LLL:EXT:femanager/Resources/Private/Language/locallang_db.xlf:' .
'fe_users.crdate',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'size' => 30,
'eval' => 'datetime',
'readOnly' => true,
'default' => time()
]
],
I have got also timezone set up in AdditionalConfiguration.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['phpTimeZone'] = 'GTM+1';
Is there any another solution than changing GTM+1 -> UTC, because it can cause changes in dates?
Obviously there is something wrong, either in EXT:femanager or the TYPO3 core.
Any conversion from the database can't be expected as it's no date or time field of any kind. So conversion, in detail subtraction of the one hour from the current time, has to be done in the extension or more likely in the TYPO3 core code.
To save the -3600 you could turn the definition of the field to
crdate int(11) DEFAULT '0' NOT NULL, or to
crdate int(12) DEFAULT '0' NOT NULL, (adding one place for the minus when all 11 places are used by digits).
Nevertheless that's likely not what you want to save, so the best is to report the bug on https://forge.typo3.org/issues/.
For the moment you could remove the configuration of the timezone in AdditionalConfiguration.php for being able to work again.
This most likely happens due to a missing crdate in the database.
When it is empty the femanager generates a new timestamp with the date "01.01.1970" which internally generates -3600. Since the database field is unsigned, this will fail.
This should be fixed in the Extension, but as a workaround one could set crdate to any value higher than 0.

Splitting a string with Swift using a PHP-equivalent regular expression (#\n\s*\n#Uis)

I need to split a given multi-line string (sample here) using a regular expression with Swift. With PHP (the language I use for building web applications) I do this (after removing comments and substituting some tokens):
// split the file contents in fragments
$fragments = preg_split("#\n\s*\n#Uis", $contents);
And this is what I get if execute preg_split over the code sample:
Array
(
...
[2] =>
CREATE TABLE IF NOT EXISTS c_search_history (
entry_id BIGINT(64) UNSIGNED NOT NULL AUTO_INCREMENT,
entry_date_added DATETIME NOT NULL,
entry_language CHAR(2) NOT NULL DEFAULT 'es',
entry_query TEXT NOT NULL,
PRIMARY KEY (entry_id),
INDEX (entry_date_added),
INDEX (entry_language)
) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
[3] =>
CREATE TABLE IF NOT EXISTS c_search_weight_entries (
entry_id BIGINT(64) UNSIGNED NOT NULL AUTO_INCREMENT,
entry_date DATETIME NOT NULL,
entry_model VARCHAR(175) NOT NULL,
entry_model_id BIGINT(64) UNSIGNED NOT NULL,
entry_value DOUBLE NOT NULL,
PRIMARY KEY (entry_id),
INDEX (entry_date),
INDEX (entry_model),
INDEX (entry_model_id),
INDEX (entry_value)
) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
...
)
The goal for this is to take an .sql file and flatten its contents so each function, table, procedure, trigger or view definition becomes a one-liner for later execution. The problem is I'm fairly new to Swift and I haven't been able to translate the #\n\s*\n#Uis regular expression into something usable for NSRegularExpression.
I tried to use this solution but it outputs nothing for me (but I may be that I have used it in the wrong way or I don't understand how it really works).
Can you give me a hint? Any help would be greatly appreciated :)
After doing, undoing and trying different approaches, seems the only thing I needed to do was to substitute #\n\s*\n#Uis with \\n\\s*\\n and it worked. I still need to do some serious research on NSRegularExpression and a lot of other Swift concepts but, for now, that did the trick :)

MySQL - 'field' doesn't have a default value

Im using Laravel framework and it gives an error with the DB
Error message:
[2016-04-25 06:07:34] local.ERROR: exception 'PDOException' with
message 'SQLSTATE[HY000]: General error: 1364 Field 'remarks' doesn't
have a default value' in ...
The field 'remarks' has a default value of 'None' set in PHPMyAdmin. I dont understand why does it gives an error when it has a default value set. I believe that 'None' is a string value so it's not like a NULL value.
$aId = DB::table('attachments')->insertGetId([ 'document_type_code'=>$document_id, 'report_no'=>'report '.$document_id,
'file_attachment_link'=>$filepath, 'file_attachment_upload'=>$file->getClientOriginalName(), 'uploaded_at'=> $now, 'uploaded_by' => 1,
//Auth::user()->id 'version_number' => 1, ]);
None is not a default string value. It means that there is no default value set.
You can either pass a value in your INSERT statement or alter the table to actually hold a default value for the column.
You can use this sql statement to alter the table
ALTER TABLE attachments MODIFY COLUMN `remarks` VARCHAR(255) DEFAULT 'something';
Or do it from PhpMyAdmin
Don't edit the tables directly. You have your model for that.
Generate a new migration and set you field to be nullable:
$table->string('name', 50)->nullable();
and then php artisan migrate

sfValidatorDoctrineUnique fails on capital letters

I've setup a post validator in my symfony form to stop duplication of primary keys.
A primary key is a two-character string in this instance. Code used to validate:
$this->mergePostValidator(new sfValidatorDoctrineUnique(array(
'model' => 'Manufacturers',
'column' => 'id',
'primary_key' => 'id'
)));
The primary key is uppercase (for example AU). Bizarrely the post validator triggers successfully is lowercase 'au' is entered into the field (i.e. stops it from going to the database and triggering a 500 integrity constraint error), but if entered correctly as 'AU' it doesn't seem to notice the duplication.
Any thoughts?
That's not a symfony sfDoctrineValidator issue. All this validor does is to search your database for an existing record. If you are using a "_ci" (case-insensitive) collation (are you using mysql?) the search returns nothing - the validator is fooled.
Then when you insert the duplicate, you get a exception from the database. Try to change the collation of your table like this:
ALTER TABLE `table` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin
(you should tell doctrine to do it for you:
MyTable:
options: { collate: utf8_bin, charset: utf8 }
)

Is the method Doctrine_Table::find() deprecated?

I had a problem with the method Doctrine_Table::find(), since it's thorowing an exception of
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
I solved the problem by using Doctrine::getTable('City')->findOneById($id); instead and it works fine.
When I tried to invistigate about the problem I was surprised since no documentation about the method Doctrine_Table::find() in the official website.
Any one knows what's the problem? is it deprecated?
BTW it's exists on the actual code! of the version (1.2.1).
more info about the database:
CREATE TABLE IF NOT EXISTS `country` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(64) NOT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `city` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(64) NOT NULL ,
`country_id` INT NOT NULL ,
PRIMARY KEY (`id`, `country_id`) ,
INDEX `fk_city_country` (`country_id` ASC) ,
CONSTRAINT `fk_city_country`
FOREIGN KEY (`country_id` )
REFERENCES `country` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;
What's weird is that both Doctrine_Table::find(), and Doctrine_Table::findOneById() works fine on Country table!.
PS: I realize that Doctrine_Table::findOneById() is a __call() generated method. And that make me confused more, why the actual find() method can't behave as expected (is my expectation wrong or what)!
Oh my bad. I didnt see it earlier, shame on me =p
Your table has two primary keys (id and country_id), so the find method requires you to pass both parameters to the find method.
You could instead use the magic methods:
Doctrine::getTable('City')->findOneById(1)
As of v 1.2.1, Doctrine_Table::find() is NOT deprecated
You can check the official documentation on http://www.doctrine-project.org/documentation/manual/1_2/en/component-overview#table:finder-methods
As for the "invalid parameter number" error, it means you query has more or fewer parameters than expected, most often you used a token (?) and forgot to add the parameter to it
Doctrine_Query::create()
->from('User u')
->where('u.name = ?', 'Jonh')
->andWhere('u.is_active = ?')
The example i used have two tokens '?', but only one parameter 'jonh', it would throw the same error: "Invalid parameter number: number of bound variables does not match number of tokens"

Categories