1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
mysql_to_pgsql.php
См. документацию.
1#!/usr/bin/php
2<?php
3namespace Bitrix\Main;
4
5//utf8: 21844 * 3 = 65532
6//utf8mb4: 21844 * 4 = 87376 # too much
7//utf8mb4: 16383 * 4 = 65532
8define('MAX_VARCHAR_LEN', 16383);
9define('CHAR_WIDTH', 4);
10define('CHARSET', 'utf8mb4');
11define('COLLATION', 'utf8mb4_0900_ai_ci');
12
13error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_WARNING & ~E_USER_WARNING & ~E_COMPILE_WARNING);
14
15class NotSupportedException extends \Exception {}
16
17spl_autoload_register(
18 function ($class_name)
19 {
20 if (strpos(strtolower($class_name), 'bitrix\\perfmon\\') === 0)
21 {
22 $file_name = substr($class_name, strlen('bitrix\\perfmon\\'));
23 $file_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $file_name));
24 $file_name = str_replace('\\', '/', $file_name);
25 require_once __DIR__ . '/../../perfmon/lib/' . $file_name . '.php';
26 }
27 }
28);
29
30$files = [];
32$host = '';
33$user = '';
36$table = '';
37
38for ($i = 1, $c = count($argv); $i < $c; $i++)
39{
40 if (preg_match('/^--file=(.+)$/', $argv[$i], $match))
41 {
42 $files[] = $match[1];
43 }
44 elseif (preg_match('/^--mysqldump=(.+)$/', $argv[$i], $match))
45 {
46 $mysqldump = $match[1];
47 }
48 elseif (preg_match('/^--host=(.+)$/', $argv[$i], $match))
49 {
50 $host = $match[1];
51 }
52 elseif (preg_match('/^--user=(.+)$/', $argv[$i], $match))
53 {
54 $user = $match[1];
55 }
56 elseif (preg_match('/^--password=(.+)$/', $argv[$i], $match))
57 {
58 $password = $match[1];
59 }
60 elseif (preg_match('/^--database=(.+)$/', $argv[$i], $match))
61 {
62 $databases[] = $match[1];
63 }
64 elseif (preg_match('/^--table=(.+)$/', $argv[$i], $match))
65 {
66 $table = $match[1];
67 }
68 else
69 {
70 $files[] = $argv[$i];
71 }
72}
73
74if ($mysqldump)
75{
76 $f = fopen($mysqldump, 'r');
77 if ($f)
78 {
79 echo "SET client_min_messages TO WARNING;\n";
80
81 $match = [];
82 $tableName = '';
83 $ddl = '';
84 while ($line = fgets($f))
85 {
86 if (preg_match('/^CREATE TABLE `(.*?)` /', $line, $match))
87 {
88 $tableName = $match[1];
89 $ddl = $line;
90 }
91 elseif ($tableName)
92 {
93 $ddl .= $line;
94 if (preg_match('/^\‍)/', $line))
95 {
96 //echo $ddl;
97 echo generate_schema_ddl($ddl, $table, true, $mysqldump);
98 $tableName = '';
99 $ddl = '';
100 }
101 }
102 elseif (preg_match('/^(?:INSERT|REPLACE) INTO `(.*?)` VALUES (.+);\s*$/', $line, $match))
103 {
104 $rows = parse_values($match[2]);
105 foreach ($rows as $row)
106 {
107 echo 'INSERT INTO "' . $match[1] . '" VALUES ' . $row . ";\n";
108 }
109 }
110 }
111 }
112}
113
114if ($files)
115{
116 foreach ($files as $file_name)
117 {
118 $sql = file_get_contents($file_name, 'r');
119 echo generate_schema_ddl($sql, $table, false, $file_name);
120 }
121}
122
123if ($host || $user || $password)
124{
125 echo "SET client_min_messages TO WARNING;\n";
126
127 $dbh = new \PDO('mysql:host=' . $host . ';port=3306', $user, $password);
128 $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
129 if (!$databases)
130 {
131 $r = $dbh->query('show databases');
132 while ($a = $r->fetch(\PDO::FETCH_ASSOC))
133 {
134 if (
135 $a['Database'] !== 'information_schema'
136 && $a['Database'] !== 'mysql'
137 && $a['Database'] !== 'performance_schema'
138 && $a['Database'] !== 'sys'
139 )
140 {
141 $databases[] = $a['Database'];
142 }
143 }
144 }
145
146 foreach ($databases as $db_name)
147 {
148 $dbh->exec('use ' . $db_name);
149 $sql = '';
150 $r = $dbh->query('show tables');
151 while ($a = $r->fetch(\PDO::FETCH_ASSOC))
152 {
153 $r2 = $dbh->query('show create table `' . $a['Tables_in_' . $db_name] . '`');
154 $a2 = $r2->fetch(\PDO::FETCH_ASSOC);
155 if (isset($a2['Table']))
156 {
157 $sql .= $a2['Create Table'] . ";\n";
158 }
159 }
160 echo generate_schema_ddl($sql, $table, true, $db_name);
161 }
162}
163
164function unquote($identifier)
165{
166 return trim($identifier, '`');
167}
168
169function convertColumnType($columnType, $length, $unsigned)
170{
171 switch ($columnType)
172 {
173 case 'TINYINT':
174 case 'SMALLINT':
175 return $unsigned ? 'int' : 'smallint';
176 case 'BOOL':
177 case 'BOOLEAN':
178 return 'smallint';
179 case 'MEDIUMINT':
180 case 'INT':
181 case 'INTEGER':
182 return $unsigned ? 'int8' : 'int';
183 case 'BIGINT':
184 return 'int8';
185 case 'DECIMAL':
186 case 'NUMERIC':
187 return strtolower($columnType);
188 case 'FLOAT':
189 return 'real';
190 case 'DOUBLE':
191 return 'double precision';
192 case 'CHAR':
193 return 'char(' . $length . ')';
194 case 'VARCHAR':
195 return 'varchar(' . $length . ')';
196 case 'VARBINARY':
197 case 'MEDIUMBLOB':
198 case 'LONGBLOB':
199 case 'BLOB':
200 return 'bytea';
201 case 'TEXT':
202 case 'TINYTEXT':
203 case 'MEDIUMTEXT':
204 case 'LONGTEXT':
205 return 'text';
206 case 'DATE':
207 return 'date';
208 case 'DATETIME':
209 case 'TIMESTAMP':
210 return 'timestamp';
211 case 'ENUM':
212 return 'enum';
213 default:
214 return '//unknown type ' . $columnType;
215 }
216}
217
218function generate_schema_ddl($sql, $tableFilter, $isDump, $source)
219{
220 $ddl = '';
221 $match = [];
222
223 //todo: Unsupported statement by Perfmon\Sql\Schema
224 $sql = str_replace('USING BTREE', ' ', $sql);
225
226 $s = new \Bitrix\Perfmon\Sql\Schema;
227 $s->createFromString($sql, ';');
229 foreach ($s->tables->getList() as $table)
230 {
231 if ($tableFilter && unquote($table->name) !== $tableFilter)
232 {
233 continue;
234 }
235
236 if ($isDump)
237 {
238 $ddl .= 'DROP TABLE IF EXISTS ' . unquote($table->name) . ";\n";
239 }
240
241 $autoIncrementValue = null;
242 $autoIncrementColumn = '';
243 $inset = [];
245 foreach ($table->columns->getList() as $column)
246 {
247 $columnDefinition = unquote($column->name);
248 if ($columnDefinition === 'OFFSET' || $columnDefinition === 'KEY')
249 {
250 $columnDefinition = '"' . strtolower($columnDefinition) . '"';
251 }
252
253 $hasAutoIncrement = preg_match('/AUTO_INCREMENT/i', $column->body) > 0;
254 if ($hasAutoIncrement && preg_match('/AUTO_INCREMENT=(\d+)/', $table->body, $match))
255 {
256 $autoIncrementValue = $match[1];
257 $autoIncrementColumn = unquote($column->name);
258 }
259 $type = convertColumnType($column->type, $column->length, $column->unsigned);
260
261 if ($type === 'enum' && $column->enum)
262 {
263 $enumType = 't_' . preg_replace('/^b_/i', '', unquote($table->name)) . '_' . unquote($column->name);
264 $ddl .= 'DROP TYPE IF EXISTS ' . $enumType . ";\n";
265 $ddl .= 'CREATE TYPE ' . $enumType . " AS ENUM ('" . implode("', '", $column->enum) . "');\n";
266 $columnDefinition .= ' ' . $enumType;
267 fwrite(STDERR, 'Warning: ' . $source . ': ' . $table->name . '.' . $column->name . " is enum. Convert to char.\n");
268 }
269 else
270 {
271 $columnDefinition .= ' ' . $type . ($hasAutoIncrement ? ' GENERATED BY DEFAULT AS IDENTITY' : '');
272 }
273
274 if (!$column->nullable || $hasAutoIncrement)
275 {
276 $columnDefinition .= ' NOT NULL';
277 }
278
279 if ($column->unsigned)
280 {
281 fwrite(STDERR, 'Notice: ' . $source . ': ' . $table->name . '.' . $column->name . " is unsigned. Consider to convert to wider type and remove unsigned defunition.\n");
282 }
283
284 if ($column->type === 'TIMESTAMP')
285 {
286 $columnDefinition .= ' DEFAULT CURRENT_TIMESTAMP';
287 fwrite(STDERR, 'Warning: ' . $source . ': ' . $table->name . '.' . $column->name . " is timestamp. Convert to datetime.\n");
288 }
289 elseif (!is_null($column->default) && strlen($column->default) > 0)
290 {
291 $default = str_replace('"', "'", $column->default);
292 $default = str_replace("'0000-00-00 00:00:00'", '', $default);
293 $default = str_replace('NOW', 'CURRENT_TIMESTAMP', $default);
294 $default = str_replace('now', 'CURRENT_TIMESTAMP', $default);
295 $default = str_replace('false', '0', $default);
296 $default = trim($default, " \t\n\r");
297 if ($default !== '')
298 {
299 $columnDefinition .= ' DEFAULT ' . $default;
300 }
301 }
302 $inset[] = $columnDefinition;
303 }
304
306 foreach ($table->constraints->getList() as $constraint)
307 {
308 if (preg_match('/^PRIMARY/i', $constraint->body) > 0)
309 {
310 $inset[] = 'PRIMARY KEY (' . implode(', ', array_map(
311 function($x)
312 {
313 return trim(unquote(preg_replace('/\s+(desc|asc)/i', '', preg_replace('/\‍(\d+\‍)/', '', $x))), " \t\n\r");
314 }, $constraint->columns)) . ')';
315 }
316 elseif (preg_match('/^UNIQUE/i', $constraint->body) > 0)
317 {
318 $inset[] = 'UNIQUE (' . implode(', ', array_map(
319 function($x)
320 {
321 return unquote($x);
322 }, $constraint->columns)) . ')';
323 }
324 }
325
326 if ($inset)
327 {
328 $ddl .= "\nCREATE TABLE " . unquote($table->name) . " (\n";
329
330 $c = count($inset) - 1;
331 foreach ($inset as $i => $line)
332 {
333 $ddl .= ' ' . $line . ($i < $c ? ',' : '') . "\n";
334 }
335
336 $ddl .= ");\n";
337 }
338
339 if ($autoIncrementValue && $isDump)
340 {
341 $ddl .= 'ALTER TABLE ' . unquote($table->name) . ' ALTER COLUMN ' . $autoIncrementColumn . ' RESTART WITH ' . $autoIncrementValue . ";\n";
342 }
343
344 $indexes = [];
346 foreach ($table->indexes->getList() as $index)
347 {
348 $indexName = substr(
349 ($index->unique ? 'ux_' : ($index->fulltext ? 'tx_' : 'ix_'))
350 . unquote($table->name)
351 . '_'
352 . implode('_', array_map(
353 function($x)
354 {
355 return strtolower(unquote(preg_replace('/\s*(\‍(\d+\‍)|asc|desc)(?![a-z0-9_])\s*/i', '', $x)));
356 }, $index->columns))
357 , 0, 63);
358 if (array_key_exists($indexName, $indexes))
359 {
360 $i = ++$indexes[$indexName];
361 $suffix = '_' . $i;
362 $indexName = substr($indexName, 0, -strlen($suffix)) . $suffix;
363 }
364 else
365 {
366 $indexes[$indexName] = 0;
367 }
368
369 if ($isDump)
370 {
371 $ddl .= 'DROP INDEX IF EXISTS ' . $indexName . ";\n";
372 }
373
374 if ($index->fulltext)
375 {
376 $ddl .= 'CREATE INDEX ' . $indexName . ' ON ' . unquote($table->name) . " USING GIN (to_tsvector('english', " . implode(' || ', array_map(
377 function($x)
378 {
379 return strtolower(unquote(preg_replace('/\s*(\‍(\d+\‍)|asc|desc)(?![a-z0-9_])\s*/i', '', $x)));
380 }, $index->columns)) . "));\n";
381 }
382 else
383 {
384 $ddl .= 'CREATE' . ($index->unique ? ' UNIQUE ' : ' ') . 'INDEX ' . $indexName . ' ON ' . unquote($table->name) . ' (' . implode(', ', array_map(
385 function($x)
386 {
387 return strtolower(unquote(preg_replace('/\s*(\‍(\d+\‍)|asc|desc)(?![a-z0-9_])\s*/i', '', $x)));
388 }, $index->columns)) . ");\n";
389 }
390 }
391 }
392 return $ddl;
393}
394
395function parse_values($values_str)
396{
397 static $search = ['\\\'', '\\"'];
398 static $replace = ['\'\'', '"'];
399 $result = [];
400 $tokens = token_get_all('<?php ' . $values_str);
401 $row = [];
402 $c = count($tokens);
403 for ($i = 1; $i < $c; $i++)
404 {
405 $token = $tokens[$i];
406 if (
407 ($token == ',' || $token == ';')
408 && ($tokens[$i - 1] == ')')
409 )
410 {
411 if ($row)
412 {
413 $result[] = '(' . implode('', $row) . ')';
414 }
415 $row = [];
416 }
417 elseif ($token == '(' || $token == ')')
418 {
419 //skip
420 }
421 elseif (is_array($token))
422 {
423 if ($token[0] === T_CONSTANT_ENCAPSED_STRING)
424 {
425 $escaped = str_replace($search, $replace, $token[1]);
426 if ($escaped === "'0000-00-00 00:00:00'")
427 {
428 $escaped = 'NULL';
429 }
430 elseif (
431 preg_match('/\\\\[bfnrt\']/', $escaped)
432 || strpos($escaped, '\\\\') !== false
433 )
434 {
435 $escaped = 'E' . $escaped;
436 }
437 $row[] = $escaped;
438 }
439 elseif (preg_match('/^0x[0-9A-F]+$/', $token[1]))
440 {
441 $row[] = 'decode(\'' . substr($token[1], 2) . '\', \'hex\')';
442 }
443 else
444 {
445 $row[] = $token[1];
446 }
447 }
448 else
449 {
450 $row[] = $token;
451 }
452 }
453 if ($row)
454 {
455 $result[] = '(' . implode('', $row) . ')';
456 }
457 return $result;
458}
$type
Определения event.php:7
static str_replace($search, $replace, $str)
Определения stringhelper.php:74
$f
Определения component_props.php:52
$result
Определения get_property_values.php:14
parse_values($values_str)
Определения mysql_to_pgsql.php:395
for($i=1, $c=count($argv); $i< $c; $i++) if( $mysqldump) if($files) if( $host||$user||$password) unquote($identifier)
Определения mysql_to_pgsql.php:164
convertColumnType($columnType, $length, $unsigned)
Определения mysql_to_pgsql.php:169
$user
Определения mysql_to_pgsql.php:33
$password
Определения mysql_to_pgsql.php:34
$host
Определения mysql_to_pgsql.php:32
$mysqldump
Определения mysql_to_pgsql.php:31
$files
Определения mysql_to_pgsql.php:30
$databases
Определения mysql_to_pgsql.php:35
$table
Определения mysql_to_pgsql.php:36
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
else $a
Определения template.php:137
$rows
Определения options.php:264