Wednesday, November 30, 2005

New links online

I have added a few links here in my weblog and at the Developer's page on db4free.net. This Developer's page was initially planned to end up as something like MySQLDevelopment.com - but as there is such a variety of great sites (what this page never could have competed with), I changed this plan to offer links to the best other resources, instead.

Many people who are familiar with the various resources about MySQL development will probably know most of the links, but for those who are not (yet), here are my personal recommandations:

Besides the official resources at mysql.com and planetmysql.org (where many of the articles written in the mentioned weblogs can be found, too), these are the best sites about MySQL development that I know!

Friday, November 25, 2005

PHP 5.1 released

Today (24th November), PHP version 5.1.0 has been released. Find a list of the new features, which include that PDO extension is now enabled by default, on the PHP website. The PDO extension provides a common interface to communicate to different database systems.

Also read the Changelog and the Upgrading Guide to get detailed information about what's new.

Tuesday, November 22, 2005

Many thanks ...

... to Shane Bester for finding a repeatable testcase for the bug report #14829, where I asked for help early this morning. The bug has now been acknowledged and it is likely that the bug will be fixed soon :-).

This showed me once more how great this Community works. If there is a problem that I can't solve myself, it really works to ask for help and get some assistance. That's one of the points that makes MySQL more attractive than many other products.

Monday, November 21, 2005

TX isolation levels (2) READ COMMITTED

This blog post has moved. Please find it at:

http://www.mpopp.net/2005/11/tx-isolation-levels-2-read-committed/.

Call for help to make a bug repeatable

I have found a bug which disallows me to log in with a user, after I have created and deleted another user. After restarting the server, I can log in again as if there never was a problem. I have reported this bug to

http://bugs.mysql.com/bug.php?id=14829

I have tried to create a repeatable case and I made it to create a situation, where I could reproduce this bug on 3 different machines. Unfortunately, when Miguel Solorzano tries to repeat this, it still works - although we have already checked out that everything is completely identical.

So I'm asking for help to find out more details to reproduce this. If you have a Windows (2000 or XP) test server available that you can play around with, please try the following:

* Install MySQL 5.0.15, if possible to c:\mysql
* download and install this my.ini file
* download the dump file from dump_mysql.sql and put it to C:
Log in as root (without password) and delete the test database and the contents from the mysql.db table:

drop database test;
delete from mysql.db;
flush privileges;

Then do the following steps, starting from C:
C:\>mysql -u root mysql < dump_mysql.sql

C:\>mysqladmin -u root flush-privileges

C:\>mysql -u root
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7 to server version: 5.0.15-nt-max

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create user user@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> drop user user@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye

C:\>mysql -u mpopp

... if everything works "fine" (to say, you can reproduce the bug), you should get following message:

ERROR 1130 (HY000): #HY000Host 'localhost' is not allowed to connect to this
MySQL server

After restarting the server, you should be able to log in as user mpopp.

If you find any clue why this bug still doesn't occur on all installations (under the given conditions), please add a comment to the bug report. Please let me know, if you can or cannot reproduce it and mail me at m.popp@db4free.net. Thanks to all who help :-).

Tuesday, November 15, 2005

db4free optimizations

Today I did some server optimizations on db4free.net, which has recently welcomed its 1,500th user. As I already wrote earlier in my weblog, I'm currently preparing for the MySQL professional exam, and I could use the new skills from learning for this exams immediately for re-configuring the db4free.net server to offer better performence to its users. I enabled the query cache, extended the buffer limits, allowed more concurrent users and enlarged the max_allowed_packet value to make it possible to import larger dump files.

But there are more benefits from learning for MySQL certification exams than that. For example, before I started, I used to create tables and users, or change user's permissions with 3rd party tools like phpMyAdmin. I knew the fundamental statements how to do it with SQL, but I didn't know the details good enough to really use it. Today, I feel even more (!) comfortable to do it in MySQL monitor using SQL than with any graphical tool. So this proofs that the exams helped me a lot to become much better in writing SQL and to be independent of any 3rd party software.

Stay steady as one of the next articles in my weblog will be to show, how the different transaction isolation levels work in practice and how a deadlock can be created artificially. Very interesting stuff, indeed!

