PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/pear/MDB2/Driver/Reverse/oci8.php

https://bitbucket.org/Yason/armory
PHP | 621 lines | 454 code | 37 blank | 130 comment | 94 complexity | a4f3d7a2a8caefa2c03e586df6ddb585 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
  6. // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann, Lorenzo Alberton |
  7. // | All rights reserved. |
  8. // +----------------------------------------------------------------------+
  9. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
  10. // | API as well as database abstraction for PHP applications. |
  11. // | This LICENSE is in the BSD license style. |
  12. // | |
  13. // | Redistribution and use in source and binary forms, with or without |
  14. // | modification, are permitted provided that the following conditions |
  15. // | are met: |
  16. // | |
  17. // | Redistributions of source code must retain the above copyright |
  18. // | notice, this list of conditions and the following disclaimer. |
  19. // | |
  20. // | Redistributions in binary form must reproduce the above copyright |
  21. // | notice, this list of conditions and the following disclaimer in the |
  22. // | documentation and/or other materials provided with the distribution. |
  23. // | |
  24. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
  25. // | Lukas Smith nor the names of his contributors may be used to endorse |
  26. // | or promote products derived from this software without specific prior|
  27. // | written permission. |
  28. // | |
  29. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
  30. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
  31. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
  32. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
  33. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
  34. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36. // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
  37. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  38. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
  40. // | POSSIBILITY OF SUCH DAMAGE. |
  41. // +----------------------------------------------------------------------+
  42. // | Authors: Lukas Smith <smith@pooteeweet.org> |
  43. // | Lorenzo Alberton <l.alberton@quipo.it> |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: oci8.php,v 1.74 2007/11/25 13:38:29 quipo Exp $
  47. //
  48. require_once 'MDB2/Driver/Reverse/Common.php';
  49. /**
  50. * MDB2 Oracle driver for the schema reverse engineering module
  51. *
  52. * @package MDB2
  53. * @category Database
  54. * @author Lukas Smith <smith@dybnet.de>
  55. */
  56. class MDB2_Driver_Reverse_oci8 extends MDB2_Driver_Reverse_Common
  57. {
  58. // {{{ getTableFieldDefinition()
  59. /**
  60. * Get the structure of a field into an array
  61. *
  62. * @param string $table_name name of table that should be used in method
  63. * @param string $field_name name of field that should be used in method
  64. * @return mixed data array on success, a MDB2 error on failure
  65. * @access public
  66. */
  67. function getTableFieldDefinition($table_name, $field_name)
  68. {
  69. $db =& $this->getDBInstance();
  70. if (PEAR::isError($db)) {
  71. return $db;
  72. }
  73. $result = $db->loadModule('Datatype', null, true);
  74. if (PEAR::isError($result)) {
  75. return $result;
  76. }
  77. list($owner, $table) = $this->splitTableSchema($table_name);
  78. if (empty($owner)) {
  79. $owner = $db->dsn['username'];
  80. }
  81. $query = 'SELECT column_name name,
  82. data_type "type",
  83. nullable,
  84. data_default "default",
  85. COALESCE(data_precision, data_length) "length",
  86. data_scale "scale"
  87. FROM all_tab_columns
  88. WHERE (table_name=? OR table_name=?)
  89. AND (owner=? OR owner=?)
  90. AND (column_name=? OR column_name=?)
  91. ORDER BY column_id';
  92. $stmt = $db->prepare($query);
  93. if (PEAR::isError($stmt)) {
  94. return $stmt;
  95. }
  96. $args = array(
  97. $table,
  98. strtoupper($table),
  99. $owner,
  100. strtoupper($owner),
  101. $field_name,
  102. strtoupper($field_name)
  103. );
  104. $result = $stmt->execute($args);
  105. if (PEAR::isError($result)) {
  106. return $result;
  107. }
  108. $column = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
  109. if (PEAR::isError($column)) {
  110. return $column;
  111. }
  112. $stmt->free();
  113. $result->free();
  114. if (empty($column)) {
  115. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  116. $field_name . ' is not a column in table ' . $table_name, __FUNCTION__);
  117. }
  118. $column = array_change_key_case($column, CASE_LOWER);
  119. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  120. if ($db->options['field_case'] == CASE_LOWER) {
  121. $column['name'] = strtolower($column['name']);
  122. } else {
  123. $column['name'] = strtoupper($column['name']);
  124. }
  125. }
  126. $mapped_datatype = $db->datatype->mapNativeDatatype($column);
  127. if (PEAR::isError($mapped_datatype)) {
  128. return $mapped_datatype;
  129. }
  130. list($types, $length, $unsigned, $fixed) = $mapped_datatype;
  131. $notnull = false;
  132. if (!empty($column['nullable']) && $column['nullable'] == 'N') {
  133. $notnull = true;
  134. }
  135. $default = false;
  136. if (array_key_exists('default', $column)) {
  137. $default = $column['default'];
  138. if ($default === 'NULL') {
  139. $default = null;
  140. }
  141. if (is_null($default) && $notnull) {
  142. $default = '';
  143. }
  144. }
  145. $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']);
  146. if (!is_null($length)) {
  147. $definition[0]['length'] = $length;
  148. }
  149. if (!is_null($unsigned)) {
  150. $definition[0]['unsigned'] = $unsigned;
  151. }
  152. if (!is_null($fixed)) {
  153. $definition[0]['fixed'] = $fixed;
  154. }
  155. if ($default !== false) {
  156. $definition[0]['default'] = $default;
  157. }
  158. foreach ($types as $key => $type) {
  159. $definition[$key] = $definition[0];
  160. if ($type == 'clob' || $type == 'blob') {
  161. unset($definition[$key]['default']);
  162. }
  163. $definition[$key]['type'] = $type;
  164. $definition[$key]['mdb2type'] = $type;
  165. }
  166. if ($type == 'integer') {
  167. $query= "SELECT trigger_body
  168. FROM all_triggers
  169. WHERE table_name=?
  170. AND triggering_event='INSERT'
  171. AND trigger_type='BEFORE EACH ROW'";
  172. // ^^ pretty reasonable mimic for "auto_increment" in oracle?
  173. $stmt = $db->prepare($query);
  174. if (PEAR::isError($stmt)) {
  175. return $stmt;
  176. }
  177. $result = $stmt->execute(strtoupper($table));
  178. if (PEAR::isError($result)) {
  179. return $result;
  180. }
  181. while ($triggerstr = $result->fetchOne()) {
  182. if (preg_match('/.*SELECT\W+(.+)\.nextval +into +\:NEW\.'.$field_name.' +FROM +dual/im', $triggerstr, $matches)) {
  183. $definition[0]['autoincrement'] = $matches[1];
  184. }
  185. }
  186. $stmt->free();
  187. $result->free();
  188. }
  189. return $definition;
  190. }
  191. // }}}
  192. // {{{ getTableIndexDefinition()
  193. /**
  194. * Get the structure of an index into an array
  195. *
  196. * @param string $table_name name of table that should be used in method
  197. * @param string $index_name name of index that should be used in method
  198. * @return mixed data array on success, a MDB2 error on failure
  199. * @access public
  200. */
  201. function getTableIndexDefinition($table_name, $index_name)
  202. {
  203. $db =& $this->getDBInstance();
  204. if (PEAR::isError($db)) {
  205. return $db;
  206. }
  207. list($owner, $table) = $this->splitTableSchema($table_name);
  208. if (empty($owner)) {
  209. $owner = $db->dsn['username'];
  210. }
  211. $query = "SELECT aic.column_name,
  212. aic.column_position,
  213. aic.descend,
  214. aic.table_owner,
  215. alc.constraint_type
  216. FROM all_ind_columns aic
  217. LEFT JOIN all_constraints alc
  218. ON aic.index_name = alc.constraint_name
  219. AND aic.table_name = alc.table_name
  220. AND aic.table_owner = alc.owner
  221. WHERE (aic.table_name=? OR aic.table_name=?)
  222. AND (aic.index_name=? OR aic.index_name=?)
  223. AND (aic.table_owner=? OR aic.table_owner=?)
  224. ORDER BY column_position";
  225. $stmt = $db->prepare($query);
  226. if (PEAR::isError($stmt)) {
  227. return $stmt;
  228. }
  229. $indexnames = array_unique(array($db->getIndexName($index_name), $index_name));
  230. $i = 0;
  231. $row = null;
  232. while (is_null($row) && array_key_exists($i, $indexnames)) {
  233. $args = array(
  234. $table,
  235. strtoupper($table),
  236. $indexnames[$i],
  237. strtoupper($indexnames[$i]),
  238. $owner,
  239. strtoupper($owner)
  240. );
  241. $result = $stmt->execute($args);
  242. if (PEAR::isError($result)) {
  243. return $result;
  244. }
  245. $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
  246. if (PEAR::isError($row)) {
  247. return $row;
  248. }
  249. $i++;
  250. }
  251. if (is_null($row)) {
  252. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  253. $index_name. ' is not an index on table '. $table_name, __FUNCTION__);
  254. }
  255. if ($row['constraint_type'] == 'U' || $row['constraint_type'] == 'P') {
  256. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  257. $index_name. ' is a constraint, not an index on table '. $table_name, __FUNCTION__);
  258. }
  259. $definition = array();
  260. while (!is_null($row)) {
  261. $row = array_change_key_case($row, CASE_LOWER);
  262. $column_name = $row['column_name'];
  263. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  264. if ($db->options['field_case'] == CASE_LOWER) {
  265. $column_name = strtolower($column_name);
  266. } else {
  267. $column_name = strtoupper($column_name);
  268. }
  269. }
  270. $definition['fields'][$column_name] = array(
  271. 'position' => (int)$row['column_position'],
  272. );
  273. if (!empty($row['descend'])) {
  274. $definition['fields'][$column_name]['sorting'] =
  275. ($row['descend'] == 'ASC' ? 'ascending' : 'descending');
  276. }
  277. $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
  278. }
  279. $result->free();
  280. if (empty($definition['fields'])) {
  281. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  282. $index_name. ' is not an index on table '. $table_name, __FUNCTION__);
  283. }
  284. return $definition;
  285. }
  286. // }}}
  287. // {{{ getTableConstraintDefinition()
  288. /**
  289. * Get the structure of a constraint into an array
  290. *
  291. * @param string $table_name name of table that should be used in method
  292. * @param string $constraint_name name of constraint that should be used in method
  293. * @return mixed data array on success, a MDB2 error on failure
  294. * @access public
  295. */
  296. function getTableConstraintDefinition($table_name, $constraint_name)
  297. {
  298. $db =& $this->getDBInstance();
  299. if (PEAR::isError($db)) {
  300. return $db;
  301. }
  302. list($owner, $table) = $this->splitTableSchema($table_name);
  303. if (empty($owner)) {
  304. $owner = $db->dsn['username'];
  305. }
  306. $query = 'SELECT alc.constraint_name,
  307. CASE alc.constraint_type WHEN \'P\' THEN 1 ELSE 0 END "primary",
  308. CASE alc.constraint_type WHEN \'R\' THEN 1 ELSE 0 END "foreign",
  309. CASE alc.constraint_type WHEN \'U\' THEN 1 ELSE 0 END "unique",
  310. CASE alc.constraint_type WHEN \'C\' THEN 1 ELSE 0 END "check",
  311. alc.DELETE_RULE "ondelete",
  312. \'NO ACTION\' "onupdate",
  313. \'SIMPLE\' "match",
  314. CASE alc.deferrable WHEN \'NOT DEFERRABLE\' THEN 0 ELSE 1 END "deferrable",
  315. CASE alc.deferred WHEN \'IMMEDIATE\' THEN 0 ELSE 1 END "initiallydeferred",
  316. alc.search_condition,
  317. alc.table_name,
  318. cols.column_name,
  319. cols.position,
  320. r_alc.table_name "references_table",
  321. r_cols.column_name "references_field",
  322. r_cols.position "references_field_position"
  323. FROM all_cons_columns cols
  324. LEFT JOIN all_constraints alc
  325. ON alc.constraint_name = cols.constraint_name
  326. AND alc.owner = cols.owner
  327. LEFT JOIN all_constraints r_alc
  328. ON alc.r_constraint_name = r_alc.constraint_name
  329. AND alc.r_owner = r_alc.owner
  330. LEFT JOIN all_cons_columns r_cols
  331. ON r_alc.constraint_name = r_cols.constraint_name
  332. AND r_alc.owner = r_cols.owner
  333. AND cols.position = r_cols.position
  334. WHERE (alc.constraint_name=? OR alc.constraint_name=?)
  335. AND alc.constraint_name = cols.constraint_name
  336. AND (alc.owner=? OR alc.owner=?)';
  337. $tablenames = array();
  338. if (!empty($table)) {
  339. $query.= ' AND (alc.table_name=? OR alc.table_name=?)';
  340. $tablenames = array($table, strtoupper($table));
  341. }
  342. $stmt = $db->prepare($query);
  343. if (PEAR::isError($stmt)) {
  344. return $stmt;
  345. }
  346. $constraintnames = array_unique(array($db->getIndexName($constraint_name), $constraint_name));
  347. $c = 0;
  348. $row = null;
  349. while (is_null($row) && array_key_exists($c, $constraintnames)) {
  350. $args = array(
  351. $constraintnames[$c],
  352. strtoupper($constraintnames[$c]),
  353. $owner,
  354. strtoupper($owner)
  355. );
  356. if (!empty($table)) {
  357. $args = array_merge($args, $tablenames);
  358. }
  359. $result = $stmt->execute($args);
  360. if (PEAR::isError($result)) {
  361. return $result;
  362. }
  363. $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
  364. if (PEAR::isError($row)) {
  365. return $row;
  366. }
  367. $c++;
  368. }
  369. $definition = array(
  370. 'primary' => (boolean)$row['primary'],
  371. 'unique' => (boolean)$row['unique'],
  372. 'foreign' => (boolean)$row['foreign'],
  373. 'check' => (boolean)$row['check'],
  374. 'deferrable' => (boolean)$row['deferrable'],
  375. 'initiallydeferred' => (boolean)$row['initiallydeferred'],
  376. 'ondelete' => $row['ondelete'],
  377. 'onupdate' => $row['onupdate'],
  378. 'match' => $row['match'],
  379. );
  380. if ($definition['check']) {
  381. // pattern match constraint for check constraint values into enum-style output:
  382. $enumregex = '/'.$row['column_name'].' in \((.+?)\)/i';
  383. if (preg_match($enumregex, $row['search_condition'], $rangestr)) {
  384. $definition['fields'][$column_name] = array();
  385. $allowed = explode(',', $rangestr[1]);
  386. foreach ($allowed as $val) {
  387. $val = trim($val);
  388. $val = preg_replace('/^\'/', '', $val);
  389. $val = preg_replace('/\'$/', '', $val);
  390. array_push($definition['fields'][$column_name], $val);
  391. }
  392. }
  393. }
  394. while (!is_null($row)) {
  395. $row = array_change_key_case($row, CASE_LOWER);
  396. $column_name = $row['column_name'];
  397. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  398. if ($db->options['field_case'] == CASE_LOWER) {
  399. $column_name = strtolower($column_name);
  400. } else {
  401. $column_name = strtoupper($column_name);
  402. }
  403. }
  404. $definition['fields'][$column_name] = array(
  405. 'position' => (int)$row['position']
  406. );
  407. if ($row['foreign']) {
  408. $ref_column_name = $row['references_field'];
  409. $ref_table_name = $row['references_table'];
  410. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  411. if ($db->options['field_case'] == CASE_LOWER) {
  412. $ref_column_name = strtolower($ref_column_name);
  413. $ref_table_name = strtolower($ref_table_name);
  414. } else {
  415. $ref_column_name = strtoupper($ref_column_name);
  416. $ref_table_name = strtoupper($ref_table_name);
  417. }
  418. }
  419. $definition['references']['table'] = $ref_table_name;
  420. $definition['references']['fields'][$ref_column_name] = array(
  421. 'position' => (int)$row['references_field_position']
  422. );
  423. }
  424. $lastrow = $row;
  425. $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
  426. }
  427. $result->free();
  428. if (empty($definition['fields'])) {
  429. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  430. $constraint_name . ' is not a constraint on table '. $table_name, __FUNCTION__);
  431. }
  432. return $definition;
  433. }
  434. // }}}
  435. // {{{ getSequenceDefinition()
  436. /**
  437. * Get the structure of a sequence into an array
  438. *
  439. * @param string $sequence name of sequence that should be used in method
  440. * @return mixed data array on success, a MDB2 error on failure
  441. * @access public
  442. */
  443. function getSequenceDefinition($sequence)
  444. {
  445. $db =& $this->getDBInstance();
  446. if (PEAR::isError($db)) {
  447. return $db;
  448. }
  449. $sequence_name = $db->getSequenceName($sequence);
  450. $query = 'SELECT last_number FROM user_sequences';
  451. $query.= ' WHERE sequence_name='.$db->quote($sequence_name, 'text');
  452. $query.= ' OR sequence_name='.$db->quote(strtoupper($sequence_name), 'text');
  453. $start = $db->queryOne($query, 'integer');
  454. if (PEAR::isError($start)) {
  455. return $start;
  456. }
  457. $definition = array();
  458. if ($start != 1) {
  459. $definition = array('start' => $start);
  460. }
  461. return $definition;
  462. }
  463. // }}}
  464. // {{{ getTriggerDefinition()
  465. /**
  466. * Get the structure of a trigger into an array
  467. *
  468. * EXPERIMENTAL
  469. *
  470. * WARNING: this function is experimental and may change the returned value
  471. * at any time until labelled as non-experimental
  472. *
  473. * @param string $trigger name of trigger that should be used in method
  474. * @return mixed data array on success, a MDB2 error on failure
  475. * @access public
  476. */
  477. function getTriggerDefinition($trigger)
  478. {
  479. $db =& $this->getDBInstance();
  480. if (PEAR::isError($db)) {
  481. return $db;
  482. }
  483. $query = 'SELECT trigger_name,
  484. table_name,
  485. trigger_body,
  486. trigger_type,
  487. triggering_event trigger_event,
  488. description trigger_comment,
  489. 1 trigger_enabled,
  490. when_clause
  491. FROM user_triggers
  492. WHERE trigger_name = \''. strtoupper($trigger).'\'';
  493. $types = array(
  494. 'trigger_name' => 'text',
  495. 'table_name' => 'text',
  496. 'trigger_body' => 'text',
  497. 'trigger_type' => 'text',
  498. 'trigger_event' => 'text',
  499. 'trigger_comment' => 'text',
  500. 'trigger_enabled' => 'boolean',
  501. 'when_clause' => 'text',
  502. );
  503. $result = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
  504. if (PEAR::isError($result)) {
  505. return $result;
  506. }
  507. if (!empty($result['trigger_type'])) {
  508. //$result['trigger_type'] = array_shift(explode(' ', $result['trigger_type']));
  509. $result['trigger_type'] = preg_replace('/(\S+).*/', '\\1', $result['trigger_type']);
  510. }
  511. return $result;
  512. }
  513. // }}}
  514. // {{{ tableInfo()
  515. /**
  516. * Returns information about a table or a result set
  517. *
  518. * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  519. * is a table name.
  520. *
  521. * NOTE: flags won't contain index information.
  522. *
  523. * @param object|string $result MDB2_result object from a query or a
  524. * string containing the name of a table.
  525. * While this also accepts a query result
  526. * resource identifier, this behavior is
  527. * deprecated.
  528. * @param int $mode a valid tableInfo mode
  529. *
  530. * @return array an associative array with the information requested.
  531. * A MDB2_Error object on failure.
  532. *
  533. * @see MDB2_Driver_Common::tableInfo()
  534. */
  535. function tableInfo($result, $mode = null)
  536. {
  537. if (is_string($result)) {
  538. return parent::tableInfo($result, $mode);
  539. }
  540. $db =& $this->getDBInstance();
  541. if (PEAR::isError($db)) {
  542. return $db;
  543. }
  544. $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
  545. if (!is_resource($resource)) {
  546. return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  547. 'Could not generate result resource', __FUNCTION__);
  548. }
  549. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  550. if ($db->options['field_case'] == CASE_LOWER) {
  551. $case_func = 'strtolower';
  552. } else {
  553. $case_func = 'strtoupper';
  554. }
  555. } else {
  556. $case_func = 'strval';
  557. }
  558. $count = @OCINumCols($resource);
  559. $res = array();
  560. if ($mode) {
  561. $res['num_fields'] = $count;
  562. }
  563. $db->loadModule('Datatype', null, true);
  564. for ($i = 0; $i < $count; $i++) {
  565. $column = array(
  566. 'table' => '',
  567. 'name' => $case_func(@OCIColumnName($resource, $i+1)),
  568. 'type' => @OCIColumnType($resource, $i+1),
  569. 'length' => @OCIColumnSize($resource, $i+1),
  570. 'flags' => '',
  571. );
  572. $res[$i] = $column;
  573. $res[$i]['mdb2type'] = $db->datatype->mapNativeDatatype($res[$i]);
  574. if ($mode & MDB2_TABLEINFO_ORDER) {
  575. $res['order'][$res[$i]['name']] = $i;
  576. }
  577. if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
  578. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  579. }
  580. }
  581. return $res;
  582. }
  583. }
  584. ?>