dolibarr-postgres2mysql.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. #!/usr/bin/env php
  2. <?php
  3. /*
  4. * Copyright (C) 2005-2011 James Grant <james@lightbox.org> Lightbox Technologies Inc.
  5. * Copyright (C) 2020 Laurent Destailleur <eldy@users.sourceforge.net>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. *
  20. * This file is base on pg2mysql provided as Open source by lightbox.org.
  21. * It was enhanced and updated by the Dolibarr team.
  22. */
  23. /**
  24. * \file dev/tools/dolibarr-postgres2mysql.php
  25. * \brief Script to migrate a postgresql dump into a mysql dump
  26. */
  27. $sapi_type = php_sapi_name();
  28. $script_file = basename(__FILE__);
  29. $path = dirname(__FILE__) . '/';
  30. // Test si mode batch
  31. $sapi_type = php_sapi_name();
  32. if (substr($sapi_type, 0, 3) == 'cgi') {
  33. echo "Error: You are using PHP for CGI. To execute " . $script_file . " from command line, you must use PHP for CLI mode.\n";
  34. exit();
  35. }
  36. error_reporting(E_ALL & ~E_DEPRECATED);
  37. define('PRODUCT', "pg2mysql");
  38. define('VERSION', "2.0");
  39. // this is the default, it can be overridden here, or specified as the third parameter on the command line
  40. $config['engine'] = "InnoDB";
  41. if (!($argv[1] && $argv[2])) {
  42. echo "Usage: php pg2mysql_cli.php <inputfilename> <outputfilename> [engine]\n";
  43. exit();
  44. } else {
  45. if (isset($argv[3])) {
  46. $config['engine'] = $argv[3];
  47. }
  48. pg2mysql_large($argv[1], $argv[2]);
  49. echo <<<XHTML
  50. Notes:
  51. - No its not perfect
  52. - Yes it discards ALL stored procedures
  53. - Yes it discards ALL queries except for CREATE TABLE and INSERT INTO
  54. - If you're having problems creating your postgres dump, make sure you use "--format p --inserts"
  55. - Default output engine if not specified is InnoDB
  56. XHTML;
  57. }
  58. /**
  59. * getfieldname
  60. *
  61. * @param string $l String
  62. * @return string|null Field name
  63. */
  64. function getfieldname($l)
  65. {
  66. // first check if its in nice quotes for us
  67. $regs = array();
  68. if (preg_match("/`(.*)`/", $l, $regs)) {
  69. if ($regs[1]) {
  70. return $regs[1];
  71. } else {
  72. return null;
  73. }
  74. } elseif (preg_match("/([^\ ]*)/", trim($l), $regs)) {
  75. // if its not in quotes, then it should (we hope!) be the first "word" on the line, up to the first space.
  76. if ($regs[1]) {
  77. return $regs[1];
  78. } else {
  79. return null;
  80. }
  81. }
  82. }
  83. /**
  84. * formatsize
  85. *
  86. * @param string $s Size to format
  87. * @return string Formated size
  88. */
  89. function formatsize($s)
  90. {
  91. if ($s < pow(2, 14)) {
  92. return "{$s}B";
  93. } elseif ($s < pow(2, 20)) {
  94. return sprintf("%.1f", round($s / 1024, 1)) . "K";
  95. } elseif ($s < pow(2, 30)) {
  96. return sprintf("%.1f", round($s / 1024 / 1024, 1)) . "M";
  97. } else {
  98. return sprintf("%.1f", round($s / 1024 / 1024 / 1024, 1)) . "G";
  99. }
  100. }
  101. /**
  102. * pg2mysql_large
  103. *
  104. * @param string $infilename Input filename
  105. * @param string $outfilename Output filename
  106. * @return int <0 if KO, >=0 if OK
  107. */
  108. function pg2mysql_large($infilename, $outfilename)
  109. {
  110. $infp = fopen($infilename, "rt");
  111. $outfp = fopen($outfilename, "wt");
  112. $outputatend = '';
  113. $arrayofprimaryalreadyintabledef = array();
  114. // we read until we get a semicolon followed by a newline (;\n);
  115. $pgsqlchunk = array();
  116. $chunkcount = 1;
  117. $linenum = 0;
  118. $inquotes = false;
  119. $first = true;
  120. if (empty($infp)) {
  121. print 'Failed to open file '.$infilename."\n";
  122. return -1;
  123. }
  124. $fs = filesize($infilename);
  125. echo "Filesize: " . formatsize($fs) . "\n";
  126. while ($instr = fgets($infp)) {
  127. $linenum++;
  128. $memusage = round(memory_get_usage(true) / 1024 / 1024);
  129. $len = strlen($instr);
  130. $pgsqlchunk[] = $instr;
  131. $c = substr_count($instr, "'");
  132. // we have an odd number of ' marks
  133. if ($c % 2 != 0) {
  134. if ($inquotes) {
  135. $inquotes = false;
  136. } else {
  137. $inquotes = true;
  138. }
  139. }
  140. if ($linenum % 10000 == 0) {
  141. $currentpos = ftell($infp);
  142. $percent = round($currentpos / $fs * 100);
  143. $position = formatsize($currentpos);
  144. printf("Reading progress: %3d%% position: %7s line: %9d sql chunk: %9d mem usage: %4dM\r", $percent, $position, $linenum, $chunkcount, $memusage);
  145. }
  146. if (strlen($instr) > 3 && ($instr[$len - 3] == ")" && $instr[$len - 2] == ";" && $instr[$len - 1] == "\n") && $inquotes == false) {
  147. $chunkcount++;
  148. if ($linenum % 10000 == 0) {
  149. $currentpos = ftell($infp);
  150. $percent = round($currentpos / $fs * 100);
  151. $position = formatsize($currentpos);
  152. printf("Processing progress: %3d%% position: %7s line: %9d sql chunk: %9d mem usage: %4dM\r", $percent, $position, $linenum, $chunkcount, $memusage);
  153. }
  154. /*
  155. * echo "sending chunk:\n";
  156. * echo "=======================\n";
  157. * print_r($pgsqlchunk);
  158. * echo "=======================\n";
  159. */
  160. /*
  161. * foreach ($pgsqlchunk as $aaa) {
  162. * if (preg_match('/MAIN_ENABLE_DEFAULT|MAIN_MAIL_SMTP_SE/', $aaa)) {
  163. * var_dump($pgsqlchunk);
  164. * }
  165. * }
  166. */
  167. $mysqlchunk = pg2mysql($pgsqlchunk, $arrayofprimaryalreadyintabledef, $first);
  168. fputs($outfp, $mysqlchunk['output']);
  169. /*
  170. * $break = false;
  171. * foreach ($pgsqlchunk as $aaa) {
  172. * if (preg_match('/MAIN_ENABLE_DEFAULT|MAIN_MAIL_SMTP_SE/', $aaa)) {
  173. * var_dump($mysqlchunk);
  174. * }
  175. * if (preg_match('/MAIN_MAIL_SMTP_SE/', $aaa)) {
  176. * $break = true;
  177. * }
  178. * }
  179. * if ($break) break;
  180. */
  181. $outputatend .= $mysqlchunk['outputatend'];
  182. $first = false;
  183. $pgsqlchunk = array();
  184. $mysqlchunk = "";
  185. }
  186. }
  187. echo "\n\n";
  188. fputs($outfp, $outputatend);
  189. fputs($outfp, "\n");
  190. fputs($outfp, '/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;' . "\n");
  191. fputs($outfp, '/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;' . "\n");
  192. fputs($outfp, '/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;' . "\n");
  193. fputs($outfp, '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;' . "\n");
  194. fputs($outfp, '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;' . "\n");
  195. fputs($outfp, '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;' . "\n");
  196. fputs($outfp, '/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;' . "\n");
  197. printf("Completed! %9d lines %9d sql chunks\n\n", $linenum, $chunkcount);
  198. fclose($infp);
  199. fclose($outfp);
  200. return 0;
  201. }
  202. /**
  203. * pg2mysql
  204. *
  205. * @param array $input Array of input
  206. * @param array $arrayofprimaryalreadyintabledef Array of table already output with a primary key set into definition
  207. * @param boolean $header Boolean
  208. * @return string[] Array of output
  209. */
  210. function pg2mysql(&$input, &$arrayofprimaryalreadyintabledef, $header = true)
  211. {
  212. global $config;
  213. if (is_array($input)) {
  214. $lines = $input;
  215. } else {
  216. $lines = explode("\n", $input);
  217. }
  218. if ($header) {
  219. $output = "-- Converted with " . PRODUCT . "-" . VERSION . "\n";
  220. $output .= "-- Converted on " . date("r") . "\n";
  221. $output .= "\n";
  222. $output .= "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n";
  223. $output .= "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n";
  224. $output .= "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n";
  225. $output .= "/*!40101 SET NAMES utf8 */;\n";
  226. $output .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n";
  227. $output .= "/*!40103 SET TIME_ZONE='+00:00' */;\n";
  228. $output .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n";
  229. $output .= "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n";
  230. $output .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n";
  231. $output .= "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n";
  232. $output .= "\n";
  233. $outputatend = "";
  234. } else {
  235. $output = "";
  236. $outputatend = "";
  237. }
  238. $in_create_table = $in_insert = false;
  239. $linenumber = 0;
  240. $tbl_extra = "";
  241. while (isset($lines[$linenumber])) {
  242. $line = $lines[$linenumber];
  243. // $line =str_replace('ALTER TABLE public\.', '', $line);
  244. $reg = array();
  245. if (preg_match('/CREATE SEQUENCE (?:public\.)(.*)_(id|rowid|id_comment)_seq/', $line, $reg)) {
  246. $outputatend .= '-- Make field ' . $reg[2] . ' auto_increment for table ' . $reg[1] . "\n";
  247. $outputatend .= 'ALTER TABLE ' . $reg[1] . ' CHANGE COLUMN ' . $reg[2] . ' ' . $reg[2] . ' INTEGER NOT NULL AUTO_INCREMENT;' . "\n\n";
  248. // var_dump($outputatend);
  249. }
  250. if (substr($line, 0, 12) == "CREATE TABLE") {
  251. $in_create_table = true;
  252. $line = str_replace("\"", "`", $line);
  253. $line = str_replace('public.', '', $line);
  254. $reg2 = array();
  255. if (preg_match('/CREATE TABLE ([^\s]+)/', $line, $reg2)) {
  256. $in_create_table = $reg2[1];
  257. }
  258. $reg2 = array();
  259. if (preg_match('/CREATE TABLE ([^\s]+)/', $line, $reg2)) {
  260. $output .= 'DROP TABLE IF EXISTS `' . $reg2[1] . '`;' . "\n";
  261. }
  262. $output .= $line;
  263. $linenumber++;
  264. continue;
  265. }
  266. if (substr($line, 0, 2) == ");" && $in_create_table) {
  267. $in_create_table = false;
  268. $line = ") ENGINE={$config['engine']};\n\n";
  269. $output .= $tbl_extra;
  270. $output .= $line;
  271. $linenumber++;
  272. $tbl_extra = "";
  273. continue;
  274. }
  275. if ($in_create_table) {
  276. $regs = array();
  277. $line = str_replace("\"", "`", $line);
  278. $line = str_replace(" integer", " int(11)", $line);
  279. $line = str_replace(" int_unsigned", " int(11) UNSIGNED", $line);
  280. $line = str_replace(" smallint_unsigned", " smallint UNSIGNED", $line);
  281. $line = str_replace(" bigint_unsigned", " bigint UNSIGNED", $line);
  282. $line = str_replace(" serial ", " int(11) auto_increment ", $line);
  283. $line = str_replace(" bytea", " BLOB", $line);
  284. $line = str_replace(" boolean", " bool", $line);
  285. $line = str_replace(" bool DEFAULT true", " bool DEFAULT 1", $line);
  286. $line = str_replace(" bool DEFAULT false", " bool DEFAULT 0", $line);
  287. if (preg_match("/ character varying\(([0-9]*)\)/", $line, $regs)) {
  288. $num = $regs[1];
  289. if ($num <= 255) {
  290. $line = preg_replace("/ character varying\([0-9]*\)/", " varchar($num)", $line);
  291. } else {
  292. $line = preg_replace("/ character varying\([0-9]*\)/", " text", $line);
  293. }
  294. }
  295. // character varying with no size, we will default to varchar(255)
  296. if (preg_match("/ character varying/", $line)) {
  297. $line = preg_replace("/ character varying/", " varchar(255)", $line);
  298. }
  299. if (preg_match("/ DEFAULT \('([0-9]*)'::int/", $line, $regs) || preg_match("/ DEFAULT \('([0-9]*)'::smallint/", $line, $regs) || preg_match("/ DEFAULT \('([0-9]*)'::bigint/", $line, $regs)) {
  300. $num = $regs[1];
  301. $line = preg_replace("/ DEFAULT \('([0-9]*)'[^ ,]*/", " DEFAULT $num ", $line);
  302. }
  303. if (preg_match("/ DEFAULT \(([0-9\-]*)\)/", $line, $regs)) {
  304. $num = $regs[1];
  305. $line = preg_replace("/ DEFAULT \(([0-9\-]*)\)/", " DEFAULT $num ", $line);
  306. }
  307. $line = preg_replace("/ DEFAULT nextval\(.*\) /", " auto_increment ", $line);
  308. $line = preg_replace("/::.*,/", ",", $line);
  309. $line = preg_replace("/::.*$/", "\n", $line);
  310. if (preg_match("/character\(([0-9]*)\)/", $line, $regs)) {
  311. $num = $regs[1];
  312. if ($num <= 255) {
  313. $line = preg_replace("/ character\([0-9]*\)/", " varchar($num)", $line);
  314. } else {
  315. $line = preg_replace("/ character\([0-9]*\)/", " text", $line);
  316. }
  317. }
  318. // timestamps
  319. $line = str_replace(" timestamp with time zone", " datetime", $line);
  320. $line = str_replace(" timestamp without time zone", " datetime", $line);
  321. // time
  322. $line = str_replace(" time with time zone", " time", $line);
  323. $line = str_replace(" time without time zone", " time", $line);
  324. $line = str_replace(" timestamp DEFAULT now()", " timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", $line);
  325. $line = str_replace(" timestamp without time zone DEFAULT now()", " timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", $line);
  326. if (strstr($line, "auto_increment") || preg_match('/ rowid int/', $line) || preg_match('/ id int/', $line)) {
  327. $field = getfieldname($line);
  328. $tbl_extra .= ", PRIMARY KEY(`$field`)\n";
  329. $arrayofprimaryalreadyintabledef[$in_create_table] = $in_create_table;
  330. }
  331. $specialfields = array("repeat","status","type","call");
  332. $field = getfieldname($line);
  333. if (in_array($field, $specialfields)) {
  334. $line = str_replace("$field ", "`$field` ", $line);
  335. }
  336. // text/blob fields are not allowed to have a default, so if we find a text DEFAULT, change it to varchar(255) DEFAULT
  337. if (strstr($line, "text DEFAULT")) {
  338. $line = str_replace(" text DEFAULT ", " varchar(255) DEFAULT ", $line);
  339. }
  340. // just skip a CONSTRAINT line
  341. if (strstr($line, " CONSTRAINT ")) {
  342. $line = "";
  343. // and if the previous output ended with a , remove the ,
  344. $lastchr = substr($output, -2, 1);
  345. // echo "lastchr=$lastchr";
  346. if ($lastchr == ",") {
  347. $output = substr($output, 0, -2) . "\n";
  348. }
  349. }
  350. $output .= $line;
  351. }
  352. if (substr($line, 0, 11) == "INSERT INTO") {
  353. $line = str_replace('public.', '', $line);
  354. if (substr($line, -3, -1) == ");") {
  355. // we have a complete insert on one line
  356. list($before, $after) = explode(" VALUES ", $line, 2);
  357. // we only replace the " with ` in what comes BEFORE the VALUES
  358. // (ie, field names, like INSERT INTO table ("bla","bla2") VALUES ('s:4:"test"','bladata2');
  359. // should convert to INSERT INTO table (`bla`,`bla2`) VALUES ('s:4:"test"','bladata2');
  360. $before = str_replace("\"", "`", $before);
  361. // in after, we need to watch out for escape format strings, ie (E'escaped \r in a string'), and ('bla',E'escaped \r in a string'), but could also be (number, E'string'); so we cant search for the previoous '
  362. // ugh i guess its possible these strings could exist IN the data as well, but the only way to solve that is to process these lines one character
  363. // at a time, and thats just stupid, so lets just hope this doesnt appear anywhere in the actual data
  364. $after = str_replace(" (E'", " ('", $after);
  365. $after = str_replace(", E'", ", '", $after);
  366. $output .= $before . " VALUES " . $after;
  367. $linenumber++;
  368. continue;
  369. } else {
  370. // this insert spans multiple lines, so keep dumping the lines until we reach a line
  371. // that ends with ");"
  372. list($before, $after) = explode(" VALUES ", $line, 2);
  373. // we only replace the " with ` in what comes BEFORE the VALUES
  374. // (ie, field names, like INSERT INTO table ("bla","bla2") VALUES ('s:4:"test"','bladata2');
  375. // should convert to INSERT INTO table (`bla`,`bla2`) VALUES ('s:4:"test"','bladata2');
  376. $before = str_replace("\"", "`", $before);
  377. // in after, we need to watch out for escape format strings, ie (E'escaped \r in a string'), and ('bla',E'escaped \r in a string')
  378. // ugh i guess its possible these strings could exist IN the data as well, but the only way to solve that is to process these lines one character
  379. // at a time, and thats just stupid, so lets just hope this doesnt appear anywhere in the actual data
  380. $after = str_replace(" (E'", " ('", $after);
  381. $after = str_replace(", E'", ", '", $after);
  382. $c = substr_count($line, "'");
  383. // we have an odd number of ' marks
  384. if ($c % 2 != 0) {
  385. $inquotes = true;
  386. } else {
  387. $inquotes = false;
  388. }
  389. $output .= $before . " VALUES " . $after;
  390. do {
  391. $linenumber++;
  392. // in after, we need to watch out for escape format strings, ie (E'escaped \r in a string'), and ('bla',E'escaped \r in a string')
  393. // ugh i guess its possible these strings could exist IN the data as well, but the only way to solve that is to process these lines one character
  394. // at a time, and thats just stupid, so lets just hope this doesnt appear anywhere in the actual data
  395. // after the first line, we only need to check for it in the middle, not at the beginning of an insert (becuase the beginning will be on the first line)
  396. // $after=str_replace(" (E'","' ('",$after);
  397. $line = $lines[$linenumber];
  398. $line = str_replace("', E'", "', '", $line);
  399. $output .= $line;
  400. // printf("inquotes: %d linenumber: %4d line: %s\n",$inquotes,$linenumber,$lines[$linenumber]);
  401. $c = substr_count($line, "'");
  402. // we have an odd number of ' marks
  403. if ($c % 2 != 0) {
  404. if ($inquotes) {
  405. $inquotes = false;
  406. } else {
  407. $inquotes = true;
  408. }
  409. // echo "inquotes=$inquotes\n";
  410. }
  411. } while (substr($lines[$linenumber], -3, -1) != ");" || $inquotes);
  412. }
  413. }
  414. if (substr($line, 0, 16) == "ALTER TABLE ONLY") {
  415. $line = preg_replace('/ ONLY/', '', $line);
  416. $line = str_replace("\"", "`", $line);
  417. $line = str_replace("public.", "", $line);
  418. $pkey = $line;
  419. $linenumber++;
  420. if (!empty($lines[$linenumber])) {
  421. $line = $lines[$linenumber];
  422. } else {
  423. $line = '';
  424. }
  425. if (strstr($line, " PRIMARY KEY ") && substr($line, -3, -1) == ");") {
  426. $reg2 = array();
  427. if (preg_match('/ALTER TABLE ([^\s]+)/', $pkey, $reg2)) {
  428. if (empty($arrayofprimaryalreadyintabledef[$reg2[1]])) {
  429. // looks like we have a single line PRIMARY KEY definition, lets go ahead and add it
  430. $output .= str_replace("\n", "", $pkey);
  431. // the postgres and mysql syntax for this is (at least, in the example im looking at)
  432. // identical, so we can just add it as is.
  433. $output .= $line . "\n";
  434. } else {
  435. $output .= '-- ' . str_replace("\n", "", $pkey);
  436. $output .= '-- ' . $line . "\n";
  437. }
  438. } else {
  439. $output .= '-- ' . str_replace("\n", "", $pkey);
  440. $output .= '-- ' . $line . "\n";
  441. }
  442. }
  443. }
  444. // while we're here, we might as well catch CREATE INDEX as well
  445. if (substr($line, 0, 12) == "CREATE INDEX") {
  446. $matches = array();
  447. preg_match('/CREATE INDEX "?([a-zA-Z0-9_]*)"? ON "?([a-zA-Z0-9_\.]*)"? USING btree \((.*)\);/', $line, $matches);
  448. if (!empty($matches[3])) {
  449. $indexname = $matches[1];
  450. $tablename = str_replace('public.', '', $matches[2]);
  451. $columns = $matches[3];
  452. if ($tablename && $columns) {
  453. $output .= "ALTER TABLE `" . $tablename . "` ADD INDEX " . $indexname . "( {$columns} ) ;\n";
  454. }
  455. }
  456. }
  457. if (substr($line, 0, 19) == "CREATE UNIQUE INDEX") {
  458. $matches = array();
  459. preg_match('/CREATE UNIQUE INDEX "?([a-zA-Z0-9_]*)"? ON "?([a-zA-Z0-9_\.]*)"? USING btree \((.*)\);/', $line, $matches);
  460. if (!empty($matches[3])) {
  461. $indexname = $matches[1];
  462. $tablename = str_replace('public.', '', $matches[2]);
  463. $columns = str_replace('"', '', $matches[3]);
  464. if ($tablename && $columns) {
  465. $output .= "ALTER TABLE `" . $tablename . "` ADD UNIQUE INDEX " . $indexname . " ( {$columns} ) ;\n";
  466. }
  467. }
  468. }
  469. if (substr($line, 0, 13) == 'DROP DATABASE') {
  470. $output .= $line;
  471. }
  472. if (substr($line, 0, 15) == 'CREATE DATABASE') {
  473. $matches = array();
  474. preg_match('/CREATE DATABASE ([a-zA-Z0-9_]*) .* ENCODING = \'(.*)\'/', $line, $matches);
  475. $output .= "CREATE DATABASE `$matches[1]` DEFAULT CHARACTER SET $matches[2];\n\n";
  476. }
  477. if (substr($line, 0, 8) == '\\connect') {
  478. $matches = array();
  479. preg_match('/connect ([a-zA-Z0-9_]*)/', $line, $matches);
  480. $output .= "USE `$matches[1]`;\n\n";
  481. }
  482. if (substr($line, 0, 5) == 'COPY ') {
  483. $matches = array();
  484. preg_match('/COPY (.*) FROM stdin/', $line, $matches);
  485. $heads = str_replace('"', "`", $matches[1]);
  486. $values = array();
  487. $in_insert = true;
  488. } elseif ($in_insert) {
  489. if ($line == "\\.\n") {
  490. $in_insert = false;
  491. if ($values) {
  492. $output .= "INSERT INTO $heads VALUES\n" . implode(",\n", $values) . ";\n\n";
  493. }
  494. } else {
  495. $vals = explode(' ', $line);
  496. foreach ($vals as $i => $val) {
  497. $vals[$i] = ($val == '\\N') ? 'NULL' : "'" . str_replace("'", "\\'", trim($val)) . "'";
  498. }
  499. $values[] = '(' . implode(',', $vals) . ')';
  500. if (count($values) >= 1000) {
  501. $output .= "INSERT INTO $heads VALUES\n" . implode(",\n", $values) . ";\n";
  502. $values = array();
  503. }
  504. }
  505. }
  506. $linenumber++;
  507. }
  508. return array('output' => $output,'outputatend' => $outputatend);
  509. }