But now back to db4free. As already mentioned, db4free has hit the 1,500 users mark. Time for some statistics. As of today, there are 1,575 users from 60 different countries. The website has been visited 9,415 times from people from 91 different countries. Most visitors (and also users) come from Germany, followed by China, USA, Taiwan, Poland, Austria and Hongkong (as it's easy to see, db4free is very popular in the Far East region). After Germany (339), most users come from Poland (259), China (192), Taiwan (166), Hongkong (160) and the USA (98).

Information schema allowed me to get some more interesting statistical data. The 1,575 users have created 22,445 tables, from which are 21,894 MyISAM tables, 470 InnoDB tables, 80 MEMORY tables and (as db4free is offering the Max version of MySQL 5.0.15) 1 BerkeleyDB table. There are 13 views, 23 Stored Procedures and 28 User Defined Functions.

Friday, November 11, 2005

Using a SP to split up a table

Lets assume that we have one big table with forum posts (called forum_posts) from quite a long period. We want to split this big table up in several smaller tables for every month. The date is stored in a datetime column called dt.

Here's a stored procedure that splits the table up in smaller tables called fp_YYMM which are identical in its structure as the original table. It uses a cursor to walk through every month, create the new table (with a CREATE TABLE ... LIKE statement) and copying the correct data into the archive tables. The original table will persist.

The procedure also uses prepared statements to dynamically build up the SQL statements for creating the new tables and copying the contents.

DELIMITER //

DROP PROCEDURE IF EXISTS splitUpTables //
CREATE PROCEDURE splitUpTables ()
BEGIN
declare finished int default 0;
declare month char(7);
declare month2 char(6);
declare dfrom date;
declare dto date;

declare curCreate cursor for
SELECT distinct date_format(dt, '%Y-%m') as month
FROM forum_ posts order by date_format(dt, '%Y-%m');
declare continue handler for not found set finished := 1;

open curCreate;

fetch curCreate into month;

while finished = 0 do

select concat(substring(month, 1, 4), substring(month, 6, 2))
into month2;

select month2;

set @sql := concat('create table if not exists fp_', month2,
' like forum_posts ');
prepare pCreate from @sql;
execute pCreate;

set dfrom := cast(concat(month, '-01') AS date);
select date_sub(date_add(dfrom, interval 1 month), interval 1 day)
into dto;

set @sql1 := concat('truncate table fb_', month2);
set @sql2 := concat('insert into fp_', month2,
' select * from forum_posts where dt between \'',
dfrom, '\' and \'', dto, '\' order by dt');

prepare pTruncate from @sql1;
execute pTruncate;
prepare pInsert from @sql2;
execute pInsert;

fetch curCreate into month;

end while;

close curCreate;

END //

DELIMITER ;

Thursday, November 10, 2005

Calculate uniqueness of text fields for setting indexes

Indexing long text fields can be more consuming than helpful. Indexes have to be maintained by the server. So if you have an indexed 255 character long varchar field, it probably means more work for the server than the index can help you.

Fortunately, it's easy to limit the index length to a specified number of characters. We can do this with e.g. a KEY(field(15)) clause when adding the index with a CREATE or ALTER TABLE or CREATE INDEX statement. In this case, only the first 15 characters would be indexed.

The question is - how long should the indexed length be? As a rule of thumb we could say, we should choose a length that's just enough to make most of the indexed contents unique. Maybe we won't reach 100 % of uniqueness, but that's not necessary. It will probably be too little to index only the first one or two characters, because they will be the same for many records. So the next question is - what's a good value?

To make the decision a little easier, we can calculate the uniqueness with following formula:
SELECT count(distinct left(field_name, indexed_length)) / 
count(*) * 100 FROM table_name;

The higher the value, the more unique the indexed contents are.

So I thought to myself, why not put this into a stored procedure where we pass the table name, the column name and two boundaries from which value to which other value we'd like to see the percentage of uniqueness. Here's how I did it: I created a temporary table inside the procedure, prepared the insert into [temporary table] select ... statement and queried the values inside a while loop from the lower bound to the upper bound. Here it is:
DELIMITER $$

DROP PROCEDURE IF EXISTS getUniqueness $$
CREATE PROCEDURE getUniqueness (IN _table VARCHAR(255),
IN _column VARCHAR(255), IN _noFrom INT, IN _noTo INT)
BEGIN

create temporary table tt_uniqueness
(noChar int unsigned not null, uniqueness decimal(10,2) not null);

set @sql := concat('insert into tt_uniqueness ',
'select ?, cast(count(distinct left(',
_column,
', ?)) / count(*) * 100 as decimal(10,2)) from ',
_table);

prepare pSql from @sql;

set @count := _noFrom;

while @count <= _noTo do

execute pSql using @count, @count;

set @count := @count + 1;

end while;

select * from tt_uniqueness;

drop temporary table if exists tt_uniqueness;

END$$

DELIMITER ;


Finally, lets take a look how it works. I try it on the phpbb_posts_text table from a phpBB database which holds 340 entries:

mysql> explain phpbb_posts_text;
+--------------+-----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------+-------+
| post_id | mediumint(8) unsigned | NO | PRI | 0 | |
| bbcode_uid | varchar(10) | NO | | | |
| post_subject | varchar(60) | YES | | NULL | |
| post_text | text | YES | | NULL | |
+--------------+-----------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> select count(*) from phpbb_posts_text;
+----------+
| count(*) |
+----------+
| 340 |
+----------+
1 row in set (0.00 sec)

mysql> call getUniqueness('phpbb_posts_text', 'post_text', 1, 10);
+--------+------------+
| noChar | uniqueness |
+--------+------------+
| 1 | 7.94 |
| 2 | 27.65 |
| 3 | 41.47 |
| 4 | 51.18 |
| 5 | 59.41 |
| 6 | 67.94 |
| 7 | 71.47 |
| 8 | 78.82 |
| 9 | 84.12 |
| 10 | 85.00 |
+--------+------------+
10 rows in set (0.03 sec)

Query OK, 0 rows affected (0.03 sec)

mysql>

So we can see, how the uniqueness rises as we choose longer index lengths. If we for example decide that we want to have a uniqueness of 80 % for the index, it would be fine to select 9 characters as the index length.

Monday, November 07, 2005

ApacheLog2MySQL

I have written a little Java program that parses an Apache Log file and stores its content in a MySQL database.

The program is published under the General Public License and can be downloaded from http://apachelog2mysql.mpopp.net/ApacheLog2MySQL.jar. You can download the source code at http://apachelog2mysql.mpopp.net/ApacheLog2MySQL.zip and find the ReadMe file at http://apachelog2mysql.mpopp.net/readme.txt. In this ReadMe file you will find all details about the limitations and the features that are planned in the future.

You can also find all the information on my website at http://www.mpopp.net/apachelog2mysql.php.

The program runs at all platforms that have the Java Runtime Environment 1.5.0 or higher installed. It can be started from the console with following command:
java -jar ApacheLog2MySQL.jar [filename] [host] [user]
[password] [database]


The program is very basic at the moment, but I plan to extend its features, so it might become a great little tool to analyze the Apache log. Please refer to the ReadMe file to get more detailed information about where the program is still limited and which features I plan to implement.

Feel free to try the program, modify it, give me feedback and let me know your thoughts about this little tool.

Friday, November 04, 2005

Compiling PHP 5 with mysql and mysqli

This blog post has moved. Please find it at:

http://www.mpopp.net/2005/11/compiling-php-5-with-mysql-and-mysqli/.

My first look at 5.1 ...

It was a great thing when MySQL 5.0 came out, but what's next? Well, of course, the stabilization process of MySQL 5.0 continues, but the work for the next release - 5.1 - has begun quite a while ago.

So, up to now I've always been using the official binaries from MySQL. That's the best thing to do for running MySQL servers in production. But why not take a look a bit further to see what's going on beyond the public releases?

So I looked into MySQL's documentation to read about Installing from the Development Source Tree. I did all the points step by step and now I've ended up with my first MySQL 5.1 server:

MySQL 5.1

These are very interesting days in terms of MySQL - two weeks ago the first Production Release of MySQL 5.0 and now my first personal MySQL 5.1 installation. It's always very exciting to have a first look at a new milestone.

Friday, October 28, 2005

Got number two ...

Today I have made my second step towards my goal of getting a row of IT certificates. After passing the MySQL Core Certificate three weeks ago, I passed the Zend PHP Certification today.

For me, today's exam was harder than the MySQL exam. One reason is certainly that I love to do things with MySQL and I do much more with MySQL than my actual work requires. So I have collected more experiences with MySQL than with PHP, which I use to do my work, but not so much for experimenting.

The second reason - the MySQL Study Guide covers the topics that will be on the exam very exactly. Therefore, it's also much bigger than the PHP Certification Study Guide. The latter also indicates what you will find on the exam, but don't expect that every little detail is mentioned in the PHP Study Guide. Comparing them, learning with the MySQL Study Guide was much easier for me. Finally, both exams might require quite the same amount of knowledge - I haven't found a big difference on this.

Well, now it's time to get myself ready for the MySQL Professional Exam. It might take some time, it's certainly not easy and even some good people haven't taken the exam at the first time - so I'll try to learn the material very closely. When it's done, you'll hear a loud 'wouhoooo' from me :-).

