OraclePlatform.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the LGPL. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\DBAL\Platforms;
  20. use Doctrine\DBAL\Schema\TableDiff;
  21. /**
  22. * OraclePlatform.
  23. *
  24. * @since 2.0
  25. * @author Roman Borschel <roman@code-factory.org>
  26. * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
  27. * @author Benjamin Eberlei <kontakt@beberlei.de>
  28. */
  29. class OraclePlatform extends AbstractPlatform
  30. {
  31. /**
  32. * return string to call a function to get a substring inside an SQL statement
  33. *
  34. * Note: Not SQL92, but common functionality.
  35. *
  36. * @param string $value an sql string literal or column name/alias
  37. * @param integer $position where to start the substring portion
  38. * @param integer $length the substring portion length
  39. * @return string SQL substring function with given parameters
  40. * @override
  41. */
  42. public function getSubstringExpression($value, $position, $length = null)
  43. {
  44. if ($length !== null) {
  45. return "SUBSTR($value, $position, $length)";
  46. }
  47. return "SUBSTR($value, $position)";
  48. }
  49. /**
  50. * Return string to call a variable with the current timestamp inside an SQL statement
  51. * There are three special variables for current date and time:
  52. * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
  53. * - CURRENT_DATE (date, DATE type)
  54. * - CURRENT_TIME (time, TIME type)
  55. *
  56. * @return string to call a variable with the current timestamp
  57. * @override
  58. */
  59. public function getNowExpression($type = 'timestamp')
  60. {
  61. switch ($type) {
  62. case 'date':
  63. case 'time':
  64. case 'timestamp':
  65. default:
  66. return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
  67. }
  68. }
  69. /**
  70. * returns the position of the first occurrence of substring $substr in string $str
  71. *
  72. * @param string $substr literal string to find
  73. * @param string $str literal string
  74. * @param int $pos position to start at, beginning of string by default
  75. * @return integer
  76. */
  77. public function getLocateExpression($str, $substr, $startPos = false)
  78. {
  79. if ($startPos == false) {
  80. return 'INSTR('.$str.', '.$substr.')';
  81. } else {
  82. return 'INSTR('.$str.', '.$substr.', '.$startPos.')';
  83. }
  84. }
  85. /**
  86. * Returns global unique identifier
  87. *
  88. * @return string to get global unique identifier
  89. * @override
  90. */
  91. public function getGuidExpression()
  92. {
  93. return 'SYS_GUID()';
  94. }
  95. /**
  96. * Get the number of days difference between two dates.
  97. *
  98. * Note: Since Oracle timestamp differences are calculated down to the microsecond we have to truncate
  99. * them to the difference in days. This is obviously a restriction of the original functionality, but we
  100. * need to make this a portable function.
  101. *
  102. * @param type $date1
  103. * @param type $date2
  104. * @return type
  105. */
  106. public function getDateDiffExpression($date1, $date2)
  107. {
  108. return "TRUNC(TO_NUMBER(SUBSTR((" . $date1 . "-" . $date2 . "), 1, INSTR(" . $date1 . "-" . $date2 .", ' '))))";
  109. }
  110. /**
  111. * {@inheritdoc}
  112. */
  113. public function getDateAddDaysExpression($date, $days)
  114. {
  115. return '(' . $date . '+' . $days . ')';
  116. }
  117. /**
  118. * {@inheritdoc}
  119. */
  120. public function getDateSubDaysExpression($date, $days)
  121. {
  122. return '(' . $date . '-' . $days . ')';
  123. }
  124. /**
  125. * {@inheritdoc}
  126. */
  127. public function getDateAddMonthExpression($date, $months)
  128. {
  129. return "ADD_MONTHS(" . $date . ", " . $months . ")";
  130. }
  131. /**
  132. * {@inheritdoc}
  133. */
  134. public function getDateSubMonthExpression($date, $months)
  135. {
  136. return "ADD_MONTHS(" . $date . ", -" . $months . ")";
  137. }
  138. /**
  139. * {@inheritdoc}
  140. */
  141. public function getBitAndComparisonExpression($value1, $value2)
  142. {
  143. return 'BITAND('.$value1 . ', ' . $value2 . ')';
  144. }
  145. /**
  146. * {@inheritdoc}
  147. */
  148. public function getBitOrComparisonExpression($value1, $value2)
  149. {
  150. return '(' . $value1 . '-' .
  151. $this->getBitAndComparisonExpression($value1, $value2)
  152. . '+' . $value2 . ')';
  153. }
  154. /**
  155. * Gets the SQL used to create a sequence that starts with a given value
  156. * and increments by the given allocation size.
  157. *
  158. * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH.
  159. * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection
  160. * in {@see listSequences()}
  161. *
  162. * @param \Doctrine\DBAL\Schema\Sequence $sequence
  163. * @return string
  164. */
  165. public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
  166. {
  167. return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
  168. ' START WITH ' . $sequence->getInitialValue() .
  169. ' MINVALUE ' . $sequence->getInitialValue() .
  170. ' INCREMENT BY ' . $sequence->getAllocationSize();
  171. }
  172. public function getAlterSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
  173. {
  174. return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) .
  175. ' INCREMENT BY ' . $sequence->getAllocationSize();
  176. }
  177. /**
  178. * {@inheritdoc}
  179. *
  180. * @param string $sequenceName
  181. * @override
  182. */
  183. public function getSequenceNextValSQL($sequenceName)
  184. {
  185. return 'SELECT ' . $sequenceName . '.nextval FROM DUAL';
  186. }
  187. /**
  188. * {@inheritdoc}
  189. *
  190. * @param integer $level
  191. * @override
  192. */
  193. public function getSetTransactionIsolationSQL($level)
  194. {
  195. return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
  196. }
  197. protected function _getTransactionIsolationLevelSQL($level)
  198. {
  199. switch ($level) {
  200. case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED:
  201. return 'READ UNCOMMITTED';
  202. case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED:
  203. return 'READ COMMITTED';
  204. case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ:
  205. case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE:
  206. return 'SERIALIZABLE';
  207. default:
  208. return parent::_getTransactionIsolationLevelSQL($level);
  209. }
  210. }
  211. /**
  212. * @override
  213. */
  214. public function getBooleanTypeDeclarationSQL(array $field)
  215. {
  216. return 'NUMBER(1)';
  217. }
  218. /**
  219. * @override
  220. */
  221. public function getIntegerTypeDeclarationSQL(array $field)
  222. {
  223. return 'NUMBER(10)';
  224. }
  225. /**
  226. * @override
  227. */
  228. public function getBigIntTypeDeclarationSQL(array $field)
  229. {
  230. return 'NUMBER(20)';
  231. }
  232. /**
  233. * @override
  234. */
  235. public function getSmallIntTypeDeclarationSQL(array $field)
  236. {
  237. return 'NUMBER(5)';
  238. }
  239. /**
  240. * @override
  241. */
  242. public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
  243. {
  244. return 'TIMESTAMP(0)';
  245. }
  246. /**
  247. * @override
  248. */
  249. public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
  250. {
  251. return 'TIMESTAMP(0) WITH TIME ZONE';
  252. }
  253. /**
  254. * @override
  255. */
  256. public function getDateTypeDeclarationSQL(array $fieldDeclaration)
  257. {
  258. return 'DATE';
  259. }
  260. /**
  261. * @override
  262. */
  263. public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
  264. {
  265. return 'DATE';
  266. }
  267. /**
  268. * @override
  269. */
  270. protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
  271. {
  272. return '';
  273. }
  274. /**
  275. * Gets the SQL snippet used to declare a VARCHAR column on the Oracle platform.
  276. *
  277. * @params array $field
  278. * @override
  279. */
  280. protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
  281. {
  282. return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)')
  283. : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)');
  284. }
  285. /** @override */
  286. public function getClobTypeDeclarationSQL(array $field)
  287. {
  288. return 'CLOB';
  289. }
  290. public function getListDatabasesSQL()
  291. {
  292. return 'SELECT username FROM all_users';
  293. }
  294. public function getListSequencesSQL($database)
  295. {
  296. return "SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ".
  297. "WHERE SEQUENCE_OWNER = '".strtoupper($database)."'";
  298. }
  299. /**
  300. *
  301. * @param string $table
  302. * @param array $columns
  303. * @param array $options
  304. * @return array
  305. */
  306. protected function _getCreateTableSQL($table, array $columns, array $options = array())
  307. {
  308. $indexes = isset($options['indexes']) ? $options['indexes'] : array();
  309. $options['indexes'] = array();
  310. $sql = parent::_getCreateTableSQL($table, $columns, $options);
  311. foreach ($columns as $name => $column) {
  312. if (isset($column['sequence'])) {
  313. $sql[] = $this->getCreateSequenceSQL($column['sequence'], 1);
  314. }
  315. if (isset($column['autoincrement']) && $column['autoincrement'] ||
  316. (isset($column['autoinc']) && $column['autoinc'])) {
  317. $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table));
  318. }
  319. }
  320. if (isset($indexes) && ! empty($indexes)) {
  321. foreach ($indexes as $indexName => $index) {
  322. $sql[] = $this->getCreateIndexSQL($index, $table);
  323. }
  324. }
  325. return $sql;
  326. }
  327. /**
  328. * @license New BSD License
  329. * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html
  330. * @param string $table
  331. * @return string
  332. */
  333. public function getListTableIndexesSQL($table, $currentDatabase = null)
  334. {
  335. $table = strtoupper($table);
  336. return "SELECT uind.index_name AS name, " .
  337. " uind.index_type AS type, " .
  338. " decode( uind.uniqueness, 'NONUNIQUE', 0, 'UNIQUE', 1 ) AS is_unique, " .
  339. " uind_col.column_name AS column_name, " .
  340. " uind_col.column_position AS column_pos, " .
  341. " (SELECT ucon.constraint_type FROM user_constraints ucon WHERE ucon.constraint_name = uind.index_name) AS is_primary ".
  342. "FROM user_indexes uind, user_ind_columns uind_col " .
  343. "WHERE uind.index_name = uind_col.index_name AND uind_col.table_name = '$table' ORDER BY uind_col.column_position ASC";
  344. }
  345. public function getListTablesSQL()
  346. {
  347. return 'SELECT * FROM sys.user_tables';
  348. }
  349. public function getListViewsSQL($database)
  350. {
  351. return 'SELECT view_name, text FROM sys.user_views';
  352. }
  353. public function getCreateViewSQL($name, $sql)
  354. {
  355. return 'CREATE VIEW ' . $name . ' AS ' . $sql;
  356. }
  357. public function getDropViewSQL($name)
  358. {
  359. return 'DROP VIEW '. $name;
  360. }
  361. public function getCreateAutoincrementSql($name, $table, $start = 1)
  362. {
  363. $table = strtoupper($table);
  364. $sql = array();
  365. $indexName = $table . '_AI_PK';
  366. $definition = array(
  367. 'primary' => true,
  368. 'columns' => array($name => true),
  369. );
  370. $idx = new \Doctrine\DBAL\Schema\Index($indexName, array($name), true, true);
  371. $sql[] = 'DECLARE
  372. constraints_Count NUMBER;
  373. BEGIN
  374. SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \''.$table.'\' AND CONSTRAINT_TYPE = \'P\';
  375. IF constraints_Count = 0 OR constraints_Count = \'\' THEN
  376. EXECUTE IMMEDIATE \''.$this->getCreateConstraintSQL($idx, $table).'\';
  377. END IF;
  378. END;';
  379. $sequenceName = $table . '_SEQ';
  380. $sequence = new \Doctrine\DBAL\Schema\Sequence($sequenceName, $start);
  381. $sql[] = $this->getCreateSequenceSQL($sequence);
  382. $triggerName = $table . '_AI_PK';
  383. $sql[] = 'CREATE TRIGGER ' . $triggerName . '
  384. BEFORE INSERT
  385. ON ' . $table . '
  386. FOR EACH ROW
  387. DECLARE
  388. last_Sequence NUMBER;
  389. last_InsertID NUMBER;
  390. BEGIN
  391. SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
  392. IF (:NEW.' . $name . ' IS NULL OR :NEW.'.$name.' = 0) THEN
  393. SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
  394. ELSE
  395. SELECT NVL(Last_Number, 0) INTO last_Sequence
  396. FROM User_Sequences
  397. WHERE Sequence_Name = \'' . $sequenceName . '\';
  398. SELECT :NEW.' . $name . ' INTO last_InsertID FROM DUAL;
  399. WHILE (last_InsertID > last_Sequence) LOOP
  400. SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL;
  401. END LOOP;
  402. END IF;
  403. END;';
  404. return $sql;
  405. }
  406. public function getDropAutoincrementSql($table)
  407. {
  408. $table = strtoupper($table);
  409. $trigger = $table . '_AI_PK';
  410. if ($trigger) {
  411. $sql[] = 'DROP TRIGGER ' . $trigger;
  412. $sql[] = $this->getDropSequenceSQL($table.'_SEQ');
  413. $indexName = $table . '_AI_PK';
  414. $sql[] = $this->getDropConstraintSQL($indexName, $table);
  415. }
  416. return $sql;
  417. }
  418. public function getListTableForeignKeysSQL($table)
  419. {
  420. $table = strtoupper($table);
  421. return "SELECT alc.constraint_name,
  422. alc.DELETE_RULE,
  423. alc.search_condition,
  424. cols.column_name \"local_column\",
  425. cols.position,
  426. r_alc.table_name \"references_table\",
  427. r_cols.column_name \"foreign_column\"
  428. FROM user_cons_columns cols
  429. LEFT JOIN user_constraints alc
  430. ON alc.constraint_name = cols.constraint_name
  431. LEFT JOIN user_constraints r_alc
  432. ON alc.r_constraint_name = r_alc.constraint_name
  433. LEFT JOIN user_cons_columns r_cols
  434. ON r_alc.constraint_name = r_cols.constraint_name
  435. AND cols.position = r_cols.position
  436. WHERE alc.constraint_name = cols.constraint_name
  437. AND alc.constraint_type = 'R'
  438. AND alc.table_name = '".$table."'";
  439. }
  440. public function getListTableConstraintsSQL($table)
  441. {
  442. $table = strtoupper($table);
  443. return 'SELECT * FROM user_constraints WHERE table_name = \'' . $table . '\'';
  444. }
  445. public function getListTableColumnsSQL($table, $database = null)
  446. {
  447. $table = strtoupper($table);
  448. $tabColumnsTableName = "user_tab_columns";
  449. $ownerCondition = '';
  450. if(null !== $database){
  451. $database = strtoupper($database);
  452. $tabColumnsTableName = "all_tab_columns";
  453. $ownerCondition = "AND c.owner = '".$database."'";
  454. }
  455. return "SELECT c.*, d.comments FROM $tabColumnsTableName c ".
  456. "INNER JOIN user_col_comments d ON d.TABLE_NAME = c.TABLE_NAME AND d.COLUMN_NAME = c.COLUMN_NAME ".
  457. "WHERE c.table_name = '" . $table . "' ".$ownerCondition." ORDER BY c.column_name";
  458. }
  459. /**
  460. *
  461. * @param \Doctrine\DBAL\Schema\Sequence $sequence
  462. * @return string
  463. */
  464. public function getDropSequenceSQL($sequence)
  465. {
  466. if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
  467. $sequence = $sequence->getQuotedName($this);
  468. }
  469. return 'DROP SEQUENCE ' . $sequence;
  470. }
  471. /**
  472. * @param ForeignKeyConstraint|string $foreignKey
  473. * @param Table|string $table
  474. * @return string
  475. */
  476. public function getDropForeignKeySQL($foreignKey, $table)
  477. {
  478. if ($foreignKey instanceof \Doctrine\DBAL\Schema\ForeignKeyConstraint) {
  479. $foreignKey = $foreignKey->getQuotedName($this);
  480. }
  481. if ($table instanceof \Doctrine\DBAL\Schema\Table) {
  482. $table = $table->getQuotedName($this);
  483. }
  484. return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey;
  485. }
  486. public function getDropDatabaseSQL($database)
  487. {
  488. return 'DROP USER ' . $database . ' CASCADE';
  489. }
  490. /**
  491. * Gets the sql statements for altering an existing table.
  492. *
  493. * The method returns an array of sql statements, since some platforms need several statements.
  494. *
  495. * @param string $diff->name name of the table that is intended to be changed.
  496. * @param array $changes associative array that contains the details of each type *
  497. * @param boolean $check indicates whether the function should just check if the DBMS driver
  498. * can perform the requested table alterations if the value is true or
  499. * actually perform them otherwise.
  500. * @return array
  501. */
  502. public function getAlterTableSQL(TableDiff $diff)
  503. {
  504. $sql = array();
  505. $commentsSQL = array();
  506. $columnSql = array();
  507. $fields = array();
  508. foreach ($diff->addedColumns AS $column) {
  509. if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
  510. continue;
  511. }
  512. $fields[] = $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
  513. if ($comment = $this->getColumnComment($column)) {
  514. $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
  515. }
  516. }
  517. if (count($fields)) {
  518. $sql[] = 'ALTER TABLE ' . $diff->name . ' ADD (' . implode(', ', $fields) . ')';
  519. }
  520. $fields = array();
  521. foreach ($diff->changedColumns AS $columnDiff) {
  522. if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
  523. continue;
  524. }
  525. $column = $columnDiff->column;
  526. $fields[] = $column->getQuotedName($this). ' ' . $this->getColumnDeclarationSQL('', $column->toArray());
  527. if ($columnDiff->hasChanged('comment') && $comment = $this->getColumnComment($column)) {
  528. $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
  529. }
  530. }
  531. if (count($fields)) {
  532. $sql[] = 'ALTER TABLE ' . $diff->name . ' MODIFY (' . implode(', ', $fields) . ')';
  533. }
  534. foreach ($diff->renamedColumns AS $oldColumnName => $column) {
  535. if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
  536. continue;
  537. }
  538. $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getQuotedName($this);
  539. }
  540. $fields = array();
  541. foreach ($diff->removedColumns AS $column) {
  542. if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
  543. continue;
  544. }
  545. $fields[] = $column->getQuotedName($this);
  546. }
  547. if (count($fields)) {
  548. $sql[] = 'ALTER TABLE ' . $diff->name . ' DROP (' . implode(', ', $fields).')';
  549. }
  550. $tableSql = array();
  551. if (!$this->onSchemaAlterTable($diff, $tableSql)) {
  552. if ($diff->newName !== false) {
  553. $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
  554. }
  555. $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
  556. }
  557. return array_merge($sql, $tableSql, $columnSql);
  558. }
  559. /**
  560. * Whether the platform prefers sequences for ID generation.
  561. *
  562. * @return boolean
  563. */
  564. public function prefersSequences()
  565. {
  566. return true;
  567. }
  568. public function supportsCommentOnStatement()
  569. {
  570. return true;
  571. }
  572. /**
  573. * Get the platform name for this instance
  574. *
  575. * @return string
  576. */
  577. public function getName()
  578. {
  579. return 'oracle';
  580. }
  581. /**
  582. * Adds an driver-specific LIMIT clause to the query
  583. *
  584. * @param string $query query to modify
  585. * @param integer $limit limit the number of rows
  586. * @param integer $offset start reading from given offset
  587. * @return string the modified query
  588. */
  589. protected function doModifyLimitQuery($query, $limit, $offset = null)
  590. {
  591. $limit = (int) $limit;
  592. $offset = (int) $offset;
  593. if (preg_match('/^\s*SELECT/i', $query)) {
  594. if (!preg_match('/\sFROM\s/i', $query)) {
  595. $query .= " FROM dual";
  596. }
  597. if ($limit > 0) {
  598. $max = $offset + $limit;
  599. $column = '*';
  600. if ($offset > 0) {
  601. $min = $offset + 1;
  602. $query = 'SELECT * FROM (SELECT a.' . $column . ', rownum AS doctrine_rownum FROM (' .
  603. $query .
  604. ') a WHERE rownum <= ' . $max . ') WHERE doctrine_rownum >= ' . $min;
  605. } else {
  606. $query = 'SELECT a.' . $column . ' FROM (' . $query . ') a WHERE ROWNUM <= ' . $max;
  607. }
  608. }
  609. }
  610. return $query;
  611. }
  612. /**
  613. * Gets the character casing of a column in an SQL result set of this platform.
  614. *
  615. * Oracle returns all column names in SQL result sets in uppercase.
  616. *
  617. * @param string $column The column name for which to get the correct character casing.
  618. * @return string The column name in the character casing used in SQL result sets.
  619. */
  620. public function getSQLResultCasing($column)
  621. {
  622. return strtoupper($column);
  623. }
  624. public function getCreateTemporaryTableSnippetSQL()
  625. {
  626. return "CREATE GLOBAL TEMPORARY TABLE";
  627. }
  628. public function getDateTimeTzFormatString()
  629. {
  630. return 'Y-m-d H:i:sP';
  631. }
  632. public function getDateFormatString()
  633. {
  634. return 'Y-m-d 00:00:00';
  635. }
  636. public function getTimeFormatString()
  637. {
  638. return '1900-01-01 H:i:s';
  639. }
  640. public function fixSchemaElementName($schemaElementName)
  641. {
  642. if (strlen($schemaElementName) > 30) {
  643. // Trim it
  644. return substr($schemaElementName, 0, 30);
  645. }
  646. return $schemaElementName;
  647. }
  648. /**
  649. * Maximum length of any given databse identifier, like tables or column names.
  650. *
  651. * @return int
  652. */
  653. public function getMaxIdentifierLength()
  654. {
  655. return 30;
  656. }
  657. /**
  658. * Whether the platform supports sequences.
  659. *
  660. * @return boolean
  661. */
  662. public function supportsSequences()
  663. {
  664. return true;
  665. }
  666. public function supportsForeignKeyOnUpdate()
  667. {
  668. return false;
  669. }
  670. /**
  671. * Whether the platform supports releasing savepoints.
  672. *
  673. * @return boolean
  674. */
  675. public function supportsReleaseSavepoints()
  676. {
  677. return false;
  678. }
  679. /**
  680. * @inheritdoc
  681. */
  682. public function getTruncateTableSQL($tableName, $cascade = false)
  683. {
  684. return 'TRUNCATE TABLE '.$tableName;
  685. }
  686. /**
  687. * This is for test reasons, many vendors have special requirements for dummy statements.
  688. *
  689. * @return string
  690. */
  691. public function getDummySelectSQL()
  692. {
  693. return 'SELECT 1 FROM DUAL';
  694. }
  695. protected function initializeDoctrineTypeMappings()
  696. {
  697. $this->doctrineTypeMapping = array(
  698. 'integer' => 'integer',
  699. 'number' => 'integer',
  700. 'pls_integer' => 'boolean',
  701. 'binary_integer' => 'boolean',
  702. 'varchar' => 'string',
  703. 'varchar2' => 'string',
  704. 'nvarchar2' => 'string',
  705. 'char' => 'string',
  706. 'nchar' => 'string',
  707. 'date' => 'datetime',
  708. 'timestamp' => 'datetime',
  709. 'timestamptz' => 'datetimetz',
  710. 'float' => 'float',
  711. 'long' => 'string',
  712. 'clob' => 'text',
  713. 'nclob' => 'text',
  714. 'raw' => 'text',
  715. 'long raw' => 'text',
  716. 'rowid' => 'string',
  717. 'urowid' => 'string',
  718. 'blob' => 'blob',
  719. );
  720. }
  721. /**
  722. * Generate SQL to release a savepoint
  723. *
  724. * @param string $savepoint
  725. * @return string
  726. */
  727. public function releaseSavePoint($savepoint)
  728. {
  729. return '';
  730. }
  731. protected function getReservedKeywordsClass()
  732. {
  733. return 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords';
  734. }
  735. /**
  736. * Gets the SQL Snippet used to declare a BLOB column type.
  737. */
  738. public function getBlobTypeDeclarationSQL(array $field)
  739. {
  740. return 'BLOB';
  741. }
  742. }