PageRenderTime 820ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/gespac/config/PEAR/MDB2/Driver/Datatype/Common.php

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