Different behavior with MySQL 5.7 and 8.0 - mysql

I'm trying to use MySQL 8.0 but I'm having some problems. I have installed MySQL 5.7 and 8.0, and have different behavior with CHAR columns.
For MySQL 5.7:
mysql> create table test (id integer, c5 char(5));
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test values(0, 'a');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test where c5 = 'a ';
+------+------+
| id | c5 |
+------+------+
| 0 | a |
+------+------+
1 row in set (0.00 sec)
mysql>
For MySQL 8.0:
mysql> create table test (id integer, c5 char(5));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test values(0, 'a');
Query OK, 1 row affected (0.01 sec)
mysql> select * from test where c5 = 'a ';
Empty set (0.00 sec)
mysql>
Both servers have same configuration.
MySQL 5.7:
[mysqld]
port=3357
datadir=/opt/mysql_57/data
sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
default_storage_engine=innodb
character-set_server=utf8mb4
socket=/opt/mysql_57/mysql57.sock
max_allowed_packet=4194304
server_id=1
lower_case_table_names=0
MySQL 8.0:
[mysqld]
port=3380
datadir=/opt/mysql_80/data
sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
default_storage_engine=innodb
character-set_server=utf8mb4
socket=/opt/mysql_80/mysql80.sock
max_allowed_packet=4194304
server_id=1
lower_case_table_names=0
A brief overview of the MySQL 8.0 changelog didn't give me any information. Where described this behavior changes?
Best regards.

How MySQL handled trailing spaces, depends on the collation being used. See https://dev.mysql.com/doc/refman/8.0/en/charset-binary-collations.html for details.
What has changed between 5.7 and 8.0, is that the default character set is now UTF8mb4 with NOPAD collations.
If you want another behavior, you should change character set/collation for your column/table/database. Check the INFORMATION_SCHEMA table COLLATIONS for available PAD collations. (One warning: The older PAD SPACE collations may be less efficient. Quite some work has been made to improve the performance of the new Unicode collations based on UCA 9.0.0.)

See PAD_CHAR_TO_FULL_LENGTH in MySQL documentation

Related

MySQL query - get a list of ALL WP admin email addresses for all WP sites on server

I have a lot of WP websites set up on my server, and I'm trying to get a list of admin email addresses registered for all of the WP sites.
The server uses WHM/cPanel, and MariaDB.
I'd hoped WordPress Toolkit could do this out of the box, but it doesn't seem to be able to.
I'm an SQL noob, and I've only gotten as far as this for my SQL query, for a single DB:
SELECT option_value
FROM `database_name`.`wp_options`
WHERE option_name="admin_email"
Another problem is, lots of the WP databases on the server don't use the standard wp_ table prefix, but instead use a random string, so I also need a way of using a wildcard in the table name like
*_options
So my 2 problems are:
Make the query loop across ALL databases on the server
make the query use a wildcard in the table name
Is this possible?
Yes. Its two queries, first to generate the SQL, and then execute it.
Example setup:
MariaDB [(none)]> create database rr;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> create database ss;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> create table ss.wp_options(option_name varchar(30), option_value varchar(30));
Query OK, 0 rows affected (0.003 sec)
MariaDB [(none)]> create table rr.rr_options(option_name varchar(30), option_value varchar(30));
Query OK, 0 rows affected (0.003 sec)
MariaDB [(none)]> insert into ss.wp_options values ('admin_email', 'me#ss');
Query OK, 1 row affected (0.003 sec)
MariaDB [(none)]> insert into rr.rr_options values ('admin_email', 'me#rr');
Query OK, 1 row affected (0.002 sec)
Then use the information_schema.TABLES to generate your query using UNION ALL to concatinate them:
SELECT group_concat(
concat('select "', TABLE_SCHEMA, '" as db, option_value from ', TABLE_SCHEMA, '.', TABLE_NAME, ' WHERE option_name="admin_email"')
SEPARATOR ' UNION ALL ') INTO #sql
FROM information_schema.TABLES
WHERE TABLE_NAME LIKE '%_options';
Just to show what we generate:
MariaDB [(none)]> select #sql\G
*************************** 1. row ***************************
#sql: select "ss" as db, option_value from ss.wp_options WHERE option_name="admin_email"
UNION ALL select "rr" as db, option_value from rr.rr_options WHERE option_name="admin_email"
Execute immediate runs a query, like a prepared statement without the setup and run, shutdown steps:
MariaDB [(none)]> execute immediate #sql;
+----+--------------+
| db | option_value |
+----+--------------+
| ss | me#ss |
| rr | me#rr |
+----+--------------+
2 rows in set (0.002 sec)

Data too long for column error with national characters

