schema.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. <?php
  2. /*
  3. FusionPBX
  4. Version: MPL 1.1
  5. The contents of this file are subject to the Mozilla Public License Version
  6. 1.1 (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. for the specific language governing rights and limitations under the
  12. License.
  13. The Original Code is FusionPBX
  14. The Initial Developer of the Original Code is
  15. Mark J Crane <[email protected]>
  16. Copyright (C) 2013 - 2023
  17. All Rights Reserved.
  18. Contributor(s):
  19. Mark J Crane <[email protected]>
  20. */
  21. //define the schema class
  22. if (!class_exists('schema')) {
  23. class schema {
  24. //define variables
  25. private $database;
  26. public $apps;
  27. public $db_type;
  28. public $result;
  29. public $data_types;
  30. //class constructor
  31. public function __construct() {
  32. //includes files
  33. require dirname(__DIR__, 2) . "/resources/require.php";
  34. //connect to the database
  35. $this->database = database::new();
  36. //get the list of installed apps from the core and mod directories
  37. $config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/app_config.php");
  38. $x=0;
  39. foreach ($config_list as $config_path) {
  40. try {
  41. include($config_path);
  42. }
  43. catch (Exception $e) {
  44. //echo 'Caught exception: ', $e->getMessage(), "\n";
  45. }
  46. $x++;
  47. }
  48. $this->apps = $apps;
  49. }
  50. //create the database schema
  51. public function sql() {
  52. $sql = '';
  53. $sql_schema = '';
  54. foreach ($this->apps as $app) {
  55. if (isset($app['db']) && count($app['db'])) {
  56. foreach ($app['db'] as $row) {
  57. //create the sql string
  58. $table_name = $row['table']['name'];
  59. $sql = "CREATE TABLE " . $row['table']['name'] . " (\n";
  60. $field_count = 0;
  61. foreach ($row['fields'] as $field) {
  62. if (!empty($field['deprecated']) and ($field['deprecated'] == "true")) {
  63. //skip this field
  64. }
  65. else {
  66. if ($field_count > 0 ) { $sql .= ",\n"; }
  67. if (is_array($field['name'])) {
  68. $sql .= $field['name']['text']." ";
  69. }
  70. else {
  71. $sql .= $field['name']." ";
  72. }
  73. if (is_array($field['type'])) {
  74. $sql .= $field['type'][$this->db_type];
  75. }
  76. else {
  77. $sql .= $field['type'];
  78. }
  79. if (isset($field['key']) && isset($field['key']['type']) && ($field['key']['type'] == "primary")) {
  80. $sql .= " PRIMARY KEY";
  81. }
  82. if (isset($field['key']) && isset($field['key']['type']) && ($field['key']['type'] == "foreign")) {
  83. if ($this->db_type == "pgsql") {
  84. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  85. }
  86. if ($this->db_type == "sqlite") {
  87. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  88. }
  89. if ($this->db_type == "mysql") {
  90. //$sql .= " references ".$field['key']['reference']['table']."(".$field['key']['reference']['field'].")";
  91. }
  92. }
  93. $field_count++;
  94. }
  95. }
  96. if ($this->db_type == "mysql") {
  97. $sql .= ") ENGINE=INNODB;";
  98. }
  99. else {
  100. $sql .= ");";
  101. }
  102. $this->result['sql'][] = $sql;
  103. unset($sql);
  104. }
  105. }
  106. }
  107. }
  108. //create the database schema
  109. public function exec() {
  110. foreach ($this->result['sql'] as $sql) {
  111. //start the sql transaction
  112. $this->database->beginTransaction();
  113. //execute the sql query
  114. try {
  115. $this->database->query($sql);
  116. }
  117. catch (PDOException $error) {
  118. echo "error: " . $error->getMessage() . " sql: $sql<br/>";
  119. }
  120. //complete the transaction
  121. $this->database->commit();
  122. }
  123. }
  124. //check if a column exists in sqlite
  125. private function sqlite_column_exists($table_info, $column_name) {
  126. foreach ($table_info as $key => $row) {
  127. if ($row['name'] == $column_name) {
  128. return true;
  129. }
  130. }
  131. return $false;
  132. }
  133. //check if a column exists
  134. public function column_exists ($db_name, $table_name, $column_name) {
  135. if ($this->db_type == "sqlite") {
  136. $table_info = $this->table_info($db_name, $table_name);
  137. if ($this->sqlite_column_exists($table_info, $column_name)) {
  138. return true;
  139. }
  140. else {
  141. return false;
  142. }
  143. }
  144. if ($this->db_type == "pgsql") {
  145. $sql = "SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '$table_name' limit 1) AND attname = '$column_name'; ";
  146. }
  147. if ($this->db_type == "mysql") {
  148. //$sql .= "SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = '$db_name' and TABLE_NAME = '$table_name' and COLUMN_NAME = '$column_name' ";
  149. $sql = "show columns from $table_name where field = '$column_name' ";
  150. }
  151. if ($sql) {
  152. $prep_statement = $this->database->db->prepare($sql);
  153. $prep_statement->execute();
  154. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  155. if (!$result) {
  156. return false;
  157. }
  158. if (count($result) > 0) {
  159. return true;
  160. }
  161. else {
  162. return false;
  163. }
  164. unset ($prep_statement);
  165. }
  166. }
  167. //get the table information
  168. public function table_info($db_name, $table_name) {
  169. if (empty($table_name)) { return false; }
  170. if ($this->db_type == "sqlite") {
  171. $sql = "PRAGMA table_info(".$table_name.");";
  172. }
  173. if ($this->db_type == "pgsql") {
  174. $sql = "SELECT ordinal_position, ";
  175. $sql .= "column_name, ";
  176. $sql .= "data_type, ";
  177. $sql .= "column_default, ";
  178. $sql .= "is_nullable, ";
  179. $sql .= "character_maximum_length, ";
  180. $sql .= "numeric_precision ";
  181. $sql .= "FROM information_schema.columns ";
  182. $sql .= "WHERE table_name = '".$table_name."' ";
  183. $sql .= "and table_catalog = '".$db_name."' ";
  184. $sql .= "ORDER BY ordinal_position; ";
  185. }
  186. if ($this->db_type == "mysql") {
  187. $sql = "describe ".$table_name.";";
  188. }
  189. $prep_statement = $this->database->db->prepare($sql);
  190. $prep_statement->execute();
  191. return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
  192. }
  193. //database table exists alternate
  194. private function db_table_exists_alternate ($db_type, $table_name) {
  195. $sql = "select count(*) from $table_name ";
  196. $result = $this->database->query($sql);
  197. if ($result > 0) {
  198. return true; //table exists
  199. }
  200. else {
  201. return false; //table doesn't exist
  202. }
  203. }
  204. //database table exists
  205. private function db_table_exists ($db_type, $db_name, $table_name) {
  206. $sql = "";
  207. if ($db_type == "sqlite") {
  208. $sql .= "SELECT * FROM sqlite_master WHERE type='table' and name='$table_name' ";
  209. }
  210. if ($db_type == "pgsql") {
  211. $sql .= "select * from pg_tables where schemaname='public' and tablename = '$table_name' ";
  212. }
  213. if ($db_type == "mysql") {
  214. $sql .= "SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = '$db_name' and TABLE_NAME = '$table_name' ";
  215. }
  216. $prep_statement = $this->database->db->prepare(check_sql($sql));
  217. $prep_statement->execute();
  218. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  219. if (count($result) > 0) {
  220. return true; //table exists
  221. }
  222. else {
  223. return false; //table doesn't exist
  224. }
  225. }
  226. //database table information
  227. private function db_table_info($db_name, $db_type, $table_name) {
  228. if (empty($table_name)) { return false; }
  229. if ($db_type == "sqlite") {
  230. $sql = "PRAGMA table_info(".$table_name.");";
  231. }
  232. if ($db_type == "pgsql") {
  233. $sql = "SELECT ordinal_position, ";
  234. $sql .= "column_name, ";
  235. $sql .= "data_type, ";
  236. $sql .= "column_default, ";
  237. $sql .= "is_nullable, ";
  238. $sql .= "character_maximum_length, ";
  239. $sql .= "numeric_precision ";
  240. $sql .= "FROM information_schema.columns ";
  241. $sql .= "WHERE table_name = '".$table_name."' ";
  242. $sql .= "and table_catalog = '".$db_name."' ";
  243. $sql .= "ORDER BY ordinal_position; ";
  244. }
  245. if ($db_type == "mysql") {
  246. $sql = "describe ".$table_name.";";
  247. }
  248. $prep_statement = $this->database->db->prepare($sql);
  249. $prep_statement->execute();
  250. return $prep_statement->fetchAll(PDO::FETCH_ASSOC);
  251. }
  252. //database type
  253. private function db_data_type($db_type, $table_info, $column_name) {
  254. if ($db_type == "sqlite") {
  255. foreach ($table_info as $key => $row) {
  256. if ($row['name'] == $column_name) {
  257. return $row['type'];
  258. }
  259. }
  260. }
  261. if ($db_type == "pgsql") {
  262. foreach ($table_info as $key => $row) {
  263. if ($row['column_name'] == $column_name) {
  264. return $row['data_type'];
  265. }
  266. }
  267. }
  268. if ($db_type == "mysql") {
  269. foreach ($table_info as $key => $row) {
  270. if ($row['Field'] == $column_name) {
  271. return $row['Type'];
  272. }
  273. }
  274. }
  275. }
  276. //sqlite column exists
  277. private function db_sqlite_column_exists($table_info, $column_name) {
  278. foreach ($table_info as $key => $row) {
  279. if ($row['name'] == $column_name) {
  280. return true;
  281. }
  282. }
  283. return $false;
  284. }
  285. //database column exists
  286. private function db_column_exists ($db_type, $db_name, $table_name, $column_name) {
  287. if ($db_type == "sqlite") {
  288. $table_info = $this->db_table_info($db_name, $db_type, $table_name);
  289. if ($this->db_sqlite_column_exists($table_info, $column_name)) {
  290. return true;
  291. }
  292. else {
  293. return false;
  294. }
  295. }
  296. if ($db_type == "pgsql") {
  297. $sql = "SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '$table_name' limit 1) AND attname = '$column_name'; ";
  298. }
  299. if ($db_type == "mysql") {
  300. //$sql .= "SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = '$db_name' and TABLE_NAME = '$table_name' and COLUMN_NAME = '$column_name' ";
  301. $sql = "show columns from $table_name where field = '$column_name' ";
  302. }
  303. if ($sql) {
  304. $prep_statement = $this->database->db->prepare(check_sql($sql));
  305. $prep_statement->execute();
  306. $result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
  307. if (!empty($result)) {
  308. return true;
  309. }
  310. else {
  311. return false;
  312. }
  313. unset ($prep_statement);
  314. }
  315. }
  316. //database column data type
  317. private function db_column_data_type ($db_type, $db_name, $table_name, $column_name) {
  318. $table_info = $this->db_table_info($db_name, $db_type, $table_name);
  319. return $this->db_data_type($db_type, $table_info, $column_name);
  320. }
  321. //database create table
  322. public function db_create_table ($apps, $db_type, $table) {
  323. if (empty($apps)) { return false; }
  324. if (is_array($apps)) foreach ($apps as $x => $app) {
  325. if (!empty($app['db']) && is_array($app['db'])) foreach ($app['db'] as $y => $row) {
  326. if (!empty($row['table']['name']) && is_array($row['table']['name'])) {
  327. $table_name = $row['table']['name']['text'];
  328. }
  329. else {
  330. $table_name = $row['table']['name'];
  331. }
  332. if ($table_name == $table) {
  333. $sql = "CREATE TABLE " . $table_name . " (\n";
  334. (int)$field_count = 0;
  335. if (!empty($row['fields']) && is_array($row['fields'])) foreach ($row['fields'] as $field) {
  336. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  337. //skip this row
  338. }
  339. else {
  340. if ($field_count > 0 ) { $sql .= ",\n"; }
  341. if (!empty($field['name']) &&is_array($field['name'])) {
  342. $sql .= $field['name']['text'] . " ";
  343. }
  344. else {
  345. $sql .= $field['name'] . " ";
  346. }
  347. if (!empty($field['type']) &&is_array($field['type'])) {
  348. $sql .= $field['type'][$db_type];
  349. }
  350. else {
  351. $sql .= $field['type'];
  352. }
  353. if (!empty($field['key']['type']) && $field['key']['type'] == "primary") {
  354. $sql .= " PRIMARY KEY";
  355. }
  356. $field_count++;
  357. }
  358. }
  359. $sql .= ");\n";
  360. return $sql;
  361. }
  362. }
  363. }
  364. }
  365. //database insert
  366. private function db_insert_into ($apps, $db_type, $table) {
  367. global $db_name;
  368. foreach ($apps as $x => $app) {
  369. foreach ($app['db'] as $y => $row) {
  370. if ($row['table']['name'] == $table) {
  371. $sql = "INSERT INTO " . $row['table']['name'] . " (";
  372. $field_count = 0;
  373. foreach ($row['fields'] as $field) {
  374. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  375. //skip this field
  376. }
  377. else {
  378. if ($field_count > 0 ) { $sql .= ","; }
  379. if (is_array($field['name'])) {
  380. $sql .= $field['name']['text'];
  381. }
  382. else {
  383. $sql .= $field['name'];
  384. }
  385. $field_count++;
  386. }
  387. }
  388. $sql .= ")\n";
  389. $sql .= "SELECT ";
  390. $field_count = 0;
  391. foreach ($row['fields'] as $field) {
  392. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  393. //skip this field
  394. }
  395. else {
  396. if ($field_count > 0 ) { $sql .= ","; }
  397. if (is_array($field['name'])) {
  398. if ($field['exists'] == "false") {
  399. if (is_array($field['name']['deprecated'])) {
  400. $found = false;
  401. foreach ($field['name']['deprecated'] as $row) {
  402. if ($this->db_column_exists ($db_type, $db_name, 'tmp_'.$table, $row)) {
  403. $sql .= $row;
  404. $found = true;
  405. break;
  406. }
  407. }
  408. if (!$found) { $sql .= "''"; }
  409. }
  410. else {
  411. if ($this->db_column_exists ($db_type, $db_name, 'tmp_'.$table, $field['name']['deprecated'])) {
  412. $sql .= $field['name']['deprecated'];
  413. }
  414. else {
  415. $sql .= "''";
  416. }
  417. }
  418. }
  419. else {
  420. $sql .= $field['name']['text'];
  421. }
  422. }
  423. else {
  424. $sql .= $field['name'];
  425. }
  426. $field_count++;
  427. }
  428. }
  429. $sql .= " FROM tmp_".$table.";\n";
  430. return $sql;
  431. }
  432. }
  433. }
  434. }
  435. //datatase schema
  436. public function schema ($format = '') {
  437. //set the global variable
  438. global $text, $output_format;
  439. if ($format == '') $format = $output_format;
  440. //get the db variables
  441. //require_once "resources/classes/config.php";
  442. //$config = new config;
  443. //$config_exists = $config->exists();
  444. //$config_path = $config->find();
  445. //$config->get();
  446. //$db_type = $config->db_type;
  447. //$db_name = $config->db_name;
  448. //$db_username = $config->db_username;
  449. //$db_password = $config->db_password;
  450. //$db_host = $config->db_host;
  451. //$db_path = $config->db_path;
  452. //$db_port = $config->db_port;
  453. //includes files
  454. require dirname(__DIR__, 2) . "/resources/require.php";
  455. //add multi-lingual support
  456. if (!isset($text)) {
  457. $language = new text;
  458. $text = $language->get(null,'core/upgrade');
  459. }
  460. //PHP PDO check if table or column exists
  461. //check if table exists
  462. // SELECT * FROM sqlite_master WHERE type='table' AND name='v_cdr'
  463. //check if column exists
  464. // SELECT * FROM sqlite_master WHERE type='table' AND name='v_cdr' AND sql LIKE '%caller_id_name TEXT,%'
  465. //aditional information
  466. // http://www.sqlite.org/faq.html#q9
  467. //postgresql
  468. //list all tables in the database
  469. // SELECT table_name FROM pg_tables WHERE schemaname='public';
  470. //check if table exists
  471. // SELECT * FROM pg_tables WHERE schemaname='public' AND table_name = 'v_groups'
  472. //check if column exists
  473. // SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'v_cdr') AND attname = 'caller_id_name';
  474. //mysql
  475. //list all tables in the database
  476. // SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'fusionpbx'
  477. //check if table exists
  478. // SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'fusionpbx' AND TABLE_NAME = 'v_groups'
  479. //check if column exists
  480. // SELECT * FROM information_schema.COLUMNS where TABLE_SCHEMA = 'fusionpbx' AND TABLE_NAME = 'v_cdr' AND COLUMN_NAME = 'context'
  481. //oracle
  482. //check if table exists
  483. // SELECT TABLE_NAME FROM ALL_TABLES
  484. //update the app db array add exists true or false
  485. $sql = '';
  486. foreach ($this->apps as $x => $app) {
  487. if (isset($app['db'])) foreach ($app['db'] as $y => $row) {
  488. if (isset($row['table']['name'])) {
  489. if (is_array($row['table']['name'])) {
  490. $table_name = $row['table']['name']['text'];
  491. }
  492. else {
  493. $table_name = $row['table']['name'];
  494. }
  495. }
  496. else {
  497. //old array syntax
  498. if (is_array($row['table'])) {
  499. $table_name = $row['table']['text'];
  500. }
  501. else {
  502. $table_name = $row['table'];
  503. }
  504. }
  505. if (!empty($table_name)) {
  506. //check if the table exists
  507. if ($this->db_table_exists($db_type, $db_name, $table_name)) {
  508. $this->apps[$x]['db'][$y]['exists'] = 'true';
  509. }
  510. else {
  511. $this->apps[$x]['db'][$y]['exists'] = 'false';
  512. }
  513. //check if the column exists
  514. foreach ($row['fields'] as $z => $field) {
  515. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  516. //skip this field
  517. }
  518. else {
  519. if (is_array($field['name'])) {
  520. $field_name = $field['name']['text'];
  521. }
  522. else {
  523. $field_name = $field['name'];
  524. }
  525. if (!empty($field_name)) {
  526. if ($this->db_column_exists ($db_type, $db_name, $table_name, $field_name)) {
  527. //found
  528. $this->apps[$x]['db'][$y]['fields'][$z]['exists'] = 'true';
  529. }
  530. else {
  531. //not found
  532. $this->apps[$x]['db'][$y]['fields'][$z]['exists'] = 'false';
  533. }
  534. }
  535. unset($field_name);
  536. }
  537. }
  538. unset($table_name);
  539. }
  540. }
  541. }
  542. //prepare the variables
  543. $sql_update = '';
  544. //add missing tables and fields
  545. foreach ($this->apps as $x => $app) {
  546. if (isset($app['db'])) foreach ($app['db'] as $y => $row) {
  547. if (is_array($row['table']['name'])) {
  548. $table_name = $row['table']['name']['text'];
  549. if ($this->db_table_exists($db_type, $db_name, $row['table']['name']['deprecated'])) {
  550. $row['exists'] = "false"; //testing
  551. if ($db_type == "pgsql") {
  552. $sql_update .= "ALTER TABLE ".$row['table']['name']['deprecated']." RENAME TO ".$row['table']['name']['text'].";\n";
  553. }
  554. if ($db_type == "mysql") {
  555. $sql_update .= "RENAME TABLE ".$row['table']['name']['deprecated']." TO ".$row['table']['name']['text'].";\n";
  556. }
  557. if ($db_type == "sqlite") {
  558. $sql_update .= "ALTER TABLE ".$row['table']['name']['deprecated']." RENAME TO ".$row['table']['name']['text'].";\n";
  559. }
  560. }
  561. else {
  562. if ($this->db_table_exists($db_type, $db_name, $row['table']['name']['text'])) {
  563. $row['exists'] = "true";
  564. }
  565. else {
  566. $row['exists'] = "false";
  567. $sql_update .= $this->db_create_table($this->apps, $db_type, $row['table']['name']['text']);
  568. }
  569. }
  570. }
  571. else {
  572. if ($this->db_table_exists($db_type, $db_name, $row['table']['name'])) {
  573. $row['exists'] = "true";
  574. }
  575. else {
  576. $row['exists'] = "false";
  577. }
  578. $table_name = $row['table']['name'];
  579. }
  580. //check if the table exists
  581. if ($row['exists'] == "true") {
  582. if (count($row['fields']) > 0) {
  583. foreach ($row['fields'] as $z => $field) {
  584. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  585. //skip this field
  586. }
  587. else {
  588. //get the data type
  589. if (is_array($field['type'])) {
  590. $field_type = $field['type'][$db_type];
  591. }
  592. else {
  593. $field_type = $field['type'];
  594. }
  595. //get the field name
  596. if (is_array($field['name'])) {
  597. $field_name = $field['name']['text'];
  598. }
  599. else {
  600. $field_name = $field['name'];
  601. }
  602. //check if the field exists
  603. // if ($this->db_column_exists($db_type, $db_name, $table_name, $field_name)) {
  604. // $field['exists'] = "true";
  605. // }
  606. // else {
  607. // $field['exists'] = "false";
  608. // }
  609. //add or rename fields
  610. if (isset($field['name']['deprecated']) && $this->db_column_exists ($db_type, $db_name, $table_name, $field['name']['deprecated'])) {
  611. if ($db_type == "pgsql") {
  612. $sql_update .= "ALTER TABLE ".$table_name." RENAME COLUMN ".$field['name']['deprecated']." to ".$field['name']['text'].";\n";
  613. }
  614. if ($db_type == "mysql") {
  615. $field_type = str_replace("AUTO_INCREMENT PRIMARY KEY", "", $field_type);
  616. $sql_update .= "ALTER TABLE ".$table_name." CHANGE ".$field['name']['deprecated']." ".$field['name']['text']." ".$field_type.";\n";
  617. }
  618. if ($db_type == "sqlite") {
  619. //a change has been made to the field name
  620. $this->apps[$x]['db'][$y]['rebuild'] = 'true';
  621. }
  622. }
  623. else {
  624. //find missing fields and add them
  625. if ($field['exists'] == "false") {
  626. $sql_update .= "ALTER TABLE ".$table_name." ADD ".$field_name." ".$field_type.";\n";
  627. }
  628. }
  629. //change the data type if it has been changed
  630. //if the data type in the app db array is different than the type in the database then change the data type
  631. if ($this->data_types) {
  632. $db_field_type = $this->db_column_data_type ($db_type, $db_name, $table_name, $field_name);
  633. $field_type_array = explode("(", $field_type);
  634. $field_type = $field_type_array[0];
  635. if (trim($db_field_type) != trim($field_type) && !empty($db_field_type)) {
  636. if ($db_type == "pgsql") {
  637. if (strtolower($field_type) == "uuid") {
  638. $sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE uuid USING\n";
  639. $sql_update .= "CAST(regexp_replace(".$field_name.", '([A-Z0-9]{4})([A-Z0-9]{12})', E'\\1-\\2')\n";
  640. $sql_update .= "AS uuid);\n";
  641. }
  642. else {
  643. //field type has not changed
  644. if ($db_field_type == "integer" && strtolower($field_type) == "serial") { }
  645. else if ($db_field_type == "timestamp without time zone" && strtolower($field_type) == "timestamp") { }
  646. else if ($db_field_type == "timestamp without time zone" && strtolower($field_type) == "datetime") { }
  647. else if ($db_field_type == "timestamp with time zone" && strtolower($field_type) == "timestamptz") { }
  648. else if ($db_field_type == "integer" && strtolower($field_type) == "numeric") { }
  649. else if ($db_field_type == "character" && strtolower($field_type) == "char") { }
  650. //field type has changed
  651. else {
  652. switch ($field_type) {
  653. case 'numeric': $using = $field_name."::numeric"; break;
  654. case 'timestamp':
  655. case 'datetime': $using = $field_name."::timestamp without time zone"; break;
  656. case 'timestamptz': $using = $field_name."::timestamp with time zone"; break;
  657. case 'boolean': $using = $field_name."::boolean"; break;
  658. default: unset($using);
  659. }
  660. $sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE ".$field_type." ".($using ? "USING ".$using : null).";\n";
  661. }
  662. }
  663. }
  664. if ($db_type == "mysql") {
  665. $type = explode("(", $db_field_type);
  666. if ($type[0] == $field_type) {
  667. //do nothing
  668. }
  669. else if ($field_type == "numeric" && $type[0] == "decimal") {
  670. //do nothing
  671. }
  672. else {
  673. $sql_update .= "ALTER TABLE ".$table_name." modify ".$field_name." ".$field_type.";\n";
  674. }
  675. unset($type);
  676. }
  677. if ($db_type == "sqlite") {
  678. //a change has been made to the field type
  679. $this->apps[$x]['db'][$y]['rebuild'] = 'true';
  680. }
  681. }
  682. }
  683. }
  684. }
  685. }
  686. }
  687. elseif (!is_array($row['table']['name'])) {
  688. //create table
  689. $sql_update .= $this->db_create_table($this->apps, $db_type, $row['table']['name']);
  690. }
  691. }
  692. }
  693. //rebuild and populate the table
  694. foreach ($this->apps as $x => $app) {
  695. if (isset($app['db'])) foreach ($app['db'] as $y => $row) {
  696. if (is_array($row['table']['name'])) {
  697. $table_name = $row['table']['name']['text'];
  698. }
  699. else {
  700. $table_name = $row['table']['name'];
  701. }
  702. if (!empty($field['rebuild']) && $row['rebuild'] == "true") {
  703. if ($db_type == "sqlite") {
  704. //start the transaction
  705. //$sql_update .= "BEGIN TRANSACTION;\n";
  706. //rename the table
  707. $sql_update .= "ALTER TABLE ".$table_name." RENAME TO tmp_".$table_name.";\n";
  708. //create the table
  709. $sql_update .= $this->db_create_table($this->apps, $db_type, $table_name);
  710. //insert the data into the new table
  711. $sql_update .= $this->db_insert_into($this->apps, $db_type, $table_name);
  712. //drop the old table
  713. $sql_update .= "DROP TABLE tmp_".$table_name.";\n";
  714. //commit the transaction
  715. //$sql_update .= "COMMIT;\n";
  716. }
  717. }
  718. }
  719. }
  720. // initialize response variable
  721. $response = '';
  722. //display results as html
  723. if ($format == "html") {
  724. //show the database type
  725. $response .= "<strong>".$text['header-database_type'].": ".$db_type. "</strong><br /><br />";
  726. //start the table
  727. $response .= "<table width='100%' border='0' cellpadding='20' cellspacing='0'>\n";
  728. //show the changes
  729. if (!empty($sql_update)) {
  730. $response .= "<tr>\n";
  731. $response .= "<td class='row_style1' colspan='3'>\n";
  732. $response .= "<br />\n";
  733. $response .= "<strong>".$text['label-sql_changes'].":</strong><br />\n";
  734. $response .= "<pre>\n";
  735. $response .= $sql_update;
  736. $response .= "</pre>\n";
  737. $response .= "<br />\n";
  738. $response .= "</td>\n";
  739. $response .= "</tr>\n";
  740. }
  741. //list all tables
  742. $response .= "<tr>\n";
  743. $response .= "<th>".$text['label-table']."</th>\n";
  744. $response .= "<th>".$text['label-exists']."</th>\n";
  745. $response .= "<th>".$text['label-details']."</th>\n";
  746. $response .= "<tr>\n";
  747. //build the html while looping through the app db array
  748. $sql = '';
  749. foreach ($this->apps as $app) {
  750. if (isset($app['db'])) foreach ($app['db'] as $row) {
  751. if (is_array($row['table']['name'])) {
  752. $table_name = $row['table']['name']['text'];
  753. }
  754. else {
  755. $table_name = $row['table']['name'];
  756. }
  757. $response .= "<tr>\n";
  758. //check if the table exists
  759. if ($row['exists'] == "true") {
  760. $response .= "<td valign='top' class='row_style1'>".$table_name."</td>\n";
  761. $response .= "<td valign='top' class='vncell' style='padding-top: 3px;'>".$text['option-true']."</td>\n";
  762. if (count($row['fields']) > 0) {
  763. $response .= "<td class='row_style1'>\n";
  764. //show the list of columns
  765. $response .= "<table border='0' cellpadding='10' cellspacing='0'>\n";
  766. $response .= "<tr>\n";
  767. $response .= "<th>".$text['label-name']."</th>\n";
  768. $response .= "<th>".$text['label-type']."</th>\n";
  769. $response .= "<th>".$text['label-exists']."</th>\n";
  770. $response .= "</tr>\n";
  771. foreach ($row['fields'] as $field) {
  772. if (!empty($field['deprecated']) && $field['deprecated'] == "true") {
  773. //skip this field
  774. }
  775. else {
  776. if (is_array($field['name'])) {
  777. $field_name = $field['name']['text'];
  778. }
  779. else {
  780. $field_name = $field['name'];
  781. }
  782. if (is_array($field['type'])) {
  783. $field_type = $field['type'][$db_type];
  784. }
  785. else {
  786. $field_type = $field['type'];
  787. }
  788. $response .= "<tr>\n";
  789. $response .= "<td class='row_style1' width='200'>".$field_name."</td>\n";
  790. $response .= "<td class='row_style1'>".$field_type."</td>\n";
  791. if ($field['exists'] == "true") {
  792. $response .= "<td class='row_style0' style=''>".$text['option-true']."</td>\n";
  793. $response .= "<td>&nbsp;</td>\n";
  794. }
  795. else {
  796. $response .= "<td class='row_style1' style='background-color:#444444;color:#CCCCCC;'>".$text['option-false']."</td>\n";
  797. $response .= "<td>&nbsp;</td>\n";
  798. }
  799. $response .= "</tr>\n";
  800. }
  801. }
  802. $response .= " </table>\n";
  803. $response .= "</td>\n";
  804. }
  805. }
  806. else {
  807. $response .= "<td valign='top' class='row_style1'>$table_name</td>\n";
  808. $response .= "<td valign='top' class='row_style1' style='background-color:#444444;color:#CCCCCC;'><strong>".$text['label-exists']."</strong><br />".$text['option-false']."</td>\n";
  809. $response .= "<td valign='top' class='row_style1'>&nbsp;</td>\n";
  810. }
  811. $response .= "</tr>\n";
  812. }
  813. }
  814. //end the list of tables
  815. $response .= "</table>\n";
  816. $response .= "<br />\n";
  817. }
  818. //loop line by line through all the lines of sql code
  819. $x = 0;
  820. if (empty($sql_update) && $format == "text") {
  821. $response .= " ".$text['label-schema'].": ".$text['label-no_change']."\n";
  822. }
  823. else {
  824. if ($format == "text") {
  825. $response .= " ".$text['label-schema']."\n";
  826. }
  827. //$this->db->beginTransaction();
  828. $update_array = explode(";", $sql_update);
  829. foreach($update_array as $sql) {
  830. if (strlen(trim($sql))) {
  831. try {
  832. $this->database->db->query(trim($sql));
  833. if ($format == "text") {
  834. $response .= " $sql;\n";
  835. }
  836. }
  837. catch (PDOException $error) {
  838. $response .= " error: " . $error->getMessage() . " sql: $sql\n";
  839. }
  840. }
  841. }
  842. //$this->db->commit();
  843. $response .= "\n";
  844. unset ($sql_update, $sql);
  845. }
  846. //refresh each postgresql subscription with its publication
  847. if ($db_type == "pgsql") {
  848. //get the list of postgresql subscriptions
  849. $sql = "select subname from pg_subscription; ";
  850. $pg_subscriptions = $this->database->select($sql, null, 'all');
  851. unset($sql, $parameters);
  852. //refresh each subscription publication
  853. foreach ($pg_subscriptions as $row) {
  854. $sql = "ALTER SUBSCRIPTION ".$row['subname']." REFRESH PUBLICATION;";
  855. $response .= $sql;
  856. $this->database->execute($sql);
  857. }
  858. }
  859. //handle response
  860. //if ($output == "echo") {
  861. // echo $response;
  862. //}
  863. //else if ($output == "return") {
  864. return $response;
  865. //}
  866. } //end function
  867. }
  868. }
  869. //example use
  870. //require_once "resources/classes/schema.php";
  871. //$obj = new schema;
  872. //$obj->db_type = $db_type;
  873. //$obj->schema();
  874. //$result_array = $schema->obj['sql'];
  875. //print_r($result_array);
  876. ?>