Wednesday, October 26, 2005

Upgrading from older versions to MySQL 5.0

I sometimes read the posts in the MySQL Newsgroup (mailing.database.mysql) and take a look if there are any questions where I can help other MySQL users. That's a good think for many purposes: I can help people, I can learn new things for myself and last but not least - there are often questions that give me interesting material for this weblog. Such as this:

There was a question, how to update to the latest MySQL 5.0 version - not only from 4.1 (which is described perfectly in the MySQL manual), but also from older versions like 3.23. Here's how I would do it:

* make a dump of all your data except the mysql database

* make a separate dump of the mysql database

* uninstall this old MySQL version

* install the latest MySQL version from scratch

* create a separate database for the previously dumped mysql database (e.g.
mysql_old) and restore this dump

* sync the old mysql database with the new one (this might require some
manual work, because the structures will be slightly different)

* when the new mysql database is OK, restore the dump of the data

If you have a chance, try to install the new version on a separate machine,
before you uninstall the old MySQL version to make sure that everythink works.

Selecting data by user in views

I have found an interesting request in the MySQL newsgroup asking, how data can be selected as of a user column in a table. Only the user who is stored in a record should be able to access and alter this row.

So this is a perfect example to demonstrate, how this can be accomplished by a view.

First I created a table called tt in the database test and filled it with sample data:
create table tt (
id int unsigned not null auto_increment primary key,
charvalue char(1) not null,
intvalue int unsigned not null,
allowed_user char(6) not null);

