Skip to content

Commit

Permalink
added support for utf8mb4 character sets. Closes ifsnop#73
Browse files Browse the repository at this point in the history
  • Loading branch information
ifsnop committed Feb 2, 2015
1 parent 9bc43ca commit 3e0c083
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 42 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ Refer to the [wiki](https://github.com/ifsnop/mysqldump-php/wiki/full-example) f
'hex-blob' => true,
'databases' => false,
'add-drop-database' => false,
'skip-tz-utc' => false
'skip-tz-utc' => false,
'no-autocommit' => true,
'default-character-set' => 'utf8',
);

$pdoSettingsDefaults = array(PDO::ATTR_PERSISTENT => true,
$pdoSettingsDefaults = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
);

Expand Down Expand Up @@ -177,6 +179,14 @@ Refer to the [wiki](https://github.com/ifsnop/mysqldump-php/wiki/full-example) f
- http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html#option_mysqldump_add-drop-database
- **skip-tz-utz**
- http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html#option_mysqldump_tz-utc
- **no-autocommit**
- Option to disable autocommit (faster inserts, no problems with index keys)
- http://dev.mysql.com/doc/refman/4.1/en/commit.html
- **default-character-set**
- utf8 (default, compatible option), utf8mb4 (for full utf8 compliance)
- Could be specified using the declared consts: IMysqldump\Mysqldump::UTF8 or IMysqldump\Mysqldump::UTF8MB4BZIP2
- http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
- https://mathiasbynens.be/notes/mysql-utf8mb4

The following options are now enabled by default, and there is no way to disable them since
they should always be used.
Expand Down Expand Up @@ -215,7 +225,6 @@ Use **SHOW GRANTS FOR user@host;** to know what privileges user has. See the fol

## TODO

- Write any tests.
- Write unit tests.

## Contributing
Expand Down
27 changes: 18 additions & 9 deletions src/Ifsnop/Mysqldump/Mysqldump.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class Mysqldump
const BZIP2 = 'Bzip2';
const NONE = 'None';

// Available connection strings
const UTF8 = 'utf8';
const UTF8MB4 = 'utf8mb4';

// This can be set both on constructor or manually
public $host;
public $user;
Expand Down Expand Up @@ -85,7 +89,7 @@ public function __construct(
$dumpSettingsDefault = array(
'include-tables' => array(),
'exclude-tables' => array(),
'compress' => 'None',
'compress' => Mysqldump::NONE,
'no-data' => false,
'add-drop-table' => false,
'single-transaction' => true,
Expand All @@ -102,13 +106,14 @@ public function __construct(
'add-drop-database' => false,
'skip-tz-utz' => false,
'no-autocommit' => true,
'default-character-set' => Mysqldump::UTF8,
/* deprecated */
'disable-foreign-keys-check' => true
);

$pdoSettingsDefault = array(PDO::ATTR_PERSISTENT => true,
$pdoSettingsDefault = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
);

Expand All @@ -120,6 +125,10 @@ public function __construct(
$this->pdoSettings = self::array_replace_recursive($pdoSettingsDefault, $pdoSettings);
$this->dumpSettings = self::array_replace_recursive($dumpSettingsDefault, $dumpSettings);

if (!isset($this->pdoSettings[PDO::MYSQL_ATTR_INIT_COMMAND])) {
$this->pdoSetttings[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES " . $this->dumpSettings['default-character-set'];
}

$diff = array_diff(array_keys($this->dumpSettings), array_keys($dumpSettingsDefault));
if (count($diff)>0) {
throw new Exception("Unexpected value in dumpSettings: (" . implode(",", $diff) . ")");
Expand Down Expand Up @@ -178,7 +187,7 @@ private function connect()
$this->pdoSettings
);
// Fix for always-unicode output
$this->dbHandler->exec("SET NAMES utf8");
$this->dbHandler->exec("SET NAMES " . $this->dumpSettings['default-character-set']);
// Store server version
$this->version = $this->dbHandler->getAttribute(PDO::ATTR_SERVER_VERSION);
break;
Expand Down Expand Up @@ -441,7 +450,7 @@ private function getTableStructure($tableName)
);
}
$this->compressManager->write(
$this->typeAdapter->create_table($r)
$this->typeAdapter->create_table($r, $this->dumpSettings)
);
break;
}
Expand Down Expand Up @@ -915,7 +924,7 @@ public function show_create_table($tableName)
* function create_table Get table creation code from database
* @todo make it do something with sqlite
*/
public function create_table($row)
public function create_table($row, $dumpSettings)
{
return "";
}
Expand Down Expand Up @@ -1163,14 +1172,14 @@ public function show_create_trigger($triggerName)
return "SHOW CREATE TRIGGER `$triggerName`";
}

public function create_table($row)
public function create_table($row, $dumpSettings)
{
if (!isset($row['Create Table'])) {
throw new Exception("Error getting table code, unknown output");
}

$ret = "/*!40101 SET @saved_cs_client = @@character_set_client */;" . PHP_EOL .
"/*!40101 SET character_set_client = utf8 */;" . PHP_EOL .
"/*!40101 SET character_set_client = " . $dumpSettings['default-character-set'] . " */;" . PHP_EOL .
$row['Create Table'] . ";" . PHP_EOL .
"/*!40101 SET character_set_client = @saved_cs_client */;" . PHP_EOL .
PHP_EOL;
Expand Down Expand Up @@ -1462,7 +1471,7 @@ public function backup_parameters()
$ret = "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;" . PHP_EOL .
"/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;" . PHP_EOL .
"/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;" . PHP_EOL .
"/*!40101 SET NAMES utf8 */;" . PHP_EOL;
"/*!40101 SET NAMES " . $dumpSettings['default-character-set'] . " */;" . PHP_EOL;

if (false === $dumpSettings['skip-tz-utz']) {
$ret .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;" . PHP_EOL .
Expand Down
15 changes: 14 additions & 1 deletion tests/test.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@
"mysql",
$dumpSettings);

$dump->start("mysqldump-php.sql");
$dump->start("mysqldump-php_test001.sql");


$dumpSettings['default-character-set'] = IMysqldump\Mysqldump::UTF8MB4;

$dump = new IMysqldump\Mysqldump(
"test002",
"travis",
"",
"localhost",
"mysql",
$dumpSettings);

$dump->start("mysqldump-php_test002.sql");

exit;
84 changes: 56 additions & 28 deletions tests/test.sh
Original file line number Diff line number Diff line change
@@ -1,59 +1,87 @@
#!/bin/bash

function checksum() {
function checksum_test001() {
for i in 000 001 002 003 010 011 015 027 029 033 200; do
mysql -B -e "CHECKSUM TABLE test${i}" test001 | grep -v -i checksum
done
}

function checksum_test002() {
for i in 201; do
mysql --default-character-set=utf8mb4 -B -e "CHECKSUM TABLE test${i}" test002 | grep -v -i checksum
done
}

for i in $(seq 0 20) ; do
ret[i]=0
ret[$i]=0
done

mysql -uroot < original.sql
ret[0]=$?
mysql -e "CREATE USER 'travis'@'localhost' IDENTIFIED BY '';" 2> /dev/null
mysql -e "GRANT ALL PRIVILEGES ON test001.* TO 'travis'@'localhost';" 2> /dev/null
mysql -e "GRANT ALL PRIVILEGES ON test002.* TO 'travis'@'localhost';" 2> /dev/null

mysql -uroot < test001.src.sql; ret[0]=$?

mysql -uroot --default-character-set=utf8mb4 < test002.src.sql; ret[1]=$?

checksum > original.checksum
checksum_test001 > test001.src.checksum
checksum_test002 > test002.src.checksum

mysqldump -uroot test001 \
--no-autocommit \
--extended-insert=false \
--hex-blob=true \
> mysqldump.sql
ret[1]=$?

php test.php
> mysqldump_test001.sql
ret[2]=$?

mysql -uroot test001 < mysqldump-php.sql
mysqldump -uroot test002 \
--no-autocommit \
--extended-insert=false \
--hex-blob=true \
--default-character-set=utf8mb4 \
> mysqldump_test002.sql
ret[3]=$?

checksum > mysqldump-php.checksum

cat original.sql | grep ^INSERT > original.filtered.sql
cat mysqldump.sql | grep ^INSERT > mysqldump.filtered.sql
cat mysqldump-php.sql | grep ^INSERT > mysqldump-php.filtered.sql

diff original.filtered.sql mysqldump.filtered.sql
php test.php
ret[4]=$?

diff original.filtered.sql mysqldump-php.filtered.sql
mysql -uroot test001 < mysqldump-php_test001.sql
ret[5]=$?

diff original.checksum mysqldump-php.checksum
mysql -uroot test002 < mysqldump-php_test002.sql
ret[6]=$?

rm original.checksum
rm mysqldump-php.checksum
rm original.filtered.sql
rm mysqldump.filtered.sql
rm mysqldump-php.filtered.sql
rm mysqldump-php.sql
rm mysqldump.sql
checksum_test001 > mysqldump-php_test001.checksum
checksum_test002 > mysqldump-php_test002.checksum

cat test001.src.sql | grep ^INSERT > test001.filtered.sql
cat test002.src.sql | grep ^INSERT > test002.filtered.sql
cat mysqldump_test001.sql | grep ^INSERT > mysqldump_test001.filtered.sql
cat mysqldump_test002.sql | grep ^INSERT > mysqldump_test002.filtered.sql
cat mysqldump-php_test001.sql | grep ^INSERT > mysqldump-php_test001.filtered.sql
cat mysqldump-php_test002.sql | grep ^INSERT > mysqldump-php_test002.filtered.sql

diff test001.filtered.sql mysqldump_test001.filtered.sql
ret[7]=$?
diff test002.filtered.sql mysqldump_test002.filtered.sql
ret[8]=$?

diff test001.filtered.sql mysqldump-php_test001.filtered.sql
ret[9]=$?
diff test002.filtered.sql mysqldump-php_test002.filtered.sql
ret[10]=$?

diff test001.src.checksum mysqldump-php_test001.checksum
ret[11]=$?
diff test002.src.checksum mysqldump-php_test002.checksum
ret[12]=$?

rm *.checksum 2> /dev/null
rm *.filtered.sql 2> /dev/null
rm mysqldump* 2> /dev/null

total=0
for i in $(seq 0 20) ; do
total=(${ret[i]} + $total)
total=$((${ret[$i]} + $total))
done

exit $total
File renamed without changes.
13 changes: 13 additions & 0 deletions tests/test002.src.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
DROP DATABASE IF EXISTS `test002`;
CREATE DATABASE `test002`;
USE `test002`;

DROP TABLE IF EXISTS `test201`;
CREATE TABLE `test201` (
`col` text COLLATE utf8mb4_unicode_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `test201` VALUES ('áéíóú');
INSERT INTO `test201` VALUES ('🎲');
INSERT INTO `test201` VALUES ('🎭');
INSERT INTO `test201` VALUES ('💩');

0 comments on commit 3e0c083

Please sign in to comment.