Port your database dump from MySQL to PostgreSQL easily with this PHP script, the article also explains how it works.
You probably have heard of PEAR::DB, you may have even used it, if not let me EXPLAIN - it is a library for database abstraction. PEAR::DB is made to help people port their code to another database backend. That's very good but RDBMS's tend to use different syntaxes and people need to convert the SQL code too.
I have used PEAR::DB for a couple of months (7 Jul 2002), and it works perfectly with the MySQL server, so I decided I need to test it against other databases too. As PostgreSQL is a nice Open Source database, a lot more advanced than MySQL, it seemed like a good choice for me.
I installed PostgreSQL FROM sources and it worked, I was able to connect
through the bundled client, but this was the moment my problems started.
I had a tough time testing different DSN's
until I found that I only had to add unix before the database host
and separate it with a + FROM it. It seems that the PostgreSQL
driver defaults to TCP/IP sockets and the MySQL to Unix as I've always used unix
sockets for MySQL.
The first problem I encountered was that PostgreSQL doesn't like MySQL dumps, so after studying the PostgreSQL docs I came to this translation TABLE that I need to use.
| MySQL | PostgreSQL |
|---|---|
| # MySQL comment | --ANSI SQL comment |
| UNIQUE KEY name (cols) | UNIQUE (cols) |
| PRIMARY KEY (cols) | the same |
| KEY name (cols) | CREATE INDEX name ON TABLE (cols) |
| id int NOT NULL auto_increment | id SERIAL |
| binary | doesn't exist |
| enum | doesn't exist, convert to varchar |
| tinyint(n) or smallint(n) | smallint |
| mediumint(n) or int(n) | int |
MySQL default dumps FROM version 3.23.49 on use the ANSI SQL comment style with a required space after --.
I also found that PostgreSQL doesn't accept dates like 0000-00-00, so I had to strip default values FROM date/datetime columns.
Note: There is no need to convert the defaultINSERT statements as they are compatible with PostgreSQL, only the DATA types are different.
The code is written to be used FROM the commandline not a webserver. I recompiled PHP several times with different configure lines but it always said
that $argv is undefined so the filenames are hard-coded.
You'll have to redefine $enum if it doesn't match your needs for a substitution of enum are different.
#!/usr/local/bin/php -q
<?php
$source = "/home/shaggy/shaggy.sql";
$output = "/home/shaggy/pgtest.sql";
$enum = 'varchar(10)'; // convert enum to this
if ( !file_exists($source) ) {
die("File not found: $sourcen");
}
$fd = fopen($source, "r");
$result = fread($fd, filesize($source));
fclose($fd);
$result = mysql2postgre($result);
$fd = fopen($output, "w");
if (fwrite($fd, $result)) {
echo "OKn";
} else {
echo "Failedn";
}
fclose($fd);
function mysql2postgre($source) {
global $enum;
$result = $source;
$result = preg_replace('/Type=MyISAM/i', '', $result);
// convert line comments
$result = preg_replace("/#(.*)/", '--$1', $result);
// and compress newlines
$result = preg_replace("/n{2,}/", "nn", $result);
// get rid of proprietary code
$result = preg_replace("/DROP TABLE IF EXISTSW+.+/i", '', $result);
// indices
$result = preg_replace("/(.*)UNIQUE KEY.+((.+))/i",
"$1UNIQUE ($2)", $result);
// a little hack to save primary keys
$result = preg_replace("/(.*)PRIMARY KEY.+((.+))/i",
"$1PRIMARY ($2)", $result);
$result = preg_replace("/,n.*KEYW.+((.+))/i",
"n-- was KEY ($1)", $result);
$result = preg_replace("/(.*)PRIMARY.+((.+))/i",
"$1PRIMARY KEY (\2)", $result);
$result = preg_replace("/(.*?)(w+).+auto_increment/i",
'$1$2 SERIAL', $result);
// Postgre doesn't support the binary modifier
$result = preg_replace('/binary/i', '', $result);
// type transformations
$result = preg_replace('/enum(.+)/i', $enum, $result);
$result = preg_replace('/tinyint(.+)/i', 'smallint', $result);
$result = preg_replace('/smallint(.+)/i', 'smallint', $result);
$result = preg_replace('/meduimint(.+)/i', 'int', $result);
$result = preg_replace('/int(.+)/i', 'int', $result);
// Most of my default dates are '0000-00-00'
$result = preg_replace("/datetime(.*) default '.*'/i",
'datetime$1', $result);
$result = preg_replace("/date(.*) default '.*'/i",
'date$1', $result);
return $result;
}
?>
I am using the PCRE regular expressions instead of POSIX because they are generally faster.
The first regular expression removes the Type=MyISAM identifier
that is used in MySQL to set the TABLE type, change it if you use InnoBD or BDB tables.
The code should process any input but it is recommended to use a dump from
mysqldump or a similar application.
Comments
enum
I have found an interesting approach to converting ENUM:
(http://archives.postgresql.org/pgsql-sql/2002-03/msg00273.php)
"enum('s','n')
I changed it for:
col1 CHAR CHECK (col1 IN ('s','n'))
Which is SQL. :-)
If what is enumerated are numbres, just use INT instead of CHAR.
Saludos... :-)"
PHP code was a cut & paste for me
Thanks, Martin, migrating from MySQL to PostgreSQL was a breeze thanks to your little swab of code. I just had to change some fields named "user" to "usr".
cheers!
Datetime...
Thanks, this is a great script Martin...
How did you guys handle the "datetime" datatype in postgre?
Jonez
datetime datatype
For others who might come across this page, postgresql's datetime equivalent would be:TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP precision
And to note PostgreSQL's TIMESTAMP precision ranges from 0 to 13, which is out of bounds to MySQL's TIMESTAMP default precision of 14... thats another thing to modify inside the dumps
How do we convert postgresqldatabase to mysql
its very informative
Do u know the conversion from access to postgresql or postgresql to mysql
PostreSQL to MySQL or Access to PostreSQL
Renju it's pretty difficult to convert a PostgreSQL dump into MySQL without losing lots of the definitions. It would also require a lot more processing and may not be exactly a linear process.
As for Access I haven't used it much.
Access to PostgreSQL or MySQL
Go to
http://www.intranet2internet.com/public/default.asp?PAGE=download&ID=DUM...
and get AccessDUMP. It's a freebie that will dump your .mdb to MySQL format. Then just take your resulting .sql file, put on the mysql box, run 'mysql < accessdump.sql', and you are set :)
By the way, I bought the 'Pro' version of AccessDUMP, and give it about 1 star. Don't bother, just stick with the freebie, as there are bugs in the Pro version and the author won't answer any emails (even from a paying customer). The extra features you get for paying aren't worth it IMHO, but hey, the guy's software gets used daily, so I paid up :)
Very useful. Thank you!
Great script. I just had to make a few changes (other than the obvious file names and changing the shebang line to where my bin/php command is.
- The script missed some "mediumint" datatypes. I just changed these to "integer"
- The script did not remove "unsigned" declarations. Wherever these were used was not a problem for me, so I just deleted them and used regular integer types.
- The script inserted a comment part way through a create table command. The comma for the line containing the column definition was placed at the end of the inserted comment (and as a result was ignored), creating a syntax error and the table wasn't created. I just put a comma back where it should have been and everything was fixed.
Thanks a bunch.
Thanks - saved me a load of pain
Needed some extra hacks - e.g. MySQL uses backticks - ` - which can apparently all be deleted, had some problems with BLOBs - but this was still a real timesaver. Thank you!
convert postgresql to mysql
can we convert postgresql to mysql using trigger and view features
it's a good thing if enum names are also given a constraint name and definition.
data-integrity is just so important :P
Hi,
I've modified your script above to make it handle what I get spat out of a MySQL 5 db; it appears to go into PGSQL without any problems (aside from numeric(5,2) perhaps needing to be something better like a decimal??)
Hope it's of some use to someone.
It does the enum conversion to a "VARCHAR CHECK (field IN ('a', 'list', 'here'))" which appears to be ok (at least pgsql allows me to create the table from the code; haven't tried actually using the resultant tables yet.... so it might be rubbish)
http://projects.codepoets.co.uk/ or http://projects.codepoets.co.uk/trac.cgi/browser/scripts/mysql2pgsql.php