Files
EasySoft-ZenTaoPMS/misc/mysql2dm.php
T

314 lines
10 KiB
PHP

#!/usr/bin/env php
<?php
include '../framework/helper.class.php';
include '../lib/dbh/dbh.class.php';
$config = new stdclass();
$config->db = new stdclass();
$config->default = new stdclass();
include '../config/my.php';
if (!file_exists('dmconfig.php')) {
print("Please create the config file named 'dmconfig.php' in this directory. Config example:");
print <<<EOT
<?php
\$dmConfig = new stdclass();
\$dmConfig->driver = 'dm';
\$dmConfig->host = '10.0.7.242';
\$dmConfig->port = '5236';
\$dmConfig->name = 'lybiz85';
\$dmConfig->user = 'SYSDBA';
\$dmConfig->encoding = 'UTF8';
\$dmConfig->prefix = 'zt_';
\$dmConfig->password = 'SYSDBA001';
EOT;
exit;
}
echo "开始迁移MySQL数据到达梦数据库\n\n";
include 'dmconfig.php';
function formatSQL($sql)
{
$fieldsBegin = stripos($sql, 'select');
$fieldsEnd = stripos($sql, 'from');
$fields = substr($sql, $fieldsBegin + 6, $fieldsEnd - $fieldsBegin - 6);
$fieldList = preg_split("/,(?![^(]+\))/", $fields);
foreach ($fieldList as $key => $field) {
$aliasPos = stripos($field, ' AS ');
$subField = substr($field, 0, $aliasPos);
if (stripos($field, 'SUM(') === 0) $subField = substr($subField, 4, -1);
$fieldParts = preg_split("/\+(?![^(]+\))/", $subField);
foreach ($fieldParts as $pkey => $fieldPart) {
$originField = trim($fieldPart);
if (stripos($originField, 'if(') === false) continue;
$fieldParts[$pkey] = formatDmIfFunction($originField);
}
$fieldList[$key] = str_replace($subField, implode(' + ', $fieldParts), $field);
}
$fields = implode(',', $fieldList);
return substr($sql, 0, $fieldsBegin + 6) . $fields . substr($sql, $fieldsEnd);
}
function formatDmIfFunction($field)
{
preg_match('/if\(.+\)+/i', $field, $matches);
$if = $matches[0];
if (substr_count($if, '(') == 1) {
$pos = strpos($if, ')');
$if = substr($if, 0, $pos + 1);
}
/* fix sum(if(..., 1, 0)) , count(if(..., 1, 0)) */
if (substr($if, strlen($if) - 2) == '))' and (stripos($field, 'sum(') == 0 or stripos($field, 'count(') == 0)) $if = substr($if, 0, strlen($if) - 1);
$parts = explode(',', substr($if, 3, strlen($if) - 4)); // remove 'if(' and ')'
$case = 'CASE WHEN ' . implode(',', array_slice($parts, 0, count($parts) - 2)) . ' THEN ' . $parts[count($parts) - 2] . ' ELSE ' . $parts[count($parts) - 1] . ' END';
$field = str_ireplace($if, $case, $field);
return $field;
}
$mysql = new dbh($config->db);
$stmt = $mysql->query('SHOW TABLES');
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$tables = array();
$views = array();
$indexes = array(); //普通索引
$tablePrimary = array(); //表的主键
foreach ($data as $table) {
$table = current($table);
/* Table. */
if (strpos($table, 'zt_') === 0) {
$stmt = $mysql->prepare('DESC ' . $table);
$stmt->execute();
$fields = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* Table. */
$tables[$table] = array();
foreach ($fields as $field) {
$type = strtolower(explode('(', $field['Type'])[0]);
$type = trim(str_replace('unsigned', '', $type));
switch ($type) {
case 'int':
case 'mediumint':
case 'smallint':
case 'tinyint':
$type = 'integer';
break;
case 'enum':
case 'varchar':
case 'char':
$type = 'varchar(1000)';
break;
case 'mediumtext':
case 'longtext':
$type = 'text';
break;
}
$tables[$table][$field['Field']] = array(
'type' => $type,
'name' => $field['Field'],
'null' => $field['Null'] == 'YES',
'default' => $field['Default'],
//'isPrimary' => $field['Key'] == 'PRI', // 不需要从DESC读取索引
'autoIncrement' => $field['Extra'] == 'auto_increment',
);
}
/* Index. */
$stmt = $mysql->prepare('SHOW INDEX FROM ' . $table);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result) {
foreach ($result as $item) {
$keyName = $item['Key_name'];
/* 主键索引在创建表的时候一起创建。 */
if ($keyName == 'PRIMARY') {
if (!isset($tablePrimary[$table])) $tablePrimary[$table] = array();
$tablePrimary[$table][(int)$item['Seq_in_index'] - 1] = $item['Column_name'];
continue;
}
/* 其他索引单独创建。 */
if (!isset($indexes[$table . $keyName])) $indexes[$table . $keyName] = array('table' => $table, 'name' => $keyName, 'type' => $item['Index_type'], 'isUnique' => !$item['Non_unique'], 'cols' => array());
/* 达梦的全文索引只支持一个字段。 */
if ($item['Index_type'] == 'FULLTEXT' && $item['Column_name'] != 'title') continue;
$indexes[$table . $keyName]['cols'][(int)$item['Seq_in_index'] - 1] = $item['Column_name'];
}
}
}
/* View. */ elseif (strpos($table, 'ztv_') === 0) {
$stmt = $mysql->prepare('SHOW CREATE VIEW ' . $table);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$pos = stripos($result[0]['Create View'], ' as ');
$sql = substr($result[0]['Create View'], $pos + 4);
$sql = str_replace('`', '"', $sql);
$views[$table] = array(
'sql' => formatSQL($sql),
);
}
}
echo "初始化表空间和用户\n";
$dm = new dbh($dmConfig, false);
/* Delete. */
$res = $dm->query("SELECT * FROM dba_users WHERE username = '{$dmConfig->name}'")->fetchAll();
if (!empty($res)) {
$dropUser = "DROP USER \"{$dmConfig->name}\" CASCADE";
$dm->rawQuery($dropUser);
}
$tableSpace = strtoupper($dmConfig->name);
$res = $dm->query("SELECT * FROM dba_data_files WHERE TABLESPACE_NAME = '$tableSpace'")->fetchAll();
if (!empty($res)) {
$dropTableSpace = "DROP TABLESPACE \"$tableSpace\"";
$dm->rawQuery($dropTableSpace);
}
/* Create. */
//$createTableSpace = "CREATE TABLESPACE \"$tableSpace\" DATAFILE '{$dmConfig->name}.DBF' size 150 AUTOEXTEND ON";
//$createUser = "CREATE USER \"{$dmConfig->name}\" IDENTIFIED by \"{$dmConfig->password}\" DEFAULT TABLESPACE \"{$dmConfig->name}\" DEFAULT INDEX TABLESPACE \"{$dmConfig->name}\"";
//
//$dm->query($createTableSpace);
//$dm->query($createUser);
$createSchema = "CREATE SCHEMA \"{$dmConfig->name}\" AUTHORIZATION \"{$dmConfig->user}\"";
$dm->query($createSchema);
echo "生成达梦数据表结构\n";
$dm = new dbh($dmConfig);
$identityTables = array(); //标记有自增字段的表,插入数据的时候会判断
/* 插入表结构。 */
foreach ($tables as $table => $fields) {
$sql = "CREATE TABLE IF NOT EXISTS \"$table\" (\n";
foreach (array_values($fields) as $key => $field) {
$sql .= '"' . $field['name'] . '" ' . $field['type'] . ($field['null'] ? ' NULL ' : ' NOT NULL ');
if($field['default'] == '0000-00-00') $field['default'] = NULL;
if($field['default'] !== NULL && $field['default'] != 'CURRENT_TIMESTAMP') $sql .= " DEFAULT '{$field['default']}' ";
if ($field['autoIncrement']) {
$sql .= " IDENTITY(1, 1) ";
$identityTables[$table] = $table;
}
$sql .= $key == count(array_values($fields)) - 1 && !isset($tablePrimary[$table]) ? "\n" : ",\n";
}
if (isset($tablePrimary[$table])) {
$primary = array();
ksort($tablePrimary[$table]);
foreach ($tablePrimary[$table] as $col) $primary[] = '"' . $col . '"';
$sql .= "NOT CLUSTER PRIMARY KEY (" . implode(',', $primary) . ")"; // 只有NOT CLUSTER可以删除
}
$sql .= "\n)\n";
$dm->rawQuery($sql);
}
echo "生成达梦表索引\n";
foreach ($indexes as $index) {
$name = strtolower($index['table']) . '_' . $index['name'];
foreach ($index['cols'] as $col) {
$fields = array();
ksort($index['cols']);
foreach ($index['cols'] as $col) {
$fields[] = '"' . $col . '"';
}
}
$sql = 'CREATE ';
if ($index['isUnique']) // 唯一索引
{
$sql .= ' UNIQUE ';
} elseif ($index['type'] == 'FULLTEXT') // 全文索引
{
$sql .= ' CONTEXT ';
}
$sql .= ' INDEX "' . $name . '" ON `' . $index['table'] . '` (' . implode(',', $fields) . ')';
$dm->rawQuery($sql);
}
echo "生成达梦视图\n";
/* 插入视图结构。 */
foreach ($views as $view => $info) {
$sql = str_replace('convert(', '(', $info['sql']);
$sql = str_replace('using utf8mb3', '', $sql);
$sql = str_replace('using utf8_general_ci', '', $sql);
$dm->rawQuery("CREATE OR REPLACE VIEW \"$view\" AS " . $sql);
}
echo "开始插入数据,请耐心等待...";
foreach ($tables as $table => $fields) {
$dm->rawQuery("DELETE FROM `$table`");
if ($table == 'zt_compile') continue;
$rows = $mysql->query("SELECT * FROM `$table`")->fetchAll(PDO::FETCH_ASSOC);
if (empty($rows)) continue;
$fs = array();
foreach ($fields as $field) $fs[] = '"' . $field['name'] . '"';
$fs = implode(',', $fs);
$template = "INSERT INTO \"$table\"($fs) VALUES";
$step = 5000;
$begin = 0;
while ($begin < count($rows)) {
$data = array();
for ($key = $begin; $key < $begin + $step; $key++) {
if (!isset($rows[$key])) continue;
$row = $rows[$key];
$values = array();
foreach ($fields as $field) {
$value = str_replace("'", "''''", $row[$field['name']]);
$value = "'{$value}'";
if ($value == "'0000-00-00 00:00:00'" || $value == "'0000-00-00'") {
$null = $tables[$table][$field['name']]['null'];
$value = $null ? 'NULL' : '1970-01-01';
}
$values[] = $value;
}
$values = '(' . implode(',', $values) . ')';
$data[] = $values;
}
$begin += $step;
if (empty($data)) continue;
$sql = $template . implode(',', $data) . ';';
if (isset($identityTables[$table])) $sql = "SET IDENTITY_INSERT $table ON;" . $sql;
//file_put_contents('./a.sql', $sql. "\n", FILE_APPEND);
$dm->rawQuery($sql);
}
}
echo "\n迁移成功,修改my.php测试一下吧\n\n";