From d13c36941c585e84c8986e1eb47a296646cc7a21 Mon Sep 17 00:00:00 2001 From: svncommit Date: Wed, 26 Oct 2005 07:18:10 +0000 Subject: [PATCH] missing mdb2 files --- program/lib/MDB2/Date.php | 180 +++ program/lib/MDB2/Driver/Datatype/Common.php | 1263 +++++++++++++++++++ program/lib/MDB2/Driver/Manager/Common.php | 616 +++++++++ program/lib/MDB2/Extended.php | 605 +++++++++ program/lib/MDB2/Iterator.php | 285 +++++ program/lib/MDB2/LOB.php | 146 +++ program/lib/MDB2/Wrapper/peardb.php | 750 +++++++++++ 7 files changed, 3845 insertions(+) create mode 100755 program/lib/MDB2/Date.php create mode 100755 program/lib/MDB2/Driver/Datatype/Common.php create mode 100755 program/lib/MDB2/Driver/Manager/Common.php create mode 100755 program/lib/MDB2/Extended.php create mode 100755 program/lib/MDB2/Iterator.php create mode 100755 program/lib/MDB2/LOB.php create mode 100755 program/lib/MDB2/Wrapper/peardb.php diff --git a/program/lib/MDB2/Date.php b/program/lib/MDB2/Date.php new file mode 100755 index 000000000..df3af2c3d --- /dev/null +++ b/program/lib/MDB2/Date.php @@ -0,0 +1,180 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Several methods to convert the MDB2 native timestamp format (ISO based) + * to and from data structures that are convienient to worth with in side of php. + * For more complex date arithmetic please take a look at the Date package in PEAR + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Date +{ + // {{{ mdbNow() + + /** + * return the current datetime + * + * @return string current datetime in the MDB2 format + * @access public + */ + function mdbNow() + { + return date('Y-m-d H:i:s'); + } + + // }}} + // {{{ mdbToday() + + /** + * return the current date + * + * @return string current date in the MDB2 format + * @access public + */ + function mdbToday() + { + return date('Y-m-d'); + } + + // }}} + // {{{ mdbTime() + + /** + * return the current time + * + * @return string current time in the MDB2 format + * @access public + */ + function mdbTime() + { + return date('H:i:s'); + } + + // }}} + // {{{ date2Mdbstamp() + + /** + * convert a date into a MDB2 timestamp + * + * @param integer $hour hour of the date + * @param integer $minute minute of the date + * @param integer $second second of the date + * @param integer $month month of the date + * @param integer $day day of the date + * @param integer $year year of the date + * @return string a valid MDB2 timestamp + * @access public + */ + function date2Mdbstamp($hour = null, $minute = null, $second = null, + $month = null, $day = null, $year = null) + { + return MDB2_Date::unix2Mdbstamp(mktime($hour, $minute, $second, $month, $day, $year, -1)); + } + + // }}} + // {{{ unix2Mdbstamp() + + /** + * convert a unix timestamp into a MDB2 timestamp + * + * @param integer $unix_timestamp a valid unix timestamp + * @return string a valid MDB2 timestamp + * @access public + */ + function unix2Mdbstamp($unix_timestamp) + { + return date('Y-m-d H:i:s', $unix_timestamp); + } + + // }}} + // {{{ mdbstamp2Unix() + + /** + * convert a MDB2 timestamp into a unix timestamp + * + * @param integer $mdb_timestamp a valid MDB2 timestamp + * @return string unix timestamp with the time stored in the MDB2 format + * @access public + */ + function mdbstamp2Unix($mdb_timestamp) + { + $arr = MDB2_Date::mdbstamp2Date($mdb_timestamp); + + return mktime($arr['hour'], $arr['minute'], $arr['second'], $arr['month'], $arr['day'], $arr['year'], -1); + } + + // }}} + // {{{ mdbstamp2Date() + + /** + * convert a MDB2 timestamp into an array containing all + * values necessary to pass to php's date() function + * + * @param integer $mdb_timestamp a valid MDB2 timestamp + * @return array with the time split + * @access public + */ + function mdbstamp2Date($mdb_timestamp) + { + list($arr['year'], $arr['month'], $arr['day'], $arr['hour'], $arr['minute'], $arr['second']) = + sscanf($mdb_timestamp, "%04u-%02u-%02u %02u:%02u:%02u"); + return $arr; + } + + // }}} +} + +?> 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 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ + +require_once 'MDB2/LOB.php'; + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +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 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Base class for the management modules that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +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'); + } +} + +?> diff --git a/program/lib/MDB2/Extended.php b/program/lib/MDB2/Extended.php new file mode 100755 index 000000000..cc308bfe0 --- /dev/null +++ b/program/lib/MDB2/Extended.php @@ -0,0 +1,605 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Used by autoPrepare() + */ +define('MDB2_AUTOQUERY_INSERT', 1); +define('MDB2_AUTOQUERY_UPDATE', 2); + +/** + * MDB2_Extended: class which adds several high level methods to MDB2 + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Extended extends MDB2_Module_Common +{ + // }}} + // {{{ autoPrepare() + + /** + * Make automaticaly an insert or update query and call prepare() with it + * + * @param string $table name of the table + * @param array $table_fields ordered array containing the fields names + * @param int $mode type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string $where in case of update queries, this string will be put after the sql WHERE statement + * @return resource handle for the query + * @param mixed $types array that contains the types of the placeholders + * @param mixed $result_types array that contains the types of the columns in + * the result set + * @see buildManipSQL + * @access public + */ + function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null, $result_types = null) + { + $query = $this->buildManipSQL($table, $table_fields, $mode, $where); + if (PEAR::isError($query)) { + return $query; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->prepare($query, $types, $result_types); + } + + // {{{ + // }}} autoExecute() + + /** + * Make automaticaly an insert or update query and call prepare() and execute() with it + * + * @param string $table name of the table + * @param array $fields_values assoc ($key=>$value) where $key is a field name and $value its value + * @param int $mode type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string $where in case of update queries, this string will be put after the sql WHERE statement + * @param mixed $types array that contains the types of the placeholders + * @param mixed $result_types array that contains the types of the columns in + * the result set + * @param mixed $result_class string which specifies which result class to use + * @return mixed a new MDB2_Result or a MDB2 Error Object when fail + * @see buildManipSQL + * @see autoPrepare + * @access public + */ + function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null, $result_types = null, $result_class = true) + { + $stmt = $this->autoPrepare($table, array_keys($fields_values), $mode, $where, $types, $result_types); + if (PEAR::isError($stmt)) { + return $stmt; + } + $params = array_values($fields_values); + $stmt->bindParamArray($params); + $result =& $stmt->execute($result_class); + $stmt->free(); + return $result; + } + + // {{{ + // }}} buildManipSQL() + + /** + * Make automaticaly an sql query for prepare() + * + * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), MDB2_AUTOQUERY_INSERT) + * will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) + * NB : - This belongs more to a SQL Builder class, but this is a simple facility + * - Be carefull ! If you don't give a $where param with an UPDATE query, all + * the records of the table will be updated ! + * + * @param string $table name of the table + * @param array $table_fields ordered array containing the fields names + * @param int $mode type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string $where in case of update queries, this string will be put after the sql WHERE statement + * @return string sql query for prepare() + * @access public + */ + function buildManipSQL($table, $table_fields, $mode, $where = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (count($table_fields) == 0) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + switch ($mode) { + case MDB2_AUTOQUERY_INSERT: + $cols = implode(', ', $table_fields); + $values = '?'.str_repeat(', ?', count($table_fields)-1); + return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')'; + break; + case MDB2_AUTOQUERY_UPDATE: + $set = implode(' = ?, ', $table_fields).' = ?'; + $sql = 'UPDATE '.$table.' SET '.$set; + if ($where !== false) { + $sql.= ' WHERE '.$where; + } + return $sql; + break; + } + return $db->raiseError(MDB2_ERROR_SYNTAX); + } + + // {{{ + // }}} limitQuery() + + /** + * Generates a limited query + * + * @param string $query query + * @param mixed $types array that contains the types of the columns in + * the result set + * @param integer $from the row to start to fetching + * @param integer $count the numbers of rows to fetch + * @param mixed $result_class string which specifies which result class to use + * @return mixed a valid ressource pointer or a MDB2 Error Object + * @access public + */ + function &limitQuery($query, $types, $count, $from = 0, $result_class = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->setLimit($count, $from); + if (PEAR::isError($result)) { + return $result; + } + $result =& $db->query($query, $types, $result_class); + return $result; + } + + // {{{ + // }}} getOne() + + /** + * Fetch the first column of the first row of data returned from + * a query. Takes care of doing the query and freeing the results + * when finished. + * + * @param string $query the SQL query + * @param string $type string that contains the type of the column in the + * result set + * @param array $params if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array $param_types array that contains the types of the values + * defined in $params + * @param mixed $colnum which column to return + * @return mixed MDB2_OK or data on success, a MDB2 error on failure + * @access public + */ + function getOne($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (count($params) == 0) { + return $db->queryOne($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $one = $result->fetchOne($colnum); + $stmt->free(); + $result->free(); + return $one; + } + + // }}} + // {{{ getRow() + + /** + * Fetch the first row of data returned from a query. Takes care + * of doing the query and freeing the results when finished. + * + * @param string $query the SQL query + * @param array $types array that contains the types of the columns in + * the result set + * @param array $params array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array $param_types array that contains the types of the values + * defined in $params + * @param integer $fetchmode the fetch mode to use + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function getRow($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryRow($query, $types, $fetchmode); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $row = $result->fetchRow($fetchmode); + $stmt->free(); + $result->free(); + return $row; + } + + // }}} + // {{{ getCol() + + /** + * Fetch a single column from a result set and return it as an + * indexed array. + * + * @param string $query the SQL query + * @param string $type string that contains the type of the column in the + * result set + * @param array $params array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array $param_types array that contains the types of the values + * defined in $params + * @param mixed $colnum which column to return + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function getCol($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (count($params) == 0) { + return $db->queryCol($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $col = $result->fetchCol($colnum); + $stmt->free(); + $result->free(); + return $col; + } + + // }}} + // {{{ getAll() + + /** + * Fetch all the rows returned from a query. + * + * @param string $query the SQL query + * @param array $types array that contains the types of the columns in + * the result set + * @param array $params array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array $param_types array that contains the types of the values + * defined in $params + * @param integer $fetchmode the fetch mode to use + * @param boolean $rekey if set to true, the $all will have the first + * column as its first dimension + * @param boolean $force_array used only when the query returns exactly + * two columns. If true, the values of the returned array will be + * one-element arrays instead of scalars. + * @param boolean $group if true, the values of the returned array is + * wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function getAll($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, + $rekey = false, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + + // }}} + // {{{ getAssoc() + + /** + * Fetch the entire result set of a query and return it as an + * associative array using the first column as the key. + * + * If the result set contains more than two columns, the value + * will be an array of the values from column 2-n. If the result + * set contains only two columns, the returned value will be a + * scalar with the value of the second column (unless forced to an + * array with the $force_array parameter). A MDB error code is + * returned on errors. If the result set contains fewer than two + * columns, a MDB2_ERROR_TRUNCATED error is returned. + * + * For example, if the table 'mytable' contains: + * + * ID TEXT DATE + * -------------------------------- + * 1 'one' 944679408 + * 2 'two' 944679408 + * 3 'three' 944679408 + * + * Then the call getAssoc('SELECT id,text FROM mytable') returns: + * array( + * '1' => 'one', + * '2' => 'two', + * '3' => 'three', + * ) + * + * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: + * array( + * '1' => array('one', '944679408'), + * '2' => array('two', '944679408'), + * '3' => array('three', '944679408') + * ) + * + * If the more than one row occurs with the same value in the + * first column, the last row overwrites all previous ones by + * default. Use the $group parameter if you don't want to + * overwrite like this. Example: + * + * getAssoc('SELECT category,id,name FROM mytable', null, null + * MDB2_FETCHMODE_ASSOC, false, true) returns: + * array( + * '1' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ), + * '9' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ) + * ) + * + * Keep in mind that database functions in PHP usually return string + * values for results regardless of the database's internal type. + * + * @param string $query the SQL query + * @param array $types array that contains the types of the columns in + * the result set + * @param array $params array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array $param_types array that contains the types of the values + * defined in $params + * @param boolean $force_array used only when the query returns + * exactly two columns. If TRUE, the values of the returned array + * will be one-element arrays instead of scalars. + * @param boolean $group if TRUE, the values of the returned array + * is wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * @return array associative array with results from the query. + * @access public + */ + function getAssoc($query, $types = null, $params = array(), $param_types = null, + $fetchmode = MDB2_FETCHMODE_DEFAULT, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, true, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + + // }}} + // {{{ executeMultiple() + + /** + * This function does several execute() calls on the same statement handle. + * $params must be an array indexed numerically from 0, one execute call is + * done for every 'row' in the array. + * + * If an error occurs during execute(), executeMultiple() does not execute + * the unfinished rows, but rather returns that error. + * + * @param resource $stmt query handle from prepare() + * @param array $params numeric array containing the + * data to insert into the query + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access public + * @see prepare(), execute() + */ + function executeMultiple(&$stmt, $params = null) + { + for ($i = 0, $j = count($params); $i < $j; $i++) { + $stmt->bindParamArray($params[$i]); + $result = $stmt->execute(); + if (PEAR::isError($result)) { + return $result; + } + } + return MDB2_OK; + } + + // }}} + // {{{ getBeforeID() + + /** + * returns the next free id of a sequence if the RDBMS + * does not support auto increment + * + * @param string $table name of the table into which a new row was inserted + * @param boolean $ondemand when true the seqence is + * automatic created, if it + * not exists + * + * @return mixed MDB2 Error Object or id + * @access public + */ + function getBeforeID($table, $field, $ondemand = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + $seq = $table.(empty($field) ? '' : '_'.$field); + $id = $db->nextID($seq, $ondemand); + if (PEAR::isError($id)) { + return $id; + } + return $db->quote($id, 'integer'); + } + return 'NULL'; + } + + // }}} + // {{{ getAfterID() + + /** + * returns the autoincrement ID if supported or $id + * + * @param mixed $id value as returned by getBeforeId() + * @param string $table name of the table into which a new row was inserted + * @return mixed MDB2 Error Object or id + * @access public + */ + function getAfterID($id, $table, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + return $id; + } + return $db->lastInsertID($table, $field); + } + +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Iterator.php b/program/lib/MDB2/Iterator.php new file mode 100755 index 000000000..13db77a97 --- /dev/null +++ b/program/lib/MDB2/Iterator.php @@ -0,0 +1,285 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Iterator implements Iterator +{ + protected $fetchmode; + protected $result; + protected $row; + + // {{{ constructor + + /** + * Constructor + */ + public function __construct($result, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $this->result = $result; + $this->fetchmode = $fetchmode; + } + + // }}} + // {{{ seek() + + /** + * seek forward to a specific row in a result set + * + * @param int $rownum number of the row where the data can be found + * @return void + * @access public + */ + public function seek($rownum) + { + $this->row = null; + if ($this->result) { + $this->result->seek($rownum); + } + } + + // }}} + // {{{ next() + + /** + * Fetch next row of data + * + * @return void + * @access public + */ + public function next() + { + $this->row = null; + } + + // }}} + // {{{ current() + + /** + * return a row of data + * + * @return void + * @access public + */ + public function current() + { + if (is_null($this->row)) { + $row = $this->result->fetchRow($this->fetchmode); + if (PEAR::isError($row)) { + $row = false; + } + $this->row = $row; + } + return $this->row; + } + + // }}} + // {{{ valid() + + /** + * check if the end of the result set has been reached + * + * @return mixed true or false on sucess, a MDB2 error on failure + * @access public + */ + public function valid() + { + return (bool)$this->current(); + } + + // }}} + // {{{ free() + + /** + * Free the internal resources associated with result. + * + * @return boolean true on success, false if result is invalid + * @access public + */ + public function free() + { + if ($this->result) { + return $this->result->free(); + } + $this->result = null; + $this->row = null; + return false; + } + + // }}} + // {{{ key() + + /** + * nothing, but Iterator wants to implement this. + * + * @return void + * @access public + */ + public function key() + { + if ($this->result) { + return $this->result->rowCount(); + } + return false; + } + + // }}} + // {{{ rewind() + + /** + * seek to the first row in a result set + * + * @return void + * @access public + */ + public function rewind() + { + } + + // }}} + // {{{ destructor + + /** + * Destructor + */ + public function __destruct() + { + $this->free(); + } +} + +class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator +{ + // }}} + // {{{ valid() + + /** + * check if the end of the result set has been reached + * + * @return mixed true or false on sucess, a MDB2 error on failure + * @access public + */ + public function valid() + { + if ($this->result) { + return $this->result->valid(); + } + return false; + } + + // }}} + // {{{count() + + /** + * returns the number of rows in a result object + * + * @return mixed MDB2 Error Object or the number of rows + * @access public + */ + public function count() + { + if ($this->result) { + return $this->result->numRows(); + } + return false; + } + + // }}} + // {{{ hasPrev() + + /** + * check if there is a previous row + * + * @return mixed true or false on sucess, a MDB2 error on failure + * @access public + */ + public function hasPrev() + { + if ($this->result) { + return $this->result->rowCount() > 0; + } + return false; + } + + // }}} + // {{{ rewind() + + /** + * seek to the first row in a result set + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + public function rewind() + { + $this->seek(0); + } + + // }}} + // {{{ prev() + + /** + * move internal row point to the previous row + * Fetch and return a row of data + * + * @return void + * @access public + */ + public function prev() + { + if ($this->hasPrev()) { + $this->seek($this->result->rowCount() - 1); + } else { + return false; + } + return $this->next(); + } +} + +?> \ No newline at end of file diff --git a/program/lib/MDB2/LOB.php b/program/lib/MDB2/LOB.php new file mode 100755 index 000000000..c17abc9fb --- /dev/null +++ b/program/lib/MDB2/LOB.php @@ -0,0 +1,146 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'MDB2.php'; + +class MDB2_LOB +{ + var $db_index; + var $lob_index; + var $lob; + + function stream_open($path, $mode, $options, &$opened_path) + { + if (!preg_match('/^rb?\+?$/', $mode)) { + return false; + } + $url = parse_url($path); + if (!array_key_exists('host', $url) && !array_key_exists('user', $url)) { + return false; + } + $this->db_index = $url['host']; + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return false; + } + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $this->lob_index = $url['user']; + if (!isset($db->datatype->lobs[$this->lob_index])) { + return false; + } + $this->lob =& $db->datatype->lobs[$this->lob_index]; + $db->datatype->_retrieveLOB($this->lob); + return true; + } + + function stream_read($count) + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + + $data = $db->datatype->_readLOB($this->lob, $count); + $length = strlen($data); + if ($length == 0) { + $this->lob['endOfLOB'] = true; + } + $this->lob['position'] += $length; + return $data; + } + } + + function stream_write($data) + { + return 0; + } + + function stream_tell() + { + return $this->lob['position']; + } + + function stream_eof() + { + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return true; + } + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $result = $db->datatype->_endOfLOB($this->lob); + if (version_compare(phpversion(), "5.0", ">=") + && version_compare(phpversion(), "5.1", "<") + ) { + return !$result; + } + return $result; + } + + function stream_seek($offset, $whence) + { + return false; + } + + function stream_close() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + if (isset($db->datatype->lobs[$this->lob_index])) { + $db->datatype->_destroyLOB($this->lob_index); + unset($db->datatype->lobs[$this->lob_index]); + } + } + } +} + +if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) { + MDB2::raiseError(); + return false; +} + +?> \ No newline at end of file diff --git a/program/lib/MDB2/Wrapper/peardb.php b/program/lib/MDB2/Wrapper/peardb.php new file mode 100755 index 000000000..a7123b3cc --- /dev/null +++ b/program/lib/MDB2/Wrapper/peardb.php @@ -0,0 +1,750 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +/** + * Wrapper that makes MDB2 behave like PEAR DB + * WARNING: this wrapper is broken and unmaintained + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'MDB2.php'; + +/* + * The method mapErrorCode in each MDB2_dbtype implementation maps + * native error codes to one of these. + * + * If you add an error code here, make sure you also add a textual + * version of it in DB::errorMessage(). + */ + +define('DB_OK', MDB2_OK); +define('DB_ERROR', MDB2_ERROR); +define('DB_ERROR_SYNTAX', MDB2_ERROR_SYNTAX); +define('DB_ERROR_CONSTRAINT', MDB2_ERROR_CONSTRAINT); +define('DB_ERROR_NOT_FOUND', MDB2_ERROR_NOT_FOUND); +define('DB_ERROR_ALREADY_EXISTS', MDB2_ERROR_ALREADY_EXISTS); +define('DB_ERROR_UNSUPPORTED', MDB2_ERROR_UNSUPPORTED); +define('DB_ERROR_MISMATCH', MDB2_ERROR_MISMATCH); +define('DB_ERROR_INVALID', MDB2_ERROR_INVALID); +define('DB_ERROR_NOT_CAPABLE', MDB2_ERROR_NOT_CAPABLE); +define('DB_ERROR_TRUNCATED', MDB2_ERROR_TRUNCATED); +define('DB_ERROR_INVALID_NUMBER', MDB2_ERROR_INVALID_NUMBER); +define('DB_ERROR_INVALID_DATE', MDB2_ERROR_INVALID_DATE); +define('DB_ERROR_DIVZERO', MDB2_ERROR_DIVZERO); +define('DB_ERROR_NODBSELECTED', MDB2_ERROR_NODBSELECTED); +define('DB_ERROR_CANNOT_CREATE', MDB2_ERROR_CANNOT_CREATE); +define('DB_ERROR_CANNOT_DROP', MDB2_ERROR_CANNOT_DROP); +define('DB_ERROR_NOSUCHTABLE', MDB2_ERROR_NOSUCHTABLE); +define('DB_ERROR_NOSUCHFIELD', MDB2_ERROR_NOSUCHFIELD); +define('DB_ERROR_NEED_MORE_DATA', MDB2_ERROR_NEED_MORE_DATA); +define('DB_ERROR_NOT_LOCKED', MDB2_ERROR_NOT_LOCKED); +define('DB_ERROR_VALUE_COUNT_ON_ROW', MDB2_ERROR_VALUE_COUNT_ON_ROW); +define('DB_ERROR_INVALID_DSN', MDB2_ERROR_INVALID_DSN); +define('DB_ERROR_CONNECT_FAILED', MDB2_ERROR_CONNECT_FAILED); +define('DB_ERROR_EXTENSION_NOT_FOUND', MDB2_ERROR_EXTENSION_NOT_FOUND); +define('DB_ERROR_ACCESS_VIOLATION', MDB2_ERROR_ACCESS_VIOLATION); +define('DB_ERROR_NOSUCHDB', MDB2_ERROR_NOSUCHDB); + +define('DB_WARNING', -1000); +define('DB_WARNING_READ_ONLY', -1001); + +define('DB_PARAM_SCALAR', 1); +define('DB_PARAM_OPAQUE', 2); +define('DB_PARAM_MISC', 3); + +define('DB_BINMODE_PASSTHRU', 1); +define('DB_BINMODE_RETURN', 2); +define('DB_BINMODE_CONVERT', 3); + +define('DB_FETCHMODE_DEFAULT', MDB2_FETCHMODE_DEFAULT); +define('DB_FETCHMODE_ORDERED', MDB2_FETCHMODE_ORDERED); +define('DB_FETCHMODE_ASSOC', MDB2_FETCHMODE_ASSOC); +define('DB_FETCHMODE_OBJECT', MDB2_FETCHMODE_OBJECT); +define('DB_FETCHMODE_FLIPPED', MDB2_FETCHMODE_FLIPPED); + +define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); +define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); +define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); + +require_once 'MDB2/Extended.php'; +define('DB_AUTOQUERY_INSERT', MDB2_AUTOQUERY_INSERT); +define('DB_AUTOQUERY_UPDATE', MDB2_AUTOQUERY_UPDATE); + +require_once 'MDB2/Driver/Reverse/Common.php'; +define('DB_TABLEINFO_ORDER', MDB2_TABLEINFO_ORDER); +define('DB_TABLEINFO_ORDERTABLE', MDB2_TABLEINFO_ORDERTABLE); +define('DB_TABLEINFO_FULL', MDB2_TABLEINFO_FULL); + +define('DB_PORTABILITY_NONE', MDB2_PORTABILITY_NONE); +define('DB_PORTABILITY_LOWERCASE', MDB2_PORTABILITY_FIX_CASE); +define('DB_PORTABILITY_RTRIM', MDB2_PORTABILITY_RTRIM); +define('DB_PORTABILITY_DELETE_COUNT', MDB2_PORTABILITY_DELETE_COUNT); +define('DB_PORTABILITY_NUMROWS', MDB2_PORTABILITY_NUMROWS); +define('DB_PORTABILITY_ERRORS', MDB2_PORTABILITY_ERRORS); +define('DB_PORTABILITY_NULL_TO_EMPTY', MDB2_PORTABILITY_EMPTY_TO_NULL); +define('DB_PORTABILITY_ALL', MDB2_PORTABILITY_ALL); + +/** + * Wrapper that makes MDB2 behave like PEAR DB + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class DB +{ + function &factory($type) + { + $db =& MDB2::factory($type); + if (PEAR::isError($db)) { + return $db; + } + $obj =& new MDB2_PEARProxy($db); + return $obj; + } + + function &connect($dsn, $options = false) + { + if (!is_array($options) && $options) { + $options = array('persistent' => true); + } + $db =& MDB2::connect($dsn, $options); + if (PEAR::isError($db)) { + return $db; + } + $obj =& new MDB2_PEARProxy($db); + return $obj; + } + + function apiVersion() + { + return 2; + } + + function isError($value) + { + return PEAR::isError($value); + } + + function isManip($query) + { + return MDB2::isManip($query); + } + + function errorMessage($value) + { + return MDB2::errorMessage($value); + } + + function parseDSN($dsn) + { + return MDB2::parseDSN($dsn); + } + + function assertExtension($name) + { + if (!extension_loaded($name)) { + $dlext = OS_WINDOWS ? '.dll' : '.so'; + @dl($name . $dlext); + } + return extension_loaded($name); + } +} + +/** + * MDB2_Error implements a class for reporting portable database error + * messages. + * + * @package MDB2 + * @category Database + * @author Stig Bakken + */ +class DB_Error extends PEAR_Error +{ + function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo); + } else { + $this->PEAR_Error("DB Error: $code", DB_ERROR, $mode, $level, $debuginfo); + } + } +} + +/** + * Wrapper that makes MDB2 behave like PEAR DB + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class DB_result extends MDB2_Result_Common +{ + var $result; + var $row_counter = null; + + var $limit_from = null; + + var $limit_count = null; + + function DB_result($result) + { + $this->result = $result; + } + + function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) + { + $arr = $this->result->fetchRow($fetchmode, $rownum); + if ($this->result->mdb->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return $arr; + } + + function fetchInto(&$arr, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) + { + $arr = $this->fetchRow($fetchmode, $rownum); + if ($this->result->mdb->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + function _convertNullArrayValuesToEmpty(&$array) + { + if (is_array($array)) { + foreach ($array as $key => $value) { + if (is_null($value)) { + $array[$key] = ''; + } + } + } + } + + function numCols() + { + return $this->result->numCols(); + } + + function numRows() + { + return $this->result->numRows(); + } + + function nextResult() + { + return $this->result->nextResult(); + } + + function free() + { + $err = $this->result->free(); + if (PEAR::isError($err)) { + return $err; + } + $this->result = false; + return true; + } + + function tableInfo($mode = null) + { + $this->result->db->loadModule('Reverse'); + return $this->result->db->reverse->tableInfo($this->result, $mode); + } + + function getRowCounter() + { + return $this->result->rowCount()+1+$this->result->offset; + } +} + +class DB_row +{ + function DB_row(&$arr) + { + for (reset($arr); $key = key($arr); next($arr)) { + $this->$key = &$arr[$key]; + } + } +} + +class MDB2_PEARProxy extends PEAR +{ + var $db_object; + var $phptype; + var $connection; + var $dsn; + + function MDB2_PEARProxy(&$db_object) + { + $this->db_object =& $db_object; + $this->PEAR('DB_Error'); + $this->db_object->setOption('seqcol_name', 'id'); + $this->db_object->setOption('result_wrap_class', 'DB_result'); + $this->phptype = $this->db_object->phptype; + $this->connection = $this->db_object->connection; + $this->dsn = $this->db_object->getDSN(); + } + + function connect($dsninfo, $persistent = false) + { + $this->options['persistent'] = $presistent; + return $this->db_object->connect(); + } + + function disconnect() + { + return $this->db_object->disconnect(); + } + + function toString() + { + return $this->db_object->__toString(); + } + + function quoteString($string) + { + $string = $this->quote($string); + if ($string{0} == "'") { + return substr($string, 1, -1); + } + return $string; + } + + function quote($string) + { + if (is_null($string)) { + return 'NULL'; + } + return $this->db_object->quote($string); + } + + function escapeSimple($str) + { + return $this->db_object->escape($str); + } + + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 1 : 0; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + function quoteIdentifier($string) + { + return $this->db_object->quoteIdentifier($string); + } + + // map? + function provides($feature) + { + return $this->db_object->support($feature); + } + + // remove? + function errorCode($nativecode) + { + return $this->db_object->errorCode($nativecode); + } + + // remove? + function errorMessage($dbcode) + { + return $this->db_object->errorMessage($dbcode); + } + + // remove? + function &raiseError($code = MDB2_ERROR, $mode = null, $options = null, + $userinfo = null, $nativecode = null) + { + return $this->db_object->raiseError($code, $mode, $options, $userinfo, $nativecode); + } + + function setFetchMode($fetchmode, $object_class = 'stdClass') + { + return $this->db_object->setFetchMode($fetchmode, $object_class); + } + + function setOption($option, $value) + { + return $this->db_object->setOption($option, $value); + } + + function getOption($option) + { + return $this->db_object->getOption($option); + } + + function prepare($query) + { + // parse for ! and & + // set types + return $this->db_object->prepare($query); + } + + function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, $where = false) + { + $this->db_object->loadModule('Extended'); + // types + return $this->db_object->extended->autoPrepare($table, $table_fields, $mode, $where); + } + + function &autoExecute($table, $fields_values, $mode, $where) + { + $this->db_object->loadModule('Extended'); + // types + return $this->db_object->extended->autoExecute($table, $fields_values, $mode, $where); + } + + function buildManipSQL($table, $table_fields, $mode, $where = false) + { + $this->db_object->loadModule('Extended'); + return $this->db_object->extended->buildManipSQL($table, $table_fields, $mode, $where); + } + + function &execute($stmt, $data = false) + { + $stmt->bindParamArray($data); + return $stmt->execute(); + } + + function executeMultiple($stmt, $data) + { + $this->db_object->loadModule('Extended'); + return $this->db_object->extended->executeMultiple($stmt, null, $data); + } + + function &query($query, $params = array()) { + if (sizeof($params) > 0) { + $sth = $this->db_object->prepare($query); + if (PEAR::isError($sth)) { + return $sth; + } + if (!is_array($params)) { + $params = array($params); + } + $stmt->bindParamArray($params); + return $stmt->execute(); + } + return $this->db_object->query($query); + } + + function simpleQuery($query) { + $result = $this->db_object->query($query); + if (PEAR::isError($result) || $result === MDB2_OK) { + return $result; + } else { + return $result->result->getResource(); + } + } + + function limitQuery($query, $from, $count, $params = array()) + { + $result = $this->db_object->setLimit($count, $from); + if (PEAR::isError($result)) { + return $result; + } + $result =& $this->query($query, $params); + return $result; + } + + function _convertNullArrayValuesToEmpty(&$array) + { + if (is_array($array)) { + foreach ($array as $key => $value) { + if (is_null($value)) { + $array[$key] = ''; + } + } + } + } + + function &getOne($query, $params = array()) + { + $result = $this->query($query, $params); + $one = $result->result->fetchOne(); + if (is_null($one)) { + $one = ''; + } + return $one; + } + + function &getRow($query, + $params = array(), + $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + if (!is_array($params)) { + if (is_array($fetchmode)) { + if (is_null($params)) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif (!is_null($params)) { + $fetchmode = $params; + $params = array(); + } + } + $result =& $this->query($query, $params); + return $result->result->fetchRow($fetchmode); + } + + function &getCol($query, $col = 0, $params = array()) + { + $result =& $this->query($query, $params); + $col = $result->result->fetchCol($col); + $this->_convertNullArrayValuesToEmpty($col); + return $col; + } + + function &getAssoc($query, $force_array = false, $params = array(), + $fetchmode = MDB2_FETCHMODE_ORDERED, $group = false) + { + $result =& $this->query($query, $params); + $all = $result->result->fetchAll($fetchmode, true, $force_array, $group); + $first = reset($all); + if (isset($first) && $this->db_object->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + if (is_array($first)) { + foreach ($all as $key => $arr) { + $this->_convertNullArrayValuesToEmpty($all[$key]); + } + } elseif (is_object($first)) { + foreach ($all as $key => $arr) { + $tmp = get_object_vars($all[$key]); + if (is_array($tmp)) { + $this->_convertNullArrayValuesToEmpty($tmp); + foreach ($tmp as $key2 => $column) { + $all[$key]->{$key2} = $column; + } + } + } + } + } + return $all; + } + + function &getAll($query, + $params = null, + $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + if (!is_array($params)) { + if (is_array($fetchmode)) { + if (is_null($params)) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif (!is_null($params)) { + $fetchmode = $params; + $params = array(); + } + } + $result =& $this->query($query, $params); + $all = $result->result->fetchAll($fetchmode); + $first = reset($all); + if (isset($first) && $this->db_object->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + if (is_array($first)) { + foreach ($all as $key => $arr) { + $this->_convertNullArrayValuesToEmpty($all[$key]); + } + } elseif (is_object($first)) { + foreach ($all as $key => $arr) { + $tmp = get_object_vars($all[$key]); + if (is_array($tmp)) { + $this->_convertNullArrayValuesToEmpty($tmp); + foreach ($tmp as $key2 => $column) { + $all[$key]->{$key2} = $column; + } + } + } + } + } + return $all; + } + + function autoCommit($onoff = false) + { + return $this->db_object->autoCommit($onoff); + } + + function commit() + { + return $this->db_object->commit(); + } + + function rollback() + { + return $this->db_object->rollback(); + } + + function affectedRows() + { + return $this->db_object->affectedRows(); + } + + // remove? + function errorNative() + { + return $this->db_object->errorNative(); + } + + function nextId($seq_name, $ondemand = true) + { + return $this->db_object->nextID($seq_name, $ondemand); + } + + function createSequence($seq_name) + { + $this->db_object->loadModule('Manager'); + return $this->db_object->manager->createSequence($seq_name, 1); + } + + function dropSequence($seq_name) + { + $this->db_object->loadModule('Manager'); + return $this->db_object->manager->dropSequence($seq_name); + } + + function &_wrapResource($result) + { + if (is_resource($result)) { + $result_class = $this->db_object->getOption('result_buffering') + ? $this->db_object->getOption('buffered_result_class') : $$this->db_object->getOption('result_class'); + $class_name = sprintf($result_class, $this->db_object->phptype); + $result =& new $class_name($this->db_object, $result); + } + return $result; + } + + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + $result = $this->_wrapResource($result); + if (!is_null($rownum)) { + $result->result->seek($rownum); + } + $arr = $result->fetchRow($fetchmode); + } + + function freePrepared($prepared) + { + return $this->db_object->freePrepared($prepared); + } + + function freeResult($result) + { + $result = $this->_wrapResource($result); + return $result->free(); + } + + function numCols($result) + { + $result = $this->_wrapResource($result); + return $result->numCols(); + } + + function numRows($result) + { + $result = $this->_wrapResource($result); + return $result->numRows(); + } + + function nextResult($result) + { + $result = $this->_wrapResource($result); + return $result->nextResult(); + } + + function tableInfo($result, $mode = null) + { + $result = $this->_wrapResource($result); + if (is_string($result) || MDB2::isResultCommon($result)) { + $this->db_object->loadModule('Reverse'); + return $this->db_object->reverse->tableInfo($result, $mode); + } + return $result->tableInfo($mode); + } + + function getTables() + { + return $this->getListOf('tables'); + } + + function getListOf($type) + { + $this->db_object->loadModule('Manager'); + switch ($type) { + case 'tables': + return $this->db_object->manager->listTables(); + case 'views': + return $this->db_object->manager->listViews(); + case 'users': + return $this->db_object->manager->listUsers(); + case 'functions': + return $this->db_object->manager->listFunctions(); + case 'databases': + return $this->db_object->manager->listDatabases(); + default: + return $this->db_object->raiseError(MDB2_ERROR_UNSUPPORTED); + } + } +} +?>