PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/generator/lib/platform/MysqlPlatform.php

https://github.com/1989gaurav/Propel
PHP | 609 lines | 425 code | 61 blank | 123 comment | 54 complexity | 25c934ef02f133db2c234c2a0483142b MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. require_once dirname(__FILE__) . '/DefaultPlatform.php';
  10. /**
  11. * MySql PropelPlatformInterface implementation.
  12. *
  13. * @author Hans Lellelid <hans@xmpl.org> (Propel)
  14. * @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
  15. * @version $Revision$
  16. * @package propel.generator.platform
  17. */
  18. class MysqlPlatform extends DefaultPlatform
  19. {
  20. protected $tableEngineKeyword = 'ENGINE'; // overwritten in build.properties
  21. protected $defaultTableEngine = 'MyISAM'; // overwritten in build.properties
  22. /**
  23. * Initializes db specific domain mapping.
  24. */
  25. protected function initialize()
  26. {
  27. parent::initialize();
  28. $this->setSchemaDomainMapping(new Domain(PropelTypes::BOOLEAN, "TINYINT", 1));
  29. $this->setSchemaDomainMapping(new Domain(PropelTypes::NUMERIC, "DECIMAL"));
  30. $this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "TEXT"));
  31. $this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "BLOB"));
  32. $this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "MEDIUMBLOB"));
  33. $this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "LONGBLOB"));
  34. $this->setSchemaDomainMapping(new Domain(PropelTypes::BLOB, "LONGBLOB"));
  35. $this->setSchemaDomainMapping(new Domain(PropelTypes::CLOB, "LONGTEXT"));
  36. $this->setSchemaDomainMapping(new Domain(PropelTypes::TIMESTAMP, "DATETIME"));
  37. $this->setSchemaDomainMapping(new Domain(PropelTypes::OBJECT, "TEXT"));
  38. $this->setSchemaDomainMapping(new Domain(PropelTypes::PHP_ARRAY, "TEXT"));
  39. $this->setSchemaDomainMapping(new Domain(PropelTypes::ENUM, "TINYINT"));
  40. }
  41. public function setGeneratorConfig(GeneratorConfig $generatorConfig)
  42. {
  43. if ($defaultTableEngine = $generatorConfig->getBuildProperty('mysqlTableType')) {
  44. $this->defaultTableEngine = $defaultTableEngine;
  45. }
  46. if ($tableEngineKeyword = $generatorConfig->getBuildProperty('mysqlTableEngineKeyword')) {
  47. $this->tableEngineKeyword = $tableEngineKeyword;
  48. }
  49. }
  50. /**
  51. * Setter for the tableEngineKeyword property
  52. *
  53. * @param string $tableEngineKeyword
  54. */
  55. function setTableEngineKeyword($tableEngineKeyword)
  56. {
  57. $this->tableEngineKeyword = $tableEngineKeyword;
  58. }
  59. /**
  60. * Getter for the tableEngineKeyword property
  61. *
  62. * @return string
  63. */
  64. function getTableEngineKeyword()
  65. {
  66. return $this->tableEngineKeyword;
  67. }
  68. /**
  69. * Setter for the defaultTableEngine property
  70. *
  71. * @param string $defaultTableEngine
  72. */
  73. function setDefaultTableEngine($defaultTableEngine)
  74. {
  75. $this->defaultTableEngine = $defaultTableEngine;
  76. }
  77. /**
  78. * Getter for the defaultTableEngine property
  79. *
  80. * @return string
  81. */
  82. function getDefaultTableEngine()
  83. {
  84. return $this->defaultTableEngine;
  85. }
  86. public function getAutoIncrement()
  87. {
  88. return "AUTO_INCREMENT";
  89. }
  90. public function getMaxColumnNameLength()
  91. {
  92. return 64;
  93. }
  94. public function supportsNativeDeleteTrigger()
  95. {
  96. return strtolower($this->getDefaultTableEngine()) == 'innodb';
  97. }
  98. public function getAddTablesDDL(Database $database)
  99. {
  100. $ret = $this->getBeginDDL();
  101. foreach ($database->getTablesForSql() as $table) {
  102. $ret .= $this->getCommentBlockDDL($table->getName());
  103. $ret .= $this->getDropTableDDL($table);
  104. $ret .= $this->getAddTableDDL($table);
  105. }
  106. $ret .= $this->getEndDDL();
  107. return $ret;
  108. }
  109. public function getBeginDDL()
  110. {
  111. return "
  112. # This is a fix for InnoDB in MySQL >= 4.1.x
  113. # It \"suspends judgement\" for fkey relationships until are tables are set.
  114. SET FOREIGN_KEY_CHECKS = 0;
  115. ";
  116. }
  117. public function getEndDDL()
  118. {
  119. return "
  120. # This restores the fkey checks, after having unset them earlier
  121. SET FOREIGN_KEY_CHECKS = 1;
  122. ";
  123. }
  124. public function getAddTableDDL(Table $table)
  125. {
  126. $lines = array();
  127. foreach ($table->getColumns() as $column) {
  128. $lines[] = $this->getColumnDDL($column);
  129. }
  130. if ($table->hasPrimaryKey()) {
  131. $lines[] = $this->getPrimaryKeyDDL($table);
  132. }
  133. foreach ($table->getUnices() as $unique) {
  134. $lines[] = $this->getUniqueDDL($unique);
  135. }
  136. foreach ($table->getIndices() as $index ) {
  137. $lines[] = $this->getIndexDDL($index);
  138. }
  139. foreach ($table->getForeignKeys() as $foreignKey) {
  140. if ($foreignKey->isSkipSql()) {
  141. continue;
  142. }
  143. $lines[] = str_replace("
  144. ", "
  145. ", $this->getForeignKeyDDL($foreignKey));
  146. }
  147. $vendorSpecific = $table->getVendorInfoForType('mysql');
  148. if ($vendorSpecific->hasParameter('Type')) {
  149. $mysqlTableType = $vendorSpecific->getParameter('Type');
  150. } elseif ($vendorSpecific->hasParameter('Engine')) {
  151. $mysqlTableType = $vendorSpecific->getParameter('Engine');
  152. } else {
  153. $mysqlTableType = $this->getDefaultTableEngine();
  154. }
  155. $tableOptions = $this->getTableOptions($table);
  156. if ($table->getDescription()) {
  157. $tableOptions []= 'COMMENT=' . $this->quote($table->getDescription());
  158. }
  159. $tableOptions = $tableOptions ? ' ' . implode(' ', $tableOptions) : '';
  160. $sep = ",
  161. ";
  162. $pattern = "
  163. CREATE TABLE %s
  164. (
  165. %s
  166. ) %s=%s%s;
  167. ";
  168. return sprintf($pattern,
  169. $this->quoteIdentifier($table->getName()),
  170. implode($sep, $lines),
  171. $this->getTableEngineKeyword(),
  172. $mysqlTableType,
  173. $tableOptions
  174. );
  175. }
  176. protected function getTableOptions(Table $table)
  177. {
  178. $dbVI = $table->getDatabase()->getVendorInfoForType('mysql');
  179. $tableVI = $table->getVendorInfoForType('mysql');
  180. $vi = $dbVI->getMergedVendorInfo($tableVI);
  181. $tableOptions = array();
  182. // List of supported table options
  183. // see http://dev.mysql.com/doc/refman/5.5/en/create-table.html
  184. $supportedOptions = array(
  185. 'AutoIncrement' => 'AUTO_INCREMENT',
  186. 'AvgRowLength' => 'AVG_ROW_LENGTH',
  187. 'Charset' => 'CHARACTER SET',
  188. 'Checksum' => 'CHECKSUM',
  189. 'Collate' => 'COLLATE',
  190. 'Connection' => 'CONNECTION',
  191. 'DataDirectory' => 'DATA DIRECTORY',
  192. 'Delay_key_write' => 'DELAY_KEY_WRITE',
  193. 'DelayKeyWrite' => 'DELAY_KEY_WRITE',
  194. 'IndexDirectory' => 'INDEX DIRECTORY',
  195. 'InsertMethod' => 'INSERT_METHOD',
  196. 'KeyBlockSize' => 'KEY_BLOCK_SIZE',
  197. 'MaxRows' => 'MAX_ROWS',
  198. 'MinRows' => 'MIN_ROWS',
  199. 'Pack_Keys' => 'PACK_KEYS',
  200. 'PackKeys' => 'PACK_KEYS',
  201. 'RowFormat' => 'ROW_FORMAT',
  202. 'Union' => 'UNION',
  203. );
  204. foreach ($supportedOptions as $name => $sqlName) {
  205. if ($vi->hasParameter($name)) {
  206. $tableOptions []= sprintf('%s=%s',
  207. $sqlName,
  208. $this->quote($vi->getParameter($name))
  209. );
  210. } elseif ($vi->hasParameter($sqlName)) {
  211. $tableOptions []= sprintf('%s=%s',
  212. $sqlName,
  213. $this->quote($vi->getParameter($sqlName))
  214. );
  215. }
  216. }
  217. return $tableOptions;
  218. }
  219. public function getDropTableDDL(Table $table)
  220. {
  221. return "
  222. DROP TABLE IF EXISTS " . $this->quoteIdentifier($table->getName()) . ";
  223. ";
  224. }
  225. public function getColumnDDL(Column $col)
  226. {
  227. $domain = $col->getDomain();
  228. $sqlType = $domain->getSqlType();
  229. $notNullString = $this->getNullString($col->isNotNull());
  230. $defaultSetting = $this->getColumnDefaultValueDDL($col);
  231. // Special handling of TIMESTAMP/DATETIME types ...
  232. // See: http://propel.phpdb.org/trac/ticket/538
  233. if ($sqlType == 'DATETIME') {
  234. $def = $domain->getDefaultValue();
  235. if ($def && $def->isExpression()) { // DATETIME values can only have constant expressions
  236. $sqlType = 'TIMESTAMP';
  237. }
  238. } elseif ($sqlType == 'DATE') {
  239. $def = $domain->getDefaultValue();
  240. if ($def && $def->isExpression()) {
  241. throw new EngineException("DATE columns cannot have default *expressions* in MySQL.");
  242. }
  243. } elseif ($sqlType == 'TEXT' || $sqlType == 'BLOB') {
  244. if ($domain->getDefaultValue()) {
  245. throw new EngineException("BLOB and TEXT columns cannot have DEFAULT values. in MySQL.");
  246. }
  247. }
  248. $ddl = array($this->quoteIdentifier($col->getName()));
  249. if ($this->hasSize($sqlType) && $col->isDefaultSqlType($this)) {
  250. $ddl []= $sqlType . $domain->printSize();
  251. } else {
  252. $ddl []= $sqlType;
  253. }
  254. $colinfo = $col->getVendorInfoForType($this->getDatabaseType());
  255. if ($colinfo->hasParameter('Charset')) {
  256. $ddl []= 'CHARACTER SET '. $this->quote($colinfo->getParameter('Charset'));
  257. }
  258. if ($colinfo->hasParameter('Collation')) {
  259. $ddl []= 'COLLATE '. $this->quote($colinfo->getParameter('Collation'));
  260. } elseif ($colinfo->hasParameter('Collate')) {
  261. $ddl []= 'COLLATE '. $this->quote($colinfo->getParameter('Collate'));
  262. }
  263. if ($sqlType == 'TIMESTAMP') {
  264. if ($notNullString == '') {
  265. $notNullString = 'NULL';
  266. }
  267. if ($defaultSetting == '' && $notNullString == 'NOT NULL') {
  268. $defaultSetting = 'DEFAULT CURRENT_TIMESTAMP';
  269. }
  270. if ($notNullString) {
  271. $ddl []= $notNullString;
  272. }
  273. if ($defaultSetting) {
  274. $ddl []= $defaultSetting;
  275. }
  276. } else {
  277. if ($defaultSetting) {
  278. $ddl []= $defaultSetting;
  279. }
  280. if ($notNullString) {
  281. $ddl []= $notNullString;
  282. }
  283. }
  284. if ($autoIncrement = $col->getAutoIncrementString()) {
  285. $ddl []= $autoIncrement;
  286. }
  287. if ($col->getDescription()) {
  288. $ddl []= 'COMMENT ' . $this->quote($col->getDescription());
  289. }
  290. return implode(' ', $ddl);
  291. }
  292. /**
  293. * Creates a comma-separated list of column names for the index.
  294. * For MySQL unique indexes there is the option of specifying size, so we cannot simply use
  295. * the getColumnsList() method.
  296. * @param Index $index
  297. * @return string
  298. */
  299. protected function getIndexColumnListDDL(Index $index)
  300. {
  301. $list = array();
  302. foreach ($index->getColumns() as $col) {
  303. $list[] = $this->quoteIdentifier($col) . ($index->hasColumnSize($col) ? '(' . $index->getColumnSize($col) . ')' : '');
  304. }
  305. return implode(', ', $list);
  306. }
  307. /**
  308. * Builds the DDL SQL to drop the primary key of a table.
  309. *
  310. * @param Table $table
  311. * @return string
  312. */
  313. public function getDropPrimaryKeyDDL(Table $table)
  314. {
  315. $pattern = "
  316. ALTER TABLE %s DROP PRIMARY KEY;
  317. ";
  318. return sprintf($pattern,
  319. $this->quoteIdentifier($table->getName())
  320. );
  321. }
  322. /**
  323. * Builds the DDL SQL to add an Index.
  324. *
  325. * @param Index $index
  326. * @return string
  327. */
  328. public function getAddIndexDDL(Index $index)
  329. {
  330. $pattern = "
  331. CREATE %sINDEX %s ON %s (%s);
  332. ";
  333. return sprintf($pattern,
  334. $this->getIndexType($index),
  335. $this->quoteIdentifier($index->getName()),
  336. $this->quoteIdentifier($index->getTable()->getName()),
  337. $this->getColumnListDDL($index->getColumns())
  338. );
  339. }
  340. /**
  341. * Builds the DDL SQL to drop an Index.
  342. *
  343. * @param Index $index
  344. * @return string
  345. */
  346. public function getDropIndexDDL(Index $index)
  347. {
  348. $pattern = "
  349. DROP INDEX %s ON %s;
  350. ";
  351. return sprintf($pattern,
  352. $this->quoteIdentifier($index->getName()),
  353. $this->quoteIdentifier($index->getTable()->getName())
  354. );
  355. }
  356. /**
  357. * Builds the DDL SQL for an Index object.
  358. * @return string
  359. */
  360. public function getIndexDDL(Index $index)
  361. {
  362. return sprintf('%sINDEX %s (%s)',
  363. $this->getIndexType($index),
  364. $this->quoteIdentifier($index->getName()),
  365. $this->getIndexColumnListDDL($index)
  366. );
  367. }
  368. protected function getIndexType(Index $index)
  369. {
  370. $type = '';
  371. $vendorInfo = $index->getVendorInfoForType($this->getDatabaseType());
  372. if ($vendorInfo && $vendorInfo->getParameter('Index_type')) {
  373. $type = $vendorInfo->getParameter('Index_type') . ' ';
  374. } elseif ($index->getIsUnique()) {
  375. $type = 'UNIQUE ';
  376. }
  377. return $type;
  378. }
  379. public function getUniqueDDL(Unique $unique)
  380. {
  381. return sprintf('UNIQUE INDEX %s (%s)',
  382. $this->quoteIdentifier($unique->getName()),
  383. $this->getIndexColumnListDDL($unique)
  384. );
  385. }
  386. public function getDropForeignKeyDDL(ForeignKey $fk)
  387. {
  388. if ($fk->isSkipSql()) {
  389. return;
  390. }
  391. $pattern = "
  392. ALTER TABLE %s DROP FOREIGN KEY %s;
  393. ";
  394. return sprintf($pattern,
  395. $this->quoteIdentifier($fk->getTable()->getName()),
  396. $this->quoteIdentifier($fk->getName())
  397. );
  398. }
  399. public function getCommentBlockDDL($comment)
  400. {
  401. $pattern = "
  402. -- ---------------------------------------------------------------------
  403. -- %s
  404. -- ---------------------------------------------------------------------
  405. ";
  406. return sprintf($pattern, $comment);
  407. }
  408. /**
  409. * Builds the DDL SQL to modify a database
  410. * based on a PropelDatabaseDiff instance
  411. *
  412. * @return string
  413. */
  414. public function getModifyDatabaseDDL(PropelDatabaseDiff $databaseDiff)
  415. {
  416. $ret = $this->getBeginDDL();
  417. foreach ($databaseDiff->getRemovedTables() as $table) {
  418. $ret .= $this->getDropTableDDL($table);
  419. }
  420. foreach ($databaseDiff->getRenamedTables() as $fromTableName => $toTableName) {
  421. $ret .= $this->getRenameTableDDL($fromTableName, $toTableName);
  422. }
  423. foreach ($databaseDiff->getModifiedTables() as $tableDiff) {
  424. $ret .= $this->getModifyTableDDL($tableDiff);
  425. }
  426. foreach ($databaseDiff->getAddedTables() as $table) {
  427. $ret .= $this->getAddTableDDL($table);
  428. }
  429. $ret .= $this->getEndDDL();
  430. return $ret;
  431. }
  432. /**
  433. * Builds the DDL SQL to rename a table
  434. * @return string
  435. */
  436. public function getRenameTableDDL($fromTableName, $toTableName)
  437. {
  438. $pattern = "
  439. RENAME TABLE %s TO %s;
  440. ";
  441. return sprintf($pattern,
  442. $this->quoteIdentifier($fromTableName),
  443. $this->quoteIdentifier($toTableName)
  444. );
  445. }
  446. /**
  447. * Builds the DDL SQL to remove a column
  448. *
  449. * @return string
  450. */
  451. public function getRemoveColumnDDL(Column $column)
  452. {
  453. $pattern = "
  454. ALTER TABLE %s DROP %s;
  455. ";
  456. return sprintf($pattern,
  457. $this->quoteIdentifier($column->getTable()->getName()),
  458. $this->quoteIdentifier($column->getName())
  459. );
  460. }
  461. /**
  462. * Builds the DDL SQL to rename a column
  463. * @return string
  464. */
  465. public function getRenameColumnDDL($fromColumn, $toColumn)
  466. {
  467. return $this->getChangeColumnDDL($fromColumn, $toColumn);
  468. }
  469. /**
  470. * Builds the DDL SQL to modify a column
  471. *
  472. * @return string
  473. */
  474. public function getModifyColumnDDL(PropelColumnDiff $columnDiff)
  475. {
  476. return $this->getChangeColumnDDL($columnDiff->getFromColumn(), $columnDiff->getToColumn());
  477. }
  478. /**
  479. * Builds the DDL SQL to change a column
  480. * @return string
  481. */
  482. public function getChangeColumnDDL($fromColumn, $toColumn)
  483. {
  484. $pattern = "
  485. ALTER TABLE %s CHANGE %s %s;
  486. ";
  487. return sprintf($pattern,
  488. $this->quoteIdentifier($fromColumn->getTable()->getName()),
  489. $this->quoteIdentifier($fromColumn->getName()),
  490. $this->getColumnDDL($toColumn)
  491. );
  492. }
  493. /**
  494. * Builds the DDL SQL to modify a list of columns
  495. *
  496. * @return string
  497. */
  498. public function getModifyColumnsDDL($columnDiffs)
  499. {
  500. $ret = '';
  501. foreach ($columnDiffs as $columnDiff) {
  502. $ret .= $this->getModifyColumnDDL($columnDiff);
  503. }
  504. return $ret;
  505. }
  506. /**
  507. * @see Platform::supportsSchemas()
  508. */
  509. public function supportsSchemas()
  510. {
  511. return true;
  512. }
  513. public function hasSize($sqlType)
  514. {
  515. return !("MEDIUMTEXT" == $sqlType || "LONGTEXT" == $sqlType
  516. || "BLOB" == $sqlType || "MEDIUMBLOB" == $sqlType
  517. || "LONGBLOB" == $sqlType);
  518. }
  519. /**
  520. * Escape the string for RDBMS.
  521. * @param string $text
  522. * @return string
  523. */
  524. public function disconnectedEscapeText($text)
  525. {
  526. if (function_exists('mysql_escape_string')) {
  527. return mysql_escape_string($text);
  528. } else {
  529. return addslashes($text);
  530. }
  531. }
  532. /**
  533. * MySQL documentation says that identifiers cannot contain '.'. Thus it
  534. * should be safe to split the string by '.' and quote each part individually
  535. * to allow for a <schema>.<table> or <table>.<column> syntax.
  536. *
  537. * @param string $text the identifier
  538. * @return string the quoted identifier
  539. */
  540. public function quoteIdentifier($text)
  541. {
  542. return $this->isIdentifierQuotingEnabled ? '`' . strtr($text, array('.' => '`.`')) . '`' : $text;
  543. }
  544. public function getTimestampFormatter()
  545. {
  546. return 'Y-m-d H:i:s';
  547. }
  548. }