Common.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  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 |
  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. // | Author: Lukas Smith <smith@pooteeweet.org> |
  43. // +----------------------------------------------------------------------+
  44. //
  45. // $Id$
  46. //
  47. /**
  48. * @package MDB2
  49. * @category Database
  50. */
  51. /**
  52. * These are constants for the tableInfo-function
  53. * they are bitwised or'ed. so if there are more constants to be defined
  54. * in the future, adjust MDB2_TABLEINFO_FULL accordingly
  55. */
  56. define('MDB2_TABLEINFO_ORDER', 1);
  57. define('MDB2_TABLEINFO_ORDERTABLE', 2);
  58. define('MDB2_TABLEINFO_FULL', 3);
  59. /**
  60. * Base class for the schema reverse engineering module that is extended by each MDB2 driver
  61. *
  62. * To load this module in the MDB2 object:
  63. * $mdb->loadModule('Reverse');
  64. *
  65. * @package MDB2
  66. * @category Database
  67. * @author Lukas Smith <smith@pooteeweet.org>
  68. */
  69. class MDB2_Driver_Reverse_Common extends MDB2_Module_Common
  70. {
  71. // {{{ splitTableSchema()
  72. /**
  73. * Split the "[owner|schema].table" notation into an array
  74. *
  75. * @param string $table [schema and] table name
  76. *
  77. * @return array array(schema, table)
  78. * @access private
  79. */
  80. function splitTableSchema($table)
  81. {
  82. $ret = array();
  83. if (strpos($table, '.') !== false) {
  84. return explode('.', $table);
  85. }
  86. return array(null, $table);
  87. }
  88. // }}}
  89. // {{{ getTableFieldDefinition()
  90. /**
  91. * Get the structure of a field into an array
  92. *
  93. * @param string $table name of table that should be used in method
  94. * @param string $field name of field that should be used in method
  95. * @return mixed data array on success, a MDB2 error on failure.
  96. * The returned array contains an array for each field definition,
  97. * with all or some of these indices, depending on the field data type:
  98. * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
  99. * @access public
  100. */
  101. function getTableFieldDefinition($table, $field)
  102. {
  103. $db = $this->getDBInstance();
  104. if (MDB2::isError($db)) {
  105. return $db;
  106. }
  107. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  108. 'method not implemented', __FUNCTION__);
  109. }
  110. // }}}
  111. // {{{ getTableIndexDefinition()
  112. /**
  113. * Get the structure of an index into an array
  114. *
  115. * @param string $table name of table that should be used in method
  116. * @param string $index name of index that should be used in method
  117. * @return mixed data array on success, a MDB2 error on failure
  118. * The returned array has this structure:
  119. * </pre>
  120. * array (
  121. * [fields] => array (
  122. * [field1name] => array() // one entry per each field covered
  123. * [field2name] => array() // by the index
  124. * [field3name] => array(
  125. * [sorting] => ascending
  126. * )
  127. * )
  128. * );
  129. * </pre>
  130. * @access public
  131. */
  132. function getTableIndexDefinition($table, $index)
  133. {
  134. $db = $this->getDBInstance();
  135. if (MDB2::isError($db)) {
  136. return $db;
  137. }
  138. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  139. 'method not implemented', __FUNCTION__);
  140. }
  141. // }}}
  142. // {{{ getTableConstraintDefinition()
  143. /**
  144. * Get the structure of an constraints into an array
  145. *
  146. * @param string $table name of table that should be used in method
  147. * @param string $index name of index that should be used in method
  148. * @return mixed data array on success, a MDB2 error on failure
  149. * The returned array has this structure:
  150. * <pre>
  151. * array (
  152. * [primary] => 0
  153. * [unique] => 0
  154. * [foreign] => 1
  155. * [check] => 0
  156. * [fields] => array (
  157. * [field1name] => array() // one entry per each field covered
  158. * [field2name] => array() // by the index
  159. * [field3name] => array(
  160. * [sorting] => ascending
  161. * [position] => 3
  162. * )
  163. * )
  164. * [references] => array(
  165. * [table] => name
  166. * [fields] => array(
  167. * [field1name] => array( //one entry per each referenced field
  168. * [position] => 1
  169. * )
  170. * )
  171. * )
  172. * [deferrable] => 0
  173. * [initiallydeferred] => 0
  174. * [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
  175. * [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
  176. * [match] => SIMPLE|PARTIAL|FULL
  177. * );
  178. * </pre>
  179. * @access public
  180. */
  181. function getTableConstraintDefinition($table, $index)
  182. {
  183. $db = $this->getDBInstance();
  184. if (MDB2::isError($db)) {
  185. return $db;
  186. }
  187. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  188. 'method not implemented', __FUNCTION__);
  189. }
  190. // }}}
  191. // {{{ getSequenceDefinition()
  192. /**
  193. * Get the structure of a sequence into an array
  194. *
  195. * @param string $sequence name of sequence that should be used in method
  196. * @return mixed data array on success, a MDB2 error on failure
  197. * The returned array has this structure:
  198. * <pre>
  199. * array (
  200. * [start] => n
  201. * );
  202. * </pre>
  203. * @access public
  204. */
  205. function getSequenceDefinition($sequence)
  206. {
  207. $db = $this->getDBInstance();
  208. if (MDB2::isError($db)) {
  209. return $db;
  210. }
  211. $start = $db->currId($sequence);
  212. if (MDB2::isError($start)) {
  213. return $start;
  214. }
  215. if ($db->supports('current_id')) {
  216. $start++;
  217. } else {
  218. $db->warnings[] = 'database does not support getting current
  219. sequence value, the sequence value was incremented';
  220. }
  221. $definition = array();
  222. if ($start != 1) {
  223. $definition = array('start' => $start);
  224. }
  225. return $definition;
  226. }
  227. // }}}
  228. // {{{ getTriggerDefinition()
  229. /**
  230. * Get the structure of a trigger into an array
  231. *
  232. * EXPERIMENTAL
  233. *
  234. * WARNING: this function is experimental and may change the returned value
  235. * at any time until labelled as non-experimental
  236. *
  237. * @param string $trigger name of trigger that should be used in method
  238. * @return mixed data array on success, a MDB2 error on failure
  239. * The returned array has this structure:
  240. * <pre>
  241. * array (
  242. * [trigger_name] => 'trigger name',
  243. * [table_name] => 'table name',
  244. * [trigger_body] => 'trigger body definition',
  245. * [trigger_type] => 'BEFORE' | 'AFTER',
  246. * [trigger_event] => 'INSERT' | 'UPDATE' | 'DELETE'
  247. * //or comma separated list of multiple events, when supported
  248. * [trigger_enabled] => true|false
  249. * [trigger_comment] => 'trigger comment',
  250. * );
  251. * </pre>
  252. * The oci8 driver also returns a [when_clause] index.
  253. * @access public
  254. */
  255. function getTriggerDefinition($trigger)
  256. {
  257. $db = $this->getDBInstance();
  258. if (MDB2::isError($db)) {
  259. return $db;
  260. }
  261. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  262. 'method not implemented', __FUNCTION__);
  263. }
  264. // }}}
  265. // {{{ tableInfo()
  266. /**
  267. * Returns information about a table or a result set
  268. *
  269. * The format of the resulting array depends on which <var>$mode</var>
  270. * you select. The sample output below is based on this query:
  271. * <pre>
  272. * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
  273. * FROM tblFoo
  274. * JOIN tblBar ON tblFoo.fldId = tblBar.fldId
  275. * </pre>
  276. *
  277. * <ul>
  278. * <li>
  279. *
  280. * <kbd>null</kbd> (default)
  281. * <pre>
  282. * [0] => Array (
  283. * [table] => tblFoo
  284. * [name] => fldId
  285. * [type] => int
  286. * [len] => 11
  287. * [flags] => primary_key not_null
  288. * )
  289. * [1] => Array (
  290. * [table] => tblFoo
  291. * [name] => fldPhone
  292. * [type] => string
  293. * [len] => 20
  294. * [flags] =>
  295. * )
  296. * [2] => Array (
  297. * [table] => tblBar
  298. * [name] => fldId
  299. * [type] => int
  300. * [len] => 11
  301. * [flags] => primary_key not_null
  302. * )
  303. * </pre>
  304. *
  305. * </li><li>
  306. *
  307. * <kbd>MDB2_TABLEINFO_ORDER</kbd>
  308. *
  309. * <p>In addition to the information found in the default output,
  310. * a notation of the number of columns is provided by the
  311. * <samp>num_fields</samp> element while the <samp>order</samp>
  312. * element provides an array with the column names as the keys and
  313. * their location index number (corresponding to the keys in the
  314. * the default output) as the values.</p>
  315. *
  316. * <p>If a result set has identical field names, the last one is
  317. * used.</p>
  318. *
  319. * <pre>
  320. * [num_fields] => 3
  321. * [order] => Array (
  322. * [fldId] => 2
  323. * [fldTrans] => 1
  324. * )
  325. * </pre>
  326. *
  327. * </li><li>
  328. *
  329. * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>
  330. *
  331. * <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> but adds more
  332. * dimensions to the array in which the table names are keys and
  333. * the field names are sub-keys. This is helpful for queries that
  334. * join tables which have identical field names.</p>
  335. *
  336. * <pre>
  337. * [num_fields] => 3
  338. * [ordertable] => Array (
  339. * [tblFoo] => Array (
  340. * [fldId] => 0
  341. * [fldPhone] => 1
  342. * )
  343. * [tblBar] => Array (
  344. * [fldId] => 2
  345. * )
  346. * )
  347. * </pre>
  348. *
  349. * </li>
  350. * </ul>
  351. *
  352. * The <samp>flags</samp> element contains a space separated list
  353. * of extra information about the field. This data is inconsistent
  354. * between DBMS's due to the way each DBMS works.
  355. * + <samp>primary_key</samp>
  356. * + <samp>unique_key</samp>
  357. * + <samp>multiple_key</samp>
  358. * + <samp>not_null</samp>
  359. *
  360. * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
  361. * elements if <var>$result</var> is a table name. The following DBMS's
  362. * provide full information from queries:
  363. * + fbsql
  364. * + mysql
  365. *
  366. * If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp>
  367. * turned on, the names of tables and fields will be lower or upper cased.
  368. *
  369. * @param object|string $result MDB2_result object from a query or a
  370. * string containing the name of a table.
  371. * While this also accepts a query result
  372. * resource identifier, this behavior is
  373. * deprecated.
  374. * @param int $mode either unused or one of the tableInfo modes:
  375. * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>,
  376. * <kbd>MDB2_TABLEINFO_ORDER</kbd> or
  377. * <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both).
  378. * These are bitwise, so the first two can be
  379. * combined using <kbd>|</kbd>.
  380. *
  381. * @return array an associative array with the information requested.
  382. * A MDB2_Error object on failure.
  383. *
  384. * @see MDB2_Driver_Common::setOption()
  385. */
  386. function tableInfo($result, $mode = null)
  387. {
  388. $db = $this->getDBInstance();
  389. if (MDB2::isError($db)) {
  390. return $db;
  391. }
  392. if (!is_string($result)) {
  393. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  394. 'method not implemented', __FUNCTION__);
  395. }
  396. $db->loadModule('Manager', null, true);
  397. $fields = $db->manager->listTableFields($result);
  398. if (MDB2::isError($fields)) {
  399. return $fields;
  400. }
  401. $flags = array();
  402. $idxname_format = $db->getOption('idxname_format');
  403. $db->setOption('idxname_format', '%s');
  404. $indexes = $db->manager->listTableIndexes($result);
  405. if (MDB2::isError($indexes)) {
  406. $db->setOption('idxname_format', $idxname_format);
  407. return $indexes;
  408. }
  409. foreach ($indexes as $index) {
  410. $definition = $this->getTableIndexDefinition($result, $index);
  411. if (MDB2::isError($definition)) {
  412. $db->setOption('idxname_format', $idxname_format);
  413. return $definition;
  414. }
  415. if (count($definition['fields']) > 1) {
  416. foreach ($definition['fields'] as $field => $sort) {
  417. $flags[$field] = 'multiple_key';
  418. }
  419. }
  420. }
  421. $constraints = $db->manager->listTableConstraints($result);
  422. if (MDB2::isError($constraints)) {
  423. return $constraints;
  424. }
  425. foreach ($constraints as $constraint) {
  426. $definition = $this->getTableConstraintDefinition($result, $constraint);
  427. if (MDB2::isError($definition)) {
  428. $db->setOption('idxname_format', $idxname_format);
  429. return $definition;
  430. }
  431. $flag = !empty($definition['primary'])
  432. ? 'primary_key' : (!empty($definition['unique'])
  433. ? 'unique_key' : false);
  434. if ($flag) {
  435. foreach ($definition['fields'] as $field => $sort) {
  436. if (empty($flags[$field]) || $flags[$field] != 'primary_key') {
  437. $flags[$field] = $flag;
  438. }
  439. }
  440. }
  441. }
  442. $res = array();
  443. if ($mode) {
  444. $res['num_fields'] = count($fields);
  445. }
  446. foreach ($fields as $i => $field) {
  447. $definition = $this->getTableFieldDefinition($result, $field);
  448. if (MDB2::isError($definition)) {
  449. $db->setOption('idxname_format', $idxname_format);
  450. return $definition;
  451. }
  452. $res[$i] = $definition[0];
  453. $res[$i]['name'] = $field;
  454. $res[$i]['table'] = $result;
  455. $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype']));
  456. // 'primary_key', 'unique_key', 'multiple_key'
  457. $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field];
  458. // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]'
  459. if (!empty($res[$i]['notnull'])) {
  460. $res[$i]['flags'].= ' not_null';
  461. }
  462. if (!empty($res[$i]['unsigned'])) {
  463. $res[$i]['flags'].= ' unsigned';
  464. }
  465. if (!empty($res[$i]['auto_increment'])) {
  466. $res[$i]['flags'].= ' autoincrement';
  467. }
  468. if (!empty($res[$i]['default'])) {
  469. $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']);
  470. }
  471. if ($mode & MDB2_TABLEINFO_ORDER) {
  472. $res['order'][$res[$i]['name']] = $i;
  473. }
  474. if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
  475. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  476. }
  477. }
  478. $db->setOption('idxname_format', $idxname_format);
  479. return $res;
  480. }
  481. }
  482. ?>