I have to port some DBS into stand alone MySQL Version: 5.0.18 running on Windows7 64bit and I got a problem I am stuck with. If I try to insert any national/unicode character into varchar I got error:
ERROR 1406 (22001): Data too long for column 'nam' at row 1
Here MCVE SQL script:
SET NAMES utf8;
DROP TABLE IF EXISTS `tab`;
CREATE TABLE `tab` (`ix` INT default 0,`nam` VARCHAR(1024) default '' ) DEFAULT CHARSET=utf8;
INSERT INTO `tab` VALUES (1,'motorček');
INSERT INTO `tab` VALUES (2,'motorcek');
SELECT * FROM `tab`;
And here output:
mysql> SET NAMES utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `tab`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `tab` (`ix` INT default 0,`nam` VARCHAR(1024) default '' ) DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `tab` VALUES (1,'motorček');
ERROR 1406 (22001): Data too long for column 'nam' at row 1
mysql> INSERT INTO `tab` VALUES (2,'motorcek');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM `tab`;
+------+----------+
| ix | nam |
+------+----------+
| 2 | motorcek |
+------+----------+
1 row in set (0.00 sec)
As you can see the entry with national character č E8h is missing.
I am aware of these QAs:
How to make MySQL handle UTF-8 properly
“Data too long for column” - why?
Error Code: 1406. Data too long for column - MySQL
but they do not address this problem (no solution from any of those work for this).
This problem is present even for single character strings. No matter the size of VARCHAR. So the only solution for now is change the national characters into ASCII but that would lose information which I would rather avoid.
I tried using various character sets utf8, ucs2, latin1 without any effect.
I tried drop the STRICT_TRANS_TABLES as some of the other answers suggest but that has no effect with this either (and the string size is many times bigger than needed).
Does anyone have any clues? May be it has something to do with fact that this MySQL server is standalone (it is not installed) it is started with this cmd:
#echo off
bin\mysqld --defaults-file=bin\my.ini --standalone --console --wait_timeout=2147483 --interactive_timeout=2147483
if errorlevel 1 goto error
goto finish
:error
echo.
echo MySQL could not be started
pause
:finish
and queries are done inside console started like this cmd:
#echo off
bin\mysql.exe -uroot -h127.0.0.1 -P3306
rem bin\mysql.exe -uroot -proot -h127.0.0.1 -P3306
Well looking at the char č code E8h (while writing question) It does not look like UTF8 but rather a extended ASCII (code above 7Fh) which finally pointed me to try this MySQL script:
SET NAMES latin1;
DROP TABLE IF EXISTS `tab`;
CREATE TABLE `tab` (`ix` INT default 0,`nam` VARCHAR(1024) default '' );
INSERT INTO `tab` VALUES (1,'motorček');
INSERT INTO `tab` VALUES (2,'motorcek');
SELECT * FROM `tab`;
Which finally works (silly me I thought I already tried it before without correct result). So my error was to force Unicode (which was set as default) for Non Unicode strings (which I think should work). Here the result:
mysql> SET NAMES latin1;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `tab`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `tab` (`ix` INT default 0,`nam` VARCHAR(1024) default '' );
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO `tab` VALUES (1,'motorček');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO `tab` VALUES (2,'motorcek');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM `tab`;
+------+----------+
| ix | nam |
+------+----------+
| 1 | motorček |
| 2 | motorcek |
+------+----------+
2 rows in set (0.00 sec)
But as you can see there is some discrepancy in the table formatting but that does not matter much as the presentation will be done in C++ anyway.
Without writing this Question I would probably going in circles for hours or even days. Hopefully this helps others too.
[Edit1]
Now I got another problem caused by Windows. If I pass the script with Clipboard or type it myself all is OK but if I use source file then the national characters will go wrong (and the -e option does not help either). As I need to use files I am still looking for solution. But as this is different problem I decided to Ask new question:
Using source command corrupts non Unicode text encoding

Mysql: MyISAM table files deleted, but still inserting and selecting data. HOW?

