diff options
Diffstat (limited to 'program/lib/MDB2/Driver')
-rwxr-xr-x | program/lib/MDB2/Driver/Datatype/Common.php | 1263 | ||||
-rwxr-xr-x | program/lib/MDB2/Driver/Manager/Common.php | 616 |
2 files changed, 1879 insertions, 0 deletions
diff --git a/program/lib/MDB2/Driver/Datatype/Common.php b/program/lib/MDB2/Driver/Datatype/Common.php new file mode 100755 index 000000000..808fd1881 --- /dev/null +++ b/program/lib/MDB2/Driver/Datatype/Common.php @@ -0,0 +1,1263 @@ +<?php +// +----------------------------------------------------------------------+ +// | PHP versions 4 and 5 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | +// | Stig. S. Bakken, Lukas Smith | +// | All rights reserved. | +// +----------------------------------------------------------------------+ +// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | +// | API as well as database abstraction for PHP applications. | +// | This LICENSE is in the BSD license style. | +// | | +// | Redistribution and use in source and binary forms, with or without | +// | modification, are permitted provided that the following conditions | +// | are met: | +// | | +// | Redistributions of source code must retain the above copyright | +// | notice, this list of conditions and the following disclaimer. | +// | | +// | Redistributions in binary form must reproduce the above copyright | +// | notice, this list of conditions and the following disclaimer in the | +// | documentation and/or other materials provided with the distribution. | +// | | +// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | +// | Lukas Smith nor the names of his contributors may be used to endorse | +// | or promote products derived from this software without specific prior| +// | written permission. | +// | | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | +// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | +// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | +// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | +// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| +// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | +// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| +// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | +// | POSSIBILITY OF SUCH DAMAGE. | +// +----------------------------------------------------------------------+ +// | Author: Lukas Smith <smith@pooteeweet.org> | +// +----------------------------------------------------------------------+ +// +// $Id$ + +require_once 'MDB2/LOB.php'; + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith <smith@pooteeweet.org> + */ + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith <smith@pooteeweet.org> + */ +class MDB2_Driver_Datatype_Common extends MDB2_Module_Common +{ + var $valid_types = array( + 'text' => true, + 'boolean' => true, + 'integer' => true, + 'decimal' => true, + 'float' => true, + 'date' => true, + 'time' => true, + 'timestamp' => true, + 'clob' => true, + 'blob' => true, + ); + + /** + * contains all LOB objects created with this MDB2 instance + * @var array + * @access protected + */ + var $lobs = array(); + + // }}} + // {{{ setResultTypes() + + /** + * Define the list of types to be associated with the columns of a given + * result set. + * + * This function may be called before invoking fetchRow(), fetchOne() + * fetchCole() and fetchAll() so that the necessary data type + * conversions are performed on the data to be retrieved by them. If this + * function is not called, the type of all result set columns is assumed + * to be text, thus leading to not perform any conversions. + * + * @param resource $result result identifier + * @param string $types array variable that lists the + * data types to be expected in the result set columns. If this array + * contains less types than the number of columns that are returned + * in the result set, the remaining columns are assumed to be of the + * type text. Currently, the types clob and blob are not fully + * supported. + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function setResultTypes(&$result, $types) + { + $types = is_array($types) ? array_values($types) : array($types); + foreach ($types as $key => $type) { + if (!isset($this->valid_types[$type])) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'setResultTypes: ' . $type . ' for '. $key .' is not a supported column type'); + } + } + $result->types = $types; + return MDB2_OK; + } + + // }}} + // {{{ _baseConvertResult() + + /** + * general type conversion method + * + * @param mixed $value refernce to a value to be converted + * @param int $type constant that specifies which type to convert to + * @return object a MDB2 error on failure + * @access protected + */ + function _baseConvertResult($value, $type) + { + switch ($type) { + case 'text': + return $value; + case 'integer': + return intval($value); + case 'boolean': + return $value == 'Y'; + case 'decimal': + return $value; + case 'float': + return doubleval($value); + case 'date': + return $value; + case 'time': + return $value; + case 'timestamp': + return $value; + case 'clob': + case 'blob': + $this->lobs[] = array( + 'buffer' => null, + 'position' => 0, + 'lob_index' => null, + 'endOfLOB' => false, + 'ressource' => $value, + 'value' => null, + ); + end($this->lobs); + $lob_index = key($this->lobs); + $this->lobs[$lob_index]['lob_index'] = $lob_index; + return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+'); + } + + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_INVALID, null, null, + 'attempt to convert result value to an unknown type ' . $type); + } + + // }}} + // {{{ convertResult() + + /** + * convert a value to a RDBMS indepdenant MDB2 type + * + * @param mixed $value value to be converted + * @param int $type constant that specifies which type to convert to + * @return mixed converted value or a MDB2 error on failure + * @access public + */ + function convertResult($value, $type) + { + if (is_null($value)) { + return null; + } + return $this->_baseConvertResult($value, $type); + } + + // }}} + // {{{ convertResultRow() + + /** + * convert a result row + * + * @param resource $result result identifier + * @param array $row array with data + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function convertResultRow($types, $row) + { + if (is_array($types)) { + $current_column = -1; + foreach ($row as $key => $column) { + ++$current_column; + if (!isset($column) || !isset($types[$current_column])) { + continue; + } + $value = $this->convertResult($row[$key], $types[$current_column]); + if (PEAR::isError($value)) { + return $value; + } + $row[$key] = $value; + } + } + return $row; + } + + // }}} + // {{{ getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare + * of the given type + * + * @param string $type type to which the value should be converted to + * @param string $name name the field to be declared. + * @param string $field definition of the field + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getDeclaration($type, $name, $field) + { + if (!method_exists($this, "_get{$type}Declaration")) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError('type not defined: '.$type); + } + return $this->{"_get{$type}Declaration"}($name, $field); + } + + // }}} + // {{{ _getIntegerDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an integer type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * unsigned + * Boolean flag that indicates whether the field should be + * declared as unsigned integer if possible. + * + * default + * Integer value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getIntegerDeclaration($name, $field) + { + if (array_key_exists('unsigned', $field) && $field['unsigned']) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; + } + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'integer') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' INT'.$default.$notnull; + } + + // }}} + // {{{ _getTextDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an text type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTextDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'text') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT'; + return $name.' '.$type.$default.$notnull; + } + + // }}} + // {{{ _getCLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an character + * large object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getCLOBDeclaration($name, $field) + { + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT'; + return $name.' '.$type.$notnull; + } + + // }}} + // {{{ _getBLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an binary large + * object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBLOBDeclaration($name, $field) + { + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT'; + return $name.' '.$type.$notnull; + } + + // }}} + // {{{ _getBooleanDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a boolean type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnullL + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBooleanDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'boolean') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' CHAR (1)'.$default.$notnull; + } + + // }}} + // {{{ _getDateDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a date type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Date value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDateDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'date') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' CHAR ('.strlen('YYYY-MM-DD').')'.$default.$notnull; + } + + // }}} + // {{{ _getTimestampDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a timestamp + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Timestamp value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimestampDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'timestamp') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'.$default.$notnull; + } + + // }}} + // {{{ _getTimeDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a time + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Time value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimeDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'time') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' CHAR ('.strlen('HH:MM:SS').')'.$default.$notnull; + } + + // }}} + // {{{ _getFloatDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a float type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Float value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getFloatDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'float') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' TEXT'.$default.$notnull; + } + + // }}} + // {{{ _getDecimalDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a decimal type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Decimal value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDecimalDeclaration($name, $field) + { + $default = array_key_exists('default', $field) ? ' DEFAULT '. + $this->quote($field['default'], 'decimal') : ''; + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + return $name.' TEXT'.$default.$notnull; + } + + // }}} + // {{{ compareDefinition() + + /** + * Obtain an array of changes that may need to applied + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access public + */ + function compareDefinition($current, $previous) + { + $type = array_key_exists('type', $current) ? $current['type'] : null; + + if (!method_exists($this, "_compare{$type}Definition")) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'type "'.$current['type'].'" is not yet supported'); + } + + if (!array_key_exists('type', $previous) || $previous['type'] != $type) { + return $current; + } + + $change = $this->{"_compare{$type}Definition"}($current, $previous); + + $previous_notnull = array_key_exists('notnull', $previous) ? $previous['notnull'] : false; + $notnull = array_key_exists('notnull', $current) ? $current['notnull'] : false; + if ($previous_notnull != $notnull) { + $change['notnull'] = true; + } + + $previous_default = array_key_exists('default', $previous) ? $previous['default'] : + ($previous_notnull ? '' : null); + $default = array_key_exists('default', $current) ? $current['default'] : + ($notnull ? '' : null); + if ($previous_default !== $default) { + $change['default'] = true; + } + + return $change; + } + + // }}} + // {{{ _compareIntegerDefinition() + + /** + * Obtain an array of changes that may need to applied to an integer field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareIntegerDefinition($current, $previous) + { + $change = array(); + $previous_unsigned = array_key_exists('unsigned', $previous) ? $previous['unsigned'] : false; + $unsigned = array_key_exists('unsigned', $current) ? $current['unsigned'] : false; + if ($previous_unsigned != $unsigned) { + $change['unsigned'] = true; + } + $previous_autoincrement = array_key_exists('autoincrement', $previous) ? $previous['autoincrement'] : false; + $autoincrement = array_key_exists('autoincrement', $current) ? $current['autoincrement'] : false; + if ($previous_autoincrement != $autoincrement) { + $change['autoincrement'] = true; + } + return $change; + } + + // }}} + // {{{ _compareTextDefinition() + + /** + * Obtain an array of changes that may need to applied to an text field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTextDefinition($current, $previous) + { + $change = array(); + $previous_length = array_key_exists('length', $previous) ? $previous['length'] : 0; + $length = array_key_exists('length', $current) ? $current['length'] : 0; + if ($previous_length != $length) { + $change['length'] = true; + } + return $change; + } + + // }}} + // {{{ _compareCLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an CLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareCLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareBLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an BLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareBLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareDateDefinition() + + /** + * Obtain an array of changes that may need to applied to an date field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareDateDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimeDefinition() + + /** + * Obtain an array of changes that may need to applied to an time field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTimeDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimestampDefinition() + + /** + * Obtain an array of changes that may need to applied to an timestamp field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTimestampDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareBooleanDefinition() + + /** + * Obtain an array of changes that may need to applied to an boolean field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareBooleanDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareFloatDefinition() + + /** + * Obtain an array of changes that may need to applied to an float field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareFloatDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareDecimalDefinition() + + /** + * Obtain an array of changes that may need to applied to an decimal field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareDecimalDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ quote() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param string $type type to which the value should be converted to + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access public + */ + function quote($value, $type = null, $quote = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_null($value) + || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) + ) { + if (!$quote) { + return null; + } + return 'NULL'; + } + + if (is_null($type)) { + switch (gettype($value)) { + case 'integer': + $type = 'integer'; + break; + case 'double': + // todo + $type = 'decimal'; + $type = 'float'; + break; + case 'boolean': + $type = 'boolean'; + break; + case 'array': + case 'object': + $type = 'text'; + break; + default: + if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) { + $type = 'timestamp'; + } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) { + $type = 'time'; + } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + $type = 'date'; + } else { + $type = 'text'; + } + break; + } + } + + if (!method_exists($this, "_quote{$type}")) { + return $db->raiseError('type not defined: '.$type); + } + $value = $this->{"_quote{$type}"}($value); + + // ugly hack to remove single quotes + if (!$quote && isset($value[0]) && $value[0] === "'") { + $value = substr($value, 1, -1); + } + + return $value; + } + + // }}} + // {{{ _quoteInteger() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteInteger($value) + { + return (int)$value; + } + + // }}} + // {{{ _quoteText() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that already contains any DBMS specific + * escaped character sequences. + * @access protected + */ + function _quoteText($value) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return "'".$db->escape($value)."'"; + } + + // }}} + // {{{ _readFile() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param $value + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _readFile($value) + { + $close = false; + if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { + $close = true; + if ($match[1] == 'file://') { + $value = $match[2]; + } + $value = @fopen($value, 'r'); + } + + if (is_resource($value)) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $fp = $value; + $value = ''; + while (!@feof($fp)) { + $value.= @fread($fp, $db->options['lob_buffer_length']); + } + if ($close) { + @fclose($fp); + } + } + + return $value; + } + + // }}} + // {{{ _quoteLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param $value + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteLOB($value) + { + $value = $this->_readFile($value); + return $this->_quoteText($value); + } + + // }}} + // {{{ _quoteCLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param $value + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteCLOB($value) + { + return $this->_quoteLOB($value); + } + + // }}} + // {{{ _quoteBLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param $value + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBLOB($value) + { + return $this->_quoteLOB($value); + } + + // }}} + // {{{ _quoteBoolean() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBoolean($value) + { + return ($value ? "'Y'" : "'N'"); + } + + // }}} + // {{{ _quoteDate() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDate($value) + { + return $this->_quoteText($value); + } + + // }}} + // {{{ _quoteTimestamp() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTimestamp($value) + { + return $this->_quoteText($value); + } + + // }}} + // {{{ _quoteTime() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTime($value) + { + return $this->_quoteText($value); + } + + // }}} + // {{{ _quoteFloat() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteFloat($value) + { + return $this->_quoteText($value); + } + + // }}} + // {{{ _quoteDecimal() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDecimal($value) + { + return $this->_quoteText($value); + } + + // }}} + // {{{ writeLOBToFile() + + /** + * retrieve LOB from the database + * + * @param resource $lob stream handle + * @param string $file name of the file into which the LOb should be fetched + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function writeLOBToFile($lob, $file) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $fp = fopen($file, 'wb'); + while (!feof($lob)) { + $result = fread($lob, $db->options['lob_buffer_length']); + $read = strlen($result); + if (fwrite($fp, $result, $read) != $read) { + fclose($fp); + return $db->raiseError(MDB2_ERROR, null, null, + 'writeLOBToFile: could not write to the output file'); + } + } + fclose($fp); + return MDB2_OK; + } + + // }}} + // {{{ _retrieveLOB() + + /** + * retrieve LOB from the database + * + * @param resource $lob stream handle + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function _retrieveLOB(&$lob) + { + if (is_null($lob['value'])) { + $lob['value'] = $lob['ressource']; + } + return MDB2_OK; + } + + // }}} + // {{{ readLOB() + + /** + * Read data from large object input stream. + * + * @param resource $lob stream handle + * @param string $data reference to a variable that will hold data + * to be read from the large object input stream + * @param integer $length value that indicates the largest ammount ofdata + * to be read from the large object input stream. + * @return mixed the effective number of bytes read from the large object + * input stream on sucess or an MDB2 error object. + * @access public + * @see endOfLOB() + */ + function _readLOB($lob, $length) + { + return substr($lob['value'], $lob['position'], $length); + } + + // }}} + // {{{ _endOfLOB() + + /** + * Determine whether it was reached the end of the large object and + * therefore there is no more data to be read for the its input stream. + * + * @param resource $lob stream handle + * @return mixed true or false on success, a MDB2 error on failure + * @access protected + */ + function _endOfLOB($lob) + { + return $lob['endOfLOB']; + } + + // }}} + // {{{ destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param resource $lob stream handle + * @access public + */ + function destroyLOB($lob) + { + $lob_data = stream_get_meta_data($lob); + $lob_index = $lob_data['wrapper_data']->lob_index; + fclose($lob); + if (isset($this->lobs[$lob_index])) { + $this->_destroyLOB($lob_index); + unset($this->lobs[$lob_index]); + } + return MDB2_OK; + } + + // }}} + // {{{ _destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param int $lob_index from the lob array + * @access private + */ + function _destroyLOB($lob_index) + { + return MDB2_OK; + } + + // }}} + // {{{ implodeArray() + + /** + * apply a type to all values of an array and return as a comma seperated string + * useful for generating IN statements + * + * @access public + * + * @param array $array data array + * @param string $type determines type of the field + * + * @return string comma seperated values + */ + function implodeArray($array, $type = false) + { + if (!is_array($array) || empty($array)) { + return 'NULL'; + } + if ($type) { + foreach ($array as $value) { + $return[] = $this->quote($value, $type); + } + } else { + $return = $array; + } + return implode(', ', $return); + } +} + +?>
\ No newline at end of file diff --git a/program/lib/MDB2/Driver/Manager/Common.php b/program/lib/MDB2/Driver/Manager/Common.php new file mode 100755 index 000000000..a9de44163 --- /dev/null +++ b/program/lib/MDB2/Driver/Manager/Common.php @@ -0,0 +1,616 @@ +<?php +// +----------------------------------------------------------------------+ +// | PHP versions 4 and 5 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | +// | Stig. S. Bakken, Lukas Smith | +// | All rights reserved. | +// +----------------------------------------------------------------------+ +// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | +// | API as well as database abstraction for PHP applications. | +// | This LICENSE is in the BSD license style. | +// | | +// | Redistribution and use in source and binary forms, with or without | +// | modification, are permitted provided that the following conditions | +// | are met: | +// | | +// | Redistributions of source code must retain the above copyright | +// | notice, this list of conditions and the following disclaimer. | +// | | +// | Redistributions in binary form must reproduce the above copyright | +// | notice, this list of conditions and the following disclaimer in the | +// | documentation and/or other materials provided with the distribution. | +// | | +// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | +// | Lukas Smith nor the names of his contributors may be used to endorse | +// | or promote products derived from this software without specific prior| +// | written permission. | +// | | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | +// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | +// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | +// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | +// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| +// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | +// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| +// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | +// | POSSIBILITY OF SUCH DAMAGE. | +// +----------------------------------------------------------------------+ +// | Author: Lukas Smith <smith@pooteeweet.org> | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith <smith@pooteeweet.org> + */ + +/** + * Base class for the management modules that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith <smith@pooteeweet.org> + */ +class MDB2_Driver_Manager_Common extends MDB2_Module_Common +{ + // }}} + // {{{ getFieldDeclarationList() + + /** + * get declaration of a number of field in bulk + * + * @param string $fields a multidimensional associative array. + * The first dimension determines the field name, while the second + * dimension is keyed with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * + * @return mixed string on success, a MDB2 error on failure + * @access public + */ + function getFieldDeclarationList($fields) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_array($fields)) { + foreach ($fields as $field_name => $field) { + $query = $db->getDeclaration($field['type'], $field_name, $field); + if (PEAR::isError($query)) { + return $query; + } + $query_fields[] = $query; + } + return implode(',', $query_fields); + } + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'getFieldDeclarationList: the definition of the table "'.$table_name.'" does not contain any fields'); + } + + // }}} + // {{{ _isSequenceName() + + /** + * list all tables in the current database + * + * @param string $sqn string that containts name of a potential sequence + * @return mixed name of the sequence if $sqn is a name of a sequence, else false + * @access protected + */ + function _isSequenceName($sqn) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $seq_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['seqname_format']).'$/i'; + $seq_name = preg_replace($seq_pattern, '\\1', $sqn); + if ($seq_name && $sqn == $db->getSequenceName($seq_name)) { + return $seq_name; + } + return false; + } + + // }}} + // {{{ createDatabase() + + /** + * create a new database + * + * @param string $name name of the database that should be created + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createDatabase($database) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'createDatabase: database creation is not supported'); + } + + // }}} + // {{{ dropDatabase() + + /** + * drop an existing database + * + * @param string $name name of the database that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropDatabase($database) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'dropDatabase: database dropping is not supported'); + } + + // }}} + // {{{ createTable() + + /** + * create a new table + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * The indexes of the array entries are the names of the fields of the table an + * the array entry values are associative arrays like those that are meant to be + * passed with the field definitions to get[Type]Declaration() functions. + * + * Example + * array( + * + * 'id' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * 'notnull' => 1 + * 'default' => 0 + * ), + * 'name' => array( + * 'type' => 'text', + * 'length' => 12 + * ), + * 'password' => array( + * 'type' => 'text', + * 'length' => 12 + * ) + * ); + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createTable($name, $fields) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!$name) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: no valid table name specified'); + } + if (empty($fields)) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: no fields specified for table "'.$name.'"'); + } + $query_fields = $this->getFieldDeclarationList($fields); + if (PEAR::isError($query_fields)) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: unkown error'); + } + $query = "CREATE TABLE $name ($query_fields)"; + return $db->query($query); + } + + // }}} + // {{{ dropTable() + + /** + * drop an existing table + * + * @param string $name name of the table that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropTable($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->query("DROP TABLE $name"); + } + + // }}} + // {{{ alterTable() + + /** + * alter an existing table + * + * @param string $name name of the table that is intended to be changed. + * @param array $changes associative array that contains the details of each type + * of change that is intended to be performed. The types of + * changes that are currently supported are defined as follows: + * + * name + * + * New name for the table. + * + * add + * + * Associative array with the names of fields to be added as + * indexes of the array. The value of each entry of the array + * should be set to another associative array with the properties + * of the fields to be added. The properties of the fields should + * be the same as defined by the Metabase parser. + * + * + * remove + * + * Associative array with the names of fields to be removed as indexes + * of the array. Currently the values assigned to each entry are ignored. + * An empty array should be used for future compatibility. + * + * rename + * + * Associative array with the names of fields to be renamed as indexes + * of the array. The value of each entry of the array should be set to + * another associative array with the entry named name with the new + * field name and the entry named Declaration that is expected to contain + * the portion of the field declaration already in DBMS specific SQL code + * as it is used in the CREATE TABLE statement. + * + * change + * + * Associative array with the names of the fields to be changed as indexes + * of the array. Keep in mind that if it is intended to change either the + * name of a field and any other properties, the change array entries + * should have the new names of the fields as array indexes. + * + * The value of each entry of the array should be set to another associative + * array with the properties of the fields to that are meant to be changed as + * array entries. These entries should be assigned to the new values of the + * respective properties. The properties of the fields should be the same + * as defined by the Metabase parser. + * + * Example + * array( + * 'name' => 'userlist', + * 'add' => array( + * 'quota' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * ) + * ), + * 'remove' => array( + * 'file_limit' => array(), + * 'time_limit' => array() + * ), + * 'change' => array( + * 'gender' => array( + * 'default' => 'M', + * ) + * ), + * 'rename' => array( + * 'sex' => array( + * 'name' => 'gender', + * ) + * ) + * ) + * @param boolean $check indicates whether the function should just check if the DBMS driver + * can perform the requested table alterations if the value is true or + * actually perform them otherwise. + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function alterTable($name, $changes, $check) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'alterTable: database table alterations are not supported'); + } + + // }}} + // {{{ listDatabases() + + /** + * list all databases + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listDatabases() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listDatabases: list databases is not supported'); + } + + // }}} + // {{{ listUsers() + + /** + * list all users + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listUsers() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listUsers: list user is not supported'); + } + + // }}} + // {{{ listViews() + + /** + * list all views in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listViews() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listViews: list view is not supported'); + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listFunctions: list function is not supported'); + } + + // }}} + // {{{ listTables() + + /** + * list all tables in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTables() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTables: list tables is not supported'); + } + + // }}} + // {{{ listTableFields() + + /** + * list all fields in a tables in the current database + * + * @param string $table name of table that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTableFields($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTableFields: list table fields is not supported'); + } + + // }}} + // {{{ createIndex() + + /** + * get the stucture of a field into an array + * + * @param string $table name of the table on which the index is to be created + * @param string $name name of the index to be created + * @param array $definition associative array that defines properties of the index to be created. + * Currently, only one property named FIELDS is supported. This property + * is also an associative with the names of the index fields as array + * indexes. Each entry of this array is set to another type of associative + * array that specifies properties of the index that are specific to + * each field. + * + * Currently, only the sorting property is supported. It should be used + * to define the sorting direction of the index. It may be set to either + * ascending or descending. + * + * Not all DBMS support index sorting direction configuration. The DBMS + * drivers of those that do not support it ignore this property. Use the + * function supports() to determine whether the DBMS driver can manage indexes. + * + * Example + * array( + * 'fields' => array( + * 'user_name' => array( + * 'sorting' => 'ascending' + * ), + * 'last_login' => array() + * ) + * ) + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createIndex($table, $name, $definition) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'createIndex: Creating Indexes is not supported'); + } + + // }}} + // {{{ dropIndex() + + /** + * drop existing index + * + * @param string $table name of table that should be used in method + * @param string $name name of the index to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropIndex($table, $name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->query("DROP INDEX $name"); + } + + // }}} + // {{{ listTableIndexes() + + /** + * list all indexes in a table + * + * @param string $table name of table that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTableIndexes($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTableIndexes: List Indexes is not supported'); + } + + // }}} + // {{{ createSequence() + + /** + * create sequence + * + * @param string $seq_name name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createSequence($seq_name, $start = 1) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'createSequence: sequence creation not supported'); + } + + // }}} + // {{{ dropSequence() + + /** + * drop existing sequence + * + * @param string $seq_name name of the sequence to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropSequence($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'dropSequence: sequence dropping not supported'); + } + + // }}} + // {{{ listSequences() + + /** + * list all sequences in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listSequences() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listSequences: List sequences is not supported'); + } +} + +?> |