ibase.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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. // | Author: Lorenzo Alberton <l.alberton@quipo.it> |
  43. // +----------------------------------------------------------------------+
  44. //
  45. // $Id$
  46. //
  47. require_once 'MDB2/Driver/Reverse/Common.php';
  48. /**
  49. * MDB2 InterbaseBase driver for the reverse engineering module
  50. *
  51. * @package MDB2
  52. * @category Database
  53. * @author Lorenzo Alberton <l.alberton@quipo.it>
  54. */
  55. class MDB2_Driver_Reverse_ibase extends MDB2_Driver_Reverse_Common
  56. {
  57. /**
  58. * Array for converting constant values to text values
  59. * @var array
  60. * @access public
  61. */
  62. var $types = array(
  63. 7 => 'smallint',
  64. 8 => 'integer',
  65. 9 => 'quad',
  66. 10 => 'float',
  67. 11 => 'd_float',
  68. 12 => 'date', //dialect 3 DATE
  69. 13 => 'time',
  70. 14 => 'char',
  71. 16 => 'int64',
  72. 27 => 'double',
  73. 35 => 'timestamp', //DATE in older versions
  74. 37 => 'varchar',
  75. 40 => 'cstring',
  76. 261 => 'blob',
  77. );
  78. /**
  79. * Array for converting constant values to text values
  80. * @var array
  81. * @access public
  82. */
  83. var $subtypes = array(
  84. //char subtypes
  85. 14 => array(
  86. 0 => 'unspecified',
  87. 1 => 'fixed', //BINARY data
  88. ),
  89. //blob subtypes
  90. 261 => array(
  91. 0 => 'unspecified',
  92. 1 => 'text',
  93. 2 => 'BLR', //Binary Language Representation
  94. 3 => 'access control list',
  95. 4 => 'reserved for future use',
  96. 5 => 'encoded description of a table\'s current metadata',
  97. 6 => 'description of multi-database transaction that finished irregularly',
  98. ),
  99. //smallint subtypes
  100. 7 => array(
  101. 0 => 'RDB$FIELD_TYPE',
  102. 1 => 'numeric',
  103. 2 => 'decimal',
  104. ),
  105. //integer subtypes
  106. 8 => array(
  107. 0 => 'RDB$FIELD_TYPE',
  108. 1 => 'numeric',
  109. 2 => 'decimal',
  110. ),
  111. //int64 subtypes
  112. 16 => array(
  113. 0 => 'RDB$FIELD_TYPE',
  114. 1 => 'numeric',
  115. 2 => 'decimal',
  116. ),
  117. );
  118. // {{{ getTableFieldDefinition()
  119. /**
  120. * Get the structure of a field into an array
  121. *
  122. * @param string $table_name name of table that should be used in method
  123. * @param string $field_name name of field that should be used in method
  124. * @return mixed data array on success, a MDB2 error on failure
  125. * @access public
  126. */
  127. function getTableFieldDefinition($table_name, $field_name)
  128. {
  129. $db = $this->getDBInstance();
  130. if (MDB2::isError($db)) {
  131. return $db;
  132. }
  133. $result = $db->loadModule('Datatype', null, true);
  134. if (MDB2::isError($result)) {
  135. return $result;
  136. }
  137. list($schema, $table) = $this->splitTableSchema($table_name);
  138. $table = $db->quote(strtoupper($table), 'text');
  139. $field_name = $db->quote(strtoupper($field_name), 'text');
  140. $query = "SELECT RDB\$RELATION_FIELDS.RDB\$FIELD_NAME AS name,
  141. RDB\$FIELDS.RDB\$FIELD_LENGTH AS \"length\",
  142. RDB\$FIELDS.RDB\$FIELD_PRECISION AS \"precision\",
  143. (RDB\$FIELDS.RDB\$FIELD_SCALE * -1) AS \"scale\",
  144. RDB\$FIELDS.RDB\$FIELD_TYPE AS field_type_code,
  145. RDB\$FIELDS.RDB\$FIELD_SUB_TYPE AS field_sub_type_code,
  146. RDB\$RELATION_FIELDS.RDB\$DESCRIPTION AS description,
  147. RDB\$RELATION_FIELDS.RDB\$NULL_FLAG AS null_flag,
  148. RDB\$FIELDS.RDB\$DEFAULT_SOURCE AS default_source,
  149. RDB\$CHARACTER_SETS.RDB\$CHARACTER_SET_NAME AS \"charset\",
  150. RDB\$COLLATIONS.RDB\$COLLATION_NAME AS \"collation\"
  151. FROM RDB\$FIELDS
  152. LEFT JOIN RDB\$RELATION_FIELDS ON RDB\$FIELDS.RDB\$FIELD_NAME = RDB\$RELATION_FIELDS.RDB\$FIELD_SOURCE
  153. LEFT JOIN RDB\$CHARACTER_SETS ON RDB\$FIELDS.RDB\$CHARACTER_SET_ID = RDB\$CHARACTER_SETS.RDB\$CHARACTER_SET_ID
  154. LEFT JOIN RDB\$COLLATIONS ON RDB\$FIELDS.RDB\$COLLATION_ID = RDB\$COLLATIONS.RDB\$COLLATION_ID
  155. WHERE UPPER(RDB\$RELATION_FIELDS.RDB\$RELATION_NAME)=$table
  156. AND UPPER(RDB\$RELATION_FIELDS.RDB\$FIELD_NAME)=$field_name;";
  157. $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
  158. if (MDB2::isError($column)) {
  159. return $column;
  160. }
  161. if (empty($column)) {
  162. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  163. 'it was not specified an existing table column', __FUNCTION__);
  164. }
  165. $column = array_change_key_case($column, CASE_LOWER);
  166. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  167. if ($db->options['field_case'] == CASE_LOWER) {
  168. $column['name'] = strtolower($column['name']);
  169. } else {
  170. $column['name'] = strtoupper($column['name']);
  171. }
  172. }
  173. $column['type'] = array_key_exists((int)$column['field_type_code'], $this->types)
  174. ? $this->types[(int)$column['field_type_code']] : 'undefined';
  175. if ($column['field_sub_type_code']
  176. && array_key_exists((int)$column['field_type_code'], $this->subtypes)
  177. && array_key_exists($column['field_sub_type_code'], $this->subtypes[(int)$column['field_type_code']])
  178. ) {
  179. $column['field_sub_type'] = $this->subtypes[(int)$column['field_type_code']][$column['field_sub_type_code']];
  180. } else {
  181. $column['field_sub_type'] = null;
  182. }
  183. $mapped_datatype = $db->datatype->mapNativeDatatype($column);
  184. if (MDB2::isError($mapped_datatype)) {
  185. return $mapped_datatype;
  186. }
  187. list($types, $length, $unsigned, $fixed) = $mapped_datatype;
  188. $notnull = !empty($column['null_flag']);
  189. $default = $column['default_source'];
  190. if ((null === $default) && $notnull) {
  191. $default = ($types[0] == 'integer') ? 0 : '';
  192. }
  193. $definition[0] = array(
  194. 'notnull' => $notnull,
  195. 'nativetype' => $column['type'],
  196. 'charset' => $column['charset'],
  197. 'collation' => $column['collation'],
  198. );
  199. if (null !== $length) {
  200. $definition[0]['length'] = $length;
  201. }
  202. if (null !== $unsigned) {
  203. $definition[0]['unsigned'] = $unsigned;
  204. }
  205. if (null !== $fixed) {
  206. $definition[0]['fixed'] = $fixed;
  207. }
  208. if (false !== $default) {
  209. $definition[0]['default'] = $default;
  210. }
  211. foreach ($types as $key => $type) {
  212. $definition[$key] = $definition[0];
  213. if ($type == 'clob' || $type == 'blob') {
  214. unset($definition[$key]['default']);
  215. }
  216. $definition[$key]['type'] = $type;
  217. $definition[$key]['mdb2type'] = $type;
  218. }
  219. return $definition;
  220. }
  221. // }}}
  222. // {{{ getTableIndexDefinition()
  223. /**
  224. * Get the structure of an index into an array
  225. *
  226. * @param string $table_name name of table that should be used in method
  227. * @param string $index_name name of index that should be used in method
  228. * @return mixed data array on success, a MDB2 error on failure
  229. * @access public
  230. */
  231. function getTableIndexDefinition($table_name, $index_name, $format_index_name = true)
  232. {
  233. $db = $this->getDBInstance();
  234. if (MDB2::isError($db)) {
  235. return $db;
  236. }
  237. list($schema, $table) = $this->splitTableSchema($table_name);
  238. $table = $db->quote(strtoupper($table), 'text');
  239. $query = "SELECT RDB\$INDEX_SEGMENTS.RDB\$FIELD_NAME AS field_name,
  240. RDB\$INDICES.RDB\$DESCRIPTION AS description,
  241. (RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION + 1) AS field_position
  242. FROM RDB\$INDEX_SEGMENTS
  243. LEFT JOIN RDB\$INDICES ON RDB\$INDICES.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
  244. LEFT JOIN RDB\$RELATION_CONSTRAINTS ON RDB\$RELATION_CONSTRAINTS.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
  245. WHERE UPPER(RDB\$INDICES.RDB\$RELATION_NAME)=$table
  246. AND UPPER(RDB\$INDICES.RDB\$INDEX_NAME)=%s
  247. AND RDB\$RELATION_CONSTRAINTS.RDB\$CONSTRAINT_TYPE IS NULL
  248. ORDER BY RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION";
  249. $index_name_mdb2 = $db->quote(strtoupper($db->getIndexName($index_name)), 'text');
  250. $result = $db->queryRow(sprintf($query, $index_name_mdb2));
  251. if (!MDB2::isError($result) && (null !== $result)) {
  252. // apply 'idxname_format' only if the query succeeded, otherwise
  253. // fallback to the given $index_name, without transformation
  254. $index_name = $index_name_mdb2;
  255. } else {
  256. $index_name = $db->quote(strtoupper($index_name), 'text');
  257. }
  258. $result = $db->query(sprintf($query, $index_name));
  259. if (MDB2::isError($result)) {
  260. return $result;
  261. }
  262. $definition = array();
  263. while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
  264. $row = array_change_key_case($row, CASE_LOWER);
  265. $column_name = $row['field_name'];
  266. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  267. if ($db->options['field_case'] == CASE_LOWER) {
  268. $column_name = strtolower($column_name);
  269. } else {
  270. $column_name = strtoupper($column_name);
  271. }
  272. }
  273. $definition['fields'][$column_name] = array(
  274. 'position' => (int)$row['field_position'],
  275. );
  276. /*
  277. if (!empty($row['collation'])) {
  278. $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
  279. ? 'ascending' : 'descending');
  280. }
  281. */
  282. }
  283. $result->free();
  284. if (empty($definition)) {
  285. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  286. 'it was not specified an existing table index', __FUNCTION__);
  287. }
  288. return $definition;
  289. }
  290. // }}}
  291. // {{{ getTableConstraintDefinition()
  292. /**
  293. * Get the structure of a constraint into an array
  294. *
  295. * @param string $table_name name of table that should be used in method
  296. * @param string $constraint_name name of constraint that should be used in method
  297. * @return mixed data array on success, a MDB2 error on failure
  298. * @access public
  299. */
  300. function getTableConstraintDefinition($table_name, $constraint_name)
  301. {
  302. $db = $this->getDBInstance();
  303. if (MDB2::isError($db)) {
  304. return $db;
  305. }
  306. list($schema, $table) = $this->splitTableSchema($table_name);
  307. $table = $db->quote(strtoupper($table), 'text');
  308. $query = "SELECT rc.RDB\$CONSTRAINT_NAME,
  309. s.RDB\$FIELD_NAME AS field_name,
  310. CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'PRIMARY KEY' THEN 1 ELSE 0 END AS \"primary\",
  311. CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'FOREIGN KEY' THEN 1 ELSE 0 END AS \"foreign\",
  312. CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'UNIQUE' THEN 1 ELSE 0 END AS \"unique\",
  313. CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'CHECK' THEN 1 ELSE 0 END AS \"check\",
  314. i.RDB\$DESCRIPTION AS description,
  315. CASE WHEN rc.RDB\$DEFERRABLE = 'NO' THEN 0 ELSE 1 END AS deferrable,
  316. CASE WHEN rc.RDB\$INITIALLY_DEFERRED = 'NO' THEN 0 ELSE 1 END AS initiallydeferred,
  317. refc.RDB\$UPDATE_RULE AS onupdate,
  318. refc.RDB\$DELETE_RULE AS ondelete,
  319. refc.RDB\$MATCH_OPTION AS \"match\",
  320. i2.RDB\$RELATION_NAME AS references_table,
  321. s2.RDB\$FIELD_NAME AS references_field,
  322. (s.RDB\$FIELD_POSITION + 1) AS field_position
  323. FROM RDB\$INDEX_SEGMENTS s
  324. LEFT JOIN RDB\$INDICES i ON i.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
  325. LEFT JOIN RDB\$RELATION_CONSTRAINTS rc ON rc.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
  326. LEFT JOIN RDB\$REF_CONSTRAINTS refc ON rc.RDB\$CONSTRAINT_NAME = refc.RDB\$CONSTRAINT_NAME
  327. LEFT JOIN RDB\$RELATION_CONSTRAINTS rc2 ON rc2.RDB\$CONSTRAINT_NAME = refc.RDB\$CONST_NAME_UQ
  328. LEFT JOIN RDB\$INDICES i2 ON i2.RDB\$INDEX_NAME = rc2.RDB\$INDEX_NAME
  329. LEFT JOIN RDB\$INDEX_SEGMENTS s2 ON i2.RDB\$INDEX_NAME = s2.RDB\$INDEX_NAME
  330. AND s.RDB\$FIELD_POSITION = s2.RDB\$FIELD_POSITION
  331. WHERE UPPER(i.RDB\$RELATION_NAME)=$table
  332. AND UPPER(rc.RDB\$CONSTRAINT_NAME)=%s
  333. AND rc.RDB\$CONSTRAINT_TYPE IS NOT NULL
  334. ORDER BY s.RDB\$FIELD_POSITION";
  335. $constraint_name_mdb2 = $db->quote(strtoupper($db->getIndexName($constraint_name)), 'text');
  336. $result = $db->queryRow(sprintf($query, $constraint_name_mdb2));
  337. if (!MDB2::isError($result) && (null !== $result)) {
  338. // apply 'idxname_format' only if the query succeeded, otherwise
  339. // fallback to the given $index_name, without transformation
  340. $constraint_name = $constraint_name_mdb2;
  341. } else {
  342. $constraint_name = $db->quote(strtoupper($constraint_name), 'text');
  343. }
  344. $result = $db->query(sprintf($query, $constraint_name));
  345. if (MDB2::isError($result)) {
  346. return $result;
  347. }
  348. $definition = array();
  349. while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
  350. $row = array_change_key_case($row, CASE_LOWER);
  351. $column_name = $row['field_name'];
  352. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  353. if ($db->options['field_case'] == CASE_LOWER) {
  354. $column_name = strtolower($column_name);
  355. } else {
  356. $column_name = strtoupper($column_name);
  357. }
  358. }
  359. $definition['fields'][$column_name] = array(
  360. 'position' => (int)$row['field_position']
  361. );
  362. if ($row['foreign']) {
  363. $ref_column_name = $row['references_field'];
  364. $ref_table_name = $row['references_table'];
  365. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  366. if ($db->options['field_case'] == CASE_LOWER) {
  367. $ref_column_name = strtolower($ref_column_name);
  368. $ref_table_name = strtolower($ref_table_name);
  369. } else {
  370. $ref_column_name = strtoupper($ref_column_name);
  371. $ref_table_name = strtoupper($ref_table_name);
  372. }
  373. }
  374. $definition['references']['table'] = $ref_table_name;
  375. $definition['references']['fields'][$ref_column_name] = array(
  376. 'position' => (int)$row['field_position']
  377. );
  378. }
  379. //collation?!?
  380. /*
  381. if (!empty($row['collation'])) {
  382. $definition['fields'][$field]['sorting'] = ($row['collation'] == 'A'
  383. ? 'ascending' : 'descending');
  384. }
  385. */
  386. $lastrow = $row;
  387. // otherwise $row is no longer usable on exit from loop
  388. }
  389. $result->free();
  390. if (empty($definition)) {
  391. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  392. $constraint_name . ' is not an existing table constraint', __FUNCTION__);
  393. }
  394. $definition['primary'] = (boolean)$lastrow['primary'];
  395. $definition['unique'] = (boolean)$lastrow['unique'];
  396. $definition['foreign'] = (boolean)$lastrow['foreign'];
  397. $definition['check'] = (boolean)$lastrow['check'];
  398. $definition['deferrable'] = (boolean)$lastrow['deferrable'];
  399. $definition['initiallydeferred'] = (boolean)$lastrow['initiallydeferred'];
  400. $definition['onupdate'] = $lastrow['onupdate'];
  401. $definition['ondelete'] = $lastrow['ondelete'];
  402. $definition['match'] = $lastrow['match'];
  403. return $definition;
  404. }
  405. // }}}
  406. // {{{ getTriggerDefinition()
  407. /**
  408. * Get the structure of a trigger into an array
  409. *
  410. * EXPERIMENTAL
  411. *
  412. * WARNING: this function is experimental and may change the returned value
  413. * at any time until labelled as non-experimental
  414. *
  415. * @param string $trigger name of trigger that should be used in method
  416. * @return mixed data array on success, a MDB2 error on failure
  417. * @access public
  418. */
  419. function getTriggerDefinition($trigger)
  420. {
  421. $db = $this->getDBInstance();
  422. if (MDB2::isError($db)) {
  423. return $db;
  424. }
  425. $trigger = $db->quote(strtoupper($trigger), 'text');
  426. $query = "SELECT RDB\$TRIGGER_NAME AS trigger_name,
  427. RDB\$RELATION_NAME AS table_name,
  428. RDB\$TRIGGER_SOURCE AS trigger_body,
  429. CASE RDB\$TRIGGER_TYPE
  430. WHEN 1 THEN 'BEFORE'
  431. WHEN 2 THEN 'AFTER'
  432. WHEN 3 THEN 'BEFORE'
  433. WHEN 4 THEN 'AFTER'
  434. WHEN 5 THEN 'BEFORE'
  435. WHEN 6 THEN 'AFTER'
  436. END AS trigger_type,
  437. CASE RDB\$TRIGGER_TYPE
  438. WHEN 1 THEN 'INSERT'
  439. WHEN 2 THEN 'INSERT'
  440. WHEN 3 THEN 'UPDATE'
  441. WHEN 4 THEN 'UPDATE'
  442. WHEN 5 THEN 'DELETE'
  443. WHEN 6 THEN 'DELETE'
  444. END AS trigger_event,
  445. CASE RDB\$TRIGGER_INACTIVE
  446. WHEN 1 THEN 0 ELSE 1
  447. END AS trigger_enabled,
  448. RDB\$DESCRIPTION AS trigger_comment
  449. FROM RDB\$TRIGGERS
  450. WHERE UPPER(RDB\$TRIGGER_NAME)=$trigger";
  451. $types = array(
  452. 'trigger_name' => 'text',
  453. 'table_name' => 'text',
  454. 'trigger_body' => 'clob',
  455. 'trigger_type' => 'text',
  456. 'trigger_event' => 'text',
  457. 'trigger_comment' => 'text',
  458. 'trigger_enabled' => 'boolean',
  459. );
  460. $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
  461. if (MDB2::isError($def)) {
  462. return $def;
  463. }
  464. $clob = $def['trigger_body'];
  465. if (!MDB2::isError($clob) && is_resource($clob)) {
  466. $value = '';
  467. while (!feof($clob)) {
  468. $data = fread($clob, 8192);
  469. $value.= $data;
  470. }
  471. $db->datatype->destroyLOB($clob);
  472. $def['trigger_body'] = $value;
  473. }
  474. return $def;
  475. }
  476. // }}}
  477. // {{{ tableInfo()
  478. /**
  479. * Returns information about a table or a result set
  480. *
  481. * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  482. * is a table name.
  483. *
  484. * @param object|string $result MDB2_result object from a query or a
  485. * string containing the name of a table.
  486. * While this also accepts a query result
  487. * resource identifier, this behavior is
  488. * deprecated.
  489. * @param int $mode a valid tableInfo mode
  490. *
  491. * @return array an associative array with the information requested.
  492. * A MDB2_Error object on failure.
  493. *
  494. * @see MDB2_Driver_Common::tableInfo()
  495. */
  496. function tableInfo($result, $mode = null)
  497. {
  498. if (is_string($result)) {
  499. return parent::tableInfo($result, $mode);
  500. }
  501. $db = $this->getDBInstance();
  502. if (MDB2::isError($db)) {
  503. return $db;
  504. }
  505. $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
  506. if (!is_resource($resource)) {
  507. return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
  508. 'Could not generate result resource', __FUNCTION__);
  509. }
  510. if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
  511. if ($db->options['field_case'] == CASE_LOWER) {
  512. $case_func = 'strtolower';
  513. } else {
  514. $case_func = 'strtoupper';
  515. }
  516. } else {
  517. $case_func = 'strval';
  518. }
  519. $count = @ibase_num_fields($resource);
  520. $res = array();
  521. if ($mode) {
  522. $res['num_fields'] = $count;
  523. }
  524. $db->loadModule('Datatype', null, true);
  525. for ($i = 0; $i < $count; $i++) {
  526. $info = @ibase_field_info($resource, $i);
  527. if (($pos = strpos($info['type'], '(')) !== false) {
  528. $info['type'] = substr($info['type'], 0, $pos);
  529. }
  530. $res[$i] = array(
  531. 'table' => $case_func($info['relation']),
  532. 'name' => $case_func($info['name']),
  533. 'type' => $info['type'],
  534. 'length' => $info['length'],
  535. 'flags' => '',
  536. );
  537. $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
  538. if (MDB2::isError($mdb2type_info)) {
  539. return $mdb2type_info;
  540. }
  541. $res[$i]['mdb2type'] = $mdb2type_info[0][0];
  542. if ($mode & MDB2_TABLEINFO_ORDER) {
  543. $res['order'][$res[$i]['name']] = $i;
  544. }
  545. if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
  546. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  547. }
  548. }
  549. return $res;
  550. }
  551. }
  552. ?>