Can someone explain me, what is happening here,
I created one table in MyISAM.
show tables -- shows it.
select command gives empty table from the table.
I delete the myisam files from location.
show tables -- does not show it.
Ok till now.
Now, still I am able to insert into table, and able to select from the table [can it happen?? how??]
Again, drop table says table does not exist.
and after this, select command says table does not exist.
Question is "where did it get inserted, and from where it is selecting the data; and after drop table call, where did it vanish?"
Server version: 5.5.38-log MySQL Community Server (GPL)
The overall sequence ..
MySQL [test]> CREATE TABLE test (id int(11) DEFAULT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.05 sec)
MySQL [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test |
+----------------+
1 row in set (0.00 sec)
MySQL [test]> select * from test;
Empty set (0.00 sec)
~~~~~~~~~~~~~~~~~~~~~~~~~
[root#localhost test]# pwd
/var/lib/mysql/test
[root#localhost test]# ll
total 16
-rw-rw---- 1 mysql mysql 8556 Dec 23 14:08 test.frm
-rw-rw---- 1 mysql mysql 0 Dec 23 14:08 test.MYD
-rw-rw---- 1 mysql mysql 1024 Dec 23 14:08 test.MYI
[root#localhost test]# rm -f *
[root#localhost test]# ll
total 0
[root#localhost test]#
~~~~~~~~~~~~~~~~~~~~~~~~~
MySQL [test]> show tables;
Empty set (0.00 sec)
MySQL [test]> insert into test values (1234);
Query OK, 1 row affected (0.00 sec)
MySQL [test]> select * from test;
+------+
| id |
+------+
| 1234 |
+------+
1 row in set (0.00 sec)
MySQL [test]> drop table test;
ERROR 1051 (42S02): Unknown table 'test'
MySQL [test]> select * from test;
ERROR 1146 (42S02): Table 'test.test' doesn't exist
On Unix, if you remove a file that another process has opened, it just removes the name from the directory, but the file still exists on disk, and the other process can continue to access it. It doesn't really go away until all processes close the file.
The MySQL daemon presumably opens the files related to a table the first time it's accessed, and then keeps the file open for as long as it can. So once it has accessed a table, removing the filename doesn't affect its operations on the contents of the table.
However, DML operations like show tables and drop tables work by accessing the directory, not the open files, so they notice the change. Then all the internal data structures are sync'ed with the filesystem.

MySQL LIKE operator with wildcard and backslash

It's frustrated with MySQL's pattern escaping used in LIKE operator.
root#dev> create table foo(name varchar(255));
Query OK, 0 rows affected (0.02 sec)
root#dev> insert into foo values('with\\slash');
Query OK, 1 row affected (0.00 sec)
root#dev> insert into foo values('\\slash');
Query OK, 1 row affected (0.00 sec)
root#dev> select * from foo where name like '%\\\\%';
Empty set (0.01 sec)
root#dev> select * from foo;
+------------+
| name |
+------------+
| with\slash |
| \slash |
+------------+
2 rows in set (0.00 sec)
root#dev> select * from foo where name like '%\\\\%';
Empty set (0.00 sec)
root#dev> select * from foo where name like binary '%\\\\%';
+------------+
| name |
+------------+
| with\slash |
| \slash |
+------------+
2 rows in set (0.00 sec)
According to MySQL docs: http://dev.mysql.com/doc/refman/5.5/en/string-comparison-functions.html#operator_like
%\\\\% is the right operand, but why it yields no result?
EDIT:
The database I'm testing that in has character_set_database set to utf8. To further my investigation, I created the same setup in a database that has character_set_database set to latin1, and guess what, '%\\\\%' works!
EDIT:
The problem can be reproduced and it's the field collation problem. Details: http://bugs.mysql.com/bug.php?id=63829
In MySQL 5.6.10, with the text field collation utf8mb4_unicode_520_ci this can be achieved by using 5 backslash characters instead of 4, i.e:
select * from foo where name like binary '%\\\\\%';
Somehow, against all expectations, this properly finds all rows with backslashes.
At least this should work until the MySQL field collation bug above is fixed. Considering it's been more than 5 years since the bug is discovered, any app designed with this may outlive its usefulness before MySQL is even fixed - so should be a pretty reliable workaround.
With MySQL 5.0.12 dev on Windows 10 I got the following results when I changed the query from
SELECT * FROM `foo` WHERE `name` LIKE '%http:\/\/%'
to
SELECT * FROM `foo` WHERE `name` LIKE '%http:\\\\\\\%'
it works and yet the first string with forward slashes was the original field content. It seems to have interpreted forward slashes as backslashes.
It seems it has some relation to that MySQL bug: http://bugs.mysql.com/bug.php?id=46659
I think you connect to mysql not specifying correct --character-set-server option (which defaults to latin1 with collation latin1_swedish_ci), and having utf-8 as the current charset of the console. That causes incorrect char conversions and comparisons when you deal with data which supposed to be converted to the utf8 from the charset of --character-set-server.

2 servers, 2 memory tables, different sizes

I have got two servers both running a MySQL instance. The first one, server1, is running MySQL 5.0.22. The other one, server2, is running MySQL 5.1.58.
When I create a memory table on server1 and I add a row its size is instantly 8,190.0 KiB.
When I create a memory table on server2 and I add a row its size is still only some bytes, though.
Is this caused by the difference in MySQL version or (hopefully) is this due to some setting I can change?
EDIT:
I haven't found the reason for this behaviour yet, but I did found a workaround. So, for future references, this is what fixed it for me:
All my memory tables are made once and are read-only from thereon. When you specify to MySQL the maximum number of rows your table will have, its size will shrink. The following query will do that for you.
ALTER TABLE table_name MAX_ROWS = N
Factor of 2?
OK, the problem likely is caused by the UTF-8 vs latin1
:- http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html
You can check the database connection, database default character set for both servers.
here is the testing I have just done :-
mysql> create table test ( name varchar(10) ) engine
-> =memory;
Query OK, 0 rows affected (0.03 sec)
mysql> show create table test;
+-------+------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`name` varchar(10) DEFAULT NULL
) ENGINE=MEMORY DEFAULT CHARSET=latin1 |
+-------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> insert into test values ( 1 );
mysql> set names utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> create table test2 ( name varchar(10) ) engine =memory default charset = utf8;
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test2 values ( convert(1 using utf8) );
Query OK, 1 row affected (0.01 sec)
mysql> select table_name, avg_row_length from information_schema.tables where TABLE_NAME in( 'test2', 'test');
+------------+----------------+
| table_name | avg_row_length |
+------------+----------------+
| test | 12 |
| test2 | 32 |
+------------+----------------+
2 rows in set (0.01 sec)