DB_Util.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <?php
  2. class DB_Util {
  3. /**
  4. * Compare db structures
  5. */
  6. function compare_db($db1, $db2) {
  7. }
  8. function action_drop_table_to_sql($table_name) {
  9. $sql = "DROP `{$table_name}` ";
  10. return $sql;
  11. }
  12. /**
  13. * @param $field_params array('type'=>'' [, 'default'=>'', 'not null'=>bool, 'extra'=>''])
  14. */
  15. function action_modify_column_to_sql($table_name, $field_name, $field_params) {
  16. $sql = "ALTER TABLE `{$table_name}` MODIFY `{$field_name}` ";
  17. $sql .= $field_params['type'];
  18. if (!empty($field_params['not null']) && $field_params['not null'] == true) {
  19. $sql .= " NOT ";
  20. }
  21. $sql .= " NULL ";
  22. if (!empty($field_params['default'])) {
  23. $sql .= " " . $field_params['default'];
  24. }
  25. if (!empty($field_params['extra'])) {
  26. $sql .= " " . $field_params['extra'];
  27. }
  28. return $sql;
  29. }
  30. /**
  31. * @param $field_params array('type'=>'' [, 'default'=>'', 'not null'=>bool, 'extra'=>''])
  32. */
  33. function action_add_column_to_sql($table_name, $field_name, $field_params) {
  34. $sql = "ALTER TABLE `{$table_name}` ADD `{$field_name}` ";
  35. $sql .= $field_params['type'];
  36. if (!empty($field_params['not null']) && $field_params['not null'] == true) {
  37. $sql .= " NOT ";
  38. }
  39. $sql .= " NULL ";
  40. if (!empty($field_params['default'])) {
  41. $sql .= " " . $field_params['default'];
  42. }
  43. if (!empty($field_params['extra'])) {
  44. $sql .= " " . $field_params['extra'];
  45. }
  46. return $sql;
  47. }
  48. function action_drop_column_to_sql($table_name, $field_name) {
  49. $sql = "ALTER TABLE `{$table_name}` DROP `{$field_name}` ";
  50. return $sql;
  51. }
  52. /**
  53. * @param $columns array of column params
  54. * @param $keys array of key params
  55. */
  56. function action_create_table_to_sql($table_name, $columns, $keys) {
  57. $sql = "DROP `{$table_name}` ";
  58. return $sql;
  59. }
  60. function action_add_key_to_sql($table_name, $key_name, $key_params) {
  61. $sql = "ALTER TABLE `{$table_name}` ADD {$key_params['type']}";
  62. if ($key_params['type'] != 'PRIMARY KEY') $sql .= " {$key_name}";
  63. $sql .= " (" . implode(", ", $key_params['columns']) . ")";
  64. return $sql;
  65. }
  66. function action_drop_key_to_sql($table_name, $key_name) {
  67. $sql = "ALTER TABLE `{$table_name}` DROP INDEX {$key_name} ";
  68. return $sql;
  69. }
  70. /**
  71. * @returns array(0=>[sql], 1=>[sql]) - array of sql for db1 and db2
  72. */
  73. function compare_db_table_to_sql($table_name, &$cmp) {
  74. $sqls = array();
  75. if (!empty($cmp['columns'])) {
  76. foreach ($cmp['columns'] as $k_field => $v_cmp) {
  77. if (count($v_cmp) == 2) {
  78. $sqls[0][$k_field] = self::action_modify_column_to_sql($table_name, $k_field, $v_cmp[1]);
  79. $sqls[1][$k_field] = self::action_modify_column_to_sql($table_name, $k_field, $v_cmp[0]);
  80. } else if (count($v_cmp) == 1) {
  81. if (array_key_exists(0, $v_cmp)) {
  82. $sqls[0][$k_field] = self::action_drop_column_to_sql($table_name, $k_field);
  83. $sqls[1][$k_field] = self::action_add_column_to_sql($table_name, $k_field, $v_cmp[0]);
  84. } else {
  85. $sqls[0][$k_field] = self::action_add_column_to_sql($table_name, $k_field, $v_cmp[1]);
  86. $sqls[1][$k_field] = self::action_drop_column_to_sql($table_name, $k_field);
  87. }
  88. }
  89. }
  90. }
  91. if (!empty($cmp['keys'])) {
  92. foreach ($cmp['keys'] as $k_key => $v_cmp) {
  93. if (count($v_cmp) == 2) {
  94. $sqls[0][$k_key] = self::action_modify_key_to_sql($table_name, $k_key, $v_cmp[0]);
  95. $sqls[1][$k_key] = self::action_modify_key_to_sql($table_name, $k_key, $v_cmp[0]);
  96. } else if (count($v_cmp) == 1) {
  97. if (array_key_exists(0, $v_cmp)) {
  98. $sqls[0][$k_key] = self::action_drop_key_to_sql($table_name, $k_key);
  99. $sqls[1][$k_key] = self::action_add_key_to_sql($table_name, $k_key, $v_cmp[0]);
  100. } else {
  101. $sqls[0][$k_key] = self::action_add_key_to_sql($table_name, $k_key, $v_cmp[1]);
  102. $sqls[1][$k_key] = self::action_drop_key_to_sql($table_name, $k_key);
  103. }
  104. }
  105. }
  106. }
  107. return $sqls;
  108. }
  109. /**
  110. * Compare db structures.
  111. * @returns mixed
  112. * null - table not exists in both db
  113. * empty array - table are the same
  114. * array - columns, keys that differs
  115. * example:
  116. * array(
  117. * 'columns' => array(
  118. * 'ID' => array(
  119. * 0 => 1-st db column ID info or null if not exists
  120. * 1 => 2-nd db column ID info or null if not exists
  121. * )
  122. * )
  123. * )
  124. * array(
  125. * 'keys' => array(
  126. * 'KEY X' => array(
  127. * 0 => 1-st db KEY X info or null if not exists
  128. * 1 => 2-nd db KEY X info or null if not exists
  129. * )
  130. * )
  131. * )
  132. */
  133. function compare_db_table($db1, $db2, $table_name) {
  134. if (empty($table_name)) {
  135. return false;
  136. }
  137. $dbs = array($db1, $db2);
  138. $tbl_structs = array();
  139. // check if table exists in both db
  140. foreach ($dbs as $k_db_ind => $v_db) {
  141. $tbl_structs[$k_db_ind] = self::get_table_struct($v_db, $table_name);
  142. }
  143. $tbl_keys = array();
  144. foreach ($dbs as $k_db_ind => $v_db) {
  145. if (!empty($tbl_structs[$k_db_ind])) {
  146. $tbl_keys[$k_db_ind] = self::get_table_keys($v_db, $table_name);
  147. } else {
  148. $tbl_keys[$k_db_ind] = null;
  149. }
  150. }
  151. $cmp = array();
  152. if (empty($tbl_structs[0]) && empty($tbl_structs[1])) {
  153. return null;
  154. }
  155. $cmp['columns'] = array();
  156. $cmp['keys'] = array();
  157. foreach ($dbs as $k_ind => $v_db) {
  158. $k_2nd_ind = 1 - $k_ind;
  159. if (empty($tbl_structs[$k_ind])) {
  160. continue;
  161. }
  162. foreach ($tbl_structs[$k_ind] as $k_field => $v_field) {
  163. if (!array_key_exists($k_field, $tbl_structs[$k_2nd_ind])) {
  164. $cmp['columns'][$k_field][$k_ind] = $v_field;
  165. } else {
  166. $v_2nd_field = $tbl_structs[$k_2nd_ind][$k_field];
  167. $column_differ = false;
  168. if ($v_field['type'] != $v_2nd_field['type']) {
  169. $column_differ = true;
  170. }
  171. $field_add_keys = array('default', 'not null', 'extra');
  172. foreach ($field_add_keys as $field_key) {
  173. if (isset($v_field[$field_key]) && isset($v_2nd_field[$field_key])) {
  174. if ($v_field[$field_key] != $v_2nd_field[$field_key]) {
  175. $column_differ = true;
  176. }
  177. } else if (isset($v_field[$field_key]) != isset($v_2nd_field[$field_key])) {
  178. $column_differ = true;
  179. }
  180. }
  181. if ($column_differ) {
  182. $cmp['columns'][$k_field][$k_ind] = $v_field;
  183. $cmp['columns'][$k_field][$k_2nd_ind] = $v_2nd_field;
  184. }
  185. }
  186. }
  187. }
  188. // keys
  189. foreach ($dbs as $k_ind => $v_db) {
  190. $k_2nd_ind = 1 - $k_ind;
  191. if (empty($tbl_structs[$k_ind])) {
  192. continue;
  193. }
  194. if (empty($tbl_keys[$k_ind])) {
  195. continue;
  196. }
  197. foreach ($tbl_keys[$k_ind] as $k_key_name => $v_key) {
  198. if (!array_key_exists($k_key_name, $tbl_keys[$k_2nd_ind])) {
  199. $cmp['keys'][$k_key_name][$k_ind] = $v_key;
  200. } else {
  201. $v_2nd_key = $tbl_keys[$k_2nd_ind][$k_key_name];
  202. $column_differ = false;
  203. if ($v_key['type'] != $v_2nd_key['type']) {
  204. $column_differ = true;
  205. }
  206. $a_diff_1 = array_diff($v_key['columns'], $v_2nd_key['columns']);
  207. $a_diff_2 = array_diff($v_2nd_key['columns'], $v_key['columns']);
  208. if (!empty($a_diff_1) || !empty($a_diff_2)) {
  209. $column_differ = true;
  210. }
  211. if ($column_differ) {
  212. $cmp['keys'][$k_key_name][$k_ind] = $v_key;
  213. $cmp['keys'][$k_key_name][$k_2nd_ind] = $v_2nd_key;
  214. }
  215. }
  216. }
  217. }
  218. if (empty($cmp['columns'])) unset($cmp['columns']);
  219. if (empty($cmp['keys'])) unset($cmp['keys']);
  220. return $cmp;
  221. }
  222. /**
  223. * @returns array('field name' => array('type'=>'' [, 'default'=>'', 'not null'=>bool, 'extra'=>''] ))
  224. */
  225. function get_table_struct(&$db, $table_name) {
  226. $tbl_struct = array();
  227. $sql = sprintf("SHOW FIELDS FROM `%s`", $table_name);
  228. $res = $db->query($sql);
  229. if ($db->num_rows($res) == 0) {
  230. return null;
  231. }
  232. else {
  233. while ($record = $db->fetch_assoc($res)) {
  234. $tbl_struct[$record['Field']] = array();
  235. $tbl_struct[$record['Field']]['type'] = $record['Type'];
  236. if (!empty($record['Default'])) {
  237. if (substr($record['Default'], 0, strlen('CURRENT_TIMESTAMP')) == 'CURRENT_TIMESTAMP') {
  238. $tbl_struct[$record['Field']]['default'] = $record['Default'];
  239. } else {
  240. $tbl_struct[$record['Field']]['default'] = "'" . $record['Default'] . "'";
  241. }
  242. }
  243. if (@strcmp($record['Null'], 'YES') != 0) {
  244. $tbl_struct[$record['Field']]['not null'] = true;
  245. }
  246. if (!empty($record['Extra'])) {
  247. $tbl_struct[$record['Field']]['extra'] = $record['Extra'];
  248. }
  249. }
  250. }
  251. return $tbl_struct;
  252. }
  253. /**
  254. * @returns array('key name' => array('type'=>'', 'columns'=>array of column names))
  255. */
  256. function get_table_keys(&$db, $table_name) {
  257. $tbl_keys = array();
  258. $sql = sprintf("SHOW KEYS FROM `%s`", $table_name);
  259. $res = $db->query($sql);
  260. if ($db->num_rows($res) == 0) {
  261. return null;
  262. }
  263. while ($row = $db->fetch($res)) {
  264. $key_name = $row->Key_name;
  265. $key_type = '';
  266. if ($row->Key_name == 'PRIMARY') {
  267. if ($row->Index_type == 'BTREE') {
  268. $key_type = "PRIMARY KEY";
  269. }
  270. }
  271. else {
  272. if ($row->Non_unique == '0' && $row->Index_type == 'BTREE') {
  273. $key_type = "UNIQUE KEY";
  274. $key_name = "`{$key_name}`";
  275. }
  276. if ($row->Non_unique == '1' && $row->Index_type == 'BTREE') {
  277. $key_type = "KEY";
  278. $key_name = "`{$key_name}`";
  279. }
  280. if ($row->Non_unique == '1' && $row->Index_type == 'FULLTEXT') {
  281. $key_type = "FULLTEXT";
  282. $key_name = "`{$key_name}`";
  283. }
  284. }
  285. if (!$key_type) {
  286. // TODO: error - unknown type
  287. } else {
  288. if (empty($tbl_keys[$key_name])) {
  289. $tbl_keys[$key_name] = array('type'=>$key_type, 'columns'=>array());
  290. }
  291. $tbl_keys[$key_name]['columns'][] = $row->Column_name;
  292. }
  293. }
  294. return $tbl_keys;
  295. }
  296. function get_table_list(&$db, $table_prefix = '', $table_type = null) {
  297. $tbl_list = array();
  298. if($table_type) $sql="SHOW FULL TABLES WHERE TABLE_TYPE LIKE '{$table_type}'";
  299. else $sql="SHOW TABLES";
  300. $res = $db->query($sql);
  301. if ($db->num_rows($res) == 0) {
  302. return $tbl_list;
  303. }
  304. while ($record = $db->fetch_row($res)) {
  305. if ($table_prefix == '' || $table_prefix == '%' || $table_prefix == substr($record[0], 0, strlen($table_prefix))) {
  306. $tbl_list[] = $record[0];
  307. }
  308. }
  309. return $tbl_list;
  310. }
  311. function get_db_structure_by_table_prefix(&$db, $table_prefix) {
  312. $structure = '';
  313. $res = $db->query('SHOW TABLES');
  314. if ($db->num_rows($res) == 0) {
  315. return false;
  316. }
  317. while ($record = $db->fetch_row($res)) {
  318. if ($table_prefix == '' || $table_prefix == '%' || $table_prefix == substr($record[0], 0, strlen($table_prefix))) {
  319. $table_struct = self::get_table_structure($db, $record[0]);
  320. if ($table_struct === false) {
  321. // TODO: get_table_structure fail
  322. } else {
  323. $structure .= $table_struct;
  324. }
  325. }
  326. }
  327. return $structure;
  328. }
  329. function get_db_structure(&$db, $tables = array()) {
  330. $structure = '';
  331. $res = $db->query('SHOW TABLES');
  332. if ($db->num_rows($res) == 0) {
  333. return false;
  334. }
  335. while ($record = $db->fetch_row($res)) {
  336. if (empty($tables) || in_array($record[0], $tables)) {
  337. $table_struct = self::get_table_structure($db, $record[0]);
  338. if ($table_struct === false) {
  339. // TODO: get_table_structure fail
  340. } else {
  341. $structure .= $table_struct;
  342. }
  343. }
  344. }
  345. return $structure;
  346. }
  347. function get_table_structure(&$db, $table) {
  348. // Structure Header
  349. $structure = "-- \n";
  350. $structure .= "-- Table structure for table `{$table}` \n";
  351. $structure .= "-- \n\n";
  352. // Dump Structure
  353. //$structure .= 'DROP TABLE IF EXISTS `'.$table.'`;'."\n";
  354. // Create sql
  355. $structure .= "CREATE TABLE `{$table}` (\n";
  356. $sql_table_fields = array();
  357. $records = $db->query('SHOW FIELDS FROM `'.$table.'`');
  358. if ($db->num_rows($records) == 0) {
  359. return false;
  360. }
  361. while ($record = $db->fetch_assoc($records)) {
  362. $curr_sql_field = "";
  363. $curr_sql_field .= "`" . $record['Field'] . "` " . $record['Type'];
  364. if (!empty($record['Default'])) {
  365. if (substr($record['Default'], 0, strlen('CURRENT_TIMESTAMP')) == 'CURRENT_TIMESTAMP') {
  366. $curr_sql_field .= " DEFAULT " . $record['Default'];
  367. } else {
  368. $curr_sql_field .= " DEFAULT '{$record['Default']}'";
  369. }
  370. }
  371. if (@strcmp($record['Null'], 'YES') != 0) {
  372. $curr_sql_field .= " NOT NULL";
  373. }
  374. if (!empty($record['Extra'])) {
  375. $curr_sql_field .= " " . $record['Extra'];
  376. }
  377. $sql_table_fields[] = $curr_sql_field;
  378. }
  379. $structure .= (!empty($sql_table_fields))? implode(",\n", $sql_table_fields) : "";
  380. //$structure = @ereg_replace(",\n$", null, $structure);
  381. // Save all Column Indexes
  382. $table_keys = self::get_sql_keys_table($db, $table);
  383. if ($table_keys === false) {
  384. // TODO: get_sql_keys_table fail
  385. } else {
  386. $structure .= ",\n" . $table_keys;
  387. }
  388. $structure .= "\n)";
  389. //Save table engine
  390. $records = $db->query("SHOW TABLE STATUS LIKE '".$table."'");
  391. if ($record = $db->fetch_assoc($records)) {
  392. if (!empty($record['Engine'])) {
  393. $structure .= ' ENGINE='.$record['Engine'];
  394. }
  395. if (!empty($record['Auto_increment'])) {
  396. $structure .= ' AUTO_INCREMENT='.$record['Auto_increment'];
  397. }
  398. }
  399. $structure .= ";\n\n-- --------------------------------------------------------\n\n";
  400. return $structure;
  401. }
  402. function get_sql_keys_table(&$db, $table) {
  403. $ret_keys = array();
  404. $primary = "";
  405. $unique = array();
  406. $index = array();
  407. $fulltext = array();
  408. $res = $db->query("SHOW KEYS FROM `" . $table . "`");
  409. if ($db->num_rows($res) == 0) {
  410. return false;
  411. }
  412. while ($row = $db->fetch($res)) {
  413. if ($row->Key_name == 'PRIMARY') {
  414. if ($row->Index_type == 'BTREE') {
  415. $ret_keys["PRIMARY KEY"][] = "`" . $row->Column_name . "`";
  416. }
  417. }
  418. else {
  419. if ($row->Non_unique == '0' && $row->Index_type == 'BTREE') {
  420. $ret_keys["UNIQUE KEY `" . $row->Key_name . "`"][] = "`" . $row->Column_name . "`";
  421. }
  422. if ($row->Non_unique == '1' && $row->Index_type == 'BTREE') {
  423. $ret_keys["KEY `" . $row->Key_name . "`"][] = "`" . $row->Column_name . "`";
  424. }
  425. if ($row->Non_unique == '1' && $row->Index_type == 'FULLTEXT') {
  426. $ret_keys["FULLTEXT `" . $row->Key_name . "`"][] = "`" . $row->Column_name . "`";
  427. }
  428. }
  429. }
  430. $out_keys = array();
  431. if (!empty($ret_keys)) {
  432. foreach ($ret_keys as $key => $val) {
  433. $out_keys[] = $key . " (" . implode(", ", $val) . ")";
  434. }
  435. }
  436. $out_keys = (!empty($out_keys))? implode(",\n", $out_keys) : '';
  437. return $out_keys;
  438. }
  439. }