PageRenderTime 104ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/generator/lib/platform/PgsqlPlatform.php

https://github.com/homer6/Propel
PHP | 467 lines | 352 code | 48 blank | 67 comment | 47 complexity | c8657957ef23dd46334ead01cab1fc5c 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. * Postgresql PropelPlatformInterface implementation.
  12. *
  13. * @author Hans Lellelid <hans@xmpl.org> (Propel)
  14. * @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
  15. * @author Niklas Närhinen <niklas@narhinen.net>
  16. * @version $Revision$
  17. * @package propel.generator.platform
  18. */
  19. class PgsqlPlatform extends DefaultPlatform
  20. {
  21. /**
  22. * Initializes db specific domain mapping.
  23. */
  24. protected function initialize()
  25. {
  26. parent::initialize();
  27. $this->setSchemaDomainMapping(new Domain(PropelTypes::BOOLEAN, "BOOLEAN"));
  28. $this->setSchemaDomainMapping(new Domain(PropelTypes::TINYINT, "INT2"));
  29. $this->setSchemaDomainMapping(new Domain(PropelTypes::SMALLINT, "INT2"));
  30. $this->setSchemaDomainMapping(new Domain(PropelTypes::BIGINT, "INT8"));
  31. $this->setSchemaDomainMapping(new Domain(PropelTypes::REAL, "FLOAT"));
  32. $this->setSchemaDomainMapping(new Domain(PropelTypes::DOUBLE, "DOUBLE PRECISION"));
  33. $this->setSchemaDomainMapping(new Domain(PropelTypes::FLOAT, "DOUBLE PRECISION"));
  34. $this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "TEXT"));
  35. $this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "BYTEA"));
  36. $this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "BYTEA"));
  37. $this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "BYTEA"));
  38. $this->setSchemaDomainMapping(new Domain(PropelTypes::BLOB, "BYTEA"));
  39. $this->setSchemaDomainMapping(new Domain(PropelTypes::CLOB, "TEXT"));
  40. $this->setSchemaDomainMapping(new Domain(PropelTypes::OBJECT, "TEXT"));
  41. $this->setSchemaDomainMapping(new Domain(PropelTypes::PHP_ARRAY, "TEXT"));
  42. $this->setSchemaDomainMapping(new Domain(PropelTypes::ENUM, "INT2"));
  43. }
  44. public function getNativeIdMethod()
  45. {
  46. return PropelPlatformInterface::SERIAL;
  47. }
  48. public function getAutoIncrement()
  49. {
  50. return '';
  51. }
  52. public function getMaxColumnNameLength()
  53. {
  54. return 32;
  55. }
  56. /**
  57. * Escape the string for RDBMS.
  58. * @param string $text
  59. * @return string
  60. */
  61. public function disconnectedEscapeText($text)
  62. {
  63. if (function_exists('pg_escape_string')) {
  64. return pg_escape_string($text);
  65. } else {
  66. return parent::disconnectedEscapeText($text);
  67. }
  68. }
  69. public function getBooleanString($b)
  70. {
  71. // parent method does the checking for allowes tring
  72. // representations & returns integer
  73. $b = parent::getBooleanString($b);
  74. return ($b ? "'t'" : "'f'");
  75. }
  76. public function supportsNativeDeleteTrigger()
  77. {
  78. return true;
  79. }
  80. /**
  81. * Override to provide sequence names that conform to postgres' standard when
  82. * no id-method-parameter specified.
  83. *
  84. * @param Table $table
  85. *
  86. * @return string
  87. */
  88. public function getSequenceName(Table $table)
  89. {
  90. static $longNamesMap = array();
  91. $result = null;
  92. if ($table->getIdMethod() == IDMethod::NATIVE) {
  93. $idMethodParams = $table->getIdMethodParameters();
  94. if (empty($idMethodParams)) {
  95. $result = null;
  96. // We're going to ignore a check for max length (mainly
  97. // because I'm not sure how Postgres would handle this w/ SERIAL anyway)
  98. foreach ($table->getColumns() as $col) {
  99. if ($col->isAutoIncrement()) {
  100. $result = $table->getName() . '_' . $col->getName() . '_seq';
  101. break; // there's only one auto-increment column allowed
  102. }
  103. }
  104. } else {
  105. $result = $idMethodParams[0]->getValue();
  106. }
  107. }
  108. return $result;
  109. }
  110. protected function getAddSequenceDDL(Table $table)
  111. {
  112. if ($table->getIdMethod() == IDMethod::NATIVE
  113. && $table->getIdMethodParameters() != null) {
  114. $pattern = "
  115. CREATE SEQUENCE %s;
  116. ";
  117. return sprintf($pattern,
  118. $this->quoteIdentifier(strtolower($this->getSequenceName($table)))
  119. );
  120. }
  121. }
  122. protected function getDropSequenceDDL(Table $table)
  123. {
  124. if ($table->getIdMethod() == IDMethod::NATIVE
  125. && $table->getIdMethodParameters() != null) {
  126. $pattern = "
  127. DROP SEQUENCE %s;
  128. ";
  129. return sprintf($pattern,
  130. $this->quoteIdentifier(strtolower($this->getSequenceName($table)))
  131. );
  132. }
  133. }
  134. public function getAddSchemasDDL(Database $database)
  135. {
  136. $ret = '';
  137. $schemas = array();
  138. foreach ($database->getTables() as $table) {
  139. $vi = $table->getVendorInfoForType('pgsql');
  140. if ($vi->hasParameter('schema') && !isset($schemas[$vi->getParameter('schema')])) {
  141. $schemas[$vi->getParameter('schema')] = true;
  142. $ret .= $this->getAddSchemaDDL($table);
  143. }
  144. }
  145. return $ret;
  146. }
  147. public function getAddSchemaDDL(Table $table)
  148. {
  149. $vi = $table->getVendorInfoForType('pgsql');
  150. if ($vi->hasParameter('schema')) {
  151. $pattern = "
  152. CREATE SCHEMA %s;
  153. ";
  154. return sprintf($pattern, $this->quoteIdentifier($vi->getParameter('schema')));
  155. };
  156. }
  157. public function getUseSchemaDDL(Table $table)
  158. {
  159. $vi = $table->getVendorInfoForType('pgsql');
  160. if ($vi->hasParameter('schema')) {
  161. $pattern = "
  162. SET search_path TO %s;
  163. ";
  164. return sprintf($pattern, $this->quoteIdentifier($vi->getParameter('schema')));
  165. }
  166. }
  167. public function getResetSchemaDDL(Table $table)
  168. {
  169. $vi = $table->getVendorInfoForType('pgsql');
  170. if ($vi->hasParameter('schema')) {
  171. return "
  172. SET search_path TO public;
  173. ";
  174. }
  175. }
  176. public function getAddTablesDDL(Database $database)
  177. {
  178. $ret = $this->getBeginDDL();
  179. $ret .= $this->getAddSchemasDDL($database);
  180. foreach ($database->getTablesForSql() as $table) {
  181. $ret .= $this->getCommentBlockDDL($table->getName());
  182. $ret .= $this->getDropTableDDL($table);
  183. $ret .= $this->getAddTableDDL($table);
  184. $ret .= $this->getAddIndicesDDL($table);
  185. }
  186. foreach ($database->getTablesForSql() as $table) {
  187. $ret .= $this->getAddForeignKeysDDL($table);
  188. }
  189. $ret .= $this->getEndDDL();
  190. return $ret;
  191. }
  192. public function getAddTableDDL(Table $table)
  193. {
  194. $ret = '';
  195. $ret .= $this->getUseSchemaDDL($table);
  196. $ret .= $this->getAddSequenceDDL($table);
  197. $lines = array();
  198. foreach ($table->getColumns() as $column) {
  199. $lines[] = $this->getColumnDDL($column);
  200. }
  201. if ($table->hasPrimaryKey()) {
  202. $lines[] = $this->getPrimaryKeyDDL($table);
  203. }
  204. foreach ($table->getUnices() as $unique) {
  205. $lines[] = $this->getUniqueDDL($unique);
  206. }
  207. $sep = ",
  208. ";
  209. $pattern = "
  210. CREATE TABLE %s
  211. (
  212. %s
  213. );
  214. ";
  215. $ret .= sprintf($pattern,
  216. $this->quoteIdentifier($table->getName()),
  217. implode($sep, $lines)
  218. );
  219. if ($table->hasDescription()) {
  220. $pattern = "
  221. COMMENT ON TABLE %s IS %s;
  222. ";
  223. $ret .= sprintf($pattern,
  224. $this->quoteIdentifier($table->getName()),
  225. $this->quote($table->getDescription())
  226. );
  227. }
  228. $ret .= $this->getAddColumnsComments($table);
  229. $ret .= $this->getResetSchemaDDL($table);
  230. return $ret;
  231. }
  232. protected function getAddColumnsComments(Table $table)
  233. {
  234. $ret = '';
  235. foreach ($table->getColumns() as $column) {
  236. $ret .= $this->getAddColumnComment($column);
  237. }
  238. return $ret;
  239. }
  240. protected function getAddColumnComment(Column $column)
  241. {
  242. $pattern = "
  243. COMMENT ON COLUMN %s.%s IS %s;
  244. ";
  245. if ($description = $column->getDescription()) {
  246. return sprintf($pattern,
  247. $this->quoteIdentifier($column->getTable()->getName()),
  248. $this->quoteIdentifier($column->getName()),
  249. $this->quote($description)
  250. );
  251. }
  252. }
  253. public function getDropTableDDL(Table $table)
  254. {
  255. $ret = '';
  256. $ret .= $this->getUseSchemaDDL($table);
  257. $pattern = "
  258. DROP TABLE %s CASCADE;
  259. ";
  260. $ret .= sprintf($pattern, $this->quoteIdentifier($table->getName()));
  261. $ret .= $this->getDropSequenceDDL($table);
  262. $ret .= $this->getResetSchemaDDL($table);
  263. return $ret;
  264. }
  265. public function getPrimaryKeyName(Table $table)
  266. {
  267. $tableName = $table->getName();
  268. return $tableName . '_pkey';
  269. }
  270. public function getColumnDDL(Column $col)
  271. {
  272. $domain = $col->getDomain();
  273. $ddl = array($this->quoteIdentifier($col->getName()));
  274. $sqlType = $domain->getSqlType();
  275. $table = $col->getTable();
  276. if ($col->isAutoIncrement() && $table && $table->getIdMethodParameters() == null) {
  277. $sqlType = $col->getType() === PropelTypes::BIGINT ? 'bigserial' : 'serial';
  278. }
  279. if ($this->hasSize($sqlType) && $col->isDefaultSqlType($this)) {
  280. $ddl []= $sqlType . $domain->printSize();
  281. } else {
  282. $ddl []= $sqlType;
  283. }
  284. if ($default = $this->getColumnDefaultValueDDL($col)) {
  285. $ddl []= $default;
  286. }
  287. if ($notNull = $this->getNullString($col->isNotNull())) {
  288. $ddl []= $notNull;
  289. }
  290. if ($autoIncrement = $col->getAutoIncrementString()) {
  291. $ddl []= $autoIncrement;
  292. }
  293. return implode(' ', $ddl);
  294. }
  295. public function getUniqueDDL(Unique $unique)
  296. {
  297. return sprintf('CONSTRAINT %s UNIQUE (%s)',
  298. $this->quoteIdentifier($unique->getName()),
  299. $this->getColumnListDDL($unique->getColumns())
  300. );
  301. }
  302. /**
  303. * @see Platform::supportsSchemas()
  304. */
  305. public function supportsSchemas()
  306. {
  307. return true;
  308. }
  309. public function hasSize($sqlType)
  310. {
  311. return !("BYTEA" == $sqlType || "TEXT" == $sqlType || "DOUBLE PRECISION" == $sqlType);
  312. }
  313. public function hasStreamBlobImpl()
  314. {
  315. return true;
  316. }
  317. public function supportsVarcharWithoutSize()
  318. {
  319. return true;
  320. }
  321. /**
  322. * Overrides the implementation from DefaultPlatform
  323. *
  324. * @author Niklas Närhinen <niklas@narhinen.net>
  325. * @return string
  326. * @see DefaultPlatform::getModifyColumnDDL
  327. */
  328. public function getModifyColumnDDL(PropelColumnDiff $columnDiff)
  329. {
  330. $ret = '';
  331. $changedProperties = $columnDiff->getChangedProperties();
  332. $toColumn = $columnDiff->getToColumn();
  333. $table = $toColumn->getTable();
  334. $colName = $this->quoteIdentifier($toColumn->getName());
  335. $pattern = "
  336. ALTER TABLE %s ALTER COLUMN %s;
  337. ";
  338. foreach ($changedProperties as $key => $property) {
  339. switch ($key) {
  340. case 'defaultValueType':
  341. continue;
  342. case 'size':
  343. case 'type':
  344. case 'scale':
  345. $sqlType = $toColumn->getDomain()->getSqlType();
  346. if ($toColumn->isAutoIncrement() && $table && $table->getIdMethodParameters() == null) {
  347. $sqlType = $toColumn->getType() === PropelTypes::BIGINT ? 'bigserial' : 'serial';
  348. }
  349. if ($this->hasSize($sqlType)) {
  350. $sqlType .= $toColumn->getDomain()->printSize();
  351. }
  352. $ret .= sprintf($pattern, $this->quoteIdentifier($table->getName()), $colName . ' TYPE ' . $sqlType);
  353. break;
  354. case 'defaultValueValue':
  355. $ret .= sprintf($pattern, $this->quoteIdentifier($table->getName()), $colName . ' SET ' . $this->getColumnDefaultValueDDL($toColumn));
  356. break;
  357. case 'notNull':
  358. $notNull = " DROP NOT NULL";
  359. if ($property[1]) {
  360. $notNull = " SET NOT NULL";
  361. }
  362. $ret .= sprintf($pattern, $this->quoteIdentifier($table->getName()), $colName . $notNull);
  363. break;
  364. }
  365. }
  366. return $ret;
  367. }
  368. /**
  369. * Overrides the implementation from DefaultPlatform
  370. *
  371. * @author Niklas Närhinen <niklas@narhinen.net>
  372. * @return string
  373. * @see DefaultPlatform::getModifyColumnsDDL
  374. */
  375. public function getModifyColumnsDDL($columnDiffs)
  376. {
  377. $ret = '';
  378. foreach ($columnDiffs as $columnDiff) {
  379. $ret .= $this->getModifyColumnDDL($columnDiff);
  380. }
  381. return $ret;
  382. }
  383. /**
  384. * Overrides the implementation from DefaultPlatform
  385. *
  386. * @author Niklas Närhinen <niklas@narhinen.net>
  387. * @return string
  388. * @see DefaultPlatform::getAddColumnsDLL
  389. */
  390. public function getAddColumnsDDL($columns)
  391. {
  392. $ret = '';
  393. foreach ($columns as $column) {
  394. $ret .= $this->getAddColumnDDL($column);
  395. }
  396. return $ret;
  397. }
  398. /**
  399. * Overrides the implementation from DefaultPlatform
  400. *
  401. * @author Niklas Närhinen <niklas@narhinen.net>
  402. * @return string
  403. * @see DefaultPlatform::getDropIndexDDL
  404. */
  405. public function getDropIndexDDL(Index $index)
  406. {
  407. if ($index instanceof Unique) {
  408. $pattern = "
  409. ALTER TABLE %s DROP CONSTRAINT %s;
  410. ";
  411. return sprintf($pattern,
  412. $this->quoteIdentifier($index->getTable()->getName()),
  413. $this->quoteIdentifier($index->getName())
  414. );
  415. } else {
  416. return parent::getDropIndexDDL($index);
  417. }
  418. }
  419. }