PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/include/database/MysqlHelper.php

https://github.com/mikmagic/sugarcrm_dev
PHP | 526 lines | 351 code | 42 blank | 133 comment | 86 complexity | ca56e3517a8cbce5581085683c8da6c9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under
  8. * the terms of the GNU Affero General Public License version 3 as published by the
  9. * Free Software Foundation with the addition of the following permission added
  10. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License along with
  20. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301 USA.
  23. *
  24. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License version 3.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  32. * these Appropriate Legal Notices must retain the display of the "Powered by
  33. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34. * technical reasons, the Appropriate Legal Notices must display the words
  35. * "Powered by SugarCRM".
  36. ********************************************************************************/
  37. /*********************************************************************************
  38. * Description: This file handles the Data base functionality for the application specific
  39. * to oracle database. It is called by the DBManager class to generate various sql statements.
  40. *
  41. * All the functions in this class will work with any bean which implements the meta interface.
  42. * Please refer the DBManager documentation for the details.
  43. *
  44. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  45. * All Rights Reserved.
  46. * Contributor(s): ______________________________________..
  47. ********************************************************************************/
  48. require_once('include/database/DBHelper.php');
  49. class MysqlHelper extends DBHelper
  50. {
  51. /**
  52. * @see DBHelper::createTableSQL()
  53. */
  54. public function createTableSQL(
  55. SugarBean $bean
  56. )
  57. {
  58. $tablename = $bean->getTableName();
  59. $fieldDefs = $bean->getFieldDefinitions();
  60. $indices = $bean->getIndices();
  61. $engine = $this->getEngine($bean);
  62. return $this->createTableSQLParams($tablename, $fieldDefs, $indices, $engine);
  63. }
  64. /**
  65. * Generates sql for create table statement for a bean.
  66. *
  67. * @param string $tablename
  68. * @param array $fieldDefs
  69. * @param array $indices
  70. * @param string $engine optional, MySQL engine to use
  71. * @return string SQL Create Table statement
  72. */
  73. public function createTableSQLParams(
  74. $tablename,
  75. $fieldDefs,
  76. $indices,
  77. $engine = null
  78. )
  79. {
  80. if ( empty($engine) && isset($fieldDefs['engine']))
  81. $engine = $fieldDefs['engine'];
  82. if ( !$this->isEngineEnabled($engine) )
  83. $engine = '';
  84. $sql = parent::createTableSQLParams($tablename,$fieldDefs,$indices);
  85. if (!empty($engine))
  86. $sql.= " ENGINE=$engine";
  87. return $sql;
  88. }
  89. /**
  90. * Returns the name of the engine to use or null if we are to use the default
  91. *
  92. * @param object $bean SugarBean instance
  93. * @return string
  94. */
  95. private function getEngine($bean)
  96. {
  97. global $dictionary;
  98. $engine = null;
  99. if (isset($dictionary[$bean->getObjectName()]['engine'])) {
  100. $engine = $dictionary[$bean->getObjectName()]['engine'];
  101. }
  102. return $engine;
  103. }
  104. /**
  105. * Returns true if the engine given is enabled in the backend
  106. *
  107. * @param string $engine
  108. * @return bool
  109. */
  110. private function isEngineEnabled(
  111. $engine
  112. )
  113. {
  114. $engine = strtoupper($engine);
  115. $r = $this->db->query("SHOW ENGINES");
  116. while ( $row = $this->db->fetchByAssoc($r) )
  117. if ( strtoupper($row['Engine']) == $engine )
  118. return ($row['Support']=='YES' || $row['Support']=='DEFAULT');
  119. return false;
  120. }
  121. /**
  122. * @see DBHelper::getColumnType()
  123. */
  124. public function getColumnType(
  125. $type,
  126. $name = '',
  127. $table = ''
  128. )
  129. {
  130. $map = array(
  131. 'int' => 'int',
  132. 'double' => 'double',
  133. 'float' => 'float',
  134. 'uint' => 'int unsigned',
  135. 'ulong' => 'bigint unsigned',
  136. 'long' => 'bigint',
  137. 'short' => 'smallint',
  138. 'varchar' => 'varchar',
  139. 'text' => 'text',
  140. 'longtext' => 'longtext',
  141. 'date' => 'date',
  142. 'enum' => 'varchar',
  143. 'relate' => 'varchar',
  144. 'multienum'=> 'text',
  145. 'html' => 'text',
  146. 'datetime' => 'datetime',
  147. 'datetimecombo' => 'datetime',
  148. 'time' => 'time',
  149. 'bool' => 'bool',
  150. 'tinyint' => 'tinyint',
  151. 'char' => 'char',
  152. 'blob' => 'blob',
  153. 'longblob' => 'longblob',
  154. 'currency' => 'decimal(26,6)',
  155. 'decimal' => 'decimal',
  156. 'decimal2' => 'decimal',
  157. 'id' => 'char(36)',
  158. 'url'=>'varchar',
  159. 'encrypt'=>'varchar',
  160. 'file' => 'varchar',
  161. );
  162. // Bug 44291 - If requested type is in array, returns it. Otherwise return requested type, so devs could see exactly what went wrong in log.
  163. if (isset($map[$type]))
  164. return $map[$type];
  165. else
  166. return $type;
  167. }
  168. /**
  169. * @see DBHelper::oneColumnSQLRep()
  170. */
  171. protected function oneColumnSQLRep(
  172. $fieldDef,
  173. $ignoreRequired = false,
  174. $table = '',
  175. $return_as_array = false
  176. )
  177. {
  178. $ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
  179. if ( $ref['colType'] == 'int'
  180. && !empty($fieldDef['len']) )
  181. $ref['colType'] .= "(".$fieldDef['len'].")";
  182. // bug 22338 - don't set a default value on text or blob fields
  183. if ( isset($ref['default']) &&
  184. ($ref['colType'] == 'text' || $ref['colType'] == 'blob'
  185. || $ref['colType'] == 'longtext' || $ref['colType'] == 'longblob' ))
  186. $ref['default'] = '';
  187. if ( $return_as_array )
  188. return $ref;
  189. else
  190. return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
  191. }
  192. /**
  193. * @see DBHelper::changeColumnSQL()
  194. */
  195. protected function changeColumnSQL(
  196. $tablename,
  197. $fieldDefs,
  198. $action,
  199. $ignoreRequired = false
  200. )
  201. {
  202. if ($this->isFieldArray($fieldDefs)){
  203. foreach ($fieldDefs as $def){
  204. if ($action == 'drop')
  205. $columns[] = $def['name'];
  206. else
  207. $columns[] = $this->oneColumnSQLRep($def, $ignoreRequired);
  208. }
  209. }else{
  210. if ($action == 'drop')
  211. $columns[] = $fieldDefs['name'];
  212. else
  213. $columns[] = $this->oneColumnSQLRep($fieldDefs);
  214. }
  215. return "alter table $tablename $action column ".implode(",$action column ", $columns);
  216. }
  217. /**
  218. * @see DBHelper::deleteColumnSQL()
  219. */
  220. public function deleteColumnSQL(
  221. SugarBean $bean,
  222. $fieldDefs
  223. )
  224. {
  225. if ($this->isFieldArray($fieldDefs))
  226. foreach ($fieldDefs as $fieldDef)
  227. $columns[] = $fieldDef['name'];
  228. else
  229. $columns[] = $fieldDefs['name'];
  230. return "alter table ".$bean->getTableName()." drop column ".implode(", drop column ", $columns);
  231. }
  232. /**
  233. * @see DBHelper::keysSQL
  234. */
  235. public function keysSQL(
  236. $indices,
  237. $alter_table = false,
  238. $alter_action = ''
  239. )
  240. {
  241. // check if the passed value is an array of fields.
  242. // if not, convert it into an array
  243. if (!$this->isFieldArray($indices))
  244. $indices[] = $indices;
  245. $columns = array();
  246. foreach ($indices as $index) {
  247. if(!empty($index['db']) && $index['db'] != 'mysql')
  248. continue;
  249. if (isset($index['source']) && $index['source'] != 'db')
  250. continue;
  251. $type = $index['type'];
  252. $name = $index['name'];
  253. if (is_array($index['fields']))
  254. $fields = implode(", ", $index['fields']);
  255. else
  256. $fields = $index['fields'];
  257. switch ($type) {
  258. case 'unique':
  259. $columns[] = " UNIQUE $name ($fields)";
  260. break;
  261. case 'primary':
  262. $columns[] = " PRIMARY KEY ($fields)";
  263. break;
  264. case 'index':
  265. case 'foreign':
  266. case 'clustered':
  267. case 'alternate_key':
  268. /**
  269. * @todo here it is assumed that the primary key of the foreign
  270. * table will always be named 'id'. It must be noted though
  271. * that this can easily be fixed by referring to db dictionary
  272. * to find the correct primary field name
  273. */
  274. if ( $alter_table )
  275. $columns[] = " INDEX $name ($fields)";
  276. else
  277. $columns[] = " KEY $name ($fields)";
  278. break;
  279. case 'fulltext':
  280. if ($this->full_text_indexing_enabled())
  281. $columns[] = " FULLTEXT ($fields)";
  282. else
  283. $GLOBALS['log']->debug('MYISAM engine is not available/enabled, full-text indexes will be skipped. Skipping:',$name);
  284. break;
  285. }
  286. }
  287. $columns = implode(", $alter_action ", $columns);
  288. if(!empty($alter_action)){
  289. $columns = $alter_action . ' '. $columns;
  290. }
  291. return $columns;
  292. }
  293. /**
  294. * @see DBHelper::setAutoIncrement()
  295. */
  296. protected function setAutoIncrement(
  297. $table,
  298. $field_name
  299. )
  300. {
  301. return "auto_increment";
  302. }
  303. /**
  304. * Sets the next auto-increment value of a column to a specific value.
  305. *
  306. * @param string $table tablename
  307. * @param string $field_name
  308. */
  309. public function setAutoIncrementStart(
  310. $table,
  311. $field_name,
  312. $start_value
  313. )
  314. {
  315. $this->db->query( "ALTER TABLE $table AUTO_INCREMENT = $start_value;");
  316. return true;
  317. }
  318. /**
  319. * Returns the next value for an auto increment
  320. *
  321. * @param string $table tablename
  322. * @param string $field_name
  323. * @return string
  324. */
  325. public function getAutoIncrement(
  326. $table,
  327. $field_name
  328. )
  329. {
  330. $result = $this->db->query("SHOW TABLE STATUS LIKE '$table'");
  331. $row = $this->db->fetchByAssoc($result);
  332. if (!empty($row['Auto_increment']))
  333. return $row['Auto_increment'];
  334. return "";
  335. }
  336. /**
  337. * @see DBHelper::get_indices()
  338. */
  339. public function get_indices(
  340. $tablename
  341. )
  342. {
  343. //find all unique indexes and primary keys.
  344. $result = $this->db->query("SHOW INDEX FROM $tablename");
  345. $indices = array();
  346. while (($row=$this->db->fetchByAssoc($result)) !=null) {
  347. $index_type='index';
  348. if ($row['Key_name'] =='PRIMARY') {
  349. $index_type='primary';
  350. }
  351. elseif ( $row['Non_unique'] == '0' ) {
  352. $index_type='unique';
  353. }
  354. $name = strtolower($row['Key_name']);
  355. $indices[$name]['name']=$name;
  356. $indices[$name]['type']=$index_type;
  357. $indices[$name]['fields'][]=strtolower($row['Column_name']);
  358. }
  359. return $indices;
  360. }
  361. /**
  362. * @see DBHelper::get_columns()
  363. */
  364. public function get_columns(
  365. $tablename
  366. )
  367. {
  368. //find all unique indexes and primary keys.
  369. $result = $this->db->query("DESCRIBE $tablename");
  370. $columns = array();
  371. while (($row=$this->db->fetchByAssoc($result)) !=null) {
  372. $name = strtolower($row['Field']);
  373. $columns[$name]['name']=$name;
  374. $matches = array();
  375. preg_match_all("/(\w+)(?:\(([0-9]+,?[0-9]*)\)|)( unsigned)?/i", $row['Type'], $matches);
  376. $columns[$name]['type']=strtolower($matches[1][0]);
  377. if ( isset($matches[2][0]) && in_array(strtolower($matches[1][0]),array('varchar','char','varchar2','int','decimal','float')) )
  378. $columns[$name]['len']=strtolower($matches[2][0]);
  379. if ( stristr($row['Extra'],'auto_increment') )
  380. $columns[$name]['auto_increment'] = '1';
  381. if ($row['Null'] == 'NO' && !stristr($row['Key'],'PRI'))
  382. $columns[$name]['required'] = 'true';
  383. if (!empty($row['Default']) )
  384. $columns[$name]['default'] = $row['Default'];
  385. }
  386. return $columns;
  387. }
  388. /**
  389. * @see DBHelper::add_drop_constraint()
  390. */
  391. public function add_drop_constraint(
  392. $table,
  393. $definition,
  394. $drop = false
  395. )
  396. {
  397. $type = $definition['type'];
  398. $fields = implode(',',$definition['fields']);
  399. $name = $definition['name'];
  400. $foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
  401. $sql = '';
  402. switch ($type){
  403. // generic indices
  404. case 'index':
  405. case 'alternate_key':
  406. if ($drop)
  407. $sql = "DROP INDEX {$name} ";
  408. else
  409. $sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
  410. break;
  411. // constraints as indices
  412. case 'unique':
  413. if ($drop)
  414. $sql = "ALTER TABLE {$table} DROP INDEX $name";
  415. else
  416. $sql = "ALTER TABLE {$table} ADD CONSTRAINT UNIQUE {$name} ({$fields})";
  417. break;
  418. case 'primary':
  419. if ($drop)
  420. $sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
  421. else
  422. $sql = "ALTER TABLE {$table} ADD CONSTRAINT PRIMARY KEY ({$fields})";
  423. break;
  424. case 'foreign':
  425. if ($drop)
  426. $sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
  427. else
  428. $sql = "ALTER TABLE {$table} ADD CONSTRAINT FOREIGN KEY {$name} ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
  429. break;
  430. }
  431. return $sql;
  432. }
  433. /**
  434. * @see DBHelper::number_of_columns()
  435. */
  436. public function number_of_columns(
  437. $table_name
  438. )
  439. {
  440. $result = $this->db->query("DESCRIBE $table_name");
  441. return ($this->db->getRowCount($result));
  442. }
  443. /**
  444. * @see DBHelper::full_text_indexing_enabled()
  445. */
  446. protected function full_text_indexing_enabled(
  447. $dbname = null
  448. )
  449. {
  450. return $this->isEngineEnabled('MyISAM');
  451. }
  452. /**
  453. * @see DBHelper::massageFieldDef()
  454. */
  455. public function massageFieldDef(
  456. &$fieldDef,
  457. $tablename
  458. )
  459. {
  460. DBHelper::massageFieldDef($fieldDef,$tablename);
  461. if ( isset($fieldDef['default']) &&
  462. ($fieldDef['dbType'] == 'text'
  463. || $fieldDef['dbType'] == 'blob'
  464. || $fieldDef['dbType'] == 'longtext'
  465. || $fieldDef['dbType'] == 'longblob' ))
  466. unset($fieldDef['default']);
  467. if ($fieldDef['dbType'] == 'uint')
  468. $fieldDef['len'] = '10';
  469. if ($fieldDef['dbType'] == 'ulong')
  470. $fieldDef['len'] = '20';
  471. if ($fieldDef['dbType'] == 'bool')
  472. $fieldDef['type'] = 'tinyint';
  473. if ($fieldDef['dbType'] == 'bool' && empty($fieldDef['default']) )
  474. $fieldDef['default'] = '0';
  475. if (($fieldDef['dbType'] == 'varchar' || $fieldDef['dbType'] == 'enum') && empty($fieldDef['len']) )
  476. $fieldDef['len'] = '255';
  477. if ($fieldDef['dbType'] == 'uint')
  478. $fieldDef['len'] = '10';
  479. if ($fieldDef['dbType'] == 'int' && empty($fieldDef['len']) )
  480. $fieldDef['len'] = '11';
  481. }
  482. }
  483. ?>