insert into tt (charvalue, intvalue, allowed_user)
values ('a', 560, 'user_g');
insert into tt (charvalue, intvalue, allowed_user)
values ('b', 931, 'user_g');
insert into tt (charvalue, intvalue, allowed_user)
values ('c', 661, 'user_c');
insert into tt (charvalue, intvalue, allowed_user)
values ('d', 246, 'user_f');
insert into tt (charvalue, intvalue, allowed_user)
values ('e', 452, 'user_g');
insert into tt (charvalue, intvalue, allowed_user)
values ('f', 130, 'user_c');
insert into tt (charvalue, intvalue, allowed_user)
values ('g', 341, 'user_f');
insert into tt (charvalue, intvalue, allowed_user)
values ('h', 847, 'user_a');
insert into tt (charvalue, intvalue, allowed_user)
values ('i', 417, 'user_b');
insert into tt (charvalue, intvalue, allowed_user)
values ('j', 151, 'user_f');
insert into tt (charvalue, intvalue, allowed_user)
values ('k', 11, 'user_e');
insert into tt (charvalue, intvalue, allowed_user)
values ('l', 66, 'user_a');
insert into tt (charvalue, intvalue, allowed_user)
values ('m', 375, 'user_g');
insert into tt (charvalue, intvalue, allowed_user)
values ('n', 412, 'user_g');
insert into tt (charvalue, intvalue, allowed_user)
values ('o', 358, 'user_c');
insert into tt (charvalue, intvalue, allowed_user)
values ('p', 78, 'user_c');
insert into tt (charvalue, intvalue, allowed_user)
values ('q', 463, 'user_e');
insert into tt (charvalue, intvalue, allowed_user)
values ('r', 773, 'user_e');
insert into tt (charvalue, intvalue, allowed_user)
values ('s', 165, 'user_b');
insert into tt (charvalue, intvalue, allowed_user)
values ('t', 740, 'user_e');
insert into tt (charvalue, intvalue, allowed_user)
values ('u', 875, 'user_c');
insert into tt (charvalue, intvalue, allowed_user)
values ('v', 793, 'user_a');
insert into tt (charvalue, intvalue, allowed_user)
values ('w', 677, 'user_a');
insert into tt (charvalue, intvalue, allowed_user)
values ('x', 133, 'user_b');
insert into tt (charvalue, intvalue, allowed_user)
values ('y', 994, 'user_d');
insert into tt (charvalue, intvalue, allowed_user)
values ('z', 479, 'user_e');

