Automatically exported from code.google.com/p/planningalerts
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

1672 rader
56 KiB

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2006 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: Common.php,v 1.109 2006/08/20 09:48:43 lsmith Exp $
  46. require_once 'MDB2/LOB.php';
  47. /**
  48. * @package MDB2
  49. * @category Database
  50. * @author Lukas Smith <smith@pooteeweet.org>
  51. */
  52. /**
  53. * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
  54. *
  55. * @package MDB2
  56. * @category Database
  57. * @author Lukas Smith <smith@pooteeweet.org>
  58. */
  59. class MDB2_Driver_Datatype_Common extends MDB2_Module_Common
  60. {
  61. var $valid_types = array(
  62. 'text' => '',
  63. 'boolean' => true,
  64. 'integer' => 0,
  65. 'decimal' => 0.0,
  66. 'float' => 0.0,
  67. 'timestamp' => '1970-01-01 00:00:00',
  68. 'time' => '00:00:00',
  69. 'date' => '1970-01-01',
  70. 'clob' => '',
  71. 'blob' => '',
  72. );
  73. /**
  74. * contains all LOB objects created with this MDB2 instance
  75. * @var array
  76. * @access protected
  77. */
  78. var $lobs = array();
  79. // }}}
  80. // {{{ getValidTypes()
  81. /**
  82. * Get the list of valid types
  83. *
  84. * This function returns an array of valid types as keys with the values
  85. * being possible default values for all native datatypes and mapped types
  86. * for custom datatypes.
  87. *
  88. * @return mixed array on success, a MDB2 error on failure
  89. * @access public
  90. */
  91. function getValidTypes()
  92. {
  93. $types = $this->valid_types;
  94. $db =& $this->getDBInstance();
  95. if (PEAR::isError($db)) {
  96. return $db;
  97. }
  98. if (!empty($db->options['datatype_map'])) {
  99. foreach ($db->options['datatype_map'] as $type => $mapped_type) {
  100. if (array_key_exists($mapped_type, $types)) {
  101. $types[$type] = $types[$mapped_type];
  102. } elseif (!empty($db->options['datatype_map_callback'][$type])) {
  103. $parameter = array('type' => $type, 'mapped_type' => $mapped_type);
  104. $default = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
  105. $types[$type] = $default;
  106. }
  107. }
  108. }
  109. return $types;
  110. }
  111. // }}}
  112. // {{{ checkResultTypes()
  113. /**
  114. * Define the list of types to be associated with the columns of a given
  115. * result set.
  116. *
  117. * This function may be called before invoking fetchRow(), fetchOne()
  118. * fetchCole() and fetchAll() so that the necessary data type
  119. * conversions are performed on the data to be retrieved by them. If this
  120. * function is not called, the type of all result set columns is assumed
  121. * to be text, thus leading to not perform any conversions.
  122. *
  123. * @param string $types array variable that lists the
  124. * data types to be expected in the result set columns. If this array
  125. * contains less types than the number of columns that are returned
  126. * in the result set, the remaining columns are assumed to be of the
  127. * type text. Currently, the types clob and blob are not fully
  128. * supported.
  129. * @return mixed MDB2_OK on success, a MDB2 error on failure
  130. * @access public
  131. */
  132. function checkResultTypes($types)
  133. {
  134. $types = is_array($types) ? $types : array($types);
  135. foreach ($types as $key => $type) {
  136. if (!isset($this->valid_types[$type])) {
  137. $db =& $this->getDBInstance();
  138. if (PEAR::isError($db)) {
  139. return $db;
  140. }
  141. if (empty($db->options['datatype_map'][$type])) {
  142. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  143. $type.' for '.$key.' is not a supported column type', __FUNCTION__);
  144. }
  145. }
  146. }
  147. return $types;
  148. }
  149. // }}}
  150. // {{{ _baseConvertResult()
  151. /**
  152. * general type conversion method
  153. *
  154. * @param mixed $value refernce to a value to be converted
  155. * @param string $type specifies which type to convert to
  156. * @return object a MDB2 error on failure
  157. * @access protected
  158. */
  159. function _baseConvertResult($value, $type, $rtrim = true)
  160. {
  161. switch ($type) {
  162. case 'text':
  163. if ($rtrim) {
  164. $value = rtrim($value);
  165. }
  166. return $value;
  167. case 'integer':
  168. return intval($value);
  169. case 'boolean':
  170. return !empty($value);
  171. case 'decimal':
  172. return $value;
  173. case 'float':
  174. return doubleval($value);
  175. case 'date':
  176. return $value;
  177. case 'time':
  178. return $value;
  179. case 'timestamp':
  180. return $value;
  181. case 'clob':
  182. case 'blob':
  183. $this->lobs[] = array(
  184. 'buffer' => null,
  185. 'position' => 0,
  186. 'lob_index' => null,
  187. 'endOfLOB' => false,
  188. 'resource' => $value,
  189. 'value' => null,
  190. 'loaded' => false,
  191. );
  192. end($this->lobs);
  193. $lob_index = key($this->lobs);
  194. $this->lobs[$lob_index]['lob_index'] = $lob_index;
  195. return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+');
  196. }
  197. $db =& $this->getDBInstance();
  198. if (PEAR::isError($db)) {
  199. return $db;
  200. }
  201. return $db->raiseError(MDB2_ERROR_INVALID, null, null,
  202. 'attempt to convert result value to an unknown type :' . $type, __FUNCTION__);
  203. }
  204. // }}}
  205. // {{{ convertResult()
  206. /**
  207. * convert a value to a RDBMS indepdenant MDB2 type
  208. *
  209. * @param mixed $value value to be converted
  210. * @param string $type specifies which type to convert to
  211. * @param bool $rtrim if to rtrim text values or not
  212. * @return mixed converted value
  213. * @access public
  214. */
  215. function convertResult($value, $type, $rtrim = true)
  216. {
  217. if (is_null($value)) {
  218. return null;
  219. }
  220. $db =& $this->getDBInstance();
  221. if (PEAR::isError($db)) {
  222. return $db;
  223. }
  224. if (!empty($db->options['datatype_map'][$type])) {
  225. $type = $db->options['datatype_map'][$type];
  226. if (!empty($db->options['datatype_map_callback'][$type])) {
  227. $parameter = array('type' => $type, 'value' => $value, 'rtrim' => $rtrim);
  228. return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
  229. }
  230. }
  231. return $this->_baseConvertResult($value, $type, $rtrim);
  232. }
  233. // }}}
  234. // {{{ convertResultRow()
  235. /**
  236. * convert a result row
  237. *
  238. * @param array $types
  239. * @param array $row specifies the types to convert to
  240. * @param bool $rtrim if to rtrim text values or not
  241. * @return mixed MDB2_OK on success, a MDB2 error on failure
  242. * @access public
  243. */
  244. function convertResultRow($types, $row, $rtrim = true)
  245. {
  246. reset($types);
  247. $current_column = -1;
  248. foreach ($row as $key => $value) {
  249. ++$current_column;
  250. if (!isset($value)) {
  251. continue;
  252. }
  253. if (isset($types[$current_column])) {
  254. $type = $types[$current_column];
  255. } elseif (isset($types[$key])) {
  256. $type = $types[$key];
  257. } elseif (current($types)) {
  258. $type = current($types);
  259. next($types);
  260. } else {
  261. continue;
  262. }
  263. $value = $this->convertResult($row[$key], $type, $rtrim);
  264. if (PEAR::isError($value)) {
  265. return $value;
  266. }
  267. $row[$key] = $value;
  268. }
  269. return $row;
  270. }
  271. // }}}
  272. // {{{ getDeclaration()
  273. /**
  274. * Obtain DBMS specific SQL code portion needed to declare
  275. * of the given type
  276. *
  277. * @param string $type type to which the value should be converted to
  278. * @param string $name name the field to be declared.
  279. * @param string $field definition of the field
  280. * @return string DBMS specific SQL code portion that should be used to
  281. * declare the specified field.
  282. * @access public
  283. */
  284. function getDeclaration($type, $name, $field)
  285. {
  286. $db =& $this->getDBInstance();
  287. if (PEAR::isError($db)) {
  288. return $db;
  289. }
  290. if (!empty($db->options['datatype_map'][$type])) {
  291. $type = $db->options['datatype_map'][$type];
  292. if (!empty($db->options['datatype_map_callback'][$type])) {
  293. $parameter = array('type' => $type, 'name' => $name, 'field' => $field);
  294. return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
  295. }
  296. }
  297. if (!method_exists($this, "_get{$type}Declaration")) {
  298. return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
  299. 'type not defined: '.$type, __FUNCTION__);
  300. }
  301. return $this->{"_get{$type}Declaration"}($name, $field);
  302. }
  303. // }}}
  304. // {{{ getTypeDeclaration()
  305. /**
  306. * Obtain DBMS specific SQL code portion needed to declare an text type
  307. * field to be used in statements like CREATE TABLE.
  308. *
  309. * @param array $field associative array with the name of the properties
  310. * of the field being declared as array indexes. Currently, the types
  311. * of supported field properties are as follows:
  312. *
  313. * length
  314. * Integer value that determines the maximum length of the text
  315. * field. If this argument is missing the field should be
  316. * declared to have the longest length allowed by the DBMS.
  317. *
  318. * default
  319. * Text value to be used as default for this field.
  320. *
  321. * notnull
  322. * Boolean flag that indicates whether this field is constrained
  323. * to not be set to null.
  324. * @return string DBMS specific SQL code portion that should be used to
  325. * declare the specified field.
  326. * @access public
  327. */
  328. function getTypeDeclaration($field)
  329. {
  330. $db =& $this->getDBInstance();
  331. if (PEAR::isError($db)) {
  332. return $db;
  333. }
  334. switch ($field['type']) {
  335. case 'text':
  336. $length = !empty($field['length']) ? $field['length'] : $db->options['default_text_field_length'];
  337. $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
  338. return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
  339. : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
  340. case 'clob':
  341. return 'TEXT';
  342. case 'blob':
  343. return 'TEXT';
  344. case 'integer':
  345. return 'INT';
  346. case 'boolean':
  347. return 'INT';
  348. case 'date':
  349. return 'CHAR ('.strlen('YYYY-MM-DD').')';
  350. case 'time':
  351. return 'CHAR ('.strlen('HH:MM:SS').')';
  352. case 'timestamp':
  353. return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')';
  354. case 'float':
  355. return 'TEXT';
  356. case 'decimal':
  357. return 'TEXT';
  358. }
  359. return '';
  360. }
  361. // }}}
  362. // {{{ _getDeclaration()
  363. /**
  364. * Obtain DBMS specific SQL code portion needed to declare a generic type
  365. * field to be used in statements like CREATE TABLE.
  366. *
  367. * @param string $name name the field to be declared.
  368. * @param array $field associative array with the name of the properties
  369. * of the field being declared as array indexes. Currently, the types
  370. * of supported field properties are as follows:
  371. *
  372. * length
  373. * Integer value that determines the maximum length of the text
  374. * field. If this argument is missing the field should be
  375. * declared to have the longest length allowed by the DBMS.
  376. *
  377. * default
  378. * Text value to be used as default for this field.
  379. *
  380. * notnull
  381. * Boolean flag that indicates whether this field is constrained
  382. * to not be set to null.
  383. * @return string DBMS specific SQL code portion that should be used to
  384. * declare the specified field.
  385. * @access protected
  386. */
  387. function _getDeclaration($name, $field)
  388. {
  389. $db =& $this->getDBInstance();
  390. if (PEAR::isError($db)) {
  391. return $db;
  392. }
  393. $default = '';
  394. if (array_key_exists('default', $field)) {
  395. if ($field['default'] === '') {
  396. $field['default'] = empty($field['notnull'])
  397. ? null : $this->valid_types[$field['type']];
  398. if ($field['default'] === ''
  399. && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
  400. ) {
  401. $field['default'] = ' ';
  402. }
  403. }
  404. $default = ' DEFAULT '.$this->quote($field['default'], $field['type']);
  405. } elseif (empty($field['notnull'])) {
  406. $default = ' DEFAULT NULL';
  407. }
  408. $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
  409. $name = $db->quoteIdentifier($name, true);
  410. return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
  411. }
  412. // }}}
  413. // {{{ _getIntegerDeclaration()
  414. /**
  415. * Obtain DBMS specific SQL code portion needed to declare an integer type
  416. * field to be used in statements like CREATE TABLE.
  417. *
  418. * @param string $name name the field to be declared.
  419. * @param array $field associative array with the name of the properties
  420. * of the field being declared as array indexes. Currently, the types
  421. * of supported field properties are as follows:
  422. *
  423. * unsigned
  424. * Boolean flag that indicates whether the field should be
  425. * declared as unsigned integer if possible.
  426. *
  427. * default
  428. * Integer value to be used as default for this field.
  429. *
  430. * notnull
  431. * Boolean flag that indicates whether this field is constrained
  432. * to not be set to null.
  433. * @return string DBMS specific SQL code portion that should be used to
  434. * declare the specified field.
  435. * @access protected
  436. */
  437. function _getIntegerDeclaration($name, $field)
  438. {
  439. if (!empty($field['unsigned'])) {
  440. $db =& $this->getDBInstance();
  441. if (PEAR::isError($db)) {
  442. return $db;
  443. }
  444. $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
  445. }
  446. return $this->_getDeclaration($name, $field);
  447. }
  448. // }}}
  449. // {{{ _getTextDeclaration()
  450. /**
  451. * Obtain DBMS specific SQL code portion needed to declare an text type
  452. * field to be used in statements like CREATE TABLE.
  453. *
  454. * @param string $name name the field to be declared.
  455. * @param array $field associative array with the name of the properties
  456. * of the field being declared as array indexes. Currently, the types
  457. * of supported field properties are as follows:
  458. *
  459. * length
  460. * Integer value that determines the maximum length of the text
  461. * field. If this argument is missing the field should be
  462. * declared to have the longest length allowed by the DBMS.
  463. *
  464. * default
  465. * Text value to be used as default for this field.
  466. *
  467. * notnull
  468. * Boolean flag that indicates whether this field is constrained
  469. * to not be set to null.
  470. * @return string DBMS specific SQL code portion that should be used to
  471. * declare the specified field.
  472. * @access protected
  473. */
  474. function _getTextDeclaration($name, $field)
  475. {
  476. return $this->_getDeclaration($name, $field);
  477. }
  478. // }}}
  479. // {{{ _getCLOBDeclaration()
  480. /**
  481. * Obtain DBMS specific SQL code portion needed to declare an character
  482. * large object type field to be used in statements like CREATE TABLE.
  483. *
  484. * @param string $name name the field to be declared.
  485. * @param array $field associative array with the name of the properties
  486. * of the field being declared as array indexes. Currently, the types
  487. * of supported field properties are as follows:
  488. *
  489. * length
  490. * Integer value that determines the maximum length of the large
  491. * object field. If this argument is missing the field should be
  492. * declared to have the longest length allowed by the DBMS.
  493. *
  494. * notnull
  495. * Boolean flag that indicates whether this field is constrained
  496. * to not be set to null.
  497. * @return string DBMS specific SQL code portion that should be used to
  498. * declare the specified field.
  499. * @access public
  500. */
  501. function _getCLOBDeclaration($name, $field)
  502. {
  503. $db =& $this->getDBInstance();
  504. if (PEAR::isError($db)) {
  505. return $db;
  506. }
  507. $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
  508. $name = $db->quoteIdentifier($name, true);
  509. return $name.' '.$this->getTypeDeclaration($field).$notnull;
  510. }
  511. // }}}
  512. // {{{ _getBLOBDeclaration()
  513. /**
  514. * Obtain DBMS specific SQL code portion needed to declare an binary large
  515. * object type field to be used in statements like CREATE TABLE.
  516. *
  517. * @param string $name name the field to be declared.
  518. * @param array $field associative array with the name of the properties
  519. * of the field being declared as array indexes. Currently, the types
  520. * of supported field properties are as follows:
  521. *
  522. * length
  523. * Integer value that determines the maximum length of the large
  524. * object field. If this argument is missing the field should be
  525. * declared to have the longest length allowed by the DBMS.
  526. *
  527. * notnull
  528. * Boolean flag that indicates whether this field is constrained
  529. * to not be set to null.
  530. * @return string DBMS specific SQL code portion that should be used to
  531. * declare the specified field.
  532. * @access protected
  533. */
  534. function _getBLOBDeclaration($name, $field)
  535. {
  536. $db =& $this->getDBInstance();
  537. if (PEAR::isError($db)) {
  538. return $db;
  539. }
  540. $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
  541. $name = $db->quoteIdentifier($name, true);
  542. return $name.' '.$this->getTypeDeclaration($field).$notnull;
  543. }
  544. // }}}
  545. // {{{ _getBooleanDeclaration()
  546. /**
  547. * Obtain DBMS specific SQL code portion needed to declare a boolean type
  548. * field to be used in statements like CREATE TABLE.
  549. *
  550. * @param string $name name the field to be declared.
  551. * @param array $field associative array with the name of the properties
  552. * of the field being declared as array indexes. Currently, the types
  553. * of supported field properties are as follows:
  554. *
  555. * default
  556. * Boolean value to be used as default for this field.
  557. *
  558. * notnullL
  559. * Boolean flag that indicates whether this field is constrained
  560. * to not be set to null.
  561. * @return string DBMS specific SQL code portion that should be used to
  562. * declare the specified field.
  563. * @access protected
  564. */
  565. function _getBooleanDeclaration($name, $field)
  566. {
  567. return $this->_getDeclaration($name, $field);
  568. }
  569. // }}}
  570. // {{{ _getDateDeclaration()
  571. /**
  572. * Obtain DBMS specific SQL code portion needed to declare a date type
  573. * field to be used in statements like CREATE TABLE.
  574. *
  575. * @param string $name name the field to be declared.
  576. * @param array $field associative array with the name of the properties
  577. * of the field being declared as array indexes. Currently, the types
  578. * of supported field properties are as follows:
  579. *
  580. * default
  581. * Date value to be used as default for this field.
  582. *
  583. * notnull
  584. * Boolean flag that indicates whether this field is constrained
  585. * to not be set to null.
  586. * @return string DBMS specific SQL code portion that should be used to
  587. * declare the specified field.
  588. * @access protected
  589. */
  590. function _getDateDeclaration($name, $field)
  591. {
  592. return $this->_getDeclaration($name, $field);
  593. }
  594. // }}}
  595. // {{{ _getTimestampDeclaration()
  596. /**
  597. * Obtain DBMS specific SQL code portion needed to declare a timestamp
  598. * field to be used in statements like CREATE TABLE.
  599. *
  600. * @param string $name name the field to be declared.
  601. * @param array $field associative array with the name of the properties
  602. * of the field being declared as array indexes. Currently, the types
  603. * of supported field properties are as follows:
  604. *
  605. * default
  606. * Timestamp value to be used as default for this field.
  607. *
  608. * notnull
  609. * Boolean flag that indicates whether this field is constrained
  610. * to not be set to null.
  611. * @return string DBMS specific SQL code portion that should be used to
  612. * declare the specified field.
  613. * @access protected
  614. */
  615. function _getTimestampDeclaration($name, $field)
  616. {
  617. return $this->_getDeclaration($name, $field);
  618. }
  619. // }}}
  620. // {{{ _getTimeDeclaration()
  621. /**
  622. * Obtain DBMS specific SQL code portion needed to declare a time
  623. * field to be used in statements like CREATE TABLE.
  624. *
  625. * @param string $name name the field to be declared.
  626. * @param array $field associative array with the name of the properties
  627. * of the field being declared as array indexes. Currently, the types
  628. * of supported field properties are as follows:
  629. *
  630. * default
  631. * Time value to be used as default for this field.
  632. *
  633. * notnull
  634. * Boolean flag that indicates whether this field is constrained
  635. * to not be set to null.
  636. * @return string DBMS specific SQL code portion that should be used to
  637. * declare the specified field.
  638. * @access protected
  639. */
  640. function _getTimeDeclaration($name, $field)
  641. {
  642. return $this->_getDeclaration($name, $field);
  643. }
  644. // }}}
  645. // {{{ _getFloatDeclaration()
  646. /**
  647. * Obtain DBMS specific SQL code portion needed to declare a float type
  648. * field to be used in statements like CREATE TABLE.
  649. *
  650. * @param string $name name the field to be declared.
  651. * @param array $field associative array with the name of the properties
  652. * of the field being declared as array indexes. Currently, the types
  653. * of supported field properties are as follows:
  654. *
  655. * default
  656. * Float value to be used as default for this field.
  657. *
  658. * notnull
  659. * Boolean flag that indicates whether this field is constrained
  660. * to not be set to null.
  661. * @return string DBMS specific SQL code portion that should be used to
  662. * declare the specified field.
  663. * @access protected
  664. */
  665. function _getFloatDeclaration($name, $field)
  666. {
  667. return $this->_getDeclaration($name, $field);
  668. }
  669. // }}}
  670. // {{{ _getDecimalDeclaration()
  671. /**
  672. * Obtain DBMS specific SQL code portion needed to declare a decimal type
  673. * field to be used in statements like CREATE TABLE.
  674. *
  675. * @param string $name name the field to be declared.
  676. * @param array $field associative array with the name of the properties
  677. * of the field being declared as array indexes. Currently, the types
  678. * of supported field properties are as follows:
  679. *
  680. * default
  681. * Decimal value to be used as default for this field.
  682. *
  683. * notnull
  684. * Boolean flag that indicates whether this field is constrained
  685. * to not be set to null.
  686. * @return string DBMS specific SQL code portion that should be used to
  687. * declare the specified field.
  688. * @access protected
  689. */
  690. function _getDecimalDeclaration($name, $field)
  691. {
  692. return $this->_getDeclaration($name, $field);
  693. }
  694. // }}}
  695. // {{{ compareDefinition()
  696. /**
  697. * Obtain an array of changes that may need to applied
  698. *
  699. * @param array $current new definition
  700. * @param array $previous old definition
  701. * @return array containing all changes that will need to be applied
  702. * @access public
  703. */
  704. function compareDefinition($current, $previous)
  705. {
  706. $type = !empty($current['type']) ? $current['type'] : null;
  707. if (!method_exists($this, "_compare{$type}Definition")) {
  708. $db =& $this->getDBInstance();
  709. if (PEAR::isError($db)) {
  710. return $db;
  711. }
  712. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  713. 'type "'.$current['type'].'" is not yet supported', __FUNCTION__);
  714. }
  715. if (empty($previous['type']) || $previous['type'] != $type) {
  716. return $current;
  717. }
  718. $change = $this->{"_compare{$type}Definition"}($current, $previous);
  719. if ($previous['type'] != $type) {
  720. $change['type'] = true;
  721. }
  722. $previous_notnull = !empty($previous['notnull']) ? $previous['notnull'] : false;
  723. $notnull = !empty($current['notnull']) ? $current['notnull'] : false;
  724. if ($previous_notnull != $notnull) {
  725. $change['notnull'] = true;
  726. }
  727. $previous_default = array_key_exists('default', $previous) ? $previous['default'] :
  728. ($previous_notnull ? '' : null);
  729. $default = array_key_exists('default', $current) ? $current['default'] :
  730. ($notnull ? '' : null);
  731. if ($previous_default !== $default) {
  732. $change['default'] = true;
  733. }
  734. return $change;
  735. }
  736. // }}}
  737. // {{{ _compareIntegerDefinition()
  738. /**
  739. * Obtain an array of changes that may need to applied to an integer field
  740. *
  741. * @param array $current new definition
  742. * @param array $previous old definition
  743. * @return array containing all changes that will need to be applied
  744. * @access protected
  745. */
  746. function _compareIntegerDefinition($current, $previous)
  747. {
  748. $change = array();
  749. $previous_unsigned = !empty($previous['unsigned']) ? $previous['unsigned'] : false;
  750. $unsigned = !empty($current['unsigned']) ? $current['unsigned'] : false;
  751. if ($previous_unsigned != $unsigned) {
  752. $change['unsigned'] = true;
  753. }
  754. $previous_autoincrement = !empty($previous['autoincrement']) ? $previous['autoincrement'] : false;
  755. $autoincrement = !empty($current['autoincrement']) ? $current['autoincrement'] : false;
  756. if ($previous_autoincrement != $autoincrement) {
  757. $change['autoincrement'] = true;
  758. }
  759. return $change;
  760. }
  761. // }}}
  762. // {{{ _compareTextDefinition()
  763. /**
  764. * Obtain an array of changes that may need to applied to an text field
  765. *
  766. * @param array $current new definition
  767. * @param array $previous old definition
  768. * @return array containing all changes that will need to be applied
  769. * @access protected
  770. */
  771. function _compareTextDefinition($current, $previous)
  772. {
  773. $change = array();
  774. $previous_length = !empty($previous['length']) ? $previous['length'] : 0;
  775. $length = !empty($current['length']) ? $current['length'] : 0;
  776. if ($previous_length != $length) {
  777. $change['length'] = true;
  778. }
  779. $previous_fixed = !empty($previous['fixed']) ? $previous['fixed'] : 0;
  780. $fixed = !empty($current['fixed']) ? $current['fixed'] : 0;
  781. if ($previous_fixed != $fixed) {
  782. $change['fixed'] = true;
  783. }
  784. return $change;
  785. }
  786. // }}}
  787. // {{{ _compareCLOBDefinition()
  788. /**
  789. * Obtain an array of changes that may need to applied to an CLOB field
  790. *
  791. * @param array $current new definition
  792. * @param array $previous old definition
  793. * @return array containing all changes that will need to be applied
  794. * @access protected
  795. */
  796. function _compareCLOBDefinition($current, $previous)
  797. {
  798. return $this->_compareTextDefinition($current, $previous);
  799. }
  800. // }}}
  801. // {{{ _compareBLOBDefinition()
  802. /**
  803. * Obtain an array of changes that may need to applied to an BLOB field
  804. *
  805. * @param array $current new definition
  806. * @param array $previous old definition
  807. * @return array containing all changes that will need to be applied
  808. * @access protected
  809. */
  810. function _compareBLOBDefinition($current, $previous)
  811. {
  812. return $this->_compareTextDefinition($current, $previous);
  813. }
  814. // }}}
  815. // {{{ _compareDateDefinition()
  816. /**
  817. * Obtain an array of changes that may need to applied to an date field
  818. *
  819. * @param array $current new definition
  820. * @param array $previous old definition
  821. * @return array containing all changes that will need to be applied
  822. * @access protected
  823. */
  824. function _compareDateDefinition($current, $previous)
  825. {
  826. return array();
  827. }
  828. // }}}
  829. // {{{ _compareTimeDefinition()
  830. /**
  831. * Obtain an array of changes that may need to applied to an time field
  832. *
  833. * @param array $current new definition
  834. * @param array $previous old definition
  835. * @return array containing all changes that will need to be applied
  836. * @access protected
  837. */
  838. function _compareTimeDefinition($current, $previous)
  839. {
  840. return array();
  841. }
  842. // }}}
  843. // {{{ _compareTimestampDefinition()
  844. /**
  845. * Obtain an array of changes that may need to applied to an timestamp field
  846. *
  847. * @param array $current new definition
  848. * @param array $previous old definition
  849. * @return array containing all changes that will need to be applied
  850. * @access protected
  851. */
  852. function _compareTimestampDefinition($current, $previous)
  853. {
  854. return array();
  855. }
  856. // }}}
  857. // {{{ _compareBooleanDefinition()
  858. /**
  859. * Obtain an array of changes that may need to applied to an boolean field
  860. *
  861. * @param array $current new definition
  862. * @param array $previous old definition
  863. * @return array containing all changes that will need to be applied
  864. * @access protected
  865. */
  866. function _compareBooleanDefinition($current, $previous)
  867. {
  868. return array();
  869. }
  870. // }}}
  871. // {{{ _compareFloatDefinition()
  872. /**
  873. * Obtain an array of changes that may need to applied to an float field
  874. *
  875. * @param array $current new definition
  876. * @param array $previous old definition
  877. * @return array containing all changes that will need to be applied
  878. * @access protected
  879. */
  880. function _compareFloatDefinition($current, $previous)
  881. {
  882. return array();
  883. }
  884. // }}}
  885. // {{{ _compareDecimalDefinition()
  886. /**
  887. * Obtain an array of changes that may need to applied to an decimal field
  888. *
  889. * @param array $current new definition
  890. * @param array $previous old definition
  891. * @return array containing all changes that will need to be applied
  892. * @access protected
  893. */
  894. function _compareDecimalDefinition($current, $previous)
  895. {
  896. return array();
  897. }
  898. // }}}
  899. // {{{ quote()
  900. /**
  901. * Convert a text value into a DBMS specific format that is suitable to
  902. * compose query statements.
  903. *
  904. * @param string $value text string value that is intended to be converted.
  905. * @param string $type type to which the value should be converted to
  906. * @param bool $quote determines if the value should be quoted and escaped
  907. * @param bool $escape_wildcards if to escape escape wildcards
  908. * @return string text string that represents the given argument value in
  909. * a DBMS specific format.
  910. * @access public
  911. */
  912. function quote($value, $type = null, $quote = true, $escape_wildcards = false)
  913. {
  914. $db =& $this->getDBInstance();
  915. if (PEAR::isError($db)) {
  916. return $db;
  917. }
  918. if (is_null($value)
  919. || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
  920. ) {
  921. if (!$quote) {
  922. return null;
  923. }
  924. return 'NULL';
  925. }
  926. if (is_null($type)) {
  927. switch (gettype($value)) {
  928. case 'integer':
  929. $type = 'integer';
  930. break;
  931. case 'double':
  932. // todo: default to decimal as float is quite unusual
  933. // $type = 'float';
  934. $type = 'decimal';
  935. break;
  936. case 'boolean':
  937. $type = 'boolean';
  938. break;
  939. case 'array':
  940. $value = serialize($value);
  941. case 'object':
  942. $type = 'text';
  943. break;
  944. default:
  945. if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) {
  946. $type = 'timestamp';
  947. } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) {
  948. $type = 'time';
  949. } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
  950. $type = 'date';
  951. } else {
  952. $type = 'text';
  953. }
  954. break;
  955. }
  956. } elseif (!empty($db->options['datatype_map'][$type])) {
  957. $type = $db->options['datatype_map'][$type];
  958. if (!empty($db->options['datatype_map_callback'][$type])) {
  959. $parameter = array('type' => $type, 'value' => $value, 'quote' => $quote, 'escape_wildcards' => $escape_wildcards);
  960. return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
  961. }
  962. }
  963. if (!method_exists($this, "_quote{$type}")) {
  964. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  965. 'type not defined: '.$type, __FUNCTION__);
  966. }
  967. $value = $this->{"_quote{$type}"}($value, $quote, $escape_wildcards);
  968. if ($quote && $escape_wildcards && $db->escape_quotes !== $db->escape_pattern) {
  969. $value.= $this->patternEscapeString();
  970. }
  971. return $value;
  972. }
  973. // }}}
  974. // {{{ _quoteInteger()
  975. /**
  976. * Convert a text value into a DBMS specific format that is suitable to
  977. * compose query statements.
  978. *
  979. * @param string $value text string value that is intended to be converted.
  980. * @param bool $quote determines if the value should be quoted and escaped
  981. * @param bool $escape_wildcards if to escape escape wildcards
  982. * @return string text string that represents the given argument value in
  983. * a DBMS specific format.
  984. * @access protected
  985. */
  986. function _quoteInteger($value, $quote, $escape_wildcards)
  987. {
  988. return (int)$value;
  989. }
  990. // }}}
  991. // {{{ _quoteText()
  992. /**
  993. * Convert a text value into a DBMS specific format that is suitable to
  994. * compose query statements.
  995. *
  996. * @param string $value text string value that is intended to be converted.
  997. * @param bool $quote determines if the value should be quoted and escaped
  998. * @param bool $escape_wildcards if to escape escape wildcards
  999. * @return string text string that already contains any DBMS specific
  1000. * escaped character sequences.
  1001. * @access protected
  1002. */
  1003. function _quoteText($value, $quote, $escape_wildcards)
  1004. {
  1005. if (!$quote) {
  1006. return $value;
  1007. }
  1008. $db =& $this->getDBInstance();
  1009. if (PEAR::isError($db)) {
  1010. return $db;
  1011. }
  1012. $value = $db->escape($value, $escape_wildcards);
  1013. return "'".$value."'";
  1014. }
  1015. // }}}
  1016. // {{{ _readFile()
  1017. /**
  1018. * Convert a text value into a DBMS specific format that is suitable to
  1019. * compose query statements.
  1020. *
  1021. * @param string $value text string value that is intended to be converted.
  1022. * @return string text string that represents the given argument value in
  1023. * a DBMS specific format.
  1024. * @access protected
  1025. */
  1026. function _readFile($value)
  1027. {
  1028. $close = false;
  1029. if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
  1030. $close = true;
  1031. if ($match[1] == 'file://') {
  1032. $value = $match[2];
  1033. }
  1034. $value = @fopen($value, 'r');
  1035. }
  1036. if (is_resource($value)) {
  1037. $db =& $this->getDBInstance();
  1038. if (PEAR::isError($db)) {
  1039. return $db;
  1040. }
  1041. $fp = $value;
  1042. $value = '';
  1043. while (!@feof($fp)) {
  1044. $value.= @fread($fp, $db->options['lob_buffer_length']);
  1045. }
  1046. if ($close) {
  1047. @fclose($fp);
  1048. }
  1049. }
  1050. return $value;
  1051. }
  1052. // }}}
  1053. // {{{ _quoteLOB()
  1054. /**
  1055. * Convert a text value into a DBMS specific format that is suitable to
  1056. * compose query statements.
  1057. *
  1058. * @param string $value text string value that is intended to be converted.
  1059. * @param bool $quote determines if the value should be quoted and escaped
  1060. * @param bool $escape_wildcards if to escape escape wildcards
  1061. * @return string text string that represents the given argument value in
  1062. * a DBMS specific format.
  1063. * @access protected
  1064. */
  1065. function _quoteLOB($value, $quote, $escape_wildcards)
  1066. {
  1067. $value = $this->_readFile($value);
  1068. return $this->_quoteText($value, $quote, $escape_wildcards);
  1069. }
  1070. // }}}
  1071. // {{{ _quoteCLOB()
  1072. /**
  1073. * Convert a text value into a DBMS specific format that is suitable to
  1074. * compose query statements.
  1075. *
  1076. * @param string $value text string value that is intended to be converted.
  1077. * @param bool $quote determines if the value should be quoted and escaped
  1078. * @param bool $escape_wildcards if to escape escape wildcards
  1079. * @return string text string that represents the given argument value in
  1080. * a DBMS specific format.
  1081. * @access protected
  1082. */
  1083. function _quoteCLOB($value, $quote, $escape_wildcards)
  1084. {
  1085. return $this->_quoteLOB($value, $quote, $escape_wildcards);
  1086. }
  1087. // }}}
  1088. // {{{ _quoteBLOB()
  1089. /**
  1090. * Convert a text value into a DBMS specific format that is suitable to
  1091. * compose query statements.
  1092. *
  1093. * @param string $value text string value that is intended to be converted.
  1094. * @param bool $quote determines if the value should be quoted and escaped
  1095. * @param bool $escape_wildcards if to escape escape wildcards
  1096. * @return string text string that represents the given argument value in
  1097. * a DBMS specific format.
  1098. * @access protected
  1099. */
  1100. function _quoteBLOB($value, $quote, $escape_wildcards)
  1101. {
  1102. return $this->_quoteLOB($value, $quote, $escape_wildcards);
  1103. }
  1104. // }}}
  1105. // {{{ _quoteBoolean()
  1106. /**
  1107. * Convert a text value into a DBMS specific format that is suitable to
  1108. * compose query statements.
  1109. *
  1110. * @param string $value text string value that is intended to be converted.
  1111. * @param bool $quote determines if the value should be quoted and escaped
  1112. * @param bool $escape_wildcards if to escape escape wildcards
  1113. * @return string text string that represents the given argument value in
  1114. * a DBMS specific format.
  1115. * @access protected
  1116. */
  1117. function _quoteBoolean($value, $quote, $escape_wildcards)
  1118. {
  1119. return ($value ? 1 : 0);
  1120. }
  1121. // }}}
  1122. // {{{ _quoteDate()
  1123. /**
  1124. * Convert a text value into a DBMS specific format that is suitable to
  1125. * compose query statements.
  1126. *
  1127. * @param string $value text string value that is intended to be converted.
  1128. * @param bool $quote determines if the value should be quoted and escaped
  1129. * @param bool $escape_wildcards if to escape escape wildcards
  1130. * @return string text string that represents the given argument value in
  1131. * a DBMS specific format.
  1132. * @access protected
  1133. */
  1134. function _quoteDate($value, $quote, $escape_wildcards)
  1135. {
  1136. if ($value === 'CURRENT_DATE') {
  1137. $db =& $this->getDBInstance();
  1138. if (PEAR::isError($db)) {
  1139. return $db;
  1140. }
  1141. if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
  1142. return $db->function->now('date');
  1143. }
  1144. return 'CURRENT_DATE';
  1145. }
  1146. return $this->_quoteText($value, $quote, $escape_wildcards);
  1147. }
  1148. // }}}
  1149. // {{{ _quoteTimestamp()
  1150. /**
  1151. * Convert a text value into a DBMS specific format that is suitable to
  1152. * compose query statements.
  1153. *
  1154. * @param string $value text string value that is intended to be converted.
  1155. * @param bool $quote determines if the value should be quoted and escaped
  1156. * @param bool $escape_wildcards if to escape escape wildcards
  1157. * @return string text string that represents the given argument value in
  1158. * a DBMS specific format.
  1159. * @access protected
  1160. */
  1161. function _quoteTimestamp($value, $quote, $escape_wildcards)
  1162. {
  1163. if ($value === 'CURRENT_TIMESTAMP') {
  1164. $db =& $this->getDBInstance();
  1165. if (PEAR::isError($db)) {
  1166. return $db;
  1167. }
  1168. if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
  1169. return $db->function->now('timestamp');
  1170. }
  1171. return 'CURRENT_TIMESTAMP';
  1172. }
  1173. return $this->_quoteText($value, $quote, $escape_wildcards);
  1174. }
  1175. // }}}
  1176. // {{{ _quoteTime()
  1177. /**
  1178. * Convert a text value into a DBMS specific format that is suitable to
  1179. * compose query statements.
  1180. *
  1181. * @param string $value text string value that is intended to be converted.
  1182. * @param bool $quote determines if the value should be quoted and escaped
  1183. * @param bool $escape_wildcards if to escape escape wildcards
  1184. * @return string text string that represents the given argument value in
  1185. * a DBMS specific format.
  1186. * @access protected
  1187. */
  1188. function _quoteTime($value, $quote, $escape_wildcards)
  1189. {
  1190. if ($value === 'CURRENT_TIME') {
  1191. $db =& $this->getDBInstance();
  1192. if (PEAR::isError($db)) {
  1193. return $db;
  1194. }
  1195. if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
  1196. return $db->function->now('time');
  1197. }
  1198. return 'CURRENT_TIME';
  1199. }
  1200. return $this->_quoteText($value, $quote, $escape_wildcards);
  1201. }
  1202. // }}}
  1203. // {{{ _quoteFloat()
  1204. /**
  1205. * Convert a text value into a DBMS specific format that is suitable to
  1206. * compose query statements.
  1207. *
  1208. * @param string $value text string value that is intended to be converted.
  1209. * @param bool $quote determines if the value should be quoted and escaped
  1210. * @param bool $escape_wildcards if to escape escape wildcards
  1211. * @return string text string that represents the given argument value in
  1212. * a DBMS specific format.
  1213. * @access protected
  1214. */
  1215. function _quoteFloat($value, $quote, $escape_wildcards)
  1216. {
  1217. if (preg_match('/^(.*)e([-+])(\d+)$/i', $value, $matches)) {
  1218. $decimal = $this->_quoteDecimal($matches[1], $quote, $escape_wildcards);
  1219. $sign = $matches[2];
  1220. $exponent = str_pad($matches[3], 2, '0', STR_PAD_LEFT);
  1221. $value = $decimal.'E'.$sign.$exponent;
  1222. } else {
  1223. $value = $this->_quoteDecimal($value, $quote, $escape_wildcards);
  1224. }
  1225. return $value;
  1226. }
  1227. // }}}
  1228. // {{{ _quoteDecimal()
  1229. /**
  1230. * Convert a text value into a DBMS specific format that is suitable to
  1231. * compose query statements.
  1232. *
  1233. * @param string $value text string value that is intended to be converted.
  1234. * @param bool $quote determines if the value should be quoted and escaped
  1235. * @param bool $escape_wildcards if to escape escape wildcards
  1236. * @return string text string that represents the given argument value in
  1237. * a DBMS specific format.
  1238. * @access protected
  1239. */
  1240. function _quoteDecimal($value, $quote, $escape_wildcards)
  1241. {
  1242. $value = (string)$value;
  1243. if (preg_match('/[^.0-9]/', $value)) {
  1244. if (strpos($value, ',')) {
  1245. // 1000,00
  1246. if (!strpos($value, '.')) {
  1247. // convert the last "," to a "."
  1248. $value = strrev(str_replace(',', '.', strrev($value)));
  1249. // 1.000,00
  1250. } elseif (strpos($value, '.') && strpos($value, '.') < strpos($value, ',')) {
  1251. $value = str_replace('.', '', $value);
  1252. // convert the last "," to a "."
  1253. $value = strrev(str_replace(',', '.', strrev($value)));
  1254. // 1,000.00
  1255. } else {
  1256. $value = str_replace(',', '', $value);
  1257. }
  1258. }
  1259. }
  1260. return $value;
  1261. }
  1262. // }}}
  1263. // {{{ writeLOBToFile()
  1264. /**
  1265. * retrieve LOB from the database
  1266. *
  1267. * @param resource $lob stream handle
  1268. * @param string $file name of the file into which the LOb should be fetched
  1269. * @return mixed MDB2_OK on success, a MDB2 error on failure
  1270. * @access protected
  1271. */
  1272. function writeLOBToFile($lob, $file)
  1273. {
  1274. $db =& $this->getDBInstance();
  1275. if (PEAR::isError($db)) {
  1276. return $db;
  1277. }
  1278. if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) {
  1279. if ($match[1] == 'file://') {
  1280. $file = $match[2];
  1281. }
  1282. }
  1283. $fp = @fopen($file, 'wb');
  1284. while (!@feof($lob)) {
  1285. $result = @fread($lob, $db->options['lob_buffer_length']);
  1286. $read = strlen($result);
  1287. if (@fwrite($fp, $result, $read) != $read) {
  1288. @fclose($fp);
  1289. return $db->raiseError(MDB2_ERROR, null, null,
  1290. 'could not write to the output file', __FUNCTION__);
  1291. }
  1292. }
  1293. @fclose($fp);
  1294. return MDB2_OK;
  1295. }
  1296. // }}}
  1297. // {{{ _retrieveLOB()
  1298. /**
  1299. * retrieve LOB from the database
  1300. *
  1301. * @param array $lob array
  1302. * @return mixed MDB2_OK on success, a MDB2 error on failure
  1303. * @access protected
  1304. */
  1305. function _retrieveLOB(&$lob)
  1306. {
  1307. if (is_null($lob['value'])) {
  1308. $lob['value'] = $lob['resource'];
  1309. }
  1310. $lob['loaded'] = true;
  1311. return MDB2_OK;
  1312. }
  1313. // }}}
  1314. // {{{ readLOB()
  1315. /**
  1316. * Read data from large object input stream.
  1317. *
  1318. * @param resource $lob stream handle
  1319. * @param string $data reference to a variable that will hold data
  1320. * to be read from the large object input stream
  1321. * @param integer $length value that indicates the largest ammount ofdata
  1322. * to be read from the large object input stream.
  1323. * @return mixed the effective number of bytes read from the large object
  1324. * input stream on sucess or an MDB2 error object.
  1325. * @access public
  1326. * @see endOfLOB()
  1327. */
  1328. function _readLOB($lob, $length)
  1329. {
  1330. return substr($lob['value'], $lob['position'], $length);
  1331. }
  1332. // }}}
  1333. // {{{ _endOfLOB()
  1334. /**
  1335. * Determine whether it was reached the end of the large object and
  1336. * therefore there is no more data to be read for the its input stream.
  1337. *
  1338. * @param array $lob array
  1339. * @return mixed true or false on success, a MDB2 error on failure
  1340. * @access protected
  1341. */
  1342. function _endOfLOB($lob)
  1343. {
  1344. return $lob['endOfLOB'];
  1345. }
  1346. // }}}
  1347. // {{{ destroyLOB()
  1348. /**
  1349. * Free any resources allocated during the lifetime of the large object
  1350. * handler object.
  1351. *
  1352. * @param resource $lob stream handle
  1353. * @access public
  1354. */
  1355. function destroyLOB($lob)
  1356. {
  1357. $lob_data = stream_get_meta_data($lob);
  1358. $lob_index = $lob_data['wrapper_data']->lob_index;
  1359. fclose($lob);
  1360. if (isset($this->lobs[$lob_index])) {
  1361. $this->_destroyLOB($this->lobs[$lob_index]);
  1362. unset($this->lobs[$lob_index]);
  1363. }
  1364. return MDB2_OK;
  1365. }
  1366. // }}}
  1367. // {{{ _destroyLOB()
  1368. /**
  1369. * Free any resources allocated during the lifetime of the large object
  1370. * handler object.
  1371. *
  1372. * @param array $lob array
  1373. * @access private
  1374. */
  1375. function _destroyLOB(&$lob)
  1376. {
  1377. return MDB2_OK;
  1378. }
  1379. // }}}
  1380. // {{{ implodeArray()
  1381. /**
  1382. * apply a type to all values of an array and return as a comma seperated string
  1383. * useful for generating IN statements
  1384. *
  1385. * @access public
  1386. *
  1387. * @param array $array data array
  1388. * @param string $type determines type of the field
  1389. *
  1390. * @return string comma seperated values
  1391. */
  1392. function implodeArray($array, $type = false)
  1393. {
  1394. if (!is_array($array) || empty($array)) {
  1395. return 'NULL';
  1396. }
  1397. if ($type) {
  1398. foreach ($array as $value) {
  1399. $return[] = $this->quote($value, $type);
  1400. }
  1401. } else {
  1402. $return = $array;
  1403. }
  1404. return implode(', ', $return);
  1405. }
  1406. // }}}
  1407. // {{{ matchPattern()
  1408. /**
  1409. * build a pattern matching string
  1410. *
  1411. * EXPERIMENTAL
  1412. *
  1413. * WARNING: this function is experimental and may change signature at
  1414. * any time until labelled as non-experimental
  1415. *
  1416. * @access public
  1417. *
  1418. * @param array $pattern even keys are strings, odd are patterns (% and _)
  1419. * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
  1420. * @param string $field optional field name that is being matched against
  1421. * (might be required when emulating ILIKE)
  1422. *
  1423. * @return string SQL pattern
  1424. */
  1425. function matchPattern($pattern, $operator = null, $field = null)
  1426. {
  1427. $db =& $this->getDBInstance();
  1428. if (PEAR::isError($db)) {
  1429. return $db;
  1430. }
  1431. $match = '';
  1432. if (!is_null($operator)) {
  1433. $operator = strtoupper($operator);
  1434. switch ($operator) {
  1435. // case insensitive
  1436. case 'ILIKE':
  1437. if (is_null($field)) {
  1438. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  1439. 'case insensitive LIKE matching requires passing the field name', __FUNCTION__);
  1440. }
  1441. $db->loadModule('Function', null, true);
  1442. $match = $db->function->lower($field).' '.'LIKE ';
  1443. break;
  1444. // case sensitive
  1445. case 'LIKE':
  1446. $match = is_null($field) ? 'LIKE ' : $field.' LIKE ';
  1447. break;
  1448. default:
  1449. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  1450. 'not a supported operator type:'. $operator, __FUNCTION__);
  1451. }
  1452. }
  1453. $match.= "'";
  1454. foreach ($pattern as $key => $value) {
  1455. if ($key % 2) {
  1456. $match.= $value;
  1457. } else {
  1458. if ($operator === 'ILIKE') {
  1459. $value = strtolower($value);
  1460. }
  1461. $match.= $db->escapePattern($db->escape($value));
  1462. }
  1463. }
  1464. $match.= "'";
  1465. $match.= $this->patternEscapeString();
  1466. return $match;
  1467. }
  1468. // }}}
  1469. // {{{ patternEscapeString()
  1470. /**
  1471. * build string to define pattern escape character
  1472. *
  1473. * EXPERIMENTAL
  1474. *
  1475. * WARNING: this function is experimental and may change signature at
  1476. * any time until labelled as non-experimental
  1477. *
  1478. * @access public
  1479. *
  1480. * @return string define pattern escape character
  1481. */
  1482. function patternEscapeString()
  1483. {
  1484. return '';
  1485. }
  1486. // }}}
  1487. // {{{ mapNativeDatatype()
  1488. /**
  1489. * Maps a native array description of a field to a MDB2 datatype and length
  1490. *
  1491. * @param array $field native field description
  1492. * @return array containing the various possible types, length, sign, fixed
  1493. * @access public
  1494. */
  1495. function mapNativeDatatype($field)
  1496. {
  1497. $db =& $this->getDBInstance();
  1498. if (PEAR::isError($db)) {
  1499. return $db;
  1500. }
  1501. return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
  1502. 'method not implemented', __FUNCTION__);
  1503. }
  1504. // }}}
  1505. // {{{ mapPrepareDatatype()
  1506. /**
  1507. * Maps an mdb2 datatype to mysqli prepare type
  1508. *
  1509. * @param string $type
  1510. * @return string
  1511. * @access public
  1512. */
  1513. function mapPrepareDatatype($type)
  1514. {
  1515. $db =& $this->getDBInstance();
  1516. if (PEAR::isError($db)) {
  1517. return $db;
  1518. }
  1519. if (!empty($db->options['datatype_map'][$type])) {
  1520. $type = $db->options['datatype_map'][$type];
  1521. if (!empty($db->options['datatype_map_callback'][$type])) {
  1522. $parameter = array('type' => $type);
  1523. return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
  1524. }
  1525. }
  1526. return $type;
  1527. }
  1528. }
  1529. ?>