├── .gitignore ├── Readme.md ├── composer.json ├── bin └── convert.php ├── LICENSE └── src ├── Convert.php └── TableConvert.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.idea/ 3 | .composer.lock 4 | composer.lock 5 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## SQLite Migrate To MySQL 2 | 3 | Simply convert and transfer sqlite database to mysql database. 4 | 5 | ### Install 6 | 7 | ```bash 8 | git clone project 9 | composer install 10 | ``` 11 | 12 | ### Usage 13 | 14 | Try example: 15 | ```bash 16 | php bin\convert.php -s sqlite3.db -m mysql://root:123456@127.0.0.1:3306/WxDB_2017 17 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loveyu/sqlite-2-mysql", 3 | "authors": [ 4 | { 5 | "name": "loveyu", 6 | "email": "i@loveyu.info" 7 | } 8 | ], 9 | "autoload": { 10 | "psr-4": { 11 | "Loveyu\\SQLite2MySQL\\":"src/" 12 | } 13 | }, 14 | "require": { 15 | "cheprasov/php-cli-args": "^2.1", 16 | "catfan/Medoo": "^1.5", 17 | "ext-pdo": "*" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bin/convert.php: -------------------------------------------------------------------------------- 1 | 's', 18 | "mysql" => "m" 19 | ]); 20 | 21 | $sqlite = $CliArgs->getArg("s"); 22 | $mysql = $CliArgs->getArg("m"); 23 | 24 | return Convert::stdConvert($sqlite,$mysql); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 loveyu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Convert.php: -------------------------------------------------------------------------------- 1 | 'sqlite', 35 | 'database_file' => $sqlite 36 | ]); 37 | $mysql_cfg = self::parseMySQL($mysql); 38 | 39 | $mysql_pdo = new Medoo($mysql_cfg); 40 | 41 | $migrate = new TableConvert($sqlite_pdo, $mysql_pdo); 42 | try { 43 | $migrate->migrate(); 44 | } catch(\Exception $exception) { 45 | self::error($exception->getMessage()); 46 | self::error($exception->getTraceAsString()); 47 | 48 | return 2; 49 | } 50 | return 0; 51 | } 52 | 53 | private static function parseMySQL(string $mysql): array 54 | { 55 | $parseUrl = parse_url($mysql); 56 | if(empty($parseUrl['path'])){ 57 | throw new \RuntimeException("Error DB Name"); 58 | } 59 | return [ 60 | 'database_type' => isset($parseUrl['scheme'])?$parseUrl['scheme']:"mysql", 61 | 'database_name' => trim($parseUrl['path'], "/"), 62 | 'server' => isset($parseUrl['host']) ? $parseUrl['host'] : 'localhost', 63 | 'username' => isset($parseUrl['user']) ? $parseUrl['user'] : 'root', 64 | 'password' => isset($parseUrl['pass']) ? $parseUrl['pass'] : '', 65 | 'charset' => 'utf8mb4', 66 | 'port' => isset($parseUrl['port']) ? (int)$parseUrl['port'] : 3306, 67 | ]; 68 | } 69 | } -------------------------------------------------------------------------------- /src/TableConvert.php: -------------------------------------------------------------------------------- 1 | sqliteMedoo = $sqliteMedoo; 32 | $this->mysqlMedoo = $mysqlMedoo; 33 | } 34 | 35 | public function migrate() 36 | { 37 | $tables = $this->getTables(); 38 | $this->mysqlMedoo->pdo->beginTransaction(); 39 | foreach($tables as $table) { 40 | echo "Create Table .....[{$table}]...", PHP_EOL; 41 | $sql = $this->getMigrateSqlFromTable($table); 42 | $this->mysqlMedoo->exec($sql); 43 | 44 | echo "Transfer Data ....[{$table}]...", PHP_EOL; 45 | $this->dataTransfer($table); 46 | } 47 | $this->mysqlMedoo->pdo->commit(); 48 | } 49 | 50 | private function dataTransfer(string $table) 51 | { 52 | $stmt = $this->sqliteMedoo->query("select * from {$table}"); 53 | $loop = true; 54 | $insert_list = []; 55 | $i = 0; 56 | while($loop) { 57 | $data = $stmt->fetch(\PDO::FETCH_ASSOC); 58 | if($data === false) { 59 | break; 60 | } 61 | $insert_list[] = $data; 62 | $i++; 63 | if($i === 1000) { 64 | $this->mysqlMedoo->insert($table, $insert_list); 65 | $i = 0; 66 | $insert_list = []; 67 | } 68 | } 69 | if(!empty($insert_list)) { 70 | $this->mysqlMedoo->insert($table, $insert_list); 71 | } 72 | } 73 | 74 | private function getMigrateSqlFromTable(string $table) 75 | { 76 | $stmt = $this->sqliteMedoo->query("PRAGMA table_info(\"{$table}\")"); 77 | $list = $stmt->fetchAll(\PDO::FETCH_ASSOC); 78 | $sql = "DROP TABLE IF EXISTS `{$table}`;\n"; 79 | $sql .= "CREATE TABLE IF NOT EXISTS `{$table}`(\n"; 80 | $fields = []; 81 | $keys = []; 82 | $generateType = function($item) use ($table) { 83 | $type = "text"; 84 | $input_type = $item['type']; 85 | $input_size = 0; 86 | if(preg_match("/^varchar\\(([\d]+)\\)$/i", $input_type, $matches) == 1) { 87 | $input_type = "varchar"; 88 | $input_size = (int)$matches[1]; 89 | } 90 | switch(strtolower($input_type)) { 91 | case "text": 92 | $type = "text"; 93 | if(!empty($item['pk']) && $item['pk'] == 1) { 94 | $type = "varchar(768)"; 95 | } 96 | break; 97 | case "varchar": 98 | $type = "varchar({$input_size})"; 99 | break; 100 | case "integer": 101 | case "int": 102 | $type = "int(11)"; 103 | break; 104 | case "short": 105 | $type = "int(11)"; 106 | break; 107 | case "long": 108 | $type = "bigint(20)"; 109 | break; 110 | case "double": 111 | $type = "double"; 112 | break; 113 | case "byte[]": 114 | case "blob": 115 | case "blog": 116 | $type = "blob"; 117 | break; 118 | default: 119 | print_r($table); 120 | print_r($item); 121 | exit; 122 | } 123 | if(!empty($item['notnull']) && $item['notnull'] == 1) { 124 | $type .= " NOT NULL"; 125 | } 126 | if($item['dflt_value'] !== null && $item['dflt_value'] !== "") { 127 | $type .= " DEFAULT '{$item['dflt_value']}'"; 128 | } 129 | return $type; 130 | }; 131 | foreach($list as $item) { 132 | if($item['pk'] == "1") { 133 | $keys[] = " PRIMARY KEY ( `{$item['name']}` )"; 134 | } 135 | $type = $generateType($item); 136 | $fields[] = "`{$item['name']}` {$type}"; 137 | } 138 | $sql .= implode(",\n", array_merge($fields, $keys))."\n);"; 139 | return $sql; 140 | } 141 | 142 | private function getTables() 143 | { 144 | $list = $this->sqliteMedoo->select("sqlite_master", ["name"], [ 145 | "type" => "table", 146 | "ORDER" => ["name" => "ASC"] 147 | ]); 148 | $tables = array_column($list, "name"); 149 | return (array)$tables; 150 | } 151 | } --------------------------------------------------------------------------------