The column allowed_user specifies, which user should be allowed to access this row.

The next step is to wrap this table into a view (called tt_select) and limit it to be accessible for only the user who is logged in:

create view tt_select as
select * from tt
where allowed_user = substring(user(), 1, locate('@', user()) - 1);


The substring and locate functions cut off the host from the user name, so e.g. user@localhost becomes user (if the limit should apply to both user and host, you can also store the complete user@host information in the table and query 'where allowed_user = user()').

Finally I created the user accounts and granted the privileges exclusively for the view (not for the table):

GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select` 
TO 'user_a'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_b'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_c'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_d'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_e'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_f'@'%' IDENTIFIED BY 'abc123';
GRANT SELECT , INSERT , UPDATE , DELETE ON `test`.`tt_select`
TO 'user_g'@'%' IDENTIFIED BY 'abc123';


That's it :-). Lets test it using the MySQL console client, assuming that the user 'user_g' logs in:

E:\>mysql -u user_g -pabc123 test
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 181 to server version: 5.0.15-max

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| tt_select |
+----------------+
1 row in set (0.00 sec)

mysql> select * from tt_select;
+----+-----------+----------+--------------+
| id | charvalue | intvalue | allowed_user |
+----+-----------+----------+--------------+
| 1 | a | 560 | user_g |
| 2 | b | 931 | user_g |
| 5 | e | 452 | user_g |
| 13 | m | 375 | user_g |
| 14 | n | 412 | user_g |
+----+-----------+----------+--------------+
5 rows in set (0.00 sec)

mysql> update tt_select set intvalue=584 where id=13;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from tt_select;
+----+-----------+----------+--------------+
| id | charvalue | intvalue | allowed_user |
+----+-----------+----------+--------------+
| 1 | a | 560 | user_g |
| 2 | b | 931 | user_g |
| 5 | e | 452 | user_g |
| 13 | m | 584 | user_g |
| 14 | n | 412 | user_g |
+----+-----------+----------+--------------+
5 rows in set (0.00 sec)

mysql> delete from tt_select where id=13;
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt_select;
+----+-----------+----------+--------------+
| id | charvalue | intvalue | allowed_user |
+----+-----------+----------+--------------+
| 1 | a | 560 | user_g |
| 2 | b | 931 | user_g |
| 5 | e | 452 | user_g |
| 14 | n | 412 | user_g |
+----+-----------+----------+--------------+
4 rows in set (0.02 sec)

mysql> insert into tt_select values (13, 'm', 375, 'user_g');
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt_select;
+----+-----------+----------+--------------+
| id | charvalue | intvalue | allowed_user |
+----+-----------+----------+--------------+
| 1 | a | 560 | user_g |
| 2 | b | 931 | user_g |
| 5 | e | 452 | user_g |
| 13 | m | 375 | user_g |
| 14 | n | 412 | user_g |
+----+-----------+----------+--------------+
5 rows in set (0.00 sec)

mysql> select * from tt;
ERROR 1142 (42000): SELECT command denied to user
'user_g'@'localhost' for table 'tt'
mysql>

As we can see - it works fine!

Tuesday, October 25, 2005

Information schema diagram

Roland Bouman has created a perfectly organized diagram about the information schema tables:

http://www.xcdsql.org/Misc/MySQL_INFORMATION_SCHEMA.html

Roland's diagram has been awarded in MySQL's beta challenge (congratulations for this prize!).

Information schema has been introduced in MySQL 5 and provides all kinds of information about the database objects.

Monday, October 24, 2005

db4free.net offers MySQL 5.0.15-Max

db4free.net has been updated to MySQL 5.0.15-Max (this enhanced variant offers some additional Storage Engines like BerkeleyDB and Archive). This way, db4free.net is probably the first public MySQL provider of the world that offers a MySQL 5 Production Release.

I hope, many - also commercial - providers will follow soon!

Congratulations

... to MySQL AB for the new "baby" 5.0 and many thanks to everyone who has been involved in the process of making MySQL 5.0 a great product. Keep on the good work!

Thursday, October 20, 2005

Web apps ready for MySQL 5?

I think there is no doubt that MySQL 5 is ready for web applications. But I'd like to put this question around and ask, whether the most popular web applications are ready for MySQL 5.

Well, this question is easy to answer, as long as MySQL 5 in not executed with any strict mode options. The behavior is similar to that of MySQL 4.x and so there should be no problems.

However, I have tested some popular web applications like Mambo/Joomla, phpBB and Typo3 with db4free.net, which uses the sql-mode:

"STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION"

On Windows, this sql-mode is the default.

I'd like to start with Mambo. There is quite an old problem when multi byte character sets are used. Trying to install Mambo into a database using utf8, the creation of the tables fails here:
CREATE TABLE `mos_core_acl_aro` (
`aro_id` int(11) NOT NULL auto_increment,
`section_value` varchar(240) NOT NULL default '0',
`value` varchar(240) NOT NULL default '',
`order_value` int(11) NOT NULL default '0',
`name` varchar(255) NOT NULL default '',
`hidden` int(11) NOT NULL default '0',
PRIMARY KEY (`aro_id`),
UNIQUE KEY `section_value_value_aro` (`section_value`,`value`),
UNIQUE KEY `mos_gacl_section_value_value_aro` (`section_value`,`value`),
KEY `hidden_aro` (`hidden`),
KEY `mos_gacl_hidden_aro` (`hidden`)
) TYPE=MyISAM

The reason is quite simple: the index length is limited to 1,000 bytes in MySQL. For single byte character sets, this is a legal statement, because the sums of the indexed column lengths are still less than 1,000 bytes. However, using utf8 or any other multi byte character set, this limit is exceeded. This problem isn't new in MySQL 5, it has also occured in MySQL 4.1.

In Joomla 1.0.3, this problem has been solved - I have been able to install Joomla 1.0.3 without any problems. But also Joomla is not free of MySQL 5 related problems. Creating a new user account, this account is created, but doesn't show up in the user management backend.
Joomla screenshot
I also have found problems trying to log in at the frontend - it simply didn't work. Searching inside the code, I found the source of the problem. They tried to insert a quoted value into a tinyint field - something that's also invalid in strict mode.

The next web app that I've tested was phpBB. It already failed during the installation at this set of queries (as you can see, I've used the German version of phpBB):
phpBB screenshot
CREATE TABLE phpbb_posts_text (
post_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
bbcode_uid char(10) NOT NULL,
post_subject char(60),
post_text text,
PRIMARY KEY (post_id)
);

INSERT INTO phpbb_posts_text (post_id, post_subject, post_text) VALUES
(1, NULL, 'Das ist ein Beispiel-Beitrag. Du kannst ihn löschen, wenn Du
willst, denn so wie es aussieht, hat die Installation geklappt!

Hier noch ein paar wichtige Informationen zu phpBB

Weitere Informationen zu phpBB und seiner Benutzung und Administration
findest Du auf phpBB.de unter der URL - http://www.phpbb.de/doku/doku.php -.

Wenn Du Fragen hast oder Probleme mit einer Funktion, schau im Forum unter
der URL - http://www.phpbb.de/index.php - nach.

Da die meisten Fragen schonmal gestellt und beantwortet wurde, nutze bitte
die Suchfunktion unter der URL - http://www.phpbb.de/search.php - bevor
Du Deine Frage ins Forum schreibst.

Erweiterungen (Mods) zu phpBB findest Du unter der URL -
http://www.phpbb.de/moddb/ -.

So, und nun viel Spaß mit phpBB ;-)');

The reason for this can also be found easily. There is no default value for the column bbcode_uid, but no value has been provided for this column in the insert statement.
phpBB screenshot
Without strict mode, MySQL uses a system defined default value (in this case, an empty string), but in strict mode, a value must be provided for any field without a default value.

The third application that I've tested was Typo3. With Typo3, no errors occured during setting up the tables, so this Content Management System could possibly work with MySQL 5 without errors.

I have reported the errors that I've found to Joomla and phpBB and I hope that they solve these problems soon. There's always the danger that MySQL 5 has to take the blame for bad written queries in the web applications, because the users often don't know what the real source of the problem is. So I think that another important job to support MySQL 5 is to make developers of these web applications aware of those problems, so that they can fix them as soon as possible until they all work well with MySQL 5, also.