diff options
author | Robin Appelman <icewind@owncloud.com> | 2012-05-11 20:25:00 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2012-05-11 20:33:56 +0200 |
commit | d2bd78c41a58320e0f1f6ff6d602371325390747 (patch) | |
tree | fb155745eb932cf5a8adbdeb262f2c6081c2dc28 /3rdparty/MDB2 | |
parent | 3c2af95108ee87edfe96a5518e9f9cebfbdaa414 (diff) | |
download | nextcloud-server-d2bd78c41a58320e0f1f6ff6d602371325390747.tar.gz nextcloud-server-d2bd78c41a58320e0f1f6ff6d602371325390747.zip |
update MDB2 and XML_Parser
Diffstat (limited to '3rdparty/MDB2')
30 files changed, 17198 insertions, 17052 deletions
diff --git a/3rdparty/MDB2/Date.php b/3rdparty/MDB2/Date.php index ce846543a50..d874531150f 100644 --- a/3rdparty/MDB2/Date.php +++ b/3rdparty/MDB2/Date.php @@ -1,183 +1,183 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Date.php,v 1.10 2006/03/01 12:15:32 lsmith Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ - -/** - * Several methods to convert the MDB2 native timestamp format (ISO based) - * to and from data structures that are convenient 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 <smith@pooteeweet.org> - */ -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 int hour of the date - * @param int minute of the date - * @param int second of the date - * @param int month of the date - * @param int day of the date - * @param int 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 int 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 int 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 int 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; - } - // }}} -} - -?> +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Date.php 208329 2006-03-01 12:15:38Z lsmith $
+//
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+
+/**
+ * Several methods to convert the MDB2 native timestamp format (ISO based)
+ * to and from data structures that are convenient 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 <smith@pooteeweet.org>
+ */
+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 int hour of the date
+ * @param int minute of the date
+ * @param int second of the date
+ * @param int month of the date
+ * @param int day of the date
+ * @param int 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 int 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 int 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 int 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/3rdparty/MDB2/Driver/Datatype/Common.php b/3rdparty/MDB2/Driver/Datatype/Common.php index 85a74f64fca..db0cb45dd89 100644 --- a/3rdparty/MDB2/Driver/Datatype/Common.php +++ b/3rdparty/MDB2/Driver/Datatype/Common.php @@ -1,1824 +1,1841 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.139 2008/12/04 11:50:42 afz Exp $ - -require_once('MDB2/LOB.php'); - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ - -/** - * MDB2_Driver_Common: Base class that is extended by each MDB2 driver - * - * To load this module in the MDB2 object: - * $mdb->loadModule('Datatype'); - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Datatype_Common extends MDB2_Module_Common -{ - var $valid_default_values = array( - 'text' => '', - 'boolean' => true, - 'integer' => 0, - 'decimal' => 0.0, - 'float' => 0.0, - 'timestamp' => '1970-01-01 00:00:00', - 'time' => '00:00:00', - 'date' => '1970-01-01', - 'clob' => '', - 'blob' => '', - ); - - /** - * contains all LOB objects created with this MDB2 instance - * @var array - * @access protected - */ - var $lobs = array(); - - // }}} - // {{{ getValidTypes() - - /** - * Get the list of valid types - * - * This function returns an array of valid types as keys with the values - * being possible default values for all native datatypes and mapped types - * for custom datatypes. - * - * @return mixed array on success, a MDB2 error on failure - * @access public - */ - function getValidTypes() - { - $types = $this->valid_default_values; - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map'])) { - foreach ($db->options['datatype_map'] as $type => $mapped_type) { - if (array_key_exists($mapped_type, $types)) { - $types[$type] = $types[$mapped_type]; - } elseif (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'mapped_type' => $mapped_type); - $default = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - $types[$type] = $default; - } - } - } - return $types; - } - - // }}} - // {{{ checkResultTypes() - - /** - * 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 array $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 checkResultTypes($types) - { - $types = is_array($types) ? $types : array($types); - foreach ($types as $key => $type) { - if (!isset($this->valid_default_values[$type])) { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (empty($db->options['datatype_map'][$type])) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - $type.' for '.$key.' is not a supported column type', __FUNCTION__); - } - } - } - return $types; - } - - // }}} - // {{{ _baseConvertResult() - - /** - * General type conversion method - * - * @param mixed $value reference to a value to be converted - * @param string $type specifies which type to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return object an MDB2 error on failure - * @access protected - */ - function _baseConvertResult($value, $type, $rtrim = true) - { - switch ($type) { - case 'text': - if ($rtrim) { - $value = rtrim($value); - } - return $value; - case 'integer': - return intval($value); - case 'boolean': - return !empty($value); - 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, - 'resource' => $value, - 'value' => null, - 'loaded' => false, - ); - 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, __FUNCTION__); - } - - // }}} - // {{{ convertResult() - - /** - * Convert a value to a RDBMS indipendent MDB2 type - * - * @param mixed $value value to be converted - * @param string $type specifies which type to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return mixed converted value - * @access public - */ - function convertResult($value, $type, $rtrim = true) - { - if (is_null($value)) { - return null; - } - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'value' => $value, 'rtrim' => $rtrim); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - return $this->_baseConvertResult($value, $type, $rtrim); - } - - // }}} - // {{{ convertResultRow() - - /** - * Convert a result row - * - * @param array $types - * @param array $row specifies the types to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return mixed MDB2_OK on success, an MDB2 error on failure - * @access public - */ - function convertResultRow($types, $row, $rtrim = true) - { - $types = $this->_sortResultFieldTypes(array_keys($row), $types); - foreach ($row as $key => $value) { - if (empty($types[$key])) { - continue; - } - $value = $this->convertResult($row[$key], $types[$key], $rtrim); - if (PEAR::isError($value)) { - return $value; - } - $row[$key] = $value; - } - return $row; - } - - // }}} - // {{{ _sortResultFieldTypes() - - /** - * convert a result row - * - * @param array $types - * @param array $row specifies the types to convert to - * @param bool $rtrim if to rtrim text values or not - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function _sortResultFieldTypes($columns, $types) - { - $n_cols = count($columns); - $n_types = count($types); - if ($n_cols > $n_types) { - for ($i= $n_cols - $n_types; $i >= 0; $i--) { - $types[] = null; - } - } - $sorted_types = array(); - foreach ($columns as $col) { - $sorted_types[$col] = null; - } - foreach ($types as $name => $type) { - if (array_key_exists($name, $sorted_types)) { - $sorted_types[$name] = $type; - unset($types[$name]); - } - } - // if there are left types in the array, fill the null values of the - // sorted array with them, in order. - if (count($types)) { - reset($types); - foreach (array_keys($sorted_types) as $k) { - if (is_null($sorted_types[$k])) { - $sorted_types[$k] = current($types); - next($types); - } - } - } - return $sorted_types; - } - - // }}} - // {{{ 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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'name' => $name, 'field' => $field); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - $field['type'] = $type; - } - - if (!method_exists($this, "_get{$type}Declaration")) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'type not defined: '.$type, __FUNCTION__); - } - return $this->{"_get{$type}Declaration"}($name, $field); - } - - // }}} - // {{{ getTypeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @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 public - */ - function getTypeDeclaration($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - switch ($field['type']) { - case 'text': - $length = !empty($field['length']) ? $field['length'] : $db->options['default_text_field_length']; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; - return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') - : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); - case 'clob': - return 'TEXT'; - case 'blob': - return 'TEXT'; - case 'integer': - return 'INT'; - case 'boolean': - return 'INT'; - case 'date': - return 'CHAR ('.strlen('YYYY-MM-DD').')'; - case 'time': - return 'CHAR ('.strlen('HH:MM:SS').')'; - case 'timestamp': - return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'; - case 'float': - return 'TEXT'; - case 'decimal': - return 'TEXT'; - } - return ''; - } - - // }}} - // {{{ _getDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a generic 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. - * charset - * Text value with the default CHARACTER SET for this field. - * collation - * Text value with the default COLLATION for this field. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field, or a MDB2_Error on failure - * @access protected - */ - function _getDeclaration($name, $field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $declaration_options = $db->datatype->_getDeclarationOptions($field); - if (PEAR::isError($declaration_options)) { - return $declaration_options; - } - return $name.' '.$this->getTypeDeclaration($field).$declaration_options; - } - - // }}} - // {{{ _getDeclarationOptions() - - /** - * Obtain DBMS specific SQL code portion needed to declare a generic type - * field to be used in statement like CREATE TABLE, without the field name - * and type values (ie. just the character set, default value, if the - * field is permitted to be NULL or not, and the collation options). - * - * @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 - * 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. - * charset - * Text value with the default CHARACTER SET for this field. - * collation - * Text value with the default COLLATION for this field. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field's options. - * @access protected - */ - function _getDeclarationOptions($field) - { - $charset = empty($field['charset']) ? '' : - ' '.$this->_getCharsetFieldDeclaration($field['charset']); - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $default = ''; - if (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $valid_default_values = $this->getValidTypes(); - $field['default'] = $valid_default_values[$field['type']]; - if ($field['default'] === ''&& ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) { - $field['default'] = ' '; - } - } - if (!is_null($field['default'])) { - $default = ' DEFAULT ' . $this->quote($field['default'], $field['type']); - } - } - - $collation = empty($field['collation']) ? '' : - ' '.$this->_getCollationFieldDeclaration($field['collation']); - - return $charset.$default.$notnull.$collation; - } - - // }}} - // {{{ _getCharsetFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $charset name of the charset - * @return string DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration. - */ - function _getCharsetFieldDeclaration($charset) - { - return ''; - } - - // }}} - // {{{ _getCollationFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $collation name of the collation - * @return string DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration. - */ - function _getCollationFieldDeclaration($collation) - { - return ''; - } - - // }}} - // {{{ _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 (!empty($field['unsigned'])) { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; - } - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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 public - */ - function _getCLOBDeclaration($name, $field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _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) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ compareDefinition() - - /** - * Obtain an array of changes that may need to applied - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access public - */ - function compareDefinition($current, $previous) - { - $type = !empty($current['type']) ? $current['type'] : null; - - if (!method_exists($this, "_compare{$type}Definition")) { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('current' => $current, 'previous' => $previous); - $change = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - return $change; - } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'type "'.$current['type'].'" is not yet supported', __FUNCTION__); - } - - if (empty($previous['type']) || $previous['type'] != $type) { - return $current; - } - - $change = $this->{"_compare{$type}Definition"}($current, $previous); - - if ($previous['type'] != $type) { - $change['type'] = true; - } - - $previous_notnull = !empty($previous['notnull']) ? $previous['notnull'] : false; - $notnull = !empty($current['notnull']) ? $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 containing all changes that will need to be applied - * @access protected - */ - function _compareIntegerDefinition($current, $previous) - { - $change = array(); - $previous_unsigned = !empty($previous['unsigned']) ? $previous['unsigned'] : false; - $unsigned = !empty($current['unsigned']) ? $current['unsigned'] : false; - if ($previous_unsigned != $unsigned) { - $change['unsigned'] = true; - } - $previous_autoincrement = !empty($previous['autoincrement']) ? $previous['autoincrement'] : false; - $autoincrement = !empty($current['autoincrement']) ? $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 containing all changes that will need to be applied - * @access protected - */ - function _compareTextDefinition($current, $previous) - { - $change = array(); - $previous_length = !empty($previous['length']) ? $previous['length'] : 0; - $length = !empty($current['length']) ? $current['length'] : 0; - if ($previous_length != $length) { - $change['length'] = true; - } - $previous_fixed = !empty($previous['fixed']) ? $previous['fixed'] : 0; - $fixed = !empty($current['fixed']) ? $current['fixed'] : 0; - if ($previous_fixed != $fixed) { - $change['fixed'] = 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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 - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access public - */ - function quote($value, $type = null, $quote = true, $escape_wildcards = false) - { - $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: default to decimal as float is quite unusual - // $type = 'float'; - $type = 'decimal'; - break; - case 'boolean': - $type = 'boolean'; - break; - case 'array': - $value = serialize($value); - 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; - } - } elseif (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'value' => $value, 'quote' => $quote, 'escape_wildcards' => $escape_wildcards); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - - if (!method_exists($this, "_quote{$type}")) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'type not defined: '.$type, __FUNCTION__); - } - $value = $this->{"_quote{$type}"}($value, $quote, $escape_wildcards); - if ($quote && $escape_wildcards && $db->string_quoting['escape_pattern'] - && $db->string_quoting['escape'] !== $db->string_quoting['escape_pattern'] - ) { - $value.= $this->patternEscapeString(); - } - 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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteInteger($value, $quote, $escape_wildcards) - { - 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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that already contains any DBMS specific - * escaped character sequences. - * @access protected - */ - function _quoteText($value, $quote, $escape_wildcards) - { - if (!$quote) { - return $value; - } - - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $value = $db->escape($value, $escape_wildcards); - if (PEAR::isError($value)) { - return $value; - } - return "'".$value."'"; - } - - // }}} - // {{{ _readFile() - - /** - * 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 _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 string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteLOB($value, $quote, $escape_wildcards) - { - $value = $this->_readFile($value); - if (PEAR::isError($value)) { - return $value; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteCLOB() - - /** - * 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 bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteCLOB($value, $quote, $escape_wildcards) - { - return $this->_quoteLOB($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteBLOB() - - /** - * 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 bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBLOB($value, $quote, $escape_wildcards) - { - return $this->_quoteLOB($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBoolean($value, $quote, $escape_wildcards) - { - return ($value ? 1 : 0); - } - - // }}} - // {{{ _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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteDate($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_DATE') { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('date'); - } - return 'CURRENT_DATE'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteTimestamp($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_TIMESTAMP') { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('timestamp'); - } - return 'CURRENT_TIMESTAMP'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteTime($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_TIME') { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('time'); - } - return 'CURRENT_TIME'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteFloat($value, $quote, $escape_wildcards) - { - if (preg_match('/^(.*)e([-+])(\d+)$/i', $value, $matches)) { - $decimal = $this->_quoteDecimal($matches[1], $quote, $escape_wildcards); - $sign = $matches[2]; - $exponent = str_pad($matches[3], 2, '0', STR_PAD_LEFT); - $value = $decimal.'E'.$sign.$exponent; - } else { - $value = $this->_quoteDecimal($value, $quote, $escape_wildcards); - } - return $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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteDecimal($value, $quote, $escape_wildcards) - { - $value = (string)$value; - $value = preg_replace('/[^\d\.,\-+eE]/', '', $value); - if (preg_match('/[^\.\d]/', $value)) { - if (strpos($value, ',')) { - // 1000,00 - if (!strpos($value, '.')) { - // convert the last "," to a "." - $value = strrev(str_replace(',', '.', strrev($value))); - // 1.000,00 - } elseif (strpos($value, '.') && strpos($value, '.') < strpos($value, ',')) { - $value = str_replace('.', '', $value); - // convert the last "," to a "." - $value = strrev(str_replace(',', '.', strrev($value))); - // 1,000.00 - } else { - $value = str_replace(',', '', $value); - } - } - } - return $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; - } - - if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) { - if ($match[1] == 'file://') { - $file = $match[2]; - } - } - - $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, - 'could not write to the output file', __FUNCTION__); - } - } - @fclose($fp); - return MDB2_OK; - } - - // }}} - // {{{ _retrieveLOB() - - /** - * retrieve LOB from the database - * - * @param array $lob array - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access protected - */ - function _retrieveLOB(&$lob) - { - if (is_null($lob['value'])) { - $lob['value'] = $lob['resource']; - } - $lob['loaded'] = true; - 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 array $lob array - * @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($this->lobs[$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 array $lob array - * @access private - */ - function _destroyLOB(&$lob) - { - 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); - } - - // }}} - // {{{ matchPattern() - - /** - * build a pattern matching string - * - * @access public - * - * @param array $pattern even keys are strings, odd are patterns (% and _) - * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) - * @param string $field optional field name that is being matched against - * (might be required when emulating ILIKE) - * - * @return string SQL pattern - */ - function matchPattern($pattern, $operator = null, $field = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $match = ''; - if (!is_null($operator)) { - $operator = strtoupper($operator); - switch ($operator) { - // case insensitive - case 'ILIKE': - if (is_null($field)) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'case insensitive LIKE matching requires passing the field name', __FUNCTION__); - } - $db->loadModule('Function', null, true); - $match = $db->function->lower($field).' LIKE '; - break; - // case sensitive - case 'LIKE': - $match = is_null($field) ? 'LIKE ' : $field.' LIKE '; - break; - default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'not a supported operator type:'. $operator, __FUNCTION__); - } - } - $match.= "'"; - foreach ($pattern as $key => $value) { - if ($key % 2) { - $match.= $value; - } else { - if ($operator === 'ILIKE') { - $value = strtolower($value); - } - $escaped = $db->escape($value); - if (PEAR::isError($escaped)) { - return $escaped; - } - $match.= $db->escapePattern($escaped); - } - } - $match.= "'"; - $match.= $this->patternEscapeString(); - return $match; - } - - // }}} - // {{{ patternEscapeString() - - /** - * build string to define pattern escape character - * - * @access public - * - * @return string define pattern escape character - */ - function patternEscapeString() - { - return ''; - } - - // }}} - // {{{ mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function mapNativeDatatype($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - // If the user has specified an option to map the native field - // type to a custom MDB2 datatype... - $db_type = strtok($field['type'], '(), '); - if (!empty($db->options['nativetype_map_callback'][$db_type])) { - return call_user_func_array($db->options['nativetype_map_callback'][$db_type], array($db, $field)); - } - - // Otherwise perform the built-in (i.e. normal) MDB2 native type to - // MDB2 datatype conversion - return $this->_mapNativeDatatype($field); - } - - // }}} - // {{{ _mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function _mapNativeDatatype($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ mapPrepareDatatype() - - /** - * Maps an mdb2 datatype to mysqli prepare type - * - * @param string $type - * @return string - * @access public - */ - function mapPrepareDatatype($type) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - - return $type; - } -} -?> +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Common.php 300551 2010-06-17 21:54:16Z quipo $
+
+require_once 'MDB2/LOB.php';
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+
+/**
+ * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
+ *
+ * To load this module in the MDB2 object:
+ * $mdb->loadModule('Datatype');
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Datatype_Common extends MDB2_Module_Common
+{
+ var $valid_default_values = array(
+ 'text' => '',
+ 'boolean' => true,
+ 'integer' => 0,
+ 'decimal' => 0.0,
+ 'float' => 0.0,
+ 'timestamp' => '1970-01-01 00:00:00',
+ 'time' => '00:00:00',
+ 'date' => '1970-01-01',
+ 'clob' => '',
+ 'blob' => '',
+ );
+
+ /**
+ * contains all LOB objects created with this MDB2 instance
+ * @var array
+ * @access protected
+ */
+ var $lobs = array();
+
+ // }}}
+ // {{{ getValidTypes()
+
+ /**
+ * Get the list of valid types
+ *
+ * This function returns an array of valid types as keys with the values
+ * being possible default values for all native datatypes and mapped types
+ * for custom datatypes.
+ *
+ * @return mixed array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getValidTypes()
+ {
+ $types = $this->valid_default_values;
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (!empty($db->options['datatype_map'])) {
+ foreach ($db->options['datatype_map'] as $type => $mapped_type) {
+ if (array_key_exists($mapped_type, $types)) {
+ $types[$type] = $types[$mapped_type];
+ } elseif (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type, 'mapped_type' => $mapped_type);
+ $default = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ $types[$type] = $default;
+ }
+ }
+ }
+ return $types;
+ }
+
+ // }}}
+ // {{{ checkResultTypes()
+
+ /**
+ * 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 array $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 checkResultTypes($types)
+ {
+ $types = is_array($types) ? $types : array($types);
+ foreach ($types as $key => $type) {
+ if (!isset($this->valid_default_values[$type])) {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (empty($db->options['datatype_map'][$type])) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ $type.' for '.$key.' is not a supported column type', __FUNCTION__);
+ }
+ }
+ }
+ return $types;
+ }
+
+ // }}}
+ // {{{ _baseConvertResult()
+
+ /**
+ * General type conversion method
+ *
+ * @param mixed $value reference to a value to be converted
+ * @param string $type specifies which type to convert to
+ * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
+ * @return object an MDB2 error on failure
+ * @access protected
+ */
+ function _baseConvertResult($value, $type, $rtrim = true)
+ {
+ switch ($type) {
+ case 'text':
+ if ($rtrim) {
+ $value = rtrim($value);
+ }
+ return $value;
+ case 'integer':
+ return intval($value);
+ case 'boolean':
+ return !empty($value);
+ 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,
+ 'resource' => $value,
+ 'value' => null,
+ 'loaded' => false,
+ );
+ 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, __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ convertResult()
+
+ /**
+ * Convert a value to a RDBMS indipendent MDB2 type
+ *
+ * @param mixed $value value to be converted
+ * @param string $type specifies which type to convert to
+ * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
+ * @return mixed converted value
+ * @access public
+ */
+ function convertResult($value, $type, $rtrim = true)
+ {
+ if (null === $value) {
+ return null;
+ }
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (!empty($db->options['datatype_map'][$type])) {
+ $type = $db->options['datatype_map'][$type];
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type, 'value' => $value, 'rtrim' => $rtrim);
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ }
+ }
+ return $this->_baseConvertResult($value, $type, $rtrim);
+ }
+
+ // }}}
+ // {{{ convertResultRow()
+
+ /**
+ * Convert a result row
+ *
+ * @param array $types
+ * @param array $row specifies the types to convert to
+ * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
+ * @return mixed MDB2_OK on success, an MDB2 error on failure
+ * @access public
+ */
+ function convertResultRow($types, $row, $rtrim = true)
+ {
+ $types = $this->_sortResultFieldTypes(array_keys($row), $types);
+ foreach ($row as $key => $value) {
+ if (empty($types[$key])) {
+ continue;
+ }
+ $value = $this->convertResult($row[$key], $types[$key], $rtrim);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ $row[$key] = $value;
+ }
+ return $row;
+ }
+
+ // }}}
+ // {{{ _sortResultFieldTypes()
+
+ /**
+ * convert a result row
+ *
+ * @param array $types
+ * @param array $row specifies the types to convert to
+ * @param bool $rtrim if to rtrim text values or not
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function _sortResultFieldTypes($columns, $types)
+ {
+ $n_cols = count($columns);
+ $n_types = count($types);
+ if ($n_cols > $n_types) {
+ for ($i= $n_cols - $n_types; $i >= 0; $i--) {
+ $types[] = null;
+ }
+ }
+ $sorted_types = array();
+ foreach ($columns as $col) {
+ $sorted_types[$col] = null;
+ }
+ foreach ($types as $name => $type) {
+ if (array_key_exists($name, $sorted_types)) {
+ $sorted_types[$name] = $type;
+ unset($types[$name]);
+ }
+ }
+ // if there are left types in the array, fill the null values of the
+ // sorted array with them, in order.
+ if (count($types)) {
+ reset($types);
+ foreach (array_keys($sorted_types) as $k) {
+ if (null === $sorted_types[$k]) {
+ $sorted_types[$k] = current($types);
+ next($types);
+ }
+ }
+ }
+ return $sorted_types;
+ }
+
+ // }}}
+ // {{{ 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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!empty($db->options['datatype_map'][$type])) {
+ $type = $db->options['datatype_map'][$type];
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type, 'name' => $name, 'field' => $field);
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ }
+ $field['type'] = $type;
+ }
+
+ if (!method_exists($this, "_get{$type}Declaration")) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'type not defined: '.$type, __FUNCTION__);
+ }
+ return $this->{"_get{$type}Declaration"}($name, $field);
+ }
+
+ // }}}
+ // {{{ getTypeDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an text type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @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 public
+ */
+ function getTypeDeclaration($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ switch ($field['type']) {
+ case 'text':
+ $length = !empty($field['length']) ? $field['length'] : $db->options['default_text_field_length'];
+ $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
+ return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
+ : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
+ case 'clob':
+ return 'TEXT';
+ case 'blob':
+ return 'TEXT';
+ case 'integer':
+ return 'INT';
+ case 'boolean':
+ return 'INT';
+ case 'date':
+ return 'CHAR ('.strlen('YYYY-MM-DD').')';
+ case 'time':
+ return 'CHAR ('.strlen('HH:MM:SS').')';
+ case 'timestamp':
+ return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')';
+ case 'float':
+ return 'TEXT';
+ case 'decimal':
+ return 'TEXT';
+ }
+ return '';
+ }
+
+ // }}}
+ // {{{ _getDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare a generic 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.
+ * charset
+ * Text value with the default CHARACTER SET for this field.
+ * collation
+ * Text value with the default COLLATION for this field.
+ * @return string DBMS specific SQL code portion that should be used to
+ * declare the specified field, or a MDB2_Error on failure
+ * @access protected
+ */
+ function _getDeclaration($name, $field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $declaration_options = $db->datatype->_getDeclarationOptions($field);
+ if (PEAR::isError($declaration_options)) {
+ return $declaration_options;
+ }
+ return $name.' '.$this->getTypeDeclaration($field).$declaration_options;
+ }
+
+ // }}}
+ // {{{ _getDeclarationOptions()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare a generic type
+ * field to be used in statement like CREATE TABLE, without the field name
+ * and type values (ie. just the character set, default value, if the
+ * field is permitted to be NULL or not, and the collation options).
+ *
+ * @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
+ * 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.
+ * charset
+ * Text value with the default CHARACTER SET for this field.
+ * collation
+ * Text value with the default COLLATION for this field.
+ * @return string DBMS specific SQL code portion that should be used to
+ * declare the specified field's options.
+ * @access protected
+ */
+ function _getDeclarationOptions($field)
+ {
+ $charset = empty($field['charset']) ? '' :
+ ' '.$this->_getCharsetFieldDeclaration($field['charset']);
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $default = '';
+ if (array_key_exists('default', $field)) {
+ if ($field['default'] === '') {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $valid_default_values = $this->getValidTypes();
+ $field['default'] = $valid_default_values[$field['type']];
+ if ($field['default'] === '' && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) {
+ $field['default'] = ' ';
+ }
+ }
+ if (null !== $field['default']) {
+ $default = ' DEFAULT ' . $this->quote($field['default'], $field['type']);
+ }
+ }
+ if (empty($default) && empty($notnull)) {
+ $default = ' DEFAULT NULL';
+ }
+
+ $collation = empty($field['collation']) ? '' :
+ ' '.$this->_getCollationFieldDeclaration($field['collation']);
+
+ return $charset.$default.$notnull.$collation;
+ }
+
+ // }}}
+ // {{{ _getCharsetFieldDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
+ * of a field declaration to be used in statements like CREATE TABLE.
+ *
+ * @param string $charset name of the charset
+ * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
+ * of a field declaration.
+ */
+ function _getCharsetFieldDeclaration($charset)
+ {
+ return '';
+ }
+
+ // }}}
+ // {{{ _getCollationFieldDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration to be used in statements like CREATE TABLE.
+ *
+ * @param string $collation name of the collation
+ * @return string DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration.
+ */
+ function _getCollationFieldDeclaration($collation)
+ {
+ return '';
+ }
+
+ // }}}
+ // {{{ _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 (!empty($field['unsigned'])) {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
+ }
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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 public
+ */
+ function _getCLOBDeclaration($name, $field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ return $this->_getDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ compareDefinition()
+
+ /**
+ * Obtain an array of changes that may need to applied
+ *
+ * @param array $current new definition
+ * @param array $previous old definition
+ * @return array containing all changes that will need to be applied
+ * @access public
+ */
+ function compareDefinition($current, $previous)
+ {
+ $type = !empty($current['type']) ? $current['type'] : null;
+
+ if (!method_exists($this, "_compare{$type}Definition")) {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('current' => $current, 'previous' => $previous);
+ $change = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ return $change;
+ }
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'type "'.$current['type'].'" is not yet supported', __FUNCTION__);
+ }
+
+ if (empty($previous['type']) || $previous['type'] != $type) {
+ return $current;
+ }
+
+ $change = $this->{"_compare{$type}Definition"}($current, $previous);
+
+ if ($previous['type'] != $type) {
+ $change['type'] = true;
+ }
+
+ $previous_notnull = !empty($previous['notnull']) ? $previous['notnull'] : false;
+ $notnull = !empty($current['notnull']) ? $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 containing all changes that will need to be applied
+ * @access protected
+ */
+ function _compareIntegerDefinition($current, $previous)
+ {
+ $change = array();
+ $previous_unsigned = !empty($previous['unsigned']) ? $previous['unsigned'] : false;
+ $unsigned = !empty($current['unsigned']) ? $current['unsigned'] : false;
+ if ($previous_unsigned != $unsigned) {
+ $change['unsigned'] = true;
+ }
+ $previous_autoincrement = !empty($previous['autoincrement']) ? $previous['autoincrement'] : false;
+ $autoincrement = !empty($current['autoincrement']) ? $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 containing all changes that will need to be applied
+ * @access protected
+ */
+ function _compareTextDefinition($current, $previous)
+ {
+ $change = array();
+ $previous_length = !empty($previous['length']) ? $previous['length'] : 0;
+ $length = !empty($current['length']) ? $current['length'] : 0;
+ if ($previous_length != $length) {
+ $change['length'] = true;
+ }
+ $previous_fixed = !empty($previous['fixed']) ? $previous['fixed'] : 0;
+ $fixed = !empty($current['fixed']) ? $current['fixed'] : 0;
+ if ($previous_fixed != $fixed) {
+ $change['fixed'] = 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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 containing 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
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access public
+ */
+ function quote($value, $type = null, $quote = true, $escape_wildcards = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if ((null === $value)
+ || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
+ ) {
+ if (!$quote) {
+ return null;
+ }
+ return 'NULL';
+ }
+
+ if (null === $type) {
+ switch (gettype($value)) {
+ case 'integer':
+ $type = 'integer';
+ break;
+ case 'double':
+ // todo: default to decimal as float is quite unusual
+ // $type = 'float';
+ $type = 'decimal';
+ break;
+ case 'boolean':
+ $type = 'boolean';
+ break;
+ case 'array':
+ $value = serialize($value);
+ 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;
+ }
+ } elseif (!empty($db->options['datatype_map'][$type])) {
+ $type = $db->options['datatype_map'][$type];
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type, 'value' => $value, 'quote' => $quote, 'escape_wildcards' => $escape_wildcards);
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ }
+ }
+
+ if (!method_exists($this, "_quote{$type}")) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'type not defined: '.$type, __FUNCTION__);
+ }
+ $value = $this->{"_quote{$type}"}($value, $quote, $escape_wildcards);
+ if ($quote && $escape_wildcards && $db->string_quoting['escape_pattern']
+ && $db->string_quoting['escape'] !== $db->string_quoting['escape_pattern']
+ ) {
+ $value.= $this->patternEscapeString();
+ }
+ 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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteInteger($value, $quote, $escape_wildcards)
+ {
+ 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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that already contains any DBMS specific
+ * escaped character sequences.
+ * @access protected
+ */
+ function _quoteText($value, $quote, $escape_wildcards)
+ {
+ if (!$quote) {
+ return $value;
+ }
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $value = $db->escape($value, $escape_wildcards);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ return "'".$value."'";
+ }
+
+ // }}}
+ // {{{ _readFile()
+
+ /**
+ * 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 _readFile($value)
+ {
+ $close = false;
+ if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
+ $close = true;
+ if (strtolower($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 string $value text string value that is intended to be converted.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteLOB($value, $quote, $escape_wildcards)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if ($db->options['lob_allow_url_include']) {
+ $value = $this->_readFile($value);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ }
+ return $this->_quoteText($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _quoteCLOB()
+
+ /**
+ * 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 bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteCLOB($value, $quote, $escape_wildcards)
+ {
+ return $this->_quoteLOB($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _quoteBLOB()
+
+ /**
+ * 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 bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteBLOB($value, $quote, $escape_wildcards)
+ {
+ return $this->_quoteLOB($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteBoolean($value, $quote, $escape_wildcards)
+ {
+ return ($value ? 1 : 0);
+ }
+
+ // }}}
+ // {{{ _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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteDate($value, $quote, $escape_wildcards)
+ {
+ if ($value === 'CURRENT_DATE') {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
+ return $db->function->now('date');
+ }
+ return 'CURRENT_DATE';
+ }
+ return $this->_quoteText($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteTimestamp($value, $quote, $escape_wildcards)
+ {
+ if ($value === 'CURRENT_TIMESTAMP') {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
+ return $db->function->now('timestamp');
+ }
+ return 'CURRENT_TIMESTAMP';
+ }
+ return $this->_quoteText($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteTime($value, $quote, $escape_wildcards)
+ {
+ if ($value === 'CURRENT_TIME') {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) {
+ return $db->function->now('time');
+ }
+ return 'CURRENT_TIME';
+ }
+ return $this->_quoteText($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteFloat($value, $quote, $escape_wildcards)
+ {
+ if (preg_match('/^(.*)e([-+])(\d+)$/i', $value, $matches)) {
+ $decimal = $this->_quoteDecimal($matches[1], $quote, $escape_wildcards);
+ $sign = $matches[2];
+ $exponent = str_pad($matches[3], 2, '0', STR_PAD_LEFT);
+ $value = $decimal.'E'.$sign.$exponent;
+ } else {
+ $value = $this->_quoteDecimal($value, $quote, $escape_wildcards);
+ }
+ return $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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteDecimal($value, $quote, $escape_wildcards)
+ {
+ $value = (string)$value;
+ $value = preg_replace('/[^\d\.,\-+eE]/', '', $value);
+ if (preg_match('/[^\.\d]/', $value)) {
+ if (strpos($value, ',')) {
+ // 1000,00
+ if (!strpos($value, '.')) {
+ // convert the last "," to a "."
+ $value = strrev(str_replace(',', '.', strrev($value)));
+ // 1.000,00
+ } elseif (strpos($value, '.') && strpos($value, '.') < strpos($value, ',')) {
+ $value = str_replace('.', '', $value);
+ // convert the last "," to a "."
+ $value = strrev(str_replace(',', '.', strrev($value)));
+ // 1,000.00
+ } else {
+ $value = str_replace(',', '', $value);
+ }
+ }
+ }
+ return $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;
+ }
+
+ if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) {
+ if ($match[1] == 'file://') {
+ $file = $match[2];
+ }
+ }
+
+ $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,
+ 'could not write to the output file', __FUNCTION__);
+ }
+ }
+ @fclose($fp);
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ _retrieveLOB()
+
+ /**
+ * retrieve LOB from the database
+ *
+ * @param array $lob array
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access protected
+ */
+ function _retrieveLOB(&$lob)
+ {
+ if (null === $lob['value']) {
+ $lob['value'] = $lob['resource'];
+ }
+ $lob['loaded'] = true;
+ 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 array $lob array
+ * @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($this->lobs[$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 array $lob array
+ * @access private
+ */
+ function _destroyLOB(&$lob)
+ {
+ 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);
+ }
+
+ // }}}
+ // {{{ matchPattern()
+
+ /**
+ * build a pattern matching string
+ *
+ * @access public
+ *
+ * @param array $pattern even keys are strings, odd are patterns (% and _)
+ * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
+ * @param string $field optional field name that is being matched against
+ * (might be required when emulating ILIKE)
+ *
+ * @return string SQL pattern
+ */
+ function matchPattern($pattern, $operator = null, $field = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $match = '';
+ if (null !== $operator) {
+ $operator = strtoupper($operator);
+ switch ($operator) {
+ // case insensitive
+ case 'ILIKE':
+ if (null === $field) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'case insensitive LIKE matching requires passing the field name', __FUNCTION__);
+ }
+ $db->loadModule('Function', null, true);
+ $match = $db->function->lower($field).' LIKE ';
+ break;
+ case 'NOT ILIKE':
+ if (null === $field) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'case insensitive NOT ILIKE matching requires passing the field name', __FUNCTION__);
+ }
+ $db->loadModule('Function', null, true);
+ $match = $db->function->lower($field).' NOT LIKE ';
+ break;
+ // case sensitive
+ case 'LIKE':
+ $match = (null === $field) ? 'LIKE ' : ($field.' LIKE ');
+ break;
+ case 'NOT LIKE':
+ $match = (null === $field) ? 'NOT LIKE ' : ($field.' NOT LIKE ');
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'not a supported operator type:'. $operator, __FUNCTION__);
+ }
+ }
+ $match.= "'";
+ foreach ($pattern as $key => $value) {
+ if ($key % 2) {
+ $match.= $value;
+ } else {
+ $escaped = $db->escape($value);
+ if (PEAR::isError($escaped)) {
+ return $escaped;
+ }
+ $match.= $db->escapePattern($escaped);
+ }
+ }
+ $match.= "'";
+ $match.= $this->patternEscapeString();
+ return $match;
+ }
+
+ // }}}
+ // {{{ patternEscapeString()
+
+ /**
+ * build string to define pattern escape character
+ *
+ * @access public
+ *
+ * @return string define pattern escape character
+ */
+ function patternEscapeString()
+ {
+ return '';
+ }
+
+ // }}}
+ // {{{ mapNativeDatatype()
+
+ /**
+ * Maps a native array description of a field to a MDB2 datatype and length
+ *
+ * @param array $field native field description
+ * @return array containing the various possible types, length, sign, fixed
+ * @access public
+ */
+ function mapNativeDatatype($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ // If the user has specified an option to map the native field
+ // type to a custom MDB2 datatype...
+ $db_type = strtok($field['type'], '(), ');
+ if (!empty($db->options['nativetype_map_callback'][$db_type])) {
+ return call_user_func_array($db->options['nativetype_map_callback'][$db_type], array($db, $field));
+ }
+
+ // Otherwise perform the built-in (i.e. normal) MDB2 native type to
+ // MDB2 datatype conversion
+ return $this->_mapNativeDatatype($field);
+ }
+
+ // }}}
+ // {{{ _mapNativeDatatype()
+
+ /**
+ * Maps a native array description of a field to a MDB2 datatype and length
+ *
+ * @param array $field native field description
+ * @return array containing the various possible types, length, sign, fixed
+ * @access public
+ */
+ function _mapNativeDatatype($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ mapPrepareDatatype()
+
+ /**
+ * Maps an mdb2 datatype to mysqli prepare type
+ *
+ * @param string $type
+ * @return string
+ * @access public
+ */
+ function mapPrepareDatatype($type)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!empty($db->options['datatype_map'][$type])) {
+ $type = $db->options['datatype_map'][$type];
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type);
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ }
+ }
+
+ return $type;
+ }
+}
+?>
diff --git a/3rdparty/MDB2/Driver/Datatype/mysql.php b/3rdparty/MDB2/Driver/Datatype/mysql.php index 93dd40524e6..299901ae6e7 100644 --- a/3rdparty/MDB2/Driver/Datatype/mysql.php +++ b/3rdparty/MDB2/Driver/Datatype/mysql.php @@ -1,553 +1,562 @@ -<?php -// vim: set et ts=4 sw=4 fdm=marker: -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.65 2008/02/22 19:23:49 quipo Exp $ -// - -require_once('MDB2/Driver/Datatype/Common.php'); - -/** - * MDB2 MySQL driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common -{ - // {{{ _getCharsetFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $charset name of the charset - * @return string DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration. - */ - function _getCharsetFieldDeclaration($charset) - { - return 'CHARACTER SET '.$charset; - } - - // }}} - // {{{ _getCollationFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $collation name of the collation - * @return string DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration. - */ - function _getCollationFieldDeclaration($collation) - { - return 'COLLATE '.$collation; - } - - // }}} - // {{{ getTypeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @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 public - */ - function getTypeDeclaration($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - switch ($field['type']) { - case 'text': - if (empty($field['length']) && array_key_exists('default', $field)) { - $field['length'] = $db->varchar_max_length; - } - $length = !empty($field['length']) ? $field['length'] : false; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; - return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)') - : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); - case 'clob': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 255) { - return 'TINYTEXT'; - } elseif ($length <= 65532) { - return 'TEXT'; - } elseif ($length <= 16777215) { - return 'MEDIUMTEXT'; - } - } - return 'LONGTEXT'; - case 'blob': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 255) { - return 'TINYBLOB'; - } elseif ($length <= 65532) { - return 'BLOB'; - } elseif ($length <= 16777215) { - return 'MEDIUMBLOB'; - } - } - return 'LONGBLOB'; - case 'integer': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 1) { - return 'TINYINT'; - } elseif ($length == 2) { - return 'SMALLINT'; - } elseif ($length == 3) { - return 'MEDIUMINT'; - } elseif ($length == 4) { - return 'INT'; - } elseif ($length > 4) { - return 'BIGINT'; - } - } - return 'INT'; - case 'boolean': - return 'TINYINT(1)'; - case 'date': - return 'DATE'; - case 'time': - return 'TIME'; - case 'timestamp': - return 'DATETIME'; - case 'float': - return 'DOUBLE'; - case 'decimal': - $length = !empty($field['length']) ? $field['length'] : 18; - $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places']; - return 'DECIMAL('.$length.','.$scale.')'; - } - return ''; - } - - // }}} - // {{{ _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 string $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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $default = $autoinc = ''; - if (!empty($field['autoincrement'])) { - $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; - } elseif (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) ? null : 0; - } - $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc; - } - - // }}} - // {{{ _getFloatDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an float type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param string $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 float if - * possible. - * - * 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) - { - // Since AUTO_INCREMENT can be used for integer or floating-point types, - // reuse the INTEGER declaration - // @see http://bugs.mysql.com/bug.php?id=31032 - return $this->_getIntegerDeclaration($name, $field); - } - - // }}} - // {{{ _getDecimalDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an decimal type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param string $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 - * 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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $default = ''; - if (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) ? null : 0; - } - $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); - } elseif (empty($field['notnull'])) { - $default = ' DEFAULT NULL'; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull; - } - - // }}} - // {{{ matchPattern() - - /** - * build a pattern matching string - * - * @access public - * - * @param array $pattern even keys are strings, odd are patterns (% and _) - * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) - * @param string $field optional field name that is being matched against - * (might be required when emulating ILIKE) - * - * @return string SQL pattern - */ - function matchPattern($pattern, $operator = null, $field = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $match = ''; - if (!is_null($operator)) { - $field = is_null($field) ? '' : $field.' '; - $operator = strtoupper($operator); - switch ($operator) { - // case insensitive - case 'ILIKE': - $match = $field.'LIKE '; - break; - // case sensitive - case 'LIKE': - $match = $field.'LIKE BINARY '; - break; - default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'not a supported operator type:'. $operator, __FUNCTION__); - } - } - $match.= "'"; - foreach ($pattern as $key => $value) { - if ($key % 2) { - $match.= $value; - } else { - $match.= $db->escapePattern($db->escape($value)); - } - } - $match.= "'"; - $match.= $this->patternEscapeString(); - return $match; - } - - // }}} - // {{{ _mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function _mapNativeDatatype($field) - { - $db_type = strtolower($field['type']); - $db_type = strtok($db_type, '(), '); - if ($db_type == 'national') { - $db_type = strtok('(), '); - } - if (!empty($field['length'])) { - $length = strtok($field['length'], ', '); - $decimal = strtok(', '); - } else { - $length = strtok('(), '); - $decimal = strtok('(), '); - } - $type = array(); - $unsigned = $fixed = null; - switch ($db_type) { - case 'tinyint': - $type[] = 'integer'; - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 1; - break; - case 'smallint': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 2; - break; - case 'mediumint': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 3; - break; - case 'int': - case 'integer': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 4; - break; - case 'bigint': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 8; - break; - case 'tinytext': - case 'mediumtext': - case 'longtext': - case 'text': - case 'varchar': - $fixed = false; - case 'string': - case 'char': - $type[] = 'text'; - if ($length == '1') { - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - } elseif (strstr($db_type, 'text')) { - $type[] = 'clob'; - if ($decimal == 'binary') { - $type[] = 'blob'; - } - $type = array_reverse($type); - } - if ($fixed !== false) { - $fixed = true; - } - break; - case 'enum': - $type[] = 'text'; - preg_match_all('/\'.+\'/U', $field['type'], $matches); - $length = 0; - $fixed = false; - if (is_array($matches)) { - foreach ($matches[0] as $value) { - $length = max($length, strlen($value)-2); - } - if ($length == '1' && count($matches[0]) == 2) { - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - } - } - $type[] = 'integer'; - case 'set': - $fixed = false; - $type[] = 'text'; - $type[] = 'integer'; - break; - case 'date': - $type[] = 'date'; - $length = null; - break; - case 'datetime': - case 'timestamp': - $type[] = 'timestamp'; - $length = null; - break; - case 'time': - $type[] = 'time'; - $length = null; - break; - case 'float': - case 'double': - case 'real': - $type[] = 'float'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - break; - case 'unknown': - case 'decimal': - case 'numeric': - $type[] = 'decimal'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - if ($decimal !== false) { - $length = $length.','.$decimal; - } - break; - case 'tinyblob': - case 'mediumblob': - case 'longblob': - case 'blob': - $type[] = 'blob'; - $length = null; - break; - case 'binary': - case 'varbinary': - $type[] = 'blob'; - break; - case 'year': - $type[] = 'integer'; - $type[] = 'date'; - $length = null; - break; - default: - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'unknown database attribute type: '.$db_type, __FUNCTION__); - } - - if ((int)$length <= 0) { - $length = null; - } - - return array($type, $length, $unsigned, $fixed); - } - - // }}} -} - +<?php
+// vim: set et ts=4 sw=4 fdm=marker:
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Datatype/Common.php';
+
+/**
+ * MDB2 MySQL driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common
+{
+ // {{{ _getCharsetFieldDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
+ * of a field declaration to be used in statements like CREATE TABLE.
+ *
+ * @param string $charset name of the charset
+ * @return string DBMS specific SQL code portion needed to set the CHARACTER SET
+ * of a field declaration.
+ */
+ function _getCharsetFieldDeclaration($charset)
+ {
+ return 'CHARACTER SET '.$charset;
+ }
+
+ // }}}
+ // {{{ _getCollationFieldDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration to be used in statements like CREATE TABLE.
+ *
+ * @param string $collation name of the collation
+ * @return string DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration.
+ */
+ function _getCollationFieldDeclaration($collation)
+ {
+ return 'COLLATE '.$collation;
+ }
+
+ // }}}
+ // {{{ getTypeDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an text type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @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 public
+ */
+ function getTypeDeclaration($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ switch ($field['type']) {
+ case 'text':
+ if (empty($field['length']) && array_key_exists('default', $field)) {
+ $field['length'] = $db->varchar_max_length;
+ }
+ $length = !empty($field['length']) ? $field['length'] : false;
+ $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
+ return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
+ : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
+ case 'clob':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 255) {
+ return 'TINYTEXT';
+ } elseif ($length <= 65532) {
+ return 'TEXT';
+ } elseif ($length <= 16777215) {
+ return 'MEDIUMTEXT';
+ }
+ }
+ return 'LONGTEXT';
+ case 'blob':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 255) {
+ return 'TINYBLOB';
+ } elseif ($length <= 65532) {
+ return 'BLOB';
+ } elseif ($length <= 16777215) {
+ return 'MEDIUMBLOB';
+ }
+ }
+ return 'LONGBLOB';
+ case 'integer':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 1) {
+ return 'TINYINT';
+ } elseif ($length == 2) {
+ return 'SMALLINT';
+ } elseif ($length == 3) {
+ return 'MEDIUMINT';
+ } elseif ($length == 4) {
+ return 'INT';
+ } elseif ($length > 4) {
+ return 'BIGINT';
+ }
+ }
+ return 'INT';
+ case 'boolean':
+ return 'TINYINT(1)';
+ case 'date':
+ return 'DATE';
+ case 'time':
+ return 'TIME';
+ case 'timestamp':
+ return 'DATETIME';
+ case 'float':
+ return 'DOUBLE';
+ case 'decimal':
+ $length = !empty($field['length']) ? $field['length'] : 18;
+ $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
+ return 'DECIMAL('.$length.','.$scale.')';
+ }
+ return '';
+ }
+
+ // }}}
+ // {{{ _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 string $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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $default = $autoinc = '';
+ if (!empty($field['autoincrement'])) {
+ $autoinc = ' AUTO_INCREMENT PRIMARY KEY';
+ } elseif (array_key_exists('default', $field)) {
+ if ($field['default'] === '') {
+ $field['default'] = empty($field['notnull']) ? null : 0;
+ }
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
+ if (empty($default) && empty($notnull)) {
+ $default = ' DEFAULT NULL';
+ }
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
+ }
+
+ // }}}
+ // {{{ _getFloatDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an float type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @param string $name name the field to be declared.
+ * @param string $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 float if
+ * possible.
+ *
+ * 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)
+ {
+ // Since AUTO_INCREMENT can be used for integer or floating-point types,
+ // reuse the INTEGER declaration
+ // @see http://bugs.mysql.com/bug.php?id=31032
+ return $this->_getIntegerDeclaration($name, $field);
+ }
+
+ // }}}
+ // {{{ _getDecimalDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an decimal type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @param string $name name the field to be declared.
+ * @param string $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
+ * 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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $default = '';
+ if (array_key_exists('default', $field)) {
+ if ($field['default'] === '') {
+ $field['default'] = empty($field['notnull']) ? null : 0;
+ }
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
+ } elseif (empty($field['notnull'])) {
+ $default = ' DEFAULT NULL';
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull;
+ }
+
+ // }}}
+ // {{{ matchPattern()
+
+ /**
+ * build a pattern matching string
+ *
+ * @access public
+ *
+ * @param array $pattern even keys are strings, odd are patterns (% and _)
+ * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
+ * @param string $field optional field name that is being matched against
+ * (might be required when emulating ILIKE)
+ *
+ * @return string SQL pattern
+ */
+ function matchPattern($pattern, $operator = null, $field = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $match = '';
+ if (null !== $operator) {
+ $field = (null === $field) ? '' : $field.' ';
+ $operator = strtoupper($operator);
+ switch ($operator) {
+ // case insensitive
+ case 'ILIKE':
+ $match = $field.'LIKE ';
+ break;
+ case 'NOT ILIKE':
+ $match = $field.'NOT LIKE ';
+ break;
+ // case sensitive
+ case 'LIKE':
+ $match = $field.'LIKE BINARY ';
+ break;
+ case 'NOT LIKE':
+ $match = $field.'NOT LIKE BINARY ';
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'not a supported operator type:'. $operator, __FUNCTION__);
+ }
+ }
+ $match.= "'";
+ foreach ($pattern as $key => $value) {
+ if ($key % 2) {
+ $match.= $value;
+ } else {
+ $match.= $db->escapePattern($db->escape($value));
+ }
+ }
+ $match.= "'";
+ $match.= $this->patternEscapeString();
+ return $match;
+ }
+
+ // }}}
+ // {{{ _mapNativeDatatype()
+
+ /**
+ * Maps a native array description of a field to a MDB2 datatype and length
+ *
+ * @param array $field native field description
+ * @return array containing the various possible types, length, sign, fixed
+ * @access public
+ */
+ function _mapNativeDatatype($field)
+ {
+ $db_type = strtolower($field['type']);
+ $db_type = strtok($db_type, '(), ');
+ if ($db_type == 'national') {
+ $db_type = strtok('(), ');
+ }
+ if (!empty($field['length'])) {
+ $length = strtok($field['length'], ', ');
+ $decimal = strtok(', ');
+ } else {
+ $length = strtok('(), ');
+ $decimal = strtok('(), ');
+ }
+ $type = array();
+ $unsigned = $fixed = null;
+ switch ($db_type) {
+ case 'tinyint':
+ $type[] = 'integer';
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 1;
+ break;
+ case 'smallint':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 2;
+ break;
+ case 'mediumint':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 3;
+ break;
+ case 'int':
+ case 'integer':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 4;
+ break;
+ case 'bigint':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 8;
+ break;
+ case 'tinytext':
+ case 'mediumtext':
+ case 'longtext':
+ case 'text':
+ case 'varchar':
+ $fixed = false;
+ case 'string':
+ case 'char':
+ $type[] = 'text';
+ if ($length == '1') {
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ } elseif (strstr($db_type, 'text')) {
+ $type[] = 'clob';
+ if ($decimal == 'binary') {
+ $type[] = 'blob';
+ }
+ $type = array_reverse($type);
+ }
+ if ($fixed !== false) {
+ $fixed = true;
+ }
+ break;
+ case 'enum':
+ $type[] = 'text';
+ preg_match_all('/\'.+\'/U', $field['type'], $matches);
+ $length = 0;
+ $fixed = false;
+ if (is_array($matches)) {
+ foreach ($matches[0] as $value) {
+ $length = max($length, strlen($value)-2);
+ }
+ if ($length == '1' && count($matches[0]) == 2) {
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ }
+ }
+ $type[] = 'integer';
+ case 'set':
+ $fixed = false;
+ $type[] = 'text';
+ $type[] = 'integer';
+ break;
+ case 'date':
+ $type[] = 'date';
+ $length = null;
+ break;
+ case 'datetime':
+ case 'timestamp':
+ $type[] = 'timestamp';
+ $length = null;
+ break;
+ case 'time':
+ $type[] = 'time';
+ $length = null;
+ break;
+ case 'float':
+ case 'double':
+ case 'real':
+ $type[] = 'float';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ break;
+ case 'unknown':
+ case 'decimal':
+ case 'numeric':
+ $type[] = 'decimal';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ if ($decimal !== false) {
+ $length = $length.','.$decimal;
+ }
+ break;
+ case 'tinyblob':
+ case 'mediumblob':
+ case 'longblob':
+ case 'blob':
+ $type[] = 'blob';
+ $length = null;
+ break;
+ case 'binary':
+ case 'varbinary':
+ $type[] = 'blob';
+ break;
+ case 'year':
+ $type[] = 'integer';
+ $type[] = 'date';
+ $length = null;
+ break;
+ default:
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'unknown database attribute type: '.$db_type, __FUNCTION__);
+ }
+
+ if ((int)$length <= 0) {
+ $length = null;
+ }
+
+ return array($type, $length, $unsigned, $fixed);
+ }
+
+ // }}}
+}
+
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Datatype/pgsql.php b/3rdparty/MDB2/Driver/Datatype/pgsql.php index e72aa743b73..fec2c9799f5 100644 --- a/3rdparty/MDB2/Driver/Datatype/pgsql.php +++ b/3rdparty/MDB2/Driver/Datatype/pgsql.php @@ -1,554 +1,575 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Paul Cooper <pgc@ucecom.com> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.93 2008/08/28 20:32:57 afz Exp $ - -require_once('MDB2/Driver/Datatype/Common.php'); - -/** - * MDB2 PostGreSQL driver - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common -{ - // {{{ _baseConvertResult() - - /** - * General type conversion method - * - * @param mixed $value refernce to a value to be converted - * @param string $type specifies which type to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return object a MDB2 error on failure - * @access protected - */ - function _baseConvertResult($value, $type, $rtrim = true) - { - if (is_null($value)) { - return null; - } - switch ($type) { - case 'boolean': - return $value == 't'; - case 'float': - return doubleval($value); - case 'date': - return $value; - case 'time': - return substr($value, 0, strlen('HH:MM:SS')); - case 'timestamp': - return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS')); - case 'blob': - $value = pg_unescape_bytea($value); - return parent::_baseConvertResult($value, $type, $rtrim); - } - return parent::_baseConvertResult($value, $type, $rtrim); - } - - // }}} - // {{{ getTypeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @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 public - */ - function getTypeDeclaration($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - switch ($field['type']) { - case 'text': - $length = !empty($field['length']) ? $field['length'] : false; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; - return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') - : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); - case 'clob': - return 'TEXT'; - case 'blob': - return 'BYTEA'; - case 'integer': - if (!empty($field['autoincrement'])) { - if (!empty($field['length'])) { - $length = $field['length']; - if ($length > 4) { - return 'BIGSERIAL PRIMARY KEY'; - } - } - return 'SERIAL PRIMARY KEY'; - } - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 2) { - return 'SMALLINT'; - } elseif ($length == 3 || $length == 4) { - return 'INT'; - } elseif ($length > 4) { - return 'BIGINT'; - } - } - return 'INT'; - case 'boolean': - return 'BOOLEAN'; - case 'date': - return 'DATE'; - case 'time': - return 'TIME without time zone'; - case 'timestamp': - return 'TIMESTAMP without time zone'; - case 'float': - return 'FLOAT8'; - case 'decimal': - $length = !empty($field['length']) ? $field['length'] : 18; - $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places']; - return 'NUMERIC('.$length.','.$scale.')'; - } - } - - // }}} - // {{{ _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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($field['unsigned'])) { - $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; - } - if (!empty($field['autoincrement'])) { - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field); - } - $default = ''; - if (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) ? null : 0; - } - $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; - } - - // }}} - // {{{ _quoteCLOB() - - /** - * 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 bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteCLOB($value, $quote, $escape_wildcards) - { - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteBLOB() - - /** - * 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 bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBLOB($value, $quote, $escape_wildcards) - { - if (!$quote) { - return $value; - } - if (version_compare(PHP_VERSION, '5.2.0RC6', '>=')) { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $connection = $db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - $value = @pg_escape_bytea($connection, $value); - } else { - $value = @pg_escape_bytea($value); - } - return "'".$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. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBoolean($value, $quote, $escape_wildcards) - { - $value = $value ? 't' : 'f'; - if (!$quote) { - return $value; - } - return "'".$value."'"; - } - - // }}} - // {{{ matchPattern() - - /** - * build a pattern matching string - * - * @access public - * - * @param array $pattern even keys are strings, odd are patterns (% and _) - * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) - * @param string $field optional field name that is being matched against - * (might be required when emulating ILIKE) - * - * @return string SQL pattern - */ - function matchPattern($pattern, $operator = null, $field = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $match = ''; - if (!is_null($operator)) { - $field = is_null($field) ? '' : $field.' '; - $operator = strtoupper($operator); - switch ($operator) { - // case insensitive - case 'ILIKE': - $match = $field.'ILIKE '; - break; - // case sensitive - case 'LIKE': - $match = $field.'LIKE '; - break; - default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'not a supported operator type:'. $operator, __FUNCTION__); - } - } - $match.= "'"; - foreach ($pattern as $key => $value) { - if ($key % 2) { - $match.= $value; - } else { - $match.= $db->escapePattern($db->escape($value)); - } - } - $match.= "'"; - $match.= $this->patternEscapeString(); - return $match; - } - - // }}} - // {{{ patternEscapeString() - - /** - * build string to define escape pattern string - * - * @access public - * - * - * @return string define escape pattern - */ - function patternEscapeString() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - return ' ESCAPE '.$this->quote($db->string_quoting['escape_pattern']); - } - - // }}} - // {{{ _mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function _mapNativeDatatype($field) - { - $db_type = strtolower($field['type']); - $length = $field['length']; - $type = array(); - $unsigned = $fixed = null; - switch ($db_type) { - case 'smallint': - case 'int2': - $type[] = 'integer'; - $unsigned = false; - $length = 2; - if ($length == '2') { - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - } - break; - case 'int': - case 'int4': - case 'integer': - case 'serial': - case 'serial4': - $type[] = 'integer'; - $unsigned = false; - $length = 4; - break; - case 'bigint': - case 'int8': - case 'bigserial': - case 'serial8': - $type[] = 'integer'; - $unsigned = false; - $length = 8; - break; - case 'bool': - case 'boolean': - $type[] = 'boolean'; - $length = null; - break; - case 'text': - case 'varchar': - $fixed = false; - case 'unknown': - case 'char': - case 'bpchar': - $type[] = 'text'; - if ($length == '1') { - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - } elseif (strstr($db_type, 'text')) { - $type[] = 'clob'; - $type = array_reverse($type); - } - if ($fixed !== false) { - $fixed = true; - } - break; - case 'date': - $type[] = 'date'; - $length = null; - break; - case 'datetime': - case 'timestamp': - case 'timestamptz': - $type[] = 'timestamp'; - $length = null; - break; - case 'time': - $type[] = 'time'; - $length = null; - break; - case 'float': - case 'float4': - case 'float8': - case 'double': - case 'real': - $type[] = 'float'; - break; - case 'decimal': - case 'money': - case 'numeric': - $type[] = 'decimal'; - if (isset($field['scale'])) { - $length = $length.','.$field['scale']; - } - break; - case 'tinyblob': - case 'mediumblob': - case 'longblob': - case 'blob': - case 'bytea': - $type[] = 'blob'; - $length = null; - break; - case 'oid': - $type[] = 'blob'; - $type[] = 'clob'; - $length = null; - break; - case 'year': - $type[] = 'integer'; - $type[] = 'date'; - $length = null; - break; - default: - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'unknown database attribute type: '.$db_type, __FUNCTION__); - } - - if ((int)$length <= 0) { - $length = null; - } - - return array($type, $length, $unsigned, $fixed); - } - - // }}} - // {{{ mapPrepareDatatype() - - /** - * Maps an mdb2 datatype to native prepare type - * - * @param string $type - * @return string - * @access public - */ - function mapPrepareDatatype($type) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - - switch ($type) { - case 'integer': - return 'int'; - case 'boolean': - return 'bool'; - case 'decimal': - case 'float': - return 'numeric'; - case 'clob': - return 'text'; - case 'blob': - return 'bytea'; - default: - break; - } - return $type; - } - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Paul Cooper <pgc@ucecom.com> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 298763 2010-04-29 08:49:41Z afz $
+
+require_once 'MDB2/Driver/Datatype/Common.php';
+
+/**
+ * MDB2 PostGreSQL driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common
+{
+ // {{{ _baseConvertResult()
+
+ /**
+ * General type conversion method
+ *
+ * @param mixed $value refernce to a value to be converted
+ * @param string $type specifies which type to convert to
+ * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
+ * @return object a MDB2 error on failure
+ * @access protected
+ */
+ function _baseConvertResult($value, $type, $rtrim = true)
+ {
+ if (null === $value) {
+ return null;
+ }
+ switch ($type) {
+ case 'boolean':
+ return $value == 't';
+ case 'float':
+ return doubleval($value);
+ case 'date':
+ return $value;
+ case 'time':
+ return substr($value, 0, strlen('HH:MM:SS'));
+ case 'timestamp':
+ return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
+ case 'blob':
+ $value = pg_unescape_bytea($value);
+ return parent::_baseConvertResult($value, $type, $rtrim);
+ }
+ return parent::_baseConvertResult($value, $type, $rtrim);
+ }
+
+ // }}}
+ // {{{ getTypeDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an text type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @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 public
+ */
+ function getTypeDeclaration($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ switch ($field['type']) {
+ case 'text':
+ $length = !empty($field['length']) ? $field['length'] : false;
+ $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
+ return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
+ : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
+ case 'clob':
+ return 'TEXT';
+ case 'blob':
+ return 'BYTEA';
+ case 'integer':
+ if (!empty($field['autoincrement'])) {
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length > 4) {
+ return 'BIGSERIAL PRIMARY KEY';
+ }
+ }
+ return 'SERIAL PRIMARY KEY';
+ }
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 2) {
+ return 'SMALLINT';
+ } elseif ($length == 3 || $length == 4) {
+ return 'INT';
+ } elseif ($length > 4) {
+ return 'BIGINT';
+ }
+ }
+ return 'INT';
+ case 'boolean':
+ return 'BOOLEAN';
+ case 'date':
+ return 'DATE';
+ case 'time':
+ return 'TIME without time zone';
+ case 'timestamp':
+ return 'TIMESTAMP without time zone';
+ case 'float':
+ return 'FLOAT8';
+ case 'decimal':
+ $length = !empty($field['length']) ? $field['length'] : 18;
+ $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
+ return 'NUMERIC('.$length.','.$scale.')';
+ }
+ }
+
+ // }}}
+ // {{{ _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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!empty($field['unsigned'])) {
+ $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
+ }
+ if (!empty($field['autoincrement'])) {
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field);
+ }
+ $default = '';
+ if (array_key_exists('default', $field)) {
+ if ($field['default'] === '') {
+ $field['default'] = empty($field['notnull']) ? null : 0;
+ }
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ if (empty($default) && empty($notnull)) {
+ $default = ' DEFAULT NULL';
+ }
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
+ }
+
+ // }}}
+ // {{{ _quoteCLOB()
+
+ /**
+ * 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 bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteCLOB($value, $quote, $escape_wildcards)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $value = $this->_readFile($value, $db->options['lob_allow_url_include']);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ return $this->_quoteText($value, $quote, $escape_wildcards);
+ }
+
+ // }}}
+ // {{{ _quoteBLOB()
+
+ /**
+ * 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 bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteBLOB($value, $quote, $escape_wildcards)
+ {
+ if (!$quote) {
+ return $value;
+ }
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $value = $this->_readFile($value, $db->options['lob_allow_url_include']);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ if (version_compare(PHP_VERSION, '5.2.0RC6', '>=')) {
+ $connection = $db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ $value = @pg_escape_bytea($connection, $value);
+ } else {
+ $value = @pg_escape_bytea($value);
+ }
+ return "'".$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.
+ * @param bool $quote determines if the value should be quoted and escaped
+ * @param bool $escape_wildcards if to escape escape wildcards
+ * @return string text string that represents the given argument value in
+ * a DBMS specific format.
+ * @access protected
+ */
+ function _quoteBoolean($value, $quote, $escape_wildcards)
+ {
+ $value = $value ? 't' : 'f';
+ if (!$quote) {
+ return $value;
+ }
+ return "'".$value."'";
+ }
+
+ // }}}
+ // {{{ matchPattern()
+
+ /**
+ * build a pattern matching string
+ *
+ * @access public
+ *
+ * @param array $pattern even keys are strings, odd are patterns (% and _)
+ * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
+ * @param string $field optional field name that is being matched against
+ * (might be required when emulating ILIKE)
+ *
+ * @return string SQL pattern
+ */
+ function matchPattern($pattern, $operator = null, $field = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $match = '';
+ if (null !== $operator) {
+ $field = (null === $field) ? '' : $field.' ';
+ $operator = strtoupper($operator);
+ switch ($operator) {
+ // case insensitive
+ case 'ILIKE':
+ $match = $field.'ILIKE ';
+ break;
+ case 'NOT ILIKE':
+ $match = $field.'NOT ILIKE ';
+ break;
+ // case sensitive
+ case 'LIKE':
+ $match = $field.'LIKE ';
+ break;
+ case 'NOT LIKE':
+ $match = $field.'NOT LIKE ';
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'not a supported operator type:'. $operator, __FUNCTION__);
+ }
+ }
+ $match.= "'";
+ foreach ($pattern as $key => $value) {
+ if ($key % 2) {
+ $match.= $value;
+ } else {
+ $match.= $db->escapePattern($db->escape($value));
+ }
+ }
+ $match.= "'";
+ $match.= $this->patternEscapeString();
+ return $match;
+ }
+
+ // }}}
+ // {{{ patternEscapeString()
+
+ /**
+ * build string to define escape pattern string
+ *
+ * @access public
+ *
+ *
+ * @return string define escape pattern
+ */
+ function patternEscapeString()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ return ' ESCAPE '.$this->quote($db->string_quoting['escape_pattern']);
+ }
+
+ // }}}
+ // {{{ _mapNativeDatatype()
+
+ /**
+ * Maps a native array description of a field to a MDB2 datatype and length
+ *
+ * @param array $field native field description
+ * @return array containing the various possible types, length, sign, fixed
+ * @access public
+ */
+ function _mapNativeDatatype($field)
+ {
+ $db_type = strtolower($field['type']);
+ $length = $field['length'];
+ $type = array();
+ $unsigned = $fixed = null;
+ switch ($db_type) {
+ case 'smallint':
+ case 'int2':
+ $type[] = 'integer';
+ $unsigned = false;
+ $length = 2;
+ if ($length == '2') {
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ }
+ break;
+ case 'int':
+ case 'int4':
+ case 'integer':
+ case 'serial':
+ case 'serial4':
+ $type[] = 'integer';
+ $unsigned = false;
+ $length = 4;
+ break;
+ case 'bigint':
+ case 'int8':
+ case 'bigserial':
+ case 'serial8':
+ $type[] = 'integer';
+ $unsigned = false;
+ $length = 8;
+ break;
+ case 'bool':
+ case 'boolean':
+ $type[] = 'boolean';
+ $length = null;
+ break;
+ case 'text':
+ case 'varchar':
+ $fixed = false;
+ case 'unknown':
+ case 'char':
+ case 'bpchar':
+ $type[] = 'text';
+ if ($length == '1') {
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ } elseif (strstr($db_type, 'text')) {
+ $type[] = 'clob';
+ $type = array_reverse($type);
+ }
+ if ($fixed !== false) {
+ $fixed = true;
+ }
+ break;
+ case 'date':
+ $type[] = 'date';
+ $length = null;
+ break;
+ case 'datetime':
+ case 'timestamp':
+ case 'timestamptz':
+ $type[] = 'timestamp';
+ $length = null;
+ break;
+ case 'time':
+ $type[] = 'time';
+ $length = null;
+ break;
+ case 'float':
+ case 'float4':
+ case 'float8':
+ case 'double':
+ case 'real':
+ $type[] = 'float';
+ break;
+ case 'decimal':
+ case 'money':
+ case 'numeric':
+ $type[] = 'decimal';
+ if (isset($field['scale'])) {
+ $length = $length.','.$field['scale'];
+ }
+ break;
+ case 'tinyblob':
+ case 'mediumblob':
+ case 'longblob':
+ case 'blob':
+ case 'bytea':
+ $type[] = 'blob';
+ $length = null;
+ break;
+ case 'oid':
+ $type[] = 'blob';
+ $type[] = 'clob';
+ $length = null;
+ break;
+ case 'year':
+ $type[] = 'integer';
+ $type[] = 'date';
+ $length = null;
+ break;
+ default:
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'unknown database attribute type: '.$db_type, __FUNCTION__);
+ }
+
+ if ((int)$length <= 0) {
+ $length = null;
+ }
+
+ return array($type, $length, $unsigned, $fixed);
+ }
+
+ // }}}
+ // {{{ mapPrepareDatatype()
+
+ /**
+ * Maps an mdb2 datatype to native prepare type
+ *
+ * @param string $type
+ * @return string
+ * @access public
+ */
+ function mapPrepareDatatype($type)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!empty($db->options['datatype_map'][$type])) {
+ $type = $db->options['datatype_map'][$type];
+ if (!empty($db->options['datatype_map_callback'][$type])) {
+ $parameter = array('type' => $type);
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
+ }
+ }
+
+ switch ($type) {
+ case 'integer':
+ return 'int';
+ case 'boolean':
+ return 'bool';
+ case 'decimal':
+ case 'float':
+ return 'numeric';
+ case 'clob':
+ return 'text';
+ case 'blob':
+ return 'bytea';
+ default:
+ break;
+ }
+ return $type;
+ }
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Datatype/sqlite.php b/3rdparty/MDB2/Driver/Datatype/sqlite.php index 9e57e7e5678..e4711e46b32 100644 --- a/3rdparty/MDB2/Driver/Datatype/sqlite.php +++ b/3rdparty/MDB2/Driver/Datatype/sqlite.php @@ -1,409 +1,418 @@ -<?php -// vim: set et ts=4 sw=4 fdm=marker: -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.67 2008/02/22 19:58:06 quipo Exp $ -// - -require_once('MDB2/Driver/Datatype/Common.php'); - -/** - * MDB2 SQLite driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Datatype_sqlite extends MDB2_Driver_Datatype_Common -{ - // {{{ _getCollationFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $collation name of the collation - * - * @return string DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration. - */ - function _getCollationFieldDeclaration($collation) - { - return 'COLLATE '.$collation; - } - - // }}} - // {{{ getTypeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @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 public - */ - function getTypeDeclaration($field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - switch ($field['type']) { - case 'text': - $length = !empty($field['length']) - ? $field['length'] : false; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; - return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') - : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); - case 'clob': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 255) { - return 'TINYTEXT'; - } elseif ($length <= 65532) { - return 'TEXT'; - } elseif ($length <= 16777215) { - return 'MEDIUMTEXT'; - } - } - return 'LONGTEXT'; - case 'blob': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 255) { - return 'TINYBLOB'; - } elseif ($length <= 65532) { - return 'BLOB'; - } elseif ($length <= 16777215) { - return 'MEDIUMBLOB'; - } - } - return 'LONGBLOB'; - case 'integer': - if (!empty($field['length'])) { - $length = $field['length']; - if ($length <= 2) { - return 'SMALLINT'; - } elseif ($length == 3 || $length == 4) { - return 'INTEGER'; - } elseif ($length > 4) { - return 'BIGINT'; - } - } - return 'INTEGER'; - case 'boolean': - return 'BOOLEAN'; - case 'date': - return 'DATE'; - case 'time': - return 'TIME'; - case 'timestamp': - return 'DATETIME'; - case 'float': - return 'DOUBLE'.($db->options['fixed_float'] ? '('. - ($db->options['fixed_float']+2).','.$db->options['fixed_float'].')' : ''); - case 'decimal': - $length = !empty($field['length']) ? $field['length'] : 18; - $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places']; - return 'DECIMAL('.$length.','.$scale.')'; - } - return ''; - } - - // }}} - // {{{ _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 string $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) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $default = $autoinc = ''; - if (!empty($field['autoincrement'])) { - $autoinc = ' PRIMARY KEY'; - } elseif (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) ? null : 0; - } - $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc; - } - - // }}} - // {{{ matchPattern() - - /** - * build a pattern matching string - * - * @access public - * - * @param array $pattern even keys are strings, odd are patterns (% and _) - * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) - * @param string $field optional field name that is being matched against - * (might be required when emulating ILIKE) - * - * @return string SQL pattern - */ - function matchPattern($pattern, $operator = null, $field = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $match = ''; - if (!is_null($operator)) { - $field = is_null($field) ? '' : $field.' '; - $operator = strtoupper($operator); - switch ($operator) { - // case insensitive - case 'ILIKE': - $match = $field.'LIKE '; - break; - // case sensitive - case 'LIKE': - $match = $field.'LIKE '; - break; - default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'not a supported operator type:'. $operator, __FUNCTION__); - } - } - $match.= "'"; - foreach ($pattern as $key => $value) { - if ($key % 2) { - $match.= $value; - } else { - $match.= $db->escapePattern($db->escape($value)); - } - } - $match.= "'"; - $match.= $this->patternEscapeString(); - return $match; - } - - // }}} - // {{{ _mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function _mapNativeDatatype($field) - { - $db_type = strtolower($field['type']); - $length = !empty($field['length']) ? $field['length'] : null; - $unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null; - $fixed = null; - $type = array(); - switch ($db_type) { - case 'boolean': - $type[] = 'boolean'; - break; - case 'tinyint': - $type[] = 'integer'; - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 1; - break; - case 'smallint': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 2; - break; - case 'mediumint': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 3; - break; - case 'int': - case 'integer': - case 'serial': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 4; - break; - case 'bigint': - case 'bigserial': - $type[] = 'integer'; - $unsigned = preg_match('/ unsigned/i', $field['type']); - $length = 8; - break; - case 'clob': - $type[] = 'clob'; - $fixed = false; - break; - case 'tinytext': - case 'mediumtext': - case 'longtext': - case 'text': - case 'varchar': - case 'varchar2': - $fixed = false; - case 'char': - $type[] = 'text'; - if ($length == '1') { - $type[] = 'boolean'; - if (preg_match('/^(is|has)/', $field['name'])) { - $type = array_reverse($type); - } - } elseif (strstr($db_type, 'text')) { - $type[] = 'clob'; - $type = array_reverse($type); - } - if ($fixed !== false) { - $fixed = true; - } - break; - case 'date': - $type[] = 'date'; - $length = null; - break; - case 'datetime': - case 'timestamp': - $type[] = 'timestamp'; - $length = null; - break; - case 'time': - $type[] = 'time'; - $length = null; - break; - case 'float': - case 'double': - case 'real': - $type[] = 'float'; - break; - case 'decimal': - case 'numeric': - $type[] = 'decimal'; - $length = $length.','.$field['decimal']; - break; - case 'tinyblob': - case 'mediumblob': - case 'longblob': - case 'blob': - $type[] = 'blob'; - $length = null; - break; - case 'year': - $type[] = 'integer'; - $type[] = 'date'; - $length = null; - break; - default: - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'unknown database attribute type: '.$db_type, __FUNCTION__); - } - - if ((int)$length <= 0) { - $length = null; - } - - return array($type, $length, $unsigned, $fixed); - } - - // }}} -} - +<?php
+// vim: set et ts=4 sw=4 fdm=marker:
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Datatype/Common.php';
+
+/**
+ * MDB2 SQLite driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Datatype_sqlite extends MDB2_Driver_Datatype_Common
+{
+ // {{{ _getCollationFieldDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration to be used in statements like CREATE TABLE.
+ *
+ * @param string $collation name of the collation
+ *
+ * @return string DBMS specific SQL code portion needed to set the COLLATION
+ * of a field declaration.
+ */
+ function _getCollationFieldDeclaration($collation)
+ {
+ return 'COLLATE '.$collation;
+ }
+
+ // }}}
+ // {{{ getTypeDeclaration()
+
+ /**
+ * Obtain DBMS specific SQL code portion needed to declare an text type
+ * field to be used in statements like CREATE TABLE.
+ *
+ * @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 public
+ */
+ function getTypeDeclaration($field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ switch ($field['type']) {
+ case 'text':
+ $length = !empty($field['length'])
+ ? $field['length'] : false;
+ $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
+ return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
+ : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
+ case 'clob':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 255) {
+ return 'TINYTEXT';
+ } elseif ($length <= 65532) {
+ return 'TEXT';
+ } elseif ($length <= 16777215) {
+ return 'MEDIUMTEXT';
+ }
+ }
+ return 'LONGTEXT';
+ case 'blob':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 255) {
+ return 'TINYBLOB';
+ } elseif ($length <= 65532) {
+ return 'BLOB';
+ } elseif ($length <= 16777215) {
+ return 'MEDIUMBLOB';
+ }
+ }
+ return 'LONGBLOB';
+ case 'integer':
+ if (!empty($field['length'])) {
+ $length = $field['length'];
+ if ($length <= 2) {
+ return 'SMALLINT';
+ } elseif ($length == 3 || $length == 4) {
+ return 'INTEGER';
+ } elseif ($length > 4) {
+ return 'BIGINT';
+ }
+ }
+ return 'INTEGER';
+ case 'boolean':
+ return 'BOOLEAN';
+ case 'date':
+ return 'DATE';
+ case 'time':
+ return 'TIME';
+ case 'timestamp':
+ return 'DATETIME';
+ case 'float':
+ return 'DOUBLE'.($db->options['fixed_float'] ? '('.
+ ($db->options['fixed_float']+2).','.$db->options['fixed_float'].')' : '');
+ case 'decimal':
+ $length = !empty($field['length']) ? $field['length'] : 18;
+ $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
+ return 'DECIMAL('.$length.','.$scale.')';
+ }
+ return '';
+ }
+
+ // }}}
+ // {{{ _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 string $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)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $default = $autoinc = '';
+ if (!empty($field['autoincrement'])) {
+ $autoinc = ' PRIMARY KEY';
+ } elseif (array_key_exists('default', $field)) {
+ if ($field['default'] === '') {
+ $field['default'] = empty($field['notnull']) ? null : 0;
+ }
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
+ }
+
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
+ $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
+ if (empty($default) && empty($notnull)) {
+ $default = ' DEFAULT NULL';
+ }
+ $name = $db->quoteIdentifier($name, true);
+ return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
+ }
+
+ // }}}
+ // {{{ matchPattern()
+
+ /**
+ * build a pattern matching string
+ *
+ * @access public
+ *
+ * @param array $pattern even keys are strings, odd are patterns (% and _)
+ * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
+ * @param string $field optional field name that is being matched against
+ * (might be required when emulating ILIKE)
+ *
+ * @return string SQL pattern
+ */
+ function matchPattern($pattern, $operator = null, $field = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $match = '';
+ if (null !== $operator) {
+ $field = (null === $field) ? '' : $field.' ';
+ $operator = strtoupper($operator);
+ switch ($operator) {
+ // case insensitive
+ case 'ILIKE':
+ $match = $field.'LIKE ';
+ break;
+ case 'NOT ILIKE':
+ $match = $field.'NOT LIKE ';
+ break;
+ // case sensitive
+ case 'LIKE':
+ $match = $field.'LIKE ';
+ break;
+ case 'NOT LIKE':
+ $match = $field.'NOT LIKE ';
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'not a supported operator type:'. $operator, __FUNCTION__);
+ }
+ }
+ $match.= "'";
+ foreach ($pattern as $key => $value) {
+ if ($key % 2) {
+ $match.= $value;
+ } else {
+ $match.= $db->escapePattern($db->escape($value));
+ }
+ }
+ $match.= "'";
+ $match.= $this->patternEscapeString();
+ return $match;
+ }
+
+ // }}}
+ // {{{ _mapNativeDatatype()
+
+ /**
+ * Maps a native array description of a field to a MDB2 datatype and length
+ *
+ * @param array $field native field description
+ * @return array containing the various possible types, length, sign, fixed
+ * @access public
+ */
+ function _mapNativeDatatype($field)
+ {
+ $db_type = strtolower($field['type']);
+ $length = !empty($field['length']) ? $field['length'] : null;
+ $unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null;
+ $fixed = null;
+ $type = array();
+ switch ($db_type) {
+ case 'boolean':
+ $type[] = 'boolean';
+ break;
+ case 'tinyint':
+ $type[] = 'integer';
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 1;
+ break;
+ case 'smallint':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 2;
+ break;
+ case 'mediumint':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 3;
+ break;
+ case 'int':
+ case 'integer':
+ case 'serial':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 4;
+ break;
+ case 'bigint':
+ case 'bigserial':
+ $type[] = 'integer';
+ $unsigned = preg_match('/ unsigned/i', $field['type']);
+ $length = 8;
+ break;
+ case 'clob':
+ $type[] = 'clob';
+ $fixed = false;
+ break;
+ case 'tinytext':
+ case 'mediumtext':
+ case 'longtext':
+ case 'text':
+ case 'varchar':
+ case 'varchar2':
+ $fixed = false;
+ case 'char':
+ $type[] = 'text';
+ if ($length == '1') {
+ $type[] = 'boolean';
+ if (preg_match('/^(is|has)/', $field['name'])) {
+ $type = array_reverse($type);
+ }
+ } elseif (strstr($db_type, 'text')) {
+ $type[] = 'clob';
+ $type = array_reverse($type);
+ }
+ if ($fixed !== false) {
+ $fixed = true;
+ }
+ break;
+ case 'date':
+ $type[] = 'date';
+ $length = null;
+ break;
+ case 'datetime':
+ case 'timestamp':
+ $type[] = 'timestamp';
+ $length = null;
+ break;
+ case 'time':
+ $type[] = 'time';
+ $length = null;
+ break;
+ case 'float':
+ case 'double':
+ case 'real':
+ $type[] = 'float';
+ break;
+ case 'decimal':
+ case 'numeric':
+ $type[] = 'decimal';
+ $length = $length.','.$field['decimal'];
+ break;
+ case 'tinyblob':
+ case 'mediumblob':
+ case 'longblob':
+ case 'blob':
+ $type[] = 'blob';
+ $length = null;
+ break;
+ case 'year':
+ $type[] = 'integer';
+ $type[] = 'date';
+ $length = null;
+ break;
+ default:
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'unknown database attribute type: '.$db_type, __FUNCTION__);
+ }
+
+ if ((int)$length <= 0) {
+ $length = null;
+ }
+
+ return array($type, $length, $unsigned, $fixed);
+ }
+
+ // }}}
+}
+
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Function/Common.php b/3rdparty/MDB2/Driver/Function/Common.php index 731f06882ce..5d247bec359 100644 --- a/3rdparty/MDB2/Driver/Function/Common.php +++ b/3rdparty/MDB2/Driver/Function/Common.php @@ -1,293 +1,293 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.21 2008/02/17 18:51:39 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ - -/** - * Base class for the function modules that is extended by each MDB2 driver - * - * To load this module in the MDB2 object: - * $mdb->loadModule('Function'); - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Function_Common extends MDB2_Module_Common -{ - // {{{ executeStoredProc() - - /** - * Execute a stored procedure and return any results - * - * @param string $name string that identifies the function to execute - * @param mixed $params array that contains the paramaters to pass the stored proc - * @param mixed $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 - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * - * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} - // {{{ functionTable() - - /** - * return string for internal table used when calling only a function - * - * @return string for internal table used when calling only a function - * @access public - */ - function functionTable() - { - return ''; - } - - // }}} - // {{{ now() - - /** - * Return string to call a variable with the current timestamp inside an SQL statement - * There are three special variables for current date and time: - * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type) - * - CURRENT_DATE (date, DATE type) - * - CURRENT_TIME (time, TIME type) - * - * @param string $type 'timestamp' | 'time' | 'date' - * - * @return string to call a variable with the current timestamp - * @access public - */ - function now($type = 'timestamp') - { - switch ($type) { - case 'time': - return 'CURRENT_TIME'; - case 'date': - return 'CURRENT_DATE'; - case 'timestamp': - default: - return 'CURRENT_TIMESTAMP'; - } - } - - // }}} - // {{{ unixtimestamp() - - /** - * return string to call a function to get the unix timestamp from a iso timestamp - * - * @param string $expression - * - * @return string to call a variable with the timestamp - * @access public - */ - function unixtimestamp($expression) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} - // {{{ substring() - - /** - * return string to call a function to get a substring inside an SQL statement - * - * @return string to call a function to get a substring - * @access public - */ - function substring($value, $position = 1, $length = null) - { - if (!is_null($length)) { - return "SUBSTRING($value FROM $position FOR $length)"; - } - return "SUBSTRING($value FROM $position)"; - } - - // }}} - // {{{ replace() - - /** - * return string to call a function to get replace inside an SQL statement. - * - * @return string to call a function to get a replace - * @access public - */ - function replace($str, $from_str, $to_str) - { - return "REPLACE($str, $from_str , $to_str)"; - } - - // }}} - // {{{ concat() - - /** - * Returns string to concatenate two or more string parameters - * - * @param string $value1 - * @param string $value2 - * @param string $values... - * - * @return string to concatenate two strings - * @access public - */ - function concat($value1, $value2) - { - $args = func_get_args(); - return "(".implode(' || ', $args).")"; - } - - // }}} - // {{{ random() - - /** - * return string to call a function to get random value inside an SQL statement - * - * @return return string to generate float between 0 and 1 - * @access public - */ - function random() - { - return 'RAND()'; - } - - // }}} - // {{{ lower() - - /** - * return string to call a function to lower the case of an expression - * - * @param string $expression - * - * @return return string to lower case of an expression - * @access public - */ - function lower($expression) - { - return "LOWER($expression)"; - } - - // }}} - // {{{ upper() - - /** - * return string to call a function to upper the case of an expression - * - * @param string $expression - * - * @return return string to upper case of an expression - * @access public - */ - function upper($expression) - { - return "UPPER($expression)"; - } - - // }}} - // {{{ length() - - /** - * return string to call a function to get the length of a string expression - * - * @param string $expression - * - * @return return string to get the string expression length - * @access public - */ - function length($expression) - { - return "LENGTH($expression)"; - } - - // }}} - // {{{ guid() - - /** - * Returns global unique identifier - * - * @return string to get global unique identifier - * @access public - */ - function guid() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Common.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+
+/**
+ * Base class for the function modules that is extended by each MDB2 driver
+ *
+ * To load this module in the MDB2 object:
+ * $mdb->loadModule('Function');
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Function_Common extends MDB2_Module_Common
+{
+ // {{{ executeStoredProc()
+
+ /**
+ * Execute a stored procedure and return any results
+ *
+ * @param string $name string that identifies the function to execute
+ * @param mixed $params array that contains the paramaters to pass the stored proc
+ * @param mixed $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
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in
+ *
+ * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ return $error;
+ }
+
+ // }}}
+ // {{{ functionTable()
+
+ /**
+ * return string for internal table used when calling only a function
+ *
+ * @return string for internal table used when calling only a function
+ * @access public
+ */
+ function functionTable()
+ {
+ return '';
+ }
+
+ // }}}
+ // {{{ now()
+
+ /**
+ * Return string to call a variable with the current timestamp inside an SQL statement
+ * There are three special variables for current date and time:
+ * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type)
+ * - CURRENT_DATE (date, DATE type)
+ * - CURRENT_TIME (time, TIME type)
+ *
+ * @param string $type 'timestamp' | 'time' | 'date'
+ *
+ * @return string to call a variable with the current timestamp
+ * @access public
+ */
+ function now($type = 'timestamp')
+ {
+ switch ($type) {
+ case 'time':
+ return 'CURRENT_TIME';
+ case 'date':
+ return 'CURRENT_DATE';
+ case 'timestamp':
+ default:
+ return 'CURRENT_TIMESTAMP';
+ }
+ }
+
+ // }}}
+ // {{{ unixtimestamp()
+
+ /**
+ * return string to call a function to get the unix timestamp from a iso timestamp
+ *
+ * @param string $expression
+ *
+ * @return string to call a variable with the timestamp
+ * @access public
+ */
+ function unixtimestamp($expression)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ return $error;
+ }
+
+ // }}}
+ // {{{ substring()
+
+ /**
+ * return string to call a function to get a substring inside an SQL statement
+ *
+ * @return string to call a function to get a substring
+ * @access public
+ */
+ function substring($value, $position = 1, $length = null)
+ {
+ if (null !== $length) {
+ return "SUBSTRING($value FROM $position FOR $length)";
+ }
+ return "SUBSTRING($value FROM $position)";
+ }
+
+ // }}}
+ // {{{ replace()
+
+ /**
+ * return string to call a function to get replace inside an SQL statement.
+ *
+ * @return string to call a function to get a replace
+ * @access public
+ */
+ function replace($str, $from_str, $to_str)
+ {
+ return "REPLACE($str, $from_str , $to_str)";
+ }
+
+ // }}}
+ // {{{ concat()
+
+ /**
+ * Returns string to concatenate two or more string parameters
+ *
+ * @param string $value1
+ * @param string $value2
+ * @param string $values...
+ *
+ * @return string to concatenate two strings
+ * @access public
+ */
+ function concat($value1, $value2)
+ {
+ $args = func_get_args();
+ return "(".implode(' || ', $args).")";
+ }
+
+ // }}}
+ // {{{ random()
+
+ /**
+ * return string to call a function to get random value inside an SQL statement
+ *
+ * @return return string to generate float between 0 and 1
+ * @access public
+ */
+ function random()
+ {
+ return 'RAND()';
+ }
+
+ // }}}
+ // {{{ lower()
+
+ /**
+ * return string to call a function to lower the case of an expression
+ *
+ * @param string $expression
+ *
+ * @return return string to lower case of an expression
+ * @access public
+ */
+ function lower($expression)
+ {
+ return "LOWER($expression)";
+ }
+
+ // }}}
+ // {{{ upper()
+
+ /**
+ * return string to call a function to upper the case of an expression
+ *
+ * @param string $expression
+ *
+ * @return return string to upper case of an expression
+ * @access public
+ */
+ function upper($expression)
+ {
+ return "UPPER($expression)";
+ }
+
+ // }}}
+ // {{{ length()
+
+ /**
+ * return string to call a function to get the length of a string expression
+ *
+ * @param string $expression
+ *
+ * @return return string to get the string expression length
+ * @access public
+ */
+ function length($expression)
+ {
+ return "LENGTH($expression)";
+ }
+
+ // }}}
+ // {{{ guid()
+
+ /**
+ * Returns global unique identifier
+ *
+ * @return string to get global unique identifier
+ * @access public
+ */
+ function guid()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ return $error;
+ }
+
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Function/mysql.php b/3rdparty/MDB2/Driver/Function/mysql.php index 44183c3aa06..bf91536e1f3 100644 --- a/3rdparty/MDB2/Driver/Function/mysql.php +++ b/3rdparty/MDB2/Driver/Function/mysql.php @@ -1,136 +1,136 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.12 2008/02/17 18:54:08 quipo Exp $ -// - -require_once('MDB2/Driver/Function/Common.php'); - -/** - * MDB2 MySQL driver for the function modules - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Function_mysql extends MDB2_Driver_Function_Common -{ - // }}} - // {{{ executeStoredProc() - - /** - * Execute a stored procedure and return any results - * - * @param string $name string that identifies the function to execute - * @param mixed $params array that contains the paramaters to pass the stored proc - * @param mixed $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 - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'CALL '.$name; - $query .= $params ? '('.implode(', ', $params).')' : '()'; - return $db->query($query, $types, $result_class, $result_wrap_class); - } - - // }}} - // {{{ unixtimestamp() - - /** - * return string to call a function to get the unix timestamp from a iso timestamp - * - * @param string $expression - * - * @return string to call a variable with the timestamp - * @access public - */ - function unixtimestamp($expression) - { - return 'UNIX_TIMESTAMP('. $expression.')'; - } - - // }}} - // {{{ concat() - - /** - * Returns string to concatenate two or more string parameters - * - * @param string $value1 - * @param string $value2 - * @param string $values... - * @return string to concatenate two strings - * @access public - **/ - function concat($value1, $value2) - { - $args = func_get_args(); - return "CONCAT(".implode(', ', $args).")"; - } - - // }}} - // {{{ guid() - - /** - * Returns global unique identifier - * - * @return string to get global unique identifier - * @access public - */ - function guid() - { - return 'UUID()'; - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Function/Common.php';
+
+/**
+ * MDB2 MySQL driver for the function modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Function_mysql extends MDB2_Driver_Function_Common
+{
+ // }}}
+ // {{{ executeStoredProc()
+
+ /**
+ * Execute a stored procedure and return any results
+ *
+ * @param string $name string that identifies the function to execute
+ * @param mixed $params array that contains the paramaters to pass the stored proc
+ * @param mixed $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
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in
+ * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'CALL '.$name;
+ $query .= $params ? '('.implode(', ', $params).')' : '()';
+ return $db->query($query, $types, $result_class, $result_wrap_class);
+ }
+
+ // }}}
+ // {{{ unixtimestamp()
+
+ /**
+ * return string to call a function to get the unix timestamp from a iso timestamp
+ *
+ * @param string $expression
+ *
+ * @return string to call a variable with the timestamp
+ * @access public
+ */
+ function unixtimestamp($expression)
+ {
+ return 'UNIX_TIMESTAMP('. $expression.')';
+ }
+
+ // }}}
+ // {{{ concat()
+
+ /**
+ * Returns string to concatenate two or more string parameters
+ *
+ * @param string $value1
+ * @param string $value2
+ * @param string $values...
+ * @return string to concatenate two strings
+ * @access public
+ **/
+ function concat($value1, $value2)
+ {
+ $args = func_get_args();
+ return "CONCAT(".implode(', ', $args).")";
+ }
+
+ // }}}
+ // {{{ guid()
+
+ /**
+ * Returns global unique identifier
+ *
+ * @return string to get global unique identifier
+ * @access public
+ */
+ function guid()
+ {
+ return 'UUID()';
+ }
+
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Function/pgsql.php b/3rdparty/MDB2/Driver/Function/pgsql.php index 173bfc91494..e232e4feec1 100644 --- a/3rdparty/MDB2/Driver/Function/pgsql.php +++ b/3rdparty/MDB2/Driver/Function/pgsql.php @@ -1,115 +1,132 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Paul Cooper <pgc@ucecom.com> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.11 2008/11/09 19:46:50 quipo Exp $ - -require_once('MDB2/Driver/Function/Common.php'); - -/** - * MDB2 MySQL driver for the function modules - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Function_pgsql extends MDB2_Driver_Function_Common -{ - // {{{ executeStoredProc() - - /** - * Execute a stored procedure and return any results - * - * @param string $name string that identifies the function to execute - * @param mixed $params array that contains the paramaters to pass the stored proc - * @param mixed $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 - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT * FROM '.$name; - $query .= $params ? '('.implode(', ', $params).')' : '()'; - return $db->query($query, $types, $result_class, $result_wrap_class); - } - // }}} - // {{{ unixtimestamp() - - /** - * return string to call a function to get the unix timestamp from a iso timestamp - * - * @param string $expression - * - * @return string to call a variable with the timestamp - * @access public - */ - function unixtimestamp($expression) - { - return 'EXTRACT(EPOCH FROM DATE_TRUNC(\'seconds\', CAST ((' . $expression . ') AS TIMESTAMP)))'; - } - - // }}} - // {{{ random() - - /** - * return string to call a function to get random value inside an SQL statement - * - * @return return string to generate float between 0 and 1 - * @access public - */ - function random() - { - return 'RANDOM()'; - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Paul Cooper <pgc@ucecom.com> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 296139 2010-03-13 04:15:22Z afz $
+
+require_once 'MDB2/Driver/Function/Common.php';
+
+/**
+ * MDB2 MySQL driver for the function modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Function_pgsql extends MDB2_Driver_Function_Common
+{
+ // {{{ executeStoredProc()
+
+ /**
+ * Execute a stored procedure and return any results
+ *
+ * @param string $name string that identifies the function to execute
+ * @param mixed $params array that contains the paramaters to pass the stored proc
+ * @param mixed $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
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in
+ * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT * FROM '.$name;
+ $query .= $params ? '('.implode(', ', $params).')' : '()';
+ return $db->query($query, $types, $result_class, $result_wrap_class);
+ }
+ // }}}
+ // {{{ unixtimestamp()
+
+ /**
+ * return string to call a function to get the unix timestamp from a iso timestamp
+ *
+ * @param string $expression
+ *
+ * @return string to call a variable with the timestamp
+ * @access public
+ */
+ function unixtimestamp($expression)
+ {
+ return 'EXTRACT(EPOCH FROM DATE_TRUNC(\'seconds\', CAST ((' . $expression . ') AS TIMESTAMP)))';
+ }
+
+ // }}}
+ // {{{ substring()
+
+ /**
+ * return string to call a function to get a substring inside an SQL statement
+ *
+ * @return string to call a function to get a substring
+ * @access public
+ */
+ function substring($value, $position = 1, $length = null)
+ {
+ if (null !== $length) {
+ return "SUBSTRING(CAST($value AS VARCHAR) FROM $position FOR $length)";
+ }
+ return "SUBSTRING(CAST($value AS VARCHAR) FROM $position)";
+ }
+
+ // }}}
+ // {{{ random()
+
+ /**
+ * return string to call a function to get random value inside an SQL statement
+ *
+ * @return return string to generate float between 0 and 1
+ * @access public
+ */
+ function random()
+ {
+ return 'RANDOM()';
+ }
+
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Function/sqlite.php b/3rdparty/MDB2/Driver/Function/sqlite.php index 8a5b7ec8fad..0a46a4f06a5 100644 --- a/3rdparty/MDB2/Driver/Function/sqlite.php +++ b/3rdparty/MDB2/Driver/Function/sqlite.php @@ -1,162 +1,162 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.10 2008/02/17 18:54:08 quipo Exp $ -// - -require_once('MDB2/Driver/Function/Common.php'); - -/** - * MDB2 SQLite driver for the function modules - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Function_sqlite extends MDB2_Driver_Function_Common -{ - // {{{ constructor - - /** - * Constructor - */ - function __construct($db_index) - { - parent::__construct($db_index); - // create all sorts of UDFs - } - - // {{{ now() - - /** - * Return string to call a variable with the current timestamp inside an SQL statement - * There are three special variables for current date and time. - * - * @return string to call a variable with the current timestamp - * @access public - */ - function now($type = 'timestamp') - { - switch ($type) { - case 'time': - return 'time(\'now\')'; - case 'date': - return 'date(\'now\')'; - case 'timestamp': - default: - return 'datetime(\'now\')'; - } - } - - // }}} - // {{{ unixtimestamp() - - /** - * return string to call a function to get the unix timestamp from a iso timestamp - * - * @param string $expression - * - * @return string to call a variable with the timestamp - * @access public - */ - function unixtimestamp($expression) - { - return 'strftime("%s",'. $expression.', "utc")'; - } - - // }}} - // {{{ substring() - - /** - * return string to call a function to get a substring inside an SQL statement - * - * @return string to call a function to get a substring - * @access public - */ - function substring($value, $position = 1, $length = null) - { - if (!is_null($length)) { - return "substr($value,$position,$length)"; - } - return "substr($value,$position,length($value))"; - } - - // }}} - // {{{ random() - - /** - * return string to call a function to get random value inside an SQL statement - * - * @return return string to generate float between 0 and 1 - * @access public - */ - function random() - { - return '((RANDOM()+2147483648)/4294967296)'; - } - - // }}} - // {{{ replace() - - /** - * return string to call a function to get a replacement inside an SQL statement. - * - * @return string to call a function to get a replace - * @access public - */ - function replace($str, $from_str, $to_str) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} -} -?> +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Function/Common.php';
+
+/**
+ * MDB2 SQLite driver for the function modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Function_sqlite extends MDB2_Driver_Function_Common
+{
+ // {{{ constructor
+
+ /**
+ * Constructor
+ */
+ function __construct($db_index)
+ {
+ parent::__construct($db_index);
+ // create all sorts of UDFs
+ }
+
+ // {{{ now()
+
+ /**
+ * Return string to call a variable with the current timestamp inside an SQL statement
+ * There are three special variables for current date and time.
+ *
+ * @return string to call a variable with the current timestamp
+ * @access public
+ */
+ function now($type = 'timestamp')
+ {
+ switch ($type) {
+ case 'time':
+ return 'time(\'now\')';
+ case 'date':
+ return 'date(\'now\')';
+ case 'timestamp':
+ default:
+ return 'datetime(\'now\')';
+ }
+ }
+
+ // }}}
+ // {{{ unixtimestamp()
+
+ /**
+ * return string to call a function to get the unix timestamp from a iso timestamp
+ *
+ * @param string $expression
+ *
+ * @return string to call a variable with the timestamp
+ * @access public
+ */
+ function unixtimestamp($expression)
+ {
+ return 'strftime("%s",'. $expression.', "utc")';
+ }
+
+ // }}}
+ // {{{ substring()
+
+ /**
+ * return string to call a function to get a substring inside an SQL statement
+ *
+ * @return string to call a function to get a substring
+ * @access public
+ */
+ function substring($value, $position = 1, $length = null)
+ {
+ if (null !== $length) {
+ return "substr($value, $position, $length)";
+ }
+ return "substr($value, $position, length($value))";
+ }
+
+ // }}}
+ // {{{ random()
+
+ /**
+ * return string to call a function to get random value inside an SQL statement
+ *
+ * @return return string to generate float between 0 and 1
+ * @access public
+ */
+ function random()
+ {
+ return '((RANDOM()+2147483648)/4294967296)';
+ }
+
+ // }}}
+ // {{{ replace()
+
+ /**
+ * return string to call a function to get a replacement inside an SQL statement.
+ *
+ * @return string to call a function to get a replace
+ * @access public
+ */
+ function replace($str, $from_str, $to_str)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ return $error;
+ }
+
+ // }}}
+}
+?>
diff --git a/3rdparty/MDB2/Driver/Manager/Common.php b/3rdparty/MDB2/Driver/Manager/Common.php index 9e16749bffc..fadd72934d6 100644 --- a/3rdparty/MDB2/Driver/Manager/Common.php +++ b/3rdparty/MDB2/Driver/Manager/Common.php @@ -1,1014 +1,1014 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Authors: Lukas Smith <smith@pooteeweet.org> | -// | Lorenzo Alberton <l.alberton@quipo.it> | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.72 2009/01/14 15:00:40 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - * @author Lorenzo Alberton <l.alberton@quipo.it> - */ - -/** - * Base class for the management modules that is extended by each MDB2 driver - * - * To load this module in the MDB2 object: - * $mdb->loadModule('Manager'); - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Manager_Common extends MDB2_Module_Common -{ - // {{{ splitTableSchema() - - /** - * Split the "[owner|schema].table" notation into an array - * - * @param string $table [schema and] table name - * - * @return array array(schema, table) - * @access private - */ - function splitTableSchema($table) - { - $ret = array(); - if (strpos($table, '.') !== false) { - return explode('.', $table); - } - return array(null, $table); - } - - // }}} - // {{{ getFieldDeclarationList() - - /** - * Get declaration of a number of field in bulk - * - * @param array $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) || empty($fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'missing any fields', __FUNCTION__); - } - 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); - } - - // }}} - // {{{ _fixSequenceName() - - /** - * Removes any formatting in an sequence name using the 'seqname_format' option - * - * @param string $sqn string that containts name of a potential sequence - * @param bool $check if only formatted sequences should be returned - * @return string name of the sequence with possible formatting removed - * @access protected - */ - function _fixSequenceName($sqn, $check = false) - { - $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 && !strcasecmp($sqn, $db->getSequenceName($seq_name))) { - return $seq_name; - } - if ($check) { - return false; - } - return $sqn; - } - - // }}} - // {{{ _fixIndexName() - - /** - * Removes any formatting in an index name using the 'idxname_format' option - * - * @param string $idx string that containts name of anl index - * @return string name of the index with eventual formatting removed - * @access protected - */ - function _fixIndexName($idx) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $idx_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['idxname_format']).'$/i'; - $idx_name = preg_replace($idx_pattern, '\\1', $idx); - if ($idx_name && !strcasecmp($idx, $db->getIndexName($idx_name))) { - return $idx_name; - } - return $idx; - } - - // }}} - // {{{ createDatabase() - - /** - * create a new database - * - * @param string $name name of the database that should be created - * @param array $options array with charset, collation info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createDatabase($database, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ alterDatabase() - - /** - * alter an existing database - * - * @param string $name name of the database that should be created - * @param array $options array with charset, collation info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function alterDatabase($database, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ _getCreateTableQuery() - - /** - * Create a basic SQL query for a new table creation - * - * @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 - * @param array $options An associative array of table options - * - * @return mixed string (the SQL query) on success, a MDB2 error on failure - * @see createTable() - */ - function _getCreateTableQuery($name, $fields, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!$name) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no valid table name specified', __FUNCTION__); - } - if (empty($fields)) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no fields specified for table "'.$name.'"', __FUNCTION__); - } - $query_fields = $this->getFieldDeclarationList($fields); - if (PEAR::isError($query_fields)) { - return $query_fields; - } - if (!empty($options['primary'])) { - $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')'; - } - - $name = $db->quoteIdentifier($name, true); - $result = 'CREATE '; - if (!empty($options['temporary'])) { - $result .= $this->_getTemporaryTableQuery(); - } - $result .= " TABLE $name ($query_fields)"; - return $result; - } - - // }}} - // {{{ _getTemporaryTableQuery() - - /** - * A method to return the required SQL string that fits between CREATE ... TABLE - * to create the table as a temporary table. - * - * Should be overridden in driver classes to return the correct string for the - * specific database type. - * - * The default is to return the string "TEMPORARY" - this will result in a - * SQL error for any database that does not support temporary tables, or that - * requires a different SQL command from "CREATE TEMPORARY TABLE". - * - * @return string The string required to be placed between "CREATE" and "TABLE" - * to generate a temporary table, if possible. - */ - function _getTemporaryTableQuery() - { - return 'TEMPORARY'; - } - - // }}} - // {{{ 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. - * array( - * 'id' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * 'notnull' => 1 - * 'default' => 0 - * ), - * 'name' => array( - * 'type' => 'text', - * 'length' => 12 - * ), - * 'password' => array( - * 'type' => 'text', - * 'length' => 12 - * ) - * ); - * @param array $options An associative array of table options: - * array( - * 'comment' => 'Foo', - * 'temporary' => true|false, - * ); - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createTable($name, $fields, $options = array()) - { - $query = $this->_getCreateTableQuery($name, $fields, $options); - if (PEAR::isError($query)) { - return $query; - } - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $result = $db->exec($query); - if (PEAR::isError($result)) { - return $result; - } - return MDB2_OK; - } - - // }}} - // {{{ 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; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("DROP TABLE $name"); - } - - // }}} - // {{{ truncateTable() - - /** - * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, - * it falls back to a DELETE FROM TABLE query) - * - * @param string $name name of the table that should be truncated - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function truncateTable($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("DELETE FROM $name"); - } - - // }}} - // {{{ vacuum() - - /** - * Optimize (vacuum) all the tables in the db (or only the specified table) - * and optionally run ANALYZE. - * - * @param string $table table name (all the tables if empty) - * @param array $options an array with driver-specific options: - * - timeout [int] (in seconds) [mssql-only] - * - analyze [boolean] [pgsql and mysql] - * - full [boolean] [pgsql-only] - * - freeze [boolean] [pgsql-only] - * - * @return mixed MDB2_OK success, a MDB2 error on failure - * @access public - */ - function vacuum($table = null, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ 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 MDB2 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 MDB2 parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @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. - * @access public - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function alterTable($name, $changes, $check) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listDatabases() - - /** - * list all databases - * - * @return mixed array of database names 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, - 'method not implementedd', __FUNCTION__); - } - - // }}} - // {{{ listUsers() - - /** - * list all users - * - * @return mixed array of user names 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listViews() - - /** - * list all views in the current database - * - * @param string database, the current is default - * NB: not all the drivers can get the view names from - * a database other than the current one - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listViews($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableViews() - - /** - * list the views in the database that reference a given table - * - * @param string table for which all referenced views should be found - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listTableViews($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableTriggers() - - /** - * list all triggers in the database that reference a given table - * - * @param string table for which all referenced triggers should be found - * @return mixed array of trigger names on success, a MDB2 error on failure - * @access public - */ - function listTableTriggers($table = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listFunctions() - - /** - * list all functions in the current database - * - * @return mixed array of function names 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTables() - - /** - * list all tables in the current database - * - * @param string database, the current is default. - * NB: not all the drivers can get the table names from - * a database other than the current one - * @return mixed array of table names on success, a MDB2 error on failure - * @access public - */ - function listTables($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableFields() - - /** - * list all fields in a table in the current database - * - * @param string $table name of table that should be used in method - * @return mixed array of field names 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ 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; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "CREATE INDEX $name ON $table"; - $fields = array(); - foreach (array_keys($definition['fields']) as $field) { - $fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ 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; - } - - $name = $db->quoteIdentifier($db->getIndexName($name), true); - return $db->exec("DROP INDEX $name"); - } - - // }}} - // {{{ listTableIndexes() - - /** - * list all indexes in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of index names 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ _getAdvancedFKOptions() - - /** - * Return the FOREIGN KEY query section dealing with non-standard options - * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... - * - * @param array $definition - * @return string - * @access protected - */ - function _getAdvancedFKOptions($definition) - { - return ''; - } - - // }}} - // {{{ createConstraint() - - /** - * create a constraint on a table - * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * The full structure of the array looks like this: - * <pre> - * array ( - * [primary] => 0 - * [unique] => 0 - * [foreign] => 1 - * [check] => 0 - * [fields] => array ( - * [field1name] => array() // one entry per each field covered - * [field2name] => array() // by the index - * [field3name] => array( - * [sorting] => ascending - * [position] => 3 - * ) - * ) - * [references] => array( - * [table] => name - * [fields] => array( - * [field1name] => array( //one entry per each referenced field - * [position] => 1 - * ) - * ) - * ) - * [deferrable] => 0 - * [initiallydeferred] => 0 - * [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION - * [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION - * [match] => SIMPLE|PARTIAL|FULL - * ); - * </pre> - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createConstraint($table, $name, $definition) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "ALTER TABLE $table ADD CONSTRAINT $name"; - if (!empty($definition['primary'])) { - $query.= ' PRIMARY KEY'; - } elseif (!empty($definition['unique'])) { - $query.= ' UNIQUE'; - } elseif (!empty($definition['foreign'])) { - $query.= ' FOREIGN KEY'; - } - $fields = array(); - foreach (array_keys($definition['fields']) as $field) { - $fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $fields) . ')'; - if (!empty($definition['foreign'])) { - $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true); - $referenced_fields = array(); - foreach (array_keys($definition['references']['fields']) as $field) { - $referenced_fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $referenced_fields) . ')'; - $query .= $this->_getAdvancedFKOptions($definition); - } - return $db->exec($query); - } - - // }}} - // {{{ dropConstraint() - - /** - * drop existing constraint - * - * @param string $table name of table that should be used in method - * @param string $name name of the constraint to be dropped - * @param string $primary hint if the constraint is primary - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropConstraint($table, $name, $primary = false) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - return $db->exec("ALTER TABLE $table DROP CONSTRAINT $name"); - } - - // }}} - // {{{ listTableConstraints() - - /** - * list all constraints in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of constraint names on success, a MDB2 error on failure - * @access public - */ - function listTableConstraints($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ 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, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listSequences() - - /** - * list all sequences in the current database - * - * @param string database, the current is default - * NB: not all the drivers can get the sequence names from - * a database other than the current one - * @return mixed array of sequence names on success, a MDB2 error on failure - * @access public - */ - function listSequences($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Authors: Lukas Smith <smith@pooteeweet.org> |
+// | Lorenzo Alberton <l.alberton@quipo.it> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Common.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ * @author Lorenzo Alberton <l.alberton@quipo.it>
+ */
+
+/**
+ * Base class for the management modules that is extended by each MDB2 driver
+ *
+ * To load this module in the MDB2 object:
+ * $mdb->loadModule('Manager');
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Manager_Common extends MDB2_Module_Common
+{
+ // {{{ splitTableSchema()
+
+ /**
+ * Split the "[owner|schema].table" notation into an array
+ *
+ * @param string $table [schema and] table name
+ *
+ * @return array array(schema, table)
+ * @access private
+ */
+ function splitTableSchema($table)
+ {
+ $ret = array();
+ if (strpos($table, '.') !== false) {
+ return explode('.', $table);
+ }
+ return array(null, $table);
+ }
+
+ // }}}
+ // {{{ getFieldDeclarationList()
+
+ /**
+ * Get declaration of a number of field in bulk
+ *
+ * @param array $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) || empty($fields)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'missing any fields', __FUNCTION__);
+ }
+ 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);
+ }
+
+ // }}}
+ // {{{ _fixSequenceName()
+
+ /**
+ * Removes any formatting in an sequence name using the 'seqname_format' option
+ *
+ * @param string $sqn string that containts name of a potential sequence
+ * @param bool $check if only formatted sequences should be returned
+ * @return string name of the sequence with possible formatting removed
+ * @access protected
+ */
+ function _fixSequenceName($sqn, $check = false)
+ {
+ $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 && !strcasecmp($sqn, $db->getSequenceName($seq_name))) {
+ return $seq_name;
+ }
+ if ($check) {
+ return false;
+ }
+ return $sqn;
+ }
+
+ // }}}
+ // {{{ _fixIndexName()
+
+ /**
+ * Removes any formatting in an index name using the 'idxname_format' option
+ *
+ * @param string $idx string that containts name of anl index
+ * @return string name of the index with eventual formatting removed
+ * @access protected
+ */
+ function _fixIndexName($idx)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $idx_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['idxname_format']).'$/i';
+ $idx_name = preg_replace($idx_pattern, '\\1', $idx);
+ if ($idx_name && !strcasecmp($idx, $db->getIndexName($idx_name))) {
+ return $idx_name;
+ }
+ return $idx;
+ }
+
+ // }}}
+ // {{{ createDatabase()
+
+ /**
+ * create a new database
+ *
+ * @param string $name name of the database that should be created
+ * @param array $options array with charset, collation info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createDatabase($database, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ alterDatabase()
+
+ /**
+ * alter an existing database
+ *
+ * @param string $name name of the database that should be created
+ * @param array $options array with charset, collation info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function alterDatabase($database, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ _getCreateTableQuery()
+
+ /**
+ * Create a basic SQL query for a new table creation
+ *
+ * @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
+ * @param array $options An associative array of table options
+ *
+ * @return mixed string (the SQL query) on success, a MDB2 error on failure
+ * @see createTable()
+ */
+ function _getCreateTableQuery($name, $fields, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!$name) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
+ 'no valid table name specified', __FUNCTION__);
+ }
+ if (empty($fields)) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
+ 'no fields specified for table "'.$name.'"', __FUNCTION__);
+ }
+ $query_fields = $this->getFieldDeclarationList($fields);
+ if (PEAR::isError($query_fields)) {
+ return $query_fields;
+ }
+ if (!empty($options['primary'])) {
+ $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')';
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $result = 'CREATE ';
+ if (!empty($options['temporary'])) {
+ $result .= $this->_getTemporaryTableQuery();
+ }
+ $result .= " TABLE $name ($query_fields)";
+ return $result;
+ }
+
+ // }}}
+ // {{{ _getTemporaryTableQuery()
+
+ /**
+ * A method to return the required SQL string that fits between CREATE ... TABLE
+ * to create the table as a temporary table.
+ *
+ * Should be overridden in driver classes to return the correct string for the
+ * specific database type.
+ *
+ * The default is to return the string "TEMPORARY" - this will result in a
+ * SQL error for any database that does not support temporary tables, or that
+ * requires a different SQL command from "CREATE TEMPORARY TABLE".
+ *
+ * @return string The string required to be placed between "CREATE" and "TABLE"
+ * to generate a temporary table, if possible.
+ */
+ function _getTemporaryTableQuery()
+ {
+ return 'TEMPORARY';
+ }
+
+ // }}}
+ // {{{ 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.
+ * array(
+ * 'id' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * 'notnull' => 1
+ * 'default' => 0
+ * ),
+ * 'name' => array(
+ * 'type' => 'text',
+ * 'length' => 12
+ * ),
+ * 'password' => array(
+ * 'type' => 'text',
+ * 'length' => 12
+ * )
+ * );
+ * @param array $options An associative array of table options:
+ * array(
+ * 'comment' => 'Foo',
+ * 'temporary' => true|false,
+ * );
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createTable($name, $fields, $options = array())
+ {
+ $query = $this->_getCreateTableQuery($name, $fields, $options);
+ if (PEAR::isError($query)) {
+ return $query;
+ }
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $result = $db->exec($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("DROP TABLE $name");
+ }
+
+ // }}}
+ // {{{ truncateTable()
+
+ /**
+ * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
+ * it falls back to a DELETE FROM TABLE query)
+ *
+ * @param string $name name of the table that should be truncated
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function truncateTable($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("DELETE FROM $name");
+ }
+
+ // }}}
+ // {{{ vacuum()
+
+ /**
+ * Optimize (vacuum) all the tables in the db (or only the specified table)
+ * and optionally run ANALYZE.
+ *
+ * @param string $table table name (all the tables if empty)
+ * @param array $options an array with driver-specific options:
+ * - timeout [int] (in seconds) [mssql-only]
+ * - analyze [boolean] [pgsql and mysql]
+ * - full [boolean] [pgsql-only]
+ * - freeze [boolean] [pgsql-only]
+ *
+ * @return mixed MDB2_OK success, a MDB2 error on failure
+ * @access public
+ */
+ function vacuum($table = null, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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 MDB2 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 MDB2 parser.
+ *
+ * Example
+ * array(
+ * 'name' => 'userlist',
+ * 'add' => array(
+ * 'quota' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * )
+ * ),
+ * 'remove' => array(
+ * 'file_limit' => array(),
+ * 'time_limit' => array()
+ * ),
+ * 'change' => array(
+ * 'name' => array(
+ * 'length' => '20',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 20,
+ * ),
+ * )
+ * ),
+ * 'rename' => array(
+ * 'sex' => array(
+ * 'name' => 'gender',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 1,
+ * 'default' => 'M',
+ * ),
+ * )
+ * )
+ * )
+ *
+ * @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.
+ * @access public
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function alterTable($name, $changes, $check)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listDatabases()
+
+ /**
+ * list all databases
+ *
+ * @return mixed array of database names 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,
+ 'method not implementedd', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listUsers()
+
+ /**
+ * list all users
+ *
+ * @return mixed array of user names 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listViews()
+
+ /**
+ * list all views in the current database
+ *
+ * @param string database, the current is default
+ * NB: not all the drivers can get the view names from
+ * a database other than the current one
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listViews($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listTableViews()
+
+ /**
+ * list the views in the database that reference a given table
+ *
+ * @param string table for which all referenced views should be found
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableViews($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listTableTriggers()
+
+ /**
+ * list all triggers in the database that reference a given table
+ *
+ * @param string table for which all referenced triggers should be found
+ * @return mixed array of trigger names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableTriggers($table = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listFunctions()
+
+ /**
+ * list all functions in the current database
+ *
+ * @return mixed array of function names 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listTables()
+
+ /**
+ * list all tables in the current database
+ *
+ * @param string database, the current is default.
+ * NB: not all the drivers can get the table names from
+ * a database other than the current one
+ * @return mixed array of table names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTables($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listTableFields()
+
+ /**
+ * list all fields in a table in the current database
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of field names 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ $query = "CREATE INDEX $name ON $table";
+ $fields = array();
+ foreach (array_keys($definition['fields']) as $field) {
+ $fields[] = $db->quoteIdentifier($field, true);
+ }
+ $query .= ' ('. implode(', ', $fields) . ')';
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ return $db->exec("DROP INDEX $name");
+ }
+
+ // }}}
+ // {{{ listTableIndexes()
+
+ /**
+ * list all indexes in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of index names 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ _getAdvancedFKOptions()
+
+ /**
+ * Return the FOREIGN KEY query section dealing with non-standard options
+ * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
+ *
+ * @param array $definition
+ * @return string
+ * @access protected
+ */
+ function _getAdvancedFKOptions($definition)
+ {
+ return '';
+ }
+
+ // }}}
+ // {{{ createConstraint()
+
+ /**
+ * create a constraint on a table
+ *
+ * @param string $table name of the table on which the constraint is to be created
+ * @param string $name name of the constraint to be created
+ * @param array $definition associative array that defines properties of the constraint to be created.
+ * The full structure of the array looks like this:
+ * <pre>
+ * array (
+ * [primary] => 0
+ * [unique] => 0
+ * [foreign] => 1
+ * [check] => 0
+ * [fields] => array (
+ * [field1name] => array() // one entry per each field covered
+ * [field2name] => array() // by the index
+ * [field3name] => array(
+ * [sorting] => ascending
+ * [position] => 3
+ * )
+ * )
+ * [references] => array(
+ * [table] => name
+ * [fields] => array(
+ * [field1name] => array( //one entry per each referenced field
+ * [position] => 1
+ * )
+ * )
+ * )
+ * [deferrable] => 0
+ * [initiallydeferred] => 0
+ * [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
+ * [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
+ * [match] => SIMPLE|PARTIAL|FULL
+ * );
+ * </pre>
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createConstraint($table, $name, $definition)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ $query = "ALTER TABLE $table ADD CONSTRAINT $name";
+ if (!empty($definition['primary'])) {
+ $query.= ' PRIMARY KEY';
+ } elseif (!empty($definition['unique'])) {
+ $query.= ' UNIQUE';
+ } elseif (!empty($definition['foreign'])) {
+ $query.= ' FOREIGN KEY';
+ }
+ $fields = array();
+ foreach (array_keys($definition['fields']) as $field) {
+ $fields[] = $db->quoteIdentifier($field, true);
+ }
+ $query .= ' ('. implode(', ', $fields) . ')';
+ if (!empty($definition['foreign'])) {
+ $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true);
+ $referenced_fields = array();
+ foreach (array_keys($definition['references']['fields']) as $field) {
+ $referenced_fields[] = $db->quoteIdentifier($field, true);
+ }
+ $query .= ' ('. implode(', ', $referenced_fields) . ')';
+ $query .= $this->_getAdvancedFKOptions($definition);
+ }
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ dropConstraint()
+
+ /**
+ * drop existing constraint
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $name name of the constraint to be dropped
+ * @param string $primary hint if the constraint is primary
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function dropConstraint($table, $name, $primary = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ return $db->exec("ALTER TABLE $table DROP CONSTRAINT $name");
+ }
+
+ // }}}
+ // {{{ listTableConstraints()
+
+ /**
+ * list all constraints in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of constraint names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableConstraints($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listSequences()
+
+ /**
+ * list all sequences in the current database
+ *
+ * @param string database, the current is default
+ * NB: not all the drivers can get the sequence names from
+ * a database other than the current one
+ * @return mixed array of sequence names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listSequences($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Manager/mysql.php b/3rdparty/MDB2/Driver/Manager/mysql.php index 099ed48a84f..8bcb3383604 100644 --- a/3rdparty/MDB2/Driver/Manager/mysql.php +++ b/3rdparty/MDB2/Driver/Manager/mysql.php @@ -1,1432 +1,1436 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.113 2008/11/23 20:30:29 quipo Exp $ -// - -require_once('MDB2/Driver/Manager/Common.php'); - -/** - * MDB2 MySQL driver for the management modules - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common -{ - - // }}} - // {{{ createDatabase() - - /** - * create a new database - * - * @param string $name name of the database that should be created - * @param array $options array with charset, collation info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createDatabase($name, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $query = 'CREATE DATABASE ' . $name; - if (!empty($options['charset'])) { - $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text'); - } - if (!empty($options['collation'])) { - $query .= ' COLLATE ' . $db->quote($options['collation'], 'text'); - } - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ alterDatabase() - - /** - * alter an existing database - * - * @param string $name name of the database that is intended to be changed - * @param array $options array with charset, collation info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function alterDatabase($name, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true); - if (!empty($options['charset'])) { - $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text'); - } - if (!empty($options['collation'])) { - $query .= ' COLLATE ' . $db->quote($options['collation'], 'text'); - } - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ 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($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $query = "DROP DATABASE $name"; - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ _getAdvancedFKOptions() - - /** - * Return the FOREIGN KEY query section dealing with non-standard options - * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... - * - * @param array $definition - * @return string - * @access protected - */ - function _getAdvancedFKOptions($definition) - { - $query = ''; - if (!empty($definition['match'])) { - $query .= ' MATCH '.$definition['match']; - } - if (!empty($definition['onupdate'])) { - $query .= ' ON UPDATE '.$definition['onupdate']; - } - if (!empty($definition['ondelete'])) { - $query .= ' ON DELETE '.$definition['ondelete']; - } - return $query; - } - - // }}} - // {{{ 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. - * array( - * 'id' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * 'notnull' => 1 - * 'default' => 0 - * ), - * 'name' => array( - * 'type' => 'text', - * 'length' => 12 - * ), - * 'password' => array( - * 'type' => 'text', - * 'length' => 12 - * ) - * ); - * @param array $options An associative array of table options: - * array( - * 'comment' => 'Foo', - * 'charset' => 'utf8', - * 'collate' => 'utf8_unicode_ci', - * 'type' => 'innodb', - * ); - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createTable($name, $fields, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - // if we have an AUTO_INCREMENT column and a PK on more than one field, - // we have to handle it differently... - $autoincrement = null; - if (empty($options['primary'])) { - $pk_fields = array(); - foreach ($fields as $fieldname => $def) { - if (!empty($def['primary'])) { - $pk_fields[$fieldname] = true; - } - if (!empty($def['autoincrement'])) { - $autoincrement = $fieldname; - } - } - if (!is_null($autoincrement) && count($pk_fields) > 1) { - $options['primary'] = $pk_fields; - } else { - // the PK constraint is on max one field => OK - $autoincrement = null; - } - } - - $query = $this->_getCreateTableQuery($name, $fields, $options); - if (PEAR::isError($query)) { - return $query; - } - - if (!is_null($autoincrement)) { - // we have to remove the PK clause added by _getIntegerDeclaration() - $query = str_replace('AUTO_INCREMENT PRIMARY KEY', 'AUTO_INCREMENT', $query); - } - - $options_strings = array(); - - if (!empty($options['comment'])) { - $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); - } - - if (!empty($options['charset'])) { - $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; - if (!empty($options['collate'])) { - $options_strings['charset'].= ' COLLATE '.$options['collate']; - } - } - - $type = false; - if (!empty($options['type'])) { - $type = $options['type']; - } elseif ($db->options['default_table_type']) { - $type = $db->options['default_table_type']; - } - if ($type) { - $options_strings[] = "ENGINE = $type"; - } - - if (!empty($options_strings)) { - $query .= ' '.implode(' ', $options_strings); - } - $result = $db->exec($query); - if (PEAR::isError($result)) { - return $result; - } - return MDB2_OK; - } - - // }}} - // {{{ 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; - } - - //delete the triggers associated to existing FK constraints - $constraints = $this->listTableConstraints($name); - if (!PEAR::isError($constraints) && !empty($constraints)) { - $db->loadModule('Reverse', null, true); - foreach ($constraints as $constraint) { - $definition = $db->reverse->getTableConstraintDefinition($name, $constraint); - if (!PEAR::isError($definition) && !empty($definition['foreign'])) { - $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']); - if (PEAR::isError($result)) { - return $result; - } - } - } - } - - return parent::dropTable($name); - } - - // }}} - // {{{ truncateTable() - - /** - * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, - * it falls back to a DELETE FROM TABLE query) - * - * @param string $name name of the table that should be truncated - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function truncateTable($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("TRUNCATE TABLE $name"); - } - - // }}} - // {{{ vacuum() - - /** - * Optimize (vacuum) all the tables in the db (or only the specified table) - * and optionally run ANALYZE. - * - * @param string $table table name (all the tables if empty) - * @param array $options an array with driver-specific options: - * - timeout [int] (in seconds) [mssql-only] - * - analyze [boolean] [pgsql and mysql] - * - full [boolean] [pgsql-only] - * - freeze [boolean] [pgsql-only] - * - * @return mixed MDB2_OK success, a MDB2 error on failure - * @access public - */ - function vacuum($table = null, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (empty($table)) { - $table = $this->listTables(); - if (PEAR::isError($table)) { - return $table; - } - } - if (is_array($table)) { - foreach (array_keys($table) as $k) { - $table[$k] = $db->quoteIdentifier($table[$k], true); - } - $table = implode(', ', $table); - } else { - $table = $db->quoteIdentifier($table, true); - } - - $result = $db->exec('OPTIMIZE TABLE '.$table); - if (PEAR::isError($result)) { - return $result; - } - if (!empty($options['analyze'])) { - return $db->exec('ANALYZE TABLE '.$table); - } - return MDB2_OK; - } - - // }}} - // {{{ 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 MDB2 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 MDB2 parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @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. - * @access public - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function alterTable($name, $changes, $check) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - foreach ($changes as $change_name => $change) { - switch ($change_name) { - case 'add': - case 'remove': - case 'change': - case 'rename': - case 'name': - break; - default: - return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'change type "'.$change_name.'" not yet supported', __FUNCTION__); - } - } - - if ($check) { - return MDB2_OK; - } - - $query = ''; - if (!empty($changes['name'])) { - $change_name = $db->quoteIdentifier($changes['name'], true); - $query .= 'RENAME TO ' . $change_name; - } - - if (!empty($changes['add']) && is_array($changes['add'])) { - foreach ($changes['add'] as $field_name => $field) { - if ($query) { - $query.= ', '; - } - $query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field); - } - } - - if (!empty($changes['remove']) && is_array($changes['remove'])) { - foreach ($changes['remove'] as $field_name => $field) { - if ($query) { - $query.= ', '; - } - $field_name = $db->quoteIdentifier($field_name, true); - $query.= 'DROP ' . $field_name; - } - } - - $rename = array(); - if (!empty($changes['rename']) && is_array($changes['rename'])) { - foreach ($changes['rename'] as $field_name => $field) { - $rename[$field['name']] = $field_name; - } - } - - if (!empty($changes['change']) && is_array($changes['change'])) { - foreach ($changes['change'] as $field_name => $field) { - if ($query) { - $query.= ', '; - } - if (isset($rename[$field_name])) { - $old_field_name = $rename[$field_name]; - unset($rename[$field_name]); - } else { - $old_field_name = $field_name; - } - $old_field_name = $db->quoteIdentifier($old_field_name, true); - $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type'], $field_name, $field['definition']); - } - } - - if (!empty($rename) && is_array($rename)) { - foreach ($rename as $rename_name => $renamed_field) { - if ($query) { - $query.= ', '; - } - $field = $changes['rename'][$renamed_field]; - $renamed_field = $db->quoteIdentifier($renamed_field, true); - $query.= 'CHANGE ' . $renamed_field . ' ' . $db->getDeclaration($field['definition']['type'], $field['name'], $field['definition']); - } - } - - if (!$query) { - return MDB2_OK; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("ALTER TABLE $name $query"); - } - - // }}} - // {{{ listDatabases() - - /** - * list all databases - * - * @return mixed array of database names on success, a MDB2 error on failure - * @access public - */ - function listDatabases() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->queryCol('SHOW DATABASES'); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listUsers() - - /** - * list all users - * - * @return mixed array of user names on success, a MDB2 error on failure - * @access public - */ - function listUsers() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER'); - } - - // }}} - // {{{ listFunctions() - - /** - * list all functions in the current database - * - * @return mixed array of function names on success, a MDB2 error on failure - * @access public - */ - function listFunctions() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name FROM mysql.proc"; - /* - SELECT ROUTINE_NAME - FROM INFORMATION_SCHEMA.ROUTINES - WHERE ROUTINE_TYPE = 'FUNCTION' - */ - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableTriggers() - - /** - * list all triggers in the database that reference a given table - * - * @param string table for which all referenced triggers should be found - * @return mixed array of trigger names on success, a MDB2 error on failure - * @access public - */ - function listTableTriggers($table = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SHOW TRIGGERS'; - if (!is_null($table)) { - $table = $db->quote($table, 'text'); - $query .= " LIKE $table"; - } - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTables() - - /** - * list all tables in the current database - * - * @param string database, the current is default - * @return mixed array of table names on success, a MDB2 error on failure - * @access public - */ - function listTables($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SHOW /*!50002 FULL*/ TABLES"; - if (!is_null($database)) { - $query .= " FROM $database"; - } - $query.= "/*!50002 WHERE Table_type = 'BASE TABLE'*/"; - - $table_names = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED); - if (PEAR::isError($table_names)) { - return $table_names; - } - - $result = array(); - foreach ($table_names as $table) { - if (!$this->_fixSequenceName($table[0], true)) { - $result[] = $table[0]; - } - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listViews() - - /** - * list all views in the current database - * - * @param string database, the current is default - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listViews($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SHOW FULL TABLES'; - if (!is_null($database)) { - $query.= " FROM $database"; - } - $query.= " WHERE Table_type = 'VIEW'"; - - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableFields() - - /** - * list all fields in a table in the current database - * - * @param string $table name of table that should be used in method - * @return mixed array of field names on success, a MDB2 error on failure - * @access public - */ - function listTableFields($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quoteIdentifier($table, true); - $result = $db->queryCol("SHOW COLUMNS FROM $table"); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ createIndex() - - /** - * Get the stucture of a field into an array - * - * @author Leoncx - * @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' - * 'length' => 10 - * ), - * '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; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "CREATE INDEX $name ON $table"; - $fields = array(); - foreach ($definition['fields'] as $field => $fieldinfo) { - if (!empty($fieldinfo['length'])) { - $fields[] = $db->quoteIdentifier($field, true) . '(' . $fieldinfo['length'] . ')'; - } else { - $fields[] = $db->quoteIdentifier($field, true); - } - } - $query .= ' ('. implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ 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; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - return $db->exec("DROP INDEX $name ON $table"); - } - - // }}} - // {{{ listTableIndexes() - - /** - * list all indexes in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of index names on success, a MDB2 error on failure - * @access public - */ - function listTableIndexes($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $key_name = 'Key_name'; - $non_unique = 'Non_unique'; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $key_name = strtolower($key_name); - $non_unique = strtolower($non_unique); - } else { - $key_name = strtoupper($key_name); - $non_unique = strtoupper($non_unique); - } - } - - $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table"; - $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $result = array(); - foreach ($indexes as $index_data) { - if ($index_data[$non_unique] && ($index = $this->_fixIndexName($index_data[$key_name]))) { - $result[$index] = true; - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ createConstraint() - - /** - * create a constraint on a table - * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'fields' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createConstraint($table, $name, $definition) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $type = ''; - $idx_name = $db->quoteIdentifier($db->getIndexName($name), true); - if (!empty($definition['primary'])) { - $type = 'PRIMARY'; - $idx_name = 'KEY'; - } elseif (!empty($definition['unique'])) { - $type = 'UNIQUE'; - } elseif (!empty($definition['foreign'])) { - $type = 'CONSTRAINT'; - } - if (empty($type)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'invalid definition, could not create constraint', __FUNCTION__); - } - - $table_quoted = $db->quoteIdentifier($table, true); - $query = "ALTER TABLE $table_quoted ADD $type $idx_name"; - if (!empty($definition['foreign'])) { - $query .= ' FOREIGN KEY'; - } - $fields = array(); - foreach ($definition['fields'] as $field => $fieldinfo) { - $quoted = $db->quoteIdentifier($field, true); - if (!empty($fieldinfo['length'])) { - $quoted .= '(' . $fieldinfo['length'] . ')'; - } - $fields[] = $quoted; - } - $query .= ' ('. implode(', ', $fields) . ')'; - if (!empty($definition['foreign'])) { - $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true); - $referenced_fields = array(); - foreach (array_keys($definition['references']['fields']) as $field) { - $referenced_fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $referenced_fields) . ')'; - $query .= $this->_getAdvancedFKOptions($definition); - - // add index on FK column(s) or we can't add a FK constraint - // @see http://forums.mysql.com/read.php?22,19755,226009 - $result = $this->createIndex($table, $name.'_fkidx', $definition); - if (PEAR::isError($result)) { - return $result; - } - } - $res = $db->exec($query); - if (PEAR::isError($res)) { - return $res; - } - if (!empty($definition['foreign'])) { - return $this->_createFKTriggers($table, array($name => $definition)); - } - return MDB2_OK; - } - - // }}} - // {{{ dropConstraint() - - /** - * drop existing constraint - * - * @param string $table name of table that should be used in method - * @param string $name name of the constraint to be dropped - * @param string $primary hint if the constraint is primary - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropConstraint($table, $name, $primary = false) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if ($primary || strtolower($name) == 'primary') { - $query = 'ALTER TABLE '. $db->quoteIdentifier($table, true) .' DROP PRIMARY KEY'; - return $db->exec($query); - } - - //is it a FK constraint? If so, also delete the associated triggers - $db->loadModule('Reverse', null, true); - $definition = $db->reverse->getTableConstraintDefinition($table, $name); - if (!PEAR::isError($definition) && !empty($definition['foreign'])) { - //first drop the FK enforcing triggers - $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']); - if (PEAR::isError($result)) { - return $result; - } - //then drop the constraint itself - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "ALTER TABLE $table DROP FOREIGN KEY $name"; - return $db->exec($query); - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "ALTER TABLE $table DROP INDEX $name"; - return $db->exec($query); - } - - // }}} - // {{{ _createFKTriggers() - - /** - * Create triggers to enforce the FOREIGN KEY constraint on the table - * - * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql, - * we call a non-existent procedure to raise the FK violation message. - * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877 - * - * @param string $table table name - * @param array $foreign_keys FOREIGN KEY definitions - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access private - */ - function _createFKTriggers($table, $foreign_keys) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - // create triggers to enforce FOREIGN KEY constraints - if ($db->supports('triggers') && !empty($foreign_keys)) { - $table_quoted = $db->quoteIdentifier($table, true); - foreach ($foreign_keys as $fkname => $fkdef) { - if (empty($fkdef)) { - continue; - } - //set actions to default if not set - $fkdef['onupdate'] = empty($fkdef['onupdate']) ? $db->options['default_fk_action_onupdate'] : strtoupper($fkdef['onupdate']); - $fkdef['ondelete'] = empty($fkdef['ondelete']) ? $db->options['default_fk_action_ondelete'] : strtoupper($fkdef['ondelete']); - - $trigger_names = array( - 'insert' => $fkname.'_insert_trg', - 'update' => $fkname.'_update_trg', - 'pk_update' => $fkname.'_pk_update_trg', - 'pk_delete' => $fkname.'_pk_delete_trg', - ); - $table_fields = array_keys($fkdef['fields']); - $referenced_fields = array_keys($fkdef['references']['fields']); - - //create the ON [UPDATE|DELETE] triggers on the primary table - $restrict_action = ' IF (SELECT '; - $aliased_fields = array(); - foreach ($table_fields as $field) { - $aliased_fields[] = $table_quoted .'.'.$field .' AS '.$field; - } - $restrict_action .= implode(',', $aliased_fields) - .' FROM '.$table_quoted - .' WHERE '; - $conditions = array(); - $new_values = array(); - $null_values = array(); - for ($i=0; $i<count($table_fields); $i++) { - $conditions[] = $table_fields[$i] .' = OLD.'.$referenced_fields[$i]; - $new_values[] = $table_fields[$i] .' = NEW.'.$referenced_fields[$i]; - $null_values[] = $table_fields[$i] .' = NULL'; - } - $conditions2 = array(); - for ($i=0; $i<count($referenced_fields); $i++) { - $conditions2[] = 'NEW.'.$referenced_fields[$i] .' <> OLD.'.$referenced_fields[$i]; - } - $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL' - .' AND (' .implode(' OR ', $conditions2) .')' - .' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();' - .' END IF;'; - - $cascade_action_update = 'UPDATE '.$table_quoted.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions). ';'; - $cascade_action_delete = 'DELETE FROM '.$table_quoted.' WHERE '.implode(' AND ', $conditions). ';'; - $setnull_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions). ';'; - - if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) { - $db->loadModule('Reverse', null, true); - $default_values = array(); - foreach ($table_fields as $table_field) { - $field_definition = $db->reverse->getTableFieldDefinition($table, $field); - if (PEAR::isError($field_definition)) { - return $field_definition; - } - $default_values[] = $table_field .' = '. $field_definition[0]['default']; - } - $setdefault_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions). ';'; - } - - $query = 'CREATE TRIGGER %s' - .' %s ON '.$fkdef['references']['table'] - .' FOR EACH ROW BEGIN ' - .' SET FOREIGN_KEY_CHECKS = 0; '; //only really needed for ON UPDATE CASCADE - - if ('CASCADE' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $cascade_action_update; - } elseif ('SET NULL' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action; - } elseif ('SET DEFAULT' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action; - } elseif ('NO ACTION' == $fkdef['onupdate']) { - $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'AFTER UPDATE', 'update'); - } elseif ('RESTRICT' == $fkdef['onupdate']) { - $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update'); - } - if ('CASCADE' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $cascade_action_delete; - } elseif ('SET NULL' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action; - } elseif ('SET DEFAULT' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action; - } elseif ('NO ACTION' == $fkdef['ondelete']) { - $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete'); - } elseif ('RESTRICT' == $fkdef['ondelete']) { - $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete'); - } - $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;'; - $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;'; - - $db->pushErrorHandling(PEAR_ERROR_RETURN); - $db->expectError(MDB2_ERROR_CANNOT_CREATE); - $result = $db->exec($sql_delete); - $expected_errmsg = 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table'; - $db->popExpect(); - $db->popErrorHandling(); - if (PEAR::isError($result)) { - if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) { - return $result; - } - $db->warnings[] = $expected_errmsg; - } - $db->pushErrorHandling(PEAR_ERROR_RETURN); - $db->expectError(MDB2_ERROR_CANNOT_CREATE); - $result = $db->exec($sql_update); - $db->popExpect(); - $db->popErrorHandling(); - if (PEAR::isError($result) && $result->getCode() != MDB2_ERROR_CANNOT_CREATE) { - if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) { - return $result; - } - $db->warnings[] = $expected_errmsg; - } - } - } - return MDB2_OK; - } - - // }}} - // {{{ _dropFKTriggers() - - /** - * Drop the triggers created to enforce the FOREIGN KEY constraint on the table - * - * @param string $table table name - * @param string $fkname FOREIGN KEY constraint name - * @param string $referenced_table referenced table name - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access private - */ - function _dropFKTriggers($table, $fkname, $referenced_table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $triggers = $this->listTableTriggers($table); - $triggers2 = $this->listTableTriggers($referenced_table); - if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) { - $triggers = array_merge($triggers, $triggers2); - $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i'; - foreach ($triggers as $trigger) { - if (preg_match($pattern, $trigger)) { - $result = $db->exec('DROP TRIGGER '.$trigger); - if (PEAR::isError($result)) { - return $result; - } - } - } - } - return MDB2_OK; - } - - // }}} - // {{{ listTableConstraints() - - /** - * list all constraints in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of constraint names on success, a MDB2 error on failure - * @access public - */ - function listTableConstraints($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $key_name = 'Key_name'; - $non_unique = 'Non_unique'; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $key_name = strtolower($key_name); - $non_unique = strtolower($non_unique); - } else { - $key_name = strtoupper($key_name); - $non_unique = strtoupper($non_unique); - } - } - - $query = 'SHOW INDEX FROM ' . $db->quoteIdentifier($table, true); - $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $result = array(); - foreach ($indexes as $index_data) { - if (!$index_data[$non_unique]) { - if ($index_data[$key_name] !== 'PRIMARY') { - $index = $this->_fixIndexName($index_data[$key_name]); - } else { - $index = 'PRIMARY'; - } - if (!empty($index)) { - $result[$index] = true; - } - } - } - - //list FOREIGN KEY constraints... - $query = 'SHOW CREATE TABLE '. $db->escape($table); - $definition = $db->queryOne($query, 'text', 1); - if (!PEAR::isError($definition) && !empty($definition)) { - $pattern = '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims'; - if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 0) { - foreach ($matches[1] as $constraint) { - $result[$constraint] = true; - } - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ 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 - * @param array $options An associative array of table options: - * array( - * 'comment' => 'Foo', - * 'charset' => 'utf8', - * 'collate' => 'utf8_unicode_ci', - * 'type' => 'innodb', - * ); - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createSequence($seq_name, $start = 1, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true); - - $options_strings = array(); - - if (!empty($options['comment'])) { - $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); - } - - if (!empty($options['charset'])) { - $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; - if (!empty($options['collate'])) { - $options_strings['charset'].= ' COLLATE '.$options['collate']; - } - } - - $type = false; - if (!empty($options['type'])) { - $type = $options['type']; - } elseif ($db->options['default_table_type']) { - $type = $db->options['default_table_type']; - } - if ($type) { - $options_strings[] = "ENGINE = $type"; - } - - $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))"; - if (!empty($options_strings)) { - $query .= ' '.implode(' ', $options_strings); - } - $res = $db->exec($query); - if (PEAR::isError($res)) { - return $res; - } - - if ($start == 1) { - return MDB2_OK; - } - - $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'; - $res = $db->exec($query); - if (!PEAR::isError($res)) { - return MDB2_OK; - } - - // Handle error - $result = $db->exec("DROP TABLE $sequence_name"); - if (PEAR::isError($result)) { - return $db->raiseError($result, null, null, - 'could not drop inconsistent sequence table', __FUNCTION__); - } - - return $db->raiseError($res, null, null, - 'could not create sequence table', __FUNCTION__); - } - - // }}} - // {{{ 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($seq_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - return $db->exec("DROP TABLE $sequence_name"); - } - - // }}} - // {{{ listSequences() - - /** - * list all sequences in the current database - * - * @param string database, the current is default - * @return mixed array of sequence names on success, a MDB2 error on failure - * @access public - */ - function listSequences($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SHOW TABLES"; - if (!is_null($database)) { - $query .= " FROM $database"; - } - $table_names = $db->queryCol($query); - if (PEAR::isError($table_names)) { - return $table_names; - } - - $result = array(); - foreach ($table_names as $table_name) { - if ($sqn = $this->_fixSequenceName($table_name, true)) { - $result[] = $sqn; - } - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 302865 2010-08-29 10:30:55Z quipo $
+//
+
+require_once 'MDB2/Driver/Manager/Common.php';
+
+/**
+ * MDB2 MySQL driver for the management modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common
+{
+
+ // }}}
+ // {{{ createDatabase()
+
+ /**
+ * create a new database
+ *
+ * @param string $name name of the database that should be created
+ * @param array $options array with charset, collation info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createDatabase($name, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $query = 'CREATE DATABASE ' . $name;
+ if (!empty($options['charset'])) {
+ $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
+ }
+ if (!empty($options['collation'])) {
+ $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
+ }
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ alterDatabase()
+
+ /**
+ * alter an existing database
+ *
+ * @param string $name name of the database that is intended to be changed
+ * @param array $options array with charset, collation info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function alterDatabase($name, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true);
+ if (!empty($options['charset'])) {
+ $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text');
+ }
+ if (!empty($options['collation'])) {
+ $query .= ' COLLATE ' . $db->quote($options['collation'], 'text');
+ }
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ 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($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $query = "DROP DATABASE $name";
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ _getAdvancedFKOptions()
+
+ /**
+ * Return the FOREIGN KEY query section dealing with non-standard options
+ * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
+ *
+ * @param array $definition
+ * @return string
+ * @access protected
+ */
+ function _getAdvancedFKOptions($definition)
+ {
+ $query = '';
+ if (!empty($definition['match'])) {
+ $query .= ' MATCH '.$definition['match'];
+ }
+ if (!empty($definition['onupdate'])) {
+ $query .= ' ON UPDATE '.$definition['onupdate'];
+ }
+ if (!empty($definition['ondelete'])) {
+ $query .= ' ON DELETE '.$definition['ondelete'];
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ 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.
+ * array(
+ * 'id' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * 'notnull' => 1
+ * 'default' => 0
+ * ),
+ * 'name' => array(
+ * 'type' => 'text',
+ * 'length' => 12
+ * ),
+ * 'password' => array(
+ * 'type' => 'text',
+ * 'length' => 12
+ * )
+ * );
+ * @param array $options An associative array of table options:
+ * array(
+ * 'comment' => 'Foo',
+ * 'charset' => 'utf8',
+ * 'collate' => 'utf8_unicode_ci',
+ * 'type' => 'innodb',
+ * );
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createTable($name, $fields, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ // if we have an AUTO_INCREMENT column and a PK on more than one field,
+ // we have to handle it differently...
+ $autoincrement = null;
+ if (empty($options['primary'])) {
+ $pk_fields = array();
+ foreach ($fields as $fieldname => $def) {
+ if (!empty($def['primary'])) {
+ $pk_fields[$fieldname] = true;
+ }
+ if (!empty($def['autoincrement'])) {
+ $autoincrement = $fieldname;
+ }
+ }
+ if ((null !== $autoincrement) && count($pk_fields) > 1) {
+ $options['primary'] = $pk_fields;
+ } else {
+ // the PK constraint is on max one field => OK
+ $autoincrement = null;
+ }
+ }
+
+ $query = $this->_getCreateTableQuery($name, $fields, $options);
+ if (PEAR::isError($query)) {
+ return $query;
+ }
+
+ if (null !== $autoincrement) {
+ // we have to remove the PK clause added by _getIntegerDeclaration()
+ $query = str_replace('AUTO_INCREMENT PRIMARY KEY', 'AUTO_INCREMENT', $query);
+ }
+
+ $options_strings = array();
+
+ if (!empty($options['comment'])) {
+ $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text');
+ }
+
+ if (!empty($options['charset'])) {
+ $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset'];
+ if (!empty($options['collate'])) {
+ $options_strings['charset'].= ' COLLATE '.$options['collate'];
+ }
+ }
+
+ $type = false;
+ if (!empty($options['type'])) {
+ $type = $options['type'];
+ } elseif ($db->options['default_table_type']) {
+ $type = $db->options['default_table_type'];
+ }
+ if ($type) {
+ $options_strings[] = "ENGINE = $type";
+ }
+
+ if (!empty($options_strings)) {
+ $query .= ' '.implode(' ', $options_strings);
+ }
+ $result = $db->exec($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ //delete the triggers associated to existing FK constraints
+ $constraints = $this->listTableConstraints($name);
+ if (!PEAR::isError($constraints) && !empty($constraints)) {
+ $db->loadModule('Reverse', null, true);
+ foreach ($constraints as $constraint) {
+ $definition = $db->reverse->getTableConstraintDefinition($name, $constraint);
+ if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
+ $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ }
+
+ return parent::dropTable($name);
+ }
+
+ // }}}
+ // {{{ truncateTable()
+
+ /**
+ * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
+ * it falls back to a DELETE FROM TABLE query)
+ *
+ * @param string $name name of the table that should be truncated
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function truncateTable($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("TRUNCATE TABLE $name");
+ }
+
+ // }}}
+ // {{{ vacuum()
+
+ /**
+ * Optimize (vacuum) all the tables in the db (or only the specified table)
+ * and optionally run ANALYZE.
+ *
+ * @param string $table table name (all the tables if empty)
+ * @param array $options an array with driver-specific options:
+ * - timeout [int] (in seconds) [mssql-only]
+ * - analyze [boolean] [pgsql and mysql]
+ * - full [boolean] [pgsql-only]
+ * - freeze [boolean] [pgsql-only]
+ *
+ * @return mixed MDB2_OK success, a MDB2 error on failure
+ * @access public
+ */
+ function vacuum($table = null, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (empty($table)) {
+ $table = $this->listTables();
+ if (PEAR::isError($table)) {
+ return $table;
+ }
+ }
+ if (is_array($table)) {
+ foreach (array_keys($table) as $k) {
+ $table[$k] = $db->quoteIdentifier($table[$k], true);
+ }
+ $table = implode(', ', $table);
+ } else {
+ $table = $db->quoteIdentifier($table, true);
+ }
+
+ $result = $db->exec('OPTIMIZE TABLE '.$table);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if (!empty($options['analyze'])) {
+ return $db->exec('ANALYZE TABLE '.$table);
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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 MDB2 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 MDB2 parser.
+ *
+ * Example
+ * array(
+ * 'name' => 'userlist',
+ * 'add' => array(
+ * 'quota' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * )
+ * ),
+ * 'remove' => array(
+ * 'file_limit' => array(),
+ * 'time_limit' => array()
+ * ),
+ * 'change' => array(
+ * 'name' => array(
+ * 'length' => '20',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 20,
+ * ),
+ * )
+ * ),
+ * 'rename' => array(
+ * 'sex' => array(
+ * 'name' => 'gender',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 1,
+ * 'default' => 'M',
+ * ),
+ * )
+ * )
+ * )
+ *
+ * @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.
+ * @access public
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function alterTable($name, $changes, $check)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ foreach ($changes as $change_name => $change) {
+ switch ($change_name) {
+ case 'add':
+ case 'remove':
+ case 'change':
+ case 'rename':
+ case 'name':
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
+ 'change type "'.$change_name.'" not yet supported', __FUNCTION__);
+ }
+ }
+
+ if ($check) {
+ return MDB2_OK;
+ }
+
+ $query = '';
+ if (!empty($changes['name'])) {
+ $change_name = $db->quoteIdentifier($changes['name'], true);
+ $query .= 'RENAME TO ' . $change_name;
+ }
+
+ if (!empty($changes['add']) && is_array($changes['add'])) {
+ foreach ($changes['add'] as $field_name => $field) {
+ if ($query) {
+ $query.= ', ';
+ }
+ $query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
+ }
+ }
+
+ if (!empty($changes['remove']) && is_array($changes['remove'])) {
+ foreach ($changes['remove'] as $field_name => $field) {
+ if ($query) {
+ $query.= ', ';
+ }
+ $field_name = $db->quoteIdentifier($field_name, true);
+ $query.= 'DROP ' . $field_name;
+ }
+ }
+
+ $rename = array();
+ if (!empty($changes['rename']) && is_array($changes['rename'])) {
+ foreach ($changes['rename'] as $field_name => $field) {
+ $rename[$field['name']] = $field_name;
+ }
+ }
+
+ if (!empty($changes['change']) && is_array($changes['change'])) {
+ foreach ($changes['change'] as $field_name => $field) {
+ if ($query) {
+ $query.= ', ';
+ }
+ if (isset($rename[$field_name])) {
+ $old_field_name = $rename[$field_name];
+ unset($rename[$field_name]);
+ } else {
+ $old_field_name = $field_name;
+ }
+ $old_field_name = $db->quoteIdentifier($old_field_name, true);
+ $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type'], $field_name, $field['definition']);
+ }
+ }
+
+ if (!empty($rename) && is_array($rename)) {
+ foreach ($rename as $rename_name => $renamed_field) {
+ if ($query) {
+ $query.= ', ';
+ }
+ $field = $changes['rename'][$renamed_field];
+ $renamed_field = $db->quoteIdentifier($renamed_field, true);
+ $query.= 'CHANGE ' . $renamed_field . ' ' . $db->getDeclaration($field['definition']['type'], $field['name'], $field['definition']);
+ }
+ }
+
+ if (!$query) {
+ return MDB2_OK;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("ALTER TABLE $name $query");
+ }
+
+ // }}}
+ // {{{ listDatabases()
+
+ /**
+ * list all databases
+ *
+ * @return mixed array of database names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listDatabases()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $result = $db->queryCol('SHOW DATABASES');
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listUsers()
+
+ /**
+ * list all users
+ *
+ * @return mixed array of user names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listUsers()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER');
+ }
+
+ // }}}
+ // {{{ listFunctions()
+
+ /**
+ * list all functions in the current database
+ *
+ * @return mixed array of function names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listFunctions()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name FROM mysql.proc";
+ /*
+ SELECT ROUTINE_NAME
+ FROM INFORMATION_SCHEMA.ROUTINES
+ WHERE ROUTINE_TYPE = 'FUNCTION'
+ */
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableTriggers()
+
+ /**
+ * list all triggers in the database that reference a given table
+ *
+ * @param string table for which all referenced triggers should be found
+ * @return mixed array of trigger names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableTriggers($table = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SHOW TRIGGERS';
+ if (null !== $table) {
+ $table = $db->quote($table, 'text');
+ $query .= " LIKE $table";
+ }
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTables()
+
+ /**
+ * list all tables in the current database
+ *
+ * @param string database, the current is default
+ * @return mixed array of table names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTables($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SHOW /*!50002 FULL*/ TABLES";
+ if (null !== $database) {
+ $query .= " FROM $database";
+ }
+ $query.= "/*!50002 WHERE Table_type = 'BASE TABLE'*/";
+
+ $table_names = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED);
+ if (PEAR::isError($table_names)) {
+ return $table_names;
+ }
+
+ $result = array();
+ foreach ($table_names as $table) {
+ if (!$this->_fixSequenceName($table[0], true)) {
+ $result[] = $table[0];
+ }
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listViews()
+
+ /**
+ * list all views in the current database
+ *
+ * @param string database, the current is default
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listViews($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SHOW FULL TABLES';
+ if (null !== $database) {
+ $query.= " FROM $database";
+ }
+ $query.= " WHERE Table_type = 'VIEW'";
+
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableFields()
+
+ /**
+ * list all fields in a table in the current database
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of field names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableFields($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $result = $db->queryCol("SHOW COLUMNS FROM $table");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ createIndex()
+
+ /**
+ * Get the stucture of a field into an array
+ *
+ * @author Leoncx
+ * @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'
+ * 'length' => 10
+ * ),
+ * '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;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ $query = "CREATE INDEX $name ON $table";
+ $fields = array();
+ foreach ($definition['fields'] as $field => $fieldinfo) {
+ if (!empty($fieldinfo['length'])) {
+ $fields[] = $db->quoteIdentifier($field, true) . '(' . $fieldinfo['length'] . ')';
+ } else {
+ $fields[] = $db->quoteIdentifier($field, true);
+ }
+ }
+ $query .= ' ('. implode(', ', $fields) . ')';
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ return $db->exec("DROP INDEX $name ON $table");
+ }
+
+ // }}}
+ // {{{ listTableIndexes()
+
+ /**
+ * list all indexes in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of index names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableIndexes($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $key_name = 'Key_name';
+ $non_unique = 'Non_unique';
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $key_name = strtolower($key_name);
+ $non_unique = strtolower($non_unique);
+ } else {
+ $key_name = strtoupper($key_name);
+ $non_unique = strtoupper($non_unique);
+ }
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $query = "SHOW INDEX FROM $table";
+ $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $result = array();
+ foreach ($indexes as $index_data) {
+ if ($index_data[$non_unique] && ($index = $this->_fixIndexName($index_data[$key_name]))) {
+ $result[$index] = true;
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ createConstraint()
+
+ /**
+ * create a constraint on a table
+ *
+ * @param string $table name of the table on which the constraint is to be created
+ * @param string $name name of the constraint to be created
+ * @param array $definition associative array that defines properties of the constraint to be created.
+ * Currently, only one property named FIELDS is supported. This property
+ * is also an associative with the names of the constraint fields as array
+ * constraints. Each entry of this array is set to another type of associative
+ * array that specifies properties of the constraint that are specific to
+ * each field.
+ *
+ * Example
+ * array(
+ * 'fields' => array(
+ * 'user_name' => array(),
+ * 'last_login' => array()
+ * )
+ * )
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createConstraint($table, $name, $definition)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $type = '';
+ $idx_name = $db->quoteIdentifier($db->getIndexName($name), true);
+ if (!empty($definition['primary'])) {
+ $type = 'PRIMARY';
+ $idx_name = 'KEY';
+ } elseif (!empty($definition['unique'])) {
+ $type = 'UNIQUE';
+ } elseif (!empty($definition['foreign'])) {
+ $type = 'CONSTRAINT';
+ }
+ if (empty($type)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'invalid definition, could not create constraint', __FUNCTION__);
+ }
+
+ $table_quoted = $db->quoteIdentifier($table, true);
+ $query = "ALTER TABLE $table_quoted ADD $type $idx_name";
+ if (!empty($definition['foreign'])) {
+ $query .= ' FOREIGN KEY';
+ }
+ $fields = array();
+ foreach ($definition['fields'] as $field => $fieldinfo) {
+ $quoted = $db->quoteIdentifier($field, true);
+ if (!empty($fieldinfo['length'])) {
+ $quoted .= '(' . $fieldinfo['length'] . ')';
+ }
+ $fields[] = $quoted;
+ }
+ $query .= ' ('. implode(', ', $fields) . ')';
+ if (!empty($definition['foreign'])) {
+ $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true);
+ $referenced_fields = array();
+ foreach (array_keys($definition['references']['fields']) as $field) {
+ $referenced_fields[] = $db->quoteIdentifier($field, true);
+ }
+ $query .= ' ('. implode(', ', $referenced_fields) . ')';
+ $query .= $this->_getAdvancedFKOptions($definition);
+
+ // add index on FK column(s) or we can't add a FK constraint
+ // @see http://forums.mysql.com/read.php?22,19755,226009
+ $result = $this->createIndex($table, $name.'_fkidx', $definition);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ $res = $db->exec($query);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ if (!empty($definition['foreign'])) {
+ return $this->_createFKTriggers($table, array($name => $definition));
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ dropConstraint()
+
+ /**
+ * drop existing constraint
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $name name of the constraint to be dropped
+ * @param string $primary hint if the constraint is primary
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function dropConstraint($table, $name, $primary = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if ($primary || strtolower($name) == 'primary') {
+ $query = 'ALTER TABLE '. $db->quoteIdentifier($table, true) .' DROP PRIMARY KEY';
+ return $db->exec($query);
+ }
+
+ //is it a FK constraint? If so, also delete the associated triggers
+ $db->loadModule('Reverse', null, true);
+ $definition = $db->reverse->getTableConstraintDefinition($table, $name);
+ if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
+ //first drop the FK enforcing triggers
+ $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ //then drop the constraint itself
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ $query = "ALTER TABLE $table DROP FOREIGN KEY $name";
+ return $db->exec($query);
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->quoteIdentifier($db->getIndexName($name), true);
+ $query = "ALTER TABLE $table DROP INDEX $name";
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ _createFKTriggers()
+
+ /**
+ * Create triggers to enforce the FOREIGN KEY constraint on the table
+ *
+ * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql,
+ * we call a non-existent procedure to raise the FK violation message.
+ * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877
+ *
+ * @param string $table table name
+ * @param array $foreign_keys FOREIGN KEY definitions
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access private
+ */
+ function _createFKTriggers($table, $foreign_keys)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ // create triggers to enforce FOREIGN KEY constraints
+ if ($db->supports('triggers') && !empty($foreign_keys)) {
+ $table_quoted = $db->quoteIdentifier($table, true);
+ foreach ($foreign_keys as $fkname => $fkdef) {
+ if (empty($fkdef)) {
+ continue;
+ }
+ //set actions to default if not set
+ $fkdef['onupdate'] = empty($fkdef['onupdate']) ? $db->options['default_fk_action_onupdate'] : strtoupper($fkdef['onupdate']);
+ $fkdef['ondelete'] = empty($fkdef['ondelete']) ? $db->options['default_fk_action_ondelete'] : strtoupper($fkdef['ondelete']);
+
+ $trigger_names = array(
+ 'insert' => $fkname.'_insert_trg',
+ 'update' => $fkname.'_update_trg',
+ 'pk_update' => $fkname.'_pk_update_trg',
+ 'pk_delete' => $fkname.'_pk_delete_trg',
+ );
+ $table_fields = array_keys($fkdef['fields']);
+ $referenced_fields = array_keys($fkdef['references']['fields']);
+
+ //create the ON [UPDATE|DELETE] triggers on the primary table
+ $restrict_action = ' IF (SELECT ';
+ $aliased_fields = array();
+ foreach ($table_fields as $field) {
+ $aliased_fields[] = $table_quoted .'.'.$field .' AS '.$field;
+ }
+ $restrict_action .= implode(',', $aliased_fields)
+ .' FROM '.$table_quoted
+ .' WHERE ';
+ $conditions = array();
+ $new_values = array();
+ $null_values = array();
+ for ($i=0; $i<count($table_fields); $i++) {
+ $conditions[] = $table_fields[$i] .' = OLD.'.$referenced_fields[$i];
+ $new_values[] = $table_fields[$i] .' = NEW.'.$referenced_fields[$i];
+ $null_values[] = $table_fields[$i] .' = NULL';
+ }
+ $conditions2 = array();
+ for ($i=0; $i<count($referenced_fields); $i++) {
+ $conditions2[] = 'NEW.'.$referenced_fields[$i] .' <> OLD.'.$referenced_fields[$i];
+ }
+
+ $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL';
+ $restrict_action2 = empty($conditions2) ? '' : ' AND (' .implode(' OR ', $conditions2) .')';
+ $restrict_action3 = ' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();'
+ .' END IF;';
+
+ $restrict_action_update = $restrict_action . $restrict_action2 . $restrict_action3;
+ $restrict_action_delete = $restrict_action . $restrict_action3; // There is no NEW row in on DELETE trigger
+
+ $cascade_action_update = 'UPDATE '.$table_quoted.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions). ';';
+ $cascade_action_delete = 'DELETE FROM '.$table_quoted.' WHERE '.implode(' AND ', $conditions). ';';
+ $setnull_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions). ';';
+
+ if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) {
+ $db->loadModule('Reverse', null, true);
+ $default_values = array();
+ foreach ($table_fields as $table_field) {
+ $field_definition = $db->reverse->getTableFieldDefinition($table, $field);
+ if (PEAR::isError($field_definition)) {
+ return $field_definition;
+ }
+ $default_values[] = $table_field .' = '. $field_definition[0]['default'];
+ }
+ $setdefault_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions). ';';
+ }
+
+ $query = 'CREATE TRIGGER %s'
+ .' %s ON '.$fkdef['references']['table']
+ .' FOR EACH ROW BEGIN '
+ .' SET FOREIGN_KEY_CHECKS = 0; '; //only really needed for ON UPDATE CASCADE
+
+ if ('CASCADE' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $cascade_action_update;
+ } elseif ('SET NULL' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action;
+ } elseif ('SET DEFAULT' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action;
+ } elseif ('NO ACTION' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query.$restrict_action_update, $trigger_names['pk_update'], 'AFTER UPDATE', 'update');
+ } elseif ('RESTRICT' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query.$restrict_action_update, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update');
+ }
+ if ('CASCADE' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $cascade_action_delete;
+ } elseif ('SET NULL' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action;
+ } elseif ('SET DEFAULT' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action;
+ } elseif ('NO ACTION' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query.$restrict_action_delete, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete');
+ } elseif ('RESTRICT' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query.$restrict_action_delete, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete');
+ }
+ $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
+ $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
+
+ $db->pushErrorHandling(PEAR_ERROR_RETURN);
+ $db->expectError(MDB2_ERROR_CANNOT_CREATE);
+ $result = $db->exec($sql_delete);
+ $expected_errmsg = 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table';
+ $db->popExpect();
+ $db->popErrorHandling();
+ if (PEAR::isError($result)) {
+ if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
+ return $result;
+ }
+ $db->warnings[] = $expected_errmsg;
+ }
+ $db->pushErrorHandling(PEAR_ERROR_RETURN);
+ $db->expectError(MDB2_ERROR_CANNOT_CREATE);
+ $result = $db->exec($sql_update);
+ $db->popExpect();
+ $db->popErrorHandling();
+ if (PEAR::isError($result) && $result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
+ if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) {
+ return $result;
+ }
+ $db->warnings[] = $expected_errmsg;
+ }
+ }
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ _dropFKTriggers()
+
+ /**
+ * Drop the triggers created to enforce the FOREIGN KEY constraint on the table
+ *
+ * @param string $table table name
+ * @param string $fkname FOREIGN KEY constraint name
+ * @param string $referenced_table referenced table name
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access private
+ */
+ function _dropFKTriggers($table, $fkname, $referenced_table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $triggers = $this->listTableTriggers($table);
+ $triggers2 = $this->listTableTriggers($referenced_table);
+ if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) {
+ $triggers = array_merge($triggers, $triggers2);
+ $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i';
+ foreach ($triggers as $trigger) {
+ if (preg_match($pattern, $trigger)) {
+ $result = $db->exec('DROP TRIGGER '.$trigger);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ listTableConstraints()
+
+ /**
+ * list all constraints in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of constraint names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableConstraints($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $key_name = 'Key_name';
+ $non_unique = 'Non_unique';
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $key_name = strtolower($key_name);
+ $non_unique = strtolower($non_unique);
+ } else {
+ $key_name = strtoupper($key_name);
+ $non_unique = strtoupper($non_unique);
+ }
+ }
+
+ $query = 'SHOW INDEX FROM ' . $db->quoteIdentifier($table, true);
+ $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $result = array();
+ foreach ($indexes as $index_data) {
+ if (!$index_data[$non_unique]) {
+ if ($index_data[$key_name] !== 'PRIMARY') {
+ $index = $this->_fixIndexName($index_data[$key_name]);
+ } else {
+ $index = 'PRIMARY';
+ }
+ if (!empty($index)) {
+ $result[$index] = true;
+ }
+ }
+ }
+
+ //list FOREIGN KEY constraints...
+ $query = 'SHOW CREATE TABLE '. $db->escape($table);
+ $definition = $db->queryOne($query, 'text', 1);
+ if (!PEAR::isError($definition) && !empty($definition)) {
+ $pattern = '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims';
+ if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 0) {
+ foreach ($matches[1] as $constraint) {
+ $result[$constraint] = true;
+ }
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ 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
+ * @param array $options An associative array of table options:
+ * array(
+ * 'comment' => 'Foo',
+ * 'charset' => 'utf8',
+ * 'collate' => 'utf8_unicode_ci',
+ * 'type' => 'innodb',
+ * );
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createSequence($seq_name, $start = 1, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true);
+
+ $options_strings = array();
+
+ if (!empty($options['comment'])) {
+ $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text');
+ }
+
+ if (!empty($options['charset'])) {
+ $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset'];
+ if (!empty($options['collate'])) {
+ $options_strings['charset'].= ' COLLATE '.$options['collate'];
+ }
+ }
+
+ $type = false;
+ if (!empty($options['type'])) {
+ $type = $options['type'];
+ } elseif ($db->options['default_table_type']) {
+ $type = $db->options['default_table_type'];
+ }
+ if ($type) {
+ $options_strings[] = "ENGINE = $type";
+ }
+
+ $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))";
+ if (!empty($options_strings)) {
+ $query .= ' '.implode(' ', $options_strings);
+ }
+ $res = $db->exec($query);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ if ($start == 1) {
+ return MDB2_OK;
+ }
+
+ $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')';
+ $res = $db->exec($query);
+ if (!PEAR::isError($res)) {
+ return MDB2_OK;
+ }
+
+ // Handle error
+ $result = $db->exec("DROP TABLE $sequence_name");
+ if (PEAR::isError($result)) {
+ return $db->raiseError($result, null, null,
+ 'could not drop inconsistent sequence table', __FUNCTION__);
+ }
+
+ return $db->raiseError($res, null, null,
+ 'could not create sequence table', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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($seq_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ return $db->exec("DROP TABLE $sequence_name");
+ }
+
+ // }}}
+ // {{{ listSequences()
+
+ /**
+ * list all sequences in the current database
+ *
+ * @param string database, the current is default
+ * @return mixed array of sequence names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listSequences($database = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SHOW TABLES";
+ if (null !== $database) {
+ $query .= " FROM $database";
+ }
+ $table_names = $db->queryCol($query);
+ if (PEAR::isError($table_names)) {
+ return $table_names;
+ }
+
+ $result = array();
+ foreach ($table_names as $table_name) {
+ if ($sqn = $this->_fixSequenceName($table_name, true)) {
+ $result[] = $sqn;
+ }
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Manager/pgsql.php b/3rdparty/MDB2/Driver/Manager/pgsql.php index 44a611d399d..ec1b08975f0 100644 --- a/3rdparty/MDB2/Driver/Manager/pgsql.php +++ b/3rdparty/MDB2/Driver/Manager/pgsql.php @@ -1,951 +1,954 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Paul Cooper <pgc@ucecom.com> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.87 2008/11/29 14:09:59 afz Exp $ - -require_once('MDB2/Driver/Manager/Common.php'); - -/** - * MDB2 MySQL driver for the management modules - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common -{ - // {{{ createDatabase() - - /** - * create a new database - * - * @param string $name name of the database that should be created - * @param array $options array with charset info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createDatabase($name, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $query = 'CREATE DATABASE ' . $name; - if (!empty($options['charset'])) { - $query .= ' WITH ENCODING ' . $db->quote($options['charset'], 'text'); - } - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ alterDatabase() - - /** - * alter an existing database - * - * @param string $name name of the database that is intended to be changed - * @param array $options array with name, owner info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function alterDatabase($name, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true); - if (!empty($options['name'])) { - $query .= ' RENAME TO ' . $options['name']; - } - if (!empty($options['owner'])) { - $query .= ' OWNER TO ' . $options['owner']; - } - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ 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($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $query = "DROP DATABASE $name"; - return $db->standaloneQuery($query, null, true); - } - - // }}} - // {{{ _getAdvancedFKOptions() - - /** - * Return the FOREIGN KEY query section dealing with non-standard options - * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... - * - * @param array $definition - * @return string - * @access protected - */ - function _getAdvancedFKOptions($definition) - { - $query = ''; - if (!empty($definition['match'])) { - $query .= ' MATCH '.$definition['match']; - } - if (!empty($definition['onupdate'])) { - $query .= ' ON UPDATE '.$definition['onupdate']; - } - if (!empty($definition['ondelete'])) { - $query .= ' ON DELETE '.$definition['ondelete']; - } - if (!empty($definition['deferrable'])) { - $query .= ' DEFERRABLE'; - } else { - $query .= ' NOT DEFERRABLE'; - } - if (!empty($definition['initiallydeferred'])) { - $query .= ' INITIALLY DEFERRED'; - } else { - $query .= ' INITIALLY IMMEDIATE'; - } - return $query; - } - - // }}} - // {{{ truncateTable() - - /** - * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, - * it falls back to a DELETE FROM TABLE query) - * - * @param string $name name of the table that should be truncated - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function truncateTable($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("TRUNCATE TABLE $name"); - } - - // }}} - // {{{ vacuum() - - /** - * Optimize (vacuum) all the tables in the db (or only the specified table) - * and optionally run ANALYZE. - * - * @param string $table table name (all the tables if empty) - * @param array $options an array with driver-specific options: - * - timeout [int] (in seconds) [mssql-only] - * - analyze [boolean] [pgsql and mysql] - * - full [boolean] [pgsql-only] - * - freeze [boolean] [pgsql-only] - * - * @return mixed MDB2_OK success, a MDB2 error on failure - * @access public - */ - function vacuum($table = null, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $query = 'VACUUM'; - - if (!empty($options['full'])) { - $query .= ' FULL'; - } - if (!empty($options['freeze'])) { - $query .= ' FREEZE'; - } - if (!empty($options['analyze'])) { - $query .= ' ANALYZE'; - } - - if (!empty($table)) { - $query .= ' '.$db->quoteIdentifier($table, true); - } - return $db->exec($query); - } - - // }}} - // {{{ 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 MDB2 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 MDB2 parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @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. - * @access public - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function alterTable($name, $changes, $check) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - foreach ($changes as $change_name => $change) { - switch ($change_name) { - case 'add': - case 'remove': - case 'change': - case 'name': - case 'rename': - break; - default: - return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'change type "'.$change_name.'\" not yet supported', __FUNCTION__); - } - } - - if ($check) { - return MDB2_OK; - } - - $name = $db->quoteIdentifier($name, true); - - if (!empty($changes['remove']) && is_array($changes['remove'])) { - foreach ($changes['remove'] as $field_name => $field) { - $field_name = $db->quoteIdentifier($field_name, true); - $query = 'DROP ' . $field_name; - $result = $db->exec("ALTER TABLE $name $query"); - if (PEAR::isError($result)) { - return $result; - } - } - } - - if (!empty($changes['rename']) && is_array($changes['rename'])) { - foreach ($changes['rename'] as $field_name => $field) { - $field_name = $db->quoteIdentifier($field_name, true); - $result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true)); - if (PEAR::isError($result)) { - return $result; - } - } - } - - if (!empty($changes['add']) && is_array($changes['add'])) { - foreach ($changes['add'] as $field_name => $field) { - $query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field); - $result = $db->exec("ALTER TABLE $name $query"); - if (PEAR::isError($result)) { - return $result; - } - } - } - - if (!empty($changes['change']) && is_array($changes['change'])) { - foreach ($changes['change'] as $field_name => $field) { - $field_name = $db->quoteIdentifier($field_name, true); - if (!empty($field['definition']['type'])) { - $server_info = $db->getServerVersion(); - if (PEAR::isError($server_info)) { - return $server_info; - } - if (is_array($server_info) && $server_info['major'] < 8) { - return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'changing column type for "'.$change_name.'\" requires PostgreSQL 8.0 or above', __FUNCTION__); - } - $db->loadModule('Datatype', null, true); - $type = $db->datatype->getTypeDeclaration($field['definition']); - if($type=='SERIAL PRIMARY KEY'){//not correct when altering a table, since serials arent a real type - $type='INTEGER';//use integer instead - } - $query = "ALTER $field_name TYPE $type USING CAST($field_name AS $type)"; - $result = $db->exec("ALTER TABLE $name $query"); - if (PEAR::isError($result)) { - return $result; - } - } - if (array_key_exists('default', $field['definition'])) { - $query = "ALTER $field_name SET DEFAULT ".$db->quote($field['definition']['default'], $field['definition']['type']); - $result = $db->exec("ALTER TABLE $name $query"); - if (PEAR::isError($result)) { - return $result; - } - } - if (!empty($field['definition']['notnull'])) { - $query = "ALTER $field_name ".($field['definition']['notnull'] ? 'SET' : 'DROP').' NOT NULL'; - $result = $db->exec("ALTER TABLE $name $query"); - if (PEAR::isError($result)) { - return $result; - } - } - } - } - - if (!empty($changes['name'])) { - $change_name = $db->quoteIdentifier($changes['name'], true); - $result = $db->exec("ALTER TABLE $name RENAME TO ".$change_name); - if (PEAR::isError($result)) { - return $result; - } - } - - return MDB2_OK; - } - - // }}} - // {{{ listDatabases() - - /** - * list all databases - * - * @return mixed array of database names on success, a MDB2 error on failure - * @access public - */ - function listDatabases() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT datname FROM pg_database'; - $result2 = $db->standaloneQuery($query, array('text'), false); - if (!MDB2::isResultCommon($result2)) { - return $result2; - } - - $result = $result2->fetchCol(); - $result2->free(); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listUsers() - - /** - * list all users - * - * @return mixed array of user names on success, a MDB2 error on failure - * @access public - */ - function listUsers() - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT usename FROM pg_user'; - $result2 = $db->standaloneQuery($query, array('text'), false); - if (!MDB2::isResultCommon($result2)) { - return $result2; - } - - $result = $result2->fetchCol(); - $result2->free(); - return $result; - } - - // }}} - // {{{ listViews() - - /** - * list all views in the current database - * - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listViews($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT viewname - FROM pg_views - WHERE schemaname NOT IN ('pg_catalog', 'information_schema') - AND viewname !~ '^pg_'"; - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableViews() - - /** - * list the views in the database that reference a given table - * - * @param string table for which all referenced views should be found - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listTableViews($table) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT viewname FROM pg_views NATURAL JOIN pg_tables'; - $query.= ' WHERE tablename ='.$db->quote($table, 'text'); - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listFunctions() - - /** - * list all functions in the current database - * - * @return mixed array of function names on success, a MDB2 error on failure - * @access public - */ - function listFunctions() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = " - SELECT - proname - FROM - pg_proc pr, - pg_type tp - WHERE - tp.oid = pr.prorettype - AND pr.proisagg = FALSE - AND tp.typname <> 'trigger' - AND pr.pronamespace IN - (SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')"; - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableTriggers() - - /** - * list all triggers in the database that reference a given table - * - * @param string table for which all referenced triggers should be found - * @return mixed array of trigger names on success, a MDB2 error on failure - * @access public - */ - function listTableTriggers($table = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT trg.tgname AS trigger_name - FROM pg_trigger trg, - pg_class tbl - WHERE trg.tgrelid = tbl.oid'; - if (!is_null($table)) { - $table = $db->quote(strtoupper($table), 'text'); - $query .= " AND tbl.relname = $table"; - } - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTables() - - /** - * list all tables in the current database - * - * @return mixed array of table names on success, a MDB2 error on failure - * @access public - */ - function listTables($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - // gratuitously stolen from PEAR DB _getSpecialQuery in pgsql.php - $query = 'SELECT c.relname AS "Name"' - . ' FROM pg_class c, pg_user u' - . ' WHERE c.relowner = u.usesysid' - . " AND c.relkind = 'r'" - . ' AND NOT EXISTS' - . ' (SELECT 1 FROM pg_views' - . ' WHERE viewname = c.relname)' - . " AND c.relname !~ '^(pg_|sql_)'" - . ' UNION' - . ' SELECT c.relname AS "Name"' - . ' FROM pg_class c' - . " WHERE c.relkind = 'r'" - . ' AND NOT EXISTS' - . ' (SELECT 1 FROM pg_views' - . ' WHERE viewname = c.relname)' - . ' AND NOT EXISTS' - . ' (SELECT 1 FROM pg_user' - . ' WHERE usesysid = c.relowner)' - . " AND c.relname !~ '^pg_'"; - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableFields() - - /** - * list all fields in a table in the current database - * - * @param string $table name of table that should be used in method - * @return mixed array of field names on success, a MDB2 error on failure - * @access public - */ - function listTableFields($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table); - - $table = $db->quoteIdentifier($table, true); - if (!empty($schema)) { - $table = $db->quoteIdentifier($schema, true) . '.' .$table; - } - $db->setLimit(1); - $result2 = $db->query("SELECT * FROM $table LIMIT 1"); - if (PEAR::isError($result2)) { - return $result2; - } - $result = $result2->getColumnNames(); - $result2->free(); - if (PEAR::isError($result)) { - return $result; - } - return array_flip($result); - } - - // }}} - // {{{ listTableIndexes() - - /** - * list all indexes in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of index names on success, a MDB2 error on failure - * @access public - */ - function listTableIndexes($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table); - - $table = $db->quote($table, 'text'); - $subquery = "SELECT indexrelid - FROM pg_index - LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid - LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid - WHERE pg_class.relname = $table - AND indisunique != 't' - AND indisprimary != 't'"; - if (!empty($schema)) { - $subquery .= ' AND pg_namespace.nspname = '.$db->quote($schema, 'text'); - } - $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)"; - $indexes = $db->queryCol($query, 'text'); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $result = array(); - foreach ($indexes as $index) { - $index = $this->_fixIndexName($index); - if (!empty($index)) { - $result[$index] = true; - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ dropConstraint() - - /** - * drop existing constraint - * - * @param string $table name of table that should be used in method - * @param string $name name of the constraint to be dropped - * @param string $primary hint if the constraint is primary - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropConstraint($table, $name, $primary = false) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - // is it an UNIQUE index? - $query = 'SELECT relname - FROM pg_class - WHERE oid IN ( - SELECT indexrelid - FROM pg_index, pg_class - WHERE pg_class.relname = '.$db->quote($table, 'text').' - AND pg_class.oid = pg_index.indrelid - AND indisunique = \'t\') - EXCEPT - SELECT conname - FROM pg_constraint, pg_class - WHERE pg_constraint.conrelid = pg_class.oid - AND relname = '. $db->quote($table, 'text'); - $unique = $db->queryCol($query, 'text'); - if (PEAR::isError($unique) || empty($unique)) { - // not an UNIQUE index, maybe a CONSTRAINT - return parent::dropConstraint($table, $name, $primary); - } - - if (in_array($name, $unique)) { - return $db->exec('DROP INDEX '.$db->quoteIdentifier($name, true)); - } - $idxname = $db->getIndexName($name); - if (in_array($idxname, $unique)) { - return $db->exec('DROP INDEX '.$db->quoteIdentifier($idxname, true)); - } - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $name . ' is not an existing constraint for table ' . $table, __FUNCTION__); - } - - // }}} - // {{{ listTableConstraints() - - /** - * list all constraints in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of constraint names on success, a MDB2 error on failure - * @access public - */ - function listTableConstraints($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table); - - $table = $db->quote($table, 'text'); - $query = 'SELECT conname - FROM pg_constraint - LEFT JOIN pg_class ON pg_constraint.conrelid = pg_class.oid - LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid - WHERE relname = ' .$table; - if (!empty($schema)) { - $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text'); - } - $query .= ' - UNION DISTINCT - SELECT relname - FROM pg_class - WHERE oid IN ( - SELECT indexrelid - FROM pg_index - LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid - LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid - WHERE pg_class.relname = '.$table.' - AND indisunique = \'t\''; - if (!empty($schema)) { - $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text'); - } - $query .= ')'; - $constraints = $db->queryCol($query); - if (PEAR::isError($constraints)) { - return $constraints; - } - - $result = array(); - foreach ($constraints as $constraint) { - $constraint = $this->_fixIndexName($constraint); - if (!empty($constraint)) { - $result[$constraint] = true; - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE - && $db->options['field_case'] == CASE_LOWER - ) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ 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; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - return $db->exec("CREATE SEQUENCE $sequence_name INCREMENT 1". - ($start < 1 ? " MINVALUE $start" : '')." START $start"); - } - - // }}} - // {{{ 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($seq_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - return $db->exec("DROP SEQUENCE $sequence_name"); - } - - // }}} - // {{{ listSequences() - - /** - * list all sequences in the current database - * - * @return mixed array of sequence names on success, a MDB2 error on failure - * @access public - */ - function listSequences($database = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT relname FROM pg_class WHERE relkind = 'S' AND relnamespace IN"; - $query.= "(SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')"; - $table_names = $db->queryCol($query); - if (PEAR::isError($table_names)) { - return $table_names; - } - $result = array(); - foreach ($table_names as $table_name) { - $result[] = $this->_fixSequenceName($table_name); - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Paul Cooper <pgc@ucecom.com> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 299393 2010-05-14 17:49:49Z afz $
+
+require_once 'MDB2/Driver/Manager/Common.php';
+
+/**
+ * MDB2 MySQL driver for the management modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common
+{
+ // {{{ createDatabase()
+
+ /**
+ * create a new database
+ *
+ * @param string $name name of the database that should be created
+ * @param array $options array with charset info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createDatabase($name, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $query = 'CREATE DATABASE ' . $name;
+ if (!empty($options['charset'])) {
+ $query .= ' WITH ENCODING ' . $db->quote($options['charset'], 'text');
+ }
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ alterDatabase()
+
+ /**
+ * alter an existing database
+ *
+ * @param string $name name of the database that is intended to be changed
+ * @param array $options array with name, owner info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function alterDatabase($name, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = '';
+ if (!empty($options['name'])) {
+ $query .= ' RENAME TO ' . $options['name'];
+ }
+ if (!empty($options['owner'])) {
+ $query .= ' OWNER TO ' . $options['owner'];
+ }
+
+ if (empty($query)) {
+ return MDB2_OK;
+ }
+
+ $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true) . $query;
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ 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($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $query = "DROP DATABASE $name";
+ return $db->standaloneQuery($query, null, true);
+ }
+
+ // }}}
+ // {{{ _getAdvancedFKOptions()
+
+ /**
+ * Return the FOREIGN KEY query section dealing with non-standard options
+ * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
+ *
+ * @param array $definition
+ * @return string
+ * @access protected
+ */
+ function _getAdvancedFKOptions($definition)
+ {
+ $query = '';
+ if (!empty($definition['match'])) {
+ $query .= ' MATCH '.$definition['match'];
+ }
+ if (!empty($definition['onupdate'])) {
+ $query .= ' ON UPDATE '.$definition['onupdate'];
+ }
+ if (!empty($definition['ondelete'])) {
+ $query .= ' ON DELETE '.$definition['ondelete'];
+ }
+ if (!empty($definition['deferrable'])) {
+ $query .= ' DEFERRABLE';
+ } else {
+ $query .= ' NOT DEFERRABLE';
+ }
+ if (!empty($definition['initiallydeferred'])) {
+ $query .= ' INITIALLY DEFERRED';
+ } else {
+ $query .= ' INITIALLY IMMEDIATE';
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ truncateTable()
+
+ /**
+ * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
+ * it falls back to a DELETE FROM TABLE query)
+ *
+ * @param string $name name of the table that should be truncated
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function truncateTable($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("TRUNCATE TABLE $name");
+ }
+
+ // }}}
+ // {{{ vacuum()
+
+ /**
+ * Optimize (vacuum) all the tables in the db (or only the specified table)
+ * and optionally run ANALYZE.
+ *
+ * @param string $table table name (all the tables if empty)
+ * @param array $options an array with driver-specific options:
+ * - timeout [int] (in seconds) [mssql-only]
+ * - analyze [boolean] [pgsql and mysql]
+ * - full [boolean] [pgsql-only]
+ * - freeze [boolean] [pgsql-only]
+ *
+ * @return mixed MDB2_OK success, a MDB2 error on failure
+ * @access public
+ */
+ function vacuum($table = null, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $query = 'VACUUM';
+
+ if (!empty($options['full'])) {
+ $query .= ' FULL';
+ }
+ if (!empty($options['freeze'])) {
+ $query .= ' FREEZE';
+ }
+ if (!empty($options['analyze'])) {
+ $query .= ' ANALYZE';
+ }
+
+ if (!empty($table)) {
+ $query .= ' '.$db->quoteIdentifier($table, true);
+ }
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ 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 MDB2 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 MDB2 parser.
+ *
+ * Example
+ * array(
+ * 'name' => 'userlist',
+ * 'add' => array(
+ * 'quota' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * )
+ * ),
+ * 'remove' => array(
+ * 'file_limit' => array(),
+ * 'time_limit' => array()
+ * ),
+ * 'change' => array(
+ * 'name' => array(
+ * 'length' => '20',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 20,
+ * ),
+ * )
+ * ),
+ * 'rename' => array(
+ * 'sex' => array(
+ * 'name' => 'gender',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 1,
+ * 'default' => 'M',
+ * ),
+ * )
+ * )
+ * )
+ *
+ * @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.
+ * @access public
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function alterTable($name, $changes, $check)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ foreach ($changes as $change_name => $change) {
+ switch ($change_name) {
+ case 'add':
+ case 'remove':
+ case 'change':
+ case 'name':
+ case 'rename':
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
+ 'change type "'.$change_name.'\" not yet supported', __FUNCTION__);
+ }
+ }
+
+ if ($check) {
+ return MDB2_OK;
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+
+ if (!empty($changes['remove']) && is_array($changes['remove'])) {
+ foreach ($changes['remove'] as $field_name => $field) {
+ $field_name = $db->quoteIdentifier($field_name, true);
+ $query = 'DROP ' . $field_name;
+ $result = $db->exec("ALTER TABLE $name $query");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+
+ if (!empty($changes['rename']) && is_array($changes['rename'])) {
+ foreach ($changes['rename'] as $field_name => $field) {
+ $field_name = $db->quoteIdentifier($field_name, true);
+ $result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+
+ if (!empty($changes['add']) && is_array($changes['add'])) {
+ foreach ($changes['add'] as $field_name => $field) {
+ $query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
+ $result = $db->exec("ALTER TABLE $name $query");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+
+ if (!empty($changes['change']) && is_array($changes['change'])) {
+ foreach ($changes['change'] as $field_name => $field) {
+ $field_name = $db->quoteIdentifier($field_name, true);
+ if (!empty($field['definition']['type'])) {
+ $server_info = $db->getServerVersion();
+ if (PEAR::isError($server_info)) {
+ return $server_info;
+ }
+ if (is_array($server_info) && $server_info['major'] < 8) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
+ 'changing column type for "'.$change_name.'\" requires PostgreSQL 8.0 or above', __FUNCTION__);
+ }
+ $db->loadModule('Datatype', null, true);
+ $type = $db->datatype->getTypeDeclaration($field['definition']);
+ $query = "ALTER $field_name TYPE $type USING CAST($field_name AS $type)";
+ $result = $db->exec("ALTER TABLE $name $query");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ if (array_key_exists('default', $field['definition'])) {
+ $query = "ALTER $field_name SET DEFAULT ".$db->quote($field['definition']['default'], $field['definition']['type']);
+ $result = $db->exec("ALTER TABLE $name $query");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ if (array_key_exists('notnull', $field['definition'])) {
+ $query = "ALTER $field_name ".($field['definition']['notnull'] ? 'SET' : 'DROP').' NOT NULL';
+ $result = $db->exec("ALTER TABLE $name $query");
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ }
+
+ if (!empty($changes['name'])) {
+ $change_name = $db->quoteIdentifier($changes['name'], true);
+ $result = $db->exec("ALTER TABLE $name RENAME TO ".$change_name);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ listDatabases()
+
+ /**
+ * list all databases
+ *
+ * @return mixed array of database names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listDatabases()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT datname FROM pg_database';
+ $result2 = $db->standaloneQuery($query, array('text'), false);
+ if (!MDB2::isResultCommon($result2)) {
+ return $result2;
+ }
+
+ $result = $result2->fetchCol();
+ $result2->free();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listUsers()
+
+ /**
+ * list all users
+ *
+ * @return mixed array of user names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listUsers()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT usename FROM pg_user';
+ $result2 = $db->standaloneQuery($query, array('text'), false);
+ if (!MDB2::isResultCommon($result2)) {
+ return $result2;
+ }
+
+ $result = $result2->fetchCol();
+ $result2->free();
+ return $result;
+ }
+
+ // }}}
+ // {{{ listViews()
+
+ /**
+ * list all views in the current database
+ *
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listViews()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT viewname
+ FROM pg_views
+ WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
+ AND viewname !~ '^pg_'";
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableViews()
+
+ /**
+ * list the views in the database that reference a given table
+ *
+ * @param string table for which all referenced views should be found
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableViews($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT viewname FROM pg_views NATURAL JOIN pg_tables';
+ $query.= ' WHERE tablename ='.$db->quote($table, 'text');
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listFunctions()
+
+ /**
+ * list all functions in the current database
+ *
+ * @return mixed array of function names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listFunctions()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "
+ SELECT
+ proname
+ FROM
+ pg_proc pr,
+ pg_type tp
+ WHERE
+ tp.oid = pr.prorettype
+ AND pr.proisagg = FALSE
+ AND tp.typname <> 'trigger'
+ AND pr.pronamespace IN
+ (SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableTriggers()
+
+ /**
+ * list all triggers in the database that reference a given table
+ *
+ * @param string table for which all referenced triggers should be found
+ * @return mixed array of trigger names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableTriggers($table = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT trg.tgname AS trigger_name
+ FROM pg_trigger trg,
+ pg_class tbl
+ WHERE trg.tgrelid = tbl.oid';
+ if (null !== $table) {
+ $table = $db->quote(strtoupper($table), 'text');
+ $query .= " AND UPPER(tbl.relname) = $table";
+ }
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTables()
+
+ /**
+ * list all tables in the current database
+ *
+ * @return mixed array of table names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTables()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ // gratuitously stolen from PEAR DB _getSpecialQuery in pgsql.php
+ $query = 'SELECT c.relname AS "Name"'
+ . ' FROM pg_class c, pg_user u'
+ . ' WHERE c.relowner = u.usesysid'
+ . " AND c.relkind = 'r'"
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_views'
+ . ' WHERE viewname = c.relname)'
+ . " AND c.relname !~ '^(pg_|sql_)'"
+ . ' UNION'
+ . ' SELECT c.relname AS "Name"'
+ . ' FROM pg_class c'
+ . " WHERE c.relkind = 'r'"
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_views'
+ . ' WHERE viewname = c.relname)'
+ . ' AND NOT EXISTS'
+ . ' (SELECT 1 FROM pg_user'
+ . ' WHERE usesysid = c.relowner)'
+ . " AND c.relname !~ '^pg_'";
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableFields()
+
+ /**
+ * list all fields in a table in the current database
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of field names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableFields($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table);
+
+ $table = $db->quoteIdentifier($table, true);
+ if (!empty($schema)) {
+ $table = $db->quoteIdentifier($schema, true) . '.' .$table;
+ }
+ $db->setLimit(1);
+ $result2 = $db->query("SELECT * FROM $table");
+ if (PEAR::isError($result2)) {
+ return $result2;
+ }
+ $result = $result2->getColumnNames();
+ $result2->free();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return array_flip($result);
+ }
+
+ // }}}
+ // {{{ listTableIndexes()
+
+ /**
+ * list all indexes in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of index names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableIndexes($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table);
+
+ $table = $db->quote($table, 'text');
+ $subquery = "SELECT indexrelid
+ FROM pg_index
+ LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid
+ LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ WHERE pg_class.relname = $table
+ AND indisunique != 't'
+ AND indisprimary != 't'";
+ if (!empty($schema)) {
+ $subquery .= ' AND pg_namespace.nspname = '.$db->quote($schema, 'text');
+ }
+ $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
+ $indexes = $db->queryCol($query, 'text');
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $result = array();
+ foreach ($indexes as $index) {
+ $index = $this->_fixIndexName($index);
+ if (!empty($index)) {
+ $result[$index] = true;
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ dropConstraint()
+
+ /**
+ * drop existing constraint
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $name name of the constraint to be dropped
+ * @param string $primary hint if the constraint is primary
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function dropConstraint($table, $name, $primary = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ // is it an UNIQUE index?
+ $query = 'SELECT relname
+ FROM pg_class
+ WHERE oid IN (
+ SELECT indexrelid
+ FROM pg_index, pg_class
+ WHERE pg_class.relname = '.$db->quote($table, 'text').'
+ AND pg_class.oid = pg_index.indrelid
+ AND indisunique = \'t\')
+ EXCEPT
+ SELECT conname
+ FROM pg_constraint, pg_class
+ WHERE pg_constraint.conrelid = pg_class.oid
+ AND relname = '. $db->quote($table, 'text');
+ $unique = $db->queryCol($query, 'text');
+ if (PEAR::isError($unique) || empty($unique)) {
+ // not an UNIQUE index, maybe a CONSTRAINT
+ return parent::dropConstraint($table, $name, $primary);
+ }
+
+ if (in_array($name, $unique)) {
+ return $db->exec('DROP INDEX '.$db->quoteIdentifier($name, true));
+ }
+ $idxname = $db->getIndexName($name);
+ if (in_array($idxname, $unique)) {
+ return $db->exec('DROP INDEX '.$db->quoteIdentifier($idxname, true));
+ }
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $name . ' is not an existing constraint for table ' . $table, __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listTableConstraints()
+
+ /**
+ * list all constraints in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of constraint names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableConstraints($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table);
+
+ $table = $db->quote($table, 'text');
+ $query = 'SELECT conname
+ FROM pg_constraint
+ LEFT JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
+ LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ WHERE relname = ' .$table;
+ if (!empty($schema)) {
+ $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text');
+ }
+ $query .= '
+ UNION DISTINCT
+ SELECT relname
+ FROM pg_class
+ WHERE oid IN (
+ SELECT indexrelid
+ FROM pg_index
+ LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid
+ LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ WHERE pg_class.relname = '.$table.'
+ AND indisunique = \'t\'';
+ if (!empty($schema)) {
+ $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text');
+ }
+ $query .= ')';
+ $constraints = $db->queryCol($query);
+ if (PEAR::isError($constraints)) {
+ return $constraints;
+ }
+
+ $result = array();
+ foreach ($constraints as $constraint) {
+ $constraint = $this->_fixIndexName($constraint);
+ if (!empty($constraint)) {
+ $result[$constraint] = true;
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
+ && $db->options['field_case'] == CASE_LOWER
+ ) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ return $db->exec("CREATE SEQUENCE $sequence_name INCREMENT 1".
+ ($start < 1 ? " MINVALUE $start" : '')." START $start");
+ }
+
+ // }}}
+ // {{{ 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($seq_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ return $db->exec("DROP SEQUENCE $sequence_name");
+ }
+
+ // }}}
+ // {{{ listSequences()
+
+ /**
+ * list all sequences in the current database
+ *
+ * @return mixed array of sequence names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listSequences()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT relname FROM pg_class WHERE relkind = 'S' AND relnamespace IN";
+ $query.= "(SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
+ $table_names = $db->queryCol($query);
+ if (PEAR::isError($table_names)) {
+ return $table_names;
+ }
+ $result = array();
+ foreach ($table_names as $table_name) {
+ $result[] = $this->_fixSequenceName($table_name);
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Manager/sqlite.php b/3rdparty/MDB2/Driver/Manager/sqlite.php index 1b7239876f1..c4c30c9ddad 100644 --- a/3rdparty/MDB2/Driver/Manager/sqlite.php +++ b/3rdparty/MDB2/Driver/Manager/sqlite.php @@ -1,1366 +1,1362 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Authors: Lukas Smith <smith@pooteeweet.org> | -// | Lorenzo Alberton <l.alberton@quipo.it> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.76 2008/05/31 11:48:48 quipo Exp $ -// - -require_once('MDB2/Driver/Manager/Common.php'); - -/** - * MDB2 SQLite driver for the management modules - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - * @author Lorenzo Alberton <l.alberton@quipo.it> - */ -class MDB2_Driver_Manager_sqlite extends MDB2_Driver_Manager_Common -{ - // {{{ createDatabase() - - /** - * create a new database - * - * @param string $name name of the database that should be created - * @param array $options array with charset info - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createDatabase($name, $options = array()) - { - $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $database_file = $db->_getDatabaseFile($name); - if (file_exists($database_file)) { - return $db->raiseError(MDB2_ERROR_ALREADY_EXISTS, null, null, - 'database already exists', __FUNCTION__); - } - $php_errormsg = ''; - $database_file="$datadir/$database_file.db"; - $handle = sqlite_open($database_file, $db->dsn['mode'], $php_errormsg); - if (!$handle) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - (isset($php_errormsg) ? $php_errormsg : 'could not create the database file'), __FUNCTION__); - } - if (!empty($options['charset'])) { - $query = 'PRAGMA encoding = ' . $db->quote($options['charset'], 'text'); - @sqlite_query($query, $handle); - } - @sqlite_close($handle); - return MDB2_OK; - } - - // }}} - // {{{ 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($name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $database_file = $db->_getDatabaseFile($name); - if (!@file_exists($database_file)) { - return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null, - 'database does not exist', __FUNCTION__); - } - $result = @unlink($database_file); - if (!$result) { - return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null, - (isset($php_errormsg) ? $php_errormsg : 'could not remove the database file'), __FUNCTION__); - } - return MDB2_OK; - } - - // }}} - // {{{ _getAdvancedFKOptions() - - /** - * Return the FOREIGN KEY query section dealing with non-standard options - * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... - * - * @param array $definition - * @return string - * @access protected - */ - function _getAdvancedFKOptions($definition) - { - $query = ''; - if (!empty($definition['match'])) { - $query .= ' MATCH '.$definition['match']; - } - if (!empty($definition['onupdate']) && (strtoupper($definition['onupdate']) != 'NO ACTION')) { - $query .= ' ON UPDATE '.$definition['onupdate']; - } - if (!empty($definition['ondelete']) && (strtoupper($definition['ondelete']) != 'NO ACTION')) { - $query .= ' ON DELETE '.$definition['ondelete']; - } - if (!empty($definition['deferrable'])) { - $query .= ' DEFERRABLE'; - } else { - $query .= ' NOT DEFERRABLE'; - } - if (!empty($definition['initiallydeferred'])) { - $query .= ' INITIALLY DEFERRED'; - } else { - $query .= ' INITIALLY IMMEDIATE'; - } - return $query; - } - - // }}} - // {{{ _getCreateTableQuery() - - /** - * Create a basic SQL query for a new table creation - * @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 - * @param array $options An associative array of table options - * @return mixed string (the SQL query) on success, a MDB2 error on failure - * @see createTable() - */ - function _getCreateTableQuery($name, $fields, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!$name) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no valid table name specified', __FUNCTION__); - } - if (empty($fields)) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no fields specified for table "'.$name.'"', __FUNCTION__); - } - $query_fields = $this->getFieldDeclarationList($fields); - if (PEAR::isError($query_fields)) { - return $query_fields; - } - if (!empty($options['primary'])) { - $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')'; - } - if (!empty($options['foreign_keys'])) { - foreach ($options['foreign_keys'] as $fkname => $fkdef) { - if (empty($fkdef)) { - continue; - } - $query_fields.= ', CONSTRAINT '.$fkname.' FOREIGN KEY ('.implode(', ', array_keys($fkdef['fields'])).')'; - $query_fields.= ' REFERENCES '.$fkdef['references']['table'].' ('.implode(', ', array_keys($fkdef['references']['fields'])).')'; - $query_fields.= $this->_getAdvancedFKOptions($fkdef); - } - } - - $name = $db->quoteIdentifier($name, true); - $result = 'CREATE '; - if (!empty($options['temporary'])) { - $result .= $this->_getTemporaryTableQuery(); - } - $result .= " TABLE $name ($query_fields)"; - return $result; - } - - // }}} - // {{{ 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 - * @param array $options An associative array of table options - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createTable($name, $fields, $options = array()) - { - $result = parent::createTable($name, $fields, $options); - if (PEAR::isError($result)) { - return $result; - } - // create triggers to enforce FOREIGN KEY constraints - if (!empty($options['foreign_keys'])) { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - foreach ($options['foreign_keys'] as $fkname => $fkdef) { - if (empty($fkdef)) { - continue; - } - //set actions to default if not set - $fkdef['onupdate'] = empty($fkdef['onupdate']) ? $db->options['default_fk_action_onupdate'] : strtoupper($fkdef['onupdate']); - $fkdef['ondelete'] = empty($fkdef['ondelete']) ? $db->options['default_fk_action_ondelete'] : strtoupper($fkdef['ondelete']); - - $trigger_names = array( - 'insert' => $fkname.'_insert_trg', - 'update' => $fkname.'_update_trg', - 'pk_update' => $fkname.'_pk_update_trg', - 'pk_delete' => $fkname.'_pk_delete_trg', - ); - - //create the [insert|update] triggers on the FK table - $table_fields = array_keys($fkdef['fields']); - $referenced_fields = array_keys($fkdef['references']['fields']); - $query = 'CREATE TRIGGER %s BEFORE %s ON '.$name - .' FOR EACH ROW BEGIN' - .' SELECT RAISE(ROLLBACK, \'%s on table "'.$name.'" violates FOREIGN KEY constraint "'.$fkname.'"\')' - .' WHERE (SELECT '; - $aliased_fields = array(); - foreach ($referenced_fields as $field) { - $aliased_fields[] = $fkdef['references']['table'] .'.'.$field .' AS '.$field; - } - $query .= implode(',', $aliased_fields) - .' FROM '.$fkdef['references']['table'] - .' WHERE '; - $conditions = array(); - for ($i=0; $i<count($table_fields); $i++) { - $conditions[] = $referenced_fields[$i] .' = NEW.'.$table_fields[$i]; - } - $query .= implode(' AND ', $conditions).') IS NULL; END;'; - $result = $db->exec(sprintf($query, $trigger_names['insert'], 'INSERT', 'insert')); - if (PEAR::isError($result)) { - return $result; - } - - $result = $db->exec(sprintf($query, $trigger_names['update'], 'UPDATE', 'update')); - if (PEAR::isError($result)) { - return $result; - } - - //create the ON [UPDATE|DELETE] triggers on the primary table - $restrict_action = 'SELECT RAISE(ROLLBACK, \'%s on table "'.$name.'" violates FOREIGN KEY constraint "'.$fkname.'"\')' - .' WHERE (SELECT '; - $aliased_fields = array(); - foreach ($table_fields as $field) { - $aliased_fields[] = $name .'.'.$field .' AS '.$field; - } - $restrict_action .= implode(',', $aliased_fields) - .' FROM '.$name - .' WHERE '; - $conditions = array(); - $new_values = array(); - $null_values = array(); - for ($i=0; $i<count($table_fields); $i++) { - $conditions[] = $table_fields[$i] .' = OLD.'.$referenced_fields[$i]; - $new_values[] = $table_fields[$i] .' = NEW.'.$referenced_fields[$i]; - $null_values[] = $table_fields[$i] .' = NULL'; - } - $conditions2 = array(); - for ($i=0; $i<count($referenced_fields); $i++) { - $conditions2[] = 'NEW.'.$referenced_fields[$i] .' <> OLD.'.$referenced_fields[$i]; - } - $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL' - .' AND (' .implode(' OR ', $conditions2) .')'; - - $cascade_action_update = 'UPDATE '.$name.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions); - $cascade_action_delete = 'DELETE FROM '.$name.' WHERE '.implode(' AND ', $conditions); - $setnull_action = 'UPDATE '.$name.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions); - - if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) { - $db->loadModule('Reverse', null, true); - $default_values = array(); - foreach ($table_fields as $table_field) { - $field_definition = $db->reverse->getTableFieldDefinition($name, $field); - if (PEAR::isError($field_definition)) { - return $field_definition; - } - $default_values[] = $table_field .' = '. $field_definition[0]['default']; - } - $setdefault_action = 'UPDATE '.$name.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions); - } - - $query = 'CREATE TRIGGER %s' - .' %s ON '.$fkdef['references']['table'] - .' FOR EACH ROW BEGIN '; - - if ('CASCADE' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'AFTER UPDATE', 'update') . $cascade_action_update. '; END;'; - } elseif ('SET NULL' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action. '; END;'; - } elseif ('SET DEFAULT' == $fkdef['onupdate']) { - $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action. '; END;'; - } elseif ('NO ACTION' == $fkdef['onupdate']) { - $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'AFTER UPDATE', 'update') . '; END;'; - } elseif ('RESTRICT' == $fkdef['onupdate']) { - $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . '; END;'; - } - if ('CASCADE' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete') . $cascade_action_delete. '; END;'; - } elseif ('SET NULL' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action. '; END;'; - } elseif ('SET DEFAULT' == $fkdef['ondelete']) { - $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action. '; END;'; - } elseif ('NO ACTION' == $fkdef['ondelete']) { - $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete') . '; END;'; - } elseif ('RESTRICT' == $fkdef['ondelete']) { - $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . '; END;'; - } - - if (PEAR::isError($result)) { - return $result; - } - $result = $db->exec($sql_delete); - if (PEAR::isError($result)) { - return $result; - } - $result = $db->exec($sql_update); - if (PEAR::isError($result)) { - return $result; - } - } - } - if (PEAR::isError($result)) { - return $result; - } - return MDB2_OK; - } - - // }}} - // {{{ 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; - } - - //delete the triggers associated to existing FK constraints - $constraints = $this->listTableConstraints($name); - if (!PEAR::isError($constraints) && !empty($constraints)) { - $db->loadModule('Reverse', null, true); - foreach ($constraints as $constraint) { - $definition = $db->reverse->getTableConstraintDefinition($name, $constraint); - if (!PEAR::isError($definition) && !empty($definition['foreign'])) { - $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']); - if (PEAR::isError($result)) { - return $result; - } - } - } - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("DROP TABLE $name"); - } - - // }}} - // {{{ vacuum() - - /** - * Optimize (vacuum) all the tables in the db (or only the specified table) - * and optionally run ANALYZE. - * - * @param string $table table name (all the tables if empty) - * @param array $options an array with driver-specific options: - * - timeout [int] (in seconds) [mssql-only] - * - analyze [boolean] [pgsql and mysql] - * - full [boolean] [pgsql-only] - * - freeze [boolean] [pgsql-only] - * - * @return mixed MDB2_OK success, a MDB2 error on failure - * @access public - */ - function vacuum($table = null, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'VACUUM'; - if (!empty($table)) { - $query .= ' '.$db->quoteIdentifier($table, true); - } - return $db->exec($query); - } - - // }}} - // {{{ 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 MDB2 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 MDB2 parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @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. - * @access public - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function alterTable($name, $changes, $check, $options = array()) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - foreach ($changes as $change_name => $change) { - switch ($change_name) { - case 'add': - case 'remove': - case 'change': - case 'name': - case 'rename': - break; - default: - return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'change type "'.$change_name.'" not yet supported', __FUNCTION__); - } - } - - if ($check) { - return MDB2_OK; - } - - $db->loadModule('Reverse', null, true); - - // actually sqlite 2.x supports no ALTER TABLE at all .. so we emulate it - $fields = $db->manager->listTableFields($name); - if (PEAR::isError($fields)) { - return $fields; - } - - $fields = array_flip($fields); - foreach ($fields as $field => $value) { - $definition = $db->reverse->getTableFieldDefinition($name, $field); - if (PEAR::isError($definition)) { - return $definition; - } - $fields[$field] = $definition[0]; - } - - $indexes = $db->manager->listTableIndexes($name); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $indexes = array_flip($indexes); - foreach ($indexes as $index => $value) { - $definition = $db->reverse->getTableIndexDefinition($name, $index); - if (PEAR::isError($definition)) { - return $definition; - } - $indexes[$index] = $definition; - } - - $constraints = $db->manager->listTableConstraints($name); - if (PEAR::isError($constraints)) { - return $constraints; - } - - if (!array_key_exists('foreign_keys', $options)) { - $options['foreign_keys'] = array(); - } - $constraints = array_flip($constraints); - foreach ($constraints as $constraint => $value) { - if (!empty($definition['primary'])) { - if (!array_key_exists('primary', $options)) { - $options['primary'] = $definition['fields']; - //remove from the $constraint array, it's already handled by createTable() - unset($constraints[$constraint]); - } - } else { - $c_definition = $db->reverse->getTableConstraintDefinition($name, $constraint); - if (PEAR::isError($c_definition)) { - return $c_definition; - } - if (!empty($c_definition['foreign'])) { - if (!array_key_exists($constraint, $options['foreign_keys'])) { - $options['foreign_keys'][$constraint] = $c_definition; - } - //remove from the $constraint array, it's already handled by createTable() - unset($constraints[$constraint]); - } else { - $constraints[$constraint] = $c_definition; - } - } - } - - $name_new = $name; - $create_order = $select_fields = array_keys($fields); - foreach ($changes as $change_name => $change) { - switch ($change_name) { - case 'add': - foreach ($change as $field_name => $field) { - $fields[$field_name] = $field; - $create_order[] = $field_name; - } - break; - case 'remove': - foreach ($change as $field_name => $field) { - unset($fields[$field_name]); - $select_fields = array_diff($select_fields, array($field_name)); - $create_order = array_diff($create_order, array($field_name)); - } - break; - case 'change': - foreach ($change as $field_name => $field) { - $fields[$field_name] = $field['definition']; - } - break; - case 'name': - $name_new = $change; - break; - case 'rename': - foreach ($change as $field_name => $field) { - unset($fields[$field_name]); - $fields[$field['name']] = $field['definition']; - $create_order[array_search($field_name, $create_order)] = $field['name']; - } - break; - default: - return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'change type "'.$change_name.'" not yet supported', __FUNCTION__); - } - } - - $data = null; - if (!empty($select_fields)) { - $query = 'SELECT '.implode(', ', $select_fields).' FROM '.$db->quoteIdentifier($name, true); - $data = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED); - } - - $result = $this->dropTable($name); - if (PEAR::isError($result)) { - return $result; - } - - $result = $this->createTable($name_new, $fields, $options); - if (PEAR::isError($result)) { - return $result; - } - - foreach ($indexes as $index => $definition) { - $this->createIndex($name_new, $index, $definition); - } - - foreach ($constraints as $constraint => $definition) { - if(empty($definition['primary']) and empty($definition['foreign'])){ - $this->createConstraint($name_new, $constraint, $definition); - } - } - - if (!empty($select_fields) && !empty($data)) { - $query = 'INSERT INTO '.$db->quoteIdentifier($name_new, true); - $query.= '('.implode(', ', array_slice(array_keys($fields), 0, count($select_fields))).')'; - $query.=' VALUES (?'.str_repeat(', ?', (count($select_fields) - 1)).')'; - $stmt =$db->prepare($query, null, MDB2_PREPARE_MANIP); - if (PEAR::isError($stmt)) { - return $stmt; - } - foreach ($data as $row) { - $result = $stmt->execute($row); - if (PEAR::isError($result)) { - return $result; - } - } - } - return MDB2_OK; - } - - // }}} - // {{{ listDatabases() - - /** - * list all databases - * - * @return mixed array of database names 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, - 'list databases is not supported', __FUNCTION__); - } - - // }}} - // {{{ listUsers() - - /** - * list all users - * - * @return mixed array of user names 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, - 'list databases is not supported', __FUNCTION__); - } - - // }}} - // {{{ listViews() - - /** - * list all views in the current database - * - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listViews($dummy=null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name FROM sqlite_master WHERE type='view' AND sql NOT NULL"; - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableViews() - - /** - * list the views in the database that reference a given table - * - * @param string table for which all referenced views should be found - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listTableViews($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; - $views = $db->queryAll($query, array('text', 'text'), MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($views)) { - return $views; - } - $result = array(); - foreach ($views as $row) { - if (preg_match("/^create view .* \bfrom\b\s+\b{$table}\b /i", $row['sql'])) { - if (!empty($row['name'])) { - $result[$row['name']] = true; - } - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ listTables() - - /** - * list all tables in the current database - * - * @return mixed array of table names on success, a MDB2 error on failure - * @access public - */ - function listTables($dummy=null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name FROM sqlite_master WHERE type='table' AND sql NOT NULL ORDER BY name"; - $table_names = $db->queryCol($query); - if (PEAR::isError($table_names)) { - return $table_names; - } - $result = array(); - foreach ($table_names as $table_name) { - if (!$this->_fixSequenceName($table_name, true)) { - $result[] = $table_name; - } - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ listTableFields() - - /** - * list all fields in a table in the current database - * - * @param string $table name of table that should be used in method - * @return mixed array of field names on success, a MDB2 error on failure - * @access public - */ - function listTableFields($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->loadModule('Reverse', null, true); - if (PEAR::isError($result)) { - return $result; - } - $query = "SELECT sql FROM sqlite_master WHERE type='table' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text'); - } else { - $query.= 'name='.$db->quote($table, 'text'); - } - $sql = $db->queryOne($query); - if (PEAR::isError($sql)) { - return $sql; - } - $columns = $db->reverse->_getTableColumns($sql); - $fields = array(); - foreach ($columns as $column) { - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $column['name'] = strtolower($column['name']); - } else { - $column['name'] = strtoupper($column['name']); - } - } else { - $column = array_change_key_case($column, $db->options['field_case']); - } - $fields[] = $column['name']; - } - return $fields; - } - - // }}} - // {{{ listTableTriggers() - - /** - * list all triggers in the database that reference a given table - * - * @param string table for which all referenced triggers should be found - * @return mixed array of trigger names on success, a MDB2 error on failure - * @access public - */ - function listTableTriggers($table = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name FROM sqlite_master WHERE type='trigger' AND sql NOT NULL"; - if (!is_null($table)) { - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= ' AND LOWER(tbl_name)='.$db->quote(strtolower($table), 'text'); - } else { - $query.= ' AND tbl_name='.$db->quote($table, 'text'); - } - } - $result = $db->queryCol($query); - if (PEAR::isError($result)) { - return $result; - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} - // {{{ 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 support() 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; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->getIndexName($name); - $query = "CREATE INDEX $name ON $table"; - $fields = array(); - foreach ($definition['fields'] as $field_name => $field) { - $field_string = $field_name; - if (!empty($field['sorting'])) { - switch ($field['sorting']) { - case 'ascending': - $field_string.= ' ASC'; - break; - case 'descending': - $field_string.= ' DESC'; - break; - } - } - $fields[] = $field_string; - } - $query .= ' ('.implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ 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; - } - - $name = $db->getIndexName($name); - return $db->exec("DROP INDEX $name"); - } - - // }}} - // {{{ listTableIndexes() - - /** - * list all indexes in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of index names on success, a MDB2 error on failure - * @access public - */ - function listTableIndexes($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quote($table, 'text'); - $query = "SELECT sql FROM sqlite_master WHERE type='index' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(tbl_name)='.strtolower($table); - } else { - $query.= "tbl_name=$table"; - } - $query.= " AND sql NOT NULL ORDER BY name"; - $indexes = $db->queryCol($query, 'text'); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $result = array(); - foreach ($indexes as $sql) { - if (preg_match("/^create index ([^ ]+) on /i", $sql, $tmp)) { - $index = $this->_fixIndexName($tmp[1]); - if (!empty($index)) { - $result[$index] = true; - } - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ createConstraint() - - /** - * create a constraint on a table - * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'fields' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createConstraint($table, $name, $definition) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($definition['primary'])) { - return $db->manager->alterTable($table, array(), false, array('primary' => $definition['fields'])); - } - - if (!empty($definition['foreign'])) { - return $db->manager->alterTable($table, array(), false, array('foreign_keys' => array($name => $definition))); - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->getIndexName($name); - $query = "CREATE UNIQUE INDEX $name ON $table"; - $fields = array(); - foreach ($definition['fields'] as $field_name => $field) { - $field_string = $field_name; - if (!empty($field['sorting'])) { - switch ($field['sorting']) { - case 'ascending': - $field_string.= ' ASC'; - break; - case 'descending': - $field_string.= ' DESC'; - break; - } - } - $fields[] = $field_string; - } - $query .= ' ('.implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ dropConstraint() - - /** - * drop existing constraint - * - * @param string $table name of table that should be used in method - * @param string $name name of the constraint to be dropped - * @param string $primary hint if the constraint is primary - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropConstraint($table, $name, $primary = false) - { - if ($primary || $name == 'PRIMARY') { - return $this->alterTable($table, array(), false, array('primary' => null)); - } - - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - //is it a FK constraint? If so, also delete the associated triggers - $db->loadModule('Reverse', null, true); - $definition = $db->reverse->getTableConstraintDefinition($table, $name); - if (!PEAR::isError($definition) && !empty($definition['foreign'])) { - //first drop the FK enforcing triggers - $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']); - if (PEAR::isError($result)) { - return $result; - } - //then drop the constraint itself - return $this->alterTable($table, array(), false, array('foreign_keys' => array($name => null))); - } - - $name = $db->getIndexName($name); - return $db->exec("DROP INDEX $name"); - } - - // }}} - // {{{ _dropFKTriggers() - - /** - * Drop the triggers created to enforce the FOREIGN KEY constraint on the table - * - * @param string $table table name - * @param string $fkname FOREIGN KEY constraint name - * @param string $referenced_table referenced table name - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access private - */ - function _dropFKTriggers($table, $fkname, $referenced_table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $triggers = $this->listTableTriggers($table); - $triggers2 = $this->listTableTriggers($referenced_table); - if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) { - $triggers = array_merge($triggers, $triggers2); - $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i'; - foreach ($triggers as $trigger) { - if (preg_match($pattern, $trigger)) { - $result = $db->exec('DROP TRIGGER '.$trigger); - if (PEAR::isError($result)) { - return $result; - } - } - } - } - return MDB2_OK; - } - - // }}} - // {{{ listTableConstraints() - - /** - * list all constraints in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of constraint names on success, a MDB2 error on failure - * @access public - */ - function listTableConstraints($table) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quote($table, 'text'); - $query = "SELECT sql FROM sqlite_master WHERE type='index' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(tbl_name)='.strtolower($table); - } else { - $query.= "tbl_name=$table"; - } - $query.= " AND sql NOT NULL ORDER BY name"; - $indexes = $db->queryCol($query, 'text'); - if (PEAR::isError($indexes)) { - return $indexes; - } - - $result = array(); - foreach ($indexes as $sql) { - if (preg_match("/^create unique index ([^ ]+) on /i", $sql, $tmp)) { - $index = $this->_fixIndexName($tmp[1]); - if (!empty($index)) { - $result[$index] = true; - } - } - } - - // also search in table definition for PRIMARY KEYs... - $query = "SELECT sql FROM sqlite_master WHERE type='table' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)='.strtolower($table); - } else { - $query.= "name=$table"; - } - $query.= " AND sql NOT NULL ORDER BY name"; - $table_def = $db->queryOne($query, 'text'); - if (PEAR::isError($table_def)) { - return $table_def; - } - if (preg_match("/\bPRIMARY\s+KEY\b/i", $table_def, $tmp)) { - $result['primary'] = true; - } - - // ...and for FOREIGN KEYs - if (preg_match_all("/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN\s+KEY/imsx", $table_def, $tmp)) { - foreach ($tmp[1] as $fk) { - $result[$fk] = true; - } - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_change_key_case($result, $db->options['field_case']); - } - return array_keys($result); - } - - // }}} - // {{{ 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; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true); - $query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER PRIMARY KEY DEFAULT 0 NOT NULL)"; - $res = $db->exec($query); - if (PEAR::isError($res)) { - return $res; - } - if ($start == 1) { - return MDB2_OK; - } - $res = $db->exec("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'); - if (!PEAR::isError($res)) { - return MDB2_OK; - } - // Handle error - $result = $db->exec("DROP TABLE $sequence_name"); - if (PEAR::isError($result)) { - return $db->raiseError($result, null, null, - 'could not drop inconsistent sequence table', __FUNCTION__); - } - return $db->raiseError($res, null, null, - 'could not create sequence table', __FUNCTION__); - } - - // }}} - // {{{ 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($seq_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); - return $db->exec("DROP TABLE $sequence_name"); - } - - // }}} - // {{{ listSequences() - - /** - * list all sequences in the current database - * - * @return mixed array of sequence names on success, a MDB2 error on failure - * @access public - */ - function listSequences($dummy=null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name FROM sqlite_master WHERE type='table' AND sql NOT NULL ORDER BY name"; - $table_names = $db->queryCol($query); - if (PEAR::isError($table_names)) { - return $table_names; - } - $result = array(); - foreach ($table_names as $table_name) { - if ($sqn = $this->_fixSequenceName($table_name, true)) { - $result[] = $sqn; - } - } - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); - } - return $result; - } - - // }}} -} -?> +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Authors: Lukas Smith <smith@pooteeweet.org> |
+// | Lorenzo Alberton <l.alberton@quipo.it> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Manager/Common.php';
+
+/**
+ * MDB2 SQLite driver for the management modules
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ * @author Lorenzo Alberton <l.alberton@quipo.it>
+ */
+class MDB2_Driver_Manager_sqlite extends MDB2_Driver_Manager_Common
+{
+ // {{{ createDatabase()
+
+ /**
+ * create a new database
+ *
+ * @param string $name name of the database that should be created
+ * @param array $options array with charset info
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createDatabase($name, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $database_file = $db->_getDatabaseFile($name);
+ if (file_exists($database_file)) {
+ return $db->raiseError(MDB2_ERROR_ALREADY_EXISTS, null, null,
+ 'database already exists', __FUNCTION__);
+ }
+ $php_errormsg = '';
+ $handle = @sqlite_open($database_file, $db->dsn['mode'], $php_errormsg);
+ if (!$handle) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
+ (isset($php_errormsg) ? $php_errormsg : 'could not create the database file'), __FUNCTION__);
+ }
+ if (!empty($options['charset'])) {
+ $query = 'PRAGMA encoding = ' . $db->quote($options['charset'], 'text');
+ @sqlite_query($query, $handle);
+ }
+ @sqlite_close($handle);
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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($name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $database_file = $db->_getDatabaseFile($name);
+ if (!@file_exists($database_file)) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null,
+ 'database does not exist', __FUNCTION__);
+ }
+ $result = @unlink($database_file);
+ if (!$result) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null,
+ (isset($php_errormsg) ? $php_errormsg : 'could not remove the database file'), __FUNCTION__);
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ _getAdvancedFKOptions()
+
+ /**
+ * Return the FOREIGN KEY query section dealing with non-standard options
+ * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
+ *
+ * @param array $definition
+ * @return string
+ * @access protected
+ */
+ function _getAdvancedFKOptions($definition)
+ {
+ $query = '';
+ if (!empty($definition['match'])) {
+ $query .= ' MATCH '.$definition['match'];
+ }
+ if (!empty($definition['onupdate']) && (strtoupper($definition['onupdate']) != 'NO ACTION')) {
+ $query .= ' ON UPDATE '.$definition['onupdate'];
+ }
+ if (!empty($definition['ondelete']) && (strtoupper($definition['ondelete']) != 'NO ACTION')) {
+ $query .= ' ON DELETE '.$definition['ondelete'];
+ }
+ if (!empty($definition['deferrable'])) {
+ $query .= ' DEFERRABLE';
+ } else {
+ $query .= ' NOT DEFERRABLE';
+ }
+ if (!empty($definition['initiallydeferred'])) {
+ $query .= ' INITIALLY DEFERRED';
+ } else {
+ $query .= ' INITIALLY IMMEDIATE';
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ _getCreateTableQuery()
+
+ /**
+ * Create a basic SQL query for a new table creation
+ * @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
+ * @param array $options An associative array of table options
+ * @return mixed string (the SQL query) on success, a MDB2 error on failure
+ * @see createTable()
+ */
+ function _getCreateTableQuery($name, $fields, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!$name) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
+ 'no valid table name specified', __FUNCTION__);
+ }
+ if (empty($fields)) {
+ return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
+ 'no fields specified for table "'.$name.'"', __FUNCTION__);
+ }
+ $query_fields = $this->getFieldDeclarationList($fields);
+ if (PEAR::isError($query_fields)) {
+ return $query_fields;
+ }
+ if (!empty($options['primary'])) {
+ $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')';
+ }
+ if (!empty($options['foreign_keys'])) {
+ foreach ($options['foreign_keys'] as $fkname => $fkdef) {
+ if (empty($fkdef)) {
+ continue;
+ }
+ $query_fields.= ', CONSTRAINT '.$fkname.' FOREIGN KEY ('.implode(', ', array_keys($fkdef['fields'])).')';
+ $query_fields.= ' REFERENCES '.$fkdef['references']['table'].' ('.implode(', ', array_keys($fkdef['references']['fields'])).')';
+ $query_fields.= $this->_getAdvancedFKOptions($fkdef);
+ }
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ $result = 'CREATE ';
+ if (!empty($options['temporary'])) {
+ $result .= $this->_getTemporaryTableQuery();
+ }
+ $result .= " TABLE $name ($query_fields)";
+ return $result;
+ }
+
+ // }}}
+ // {{{ 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
+ * @param array $options An associative array of table options
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createTable($name, $fields, $options = array())
+ {
+ $result = parent::createTable($name, $fields, $options);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ // create triggers to enforce FOREIGN KEY constraints
+ if (!empty($options['foreign_keys'])) {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ foreach ($options['foreign_keys'] as $fkname => $fkdef) {
+ if (empty($fkdef)) {
+ continue;
+ }
+ //set actions to default if not set
+ $fkdef['onupdate'] = empty($fkdef['onupdate']) ? $db->options['default_fk_action_onupdate'] : strtoupper($fkdef['onupdate']);
+ $fkdef['ondelete'] = empty($fkdef['ondelete']) ? $db->options['default_fk_action_ondelete'] : strtoupper($fkdef['ondelete']);
+
+ $trigger_names = array(
+ 'insert' => $fkname.'_insert_trg',
+ 'update' => $fkname.'_update_trg',
+ 'pk_update' => $fkname.'_pk_update_trg',
+ 'pk_delete' => $fkname.'_pk_delete_trg',
+ );
+
+ //create the [insert|update] triggers on the FK table
+ $table_fields = array_keys($fkdef['fields']);
+ $referenced_fields = array_keys($fkdef['references']['fields']);
+ $query = 'CREATE TRIGGER %s BEFORE %s ON '.$name
+ .' FOR EACH ROW BEGIN'
+ .' SELECT RAISE(ROLLBACK, \'%s on table "'.$name.'" violates FOREIGN KEY constraint "'.$fkname.'"\')'
+ .' WHERE (SELECT ';
+ $aliased_fields = array();
+ foreach ($referenced_fields as $field) {
+ $aliased_fields[] = $fkdef['references']['table'] .'.'.$field .' AS '.$field;
+ }
+ $query .= implode(',', $aliased_fields)
+ .' FROM '.$fkdef['references']['table']
+ .' WHERE ';
+ $conditions = array();
+ for ($i=0; $i<count($table_fields); $i++) {
+ $conditions[] = $referenced_fields[$i] .' = NEW.'.$table_fields[$i];
+ }
+ $query .= implode(' AND ', $conditions).') IS NULL; END;';
+ $result = $db->exec(sprintf($query, $trigger_names['insert'], 'INSERT', 'insert'));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ $result = $db->exec(sprintf($query, $trigger_names['update'], 'UPDATE', 'update'));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ //create the ON [UPDATE|DELETE] triggers on the primary table
+ $restrict_action = 'SELECT RAISE(ROLLBACK, \'%s on table "'.$name.'" violates FOREIGN KEY constraint "'.$fkname.'"\')'
+ .' WHERE (SELECT ';
+ $aliased_fields = array();
+ foreach ($table_fields as $field) {
+ $aliased_fields[] = $name .'.'.$field .' AS '.$field;
+ }
+ $restrict_action .= implode(',', $aliased_fields)
+ .' FROM '.$name
+ .' WHERE ';
+ $conditions = array();
+ $new_values = array();
+ $null_values = array();
+ for ($i=0; $i<count($table_fields); $i++) {
+ $conditions[] = $table_fields[$i] .' = OLD.'.$referenced_fields[$i];
+ $new_values[] = $table_fields[$i] .' = NEW.'.$referenced_fields[$i];
+ $null_values[] = $table_fields[$i] .' = NULL';
+ }
+ $conditions2 = array();
+ for ($i=0; $i<count($referenced_fields); $i++) {
+ $conditions2[] = 'NEW.'.$referenced_fields[$i] .' <> OLD.'.$referenced_fields[$i];
+ }
+ $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL'
+ .' AND (' .implode(' OR ', $conditions2) .')';
+
+ $cascade_action_update = 'UPDATE '.$name.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions);
+ $cascade_action_delete = 'DELETE FROM '.$name.' WHERE '.implode(' AND ', $conditions);
+ $setnull_action = 'UPDATE '.$name.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions);
+
+ if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) {
+ $db->loadModule('Reverse', null, true);
+ $default_values = array();
+ foreach ($table_fields as $table_field) {
+ $field_definition = $db->reverse->getTableFieldDefinition($name, $field);
+ if (PEAR::isError($field_definition)) {
+ return $field_definition;
+ }
+ $default_values[] = $table_field .' = '. $field_definition[0]['default'];
+ }
+ $setdefault_action = 'UPDATE '.$name.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions);
+ }
+
+ $query = 'CREATE TRIGGER %s'
+ .' %s ON '.$fkdef['references']['table']
+ .' FOR EACH ROW BEGIN ';
+
+ if ('CASCADE' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'AFTER UPDATE', 'update') . $cascade_action_update. '; END;';
+ } elseif ('SET NULL' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action. '; END;';
+ } elseif ('SET DEFAULT' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action. '; END;';
+ } elseif ('NO ACTION' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'AFTER UPDATE', 'update') . '; END;';
+ } elseif ('RESTRICT' == $fkdef['onupdate']) {
+ $sql_update = sprintf($query.$restrict_action, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . '; END;';
+ }
+ if ('CASCADE' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete') . $cascade_action_delete. '; END;';
+ } elseif ('SET NULL' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action. '; END;';
+ } elseif ('SET DEFAULT' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action. '; END;';
+ } elseif ('NO ACTION' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete') . '; END;';
+ } elseif ('RESTRICT' == $fkdef['ondelete']) {
+ $sql_delete = sprintf($query.$restrict_action, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . '; END;';
+ }
+
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $result = $db->exec($sql_delete);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $result = $db->exec($sql_update);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ //delete the triggers associated to existing FK constraints
+ $constraints = $this->listTableConstraints($name);
+ if (!PEAR::isError($constraints) && !empty($constraints)) {
+ $db->loadModule('Reverse', null, true);
+ foreach ($constraints as $constraint) {
+ $definition = $db->reverse->getTableConstraintDefinition($name, $constraint);
+ if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
+ $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ }
+
+ $name = $db->quoteIdentifier($name, true);
+ return $db->exec("DROP TABLE $name");
+ }
+
+ // }}}
+ // {{{ vacuum()
+
+ /**
+ * Optimize (vacuum) all the tables in the db (or only the specified table)
+ * and optionally run ANALYZE.
+ *
+ * @param string $table table name (all the tables if empty)
+ * @param array $options an array with driver-specific options:
+ * - timeout [int] (in seconds) [mssql-only]
+ * - analyze [boolean] [pgsql and mysql]
+ * - full [boolean] [pgsql-only]
+ * - freeze [boolean] [pgsql-only]
+ *
+ * @return mixed MDB2_OK success, a MDB2 error on failure
+ * @access public
+ */
+ function vacuum($table = null, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'VACUUM';
+ if (!empty($table)) {
+ $query .= ' '.$db->quoteIdentifier($table, true);
+ }
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ 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 MDB2 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 MDB2 parser.
+ *
+ * Example
+ * array(
+ * 'name' => 'userlist',
+ * 'add' => array(
+ * 'quota' => array(
+ * 'type' => 'integer',
+ * 'unsigned' => 1
+ * )
+ * ),
+ * 'remove' => array(
+ * 'file_limit' => array(),
+ * 'time_limit' => array()
+ * ),
+ * 'change' => array(
+ * 'name' => array(
+ * 'length' => '20',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 20,
+ * ),
+ * )
+ * ),
+ * 'rename' => array(
+ * 'sex' => array(
+ * 'name' => 'gender',
+ * 'definition' => array(
+ * 'type' => 'text',
+ * 'length' => 1,
+ * 'default' => 'M',
+ * ),
+ * )
+ * )
+ * )
+ *
+ * @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.
+ * @access public
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function alterTable($name, $changes, $check, $options = array())
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ foreach ($changes as $change_name => $change) {
+ switch ($change_name) {
+ case 'add':
+ case 'remove':
+ case 'change':
+ case 'name':
+ case 'rename':
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
+ 'change type "'.$change_name.'" not yet supported', __FUNCTION__);
+ }
+ }
+
+ if ($check) {
+ return MDB2_OK;
+ }
+
+ $db->loadModule('Reverse', null, true);
+
+ // actually sqlite 2.x supports no ALTER TABLE at all .. so we emulate it
+ $fields = $db->manager->listTableFields($name);
+ if (PEAR::isError($fields)) {
+ return $fields;
+ }
+
+ $fields = array_flip($fields);
+ foreach ($fields as $field => $value) {
+ $definition = $db->reverse->getTableFieldDefinition($name, $field);
+ if (PEAR::isError($definition)) {
+ return $definition;
+ }
+ $fields[$field] = $definition[0];
+ }
+
+ $indexes = $db->manager->listTableIndexes($name);
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $indexes = array_flip($indexes);
+ foreach ($indexes as $index => $value) {
+ $definition = $db->reverse->getTableIndexDefinition($name, $index);
+ if (PEAR::isError($definition)) {
+ return $definition;
+ }
+ $indexes[$index] = $definition;
+ }
+
+ $constraints = $db->manager->listTableConstraints($name);
+ if (PEAR::isError($constraints)) {
+ return $constraints;
+ }
+
+ if (!array_key_exists('foreign_keys', $options)) {
+ $options['foreign_keys'] = array();
+ }
+ $constraints = array_flip($constraints);
+ foreach ($constraints as $constraint => $value) {
+ if (!empty($definition['primary'])) {
+ if (!array_key_exists('primary', $options)) {
+ $options['primary'] = $definition['fields'];
+ //remove from the $constraint array, it's already handled by createTable()
+ unset($constraints[$constraint]);
+ }
+ } else {
+ $c_definition = $db->reverse->getTableConstraintDefinition($name, $constraint);
+ if (PEAR::isError($c_definition)) {
+ return $c_definition;
+ }
+ if (!empty($c_definition['foreign'])) {
+ if (!array_key_exists($constraint, $options['foreign_keys'])) {
+ $options['foreign_keys'][$constraint] = $c_definition;
+ }
+ //remove from the $constraint array, it's already handled by createTable()
+ unset($constraints[$constraint]);
+ } else {
+ $constraints[$constraint] = $c_definition;
+ }
+ }
+ }
+
+ $name_new = $name;
+ $create_order = $select_fields = array_keys($fields);
+ foreach ($changes as $change_name => $change) {
+ switch ($change_name) {
+ case 'add':
+ foreach ($change as $field_name => $field) {
+ $fields[$field_name] = $field;
+ $create_order[] = $field_name;
+ }
+ break;
+ case 'remove':
+ foreach ($change as $field_name => $field) {
+ unset($fields[$field_name]);
+ $select_fields = array_diff($select_fields, array($field_name));
+ $create_order = array_diff($create_order, array($field_name));
+ }
+ break;
+ case 'change':
+ foreach ($change as $field_name => $field) {
+ $fields[$field_name] = $field['definition'];
+ }
+ break;
+ case 'name':
+ $name_new = $change;
+ break;
+ case 'rename':
+ foreach ($change as $field_name => $field) {
+ unset($fields[$field_name]);
+ $fields[$field['name']] = $field['definition'];
+ $create_order[array_search($field_name, $create_order)] = $field['name'];
+ }
+ break;
+ default:
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
+ 'change type "'.$change_name.'" not yet supported', __FUNCTION__);
+ }
+ }
+
+ $data = null;
+ if (!empty($select_fields)) {
+ $query = 'SELECT '.implode(', ', $select_fields).' FROM '.$db->quoteIdentifier($name, true);
+ $data = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED);
+ }
+
+ $result = $this->dropTable($name);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ $result = $this->createTable($name_new, $fields, $options);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ foreach ($indexes as $index => $definition) {
+ $this->createIndex($name_new, $index, $definition);
+ }
+
+ foreach ($constraints as $constraint => $definition) {
+ $this->createConstraint($name_new, $constraint, $definition);
+ }
+
+ if (!empty($select_fields) && !empty($data)) {
+ $query = 'INSERT INTO '.$db->quoteIdentifier($name_new, true);
+ $query.= '('.implode(', ', array_slice(array_keys($fields), 0, count($select_fields))).')';
+ $query.=' VALUES (?'.str_repeat(', ?', (count($select_fields) - 1)).')';
+ $stmt = $db->prepare($query, null, MDB2_PREPARE_MANIP);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+ foreach ($data as $row) {
+ $result = $stmt->execute($row);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ listDatabases()
+
+ /**
+ * list all databases
+ *
+ * @return mixed array of database names 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,
+ 'list databases is not supported', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listUsers()
+
+ /**
+ * list all users
+ *
+ * @return mixed array of user names 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,
+ 'list databases is not supported', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ listViews()
+
+ /**
+ * list all views in the current database
+ *
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listViews()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name FROM sqlite_master WHERE type='view' AND sql NOT NULL";
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableViews()
+
+ /**
+ * list the views in the database that reference a given table
+ *
+ * @param string table for which all referenced views should be found
+ * @return mixed array of view names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableViews($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL";
+ $views = $db->queryAll($query, array('text', 'text'), MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($views)) {
+ return $views;
+ }
+ $result = array();
+ foreach ($views as $row) {
+ if (preg_match("/^create view .* \bfrom\b\s+\b{$table}\b /i", $row['sql'])) {
+ if (!empty($row['name'])) {
+ $result[$row['name']] = true;
+ }
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ listTables()
+
+ /**
+ * list all tables in the current database
+ *
+ * @return mixed array of table names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTables()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name FROM sqlite_master WHERE type='table' AND sql NOT NULL ORDER BY name";
+ $table_names = $db->queryCol($query);
+ if (PEAR::isError($table_names)) {
+ return $table_names;
+ }
+ $result = array();
+ foreach ($table_names as $table_name) {
+ if (!$this->_fixSequenceName($table_name, true)) {
+ $result[] = $table_name;
+ }
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ listTableFields()
+
+ /**
+ * list all fields in a table in the current database
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of field names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableFields($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $result = $db->loadModule('Reverse', null, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
+ } else {
+ $query.= 'name='.$db->quote($table, 'text');
+ }
+ $sql = $db->queryOne($query);
+ if (PEAR::isError($sql)) {
+ return $sql;
+ }
+ $columns = $db->reverse->_getTableColumns($sql);
+ $fields = array();
+ foreach ($columns as $column) {
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $column['name'] = strtolower($column['name']);
+ } else {
+ $column['name'] = strtoupper($column['name']);
+ }
+ } else {
+ $column = array_change_key_case($column, $db->options['field_case']);
+ }
+ $fields[] = $column['name'];
+ }
+ return $fields;
+ }
+
+ // }}}
+ // {{{ listTableTriggers()
+
+ /**
+ * list all triggers in the database that reference a given table
+ *
+ * @param string table for which all referenced triggers should be found
+ * @return mixed array of trigger names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableTriggers($table = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name FROM sqlite_master WHERE type='trigger' AND sql NOT NULL";
+ if (null !== $table) {
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= ' AND LOWER(tbl_name)='.$db->quote(strtolower($table), 'text');
+ } else {
+ $query.= ' AND tbl_name='.$db->quote($table, 'text');
+ }
+ }
+ $result = $db->queryCol($query);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ 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 support() 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;
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->getIndexName($name);
+ $query = "CREATE INDEX $name ON $table";
+ $fields = array();
+ foreach ($definition['fields'] as $field_name => $field) {
+ $field_string = $field_name;
+ if (!empty($field['sorting'])) {
+ switch ($field['sorting']) {
+ case 'ascending':
+ $field_string.= ' ASC';
+ break;
+ case 'descending':
+ $field_string.= ' DESC';
+ break;
+ }
+ }
+ $fields[] = $field_string;
+ }
+ $query .= ' ('.implode(', ', $fields) . ')';
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $name = $db->getIndexName($name);
+ return $db->exec("DROP INDEX $name");
+ }
+
+ // }}}
+ // {{{ listTableIndexes()
+
+ /**
+ * list all indexes in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of index names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableIndexes($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $table = $db->quote($table, 'text');
+ $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(tbl_name)='.strtolower($table);
+ } else {
+ $query.= "tbl_name=$table";
+ }
+ $query.= " AND sql NOT NULL ORDER BY name";
+ $indexes = $db->queryCol($query, 'text');
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $result = array();
+ foreach ($indexes as $sql) {
+ if (preg_match("/^create index ([^ ]+) on /i", $sql, $tmp)) {
+ $index = $this->_fixIndexName($tmp[1]);
+ if (!empty($index)) {
+ $result[$index] = true;
+ }
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ createConstraint()
+
+ /**
+ * create a constraint on a table
+ *
+ * @param string $table name of the table on which the constraint is to be created
+ * @param string $name name of the constraint to be created
+ * @param array $definition associative array that defines properties of the constraint to be created.
+ * Currently, only one property named FIELDS is supported. This property
+ * is also an associative with the names of the constraint fields as array
+ * constraints. Each entry of this array is set to another type of associative
+ * array that specifies properties of the constraint that are specific to
+ * each field.
+ *
+ * Example
+ * array(
+ * 'fields' => array(
+ * 'user_name' => array(),
+ * 'last_login' => array()
+ * )
+ * )
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function createConstraint($table, $name, $definition)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!empty($definition['primary'])) {
+ return $db->manager->alterTable($table, array(), false, array('primary' => $definition['fields']));
+ }
+
+ if (!empty($definition['foreign'])) {
+ return $db->manager->alterTable($table, array(), false, array('foreign_keys' => array($name => $definition)));
+ }
+
+ $table = $db->quoteIdentifier($table, true);
+ $name = $db->getIndexName($name);
+ $query = "CREATE UNIQUE INDEX $name ON $table";
+ $fields = array();
+ foreach ($definition['fields'] as $field_name => $field) {
+ $field_string = $field_name;
+ if (!empty($field['sorting'])) {
+ switch ($field['sorting']) {
+ case 'ascending':
+ $field_string.= ' ASC';
+ break;
+ case 'descending':
+ $field_string.= ' DESC';
+ break;
+ }
+ }
+ $fields[] = $field_string;
+ }
+ $query .= ' ('.implode(', ', $fields) . ')';
+ return $db->exec($query);
+ }
+
+ // }}}
+ // {{{ dropConstraint()
+
+ /**
+ * drop existing constraint
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $name name of the constraint to be dropped
+ * @param string $primary hint if the constraint is primary
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function dropConstraint($table, $name, $primary = false)
+ {
+ if ($primary || $name == 'PRIMARY') {
+ return $this->alterTable($table, array(), false, array('primary' => null));
+ }
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ //is it a FK constraint? If so, also delete the associated triggers
+ $db->loadModule('Reverse', null, true);
+ $definition = $db->reverse->getTableConstraintDefinition($table, $name);
+ if (!PEAR::isError($definition) && !empty($definition['foreign'])) {
+ //first drop the FK enforcing triggers
+ $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ //then drop the constraint itself
+ return $this->alterTable($table, array(), false, array('foreign_keys' => array($name => null)));
+ }
+
+ $name = $db->getIndexName($name);
+ return $db->exec("DROP INDEX $name");
+ }
+
+ // }}}
+ // {{{ _dropFKTriggers()
+
+ /**
+ * Drop the triggers created to enforce the FOREIGN KEY constraint on the table
+ *
+ * @param string $table table name
+ * @param string $fkname FOREIGN KEY constraint name
+ * @param string $referenced_table referenced table name
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access private
+ */
+ function _dropFKTriggers($table, $fkname, $referenced_table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $triggers = $this->listTableTriggers($table);
+ $triggers2 = $this->listTableTriggers($referenced_table);
+ if (!PEAR::isError($triggers2) && !PEAR::isError($triggers)) {
+ $triggers = array_merge($triggers, $triggers2);
+ $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i';
+ foreach ($triggers as $trigger) {
+ if (preg_match($pattern, $trigger)) {
+ $result = $db->exec('DROP TRIGGER '.$trigger);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ listTableConstraints()
+
+ /**
+ * list all constraints in a table
+ *
+ * @param string $table name of table that should be used in method
+ * @return mixed array of constraint names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listTableConstraints($table)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $table = $db->quote($table, 'text');
+ $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(tbl_name)='.strtolower($table);
+ } else {
+ $query.= "tbl_name=$table";
+ }
+ $query.= " AND sql NOT NULL ORDER BY name";
+ $indexes = $db->queryCol($query, 'text');
+ if (PEAR::isError($indexes)) {
+ return $indexes;
+ }
+
+ $result = array();
+ foreach ($indexes as $sql) {
+ if (preg_match("/^create unique index ([^ ]+) on /i", $sql, $tmp)) {
+ $index = $this->_fixIndexName($tmp[1]);
+ if (!empty($index)) {
+ $result[$index] = true;
+ }
+ }
+ }
+
+ // also search in table definition for PRIMARY KEYs...
+ $query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)='.strtolower($table);
+ } else {
+ $query.= "name=$table";
+ }
+ $query.= " AND sql NOT NULL ORDER BY name";
+ $table_def = $db->queryOne($query, 'text');
+ if (PEAR::isError($table_def)) {
+ return $table_def;
+ }
+ if (preg_match("/\bPRIMARY\s+KEY\b/i", $table_def, $tmp)) {
+ $result['primary'] = true;
+ }
+
+ // ...and for FOREIGN KEYs
+ if (preg_match_all("/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN\s+KEY/imsx", $table_def, $tmp)) {
+ foreach ($tmp[1] as $fk) {
+ $result[$fk] = true;
+ }
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_change_key_case($result, $db->options['field_case']);
+ }
+ return array_keys($result);
+ }
+
+ // }}}
+ // {{{ 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;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true);
+ $query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER PRIMARY KEY DEFAULT 0 NOT NULL)";
+ $res = $db->exec($query);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ if ($start == 1) {
+ return MDB2_OK;
+ }
+ $res = $db->exec("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')');
+ if (!PEAR::isError($res)) {
+ return MDB2_OK;
+ }
+ // Handle error
+ $result = $db->exec("DROP TABLE $sequence_name");
+ if (PEAR::isError($result)) {
+ return $db->raiseError($result, null, null,
+ 'could not drop inconsistent sequence table', __FUNCTION__);
+ }
+ return $db->raiseError($res, null, null,
+ 'could not create sequence table', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ 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($seq_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
+ return $db->exec("DROP TABLE $sequence_name");
+ }
+
+ // }}}
+ // {{{ listSequences()
+
+ /**
+ * list all sequences in the current database
+ *
+ * @return mixed array of sequence names on success, a MDB2 error on failure
+ * @access public
+ */
+ function listSequences()
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name FROM sqlite_master WHERE type='table' AND sql NOT NULL ORDER BY name";
+ $table_names = $db->queryCol($query);
+ if (PEAR::isError($table_names)) {
+ return $table_names;
+ }
+ $result = array();
+ foreach ($table_names as $table_name) {
+ if ($sqn = $this->_fixSequenceName($table_name, true)) {
+ $result[] = $sqn;
+ }
+ }
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
+ }
+ return $result;
+ }
+
+ // }}}
+}
+?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Native/Common.php b/3rdparty/MDB2/Driver/Native/Common.php index c01caa35b71..7cd536ee566 100644 --- a/3rdparty/MDB2/Driver/Native/Common.php +++ b/3rdparty/MDB2/Driver/Native/Common.php @@ -1,61 +1,61 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.2 2007/09/09 13:47:36 quipo Exp $ -// - -/** - * Base class for the natuve modules that is extended by each MDB2 driver - * - * To load this module in the MDB2 object: - * $mdb->loadModule('Native'); - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Native_Common extends MDB2_Module_Common -{ -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Common.php 242348 2007-09-09 13:47:36Z quipo $
+//
+
+/**
+ * Base class for the natuve modules that is extended by each MDB2 driver
+ *
+ * To load this module in the MDB2 object:
+ * $mdb->loadModule('Native');
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Native_Common extends MDB2_Module_Common
+{
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Native/mysql.php b/3rdparty/MDB2/Driver/Native/mysql.php index 90ff068e6ff..f32e3ec3374 100644 --- a/3rdparty/MDB2/Driver/Native/mysql.php +++ b/3rdparty/MDB2/Driver/Native/mysql.php @@ -1,60 +1,60 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.9 2006/06/18 21:59:05 lsmith Exp $ -// - -require_once 'MDB2/Driver/Native/Common.php'; - -/** - * MDB2 MySQL driver for the native module - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Native_mysql extends MDB2_Driver_Native_Common -{ -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 215004 2006-06-18 21:59:05Z lsmith $
+//
+
+require_once 'MDB2/Driver/Native/Common.php';
+
+/**
+ * MDB2 MySQL driver for the native module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Native_mysql extends MDB2_Driver_Native_Common
+{
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Native/pgsql.php b/3rdparty/MDB2/Driver/Native/pgsql.php index acab8389c89..7977b38d3b4 100644 --- a/3rdparty/MDB2/Driver/Native/pgsql.php +++ b/3rdparty/MDB2/Driver/Native/pgsql.php @@ -1,88 +1,88 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Paul Cooper <pgc@ucecom.com> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.12 2006/07/15 13:07:15 lsmith Exp $ - -require_once 'MDB2/Driver/Native/Common.php'; - -/** - * MDB2 PostGreSQL driver for the native module - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Driver_Native_pgsql extends MDB2_Driver_Native_Common -{ - // }}} - // {{{ deleteOID() - - /** - * delete an OID - * - * @param integer $OID - * @return mixed MDB2_OK on success or MDB2 Error Object on failure - * @access public - */ - function deleteOID($OID) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $connection = $db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - if (!@pg_lo_unlink($connection, $OID)) { - return $db->raiseError(null, null, null, - 'Unable to unlink OID: '.$OID, __FUNCTION__); - } - return MDB2_OK; - } - -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Paul Cooper <pgc@ucecom.com> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 295587 2010-02-28 17:16:38Z quipo $
+
+require_once 'MDB2/Driver/Native/Common.php';
+
+/**
+ * MDB2 PostGreSQL driver for the native module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Driver_Native_pgsql extends MDB2_Driver_Native_Common
+{
+ // }}}
+ // {{{ deleteOID()
+
+ /**
+ * delete an OID
+ *
+ * @param integer $OID
+ * @return mixed MDB2_OK on success or MDB2 Error Object on failure
+ * @access public
+ */
+ function deleteOID($OID)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $connection = $db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ if (!@pg_lo_unlink($connection, $OID)) {
+ return $db->raiseError(null, null, null,
+ 'Unable to unlink OID: '.$OID, __FUNCTION__);
+ }
+ return MDB2_OK;
+ }
+
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Native/sqlite.php b/3rdparty/MDB2/Driver/Native/sqlite.php index 0213293a50a..b4da1ce83a3 100644 --- a/3rdparty/MDB2/Driver/Native/sqlite.php +++ b/3rdparty/MDB2/Driver/Native/sqlite.php @@ -1,60 +1,60 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.9 2006/06/18 21:59:05 lsmith Exp $ -// - -require_once 'MDB2/Driver/Native/Common.php'; - -/** - * MDB2 SQLite driver for the native module - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Native_sqlite extends MDB2_Driver_Native_Common -{ -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 215004 2006-06-18 21:59:05Z lsmith $
+//
+
+require_once 'MDB2/Driver/Native/Common.php';
+
+/**
+ * MDB2 SQLite driver for the native module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Native_sqlite extends MDB2_Driver_Native_Common
+{
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Reverse/Common.php b/3rdparty/MDB2/Driver/Reverse/Common.php index c78d84f760a..153516d80d8 100644 --- a/3rdparty/MDB2/Driver/Reverse/Common.php +++ b/3rdparty/MDB2/Driver/Reverse/Common.php @@ -1,517 +1,517 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.43 2009/01/14 15:01:21 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - */ - -/** - * These are constants for the tableInfo-function - * they are bitwised or'ed. so if there are more constants to be defined - * in the future, adjust MDB2_TABLEINFO_FULL accordingly - */ - -define('MDB2_TABLEINFO_ORDER', 1); -define('MDB2_TABLEINFO_ORDERTABLE', 2); -define('MDB2_TABLEINFO_FULL', 3); - -/** - * Base class for the schema reverse engineering module that is extended by each MDB2 driver - * - * To load this module in the MDB2 object: - * $mdb->loadModule('Reverse'); - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Reverse_Common extends MDB2_Module_Common -{ - // {{{ splitTableSchema() - - /** - * Split the "[owner|schema].table" notation into an array - * - * @param string $table [schema and] table name - * - * @return array array(schema, table) - * @access private - */ - function splitTableSchema($table) - { - $ret = array(); - if (strpos($table, '.') !== false) { - return explode('.', $table); - } - return array(null, $table); - } - - // }}} - // {{{ getTableFieldDefinition() - - /** - * Get the structure of a field into an array - * - * @param string $table name of table that should be used in method - * @param string $field name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure. - * The returned array contains an array for each field definition, - * with all or some of these indices, depending on the field data type: - * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] - * @access public - */ - function getTableFieldDefinition($table, $field) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getTableIndexDefinition() - - /** - * Get the structure of an index into an array - * - * @param string $table name of table that should be used in method - * @param string $index name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - * </pre> - * array ( - * [fields] => array ( - * [field1name] => array() // one entry per each field covered - * [field2name] => array() // by the index - * [field3name] => array( - * [sorting] => ascending - * ) - * ) - * ); - * </pre> - * @access public - */ - function getTableIndexDefinition($table, $index) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getTableConstraintDefinition() - - /** - * Get the structure of an constraints into an array - * - * @param string $table name of table that should be used in method - * @param string $index name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - * <pre> - * array ( - * [primary] => 0 - * [unique] => 0 - * [foreign] => 1 - * [check] => 0 - * [fields] => array ( - * [field1name] => array() // one entry per each field covered - * [field2name] => array() // by the index - * [field3name] => array( - * [sorting] => ascending - * [position] => 3 - * ) - * ) - * [references] => array( - * [table] => name - * [fields] => array( - * [field1name] => array( //one entry per each referenced field - * [position] => 1 - * ) - * ) - * ) - * [deferrable] => 0 - * [initiallydeferred] => 0 - * [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION - * [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION - * [match] => SIMPLE|PARTIAL|FULL - * ); - * </pre> - * @access public - */ - function getTableConstraintDefinition($table, $index) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getSequenceDefinition() - - /** - * Get the structure of a sequence into an array - * - * @param string $sequence name of sequence that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - * <pre> - * array ( - * [start] => n - * ); - * </pre> - * @access public - */ - function getSequenceDefinition($sequence) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $start = $db->currId($sequence); - if (PEAR::isError($start)) { - return $start; - } - if ($db->supports('current_id')) { - $start++; - } else { - $db->warnings[] = 'database does not support getting current - sequence value, the sequence value was incremented'; - } - $definition = array(); - if ($start != 1) { - $definition = array('start' => $start); - } - return $definition; - } - - // }}} - // {{{ getTriggerDefinition() - - /** - * Get the structure of a trigger into an array - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change the returned value - * at any time until labelled as non-experimental - * - * @param string $trigger name of trigger that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - * <pre> - * array ( - * [trigger_name] => 'trigger name', - * [table_name] => 'table name', - * [trigger_body] => 'trigger body definition', - * [trigger_type] => 'BEFORE' | 'AFTER', - * [trigger_event] => 'INSERT' | 'UPDATE' | 'DELETE' - * //or comma separated list of multiple events, when supported - * [trigger_enabled] => true|false - * [trigger_comment] => 'trigger comment', - * ); - * </pre> - * The oci8 driver also returns a [when_clause] index. - * @access public - */ - function getTriggerDefinition($trigger) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ tableInfo() - - /** - * Returns information about a table or a result set - * - * The format of the resulting array depends on which <var>$mode</var> - * you select. The sample output below is based on this query: - * <pre> - * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId - * FROM tblFoo - * JOIN tblBar ON tblFoo.fldId = tblBar.fldId - * </pre> - * - * <ul> - * <li> - * - * <kbd>null</kbd> (default) - * <pre> - * [0] => Array ( - * [table] => tblFoo - * [name] => fldId - * [type] => int - * [len] => 11 - * [flags] => primary_key not_null - * ) - * [1] => Array ( - * [table] => tblFoo - * [name] => fldPhone - * [type] => string - * [len] => 20 - * [flags] => - * ) - * [2] => Array ( - * [table] => tblBar - * [name] => fldId - * [type] => int - * [len] => 11 - * [flags] => primary_key not_null - * ) - * </pre> - * - * </li><li> - * - * <kbd>MDB2_TABLEINFO_ORDER</kbd> - * - * <p>In addition to the information found in the default output, - * a notation of the number of columns is provided by the - * <samp>num_fields</samp> element while the <samp>order</samp> - * element provides an array with the column names as the keys and - * their location index number (corresponding to the keys in the - * the default output) as the values.</p> - * - * <p>If a result set has identical field names, the last one is - * used.</p> - * - * <pre> - * [num_fields] => 3 - * [order] => Array ( - * [fldId] => 2 - * [fldTrans] => 1 - * ) - * </pre> - * - * </li><li> - * - * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd> - * - * <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> but adds more - * dimensions to the array in which the table names are keys and - * the field names are sub-keys. This is helpful for queries that - * join tables which have identical field names.</p> - * - * <pre> - * [num_fields] => 3 - * [ordertable] => Array ( - * [tblFoo] => Array ( - * [fldId] => 0 - * [fldPhone] => 1 - * ) - * [tblBar] => Array ( - * [fldId] => 2 - * ) - * ) - * </pre> - * - * </li> - * </ul> - * - * The <samp>flags</samp> element contains a space separated list - * of extra information about the field. This data is inconsistent - * between DBMS's due to the way each DBMS works. - * + <samp>primary_key</samp> - * + <samp>unique_key</samp> - * + <samp>multiple_key</samp> - * + <samp>not_null</samp> - * - * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp> - * elements if <var>$result</var> is a table name. The following DBMS's - * provide full information from queries: - * + fbsql - * + mysql - * - * If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp> - * turned on, the names of tables and fields will be lower or upper cased. - * - * @param object|string $result MDB2_result object from a query or a - * string containing the name of a table. - * While this also accepts a query result - * resource identifier, this behavior is - * deprecated. - * @param int $mode either unused or one of the tableInfo modes: - * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>, - * <kbd>MDB2_TABLEINFO_ORDER</kbd> or - * <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both). - * These are bitwise, so the first two can be - * combined using <kbd>|</kbd>. - * - * @return array an associative array with the information requested. - * A MDB2_Error object on failure. - * - * @see MDB2_Driver_Common::setOption() - */ - function tableInfo($result, $mode = null) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!is_string($result)) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - $db->loadModule('Manager', null, true); - $fields = $db->manager->listTableFields($result); - if (PEAR::isError($fields)) { - return $fields; - } - - $flags = array(); - - $idxname_format = $db->getOption('idxname_format'); - $db->setOption('idxname_format', '%s'); - - $indexes = $db->manager->listTableIndexes($result); - if (PEAR::isError($indexes)) { - $db->setOption('idxname_format', $idxname_format); - return $indexes; - } - - foreach ($indexes as $index) { - $definition = $this->getTableIndexDefinition($result, $index); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - if (count($definition['fields']) > 1) { - foreach ($definition['fields'] as $field => $sort) { - $flags[$field] = 'multiple_key'; - } - } - } - - $constraints = $db->manager->listTableConstraints($result); - if (PEAR::isError($constraints)) { - return $constraints; - } - - foreach ($constraints as $constraint) { - $definition = $this->getTableConstraintDefinition($result, $constraint); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - $flag = !empty($definition['primary']) - ? 'primary_key' : (!empty($definition['unique']) - ? 'unique_key' : false); - if ($flag) { - foreach ($definition['fields'] as $field => $sort) { - if (empty($flags[$field]) || $flags[$field] != 'primary_key') { - $flags[$field] = $flag; - } - } - } - } - - $res = array(); - - if ($mode) { - $res['num_fields'] = count($fields); - } - - foreach ($fields as $i => $field) { - $definition = $this->getTableFieldDefinition($result, $field); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - $res[$i] = $definition[0]; - $res[$i]['name'] = $field; - $res[$i]['table'] = $result; - $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype'])); - // 'primary_key', 'unique_key', 'multiple_key' - $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field]; - // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]' - if (!empty($res[$i]['notnull'])) { - $res[$i]['flags'].= ' not_null'; - } - if (!empty($res[$i]['unsigned'])) { - $res[$i]['flags'].= ' unsigned'; - } - if (!empty($res[$i]['auto_increment'])) { - $res[$i]['flags'].= ' autoincrement'; - } - if (!empty($res[$i]['default'])) { - $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']); - } - - if ($mode & MDB2_TABLEINFO_ORDER) { - $res['order'][$res[$i]['name']] = $i; - } - if ($mode & MDB2_TABLEINFO_ORDERTABLE) { - $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; - } - } - - $db->setOption('idxname_format', $idxname_format); - return $res; - } -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Common.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+/**
+ * @package MDB2
+ * @category Database
+ */
+
+/**
+ * These are constants for the tableInfo-function
+ * they are bitwised or'ed. so if there are more constants to be defined
+ * in the future, adjust MDB2_TABLEINFO_FULL accordingly
+ */
+
+define('MDB2_TABLEINFO_ORDER', 1);
+define('MDB2_TABLEINFO_ORDERTABLE', 2);
+define('MDB2_TABLEINFO_FULL', 3);
+
+/**
+ * Base class for the schema reverse engineering module that is extended by each MDB2 driver
+ *
+ * To load this module in the MDB2 object:
+ * $mdb->loadModule('Reverse');
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Reverse_Common extends MDB2_Module_Common
+{
+ // {{{ splitTableSchema()
+
+ /**
+ * Split the "[owner|schema].table" notation into an array
+ *
+ * @param string $table [schema and] table name
+ *
+ * @return array array(schema, table)
+ * @access private
+ */
+ function splitTableSchema($table)
+ {
+ $ret = array();
+ if (strpos($table, '.') !== false) {
+ return explode('.', $table);
+ }
+ return array(null, $table);
+ }
+
+ // }}}
+ // {{{ getTableFieldDefinition()
+
+ /**
+ * Get the structure of a field into an array
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $field name of field that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure.
+ * The returned array contains an array for each field definition,
+ * with all or some of these indices, depending on the field data type:
+ * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
+ * @access public
+ */
+ function getTableFieldDefinition($table, $field)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getTableIndexDefinition()
+
+ /**
+ * Get the structure of an index into an array
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $index name of index that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * The returned array has this structure:
+ * </pre>
+ * array (
+ * [fields] => array (
+ * [field1name] => array() // one entry per each field covered
+ * [field2name] => array() // by the index
+ * [field3name] => array(
+ * [sorting] => ascending
+ * )
+ * )
+ * );
+ * </pre>
+ * @access public
+ */
+ function getTableIndexDefinition($table, $index)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getTableConstraintDefinition()
+
+ /**
+ * Get the structure of an constraints into an array
+ *
+ * @param string $table name of table that should be used in method
+ * @param string $index name of index that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * The returned array has this structure:
+ * <pre>
+ * array (
+ * [primary] => 0
+ * [unique] => 0
+ * [foreign] => 1
+ * [check] => 0
+ * [fields] => array (
+ * [field1name] => array() // one entry per each field covered
+ * [field2name] => array() // by the index
+ * [field3name] => array(
+ * [sorting] => ascending
+ * [position] => 3
+ * )
+ * )
+ * [references] => array(
+ * [table] => name
+ * [fields] => array(
+ * [field1name] => array( //one entry per each referenced field
+ * [position] => 1
+ * )
+ * )
+ * )
+ * [deferrable] => 0
+ * [initiallydeferred] => 0
+ * [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
+ * [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
+ * [match] => SIMPLE|PARTIAL|FULL
+ * );
+ * </pre>
+ * @access public
+ */
+ function getTableConstraintDefinition($table, $index)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getSequenceDefinition()
+
+ /**
+ * Get the structure of a sequence into an array
+ *
+ * @param string $sequence name of sequence that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * The returned array has this structure:
+ * <pre>
+ * array (
+ * [start] => n
+ * );
+ * </pre>
+ * @access public
+ */
+ function getSequenceDefinition($sequence)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $start = $db->currId($sequence);
+ if (PEAR::isError($start)) {
+ return $start;
+ }
+ if ($db->supports('current_id')) {
+ $start++;
+ } else {
+ $db->warnings[] = 'database does not support getting current
+ sequence value, the sequence value was incremented';
+ }
+ $definition = array();
+ if ($start != 1) {
+ $definition = array('start' => $start);
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTriggerDefinition()
+
+ /**
+ * Get the structure of a trigger into an array
+ *
+ * EXPERIMENTAL
+ *
+ * WARNING: this function is experimental and may change the returned value
+ * at any time until labelled as non-experimental
+ *
+ * @param string $trigger name of trigger that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * The returned array has this structure:
+ * <pre>
+ * array (
+ * [trigger_name] => 'trigger name',
+ * [table_name] => 'table name',
+ * [trigger_body] => 'trigger body definition',
+ * [trigger_type] => 'BEFORE' | 'AFTER',
+ * [trigger_event] => 'INSERT' | 'UPDATE' | 'DELETE'
+ * //or comma separated list of multiple events, when supported
+ * [trigger_enabled] => true|false
+ * [trigger_comment] => 'trigger comment',
+ * );
+ * </pre>
+ * The oci8 driver also returns a [when_clause] index.
+ * @access public
+ */
+ function getTriggerDefinition($trigger)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ tableInfo()
+
+ /**
+ * Returns information about a table or a result set
+ *
+ * The format of the resulting array depends on which <var>$mode</var>
+ * you select. The sample output below is based on this query:
+ * <pre>
+ * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
+ * FROM tblFoo
+ * JOIN tblBar ON tblFoo.fldId = tblBar.fldId
+ * </pre>
+ *
+ * <ul>
+ * <li>
+ *
+ * <kbd>null</kbd> (default)
+ * <pre>
+ * [0] => Array (
+ * [table] => tblFoo
+ * [name] => fldId
+ * [type] => int
+ * [len] => 11
+ * [flags] => primary_key not_null
+ * )
+ * [1] => Array (
+ * [table] => tblFoo
+ * [name] => fldPhone
+ * [type] => string
+ * [len] => 20
+ * [flags] =>
+ * )
+ * [2] => Array (
+ * [table] => tblBar
+ * [name] => fldId
+ * [type] => int
+ * [len] => 11
+ * [flags] => primary_key not_null
+ * )
+ * </pre>
+ *
+ * </li><li>
+ *
+ * <kbd>MDB2_TABLEINFO_ORDER</kbd>
+ *
+ * <p>In addition to the information found in the default output,
+ * a notation of the number of columns is provided by the
+ * <samp>num_fields</samp> element while the <samp>order</samp>
+ * element provides an array with the column names as the keys and
+ * their location index number (corresponding to the keys in the
+ * the default output) as the values.</p>
+ *
+ * <p>If a result set has identical field names, the last one is
+ * used.</p>
+ *
+ * <pre>
+ * [num_fields] => 3
+ * [order] => Array (
+ * [fldId] => 2
+ * [fldTrans] => 1
+ * )
+ * </pre>
+ *
+ * </li><li>
+ *
+ * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>
+ *
+ * <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> but adds more
+ * dimensions to the array in which the table names are keys and
+ * the field names are sub-keys. This is helpful for queries that
+ * join tables which have identical field names.</p>
+ *
+ * <pre>
+ * [num_fields] => 3
+ * [ordertable] => Array (
+ * [tblFoo] => Array (
+ * [fldId] => 0
+ * [fldPhone] => 1
+ * )
+ * [tblBar] => Array (
+ * [fldId] => 2
+ * )
+ * )
+ * </pre>
+ *
+ * </li>
+ * </ul>
+ *
+ * The <samp>flags</samp> element contains a space separated list
+ * of extra information about the field. This data is inconsistent
+ * between DBMS's due to the way each DBMS works.
+ * + <samp>primary_key</samp>
+ * + <samp>unique_key</samp>
+ * + <samp>multiple_key</samp>
+ * + <samp>not_null</samp>
+ *
+ * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
+ * elements if <var>$result</var> is a table name. The following DBMS's
+ * provide full information from queries:
+ * + fbsql
+ * + mysql
+ *
+ * If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp>
+ * turned on, the names of tables and fields will be lower or upper cased.
+ *
+ * @param object|string $result MDB2_result object from a query or a
+ * string containing the name of a table.
+ * While this also accepts a query result
+ * resource identifier, this behavior is
+ * deprecated.
+ * @param int $mode either unused or one of the tableInfo modes:
+ * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>,
+ * <kbd>MDB2_TABLEINFO_ORDER</kbd> or
+ * <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both).
+ * These are bitwise, so the first two can be
+ * combined using <kbd>|</kbd>.
+ *
+ * @return array an associative array with the information requested.
+ * A MDB2_Error object on failure.
+ *
+ * @see MDB2_Driver_Common::setOption()
+ */
+ function tableInfo($result, $mode = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ if (!is_string($result)) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'method not implemented', __FUNCTION__);
+ }
+
+ $db->loadModule('Manager', null, true);
+ $fields = $db->manager->listTableFields($result);
+ if (PEAR::isError($fields)) {
+ return $fields;
+ }
+
+ $flags = array();
+
+ $idxname_format = $db->getOption('idxname_format');
+ $db->setOption('idxname_format', '%s');
+
+ $indexes = $db->manager->listTableIndexes($result);
+ if (PEAR::isError($indexes)) {
+ $db->setOption('idxname_format', $idxname_format);
+ return $indexes;
+ }
+
+ foreach ($indexes as $index) {
+ $definition = $this->getTableIndexDefinition($result, $index);
+ if (PEAR::isError($definition)) {
+ $db->setOption('idxname_format', $idxname_format);
+ return $definition;
+ }
+ if (count($definition['fields']) > 1) {
+ foreach ($definition['fields'] as $field => $sort) {
+ $flags[$field] = 'multiple_key';
+ }
+ }
+ }
+
+ $constraints = $db->manager->listTableConstraints($result);
+ if (PEAR::isError($constraints)) {
+ return $constraints;
+ }
+
+ foreach ($constraints as $constraint) {
+ $definition = $this->getTableConstraintDefinition($result, $constraint);
+ if (PEAR::isError($definition)) {
+ $db->setOption('idxname_format', $idxname_format);
+ return $definition;
+ }
+ $flag = !empty($definition['primary'])
+ ? 'primary_key' : (!empty($definition['unique'])
+ ? 'unique_key' : false);
+ if ($flag) {
+ foreach ($definition['fields'] as $field => $sort) {
+ if (empty($flags[$field]) || $flags[$field] != 'primary_key') {
+ $flags[$field] = $flag;
+ }
+ }
+ }
+ }
+
+ $res = array();
+
+ if ($mode) {
+ $res['num_fields'] = count($fields);
+ }
+
+ foreach ($fields as $i => $field) {
+ $definition = $this->getTableFieldDefinition($result, $field);
+ if (PEAR::isError($definition)) {
+ $db->setOption('idxname_format', $idxname_format);
+ return $definition;
+ }
+ $res[$i] = $definition[0];
+ $res[$i]['name'] = $field;
+ $res[$i]['table'] = $result;
+ $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype']));
+ // 'primary_key', 'unique_key', 'multiple_key'
+ $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field];
+ // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]'
+ if (!empty($res[$i]['notnull'])) {
+ $res[$i]['flags'].= ' not_null';
+ }
+ if (!empty($res[$i]['unsigned'])) {
+ $res[$i]['flags'].= ' unsigned';
+ }
+ if (!empty($res[$i]['auto_increment'])) {
+ $res[$i]['flags'].= ' autoincrement';
+ }
+ if (!empty($res[$i]['default'])) {
+ $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']);
+ }
+
+ if ($mode & MDB2_TABLEINFO_ORDER) {
+ $res['order'][$res[$i]['name']] = $i;
+ }
+ if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
+ $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
+ }
+ }
+
+ $db->setOption('idxname_format', $idxname_format);
+ return $res;
+ }
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Reverse/mysql.php b/3rdparty/MDB2/Driver/Reverse/mysql.php index 6e366c22a5e..7b9b4e0019c 100644 --- a/3rdparty/MDB2/Driver/Reverse/mysql.php +++ b/3rdparty/MDB2/Driver/Reverse/mysql.php @@ -1,536 +1,546 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.80 2008/03/26 21:15:37 quipo Exp $ -// - -require_once('MDB2/Driver/Reverse/Common.php'); - -/** - * MDB2 MySQL driver for the schema reverse engineering module - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - * @author Lorenzo Alberton <l.alberton@quipo.it> - */ -class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common -{ - // {{{ getTableFieldDefinition() - - /** - * Get the structure of a field into an array - * - * @param string $table_name name of table that should be used in method - * @param string $field_name name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableFieldDefinition($table_name, $field_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $table = $db->quoteIdentifier($table, true); - $query = "SHOW FULL COLUMNS FROM $table LIKE ".$db->quote($field_name); - $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($columns)) { - return $columns; - } - foreach ($columns as $column) { - $column = array_change_key_case($column, CASE_LOWER); - $column['name'] = $column['field']; - unset($column['field']); - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $column['name'] = strtolower($column['name']); - } else { - $column['name'] = strtoupper($column['name']); - } - } else { - $column = array_change_key_case($column, $db->options['field_case']); - } - if ($field_name == $column['name']) { - $mapped_datatype = $db->datatype->mapNativeDatatype($column); - if (PEAR::isError($mapped_datatype)) { - return $mapped_datatype; - } - list($types, $length, $unsigned, $fixed) = $mapped_datatype; - $notnull = false; - if (empty($column['null']) || $column['null'] !== 'YES') { - $notnull = true; - } - $default = false; - if (array_key_exists('default', $column)) { - $default = $column['default']; - if (is_null($default) && $notnull) { - $default = ''; - } - } - $autoincrement = false; - if (!empty($column['extra']) && $column['extra'] == 'auto_increment') { - $autoincrement = true; - } - $collate = null; - if (!empty($column['collation'])) { - $collate = $column['collation']; - $charset = preg_replace('/(.+?)(_.+)?/', '$1', $collate); - } - - $definition[0] = array( - 'notnull' => $notnull, - 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) - ); - if (!is_null($length)) { - $definition[0]['length'] = $length; - } - if (!is_null($unsigned)) { - $definition[0]['unsigned'] = $unsigned; - } - if (!is_null($fixed)) { - $definition[0]['fixed'] = $fixed; - } - if ($default !== false) { - $definition[0]['default'] = $default; - } - if ($autoincrement !== false) { - $definition[0]['autoincrement'] = $autoincrement; - } - if (!is_null($collate)) { - $definition[0]['collate'] = $collate; - $definition[0]['charset'] = $charset; - } - foreach ($types as $key => $type) { - $definition[$key] = $definition[0]; - if ($type == 'clob' || $type == 'blob') { - unset($definition[$key]['default']); - } elseif ($type == 'timestamp' && $notnull && empty($definition[$key]['default'])) { - $definition[$key]['default'] = '0000-00-00 00:00:00'; - } - $definition[$key]['type'] = $type; - $definition[$key]['mdb2type'] = $type; - } - return $definition; - } - } - - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table column', __FUNCTION__); - } - - // }}} - // {{{ getTableIndexDefinition() - - /** - * Get the structure of an index into an array - * - * @param string $table_name name of table that should be used in method - * @param string $index_name name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableIndexDefinition($table_name, $index_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; - $index_name_mdb2 = $db->getIndexName($index_name); - $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2))); - if (!PEAR::isError($result) && !is_null($result)) { - // apply 'idxname_format' only if the query succeeded, otherwise - // fallback to the given $index_name, without transformation - $index_name = $index_name_mdb2; - } - $result = $db->query(sprintf($query, $db->quote($index_name))); - if (PEAR::isError($result)) { - return $result; - } - $colpos = 1; - $definition = array(); - while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { - $row = array_change_key_case($row, CASE_LOWER); - $key_name = $row['key_name']; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $key_name = strtolower($key_name); - } else { - $key_name = strtoupper($key_name); - } - } - if ($index_name == $key_name) { - if (!$row['non_unique']) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $index_name . ' is not an existing table index', __FUNCTION__); - } - $column_name = $row['column_name']; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $column_name = strtolower($column_name); - } else { - $column_name = strtoupper($column_name); - } - } - $definition['fields'][$column_name] = array( - 'position' => $colpos++ - ); - if (!empty($row['collation'])) { - $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' - ? 'ascending' : 'descending'); - } - } - } - $result->free(); - if (empty($definition['fields'])) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $index_name . ' is not an existing table index', __FUNCTION__); - } - return $definition; - } - - // }}} - // {{{ getTableConstraintDefinition() - - /** - * Get the structure of a constraint into an array - * - * @param string $table_name name of table that should be used in method - * @param string $constraint_name name of constraint that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableConstraintDefinition($table_name, $constraint_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - $constraint_name_original = $constraint_name; - - $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; - if (strtolower($constraint_name) != 'primary') { - $constraint_name_mdb2 = $db->getIndexName($constraint_name); - $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2))); - if (!PEAR::isError($result) && !is_null($result)) { - // apply 'idxname_format' only if the query succeeded, otherwise - // fallback to the given $index_name, without transformation - $constraint_name = $constraint_name_mdb2; - } - } - $result = $db->query(sprintf($query, $db->quote($constraint_name))); - if (PEAR::isError($result)) { - return $result; - } - $colpos = 1; - //default values, eventually overridden - $definition = array( - 'primary' => false, - 'unique' => false, - 'foreign' => false, - 'check' => false, - 'fields' => array(), - 'references' => array( - 'table' => '', - 'fields' => array(), - ), - 'onupdate' => '', - 'ondelete' => '', - 'match' => '', - 'deferrable' => false, - 'initiallydeferred' => false, - ); - while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { - $row = array_change_key_case($row, CASE_LOWER); - $key_name = $row['key_name']; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $key_name = strtolower($key_name); - } else { - $key_name = strtoupper($key_name); - } - } - if ($constraint_name == $key_name) { - if ($row['non_unique']) { - //FOREIGN KEY? - return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition); - } - if ($row['key_name'] == 'PRIMARY') { - $definition['primary'] = true; - } elseif (!$row['non_unique']) { - $definition['unique'] = true; - } - $column_name = $row['column_name']; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $column_name = strtolower($column_name); - } else { - $column_name = strtoupper($column_name); - } - } - $definition['fields'][$column_name] = array( - 'position' => $colpos++ - ); - if (!empty($row['collation'])) { - $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' - ? 'ascending' : 'descending'); - } - } - } - $result->free(); - if (empty($definition['fields'])) { - return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition); - } - return $definition; - } - - // }}} - // {{{ _getTableFKConstraintDefinition() - - /** - * Get the FK definition from the CREATE TABLE statement - * - * @param string $table table name - * @param string $constraint_name constraint name - * @param array $definition default values for constraint definition - * - * @return array|PEAR_Error - * @access private - */ - function _getTableFKConstraintDefinition($table, $constraint_name, $definition) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $query = 'SHOW CREATE TABLE '. $db->escape($table); - $constraint = $db->queryOne($query, 'text', 1); - if (!PEAR::isError($constraint) && !empty($constraint)) { - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $constraint = strtolower($constraint); - } else { - $constraint = strtoupper($constraint); - } - } - $constraint_name_original = $constraint_name; - $constraint_name = $db->getIndexName($constraint_name); - $pattern = '/\bCONSTRAINT\s+'.$constraint_name.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^ ]+) \(([^\)]+)\)/i'; - if (!preg_match($pattern, str_replace('`', '', $constraint), $matches)) { - //fallback to original constraint name - $pattern = '/\bCONSTRAINT\s+'.$constraint_name_original.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^ ]+) \(([^\)]+)\)/i'; - } - if (preg_match($pattern, str_replace('`', '', $constraint), $matches)) { - $definition['foreign'] = true; - $column_names = explode(',', $matches[1]); - $referenced_cols = explode(',', $matches[3]); - $definition['references'] = array( - 'table' => $matches[2], - 'fields' => array(), - ); - $colpos = 1; - foreach ($column_names as $column_name) { - $definition['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - $colpos = 1; - foreach ($referenced_cols as $column_name) { - $definition['references']['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - $definition['onupdate'] = 'NO ACTION'; - $definition['ondelete'] = 'NO ACTION'; - $definition['match'] = 'SIMPLE'; - return $definition; - } - } - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $constraint_name . ' is not an existing table constraint', __FUNCTION__); - } - - // }}} - // {{{ getTriggerDefinition() - - /** - * Get the structure of a trigger into an array - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change the returned value - * at any time until labelled as non-experimental - * - * @param string $trigger name of trigger that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTriggerDefinition($trigger) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = 'SELECT trigger_name, - event_object_table AS table_name, - action_statement AS trigger_body, - action_timing AS trigger_type, - event_manipulation AS trigger_event - FROM information_schema.triggers - WHERE trigger_name = '. $db->quote($trigger, 'text'); - $types = array( - 'trigger_name' => 'text', - 'table_name' => 'text', - 'trigger_body' => 'text', - 'trigger_type' => 'text', - 'trigger_event' => 'text', - ); - $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($def)) { - return $def; - } - $def['trigger_comment'] = ''; - $def['trigger_enabled'] = true; - return $def; - } - - // }}} - // {{{ tableInfo() - - /** - * Returns information about a table or a result set - * - * @param object|string $result MDB2_result object from a query or a - * string containing the name of a table. - * While this also accepts a query result - * resource identifier, this behavior is - * deprecated. - * @param int $mode a valid tableInfo mode - * - * @return array an associative array with the information requested. - * A MDB2_Error object on failure. - * - * @see MDB2_Driver_Common::setOption() - */ - function tableInfo($result, $mode = null) - { - if (is_string($result)) { - return parent::tableInfo($result, $mode); - } - - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result; - if (!is_resource($resource)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Could not generate result resource', __FUNCTION__); - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $case_func = 'strtolower'; - } else { - $case_func = 'strtoupper'; - } - } else { - $case_func = 'strval'; - } - - $count = @mysql_num_fields($resource); - $res = array(); - if ($mode) { - $res['num_fields'] = $count; - } - - $db->loadModule('Datatype', null, true); - for ($i = 0; $i < $count; $i++) { - $res[$i] = array( - 'table' => $case_func(@mysql_field_table($resource, $i)), - 'name' => $case_func(@mysql_field_name($resource, $i)), - 'type' => @mysql_field_type($resource, $i), - 'length' => @mysql_field_len($resource, $i), - 'flags' => @mysql_field_flags($resource, $i), - ); - if ($res[$i]['type'] == 'string') { - $res[$i]['type'] = 'char'; - } elseif ($res[$i]['type'] == 'unknown') { - $res[$i]['type'] = 'decimal'; - } - $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]); - if (PEAR::isError($mdb2type_info)) { - return $mdb2type_info; - } - $res[$i]['mdb2type'] = $mdb2type_info[0][0]; - if ($mode & MDB2_TABLEINFO_ORDER) { - $res['order'][$res[$i]['name']] = $i; - } - if ($mode & MDB2_TABLEINFO_ORDERTABLE) { - $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; - } - } - - return $res; - } -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Reverse/Common.php';
+
+/**
+ * MDB2 MySQL driver for the schema reverse engineering module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ * @author Lorenzo Alberton <l.alberton@quipo.it>
+ */
+class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common
+{
+ // {{{ getTableFieldDefinition()
+
+ /**
+ * Get the structure of a field into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $field_name name of field that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableFieldDefinition($table_name, $field_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $result = $db->loadModule('Datatype', null, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $table = $db->quoteIdentifier($table, true);
+ $query = "SHOW FULL COLUMNS FROM $table LIKE ".$db->quote($field_name);
+ $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($columns)) {
+ return $columns;
+ }
+ foreach ($columns as $column) {
+ $column = array_change_key_case($column, CASE_LOWER);
+ $column['name'] = $column['field'];
+ unset($column['field']);
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $column['name'] = strtolower($column['name']);
+ } else {
+ $column['name'] = strtoupper($column['name']);
+ }
+ } else {
+ $column = array_change_key_case($column, $db->options['field_case']);
+ }
+ if ($field_name == $column['name']) {
+ $mapped_datatype = $db->datatype->mapNativeDatatype($column);
+ if (PEAR::isError($mapped_datatype)) {
+ return $mapped_datatype;
+ }
+ list($types, $length, $unsigned, $fixed) = $mapped_datatype;
+ $notnull = false;
+ if (empty($column['null']) || $column['null'] !== 'YES') {
+ $notnull = true;
+ }
+ $default = false;
+ if (array_key_exists('default', $column)) {
+ $default = $column['default'];
+ if ((null === $default) && $notnull) {
+ $default = '';
+ }
+ }
+ $definition[0] = array(
+ 'notnull' => $notnull,
+ 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
+ );
+ $autoincrement = false;
+ if (!empty($column['extra'])) {
+ if ($column['extra'] == 'auto_increment') {
+ $autoincrement = true;
+ } else {
+ $definition[0]['extra'] = $column['extra'];
+ }
+ }
+ $collate = null;
+ if (!empty($column['collation'])) {
+ $collate = $column['collation'];
+ $charset = preg_replace('/(.+?)(_.+)?/', '$1', $collate);
+ }
+
+ if (null !== $length) {
+ $definition[0]['length'] = $length;
+ }
+ if (null !== $unsigned) {
+ $definition[0]['unsigned'] = $unsigned;
+ }
+ if (null !== $fixed) {
+ $definition[0]['fixed'] = $fixed;
+ }
+ if ($default !== false) {
+ $definition[0]['default'] = $default;
+ }
+ if ($autoincrement !== false) {
+ $definition[0]['autoincrement'] = $autoincrement;
+ }
+ if (null !== $collate) {
+ $definition[0]['collate'] = $collate;
+ $definition[0]['charset'] = $charset;
+ }
+ foreach ($types as $key => $type) {
+ $definition[$key] = $definition[0];
+ if ($type == 'clob' || $type == 'blob') {
+ unset($definition[$key]['default']);
+ } elseif ($type == 'timestamp' && $notnull && empty($definition[$key]['default'])) {
+ $definition[$key]['default'] = '0000-00-00 00:00:00';
+ }
+ $definition[$key]['type'] = $type;
+ $definition[$key]['mdb2type'] = $type;
+ }
+ return $definition;
+ }
+ }
+
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table column', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getTableIndexDefinition()
+
+ /**
+ * Get the structure of an index into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $index_name name of index that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableIndexDefinition($table_name, $index_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $table = $db->quoteIdentifier($table, true);
+ $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
+ $index_name_mdb2 = $db->getIndexName($index_name);
+ $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2)));
+ if (!PEAR::isError($result) && (null !== $result)) {
+ // apply 'idxname_format' only if the query succeeded, otherwise
+ // fallback to the given $index_name, without transformation
+ $index_name = $index_name_mdb2;
+ }
+ $result = $db->query(sprintf($query, $db->quote($index_name)));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $colpos = 1;
+ $definition = array();
+ while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
+ $row = array_change_key_case($row, CASE_LOWER);
+ $key_name = $row['key_name'];
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $key_name = strtolower($key_name);
+ } else {
+ $key_name = strtoupper($key_name);
+ }
+ }
+ if ($index_name == $key_name) {
+ if (!$row['non_unique']) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $index_name . ' is not an existing table index', __FUNCTION__);
+ }
+ $column_name = $row['column_name'];
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $column_name = strtolower($column_name);
+ } else {
+ $column_name = strtoupper($column_name);
+ }
+ }
+ $definition['fields'][$column_name] = array(
+ 'position' => $colpos++
+ );
+ if (!empty($row['collation'])) {
+ $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+ ? 'ascending' : 'descending');
+ }
+ }
+ }
+ $result->free();
+ if (empty($definition['fields'])) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $index_name . ' is not an existing table index', __FUNCTION__);
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTableConstraintDefinition()
+
+ /**
+ * Get the structure of a constraint into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $constraint_name name of constraint that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableConstraintDefinition($table_name, $constraint_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+ $constraint_name_original = $constraint_name;
+
+ $table = $db->quoteIdentifier($table, true);
+ $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
+ if (strtolower($constraint_name) != 'primary') {
+ $constraint_name_mdb2 = $db->getIndexName($constraint_name);
+ $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2)));
+ if (!PEAR::isError($result) && (null !== $result)) {
+ // apply 'idxname_format' only if the query succeeded, otherwise
+ // fallback to the given $index_name, without transformation
+ $constraint_name = $constraint_name_mdb2;
+ }
+ }
+ $result = $db->query(sprintf($query, $db->quote($constraint_name)));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $colpos = 1;
+ //default values, eventually overridden
+ $definition = array(
+ 'primary' => false,
+ 'unique' => false,
+ 'foreign' => false,
+ 'check' => false,
+ 'fields' => array(),
+ 'references' => array(
+ 'table' => '',
+ 'fields' => array(),
+ ),
+ 'onupdate' => '',
+ 'ondelete' => '',
+ 'match' => '',
+ 'deferrable' => false,
+ 'initiallydeferred' => false,
+ );
+ while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
+ $row = array_change_key_case($row, CASE_LOWER);
+ $key_name = $row['key_name'];
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $key_name = strtolower($key_name);
+ } else {
+ $key_name = strtoupper($key_name);
+ }
+ }
+ if ($constraint_name == $key_name) {
+ if ($row['non_unique']) {
+ //FOREIGN KEY?
+ return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition);
+ }
+ if ($row['key_name'] == 'PRIMARY') {
+ $definition['primary'] = true;
+ } elseif (!$row['non_unique']) {
+ $definition['unique'] = true;
+ }
+ $column_name = $row['column_name'];
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $column_name = strtolower($column_name);
+ } else {
+ $column_name = strtoupper($column_name);
+ }
+ }
+ $definition['fields'][$column_name] = array(
+ 'position' => $colpos++
+ );
+ if (!empty($row['collation'])) {
+ $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+ ? 'ascending' : 'descending');
+ }
+ }
+ }
+ $result->free();
+ if (empty($definition['fields'])) {
+ return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition);
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ _getTableFKConstraintDefinition()
+
+ /**
+ * Get the FK definition from the CREATE TABLE statement
+ *
+ * @param string $table table name
+ * @param string $constraint_name constraint name
+ * @param array $definition default values for constraint definition
+ *
+ * @return array|PEAR_Error
+ * @access private
+ */
+ function _getTableFKConstraintDefinition($table, $constraint_name, $definition)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ //Use INFORMATION_SCHEMA instead?
+ //SELECT *
+ // FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
+ // WHERE CONSTRAINT_SCHEMA = '$dbname'
+ // AND TABLE_NAME = '$table'
+ // AND CONSTRAINT_NAME = '$constraint_name';
+ $query = 'SHOW CREATE TABLE '. $db->escape($table);
+ $constraint = $db->queryOne($query, 'text', 1);
+ if (!PEAR::isError($constraint) && !empty($constraint)) {
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $constraint = strtolower($constraint);
+ } else {
+ $constraint = strtoupper($constraint);
+ }
+ }
+ $constraint_name_original = $constraint_name;
+ $constraint_name = $db->getIndexName($constraint_name);
+ $pattern = '/\bCONSTRAINT\s+'.$constraint_name.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i';
+ if (!preg_match($pattern, str_replace('`', '', $constraint), $matches)) {
+ //fallback to original constraint name
+ $pattern = '/\bCONSTRAINT\s+'.$constraint_name_original.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i';
+ }
+ if (preg_match($pattern, str_replace('`', '', $constraint), $matches)) {
+ $definition['foreign'] = true;
+ $column_names = explode(',', $matches[1]);
+ $referenced_cols = explode(',', $matches[3]);
+ $definition['references'] = array(
+ 'table' => $matches[2],
+ 'fields' => array(),
+ );
+ $colpos = 1;
+ foreach ($column_names as $column_name) {
+ $definition['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ $colpos = 1;
+ foreach ($referenced_cols as $column_name) {
+ $definition['references']['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ $definition['ondelete'] = empty($matches[4]) ? 'RESTRICT' : strtoupper($matches[4]);
+ $definition['onupdate'] = empty($matches[5]) ? 'RESTRICT' : strtoupper($matches[5]);
+ $definition['match'] = 'SIMPLE';
+ return $definition;
+ }
+ }
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getTriggerDefinition()
+
+ /**
+ * Get the structure of a trigger into an array
+ *
+ * EXPERIMENTAL
+ *
+ * WARNING: this function is experimental and may change the returned value
+ * at any time until labelled as non-experimental
+ *
+ * @param string $trigger name of trigger that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTriggerDefinition($trigger)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = 'SELECT trigger_name,
+ event_object_table AS table_name,
+ action_statement AS trigger_body,
+ action_timing AS trigger_type,
+ event_manipulation AS trigger_event
+ FROM information_schema.triggers
+ WHERE trigger_name = '. $db->quote($trigger, 'text');
+ $types = array(
+ 'trigger_name' => 'text',
+ 'table_name' => 'text',
+ 'trigger_body' => 'text',
+ 'trigger_type' => 'text',
+ 'trigger_event' => 'text',
+ );
+ $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($def)) {
+ return $def;
+ }
+ $def['trigger_comment'] = '';
+ $def['trigger_enabled'] = true;
+ return $def;
+ }
+
+ // }}}
+ // {{{ tableInfo()
+
+ /**
+ * Returns information about a table or a result set
+ *
+ * @param object|string $result MDB2_result object from a query or a
+ * string containing the name of a table.
+ * While this also accepts a query result
+ * resource identifier, this behavior is
+ * deprecated.
+ * @param int $mode a valid tableInfo mode
+ *
+ * @return array an associative array with the information requested.
+ * A MDB2_Error object on failure.
+ *
+ * @see MDB2_Driver_Common::setOption()
+ */
+ function tableInfo($result, $mode = null)
+ {
+ if (is_string($result)) {
+ return parent::tableInfo($result, $mode);
+ }
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
+ if (!is_resource($resource)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'Could not generate result resource', __FUNCTION__);
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $case_func = 'strtolower';
+ } else {
+ $case_func = 'strtoupper';
+ }
+ } else {
+ $case_func = 'strval';
+ }
+
+ $count = @mysql_num_fields($resource);
+ $res = array();
+ if ($mode) {
+ $res['num_fields'] = $count;
+ }
+
+ $db->loadModule('Datatype', null, true);
+ for ($i = 0; $i < $count; $i++) {
+ $res[$i] = array(
+ 'table' => $case_func(@mysql_field_table($resource, $i)),
+ 'name' => $case_func(@mysql_field_name($resource, $i)),
+ 'type' => @mysql_field_type($resource, $i),
+ 'length' => @mysql_field_len($resource, $i),
+ 'flags' => @mysql_field_flags($resource, $i),
+ );
+ if ($res[$i]['type'] == 'string') {
+ $res[$i]['type'] = 'char';
+ } elseif ($res[$i]['type'] == 'unknown') {
+ $res[$i]['type'] = 'decimal';
+ }
+ $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
+ if (PEAR::isError($mdb2type_info)) {
+ return $mdb2type_info;
+ }
+ $res[$i]['mdb2type'] = $mdb2type_info[0][0];
+ if ($mode & MDB2_TABLEINFO_ORDER) {
+ $res['order'][$res[$i]['name']] = $i;
+ }
+ if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
+ $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
+ }
+ }
+
+ return $res;
+ }
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Reverse/pgsql.php b/3rdparty/MDB2/Driver/Reverse/pgsql.php index 8669c2b919b..45aa5a1503b 100644 --- a/3rdparty/MDB2/Driver/Reverse/pgsql.php +++ b/3rdparty/MDB2/Driver/Reverse/pgsql.php @@ -1,573 +1,574 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Authors: Paul Cooper <pgc@ucecom.com> | -// | Lorenzo Alberton <l.alberton@quipo.it> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.75 2008/08/22 16:36:20 quipo Exp $ - -require_once('MDB2/Driver/Reverse/Common.php'); - -/** - * MDB2 PostGreSQL driver for the schema reverse engineering module - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - * @author Lorenzo Alberton <l.alberton@quipo.it> - */ -class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common -{ - // {{{ getTableFieldDefinition() - - /** - * Get the structure of a field into an array - * - * @param string $table_name name of table that should be used in method - * @param string $field_name name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableFieldDefinition($table_name, $field_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $query = "SELECT a.attname AS name, - t.typname AS type, - CASE a.attlen - WHEN -1 THEN - CASE t.typname - WHEN 'numeric' THEN (a.atttypmod / 65536) - WHEN 'decimal' THEN (a.atttypmod / 65536) - WHEN 'money' THEN (a.atttypmod / 65536) - ELSE CASE a.atttypmod - WHEN -1 THEN NULL - ELSE a.atttypmod - 4 - END - END - ELSE a.attlen - END AS length, - CASE t.typname - WHEN 'numeric' THEN (a.atttypmod % 65536) - 4 - WHEN 'decimal' THEN (a.atttypmod % 65536) - 4 - WHEN 'money' THEN (a.atttypmod % 65536) - 4 - ELSE 0 - END AS scale, - a.attnotnull, - a.atttypmod, - a.atthasdef, - (SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128) - FROM pg_attrdef d - WHERE d.adrelid = a.attrelid - AND d.adnum = a.attnum - AND a.atthasdef - ) as default - FROM pg_attribute a, - pg_class c, - pg_type t - WHERE c.relname = ".$db->quote($table, 'text')." - AND a.atttypid = t.oid - AND c.oid = a.attrelid - AND NOT a.attisdropped - AND a.attnum > 0 - AND a.attname = ".$db->quote($field_name, 'text')." - ORDER BY a.attnum"; - $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($column)) { - return $column; - } - - if (empty($column)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table column', __FUNCTION__); - } - - $column = array_change_key_case($column, CASE_LOWER); - $mapped_datatype = $db->datatype->mapNativeDatatype($column); - if (PEAR::isError($mapped_datatype)) { - return $mapped_datatype; - } - list($types, $length, $unsigned, $fixed) = $mapped_datatype; - $notnull = false; - if (!empty($column['attnotnull']) && $column['attnotnull'] == 't') { - $notnull = true; - } - $default = null; - if ($column['atthasdef'] === 't' - && !preg_match("/nextval\('([^']+)'/", $column['default']) - ) { - $pattern = '/^\'(.*)\'::[\w ]+$/i'; - $default = $column['default'];#substr($column['adsrc'], 1, -1); - if (is_null($default) && $notnull) { - $default = ''; - } elseif (!empty($default) && preg_match($pattern, $default)) { - //remove data type cast - $default = preg_replace ($pattern, '\\1', $default); - } - } - $autoincrement = false; - if (preg_match("/nextval\('([^']+)'/", $column['default'], $nextvals)) { - $autoincrement = true; - } - $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']); - if (!is_null($length)) { - $definition[0]['length'] = $length; - } - if (!is_null($unsigned)) { - $definition[0]['unsigned'] = $unsigned; - } - if (!is_null($fixed)) { - $definition[0]['fixed'] = $fixed; - } - if ($default !== false) { - $definition[0]['default'] = $default; - } - if ($autoincrement !== false) { - $definition[0]['autoincrement'] = $autoincrement; - } - foreach ($types as $key => $type) { - $definition[$key] = $definition[0]; - if ($type == 'clob' || $type == 'blob') { - unset($definition[$key]['default']); - } - $definition[$key]['type'] = $type; - $definition[$key]['mdb2type'] = $type; - } - return $definition; - } - - // }}} - // {{{ getTableIndexDefinition() - - /** - * Get the structure of an index into an array - * - * @param string $table_name name of table that should be used in method - * @param string $index_name name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableIndexDefinition($table_name, $index_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $query = 'SELECT relname, indkey FROM pg_index, pg_class'; - $query.= ' WHERE pg_class.oid = pg_index.indexrelid'; - $query.= " AND indisunique != 't' AND indisprimary != 't'"; - $query.= ' AND pg_class.relname = %s'; - $index_name_mdb2 = $db->getIndexName($index_name); - $row = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($row) || empty($row)) { - // fallback to the given $index_name, without transformation - $row = $db->queryRow(sprintf($query, $db->quote($index_name, 'text')), null, MDB2_FETCHMODE_ASSOC); - } - if (PEAR::isError($row)) { - return $row; - } - - if (empty($row)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); - } - - $row = array_change_key_case($row, CASE_LOWER); - - $db->loadModule('Manager', null, true); - $columns = $db->manager->listTableFields($table_name); - - $definition = array(); - - $index_column_numbers = explode(' ', $row['indkey']); - - $colpos = 1; - foreach ($index_column_numbers as $number) { - $definition['fields'][$columns[($number - 1)]] = array( - 'position' => $colpos++, - 'sorting' => 'ascending', - ); - } - return $definition; - } - - // }}} - // {{{ getTableConstraintDefinition() - - /** - * Get the structure of a constraint into an array - * - * @param string $table_name name of table that should be used in method - * @param string $constraint_name name of constraint that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableConstraintDefinition($table_name, $constraint_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $query = "SELECT c.oid, - c.conname AS constraint_name, - CASE WHEN c.contype = 'c' THEN 1 ELSE 0 END AS \"check\", - CASE WHEN c.contype = 'f' THEN 1 ELSE 0 END AS \"foreign\", - CASE WHEN c.contype = 'p' THEN 1 ELSE 0 END AS \"primary\", - CASE WHEN c.contype = 'u' THEN 1 ELSE 0 END AS \"unique\", - CASE WHEN c.condeferrable = 'f' THEN 0 ELSE 1 END AS deferrable, - CASE WHEN c.condeferred = 'f' THEN 0 ELSE 1 END AS initiallydeferred, - --array_to_string(c.conkey, ' ') AS constraint_key, - t.relname AS table_name, - t2.relname AS references_table, - CASE confupdtype - WHEN 'a' THEN 'NO ACTION' - WHEN 'r' THEN 'RESTRICT' - WHEN 'c' THEN 'CASCADE' - WHEN 'n' THEN 'SET NULL' - WHEN 'd' THEN 'SET DEFAULT' - END AS onupdate, - CASE confdeltype - WHEN 'a' THEN 'NO ACTION' - WHEN 'r' THEN 'RESTRICT' - WHEN 'c' THEN 'CASCADE' - WHEN 'n' THEN 'SET NULL' - WHEN 'd' THEN 'SET DEFAULT' - END AS ondelete, - CASE confmatchtype - WHEN 'u' THEN 'UNSPECIFIED' - WHEN 'f' THEN 'FULL' - WHEN 'p' THEN 'PARTIAL' - END AS match, - --array_to_string(c.confkey, ' ') AS fk_constraint_key, - consrc - FROM pg_constraint c - LEFT JOIN pg_class t ON c.conrelid = t.oid - LEFT JOIN pg_class t2 ON c.confrelid = t2.oid - WHERE c.conname = %s - AND t.relname = " . $db->quote($table, 'text'); - $constraint_name_mdb2 = $db->getIndexName($constraint_name); - $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($row) || empty($row)) { - // fallback to the given $index_name, without transformation - $constraint_name_mdb2 = $constraint_name; - $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); - } - if (PEAR::isError($row)) { - return $row; - } - $uniqueIndex = false; - if (empty($row)) { - // We might be looking for a UNIQUE index that was not created - // as a constraint but should be treated as such. - $query = 'SELECT relname AS constraint_name, - indkey, - 0 AS "check", - 0 AS "foreign", - 0 AS "primary", - 1 AS "unique", - 0 AS deferrable, - 0 AS initiallydeferred, - NULL AS references_table, - NULL AS onupdate, - NULL AS ondelete, - NULL AS match - FROM pg_index, pg_class - WHERE pg_class.oid = pg_index.indexrelid - AND indisunique = \'t\' - AND pg_class.relname = %s'; - $constraint_name_mdb2 = $db->getIndexName($constraint_name); - $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($row) || empty($row)) { - // fallback to the given $index_name, without transformation - $constraint_name_mdb2 = $constraint_name; - $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); - } - if (PEAR::isError($row)) { - return $row; - } - if (empty($row)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $constraint_name . ' is not an existing table constraint', __FUNCTION__); - } - $uniqueIndex = true; - } - - $row = array_change_key_case($row, CASE_LOWER); - - $definition = array( - 'primary' => (boolean)$row['primary'], - 'unique' => (boolean)$row['unique'], - 'foreign' => (boolean)$row['foreign'], - 'check' => (boolean)$row['check'], - 'fields' => array(), - 'references' => array( - 'table' => $row['references_table'], - 'fields' => array(), - ), - 'deferrable' => (boolean)$row['deferrable'], - 'initiallydeferred' => (boolean)$row['initiallydeferred'], - 'onupdate' => $row['onupdate'], - 'ondelete' => $row['ondelete'], - 'match' => $row['match'], - ); - - if ($uniqueIndex) { - $db->loadModule('Manager', null, true); - $columns = $db->manager->listTableFields($table_name); - $index_column_numbers = explode(' ', $row['indkey']); - $colpos = 1; - foreach ($index_column_numbers as $number) { - $definition['fields'][$columns[($number - 1)]] = array( - 'position' => $colpos++, - 'sorting' => 'ascending', - ); - } - return $definition; - } - - $query = 'SELECT a.attname - FROM pg_constraint c - LEFT JOIN pg_class t ON c.conrelid = t.oid - LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey) - WHERE c.conname = %s - AND t.relname = ' . $db->quote($table, 'text'); - $fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null); - if (PEAR::isError($fields)) { - return $fields; - } - $colpos = 1; - foreach ($fields as $field) { - $definition['fields'][$field] = array( - 'position' => $colpos++, - 'sorting' => 'ascending', - ); - } - - if ($definition['foreign']) { - $query = 'SELECT a.attname - FROM pg_constraint c - LEFT JOIN pg_class t ON c.confrelid = t.oid - LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.confkey) - WHERE c.conname = %s - AND t.relname = ' . $db->quote($definition['references']['table'], 'text'); - $foreign_fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null); - if (PEAR::isError($foreign_fields)) { - return $foreign_fields; - } - $colpos = 1; - foreach ($foreign_fields as $foreign_field) { - $definition['references']['fields'][$foreign_field] = array( - 'position' => $colpos++, - ); - } - } - - if ($definition['check']) { - $check_def = $db->queryOne("SELECT pg_get_constraintdef(" . $row['oid'] . ", 't')"); - // ... - } - return $definition; - } - - // }}} - // {{{ getTriggerDefinition() - - /** - * Get the structure of a trigger into an array - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change the returned value - * at any time until labelled as non-experimental - * - * @param string $trigger name of trigger that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - * - * @TODO: add support for plsql functions and functions with args - */ - function getTriggerDefinition($trigger) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT trg.tgname AS trigger_name, - tbl.relname AS table_name, - CASE - WHEN p.proname IS NOT NULL THEN 'EXECUTE PROCEDURE ' || p.proname || '();' - ELSE '' - END AS trigger_body, - CASE trg.tgtype & cast(2 as int2) - WHEN 0 THEN 'AFTER' - ELSE 'BEFORE' - END AS trigger_type, - CASE trg.tgtype & cast(28 as int2) - WHEN 16 THEN 'UPDATE' - WHEN 8 THEN 'DELETE' - WHEN 4 THEN 'INSERT' - WHEN 20 THEN 'INSERT, UPDATE' - WHEN 28 THEN 'INSERT, UPDATE, DELETE' - WHEN 24 THEN 'UPDATE, DELETE' - WHEN 12 THEN 'INSERT, DELETE' - END AS trigger_event, - CASE trg.tgenabled - WHEN 'O' THEN 't' - ELSE trg.tgenabled - END AS trigger_enabled, - obj_description(trg.oid, 'pg_trigger') AS trigger_comment - FROM pg_trigger trg, - pg_class tbl, - pg_proc p - WHERE trg.tgrelid = tbl.oid - AND trg.tgfoid = p.oid - AND trg.tgname = ". $db->quote($trigger, 'text'); - $types = array( - 'trigger_name' => 'text', - 'table_name' => 'text', - 'trigger_body' => 'text', - 'trigger_type' => 'text', - 'trigger_event' => 'text', - 'trigger_comment' => 'text', - 'trigger_enabled' => 'boolean', - ); - return $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); - } - - // }}} - // {{{ tableInfo() - - /** - * Returns information about a table or a result set - * - * NOTE: only supports 'table' and 'flags' if <var>$result</var> - * is a table name. - * - * @param object|string $result MDB2_result object from a query or a - * string containing the name of a table. - * While this also accepts a query result - * resource identifier, this behavior is - * deprecated. - * @param int $mode a valid tableInfo mode - * - * @return array an associative array with the information requested. - * A MDB2_Error object on failure. - * - * @see MDB2_Driver_Common::tableInfo() - */ - function tableInfo($result, $mode = null) - { - if (is_string($result)) { - return parent::tableInfo($result, $mode); - } - - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result; - if (!is_resource($resource)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Could not generate result resource', __FUNCTION__); - } - - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $case_func = 'strtolower'; - } else { - $case_func = 'strtoupper'; - } - } else { - $case_func = 'strval'; - } - - $count = @pg_num_fields($resource); - $res = array(); - - if ($mode) { - $res['num_fields'] = $count; - } - - $db->loadModule('Datatype', null, true); - for ($i = 0; $i < $count; $i++) { - $res[$i] = array( - 'table' => function_exists('pg_field_table') ? @pg_field_table($resource, $i) : '', - 'name' => $case_func(@pg_field_name($resource, $i)), - 'type' => @pg_field_type($resource, $i), - 'length' => @pg_field_size($resource, $i), - 'flags' => '', - ); - $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]); - if (PEAR::isError($mdb2type_info)) { - return $mdb2type_info; - } - $res[$i]['mdb2type'] = $mdb2type_info[0][0]; - if ($mode & MDB2_TABLEINFO_ORDER) { - $res['order'][$res[$i]['name']] = $i; - } - if ($mode & MDB2_TABLEINFO_ORDERTABLE) { - $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; - } - } - - return $res; - } -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Authors: Paul Cooper <pgc@ucecom.com> |
+// | Lorenzo Alberton <l.alberton@quipo.it> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 295587 2010-02-28 17:16:38Z quipo $
+
+require_once 'MDB2/Driver/Reverse/Common.php';
+
+/**
+ * MDB2 PostGreSQL driver for the schema reverse engineering module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ * @author Lorenzo Alberton <l.alberton@quipo.it>
+ */
+class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common
+{
+ // {{{ getTableFieldDefinition()
+
+ /**
+ * Get the structure of a field into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $field_name name of field that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableFieldDefinition($table_name, $field_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $result = $db->loadModule('Datatype', null, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $query = "SELECT a.attname AS name,
+ t.typname AS type,
+ CASE a.attlen
+ WHEN -1 THEN
+ CASE t.typname
+ WHEN 'numeric' THEN (a.atttypmod / 65536)
+ WHEN 'decimal' THEN (a.atttypmod / 65536)
+ WHEN 'money' THEN (a.atttypmod / 65536)
+ ELSE CASE a.atttypmod
+ WHEN -1 THEN NULL
+ ELSE a.atttypmod - 4
+ END
+ END
+ ELSE a.attlen
+ END AS length,
+ CASE t.typname
+ WHEN 'numeric' THEN (a.atttypmod % 65536) - 4
+ WHEN 'decimal' THEN (a.atttypmod % 65536) - 4
+ WHEN 'money' THEN (a.atttypmod % 65536) - 4
+ ELSE 0
+ END AS scale,
+ a.attnotnull,
+ a.atttypmod,
+ a.atthasdef,
+ (SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128)
+ FROM pg_attrdef d
+ WHERE d.adrelid = a.attrelid
+ AND d.adnum = a.attnum
+ AND a.atthasdef
+ ) as default
+ FROM pg_attribute a,
+ pg_class c,
+ pg_type t
+ WHERE c.relname = ".$db->quote($table, 'text')."
+ AND a.atttypid = t.oid
+ AND c.oid = a.attrelid
+ AND NOT a.attisdropped
+ AND a.attnum > 0
+ AND a.attname = ".$db->quote($field_name, 'text')."
+ ORDER BY a.attnum";
+ $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($column)) {
+ return $column;
+ }
+
+ if (empty($column)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table column', __FUNCTION__);
+ }
+
+ $column = array_change_key_case($column, CASE_LOWER);
+ $mapped_datatype = $db->datatype->mapNativeDatatype($column);
+ if (PEAR::isError($mapped_datatype)) {
+ return $mapped_datatype;
+ }
+ list($types, $length, $unsigned, $fixed) = $mapped_datatype;
+ $notnull = false;
+ if (!empty($column['attnotnull']) && $column['attnotnull'] == 't') {
+ $notnull = true;
+ }
+ $default = null;
+ if ($column['atthasdef'] === 't'
+ && strpos($column['default'], 'NULL') !== 0
+ && !preg_match("/nextval\('([^']+)'/", $column['default'])
+ ) {
+ $pattern = '/^\'(.*)\'::[\w ]+$/i';
+ $default = $column['default'];#substr($column['adsrc'], 1, -1);
+ if ((null === $default) && $notnull) {
+ $default = '';
+ } elseif (!empty($default) && preg_match($pattern, $default)) {
+ //remove data type cast
+ $default = preg_replace ($pattern, '\\1', $default);
+ }
+ }
+ $autoincrement = false;
+ if (preg_match("/nextval\('([^']+)'/", $column['default'], $nextvals)) {
+ $autoincrement = true;
+ }
+ $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']);
+ if (null !== $length) {
+ $definition[0]['length'] = $length;
+ }
+ if (null !== $unsigned) {
+ $definition[0]['unsigned'] = $unsigned;
+ }
+ if (null !== $fixed) {
+ $definition[0]['fixed'] = $fixed;
+ }
+ if ($default !== false) {
+ $definition[0]['default'] = $default;
+ }
+ if ($autoincrement !== false) {
+ $definition[0]['autoincrement'] = $autoincrement;
+ }
+ foreach ($types as $key => $type) {
+ $definition[$key] = $definition[0];
+ if ($type == 'clob' || $type == 'blob') {
+ unset($definition[$key]['default']);
+ }
+ $definition[$key]['type'] = $type;
+ $definition[$key]['mdb2type'] = $type;
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTableIndexDefinition()
+
+ /**
+ * Get the structure of an index into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $index_name name of index that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableIndexDefinition($table_name, $index_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $query = 'SELECT relname, indkey FROM pg_index, pg_class';
+ $query.= ' WHERE pg_class.oid = pg_index.indexrelid';
+ $query.= " AND indisunique != 't' AND indisprimary != 't'";
+ $query.= ' AND pg_class.relname = %s';
+ $index_name_mdb2 = $db->getIndexName($index_name);
+ $row = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($row) || empty($row)) {
+ // fallback to the given $index_name, without transformation
+ $row = $db->queryRow(sprintf($query, $db->quote($index_name, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ }
+ if (PEAR::isError($row)) {
+ return $row;
+ }
+
+ if (empty($row)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table index', __FUNCTION__);
+ }
+
+ $row = array_change_key_case($row, CASE_LOWER);
+
+ $db->loadModule('Manager', null, true);
+ $columns = $db->manager->listTableFields($table_name);
+
+ $definition = array();
+
+ $index_column_numbers = explode(' ', $row['indkey']);
+
+ $colpos = 1;
+ foreach ($index_column_numbers as $number) {
+ $definition['fields'][$columns[($number - 1)]] = array(
+ 'position' => $colpos++,
+ 'sorting' => 'ascending',
+ );
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTableConstraintDefinition()
+
+ /**
+ * Get the structure of a constraint into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $constraint_name name of constraint that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableConstraintDefinition($table_name, $constraint_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $query = "SELECT c.oid,
+ c.conname AS constraint_name,
+ CASE WHEN c.contype = 'c' THEN 1 ELSE 0 END AS \"check\",
+ CASE WHEN c.contype = 'f' THEN 1 ELSE 0 END AS \"foreign\",
+ CASE WHEN c.contype = 'p' THEN 1 ELSE 0 END AS \"primary\",
+ CASE WHEN c.contype = 'u' THEN 1 ELSE 0 END AS \"unique\",
+ CASE WHEN c.condeferrable = 'f' THEN 0 ELSE 1 END AS deferrable,
+ CASE WHEN c.condeferred = 'f' THEN 0 ELSE 1 END AS initiallydeferred,
+ --array_to_string(c.conkey, ' ') AS constraint_key,
+ t.relname AS table_name,
+ t2.relname AS references_table,
+ CASE confupdtype
+ WHEN 'a' THEN 'NO ACTION'
+ WHEN 'r' THEN 'RESTRICT'
+ WHEN 'c' THEN 'CASCADE'
+ WHEN 'n' THEN 'SET NULL'
+ WHEN 'd' THEN 'SET DEFAULT'
+ END AS onupdate,
+ CASE confdeltype
+ WHEN 'a' THEN 'NO ACTION'
+ WHEN 'r' THEN 'RESTRICT'
+ WHEN 'c' THEN 'CASCADE'
+ WHEN 'n' THEN 'SET NULL'
+ WHEN 'd' THEN 'SET DEFAULT'
+ END AS ondelete,
+ CASE confmatchtype
+ WHEN 'u' THEN 'UNSPECIFIED'
+ WHEN 'f' THEN 'FULL'
+ WHEN 'p' THEN 'PARTIAL'
+ END AS match,
+ --array_to_string(c.confkey, ' ') AS fk_constraint_key,
+ consrc
+ FROM pg_constraint c
+ LEFT JOIN pg_class t ON c.conrelid = t.oid
+ LEFT JOIN pg_class t2 ON c.confrelid = t2.oid
+ WHERE c.conname = %s
+ AND t.relname = " . $db->quote($table, 'text');
+ $constraint_name_mdb2 = $db->getIndexName($constraint_name);
+ $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($row) || empty($row)) {
+ // fallback to the given $index_name, without transformation
+ $constraint_name_mdb2 = $constraint_name;
+ $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ }
+ if (PEAR::isError($row)) {
+ return $row;
+ }
+ $uniqueIndex = false;
+ if (empty($row)) {
+ // We might be looking for a UNIQUE index that was not created
+ // as a constraint but should be treated as such.
+ $query = 'SELECT relname AS constraint_name,
+ indkey,
+ 0 AS "check",
+ 0 AS "foreign",
+ 0 AS "primary",
+ 1 AS "unique",
+ 0 AS deferrable,
+ 0 AS initiallydeferred,
+ NULL AS references_table,
+ NULL AS onupdate,
+ NULL AS ondelete,
+ NULL AS match
+ FROM pg_index, pg_class
+ WHERE pg_class.oid = pg_index.indexrelid
+ AND indisunique = \'t\'
+ AND pg_class.relname = %s';
+ $constraint_name_mdb2 = $db->getIndexName($constraint_name);
+ $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($row) || empty($row)) {
+ // fallback to the given $index_name, without transformation
+ $constraint_name_mdb2 = $constraint_name;
+ $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
+ }
+ if (PEAR::isError($row)) {
+ return $row;
+ }
+ if (empty($row)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__);
+ }
+ $uniqueIndex = true;
+ }
+
+ $row = array_change_key_case($row, CASE_LOWER);
+
+ $definition = array(
+ 'primary' => (boolean)$row['primary'],
+ 'unique' => (boolean)$row['unique'],
+ 'foreign' => (boolean)$row['foreign'],
+ 'check' => (boolean)$row['check'],
+ 'fields' => array(),
+ 'references' => array(
+ 'table' => $row['references_table'],
+ 'fields' => array(),
+ ),
+ 'deferrable' => (boolean)$row['deferrable'],
+ 'initiallydeferred' => (boolean)$row['initiallydeferred'],
+ 'onupdate' => $row['onupdate'],
+ 'ondelete' => $row['ondelete'],
+ 'match' => $row['match'],
+ );
+
+ if ($uniqueIndex) {
+ $db->loadModule('Manager', null, true);
+ $columns = $db->manager->listTableFields($table_name);
+ $index_column_numbers = explode(' ', $row['indkey']);
+ $colpos = 1;
+ foreach ($index_column_numbers as $number) {
+ $definition['fields'][$columns[($number - 1)]] = array(
+ 'position' => $colpos++,
+ 'sorting' => 'ascending',
+ );
+ }
+ return $definition;
+ }
+
+ $query = 'SELECT a.attname
+ FROM pg_constraint c
+ LEFT JOIN pg_class t ON c.conrelid = t.oid
+ LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
+ WHERE c.conname = %s
+ AND t.relname = ' . $db->quote($table, 'text');
+ $fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null);
+ if (PEAR::isError($fields)) {
+ return $fields;
+ }
+ $colpos = 1;
+ foreach ($fields as $field) {
+ $definition['fields'][$field] = array(
+ 'position' => $colpos++,
+ 'sorting' => 'ascending',
+ );
+ }
+
+ if ($definition['foreign']) {
+ $query = 'SELECT a.attname
+ FROM pg_constraint c
+ LEFT JOIN pg_class t ON c.confrelid = t.oid
+ LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.confkey)
+ WHERE c.conname = %s
+ AND t.relname = ' . $db->quote($definition['references']['table'], 'text');
+ $foreign_fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null);
+ if (PEAR::isError($foreign_fields)) {
+ return $foreign_fields;
+ }
+ $colpos = 1;
+ foreach ($foreign_fields as $foreign_field) {
+ $definition['references']['fields'][$foreign_field] = array(
+ 'position' => $colpos++,
+ );
+ }
+ }
+
+ if ($definition['check']) {
+ $check_def = $db->queryOne("SELECT pg_get_constraintdef(" . $row['oid'] . ", 't')");
+ // ...
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTriggerDefinition()
+
+ /**
+ * Get the structure of a trigger into an array
+ *
+ * EXPERIMENTAL
+ *
+ * WARNING: this function is experimental and may change the returned value
+ * at any time until labelled as non-experimental
+ *
+ * @param string $trigger name of trigger that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ *
+ * @TODO: add support for plsql functions and functions with args
+ */
+ function getTriggerDefinition($trigger)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT trg.tgname AS trigger_name,
+ tbl.relname AS table_name,
+ CASE
+ WHEN p.proname IS NOT NULL THEN 'EXECUTE PROCEDURE ' || p.proname || '();'
+ ELSE ''
+ END AS trigger_body,
+ CASE trg.tgtype & cast(2 as int2)
+ WHEN 0 THEN 'AFTER'
+ ELSE 'BEFORE'
+ END AS trigger_type,
+ CASE trg.tgtype & cast(28 as int2)
+ WHEN 16 THEN 'UPDATE'
+ WHEN 8 THEN 'DELETE'
+ WHEN 4 THEN 'INSERT'
+ WHEN 20 THEN 'INSERT, UPDATE'
+ WHEN 28 THEN 'INSERT, UPDATE, DELETE'
+ WHEN 24 THEN 'UPDATE, DELETE'
+ WHEN 12 THEN 'INSERT, DELETE'
+ END AS trigger_event,
+ CASE trg.tgenabled
+ WHEN 'O' THEN 't'
+ ELSE trg.tgenabled
+ END AS trigger_enabled,
+ obj_description(trg.oid, 'pg_trigger') AS trigger_comment
+ FROM pg_trigger trg,
+ pg_class tbl,
+ pg_proc p
+ WHERE trg.tgrelid = tbl.oid
+ AND trg.tgfoid = p.oid
+ AND trg.tgname = ". $db->quote($trigger, 'text');
+ $types = array(
+ 'trigger_name' => 'text',
+ 'table_name' => 'text',
+ 'trigger_body' => 'text',
+ 'trigger_type' => 'text',
+ 'trigger_event' => 'text',
+ 'trigger_comment' => 'text',
+ 'trigger_enabled' => 'boolean',
+ );
+ return $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
+ }
+
+ // }}}
+ // {{{ tableInfo()
+
+ /**
+ * Returns information about a table or a result set
+ *
+ * NOTE: only supports 'table' and 'flags' if <var>$result</var>
+ * is a table name.
+ *
+ * @param object|string $result MDB2_result object from a query or a
+ * string containing the name of a table.
+ * While this also accepts a query result
+ * resource identifier, this behavior is
+ * deprecated.
+ * @param int $mode a valid tableInfo mode
+ *
+ * @return array an associative array with the information requested.
+ * A MDB2_Error object on failure.
+ *
+ * @see MDB2_Driver_Common::tableInfo()
+ */
+ function tableInfo($result, $mode = null)
+ {
+ if (is_string($result)) {
+ return parent::tableInfo($result, $mode);
+ }
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
+ if (!is_resource($resource)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'Could not generate result resource', __FUNCTION__);
+ }
+
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $case_func = 'strtolower';
+ } else {
+ $case_func = 'strtoupper';
+ }
+ } else {
+ $case_func = 'strval';
+ }
+
+ $count = @pg_num_fields($resource);
+ $res = array();
+
+ if ($mode) {
+ $res['num_fields'] = $count;
+ }
+
+ $db->loadModule('Datatype', null, true);
+ for ($i = 0; $i < $count; $i++) {
+ $res[$i] = array(
+ 'table' => function_exists('pg_field_table') ? @pg_field_table($resource, $i) : '',
+ 'name' => $case_func(@pg_field_name($resource, $i)),
+ 'type' => @pg_field_type($resource, $i),
+ 'length' => @pg_field_size($resource, $i),
+ 'flags' => '',
+ );
+ $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
+ if (PEAR::isError($mdb2type_info)) {
+ return $mdb2type_info;
+ }
+ $res[$i]['mdb2type'] = $mdb2type_info[0][0];
+ if ($mode & MDB2_TABLEINFO_ORDER) {
+ $res['order'][$res[$i]['name']] = $i;
+ }
+ if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
+ $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
+ }
+ }
+
+ return $res;
+ }
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/Reverse/sqlite.php b/3rdparty/MDB2/Driver/Reverse/sqlite.php index 60c686c418a..b98ccdb62cd 100644 --- a/3rdparty/MDB2/Driver/Reverse/sqlite.php +++ b/3rdparty/MDB2/Driver/Reverse/sqlite.php @@ -1,609 +1,609 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Authors: Lukas Smith <smith@pooteeweet.org> | -// | Lorenzo Alberton <l.alberton@quipo.it> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.80 2008/05/03 10:30:14 quipo Exp $ -// - -require_once('MDB2/Driver/Reverse/Common.php'); - -/** - * MDB2 SQlite driver for the schema reverse engineering module - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common -{ - /** - * Remove SQL comments from the field definition - * - * @access private - */ - function _removeComments($sql) { - $lines = explode("\n", $sql); - foreach ($lines as $k => $line) { - $pieces = explode('--', $line); - if (count($pieces) > 1 && (substr_count($pieces[0], '\'') % 2) == 0) { - $lines[$k] = substr($line, 0, strpos($line, '--')); - } - } - return implode("\n", $lines); - } - - /** - * - */ - function _getTableColumns($sql) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $start_pos = strpos($sql, '('); - $end_pos = strrpos($sql, ')'); - $column_def = substr($sql, $start_pos+1, $end_pos-$start_pos-1); - // replace the decimal length-places-separator with a colon - $column_def = preg_replace('/(\d),(\d)/', '\1:\2', $column_def); - $column_def = $this->_removeComments($column_def); - $column_sql = explode(',', $column_def); - $columns = array(); - $count = count($column_sql); - if ($count == 0) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'unexpected empty table column definition list', __FUNCTION__); - } - $regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i'; - $regexp2 = '/^\s*([^ ]+) +(PRIMARY|UNIQUE|CHECK)$/i'; - for ($i=0, $j=0; $i<$count; ++$i) { - if (!preg_match($regexp, trim($column_sql[$i]), $matches)) { - if (!preg_match($regexp2, trim($column_sql[$i]))) { - continue; - } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'unexpected table column SQL definition: "'.$column_sql[$i].'"', __FUNCTION__); - } - $columns[$j]['name'] = trim($matches[1], implode('', $db->identifier_quoting)); - $columns[$j]['type'] = strtolower($matches[2]); - if (isset($matches[4]) && strlen($matches[4])) { - $columns[$j]['length'] = $matches[4]; - } - if (isset($matches[6]) && strlen($matches[6])) { - $columns[$j]['decimal'] = $matches[6]; - } - if (isset($matches[8]) && strlen($matches[8])) { - $columns[$j]['unsigned'] = true; - } - if (isset($matches[9]) && strlen($matches[9])) { - $columns[$j]['autoincrement'] = true; - } - if (isset($matches[12]) && strlen($matches[12])) { - $default = $matches[12]; - if (strlen($default) && $default[0]=="'") { - $default = str_replace("''", "'", substr($default, 1, strlen($default)-2)); - } - if ($default === 'NULL') { - $default = null; - } - $columns[$j]['default'] = $default; - } - if (isset($matches[7]) && strlen($matches[7])) { - $columns[$j]['notnull'] = ($matches[7] === ' NOT NULL'); - } else if (isset($matches[9]) && strlen($matches[9])) { - $columns[$j]['notnull'] = ($matches[9] === ' NOT NULL'); - } else if (isset($matches[13]) && strlen($matches[13])) { - $columns[$j]['notnull'] = ($matches[13] === ' NOT NULL'); - } - ++$j; - } - return $columns; - } - - // {{{ getTableFieldDefinition() - - /** - * Get the stucture of a field into an array - * - * @param string $table_name name of table that should be used in method - * @param string $field_name name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure. - * The returned array contains an array for each field definition, - * with (some of) these indices: - * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] - * @access public - */ - function getTableFieldDefinition($table_name, $field_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $result = $db->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - $query = "SELECT sql FROM sqlite_master WHERE type='table' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text'); - } else { - $query.= 'name='.$db->quote($table, 'text'); - } - $sql = $db->queryOne($query); - if (PEAR::isError($sql)) { - return $sql; - } - $columns = $this->_getTableColumns($sql); - foreach ($columns as $column) { - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($db->options['field_case'] == CASE_LOWER) { - $column['name'] = strtolower($column['name']); - } else { - $column['name'] = strtoupper($column['name']); - } - } else { - $column = array_change_key_case($column, $db->options['field_case']); - } - if ($field_name == $column['name']) { - $mapped_datatype = $db->datatype->mapNativeDatatype($column); - if (PEAR::isError($mapped_datatype)) { - return $mapped_datatype; - } - list($types, $length, $unsigned, $fixed) = $mapped_datatype; - $notnull = false; - if (!empty($column['notnull'])) { - $notnull = $column['notnull']; - } - $default = false; - if (array_key_exists('default', $column)) { - $default = $column['default']; - if (is_null($default) && $notnull) { - $default = ''; - } - } - $autoincrement = false; - if (!empty($column['autoincrement'])) { - $autoincrement = true; - } - - $definition[0] = array( - 'notnull' => $notnull, - 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) - ); - if (!is_null($length)) { - $definition[0]['length'] = $length; - } - if (!is_null($unsigned)) { - $definition[0]['unsigned'] = $unsigned; - } - if (!is_null($fixed)) { - $definition[0]['fixed'] = $fixed; - } - if ($default !== false) { - $definition[0]['default'] = $default; - } - if ($autoincrement !== false) { - $definition[0]['autoincrement'] = $autoincrement; - } - foreach ($types as $key => $type) { - $definition[$key] = $definition[0]; - if ($type == 'clob' || $type == 'blob') { - unset($definition[$key]['default']); - } - $definition[$key]['type'] = $type; - $definition[$key]['mdb2type'] = $type; - } - return $definition; - } - } - - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table column', __FUNCTION__); - } - - // }}} - // {{{ getTableIndexDefinition() - - /** - * Get the stucture of an index into an array - * - * @param string $table_name name of table that should be used in method - * @param string $index_name name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableIndexDefinition($table_name, $index_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $query = "SELECT sql FROM sqlite_master WHERE type='index' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text'); - } else { - $query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text'); - } - $query.= ' AND sql NOT NULL ORDER BY name'; - $index_name_mdb2 = $db->getIndexName($index_name); - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $qry = sprintf($query, $db->quote(strtolower($index_name_mdb2), 'text')); - } else { - $qry = sprintf($query, $db->quote($index_name_mdb2, 'text')); - } - $sql = $db->queryOne($qry, 'text'); - if (PEAR::isError($sql) || empty($sql)) { - // fallback to the given $index_name, without transformation - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $qry = sprintf($query, $db->quote(strtolower($index_name), 'text')); - } else { - $qry = sprintf($query, $db->quote($index_name, 'text')); - } - $sql = $db->queryOne($qry, 'text'); - } - if (PEAR::isError($sql)) { - return $sql; - } - if (!$sql) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); - } - - $sql = strtolower($sql); - $start_pos = strpos($sql, '('); - $end_pos = strrpos($sql, ')'); - $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1); - $column_names = explode(',', $column_names); - - if (preg_match("/^create unique/", $sql)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); - } - - $definition = array(); - $count = count($column_names); - for ($i=0; $i<$count; ++$i) { - $column_name = strtok($column_names[$i], ' '); - $collation = strtok(' '); - $definition['fields'][$column_name] = array( - 'position' => $i+1 - ); - if (!empty($collation)) { - $definition['fields'][$column_name]['sorting'] = - ($collation=='ASC' ? 'ascending' : 'descending'); - } - } - - if (empty($definition['fields'])) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); - } - return $definition; - } - - // }}} - // {{{ getTableConstraintDefinition() - - /** - * Get the stucture of a constraint into an array - * - * @param string $table_name name of table that should be used in method - * @param string $constraint_name name of constraint that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTableConstraintDefinition($table_name, $constraint_name) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - list($schema, $table) = $this->splitTableSchema($table_name); - - $query = "SELECT sql FROM sqlite_master WHERE type='index' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text'); - } else { - $query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text'); - } - $query.= ' AND sql NOT NULL ORDER BY name'; - $constraint_name_mdb2 = $db->getIndexName($constraint_name); - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $qry = sprintf($query, $db->quote(strtolower($constraint_name_mdb2), 'text')); - } else { - $qry = sprintf($query, $db->quote($constraint_name_mdb2, 'text')); - } - $sql = $db->queryOne($qry, 'text'); - if (PEAR::isError($sql) || empty($sql)) { - // fallback to the given $index_name, without transformation - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $qry = sprintf($query, $db->quote(strtolower($constraint_name), 'text')); - } else { - $qry = sprintf($query, $db->quote($constraint_name, 'text')); - } - $sql = $db->queryOne($qry, 'text'); - } - if (PEAR::isError($sql)) { - return $sql; - } - //default values, eventually overridden - $definition = array( - 'primary' => false, - 'unique' => false, - 'foreign' => false, - 'check' => false, - 'fields' => array(), - 'references' => array( - 'table' => '', - 'fields' => array(), - ), - 'onupdate' => '', - 'ondelete' => '', - 'match' => '', - 'deferrable' => false, - 'initiallydeferred' => false, - ); - if (!$sql) { - $query = "SELECT sql FROM sqlite_master WHERE type='table' AND "; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text'); - } else { - $query.= 'name='.$db->quote($table, 'text'); - } - $query.= " AND sql NOT NULL ORDER BY name"; - $sql = $db->queryOne($query, 'text'); - if (PEAR::isError($sql)) { - return $sql; - } - if ($constraint_name == 'primary') { - // search in table definition for PRIMARY KEYs - if (preg_match("/\bPRIMARY\s+KEY\b\s*\(([^)]+)/i", $sql, $tmp)) { - $definition['primary'] = true; - $definition['fields'] = array(); - $column_names = explode(',', $tmp[1]); - $colpos = 1; - foreach ($column_names as $column_name) { - $definition['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - return $definition; - } - if (preg_match("/\"([^\"]+)\"[^\,\"]+\bPRIMARY\s+KEY\b[^\,\)]*/i", $sql, $tmp)) { - $definition['primary'] = true; - $definition['fields'] = array(); - $column_names = explode(',', $tmp[1]); - $colpos = 1; - foreach ($column_names as $column_name) { - $definition['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - return $definition; - } - } else { - // search in table definition for FOREIGN KEYs - $pattern = "/\bCONSTRAINT\b\s+%s\s+ - \bFOREIGN\s+KEY\b\s*\(([^\)]+)\)\s* - \bREFERENCES\b\s+([^\s]+)\s*\(([^\)]+)\)\s* - (?:\bMATCH\s*([^\s]+))?\s* - (?:\bON\s+UPDATE\s+([^\s,\)]+))?\s* - (?:\bON\s+DELETE\s+([^\s,\)]+))?\s* - /imsx"; - $found_fk = false; - if (preg_match(sprintf($pattern, $constraint_name_mdb2), $sql, $tmp)) { - $found_fk = true; - } elseif (preg_match(sprintf($pattern, $constraint_name), $sql, $tmp)) { - $found_fk = true; - } - if ($found_fk) { - $definition['foreign'] = true; - $definition['match'] = 'SIMPLE'; - $definition['onupdate'] = 'NO ACTION'; - $definition['ondelete'] = 'NO ACTION'; - $definition['references']['table'] = $tmp[2]; - $column_names = explode(',', $tmp[1]); - $colpos = 1; - foreach ($column_names as $column_name) { - $definition['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - $referenced_cols = explode(',', $tmp[3]); - $colpos = 1; - foreach ($referenced_cols as $column_name) { - $definition['references']['fields'][trim($column_name)] = array( - 'position' => $colpos++ - ); - } - if (isset($tmp[4])) { - $definition['match'] = $tmp[4]; - } - if (isset($tmp[5])) { - $definition['onupdate'] = $tmp[5]; - } - if (isset($tmp[6])) { - $definition['ondelete'] = $tmp[6]; - } - return $definition; - } - } - $sql = false; - } - if (!$sql) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $constraint_name . ' is not an existing table constraint', __FUNCTION__); - } - - $sql = strtolower($sql); - $start_pos = strpos($sql, '('); - $end_pos = strrpos($sql, ')'); - $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1); - $column_names = explode(',', $column_names); - - if (!preg_match("/^create unique/", $sql)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $constraint_name . ' is not an existing table constraint', __FUNCTION__); - } - - $definition['unique'] = true; - $count = count($column_names); - for ($i=0; $i<$count; ++$i) { - $column_name = strtok($column_names[$i]," "); - $collation = strtok(" "); - $definition['fields'][$column_name] = array( - 'position' => $i+1 - ); - if (!empty($collation)) { - $definition['fields'][$column_name]['sorting'] = - ($collation=='ASC' ? 'ascending' : 'descending'); - } - } - - if (empty($definition['fields'])) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - $constraint_name . ' is not an existing table constraint', __FUNCTION__); - } - return $definition; - } - - // }}} - // {{{ getTriggerDefinition() - - /** - * Get the structure of a trigger into an array - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change the returned value - * at any time until labelled as non-experimental - * - * @param string $trigger name of trigger that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * @access public - */ - function getTriggerDefinition($trigger) - { - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $query = "SELECT name as trigger_name, - tbl_name AS table_name, - sql AS trigger_body, - NULL AS trigger_type, - NULL AS trigger_event, - NULL AS trigger_comment, - 1 AS trigger_enabled - FROM sqlite_master - WHERE type='trigger'"; - if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $query.= ' AND LOWER(name)='.$db->quote(strtolower($trigger), 'text'); - } else { - $query.= ' AND name='.$db->quote($trigger, 'text'); - } - $types = array( - 'trigger_name' => 'text', - 'table_name' => 'text', - 'trigger_body' => 'text', - 'trigger_type' => 'text', - 'trigger_event' => 'text', - 'trigger_comment' => 'text', - 'trigger_enabled' => 'boolean', - ); - $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($def)) { - return $def; - } - if (empty($def)) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing trigger', __FUNCTION__); - } - if (preg_match("/^create\s+(?:temp|temporary)?trigger\s+(?:if\s+not\s+exists\s+)?.*(before|after)?\s+(insert|update|delete)/Uims", $def['trigger_body'], $tmp)) { - $def['trigger_type'] = strtoupper($tmp[1]); - $def['trigger_event'] = strtoupper($tmp[2]); - } - return $def; - } - - // }}} - // {{{ tableInfo() - - /** - * Returns information about a table - * - * @param string $result a string containing the name of a table - * @param int $mode a valid tableInfo mode - * - * @return array an associative array with the information requested. - * A MDB2_Error object on failure. - * - * @see MDB2_Driver_Common::tableInfo() - * @since Method available since Release 1.7.0 - */ - function tableInfo($result, $mode = null) - { - if (is_string($result)) { - return parent::tableInfo($result, $mode); - } - - $db =$this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null, - 'This DBMS can not obtain tableInfo from result sets', __FUNCTION__); - } -} - +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Authors: Lukas Smith <smith@pooteeweet.org> |
+// | Lorenzo Alberton <l.alberton@quipo.it> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+require_once 'MDB2/Driver/Reverse/Common.php';
+
+/**
+ * MDB2 SQlite driver for the schema reverse engineering module
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common
+{
+ /**
+ * Remove SQL comments from the field definition
+ *
+ * @access private
+ */
+ function _removeComments($sql) {
+ $lines = explode("\n", $sql);
+ foreach ($lines as $k => $line) {
+ $pieces = explode('--', $line);
+ if (count($pieces) > 1 && (substr_count($pieces[0], '\'') % 2) == 0) {
+ $lines[$k] = substr($line, 0, strpos($line, '--'));
+ }
+ }
+ return implode("\n", $lines);
+ }
+
+ /**
+ *
+ */
+ function _getTableColumns($sql)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $start_pos = strpos($sql, '(');
+ $end_pos = strrpos($sql, ')');
+ $column_def = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
+ // replace the decimal length-places-separator with a colon
+ $column_def = preg_replace('/(\d),(\d)/', '\1:\2', $column_def);
+ $column_def = $this->_removeComments($column_def);
+ $column_sql = explode(',', $column_def);
+ $columns = array();
+ $count = count($column_sql);
+ if ($count == 0) {
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'unexpected empty table column definition list', __FUNCTION__);
+ }
+ $regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i';
+ $regexp2 = '/^\s*([^ ]+) +(PRIMARY|UNIQUE|CHECK)$/i';
+ for ($i=0, $j=0; $i<$count; ++$i) {
+ if (!preg_match($regexp, trim($column_sql[$i]), $matches)) {
+ if (!preg_match($regexp2, trim($column_sql[$i]))) {
+ continue;
+ }
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'unexpected table column SQL definition: "'.$column_sql[$i].'"', __FUNCTION__);
+ }
+ $columns[$j]['name'] = trim($matches[1], implode('', $db->identifier_quoting));
+ $columns[$j]['type'] = strtolower($matches[2]);
+ if (isset($matches[4]) && strlen($matches[4])) {
+ $columns[$j]['length'] = $matches[4];
+ }
+ if (isset($matches[6]) && strlen($matches[6])) {
+ $columns[$j]['decimal'] = $matches[6];
+ }
+ if (isset($matches[8]) && strlen($matches[8])) {
+ $columns[$j]['unsigned'] = true;
+ }
+ if (isset($matches[9]) && strlen($matches[9])) {
+ $columns[$j]['autoincrement'] = true;
+ }
+ if (isset($matches[12]) && strlen($matches[12])) {
+ $default = $matches[12];
+ if (strlen($default) && $default[0]=="'") {
+ $default = str_replace("''", "'", substr($default, 1, strlen($default)-2));
+ }
+ if ($default === 'NULL') {
+ $default = null;
+ }
+ $columns[$j]['default'] = $default;
+ }
+ if (isset($matches[7]) && strlen($matches[7])) {
+ $columns[$j]['notnull'] = ($matches[7] === ' NOT NULL');
+ } else if (isset($matches[9]) && strlen($matches[9])) {
+ $columns[$j]['notnull'] = ($matches[9] === ' NOT NULL');
+ } else if (isset($matches[13]) && strlen($matches[13])) {
+ $columns[$j]['notnull'] = ($matches[13] === ' NOT NULL');
+ }
+ ++$j;
+ }
+ return $columns;
+ }
+
+ // {{{ getTableFieldDefinition()
+
+ /**
+ * Get the stucture of a field into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $field_name name of field that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure.
+ * The returned array contains an array for each field definition,
+ * with (some of) these indices:
+ * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
+ * @access public
+ */
+ function getTableFieldDefinition($table_name, $field_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $result = $db->loadModule('Datatype', null, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
+ } else {
+ $query.= 'name='.$db->quote($table, 'text');
+ }
+ $sql = $db->queryOne($query);
+ if (PEAR::isError($sql)) {
+ return $sql;
+ }
+ $columns = $this->_getTableColumns($sql);
+ foreach ($columns as $column) {
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ if ($db->options['field_case'] == CASE_LOWER) {
+ $column['name'] = strtolower($column['name']);
+ } else {
+ $column['name'] = strtoupper($column['name']);
+ }
+ } else {
+ $column = array_change_key_case($column, $db->options['field_case']);
+ }
+ if ($field_name == $column['name']) {
+ $mapped_datatype = $db->datatype->mapNativeDatatype($column);
+ if (PEAR::isError($mapped_datatype)) {
+ return $mapped_datatype;
+ }
+ list($types, $length, $unsigned, $fixed) = $mapped_datatype;
+ $notnull = false;
+ if (!empty($column['notnull'])) {
+ $notnull = $column['notnull'];
+ }
+ $default = false;
+ if (array_key_exists('default', $column)) {
+ $default = $column['default'];
+ if ((null === $default) && $notnull) {
+ $default = '';
+ }
+ }
+ $autoincrement = false;
+ if (!empty($column['autoincrement'])) {
+ $autoincrement = true;
+ }
+
+ $definition[0] = array(
+ 'notnull' => $notnull,
+ 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
+ );
+ if (null !== $length) {
+ $definition[0]['length'] = $length;
+ }
+ if (null !== $unsigned) {
+ $definition[0]['unsigned'] = $unsigned;
+ }
+ if (null !== $fixed) {
+ $definition[0]['fixed'] = $fixed;
+ }
+ if ($default !== false) {
+ $definition[0]['default'] = $default;
+ }
+ if ($autoincrement !== false) {
+ $definition[0]['autoincrement'] = $autoincrement;
+ }
+ foreach ($types as $key => $type) {
+ $definition[$key] = $definition[0];
+ if ($type == 'clob' || $type == 'blob') {
+ unset($definition[$key]['default']);
+ }
+ $definition[$key]['type'] = $type;
+ $definition[$key]['mdb2type'] = $type;
+ }
+ return $definition;
+ }
+ }
+
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table column', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ getTableIndexDefinition()
+
+ /**
+ * Get the stucture of an index into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $index_name name of index that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableIndexDefinition($table_name, $index_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
+ } else {
+ $query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
+ }
+ $query.= ' AND sql NOT NULL ORDER BY name';
+ $index_name_mdb2 = $db->getIndexName($index_name);
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $qry = sprintf($query, $db->quote(strtolower($index_name_mdb2), 'text'));
+ } else {
+ $qry = sprintf($query, $db->quote($index_name_mdb2, 'text'));
+ }
+ $sql = $db->queryOne($qry, 'text');
+ if (PEAR::isError($sql) || empty($sql)) {
+ // fallback to the given $index_name, without transformation
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $qry = sprintf($query, $db->quote(strtolower($index_name), 'text'));
+ } else {
+ $qry = sprintf($query, $db->quote($index_name, 'text'));
+ }
+ $sql = $db->queryOne($qry, 'text');
+ }
+ if (PEAR::isError($sql)) {
+ return $sql;
+ }
+ if (!$sql) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table index', __FUNCTION__);
+ }
+
+ $sql = strtolower($sql);
+ $start_pos = strpos($sql, '(');
+ $end_pos = strrpos($sql, ')');
+ $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
+ $column_names = explode(',', $column_names);
+
+ if (preg_match("/^create unique/", $sql)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table index', __FUNCTION__);
+ }
+
+ $definition = array();
+ $count = count($column_names);
+ for ($i=0; $i<$count; ++$i) {
+ $column_name = strtok($column_names[$i], ' ');
+ $collation = strtok(' ');
+ $definition['fields'][$column_name] = array(
+ 'position' => $i+1
+ );
+ if (!empty($collation)) {
+ $definition['fields'][$column_name]['sorting'] =
+ ($collation=='ASC' ? 'ascending' : 'descending');
+ }
+ }
+
+ if (empty($definition['fields'])) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing table index', __FUNCTION__);
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTableConstraintDefinition()
+
+ /**
+ * Get the stucture of a constraint into an array
+ *
+ * @param string $table_name name of table that should be used in method
+ * @param string $constraint_name name of constraint that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTableConstraintDefinition($table_name, $constraint_name)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ list($schema, $table) = $this->splitTableSchema($table_name);
+
+ $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
+ } else {
+ $query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
+ }
+ $query.= ' AND sql NOT NULL ORDER BY name';
+ $constraint_name_mdb2 = $db->getIndexName($constraint_name);
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $qry = sprintf($query, $db->quote(strtolower($constraint_name_mdb2), 'text'));
+ } else {
+ $qry = sprintf($query, $db->quote($constraint_name_mdb2, 'text'));
+ }
+ $sql = $db->queryOne($qry, 'text');
+ if (PEAR::isError($sql) || empty($sql)) {
+ // fallback to the given $index_name, without transformation
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $qry = sprintf($query, $db->quote(strtolower($constraint_name), 'text'));
+ } else {
+ $qry = sprintf($query, $db->quote($constraint_name, 'text'));
+ }
+ $sql = $db->queryOne($qry, 'text');
+ }
+ if (PEAR::isError($sql)) {
+ return $sql;
+ }
+ //default values, eventually overridden
+ $definition = array(
+ 'primary' => false,
+ 'unique' => false,
+ 'foreign' => false,
+ 'check' => false,
+ 'fields' => array(),
+ 'references' => array(
+ 'table' => '',
+ 'fields' => array(),
+ ),
+ 'onupdate' => '',
+ 'ondelete' => '',
+ 'match' => '',
+ 'deferrable' => false,
+ 'initiallydeferred' => false,
+ );
+ if (!$sql) {
+ $query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
+ } else {
+ $query.= 'name='.$db->quote($table, 'text');
+ }
+ $query.= " AND sql NOT NULL ORDER BY name";
+ $sql = $db->queryOne($query, 'text');
+ if (PEAR::isError($sql)) {
+ return $sql;
+ }
+ if ($constraint_name == 'primary') {
+ // search in table definition for PRIMARY KEYs
+ if (preg_match("/\bPRIMARY\s+KEY\b\s*\(([^)]+)/i", $sql, $tmp)) {
+ $definition['primary'] = true;
+ $definition['fields'] = array();
+ $column_names = explode(',', $tmp[1]);
+ $colpos = 1;
+ foreach ($column_names as $column_name) {
+ $definition['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ return $definition;
+ }
+ if (preg_match("/\"([^\"]+)\"[^\,\"]+\bPRIMARY\s+KEY\b[^\,\)]*/i", $sql, $tmp)) {
+ $definition['primary'] = true;
+ $definition['fields'] = array();
+ $column_names = explode(',', $tmp[1]);
+ $colpos = 1;
+ foreach ($column_names as $column_name) {
+ $definition['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ return $definition;
+ }
+ } else {
+ // search in table definition for FOREIGN KEYs
+ $pattern = "/\bCONSTRAINT\b\s+%s\s+
+ \bFOREIGN\s+KEY\b\s*\(([^\)]+)\)\s*
+ \bREFERENCES\b\s+([^\s]+)\s*\(([^\)]+)\)\s*
+ (?:\bMATCH\s*([^\s]+))?\s*
+ (?:\bON\s+UPDATE\s+([^\s,\)]+))?\s*
+ (?:\bON\s+DELETE\s+([^\s,\)]+))?\s*
+ /imsx";
+ $found_fk = false;
+ if (preg_match(sprintf($pattern, $constraint_name_mdb2), $sql, $tmp)) {
+ $found_fk = true;
+ } elseif (preg_match(sprintf($pattern, $constraint_name), $sql, $tmp)) {
+ $found_fk = true;
+ }
+ if ($found_fk) {
+ $definition['foreign'] = true;
+ $definition['match'] = 'SIMPLE';
+ $definition['onupdate'] = 'NO ACTION';
+ $definition['ondelete'] = 'NO ACTION';
+ $definition['references']['table'] = $tmp[2];
+ $column_names = explode(',', $tmp[1]);
+ $colpos = 1;
+ foreach ($column_names as $column_name) {
+ $definition['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ $referenced_cols = explode(',', $tmp[3]);
+ $colpos = 1;
+ foreach ($referenced_cols as $column_name) {
+ $definition['references']['fields'][trim($column_name)] = array(
+ 'position' => $colpos++
+ );
+ }
+ if (isset($tmp[4])) {
+ $definition['match'] = $tmp[4];
+ }
+ if (isset($tmp[5])) {
+ $definition['onupdate'] = $tmp[5];
+ }
+ if (isset($tmp[6])) {
+ $definition['ondelete'] = $tmp[6];
+ }
+ return $definition;
+ }
+ }
+ $sql = false;
+ }
+ if (!$sql) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__);
+ }
+
+ $sql = strtolower($sql);
+ $start_pos = strpos($sql, '(');
+ $end_pos = strrpos($sql, ')');
+ $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
+ $column_names = explode(',', $column_names);
+
+ if (!preg_match("/^create unique/", $sql)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__);
+ }
+
+ $definition['unique'] = true;
+ $count = count($column_names);
+ for ($i=0; $i<$count; ++$i) {
+ $column_name = strtok($column_names[$i]," ");
+ $collation = strtok(" ");
+ $definition['fields'][$column_name] = array(
+ 'position' => $i+1
+ );
+ if (!empty($collation)) {
+ $definition['fields'][$column_name]['sorting'] =
+ ($collation=='ASC' ? 'ascending' : 'descending');
+ }
+ }
+
+ if (empty($definition['fields'])) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__);
+ }
+ return $definition;
+ }
+
+ // }}}
+ // {{{ getTriggerDefinition()
+
+ /**
+ * Get the structure of a trigger into an array
+ *
+ * EXPERIMENTAL
+ *
+ * WARNING: this function is experimental and may change the returned value
+ * at any time until labelled as non-experimental
+ *
+ * @param string $trigger name of trigger that should be used in method
+ * @return mixed data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function getTriggerDefinition($trigger)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $query = "SELECT name as trigger_name,
+ tbl_name AS table_name,
+ sql AS trigger_body,
+ NULL AS trigger_type,
+ NULL AS trigger_event,
+ NULL AS trigger_comment,
+ 1 AS trigger_enabled
+ FROM sqlite_master
+ WHERE type='trigger'";
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $query.= ' AND LOWER(name)='.$db->quote(strtolower($trigger), 'text');
+ } else {
+ $query.= ' AND name='.$db->quote($trigger, 'text');
+ }
+ $types = array(
+ 'trigger_name' => 'text',
+ 'table_name' => 'text',
+ 'trigger_body' => 'text',
+ 'trigger_type' => 'text',
+ 'trigger_event' => 'text',
+ 'trigger_comment' => 'text',
+ 'trigger_enabled' => 'boolean',
+ );
+ $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($def)) {
+ return $def;
+ }
+ if (empty($def)) {
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'it was not specified an existing trigger', __FUNCTION__);
+ }
+ if (preg_match("/^create\s+(?:temp|temporary)?trigger\s+(?:if\s+not\s+exists\s+)?.*(before|after)?\s+(insert|update|delete)/Uims", $def['trigger_body'], $tmp)) {
+ $def['trigger_type'] = strtoupper($tmp[1]);
+ $def['trigger_event'] = strtoupper($tmp[2]);
+ }
+ return $def;
+ }
+
+ // }}}
+ // {{{ tableInfo()
+
+ /**
+ * Returns information about a table
+ *
+ * @param string $result a string containing the name of a table
+ * @param int $mode a valid tableInfo mode
+ *
+ * @return array an associative array with the information requested.
+ * A MDB2_Error object on failure.
+ *
+ * @see MDB2_Driver_Common::tableInfo()
+ * @since Method available since Release 1.7.0
+ */
+ function tableInfo($result, $mode = null)
+ {
+ if (is_string($result)) {
+ return parent::tableInfo($result, $mode);
+ }
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
+ 'This DBMS can not obtain tableInfo from result sets', __FUNCTION__);
+ }
+}
+
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/mysql.php b/3rdparty/MDB2/Driver/mysql.php index 2cec1e9c033..eda3310deeb 100644 --- a/3rdparty/MDB2/Driver/mysql.php +++ b/3rdparty/MDB2/Driver/mysql.php @@ -1,1700 +1,1710 @@ -<?php -// vim: set et ts=4 sw=4 fdm=marker: -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: mysql.php,v 1.214 2008/11/16 21:45:08 quipo Exp $ -// - -/** - * MDB2 MySQL driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_mysql extends MDB2_Driver_Common -{ - // {{{ properties - - var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => '\\', 'escape_pattern' => '\\'); - - var $identifier_quoting = array('start' => '`', 'end' => '`', 'escape' => '`'); - - var $sql_comments = array( - array('start' => '-- ', 'end' => "\n", 'escape' => false), - array('start' => '#', 'end' => "\n", 'escape' => false), - array('start' => '/*', 'end' => '*/', 'escape' => false), - ); - - var $server_capabilities_checked = false; - - var $start_transaction = false; - - var $varchar_max_length = 255; - - // }}} - // {{{ constructor - - /** - * Constructor - */ - function __construct() - { - parent::__construct(); - - $this->phptype = 'mysql'; - $this->dbsyntax = 'mysql'; - - $this->supported['sequences'] = 'emulated'; - $this->supported['indexes'] = true; - $this->supported['affected_rows'] = true; - $this->supported['transactions'] = false; - $this->supported['savepoints'] = false; - $this->supported['summary_functions'] = true; - $this->supported['order_by_text'] = true; - $this->supported['current_id'] = 'emulated'; - $this->supported['limit_queries'] = true; - $this->supported['LOBs'] = true; - $this->supported['replace'] = true; - $this->supported['sub_selects'] = 'emulated'; - $this->supported['triggers'] = false; - $this->supported['auto_increment'] = true; - $this->supported['primary_key'] = true; - $this->supported['result_introspection'] = true; - $this->supported['prepared_statements'] = 'emulated'; - $this->supported['identifier_quoting'] = true; - $this->supported['pattern_escaping'] = true; - $this->supported['new_link'] = true; - - $this->options['DBA_username'] = false; - $this->options['DBA_password'] = false; - $this->options['default_table_type'] = ''; - $this->options['max_identifiers_length'] = 64; - - $this->_reCheckSupportedOptions(); - } - - // }}} - // {{{ _reCheckSupportedOptions() - - /** - * If the user changes certain options, other capabilities may depend - * on the new settings, so we need to check them (again). - * - * @access private - */ - function _reCheckSupportedOptions() - { - $this->supported['transactions'] = $this->options['use_transactions']; - $this->supported['savepoints'] = $this->options['use_transactions']; - if ($this->options['default_table_type']) { - switch (strtoupper($this->options['default_table_type'])) { - case 'BLACKHOLE': - case 'MEMORY': - case 'ARCHIVE': - case 'CSV': - case 'HEAP': - case 'ISAM': - case 'MERGE': - case 'MRG_ISAM': - case 'ISAM': - case 'MRG_MYISAM': - case 'MYISAM': - $this->supported['savepoints'] = false; - $this->supported['transactions'] = false; - $this->warnings[] = $this->options['default_table_type'] . - ' is not a supported default table type'; - break; - } - } - } - - // }}} - // {{{ function setOption($option, $value) - - /** - * set the option for the db class - * - * @param string option name - * @param mixed value for the option - * - * @return mixed MDB2_OK or MDB2 Error Object - * - * @access public - */ - function setOption($option, $value) - { - $res = parent::setOption($option, $value); - $this->_reCheckSupportedOptions(); - } - - // }}} - // {{{ errorInfo() - - /** - * This method is used to collect information about an error - * - * @param integer $error - * @return array - * @access public - */ - function errorInfo($error = null) - { - if ($this->connection) { - $native_code = @mysql_errno($this->connection); - $native_msg = @mysql_error($this->connection); - } else { - $native_code = @mysql_errno(); - $native_msg = @mysql_error(); - } - if (is_null($error)) { - static $ecode_map; - if (empty($ecode_map)) { - $ecode_map = array( - 1000 => MDB2_ERROR_INVALID, //hashchk - 1001 => MDB2_ERROR_INVALID, //isamchk - 1004 => MDB2_ERROR_CANNOT_CREATE, - 1005 => MDB2_ERROR_CANNOT_CREATE, - 1006 => MDB2_ERROR_CANNOT_CREATE, - 1007 => MDB2_ERROR_ALREADY_EXISTS, - 1008 => MDB2_ERROR_CANNOT_DROP, - 1009 => MDB2_ERROR_CANNOT_DROP, - 1010 => MDB2_ERROR_CANNOT_DROP, - 1011 => MDB2_ERROR_CANNOT_DELETE, - 1022 => MDB2_ERROR_ALREADY_EXISTS, - 1029 => MDB2_ERROR_NOT_FOUND, - 1032 => MDB2_ERROR_NOT_FOUND, - 1044 => MDB2_ERROR_ACCESS_VIOLATION, - 1045 => MDB2_ERROR_ACCESS_VIOLATION, - 1046 => MDB2_ERROR_NODBSELECTED, - 1048 => MDB2_ERROR_CONSTRAINT, - 1049 => MDB2_ERROR_NOSUCHDB, - 1050 => MDB2_ERROR_ALREADY_EXISTS, - 1051 => MDB2_ERROR_NOSUCHTABLE, - 1054 => MDB2_ERROR_NOSUCHFIELD, - 1060 => MDB2_ERROR_ALREADY_EXISTS, - 1061 => MDB2_ERROR_ALREADY_EXISTS, - 1062 => MDB2_ERROR_ALREADY_EXISTS, - 1064 => MDB2_ERROR_SYNTAX, - 1067 => MDB2_ERROR_INVALID, - 1072 => MDB2_ERROR_NOT_FOUND, - 1086 => MDB2_ERROR_ALREADY_EXISTS, - 1091 => MDB2_ERROR_NOT_FOUND, - 1100 => MDB2_ERROR_NOT_LOCKED, - 1109 => MDB2_ERROR_NOT_FOUND, - 1125 => MDB2_ERROR_ALREADY_EXISTS, - 1136 => MDB2_ERROR_VALUE_COUNT_ON_ROW, - 1138 => MDB2_ERROR_INVALID, - 1142 => MDB2_ERROR_ACCESS_VIOLATION, - 1143 => MDB2_ERROR_ACCESS_VIOLATION, - 1146 => MDB2_ERROR_NOSUCHTABLE, - 1149 => MDB2_ERROR_SYNTAX, - 1169 => MDB2_ERROR_CONSTRAINT, - 1176 => MDB2_ERROR_NOT_FOUND, - 1177 => MDB2_ERROR_NOSUCHTABLE, - 1213 => MDB2_ERROR_DEADLOCK, - 1216 => MDB2_ERROR_CONSTRAINT, - 1217 => MDB2_ERROR_CONSTRAINT, - 1227 => MDB2_ERROR_ACCESS_VIOLATION, - 1235 => MDB2_ERROR_CANNOT_CREATE, - 1299 => MDB2_ERROR_INVALID_DATE, - 1300 => MDB2_ERROR_INVALID, - 1304 => MDB2_ERROR_ALREADY_EXISTS, - 1305 => MDB2_ERROR_NOT_FOUND, - 1306 => MDB2_ERROR_CANNOT_DROP, - 1307 => MDB2_ERROR_CANNOT_CREATE, - 1334 => MDB2_ERROR_CANNOT_ALTER, - 1339 => MDB2_ERROR_NOT_FOUND, - 1356 => MDB2_ERROR_INVALID, - 1359 => MDB2_ERROR_ALREADY_EXISTS, - 1360 => MDB2_ERROR_NOT_FOUND, - 1363 => MDB2_ERROR_NOT_FOUND, - 1365 => MDB2_ERROR_DIVZERO, - 1451 => MDB2_ERROR_CONSTRAINT, - 1452 => MDB2_ERROR_CONSTRAINT, - 1542 => MDB2_ERROR_CANNOT_DROP, - 1546 => MDB2_ERROR_CONSTRAINT, - 1582 => MDB2_ERROR_CONSTRAINT, - 2003 => MDB2_ERROR_CONNECT_FAILED, - 2019 => MDB2_ERROR_INVALID, - ); - } - if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) { - $ecode_map[1022] = MDB2_ERROR_CONSTRAINT; - $ecode_map[1048] = MDB2_ERROR_CONSTRAINT_NOT_NULL; - $ecode_map[1062] = MDB2_ERROR_CONSTRAINT; - } else { - // Doing this in case mode changes during runtime. - $ecode_map[1022] = MDB2_ERROR_ALREADY_EXISTS; - $ecode_map[1048] = MDB2_ERROR_CONSTRAINT; - $ecode_map[1062] = MDB2_ERROR_ALREADY_EXISTS; - } - if (isset($ecode_map[$native_code])) { - $error = $ecode_map[$native_code]; - } - } - return array($error, $native_code, $native_msg); - } - - // }}} - // {{{ escape() - - /** - * Quotes a string so it can be safely used in a query. It will quote - * the text so it can safely be used within a query. - * - * @param string the input string to quote - * @param bool escape wildcards - * - * @return string quoted string - * - * @access public - */ - function escape($text, $escape_wildcards = false) - { - if ($escape_wildcards) { - $text = $this->escapePattern($text); - } - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - $text = @mysql_real_escape_string($text, $connection); - return $text; - } - - // }}} - // {{{ beginTransaction() - - /** - * Start a transaction or set a savepoint. - * - * @param string name of a savepoint to set - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function beginTransaction($savepoint = null) - { - $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - $this->_getServerCapabilities(); - if (!is_null($savepoint)) { - if (!$this->supports('savepoints')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'savepoint cannot be released when changes are auto committed', __FUNCTION__); - } - $query = 'SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } elseif ($this->in_transaction) { - return MDB2_OK; //nothing to do - } - if (!$this->destructor_registered && $this->opened_persistent) { - $this->destructor_registered = true; - register_shutdown_function('MDB2_closeOpenTransactions'); - } - $query = $this->start_transaction ? 'START TRANSACTION' : 'SET AUTOCOMMIT = 0'; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = true; - return MDB2_OK; - } - - // }}} - // {{{ commit() - - /** - * Commit the database changes done during a transaction that is in - * progress or release a savepoint. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after committing the pending changes. - * - * @param string name of a savepoint to release - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function commit($savepoint = null) - { - $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - if (!$this->supports('savepoints')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } - $server_info = $this->getServerVersion(); - if (version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { - return MDB2_OK; - } - $query = 'RELEASE SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } - - if (!$this->supports('transactions')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'transactions are not supported', __FUNCTION__); - } - - $result =& $this->_doQuery('COMMIT', true); - if (PEAR::isError($result)) { - return $result; - } - if (!$this->start_transaction) { - $query = 'SET AUTOCOMMIT = 1'; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ rollback() - - /** - * Cancel any database changes done during a transaction or since a specific - * savepoint that is in progress. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after canceling the pending changes. - * - * @param string name of a savepoint to rollback to - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function rollback($savepoint = null) - { - $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'rollback cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - if (!$this->supports('savepoints')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } - $query = 'ROLLBACK TO SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } - - $query = 'ROLLBACK'; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - if (!$this->start_transaction) { - $query = 'SET AUTOCOMMIT = 1'; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ function setTransactionIsolation() - - /** - * Set the transacton isolation level. - * - * @param string standard isolation level - * READ UNCOMMITTED (allows dirty reads) - * READ COMMITTED (prevents dirty reads) - * REPEATABLE READ (prevents nonrepeatable reads) - * SERIALIZABLE (prevents phantom reads) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - static function setTransactionIsolation($isolation, $options = array()) - { - $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); - if (!$this->supports('transactions')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'transactions are not supported', __FUNCTION__); - } - switch ($isolation) { - case 'READ UNCOMMITTED': - case 'READ COMMITTED': - case 'REPEATABLE READ': - case 'SERIALIZABLE': - break; - default: - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'isolation level is not supported: '.$isolation, __FUNCTION__); - } - - $query = "SET SESSION TRANSACTION ISOLATION LEVEL $isolation"; - return $this->_doQuery($query, true); - } - - // }}} - // {{{ _doConnect() - - /** - * do the grunt work of the connect - * - * @return connection on success or MDB2 Error Object on failure - * @access protected - */ - function _doConnect($username, $password, $persistent = false) - { - if (!PEAR::loadExtension($this->phptype)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); - } - - $params = array(); - if ($this->dsn['protocol'] && $this->dsn['protocol'] == 'unix') { - $params[0] = ':' . $this->dsn['socket']; - } else { - $params[0] = $this->dsn['hostspec'] ? $this->dsn['hostspec'] - : 'localhost'; - if ($this->dsn['port']) { - $params[0].= ':' . $this->dsn['port']; - } - } - $params[] = $username ? $username : null; - $params[] = $password ? $password : null; - if (!$persistent) { - if ($this->_isNewLinkSet()) { - $params[] = true; - } else { - $params[] = false; - } - } - if (version_compare(phpversion(), '4.3.0', '>=')) { - $params[] = isset($this->dsn['client_flags']) - ? $this->dsn['client_flags'] : null; - } - $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; - - $connection = @call_user_func_array($connect_function, $params); - if (!$connection) { - if (($err = @mysql_error()) != '') { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, - $err, __FUNCTION__); - } else { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, - 'unable to establish a connection', __FUNCTION__); - } - } - - if (!empty($this->dsn['charset'])) { - $result = $this->setCharset($this->dsn['charset'], $connection); - if (PEAR::isError($result)) { - $this->disconnect(false); - return $result; - } - } - - return $connection; - } - - // }}} - // {{{ connect() - - /** - * Connect to the database - * - * @return MDB2_OK on success, MDB2 Error Object on failure - * @access public - */ - function connect() - { - if (is_resource($this->connection)) { - //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 - if (MDB2::areEquals($this->connected_dsn, $this->dsn) - && $this->opened_persistent == $this->options['persistent'] - ) { - return MDB2_OK; - } - $this->disconnect(false); - } - - $connection = $this->_doConnect( - $this->dsn['username'], - $this->dsn['password'], - $this->options['persistent'] - ); - if (PEAR::isError($connection)) { - return $connection; - } - - $this->connection = $connection; - $this->connected_dsn = $this->dsn; - $this->connected_database_name = ''; - $this->opened_persistent = $this->options['persistent']; - $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; - - if ($this->database_name) { - if ($this->database_name != $this->connected_database_name) { - if (!@mysql_select_db($this->database_name, $connection)) { - $err = $this->raiseError(null, null, null, - 'Could not select the database: '.$this->database_name, __FUNCTION__); - return $err; - } - $this->connected_database_name = $this->database_name; - } - } - - $this->_getServerCapabilities(); - - return MDB2_OK; - } - - // }}} - // {{{ setCharset() - - /** - * Set the charset on the current connection - * - * @param string charset (or array(charset, collation)) - * @param resource connection handle - * - * @return true on success, MDB2 Error Object on failure - */ - function setCharset($charset, $connection = null) - { - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - $collation = null; - if (is_array($charset) && 2 == count($charset)) { - $collation = array_pop($charset); - $charset = array_pop($charset); - } - $client_info = mysql_get_client_info(); - if (function_exists('mysql_set_charset') && version_compare($client_info, '5.0.6')) { - if (!$result = mysql_set_charset($charset, $connection)) { - $err =& $this->raiseError(null, null, null, - 'Could not set client character set', __FUNCTION__); - return $err; - } - return $result; - } - $query = "SET NAMES '".mysql_real_escape_string($charset, $connection)."'"; - if (!is_null($collation)) { - $query .= " COLLATE '".mysqli_real_escape_string($connection, $collation)."'"; - } - return $this->_doQuery($query, true, $connection); - } - - // }}} - // {{{ databaseExists() - - /** - * check if given database name is exists? - * - * @param string $name name of the database that should be checked - * - * @return mixed true/false on success, a MDB2 error on failure - * @access public - */ - function databaseExists($name) - { - $connection = $this->_doConnect($this->dsn['username'], - $this->dsn['password'], - $this->options['persistent']); - if (PEAR::isError($connection)) { - return $connection; - } - - $result = @mysql_select_db($name, $connection); - @mysql_close($connection); - - return $result; - } - - // }}} - // {{{ disconnect() - - /** - * Log out and disconnect from the database. - * - * @param boolean $force if the disconnect should be forced even if the - * connection is opened persistently - * @return mixed true on success, false if not connected and error - * object on error - * @access public - */ - function disconnect($force = true) - { - if (is_resource($this->connection)) { - if ($this->in_transaction) { - $dsn = $this->dsn; - $database_name = $this->database_name; - $persistent = $this->options['persistent']; - $this->dsn = $this->connected_dsn; - $this->database_name = $this->connected_database_name; - $this->options['persistent'] = $this->opened_persistent; - $this->rollback(); - $this->dsn = $dsn; - $this->database_name = $database_name; - $this->options['persistent'] = $persistent; - } - - if (!$this->opened_persistent || $force) { - $ok = @mysql_close($this->connection); - if (!$ok) { - return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED, - null, null, null, __FUNCTION__); - } - } - } else { - return false; - } - return parent::disconnect($force); - } - - // }}} - // {{{ standaloneQuery() - - /** - * execute a query as DBA - * - * @param string $query the SQL query - * @param mixed $types array that contains the types of the columns in - * the result set - * @param boolean $is_manip if the query is a manipulation query - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &standaloneQuery($query, $types = null, $is_manip = false) - { - $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username']; - $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password']; - $connection = $this->_doConnect($user, $pass, $this->options['persistent']); - if (PEAR::isError($connection)) { - return $connection; - } - - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); - - $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name); - if (!PEAR::isError($result)) { - $result = $this->_affectedRows($connection, $result); - } - - @mysql_close($connection); - return $result; - } - - // }}} - // {{{ _doQuery() - - /** - * Execute a query - * @param string $query query - * @param boolean $is_manip if the query is a manipulation query - * @param resource $connection - * @param string $database_name - * @return result or error object - * @access protected - */ - function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) - { - $this->last_query = $query; - $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - if ($this->options['disable_query']) { - $result = $is_manip ? 0 : null; - return $result; - } - - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - if (is_null($database_name)) { - $database_name = $this->database_name; - } - - if ($database_name) { - if ($database_name != $this->connected_database_name) { - if (!@mysql_select_db($database_name, $connection)) { - $err = $this->raiseError(null, null, null, - 'Could not select the database: '.$database_name, __FUNCTION__); - return $err; - } - $this->connected_database_name = $database_name; - } - } - - $function = $this->options['result_buffering'] - ? 'mysql_query' : 'mysql_unbuffered_query'; - $result = @$function($query, $connection); - if (!$result) { - $err =$this->raiseError(null, null, null, - 'Could not execute statement', __FUNCTION__); - return $err; - } - - $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result)); - return $result; - } - - // }}} - // {{{ _affectedRows() - - /** - * Returns the number of rows affected - * - * @param resource $result - * @param resource $connection - * @return mixed MDB2 Error Object or the number of rows affected - * @access private - */ - function _affectedRows($connection, $result = null) - { - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - return @mysql_affected_rows($connection); - } - - // }}} - // {{{ _modifyQuery() - - /** - * Changes a query string for various DBMS specific reasons - * - * @param string $query query to modify - * @param boolean $is_manip if it is a DML query - * @param integer $limit limit the number of rows - * @param integer $offset start reading from given offset - * @return string modified query - * @access protected - */ - function _modifyQuery($query, $is_manip, $limit, $offset) - { - if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) { - // "DELETE FROM table" gives 0 affected rows in MySQL. - // This little hack lets you know how many rows were deleted. - if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { - $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', - 'DELETE FROM \1 WHERE 1=1', $query); - } - } - if ($limit > 0 - && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) - ) { - $query = rtrim($query); - if (substr($query, -1) == ';') { - $query = substr($query, 0, -1); - } - - // LIMIT doesn't always come last in the query - // @see http://dev.mysql.com/doc/refman/5.0/en/select.html - $after = ''; - if (preg_match('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', $query, $matches)) { - $after = $matches[0]; - $query = preg_replace('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', '', $query); - } elseif (preg_match('/(\s+FOR\s+UPDATE\s*)$/i', $query, $matches)) { - $after = $matches[0]; - $query = preg_replace('/(\s+FOR\s+UPDATE\s*)$/im', '', $query); - } elseif (preg_match('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', $query, $matches)) { - $after = $matches[0]; - $query = preg_replace('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', '', $query); - } - - if ($is_manip) { - return $query . " LIMIT $limit" . $after; - } else { - return $query . " LIMIT $offset, $limit" . $after; - } - } - return $query; - } - - // }}} - // {{{ getServerVersion() - - /** - * return version information about the server - * - * @param bool $native determines if the raw version string should be returned - * @return mixed array/string with version information or MDB2 error object - * @access public - */ - function getServerVersion($native = false) - { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - if ($this->connected_server_info) { - $server_info = $this->connected_server_info; - } else { - $server_info = @mysql_get_server_info($connection); - } - if (!$server_info) { - return $this->raiseError(null, null, null, - 'Could not get server information', __FUNCTION__); - } - // cache server_info - $this->connected_server_info = $server_info; - if (!$native) { - $tmp = explode('.', $server_info, 3); - if (isset($tmp[2]) && strpos($tmp[2], '-')) { - $tmp2 = explode('-', @$tmp[2], 2); - } else { - $tmp2[0] = isset($tmp[2]) ? $tmp[2] : null; - $tmp2[1] = null; - } - $server_info = array( - 'major' => isset($tmp[0]) ? $tmp[0] : null, - 'minor' => isset($tmp[1]) ? $tmp[1] : null, - 'patch' => $tmp2[0], - 'extra' => $tmp2[1], - 'native' => $server_info, - ); - } - return $server_info; - } - - // }}} - // {{{ _getServerCapabilities() - - /** - * Fetch some information about the server capabilities - * (transactions, subselects, prepared statements, etc). - * - * @access private - */ - function _getServerCapabilities() - { - if (!$this->server_capabilities_checked) { - $this->server_capabilities_checked = true; - - //set defaults - $this->supported['sub_selects'] = 'emulated'; - $this->supported['prepared_statements'] = 'emulated'; - $this->supported['triggers'] = false; - $this->start_transaction = false; - $this->varchar_max_length = 255; - - $server_info = $this->getServerVersion(); - if (is_array($server_info)) { - $server_version = $server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch']; - - if (!version_compare($server_version, '4.1.0', '<')) { - $this->supported['sub_selects'] = true; - $this->supported['prepared_statements'] = true; - } - - // SAVEPOINTs were introduced in MySQL 4.0.14 and 4.1.1 (InnoDB) - if (version_compare($server_version, '4.1.0', '>=')) { - if (version_compare($server_version, '4.1.1', '<')) { - $this->supported['savepoints'] = false; - } - } elseif (version_compare($server_version, '4.0.14', '<')) { - $this->supported['savepoints'] = false; - } - - if (!version_compare($server_version, '4.0.11', '<')) { - $this->start_transaction = true; - } - - if (!version_compare($server_version, '5.0.3', '<')) { - $this->varchar_max_length = 65532; - } - - if (!version_compare($server_version, '5.0.2', '<')) { - $this->supported['triggers'] = true; - } - } - } - } - - // }}} - // {{{ function _skipUserDefinedVariable($query, $position) - - /** - * Utility method, used by prepare() to avoid misinterpreting MySQL user - * defined variables (SELECT @x:=5) for placeholders. - * Check if the placeholder is a false positive, i.e. if it is an user defined - * variable instead. If so, skip it and advance the position, otherwise - * return the current position, which is valid - * - * @param string $query - * @param integer $position current string cursor position - * @return integer $new_position - * @access protected - */ - function _skipUserDefinedVariable($query, $position) - { - $found = strpos(strrev(substr($query, 0, $position)), '@'); - if ($found === false) { - return $position; - } - $pos = strlen($query) - strlen(substr($query, $position)) - $found - 1; - $substring = substr($query, $pos, $position - $pos + 2); - if (preg_match('/^@\w+\s*:=$/', $substring)) { - return $position + 1; //found an user defined variable: skip it - } - return $position; - } - - // }}} - // {{{ prepare() - - /** - * Prepares a query for multiple execution with execute(). - * With some database backends, this is emulated. - * prepare() requires a generic query as string like - * 'INSERT INTO numbers VALUES(?,?)' or - * 'INSERT INTO numbers VALUES(:foo,:bar)'. - * The ? and :name and are placeholders which can be set using - * bindParam() and the query can be sent off using the execute() method. - * The allowed format for :name can be set with the 'bindname_format' option. - * - * @param string $query the query to prepare - * @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 or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders - * @return mixed resource handle for the prepared query on success, a MDB2 - * error on failure - * @access public - * @see bindParam, execute - */ - function &prepare($query, $types = null, $result_types = null, $lobs = array()) - { - if ($this->options['emulate_prepared'] - || $this->supported['prepared_statements'] !== true - ) { - $obj =& parent::prepare($query, $types, $result_types, $lobs); - return $obj; - } - $is_manip = ($result_types === MDB2_PREPARE_MANIP); - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); - $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - $placeholder_type_guess = $placeholder_type = null; - $question = '?'; - $colon = ':'; - $positions = array(); - $position = 0; - while ($position < strlen($query)) { - $q_position = strpos($query, $question, $position); - $c_position = strpos($query, $colon, $position); - if ($q_position && $c_position) { - $p_position = min($q_position, $c_position); - } elseif ($q_position) { - $p_position = $q_position; - } elseif ($c_position) { - $p_position = $c_position; - } else { - break; - } - if (is_null($placeholder_type)) { - $placeholder_type_guess = $query[$p_position]; - } - - $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); - if (PEAR::isError($new_pos)) { - return $new_pos; - } - if ($new_pos != $position) { - $position = $new_pos; - continue; //evaluate again starting from the new position - } - - //make sure this is not part of an user defined variable - $new_pos = $this->_skipUserDefinedVariable($query, $position); - if ($new_pos != $position) { - $position = $new_pos; - continue; //evaluate again starting from the new position - } - - if ($query[$position] == $placeholder_type_guess) { - if (is_null($placeholder_type)) { - $placeholder_type = $query[$p_position]; - $question = $colon = $placeholder_type; - } - if ($placeholder_type == ':') { - $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s'; - $parameter = preg_replace($regexp, '\\1', $query); - if ($parameter === '') { - $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'named parameter name must match "bindname_format" option', __FUNCTION__); - return $err; - } - $positions[$p_position] = $parameter; - $query = substr_replace($query, '?', $position, strlen($parameter)+1); - } else { - $positions[$p_position] = count($positions); - } - $position = $p_position + 1; - } else { - $position = $p_position; - } - } - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - static $prep_statement_counter = 1; - $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand())); - $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']); - $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text'); - $statement =& $this->_doQuery($query, true, $connection); - if (PEAR::isError($statement)) { - return $statement; - } - - $class_name = 'MDB2_Statement_'.$this->phptype; - $obj = new $class_name($this, $statement_name, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); - $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj)); - return $obj; - } - - // }}} - // {{{ replace() - - /** - * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT - * query, except that if there is already a row in the table with the same - * key field values, the old row is deleted before the new row is inserted. - * - * The REPLACE type of query does not make part of the SQL standards. Since - * practically only MySQL implements it natively, this type of query is - * emulated through this method for other DBMS using standard types of - * queries inside a transaction to assure the atomicity of the operation. - * - * @access public - * - * @param string $table name of the table on which the REPLACE query will - * be executed. - * @param array $fields associative array that describes the fields and the - * values that will be inserted or updated in the specified table. The - * indexes of the array are the names of all the fields of the table. The - * values of the array are also associative arrays that describe the - * values and other properties of the table fields. - * - * Here follows a list of field properties that need to be specified: - * - * value: - * Value to be assigned to the specified field. This value may be - * of specified in database independent type format as this - * function can perform the necessary datatype conversions. - * - * Default: - * this property is required unless the Null property - * is set to 1. - * - * type - * Name of the type of the field. Currently, all types Metabase - * are supported except for clob and blob. - * - * Default: no type conversion - * - * null - * Boolean property that indicates that the value for this field - * should be set to null. - * - * The default value for fields missing in INSERT queries may be - * specified the definition of a table. Often, the default value - * is already null, but since the REPLACE may be emulated using - * an UPDATE query, make sure that all fields of the table are - * listed in this function argument array. - * - * Default: 0 - * - * key - * Boolean property that indicates that this field should be - * handled as a primary key or at least as part of the compound - * unique index of the table that will determine the row that will - * updated if it exists or inserted a new row otherwise. - * - * This function will fail if no key field is specified or if the - * value of a key field is set to null because fields that are - * part of unique index they may not be null. - * - * Default: 0 - * - * @see http://dev.mysql.com/doc/refman/5.0/en/replace.html - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function replace($table, $fields) - { - $count = count($fields); - $query = $values = ''; - $keys = $colnum = 0; - for (reset($fields); $colnum < $count; next($fields), $colnum++) { - $name = key($fields); - if ($colnum > 0) { - $query .= ','; - $values.= ','; - } - $query.= $this->quoteIdentifier($name, true); - if (isset($fields[$name]['null']) && $fields[$name]['null']) { - $value = 'NULL'; - } else { - $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null; - $value = $this->quote($fields[$name]['value'], $type); - if (PEAR::isError($value)) { - return $value; - } - } - $values.= $value; - if (isset($fields[$name]['key']) && $fields[$name]['key']) { - if ($value === 'NULL') { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'key value '.$name.' may not be NULL', __FUNCTION__); - } - $keys++; - } - } - if ($keys == 0) { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'not specified which fields are keys', __FUNCTION__); - } - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $table = $this->quoteIdentifier($table, true); - $query = "REPLACE INTO $table ($query) VALUES ($values)"; - $result =& $this->_doQuery($query, true, $connection); - if (PEAR::isError($result)) { - return $result; - } - return $this->_affectedRows($connection, $result); - } - - // }}} - // {{{ nextID() - - /** - * Returns the next free id of a sequence - * - * @param string $seq_name name of the sequence - * @param boolean $ondemand when true the sequence is - * automatic created, if it - * not exists - * - * @return mixed MDB2 Error Object or id - * @access public - */ - function nextID($seq_name, $ondemand = true) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); - $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)"; - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->expectError(MDB2_ERROR_NOSUCHTABLE); - $result =& $this->_doQuery($query, true); - $this->popExpect(); - $this->popErrorHandling(); - if (PEAR::isError($result)) { - if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { - $this->loadModule('Manager', null, true); - $result = $this->manager->createSequence($seq_name); - if (PEAR::isError($result)) { - return $this->raiseError($result, null, null, - 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__); - } else { - return $this->nextID($seq_name, false); - } - } - return $result; - } - $value = $this->lastInsertID(); - if (is_numeric($value)) { - $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value"; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; - } - } - return $value; - } - - // }}} - // {{{ lastInsertID() - - /** - * Returns the autoincrement ID if supported or $id or fetches the current - * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) - * - * @param string $table name of the table into which a new row was inserted - * @param string $field name of the field into which a new row was inserted - * @return mixed MDB2 Error Object or id - * @access public - */ - function lastInsertID($table = null, $field = null) - { - // not using mysql_insert_id() due to http://pear.php.net/bugs/bug.php?id=8051 - return $this->queryOne('SELECT LAST_INSERT_ID()', 'integer'); - } - - // }}} - // {{{ currID() - - /** - * Returns the current id of a sequence - * - * @param string $seq_name name of the sequence - * @return mixed MDB2 Error Object or id - * @access public - */ - function currID($seq_name) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); - $query = "SELECT MAX($seqcol_name) FROM $sequence_name"; - return $this->queryOne($query, 'integer'); - } -} - -/** - * MDB2 MySQL result driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Result_mysql extends MDB2_Result_Common -{ - // }}} - // {{{ fetchRow() - - /** - * Fetch a row and insert the data into an existing array. - * - * @param int $fetchmode how the array data should be indexed - * @param int $rownum number of the row where the data can be found - * @return int data array on success, a MDB2 error on failure - * @access public - */ - function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) - { - if (!is_null($rownum)) { - $seek = $this->seek($rownum); - if (PEAR::isError($seek)) { - return $seek; - } - } - if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { - $fetchmode = $this->db->fetchmode; - } - if ($fetchmode & MDB2_FETCHMODE_ASSOC) { - $row = @mysql_fetch_assoc($this->result); - if (is_array($row) - && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE - ) { - $row = array_change_key_case($row, $this->db->options['field_case']); - } - } else { - $row = @mysql_fetch_row($this->result); - } - - if (!$row) { - if ($this->result === false) { - $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - return $err; - } - $null = null; - return $null; - } - $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL; - $rtrim = false; - if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { - if (empty($this->types)) { - $mode += MDB2_PORTABILITY_RTRIM; - } else { - $rtrim = true; - } - } - if ($mode) { - $this->db->_fixResultArrayValues($row, $mode); - } - if (!empty($this->types)) { - $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim); - } - if (!empty($this->values)) { - $this->_assignBindColumns($row); - } - if ($fetchmode === MDB2_FETCHMODE_OBJECT) { - $object_class = $this->db->options['fetch_class']; - if ($object_class == 'stdClass') { - $row = (object) $row; - } else { - $row = new $object_class($row); - } - } - ++$this->rownum; - return $row; - } - - // }}} - // {{{ _getColumnNames() - - /** - * Retrieve the names of columns returned by the DBMS in a query result. - * - * @return mixed Array variable that holds the names of columns as keys - * or an MDB2 error on failure. - * Some DBMS may not return any columns when the result set - * does not contain any rows. - * @access private - */ - function _getColumnNames() - { - $columns = array(); - $numcols = $this->numCols(); - if (PEAR::isError($numcols)) { - return $numcols; - } - for ($column = 0; $column < $numcols; $column++) { - $column_name = @mysql_field_name($this->result, $column); - $columns[$column_name] = $column; - } - if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $columns = array_change_key_case($columns, $this->db->options['field_case']); - } - return $columns; - } - - // }}} - // {{{ numCols() - - /** - * Count the number of columns returned by the DBMS in a query result. - * - * @return mixed integer value with the number of columns, a MDB2 error - * on failure - * @access public - */ - function numCols() - { - $cols = @mysql_num_fields($this->result); - if (is_null($cols)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return count($this->types); - } - return $this->db->raiseError(null, null, null, - 'Could not get column count', __FUNCTION__); - } - return $cols; - } - - // }}} - // {{{ free() - - /** - * Free the internal resources associated with result. - * - * @return boolean true on success, false if result is invalid - * @access public - */ - function free() - { - if (is_resource($this->result) && $this->db->connection) { - $free = @mysql_free_result($this->result); - if ($free === false) { - return $this->db->raiseError(null, null, null, - 'Could not free result', __FUNCTION__); - } - } - $this->result = false; - return MDB2_OK; - } -} - -/** - * MDB2 MySQL buffered result driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_BufferedResult_mysql extends MDB2_Result_mysql -{ - // }}} - // {{{ seek() - - /** - * Seek to a specific row in a result set - * - * @param int $rownum number of the row where the data can be found - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function seek($rownum = 0) - { - if ($this->rownum != ($rownum - 1) && !@mysql_data_seek($this->result, $rownum)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return MDB2_OK; - } - return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, - 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__); - } - $this->rownum = $rownum - 1; - return MDB2_OK; - } - - // }}} - // {{{ 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 - */ - function valid() - { - $numrows = $this->numRows(); - if (PEAR::isError($numrows)) { - return $numrows; - } - return $this->rownum < ($numrows - 1); - } - - // }}} - // {{{ numRows() - - /** - * Returns the number of rows in a result object - * - * @return mixed MDB2 Error Object or the number of rows - * @access public - */ - function numRows() - { - $rows = @mysql_num_rows($this->result); - if (false === $rows) { - if (false === $this->result) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return 0; - } - return $this->db->raiseError(null, null, null, - 'Could not get row count', __FUNCTION__); - } - return $rows; - } -} - -/** - * MDB2 MySQL statement driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Statement_mysql extends MDB2_Statement_Common -{ - // {{{ _execute() - - /** - * Execute a prepared query statement helper method. - * - * @param mixed $result_class string which specifies which result class to use - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * - * @return mixed MDB2_Result or integer (affected rows) on success, - * a MDB2 error on failure - * @access private - */ - function &_execute($result_class = true, $result_wrap_class = false) - { - if (is_null($this->statement)) { - $result =& parent::_execute($result_class, $result_wrap_class); - return $result; - } - $this->db->last_query = $this->query; - $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values)); - if ($this->db->getOption('disable_query')) { - $result = $this->is_manip ? 0 : null; - return $result; - } - - $connection = $this->db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $query = 'EXECUTE '.$this->statement; - if (!empty($this->positions)) { - $parameters = array(); - foreach ($this->positions as $parameter) { - if (!array_key_exists($parameter, $this->values)) { - return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); - } - $value = $this->values[$parameter]; - $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; - if (is_resource($value) || $type == 'clob' || $type == 'blob' && $this->db->options['lob_allow_url_include']) { - if (!is_resource($value) && preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { - if ($match[1] == 'file://') { - $value = $match[2]; - } - $value = @fopen($value, 'r'); - $close = true; - } - if (is_resource($value)) { - $data = ''; - while (!@feof($value)) { - $data.= @fread($value, $this->db->options['lob_buffer_length']); - } - if ($close) { - @fclose($value); - } - $value = $data; - } - } - $quoted = $this->db->quote($value, $type); - if (PEAR::isError($quoted)) { - return $quoted; - } - $param_query = 'SET @'.$parameter.' = '.$quoted; - $result = $this->db->_doQuery($param_query, true, $connection); - if (PEAR::isError($result)) { - return $result; - } - } - $query.= ' USING @'.implode(', @', array_values($this->positions)); - } - - $result = $this->db->_doQuery($query, $this->is_manip, $connection); - if (PEAR::isError($result)) { - return $result; - } - - if ($this->is_manip) { - $affected_rows = $this->db->_affectedRows($connection, $result); - return $affected_rows; - } - - $result =& $this->db->_wrapResult($result, $this->result_types, - $result_class, $result_wrap_class, $this->limit, $this->offset); - $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result)); - return $result; - } - - // }}} - // {{{ free() - - /** - * Release resources allocated for the specified prepared query. - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function free() - { - if (is_null($this->positions)) { - return $this->db->raiseError(MDB2_ERROR, null, null, - 'Prepared statement has already been freed', __FUNCTION__); - } - $result = MDB2_OK; - - if (!is_null($this->statement)) { - $connection = $this->db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - $query = 'DEALLOCATE PREPARE '.$this->statement; - $result = $this->db->_doQuery($query, true, $connection); - } - - parent::free(); - return $result; - } -} -?>
\ No newline at end of file +<?php
+// vim: set et ts=4 sw=4 fdm=marker:
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: mysql.php 302867 2010-08-29 11:22:07Z quipo $
+//
+
+/**
+ * MDB2 MySQL driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_mysql extends MDB2_Driver_Common
+{
+ // {{{ properties
+
+ var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => '\\', 'escape_pattern' => '\\');
+
+ var $identifier_quoting = array('start' => '`', 'end' => '`', 'escape' => '`');
+
+ var $sql_comments = array(
+ array('start' => '-- ', 'end' => "\n", 'escape' => false),
+ array('start' => '#', 'end' => "\n", 'escape' => false),
+ array('start' => '/*', 'end' => '*/', 'escape' => false),
+ );
+
+ var $server_capabilities_checked = false;
+
+ var $start_transaction = false;
+
+ var $varchar_max_length = 255;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * Constructor
+ */
+ function __construct()
+ {
+ parent::__construct();
+
+ $this->phptype = 'mysql';
+ $this->dbsyntax = 'mysql';
+
+ $this->supported['sequences'] = 'emulated';
+ $this->supported['indexes'] = true;
+ $this->supported['affected_rows'] = true;
+ $this->supported['transactions'] = false;
+ $this->supported['savepoints'] = false;
+ $this->supported['summary_functions'] = true;
+ $this->supported['order_by_text'] = true;
+ $this->supported['current_id'] = 'emulated';
+ $this->supported['limit_queries'] = true;
+ $this->supported['LOBs'] = true;
+ $this->supported['replace'] = true;
+ $this->supported['sub_selects'] = 'emulated';
+ $this->supported['triggers'] = false;
+ $this->supported['auto_increment'] = true;
+ $this->supported['primary_key'] = true;
+ $this->supported['result_introspection'] = true;
+ $this->supported['prepared_statements'] = 'emulated';
+ $this->supported['identifier_quoting'] = true;
+ $this->supported['pattern_escaping'] = true;
+ $this->supported['new_link'] = true;
+
+ $this->options['DBA_username'] = false;
+ $this->options['DBA_password'] = false;
+ $this->options['default_table_type'] = '';
+ $this->options['max_identifiers_length'] = 64;
+
+ $this->_reCheckSupportedOptions();
+ }
+
+ // }}}
+ // {{{ _reCheckSupportedOptions()
+
+ /**
+ * If the user changes certain options, other capabilities may depend
+ * on the new settings, so we need to check them (again).
+ *
+ * @access private
+ */
+ function _reCheckSupportedOptions()
+ {
+ $this->supported['transactions'] = $this->options['use_transactions'];
+ $this->supported['savepoints'] = $this->options['use_transactions'];
+ if ($this->options['default_table_type']) {
+ switch (strtoupper($this->options['default_table_type'])) {
+ case 'BLACKHOLE':
+ case 'MEMORY':
+ case 'ARCHIVE':
+ case 'CSV':
+ case 'HEAP':
+ case 'ISAM':
+ case 'MERGE':
+ case 'MRG_ISAM':
+ case 'ISAM':
+ case 'MRG_MYISAM':
+ case 'MYISAM':
+ $this->supported['savepoints'] = false;
+ $this->supported['transactions'] = false;
+ $this->warnings[] = $this->options['default_table_type'] .
+ ' is not a supported default table type';
+ break;
+ }
+ }
+ }
+
+ // }}}
+ // {{{ function setOption($option, $value)
+
+ /**
+ * set the option for the db class
+ *
+ * @param string option name
+ * @param mixed value for the option
+ *
+ * @return mixed MDB2_OK or MDB2 Error Object
+ *
+ * @access public
+ */
+ function setOption($option, $value)
+ {
+ $res = parent::setOption($option, $value);
+ $this->_reCheckSupportedOptions();
+ }
+
+ // }}}
+ // {{{ errorInfo()
+
+ /**
+ * This method is used to collect information about an error
+ *
+ * @param integer $error
+ * @return array
+ * @access public
+ */
+ function errorInfo($error = null)
+ {
+ if ($this->connection) {
+ $native_code = @mysql_errno($this->connection);
+ $native_msg = @mysql_error($this->connection);
+ } else {
+ $native_code = @mysql_errno();
+ $native_msg = @mysql_error();
+ }
+ if (is_null($error)) {
+ static $ecode_map;
+ if (empty($ecode_map)) {
+ $ecode_map = array(
+ 1000 => MDB2_ERROR_INVALID, //hashchk
+ 1001 => MDB2_ERROR_INVALID, //isamchk
+ 1004 => MDB2_ERROR_CANNOT_CREATE,
+ 1005 => MDB2_ERROR_CANNOT_CREATE,
+ 1006 => MDB2_ERROR_CANNOT_CREATE,
+ 1007 => MDB2_ERROR_ALREADY_EXISTS,
+ 1008 => MDB2_ERROR_CANNOT_DROP,
+ 1009 => MDB2_ERROR_CANNOT_DROP,
+ 1010 => MDB2_ERROR_CANNOT_DROP,
+ 1011 => MDB2_ERROR_CANNOT_DELETE,
+ 1022 => MDB2_ERROR_ALREADY_EXISTS,
+ 1029 => MDB2_ERROR_NOT_FOUND,
+ 1032 => MDB2_ERROR_NOT_FOUND,
+ 1044 => MDB2_ERROR_ACCESS_VIOLATION,
+ 1045 => MDB2_ERROR_ACCESS_VIOLATION,
+ 1046 => MDB2_ERROR_NODBSELECTED,
+ 1048 => MDB2_ERROR_CONSTRAINT,
+ 1049 => MDB2_ERROR_NOSUCHDB,
+ 1050 => MDB2_ERROR_ALREADY_EXISTS,
+ 1051 => MDB2_ERROR_NOSUCHTABLE,
+ 1054 => MDB2_ERROR_NOSUCHFIELD,
+ 1060 => MDB2_ERROR_ALREADY_EXISTS,
+ 1061 => MDB2_ERROR_ALREADY_EXISTS,
+ 1062 => MDB2_ERROR_ALREADY_EXISTS,
+ 1064 => MDB2_ERROR_SYNTAX,
+ 1067 => MDB2_ERROR_INVALID,
+ 1072 => MDB2_ERROR_NOT_FOUND,
+ 1086 => MDB2_ERROR_ALREADY_EXISTS,
+ 1091 => MDB2_ERROR_NOT_FOUND,
+ 1100 => MDB2_ERROR_NOT_LOCKED,
+ 1109 => MDB2_ERROR_NOT_FOUND,
+ 1125 => MDB2_ERROR_ALREADY_EXISTS,
+ 1136 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
+ 1138 => MDB2_ERROR_INVALID,
+ 1142 => MDB2_ERROR_ACCESS_VIOLATION,
+ 1143 => MDB2_ERROR_ACCESS_VIOLATION,
+ 1146 => MDB2_ERROR_NOSUCHTABLE,
+ 1149 => MDB2_ERROR_SYNTAX,
+ 1169 => MDB2_ERROR_CONSTRAINT,
+ 1176 => MDB2_ERROR_NOT_FOUND,
+ 1177 => MDB2_ERROR_NOSUCHTABLE,
+ 1213 => MDB2_ERROR_DEADLOCK,
+ 1216 => MDB2_ERROR_CONSTRAINT,
+ 1217 => MDB2_ERROR_CONSTRAINT,
+ 1227 => MDB2_ERROR_ACCESS_VIOLATION,
+ 1235 => MDB2_ERROR_CANNOT_CREATE,
+ 1299 => MDB2_ERROR_INVALID_DATE,
+ 1300 => MDB2_ERROR_INVALID,
+ 1304 => MDB2_ERROR_ALREADY_EXISTS,
+ 1305 => MDB2_ERROR_NOT_FOUND,
+ 1306 => MDB2_ERROR_CANNOT_DROP,
+ 1307 => MDB2_ERROR_CANNOT_CREATE,
+ 1334 => MDB2_ERROR_CANNOT_ALTER,
+ 1339 => MDB2_ERROR_NOT_FOUND,
+ 1356 => MDB2_ERROR_INVALID,
+ 1359 => MDB2_ERROR_ALREADY_EXISTS,
+ 1360 => MDB2_ERROR_NOT_FOUND,
+ 1363 => MDB2_ERROR_NOT_FOUND,
+ 1365 => MDB2_ERROR_DIVZERO,
+ 1451 => MDB2_ERROR_CONSTRAINT,
+ 1452 => MDB2_ERROR_CONSTRAINT,
+ 1542 => MDB2_ERROR_CANNOT_DROP,
+ 1546 => MDB2_ERROR_CONSTRAINT,
+ 1582 => MDB2_ERROR_CONSTRAINT,
+ 2003 => MDB2_ERROR_CONNECT_FAILED,
+ 2019 => MDB2_ERROR_INVALID,
+ );
+ }
+ if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) {
+ $ecode_map[1022] = MDB2_ERROR_CONSTRAINT;
+ $ecode_map[1048] = MDB2_ERROR_CONSTRAINT_NOT_NULL;
+ $ecode_map[1062] = MDB2_ERROR_CONSTRAINT;
+ } else {
+ // Doing this in case mode changes during runtime.
+ $ecode_map[1022] = MDB2_ERROR_ALREADY_EXISTS;
+ $ecode_map[1048] = MDB2_ERROR_CONSTRAINT;
+ $ecode_map[1062] = MDB2_ERROR_ALREADY_EXISTS;
+ }
+ if (isset($ecode_map[$native_code])) {
+ $error = $ecode_map[$native_code];
+ }
+ }
+ return array($error, $native_code, $native_msg);
+ }
+
+ // }}}
+ // {{{ escape()
+
+ /**
+ * Quotes a string so it can be safely used in a query. It will quote
+ * the text so it can safely be used within a query.
+ *
+ * @param string the input string to quote
+ * @param bool escape wildcards
+ *
+ * @return string quoted string
+ *
+ * @access public
+ */
+ function escape($text, $escape_wildcards = false)
+ {
+ if ($escape_wildcards) {
+ $text = $this->escapePattern($text);
+ }
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ $text = @mysql_real_escape_string($text, $connection);
+ return $text;
+ }
+
+ // }}}
+ // {{{ beginTransaction()
+
+ /**
+ * Start a transaction or set a savepoint.
+ *
+ * @param string name of a savepoint to set
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function beginTransaction($savepoint = null)
+ {
+ $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ $this->_getServerCapabilities();
+ if (!is_null($savepoint)) {
+ if (!$this->supports('savepoints')) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'savepoint cannot be released when changes are auto committed', __FUNCTION__);
+ }
+ $query = 'SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ } elseif ($this->in_transaction) {
+ return MDB2_OK; //nothing to do
+ }
+ if (!$this->destructor_registered && $this->opened_persistent) {
+ $this->destructor_registered = true;
+ register_shutdown_function('MDB2_closeOpenTransactions');
+ }
+ $query = $this->start_transaction ? 'START TRANSACTION' : 'SET AUTOCOMMIT = 0';
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = true;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ commit()
+
+ /**
+ * Commit the database changes done during a transaction that is in
+ * progress or release a savepoint. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after committing the pending changes.
+ *
+ * @param string name of a savepoint to release
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function commit($savepoint = null)
+ {
+ $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (!is_null($savepoint)) {
+ if (!$this->supports('savepoints')) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+ $server_info = $this->getServerVersion();
+ if (version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) {
+ return MDB2_OK;
+ }
+ $query = 'RELEASE SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ }
+
+ if (!$this->supports('transactions')) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'transactions are not supported', __FUNCTION__);
+ }
+
+ $result = $this->_doQuery('COMMIT', true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if (!$this->start_transaction) {
+ $query = 'SET AUTOCOMMIT = 1';
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ rollback()
+
+ /**
+ * Cancel any database changes done during a transaction or since a specific
+ * savepoint that is in progress. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after canceling the pending changes.
+ *
+ * @param string name of a savepoint to rollback to
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function rollback($savepoint = null)
+ {
+ $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'rollback cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (!is_null($savepoint)) {
+ if (!$this->supports('savepoints')) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+ $query = 'ROLLBACK TO SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ }
+
+ $query = 'ROLLBACK';
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if (!$this->start_transaction) {
+ $query = 'SET AUTOCOMMIT = 1';
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ function setTransactionIsolation()
+
+ /**
+ * Set the transacton isolation level.
+ *
+ * @param string standard isolation level
+ * READ UNCOMMITTED (allows dirty reads)
+ * READ COMMITTED (prevents dirty reads)
+ * REPEATABLE READ (prevents nonrepeatable reads)
+ * SERIALIZABLE (prevents phantom reads)
+ * @param array some transaction options:
+ * 'wait' => 'WAIT' | 'NO WAIT'
+ * 'rw' => 'READ WRITE' | 'READ ONLY'
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ * @since 2.1.1
+ */
+ function setTransactionIsolation($isolation, $options = array())
+ {
+ $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
+ if (!$this->supports('transactions')) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'transactions are not supported', __FUNCTION__);
+ }
+ switch ($isolation) {
+ case 'READ UNCOMMITTED':
+ case 'READ COMMITTED':
+ case 'REPEATABLE READ':
+ case 'SERIALIZABLE':
+ break;
+ default:
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'isolation level is not supported: '.$isolation, __FUNCTION__);
+ }
+
+ $query = "SET SESSION TRANSACTION ISOLATION LEVEL $isolation";
+ return $this->_doQuery($query, true);
+ }
+
+ // }}}
+ // {{{ _doConnect()
+
+ /**
+ * do the grunt work of the connect
+ *
+ * @return connection on success or MDB2 Error Object on failure
+ * @access protected
+ */
+ function _doConnect($username, $password, $persistent = false)
+ {
+ if (!PEAR::loadExtension($this->phptype)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
+ }
+
+ $params = array();
+ $unix = ($this->dsn['protocol'] && $this->dsn['protocol'] == 'unix');
+ if (empty($this->dsn['hostspec'])) {
+ $this->dsn['hostspec'] = $unix ? '' : 'localhost';
+ }
+ if ($this->dsn['hostspec']) {
+ $params[0] = $this->dsn['hostspec'] . ($this->dsn['port'] ? ':' . $this->dsn['port'] : '');
+ } else {
+ $params[0] = ':' . $this->dsn['socket'];
+ }
+ $params[] = $username ? $username : null;
+ $params[] = $password ? $password : null;
+ if (!$persistent) {
+ if ($this->_isNewLinkSet()) {
+ $params[] = true;
+ } else {
+ $params[] = false;
+ }
+ }
+ if (version_compare(phpversion(), '4.3.0', '>=')) {
+ $params[] = isset($this->dsn['client_flags'])
+ ? $this->dsn['client_flags'] : null;
+ }
+ $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
+
+ $connection = @call_user_func_array($connect_function, $params);
+ if (!$connection) {
+ if (($err = @mysql_error()) != '') {
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
+ $err, __FUNCTION__);
+ } else {
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
+ 'unable to establish a connection', __FUNCTION__);
+ }
+ }
+
+ if (!empty($this->dsn['charset'])) {
+ $result = $this->setCharset($this->dsn['charset'], $connection);
+ if (PEAR::isError($result)) {
+ $this->disconnect(false);
+ return $result;
+ }
+ }
+
+ return $connection;
+ }
+
+ // }}}
+ // {{{ connect()
+
+ /**
+ * Connect to the database
+ *
+ * @return MDB2_OK on success, MDB2 Error Object on failure
+ * @access public
+ */
+ function connect()
+ {
+ if (is_resource($this->connection)) {
+ //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
+ if (MDB2::areEquals($this->connected_dsn, $this->dsn)
+ && $this->opened_persistent == $this->options['persistent']
+ ) {
+ return MDB2_OK;
+ }
+ $this->disconnect(false);
+ }
+
+ $connection = $this->_doConnect(
+ $this->dsn['username'],
+ $this->dsn['password'],
+ $this->options['persistent']
+ );
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $this->connection = $connection;
+ $this->connected_dsn = $this->dsn;
+ $this->connected_database_name = '';
+ $this->opened_persistent = $this->options['persistent'];
+ $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
+
+ if ($this->database_name) {
+ if ($this->database_name != $this->connected_database_name) {
+ if (!@mysql_select_db($this->database_name, $connection)) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not select the database: '.$this->database_name, __FUNCTION__);
+ return $err;
+ }
+ $this->connected_database_name = $this->database_name;
+ }
+ }
+
+ $this->_getServerCapabilities();
+
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ setCharset()
+
+ /**
+ * Set the charset on the current connection
+ *
+ * @param string charset (or array(charset, collation))
+ * @param resource connection handle
+ *
+ * @return true on success, MDB2 Error Object on failure
+ */
+ function setCharset($charset, $connection = null)
+ {
+ if (is_null($connection)) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ $collation = null;
+ if (is_array($charset) && 2 == count($charset)) {
+ $collation = array_pop($charset);
+ $charset = array_pop($charset);
+ }
+ $client_info = mysql_get_client_info();
+ if (function_exists('mysql_set_charset') && version_compare($client_info, '5.0.6')) {
+ if (!$result = mysql_set_charset($charset, $connection)) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not set client character set', __FUNCTION__);
+ return $err;
+ }
+ return $result;
+ }
+ $query = "SET NAMES '".mysql_real_escape_string($charset, $connection)."'";
+ if (!is_null($collation)) {
+ $query .= " COLLATE '".mysql_real_escape_string($collation, $connection)."'";
+ }
+ return $this->_doQuery($query, true, $connection);
+ }
+
+ // }}}
+ // {{{ databaseExists()
+
+ /**
+ * check if given database name is exists?
+ *
+ * @param string $name name of the database that should be checked
+ *
+ * @return mixed true/false on success, a MDB2 error on failure
+ * @access public
+ */
+ function databaseExists($name)
+ {
+ $connection = $this->_doConnect($this->dsn['username'],
+ $this->dsn['password'],
+ $this->options['persistent']);
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $result = @mysql_select_db($name, $connection);
+ @mysql_close($connection);
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ disconnect()
+
+ /**
+ * Log out and disconnect from the database.
+ *
+ * @param boolean $force if the disconnect should be forced even if the
+ * connection is opened persistently
+ * @return mixed true on success, false if not connected and error
+ * object on error
+ * @access public
+ */
+ function disconnect($force = true)
+ {
+ if (is_resource($this->connection)) {
+ if ($this->in_transaction) {
+ $dsn = $this->dsn;
+ $database_name = $this->database_name;
+ $persistent = $this->options['persistent'];
+ $this->dsn = $this->connected_dsn;
+ $this->database_name = $this->connected_database_name;
+ $this->options['persistent'] = $this->opened_persistent;
+ $this->rollback();
+ $this->dsn = $dsn;
+ $this->database_name = $database_name;
+ $this->options['persistent'] = $persistent;
+ }
+
+ if (!$this->opened_persistent || $force) {
+ $ok = @mysql_close($this->connection);
+ if (!$ok) {
+ return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED,
+ null, null, null, __FUNCTION__);
+ }
+ }
+ } else {
+ return false;
+ }
+ return parent::disconnect($force);
+ }
+
+ // }}}
+ // {{{ standaloneQuery()
+
+ /**
+ * execute a query as DBA
+ *
+ * @param string $query the SQL query
+ * @param mixed $types array that contains the types of the columns in
+ * the result set
+ * @param boolean $is_manip if the query is a manipulation query
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function standaloneQuery($query, $types = null, $is_manip = false)
+ {
+ $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
+ $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
+ $connection = $this->_doConnect($user, $pass, $this->options['persistent']);
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $offset = $this->offset;
+ $limit = $this->limit;
+ $this->offset = $this->limit = 0;
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
+
+ $result = $this->_doQuery($query, $is_manip, $connection, $this->database_name);
+ if (!PEAR::isError($result)) {
+ $result = $this->_affectedRows($connection, $result);
+ }
+
+ @mysql_close($connection);
+ return $result;
+ }
+
+ // }}}
+ // {{{ _doQuery()
+
+ /**
+ * Execute a query
+ * @param string $query query
+ * @param boolean $is_manip if the query is a manipulation query
+ * @param resource $connection
+ * @param string $database_name
+ * @return result or error object
+ * @access protected
+ */
+ function _doQuery($query, $is_manip = false, $connection = null, $database_name = null)
+ {
+ $this->last_query = $query;
+ $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
+ if ($result) {
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = $result;
+ }
+ if ($this->options['disable_query']) {
+ $result = $is_manip ? 0 : null;
+ return $result;
+ }
+
+ if (is_null($connection)) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ if (is_null($database_name)) {
+ $database_name = $this->database_name;
+ }
+
+ if ($database_name) {
+ if ($database_name != $this->connected_database_name) {
+ if (!@mysql_select_db($database_name, $connection)) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not select the database: '.$database_name, __FUNCTION__);
+ return $err;
+ }
+ $this->connected_database_name = $database_name;
+ }
+ }
+
+ $function = $this->options['result_buffering']
+ ? 'mysql_query' : 'mysql_unbuffered_query';
+ $result = @$function($query, $connection);
+ if (!$result && 0 !== mysql_errno($connection)) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not execute statement', __FUNCTION__);
+ return $err;
+ }
+
+ $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result));
+ return $result;
+ }
+
+ // }}}
+ // {{{ _affectedRows()
+
+ /**
+ * Returns the number of rows affected
+ *
+ * @param resource $result
+ * @param resource $connection
+ * @return mixed MDB2 Error Object or the number of rows affected
+ * @access private
+ */
+ function _affectedRows($connection, $result = null)
+ {
+ if (is_null($connection)) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ return @mysql_affected_rows($connection);
+ }
+
+ // }}}
+ // {{{ _modifyQuery()
+
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * @param string $query query to modify
+ * @param boolean $is_manip if it is a DML query
+ * @param integer $limit limit the number of rows
+ * @param integer $offset start reading from given offset
+ * @return string modified query
+ * @access protected
+ */
+ function _modifyQuery($query, $is_manip, $limit, $offset)
+ {
+ if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) {
+ // "DELETE FROM table" gives 0 affected rows in MySQL.
+ // This little hack lets you know how many rows were deleted.
+ if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
+ $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
+ 'DELETE FROM \1 WHERE 1=1', $query);
+ }
+ }
+ if ($limit > 0
+ && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query)
+ ) {
+ $query = rtrim($query);
+ if (substr($query, -1) == ';') {
+ $query = substr($query, 0, -1);
+ }
+
+ // LIMIT doesn't always come last in the query
+ // @see http://dev.mysql.com/doc/refman/5.0/en/select.html
+ $after = '';
+ if (preg_match('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', $query, $matches)) {
+ $after = $matches[0];
+ $query = preg_replace('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', '', $query);
+ } elseif (preg_match('/(\s+FOR\s+UPDATE\s*)$/i', $query, $matches)) {
+ $after = $matches[0];
+ $query = preg_replace('/(\s+FOR\s+UPDATE\s*)$/im', '', $query);
+ } elseif (preg_match('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', $query, $matches)) {
+ $after = $matches[0];
+ $query = preg_replace('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', '', $query);
+ }
+
+ if ($is_manip) {
+ return $query . " LIMIT $limit" . $after;
+ } else {
+ return $query . " LIMIT $offset, $limit" . $after;
+ }
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ getServerVersion()
+
+ /**
+ * return version information about the server
+ *
+ * @param bool $native determines if the raw version string should be returned
+ * @return mixed array/string with version information or MDB2 error object
+ * @access public
+ */
+ function getServerVersion($native = false)
+ {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ if ($this->connected_server_info) {
+ $server_info = $this->connected_server_info;
+ } else {
+ $server_info = @mysql_get_server_info($connection);
+ }
+ if (!$server_info) {
+ return $this->raiseError(null, null, null,
+ 'Could not get server information', __FUNCTION__);
+ }
+ // cache server_info
+ $this->connected_server_info = $server_info;
+ if (!$native) {
+ $tmp = explode('.', $server_info, 3);
+ if (isset($tmp[2]) && strpos($tmp[2], '-')) {
+ $tmp2 = explode('-', @$tmp[2], 2);
+ } else {
+ $tmp2[0] = isset($tmp[2]) ? $tmp[2] : null;
+ $tmp2[1] = null;
+ }
+ $server_info = array(
+ 'major' => isset($tmp[0]) ? $tmp[0] : null,
+ 'minor' => isset($tmp[1]) ? $tmp[1] : null,
+ 'patch' => $tmp2[0],
+ 'extra' => $tmp2[1],
+ 'native' => $server_info,
+ );
+ }
+ return $server_info;
+ }
+
+ // }}}
+ // {{{ _getServerCapabilities()
+
+ /**
+ * Fetch some information about the server capabilities
+ * (transactions, subselects, prepared statements, etc).
+ *
+ * @access private
+ */
+ function _getServerCapabilities()
+ {
+ if (!$this->server_capabilities_checked) {
+ $this->server_capabilities_checked = true;
+
+ //set defaults
+ $this->supported['sub_selects'] = 'emulated';
+ $this->supported['prepared_statements'] = 'emulated';
+ $this->supported['triggers'] = false;
+ $this->start_transaction = false;
+ $this->varchar_max_length = 255;
+
+ $server_info = $this->getServerVersion();
+ if (is_array($server_info)) {
+ $server_version = $server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'];
+
+ if (!version_compare($server_version, '4.1.0', '<')) {
+ $this->supported['sub_selects'] = true;
+ $this->supported['prepared_statements'] = true;
+ }
+
+ // SAVEPOINTs were introduced in MySQL 4.0.14 and 4.1.1 (InnoDB)
+ if (version_compare($server_version, '4.1.0', '>=')) {
+ if (version_compare($server_version, '4.1.1', '<')) {
+ $this->supported['savepoints'] = false;
+ }
+ } elseif (version_compare($server_version, '4.0.14', '<')) {
+ $this->supported['savepoints'] = false;
+ }
+
+ if (!version_compare($server_version, '4.0.11', '<')) {
+ $this->start_transaction = true;
+ }
+
+ if (!version_compare($server_version, '5.0.3', '<')) {
+ $this->varchar_max_length = 65532;
+ }
+
+ if (!version_compare($server_version, '5.0.2', '<')) {
+ $this->supported['triggers'] = true;
+ }
+ }
+ }
+ }
+
+ // }}}
+ // {{{ function _skipUserDefinedVariable($query, $position)
+
+ /**
+ * Utility method, used by prepare() to avoid misinterpreting MySQL user
+ * defined variables (SELECT @x:=5) for placeholders.
+ * Check if the placeholder is a false positive, i.e. if it is an user defined
+ * variable instead. If so, skip it and advance the position, otherwise
+ * return the current position, which is valid
+ *
+ * @param string $query
+ * @param integer $position current string cursor position
+ * @return integer $new_position
+ * @access protected
+ */
+ function _skipUserDefinedVariable($query, $position)
+ {
+ $found = strpos(strrev(substr($query, 0, $position)), '@');
+ if ($found === false) {
+ return $position;
+ }
+ $pos = strlen($query) - strlen(substr($query, $position)) - $found - 1;
+ $substring = substr($query, $pos, $position - $pos + 2);
+ if (preg_match('/^@\w+\s*:=$/', $substring)) {
+ return $position + 1; //found an user defined variable: skip it
+ }
+ return $position;
+ }
+
+ // }}}
+ // {{{ prepare()
+
+ /**
+ * Prepares a query for multiple execution with execute().
+ * With some database backends, this is emulated.
+ * prepare() requires a generic query as string like
+ * 'INSERT INTO numbers VALUES(?,?)' or
+ * 'INSERT INTO numbers VALUES(:foo,:bar)'.
+ * The ? and :name and are placeholders which can be set using
+ * bindParam() and the query can be sent off using the execute() method.
+ * The allowed format for :name can be set with the 'bindname_format' option.
+ *
+ * @param string $query the query to prepare
+ * @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 or MDB2_PREPARE_RESULT, if set to
+ * MDB2_PREPARE_MANIP the query is handled as a manipulation query
+ * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders
+ * @return mixed resource handle for the prepared query on success, a MDB2
+ * error on failure
+ * @access public
+ * @see bindParam, execute
+ */
+ function prepare($query, $types = null, $result_types = null, $lobs = array())
+ {
+ // connect to get server capabilities (http://pear.php.net/bugs/16147)
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ if ($this->options['emulate_prepared']
+ || $this->supported['prepared_statements'] !== true
+ ) {
+ return parent::prepare($query, $types, $result_types, $lobs);
+ }
+ $is_manip = ($result_types === MDB2_PREPARE_MANIP);
+ $offset = $this->offset;
+ $limit = $this->limit;
+ $this->offset = $this->limit = 0;
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
+ $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
+ if ($result) {
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = $result;
+ }
+ $placeholder_type_guess = $placeholder_type = null;
+ $question = '?';
+ $colon = ':';
+ $positions = array();
+ $position = 0;
+ while ($position < strlen($query)) {
+ $q_position = strpos($query, $question, $position);
+ $c_position = strpos($query, $colon, $position);
+ if ($q_position && $c_position) {
+ $p_position = min($q_position, $c_position);
+ } elseif ($q_position) {
+ $p_position = $q_position;
+ } elseif ($c_position) {
+ $p_position = $c_position;
+ } else {
+ break;
+ }
+ if (is_null($placeholder_type)) {
+ $placeholder_type_guess = $query[$p_position];
+ }
+
+ $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
+ if (PEAR::isError($new_pos)) {
+ return $new_pos;
+ }
+ if ($new_pos != $position) {
+ $position = $new_pos;
+ continue; //evaluate again starting from the new position
+ }
+
+ //make sure this is not part of an user defined variable
+ $new_pos = $this->_skipUserDefinedVariable($query, $position);
+ if ($new_pos != $position) {
+ $position = $new_pos;
+ continue; //evaluate again starting from the new position
+ }
+
+ if ($query[$position] == $placeholder_type_guess) {
+ if (is_null($placeholder_type)) {
+ $placeholder_type = $query[$p_position];
+ $question = $colon = $placeholder_type;
+ }
+ if ($placeholder_type == ':') {
+ $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s';
+ $parameter = preg_replace($regexp, '\\1', $query);
+ if ($parameter === '') {
+ $err = $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
+ 'named parameter name must match "bindname_format" option', __FUNCTION__);
+ return $err;
+ }
+ $positions[$p_position] = $parameter;
+ $query = substr_replace($query, '?', $position, strlen($parameter)+1);
+ } else {
+ $positions[$p_position] = count($positions);
+ }
+ $position = $p_position + 1;
+ } else {
+ $position = $p_position;
+ }
+ }
+
+ static $prep_statement_counter = 1;
+ $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand()));
+ $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']);
+ $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text');
+ $statement = $this->_doQuery($query, true, $connection);
+ if (PEAR::isError($statement)) {
+ return $statement;
+ }
+
+ $class_name = 'MDB2_Statement_'.$this->phptype;
+ $obj = new $class_name($this, $statement_name, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
+ $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
+ return $obj;
+ }
+
+ // }}}
+ // {{{ replace()
+
+ /**
+ * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
+ * query, except that if there is already a row in the table with the same
+ * key field values, the old row is deleted before the new row is inserted.
+ *
+ * The REPLACE type of query does not make part of the SQL standards. Since
+ * practically only MySQL implements it natively, this type of query is
+ * emulated through this method for other DBMS using standard types of
+ * queries inside a transaction to assure the atomicity of the operation.
+ *
+ * @access public
+ *
+ * @param string $table name of the table on which the REPLACE query will
+ * be executed.
+ * @param array $fields associative array that describes the fields and the
+ * values that will be inserted or updated in the specified table. The
+ * indexes of the array are the names of all the fields of the table. The
+ * values of the array are also associative arrays that describe the
+ * values and other properties of the table fields.
+ *
+ * Here follows a list of field properties that need to be specified:
+ *
+ * value:
+ * Value to be assigned to the specified field. This value may be
+ * of specified in database independent type format as this
+ * function can perform the necessary datatype conversions.
+ *
+ * Default:
+ * this property is required unless the Null property
+ * is set to 1.
+ *
+ * type
+ * Name of the type of the field. Currently, all types Metabase
+ * are supported except for clob and blob.
+ *
+ * Default: no type conversion
+ *
+ * null
+ * Boolean property that indicates that the value for this field
+ * should be set to null.
+ *
+ * The default value for fields missing in INSERT queries may be
+ * specified the definition of a table. Often, the default value
+ * is already null, but since the REPLACE may be emulated using
+ * an UPDATE query, make sure that all fields of the table are
+ * listed in this function argument array.
+ *
+ * Default: 0
+ *
+ * key
+ * Boolean property that indicates that this field should be
+ * handled as a primary key or at least as part of the compound
+ * unique index of the table that will determine the row that will
+ * updated if it exists or inserted a new row otherwise.
+ *
+ * This function will fail if no key field is specified or if the
+ * value of a key field is set to null because fields that are
+ * part of unique index they may not be null.
+ *
+ * Default: 0
+ *
+ * @see http://dev.mysql.com/doc/refman/5.0/en/replace.html
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function replace($table, $fields)
+ {
+ $count = count($fields);
+ $query = $values = '';
+ $keys = $colnum = 0;
+ for (reset($fields); $colnum < $count; next($fields), $colnum++) {
+ $name = key($fields);
+ if ($colnum > 0) {
+ $query .= ',';
+ $values.= ',';
+ }
+ $query.= $this->quoteIdentifier($name, true);
+ if (isset($fields[$name]['null']) && $fields[$name]['null']) {
+ $value = 'NULL';
+ } else {
+ $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
+ $value = $this->quote($fields[$name]['value'], $type);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ }
+ $values.= $value;
+ if (isset($fields[$name]['key']) && $fields[$name]['key']) {
+ if ($value === 'NULL') {
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
+ 'key value '.$name.' may not be NULL', __FUNCTION__);
+ }
+ $keys++;
+ }
+ }
+ if ($keys == 0) {
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
+ 'not specified which fields are keys', __FUNCTION__);
+ }
+
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $table = $this->quoteIdentifier($table, true);
+ $query = "REPLACE INTO $table ($query) VALUES ($values)";
+ $result = $this->_doQuery($query, true, $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return $this->_affectedRows($connection, $result);
+ }
+
+ // }}}
+ // {{{ nextID()
+
+ /**
+ * Returns the next free id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true the sequence is
+ * automatic created, if it
+ * not exists
+ *
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function nextID($seq_name, $ondemand = true)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
+ $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->expectError(MDB2_ERROR_NOSUCHTABLE);
+ $result = $this->_doQuery($query, true);
+ $this->popExpect();
+ $this->popErrorHandling();
+ if (PEAR::isError($result)) {
+ if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
+ $this->loadModule('Manager', null, true);
+ $result = $this->manager->createSequence($seq_name);
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result, null, null,
+ 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__);
+ } else {
+ return $this->nextID($seq_name, false);
+ }
+ }
+ return $result;
+ }
+ $value = $this->lastInsertID();
+ if (is_numeric($value)) {
+ $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name;
+ }
+ }
+ return $value;
+ }
+
+ // }}}
+ // {{{ lastInsertID()
+
+ /**
+ * Returns the autoincrement ID if supported or $id or fetches the current
+ * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param string $field name of the field into which a new row was inserted
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function lastInsertID($table = null, $field = null)
+ {
+ // not using mysql_insert_id() due to http://pear.php.net/bugs/bug.php?id=8051
+ // not casting to integer to handle BIGINT http://pear.php.net/bugs/bug.php?id=17650
+ return $this->queryOne('SELECT LAST_INSERT_ID()');
+ }
+
+ // }}}
+ // {{{ currID()
+
+ /**
+ * Returns the current id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function currID($seq_name)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
+ $query = "SELECT MAX($seqcol_name) FROM $sequence_name";
+ return $this->queryOne($query, 'integer');
+ }
+}
+
+/**
+ * MDB2 MySQL result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Result_mysql extends MDB2_Result_Common
+{
+ // }}}
+ // {{{ fetchRow()
+
+ /**
+ * Fetch a row and insert the data into an existing array.
+ *
+ * @param int $fetchmode how the array data should be indexed
+ * @param int $rownum number of the row where the data can be found
+ * @return int data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
+ {
+ if (!is_null($rownum)) {
+ $seek = $this->seek($rownum);
+ if (PEAR::isError($seek)) {
+ return $seek;
+ }
+ }
+ if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
+ $fetchmode = $this->db->fetchmode;
+ }
+ if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
+ $row = @mysql_fetch_assoc($this->result);
+ if (is_array($row)
+ && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
+ ) {
+ $row = array_change_key_case($row, $this->db->options['field_case']);
+ }
+ } else {
+ $row = @mysql_fetch_row($this->result);
+ }
+
+ if (!$row) {
+ if ($this->result === false) {
+ $err = $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ return $err;
+ }
+ return null;
+ }
+ $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL;
+ $rtrim = false;
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) {
+ if (empty($this->types)) {
+ $mode += MDB2_PORTABILITY_RTRIM;
+ } else {
+ $rtrim = true;
+ }
+ }
+ if ($mode) {
+ $this->db->_fixResultArrayValues($row, $mode);
+ }
+ if (!empty($this->types)) {
+ $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim);
+ }
+ if (!empty($this->values)) {
+ $this->_assignBindColumns($row);
+ }
+ if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
+ $object_class = $this->db->options['fetch_class'];
+ if ($object_class == 'stdClass') {
+ $row = (object) $row;
+ } else {
+ $rowObj = new $object_class($row);
+ $row = $rowObj;
+ }
+ }
+ ++$this->rownum;
+ return $row;
+ }
+
+ // }}}
+ // {{{ _getColumnNames()
+
+ /**
+ * Retrieve the names of columns returned by the DBMS in a query result.
+ *
+ * @return mixed Array variable that holds the names of columns as keys
+ * or an MDB2 error on failure.
+ * Some DBMS may not return any columns when the result set
+ * does not contain any rows.
+ * @access private
+ */
+ function _getColumnNames()
+ {
+ $columns = array();
+ $numcols = $this->numCols();
+ if (PEAR::isError($numcols)) {
+ return $numcols;
+ }
+ for ($column = 0; $column < $numcols; $column++) {
+ $column_name = @mysql_field_name($this->result, $column);
+ $columns[$column_name] = $column;
+ }
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $columns = array_change_key_case($columns, $this->db->options['field_case']);
+ }
+ return $columns;
+ }
+
+ // }}}
+ // {{{ numCols()
+
+ /**
+ * Count the number of columns returned by the DBMS in a query result.
+ *
+ * @return mixed integer value with the number of columns, a MDB2 error
+ * on failure
+ * @access public
+ */
+ function numCols()
+ {
+ $cols = @mysql_num_fields($this->result);
+ if (is_null($cols)) {
+ if ($this->result === false) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ } elseif (is_null($this->result)) {
+ return count($this->types);
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get column count', __FUNCTION__);
+ }
+ return $cols;
+ }
+
+ // }}}
+ // {{{ free()
+
+ /**
+ * Free the internal resources associated with result.
+ *
+ * @return boolean true on success, false if result is invalid
+ * @access public
+ */
+ function free()
+ {
+ if (is_resource($this->result) && $this->db->connection) {
+ $free = @mysql_free_result($this->result);
+ if ($free === false) {
+ return $this->db->raiseError(null, null, null,
+ 'Could not free result', __FUNCTION__);
+ }
+ }
+ $this->result = false;
+ return MDB2_OK;
+ }
+}
+
+/**
+ * MDB2 MySQL buffered result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_BufferedResult_mysql extends MDB2_Result_mysql
+{
+ // }}}
+ // {{{ seek()
+
+ /**
+ * Seek to a specific row in a result set
+ *
+ * @param int $rownum number of the row where the data can be found
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function seek($rownum = 0)
+ {
+ if ($this->rownum != ($rownum - 1) && !@mysql_data_seek($this->result, $rownum)) {
+ if ($this->result === false) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ } elseif (is_null($this->result)) {
+ return MDB2_OK;
+ }
+ return $this->db->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__);
+ }
+ $this->rownum = $rownum - 1;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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
+ */
+ function valid()
+ {
+ $numrows = $this->numRows();
+ if (PEAR::isError($numrows)) {
+ return $numrows;
+ }
+ return $this->rownum < ($numrows - 1);
+ }
+
+ // }}}
+ // {{{ numRows()
+
+ /**
+ * Returns the number of rows in a result object
+ *
+ * @return mixed MDB2 Error Object or the number of rows
+ * @access public
+ */
+ function numRows()
+ {
+ $rows = @mysql_num_rows($this->result);
+ if (false === $rows) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ } elseif (is_null($this->result)) {
+ return 0;
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get row count', __FUNCTION__);
+ }
+ return $rows;
+ }
+
+ // }}}
+}
+
+/**
+ * MDB2 MySQL statement driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Statement_mysql extends MDB2_Statement_Common
+{
+ // {{{ _execute()
+
+ /**
+ * Execute a prepared query statement helper method.
+ *
+ * @param mixed $result_class string which specifies which result class to use
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in
+ *
+ * @return mixed MDB2_Result or integer (affected rows) on success,
+ * a MDB2 error on failure
+ * @access private
+ */
+ function _execute($result_class = true, $result_wrap_class = false)
+ {
+ if (is_null($this->statement)) {
+ $result = parent::_execute($result_class, $result_wrap_class);
+ return $result;
+ }
+ $this->db->last_query = $this->query;
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values));
+ if ($this->db->getOption('disable_query')) {
+ $result = $this->is_manip ? 0 : null;
+ return $result;
+ }
+
+ $connection = $this->db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $query = 'EXECUTE '.$this->statement;
+ if (!empty($this->positions)) {
+ $parameters = array();
+ foreach ($this->positions as $parameter) {
+ if (!array_key_exists($parameter, $this->values)) {
+ return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
+ }
+ $close = false;
+ $value = $this->values[$parameter];
+ $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null;
+ if (is_resource($value) || $type == 'clob' || $type == 'blob' && $this->db->options['lob_allow_url_include']) {
+ if (!is_resource($value) && preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
+ if ($match[1] == 'file://') {
+ $value = $match[2];
+ }
+ $value = @fopen($value, 'r');
+ $close = true;
+ }
+ if (is_resource($value)) {
+ $data = '';
+ while (!@feof($value)) {
+ $data.= @fread($value, $this->db->options['lob_buffer_length']);
+ }
+ if ($close) {
+ @fclose($value);
+ }
+ $value = $data;
+ }
+ }
+ $quoted = $this->db->quote($value, $type);
+ if (PEAR::isError($quoted)) {
+ return $quoted;
+ }
+ $param_query = 'SET @'.$parameter.' = '.$quoted;
+ $result = $this->db->_doQuery($param_query, true, $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ $query.= ' USING @'.implode(', @', array_values($this->positions));
+ }
+
+ $result = $this->db->_doQuery($query, $this->is_manip, $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ if ($this->is_manip) {
+ $affected_rows = $this->db->_affectedRows($connection, $result);
+ return $affected_rows;
+ }
+
+ $result = $this->db->_wrapResult($result, $this->result_types,
+ $result_class, $result_wrap_class, $this->limit, $this->offset);
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result));
+ return $result;
+ }
+
+ // }}}
+ // {{{ free()
+
+ /**
+ * Release resources allocated for the specified prepared query.
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function free()
+ {
+ if (is_null($this->positions)) {
+ return $this->db->raiseError(MDB2_ERROR, null, null,
+ 'Prepared statement has already been freed', __FUNCTION__);
+ }
+ $result = MDB2_OK;
+
+ if (!is_null($this->statement)) {
+ $connection = $this->db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ $query = 'DEALLOCATE PREPARE '.$this->statement;
+ $result = $this->db->_doQuery($query, true, $connection);
+ }
+
+ parent::free();
+ return $result;
+ }
+}
+?>
diff --git a/3rdparty/MDB2/Driver/pgsql.php b/3rdparty/MDB2/Driver/pgsql.php index 13fea690680..15bd280f40b 100644 --- a/3rdparty/MDB2/Driver/pgsql.php +++ b/3rdparty/MDB2/Driver/pgsql.php @@ -1,1519 +1,1548 @@ -<?php -// vim: set et ts=4 sw=4 fdm=marker: -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Paul Cooper <pgc@ucecom.com> | -// +----------------------------------------------------------------------+ -// -// $Id: pgsql.php,v 1.203 2008/11/29 14:04:46 afz Exp $ - -/** - * MDB2 PostGreSQL driver - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Driver_pgsql extends MDB2_Driver_Common -{ - // {{{ properties - var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => '\\'); - - var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"'); - // }}} - // {{{ constructor - - /** - * Constructor - */ - function __construct() - { - parent::__construct(); - - $this->phptype = 'pgsql'; - $this->dbsyntax = 'pgsql'; - - $this->supported['sequences'] = true; - $this->supported['indexes'] = true; - $this->supported['affected_rows'] = true; - $this->supported['summary_functions'] = true; - $this->supported['order_by_text'] = true; - $this->supported['transactions'] = true; - $this->supported['savepoints'] = true; - $this->supported['current_id'] = true; - $this->supported['limit_queries'] = true; - $this->supported['LOBs'] = true; - $this->supported['replace'] = 'emulated'; - $this->supported['sub_selects'] = true; - $this->supported['triggers'] = true; - $this->supported['auto_increment'] = 'emulated'; - $this->supported['primary_key'] = true; - $this->supported['result_introspection'] = true; - $this->supported['prepared_statements'] = true; - $this->supported['identifier_quoting'] = true; - $this->supported['pattern_escaping'] = true; - $this->supported['new_link'] = true; - - $this->options['DBA_username'] = false; - $this->options['DBA_password'] = false; - $this->options['multi_query'] = false; - $this->options['disable_smart_seqname'] = true; - $this->options['max_identifiers_length'] = 63; - } - - // }}} - // {{{ errorInfo() - - /** - * This method is used to collect information about an error - * - * @param integer $error - * @return array - * @access public - */ - function errorInfo($error = null) - { - // Fall back to MDB2_ERROR if there was no mapping. - $error_code = MDB2_ERROR; - - $native_msg = ''; - if (is_resource($error)) { - $native_msg = @pg_result_error($error); - } elseif ($this->connection) { - $native_msg = @pg_last_error($this->connection); - if (!$native_msg && @pg_connection_status($this->connection) === PGSQL_CONNECTION_BAD) { - $native_msg = 'Database connection has been lost.'; - $error_code = MDB2_ERROR_CONNECT_FAILED; - } - } else { - $native_msg = @pg_last_error(); - } - - static $error_regexps; - if (empty($error_regexps)) { - $error_regexps = array( - '/column .* (of relation .*)?does not exist/i' - => MDB2_ERROR_NOSUCHFIELD, - '/(relation|sequence|table).*does not exist|class .* not found/i' - => MDB2_ERROR_NOSUCHTABLE, - '/database .* does not exist/' - => MDB2_ERROR_NOT_FOUND, - '/constraint .* does not exist/' - => MDB2_ERROR_NOT_FOUND, - '/index .* does not exist/' - => MDB2_ERROR_NOT_FOUND, - '/database .* already exists/i' - => MDB2_ERROR_ALREADY_EXISTS, - '/relation .* already exists/i' - => MDB2_ERROR_ALREADY_EXISTS, - '/(divide|division) by zero$/i' - => MDB2_ERROR_DIVZERO, - '/pg_atoi: error in .*: can\'t parse /i' - => MDB2_ERROR_INVALID_NUMBER, - '/invalid input syntax for( type)? (integer|numeric)/i' - => MDB2_ERROR_INVALID_NUMBER, - '/value .* is out of range for type \w*int/i' - => MDB2_ERROR_INVALID_NUMBER, - '/integer out of range/i' - => MDB2_ERROR_INVALID_NUMBER, - '/value too long for type character/i' - => MDB2_ERROR_INVALID, - '/attribute .* not found|relation .* does not have attribute/i' - => MDB2_ERROR_NOSUCHFIELD, - '/column .* specified in USING clause does not exist in (left|right) table/i' - => MDB2_ERROR_NOSUCHFIELD, - '/parser: parse error at or near/i' - => MDB2_ERROR_SYNTAX, - '/syntax error at/' - => MDB2_ERROR_SYNTAX, - '/column reference .* is ambiguous/i' - => MDB2_ERROR_SYNTAX, - '/permission denied/' - => MDB2_ERROR_ACCESS_VIOLATION, - '/violates not-null constraint/' - => MDB2_ERROR_CONSTRAINT_NOT_NULL, - '/violates [\w ]+ constraint/' - => MDB2_ERROR_CONSTRAINT, - '/referential integrity violation/' - => MDB2_ERROR_CONSTRAINT, - '/more expressions than target columns/i' - => MDB2_ERROR_VALUE_COUNT_ON_ROW, - ); - } - if (is_numeric($error) && $error < 0) { - $error_code = $error; - } else { - foreach ($error_regexps as $regexp => $code) { - if (preg_match($regexp, $native_msg)) { - $error_code = $code; - break; - } - } - } - return array($error_code, null, $native_msg); - } - - // }}} - // {{{ escape() - - /** - * Quotes a string so it can be safely used in a query. It will quote - * the text so it can safely be used within a query. - * - * @param string the input string to quote - * @param bool escape wildcards - * - * @return string quoted string - * - * @access public - */ - function escape($text, $escape_wildcards = false) - { - if ($escape_wildcards) { - $text = $this->escapePattern($text); - } - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - if (is_resource($connection) && version_compare(PHP_VERSION, '5.2.0RC5', '>=')) { - $text = @pg_escape_string($connection, $text); - } else { - $text = @pg_escape_string($text); - } - return $text; - } - - // }}} - // {{{ beginTransaction() - - /** - * Start a transaction or set a savepoint. - * - * @param string name of a savepoint to set - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function beginTransaction($savepoint = null) - { - $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!is_null($savepoint)) { - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'savepoint cannot be released when changes are auto committed', __FUNCTION__); - } - $query = 'SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } elseif ($this->in_transaction) { - return MDB2_OK; //nothing to do - } - if (!$this->destructor_registered && $this->opened_persistent) { - $this->destructor_registered = true; - register_shutdown_function('MDB2_closeOpenTransactions'); - } - $result =& $this->_doQuery('BEGIN', true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = true; - return MDB2_OK; - } - - // }}} - // {{{ commit() - - /** - * Commit the database changes done during a transaction that is in - * progress or release a savepoint. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after committing the pending changes. - * - * @param string name of a savepoint to release - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function commit($savepoint = null) - { - $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - $query = 'RELEASE SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } - - $result =& $this->_doQuery('COMMIT', true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ rollback() - - /** - * Cancel any database changes done during a transaction or since a specific - * savepoint that is in progress. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after canceling the pending changes. - * - * @param string name of a savepoint to rollback to - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function rollback($savepoint = null) - { - $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'rollback cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - $query = 'ROLLBACK TO SAVEPOINT '.$savepoint; - return $this->_doQuery($query, true); - } - - $query = 'ROLLBACK'; - $result =& $this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ function setTransactionIsolation() - - /** - * Set the transacton isolation level. - * - * @param string standard isolation level - * READ UNCOMMITTED (allows dirty reads) - * READ COMMITTED (prevents dirty reads) - * REPEATABLE READ (prevents nonrepeatable reads) - * SERIALIZABLE (prevents phantom reads) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - static function setTransactionIsolation($isolation, $options = array()) - { - $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); - switch ($isolation) { - case 'READ UNCOMMITTED': - case 'READ COMMITTED': - case 'REPEATABLE READ': - case 'SERIALIZABLE': - break; - default: - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'isolation level is not supported: '.$isolation, __FUNCTION__); - } - - $query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL $isolation"; - return $this->_doQuery($query, true); - } - - // }}} - // {{{ _doConnect() - - /** - * Do the grunt work of connecting to the database - * - * @return mixed connection resource on success, MDB2 Error Object on failure - * @access protected - */ - function _doConnect($username, $password, $database_name, $persistent = false) - { - if (!PEAR::loadExtension($this->phptype)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); - } - - if ($database_name == '') { - $database_name = 'template1'; - } - - $protocol = $this->dsn['protocol'] ? $this->dsn['protocol'] : 'tcp'; - - $params = array(''); - if ($protocol == 'tcp') { - if ($this->dsn['hostspec']) { - $params[0].= 'host=' . $this->dsn['hostspec']; - } - if ($this->dsn['port']) { - $params[0].= ' port=' . $this->dsn['port']; - } - } elseif ($protocol == 'unix') { - // Allow for pg socket in non-standard locations. - if ($this->dsn['socket']) { - $params[0].= 'host=' . $this->dsn['socket']; - } - if ($this->dsn['port']) { - $params[0].= ' port=' . $this->dsn['port']; - } - } - if ($database_name) { - $params[0].= ' dbname=\'' . addslashes($database_name) . '\''; - } - if ($username) { - $params[0].= ' user=\'' . addslashes($username) . '\''; - } - if ($password) { - $params[0].= ' password=\'' . addslashes($password) . '\''; - } - if (!empty($this->dsn['options'])) { - $params[0].= ' options=' . $this->dsn['options']; - } - if (!empty($this->dsn['tty'])) { - $params[0].= ' tty=' . $this->dsn['tty']; - } - if (!empty($this->dsn['connect_timeout'])) { - $params[0].= ' connect_timeout=' . $this->dsn['connect_timeout']; - } - if (!empty($this->dsn['sslmode'])) { - $params[0].= ' sslmode=' . $this->dsn['sslmode']; - } - if (!empty($this->dsn['service'])) { - $params[0].= ' service=' . $this->dsn['service']; - } - - if ($this->_isNewLinkSet()) { - if (version_compare(phpversion(), '4.3.0', '>=')) { - $params[] = PGSQL_CONNECT_FORCE_NEW; - } - } - - $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; - $connection = @call_user_func_array($connect_function, $params); - if (!$connection) { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, - 'unable to establish a connection', __FUNCTION__); - } - - if (empty($this->dsn['disable_iso_date'])) { - if (!@pg_query($connection, "SET SESSION DATESTYLE = 'ISO'")) { - return $this->raiseError(null, null, null, - 'Unable to set date style to iso', __FUNCTION__); - } - } - - if (!empty($this->dsn['charset'])) { - $result = $this->setCharset($this->dsn['charset'], $connection); - if (PEAR::isError($result)) { - return $result; - } - } - - return $connection; - } - - // }}} - // {{{ connect() - - /** - * Connect to the database - * - * @return true on success, MDB2 Error Object on failure - * @access public - */ - function connect() - { - if (is_resource($this->connection)) { - //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 - if (MDB2::areEquals($this->connected_dsn, $this->dsn) - && $this->connected_database_name == $this->database_name - && ($this->opened_persistent == $this->options['persistent']) - ) { - return MDB2_OK; - } - $this->disconnect(false); - } - - if ($this->database_name) { - $connection = $this->_doConnect($this->dsn['username'], - $this->dsn['password'], - $this->database_name, - $this->options['persistent']); - if (PEAR::isError($connection)) { - return $connection; - } - - $this->connection = $connection; - $this->connected_dsn = $this->dsn; - $this->connected_database_name = $this->database_name; - $this->opened_persistent = $this->options['persistent']; - $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; - } - - return MDB2_OK; - } - - // }}} - // {{{ setCharset() - - /** - * Set the charset on the current connection - * - * @param string charset - * @param resource connection handle - * - * @return true on success, MDB2 Error Object on failure - */ - function setCharset($charset, $connection = null) - { - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - if (is_array($charset)) { - $charset = array_shift($charset); - $this->warnings[] = 'postgresql does not support setting client collation'; - } - $result = @pg_set_client_encoding($connection, $charset); - if ($result == -1) { - return $this->raiseError(null, null, null, - 'Unable to set client charset: '.$charset, __FUNCTION__); - } - return MDB2_OK; - } - - // }}} - // {{{ databaseExists() - - /** - * check if given database name is exists? - * - * @param string $name name of the database that should be checked - * - * @return mixed true/false on success, a MDB2 error on failure - * @access public - */ - function databaseExists($name) - { - $res = $this->_doConnect($this->dsn['username'], - $this->dsn['password'], - $this->escape($name), - $this->options['persistent']); - if (!PEAR::isError($res)) { - return true; - } - - return false; - } - - // }}} - // {{{ disconnect() - - /** - * Log out and disconnect from the database. - * - * @param boolean $force if the disconnect should be forced even if the - * connection is opened persistently - * @return mixed true on success, false if not connected and error - * object on error - * @access public - */ - function disconnect($force = true) - { - if (is_resource($this->connection)) { - if ($this->in_transaction) { - $dsn = $this->dsn; - $database_name = $this->database_name; - $persistent = $this->options['persistent']; - $this->dsn = $this->connected_dsn; - $this->database_name = $this->connected_database_name; - $this->options['persistent'] = $this->opened_persistent; - $this->rollback(); - $this->dsn = $dsn; - $this->database_name = $database_name; - $this->options['persistent'] = $persistent; - } - - if (!$this->opened_persistent || $force) { - $ok = @pg_close($this->connection); - if (!$ok) { - return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED, - null, null, null, __FUNCTION__); - } - } - } else { - return false; - } - return parent::disconnect($force); - } - - // }}} - // {{{ standaloneQuery() - - /** - * execute a query as DBA - * - * @param string $query the SQL query - * @param mixed $types array that contains the types of the columns in - * the result set - * @param boolean $is_manip if the query is a manipulation query - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &standaloneQuery($query, $types = null, $is_manip = false) - { - $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username']; - $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password']; - $connection = $this->_doConnect($user, $pass, $this->database_name, $this->options['persistent']); - if (PEAR::isError($connection)) { - return $connection; - } - - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); - - $result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name); - if (!PEAR::isError($result)) { - if ($is_manip) { - $result = $this->_affectedRows($connection, $result); - } else { - $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset); - } - } - - @pg_close($connection); - return $result; - } - - // }}} - // {{{ _doQuery() - - /** - * Execute a query - * @param string $query query - * @param boolean $is_manip if the query is a manipulation query - * @param resource $connection - * @param string $database_name - * @return result or error object - * @access protected - */ - function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) - { - $this->last_query = $query; - $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - if ($this->options['disable_query']) { - $result = $is_manip ? 0 : null; - return $result; - } - - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - - $function = $this->options['multi_query'] ? 'pg_send_query' : 'pg_query'; - $result = @$function($connection, $query); - if (!$result) { - $err =& $this->raiseError(null, null, null, - 'Could not execute statement', __FUNCTION__); - return $err; - } elseif ($this->options['multi_query']) { - if (!($result = @pg_get_result($connection))) { - $err =& $this->raiseError(null, null, null, - 'Could not get the first result from a multi query', __FUNCTION__); - return $err; - } - } - - $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result)); - return $result; - } - - // }}} - // {{{ _affectedRows() - - /** - * Returns the number of rows affected - * - * @param resource $result - * @param resource $connection - * @return mixed MDB2 Error Object or the number of rows affected - * @access private - */ - function _affectedRows($connection, $result = null) - { - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - return @pg_affected_rows($result); - } - - // }}} - // {{{ _modifyQuery() - - /** - * Changes a query string for various DBMS specific reasons - * - * @param string $query query to modify - * @param boolean $is_manip if it is a DML query - * @param integer $limit limit the number of rows - * @param integer $offset start reading from given offset - * @return string modified query - * @access protected - */ - function _modifyQuery($query, $is_manip, $limit, $offset) - { - if ($limit > 0 - && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) - ) { - $query = rtrim($query); - if (substr($query, -1) == ';') { - $query = substr($query, 0, -1); - } - if ($is_manip) { - $query = $this->_modifyManipQuery($query, $limit); - } else { - $query.= " LIMIT $limit OFFSET $offset"; - } - } - return $query; - } - - // }}} - // {{{ _modifyManipQuery() - - /** - * Changes a manip query string for various DBMS specific reasons - * - * @param string $query query to modify - * @param integer $limit limit the number of rows - * @return string modified query - * @access protected - */ - function _modifyManipQuery($query, $limit) - { - $pos = strpos(strtolower($query), 'where'); - $where = $pos ? substr($query, $pos) : ''; - - $manip_clause = '(\bDELETE\b\s+(?:\*\s+)?\bFROM\b|\bUPDATE\b)'; - $from_clause = '([\w\.]+)'; - $where_clause = '(?:(.*)\bWHERE\b\s+(.*))|(.*)'; - $pattern = '/^'. $manip_clause . '\s+' . $from_clause .'(?:\s)*(?:'. $where_clause .')?$/i'; - $matches = preg_match($pattern, $query, $match); - if ($matches) { - $manip = $match[1]; - $from = $match[2]; - $what = (count($matches) == 6) ? $match[5] : $match[3]; - return $manip.' '.$from.' '.$what.' WHERE ctid=(SELECT ctid FROM '.$from.' '.$where.' LIMIT '.$limit.')'; - } - //return error? - return $query; - } - - // }}} - // {{{ getServerVersion() - - /** - * return version information about the server - * - * @param bool $native determines if the raw version string should be returned - * @return mixed array/string with version information or MDB2 error object - * @access public - */ - function getServerVersion($native = false) - { - $query = 'SHOW SERVER_VERSION'; - if ($this->connected_server_info) { - $server_info = $this->connected_server_info; - } else { - $server_info = $this->queryOne($query, 'text'); - if (PEAR::isError($server_info)) { - return $server_info; - } - } - // cache server_info - $this->connected_server_info = $server_info; - if (!$native && !PEAR::isError($server_info)) { - $tmp = explode('.', $server_info, 3); - if (empty($tmp[2]) - && isset($tmp[1]) - && preg_match('/(\d+)(.*)/', $tmp[1], $tmp2) - ) { - $server_info = array( - 'major' => $tmp[0], - 'minor' => $tmp2[1], - 'patch' => null, - 'extra' => $tmp2[2], - 'native' => $server_info, - ); - } else { - $server_info = array( - 'major' => isset($tmp[0]) ? $tmp[0] : null, - 'minor' => isset($tmp[1]) ? $tmp[1] : null, - 'patch' => isset($tmp[2]) ? $tmp[2] : null, - 'extra' => null, - 'native' => $server_info, - ); - } - } - return $server_info; - } - - // }}} - // {{{ prepare() - - /** - * Prepares a query for multiple execution with execute(). - * With some database backends, this is emulated. - * prepare() requires a generic query as string like - * 'INSERT INTO numbers VALUES(?,?)' or - * 'INSERT INTO numbers VALUES(:foo,:bar)'. - * The ? and :name and are placeholders which can be set using - * bindParam() and the query can be sent off using the execute() method. - * The allowed format for :name can be set with the 'bindname_format' option. - * - * @param string $query the query to prepare - * @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 or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders - * @return mixed resource handle for the prepared query on success, a MDB2 - * error on failure - * @access public - * @see bindParam, execute - */ - function &prepare($query, $types = null, $result_types = null, $lobs = array()) - { - if ($this->options['emulate_prepared']) { - $obj =& parent::prepare($query, $types, $result_types, $lobs); - return $obj; - } - $is_manip = ($result_types === MDB2_PREPARE_MANIP); - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - $pgtypes = function_exists('pg_prepare') ? false : array(); - if ($pgtypes !== false && !empty($types)) { - $this->loadModule('Datatype', null, true); - } - $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); - $placeholder_type_guess = $placeholder_type = null; - $question = '?'; - $colon = ':'; - $positions = array(); - $position = $parameter = 0; - while ($position < strlen($query)) { - $q_position = strpos($query, $question, $position); - $c_position = strpos($query, $colon, $position); - //skip "::type" cast ("select id::varchar(20) from sometable where name=?") - $doublecolon_position = strpos($query, '::', $position); - if ($doublecolon_position !== false && $doublecolon_position == $c_position) { - $c_position = strpos($query, $colon, $position+2); - } - if ($q_position && $c_position) { - $p_position = min($q_position, $c_position); - } elseif ($q_position) { - $p_position = $q_position; - } elseif ($c_position) { - $p_position = $c_position; - } else { - break; - } - if (is_null($placeholder_type)) { - $placeholder_type_guess = $query[$p_position]; - } - - $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); - if (PEAR::isError($new_pos)) { - return $new_pos; - } - if ($new_pos != $position) { - $position = $new_pos; - continue; //evaluate again starting from the new position - } - - if ($query[$position] == $placeholder_type_guess) { - if (is_null($placeholder_type)) { - $placeholder_type = $query[$p_position]; - $question = $colon = $placeholder_type; - if (!empty($types) && is_array($types)) { - if ($placeholder_type == ':') { - } else { - $types = array_values($types); - } - } - } - if ($placeholder_type_guess == '?') { - $length = 1; - $name = $parameter; - } else { - $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s'; - $param = preg_replace($regexp, '\\1', $query); - if ($param === '') { - $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'named parameter name must match "bindname_format" option', __FUNCTION__); - return $err; - } - $length = strlen($param) + 1; - $name = $param; - } - if ($pgtypes !== false) { - if (is_array($types) && array_key_exists($name, $types)) { - $pgtypes[] = $this->datatype->mapPrepareDatatype($types[$name]); - } elseif (is_array($types) && array_key_exists($parameter, $types)) { - $pgtypes[] = $this->datatype->mapPrepareDatatype($types[$parameter]); - } else { - $pgtypes[] = 'text'; - } - } - if (($key_parameter = array_search($name, $positions))) { - $next_parameter = 1; - foreach ($positions as $key => $value) { - if ($key_parameter == $key) { - break; - } - ++$next_parameter; - } - } else { - ++$parameter; - $next_parameter = $parameter; - $positions[] = $name; - } - $query = substr_replace($query, '$'.$parameter, $position, $length); - $position = $p_position + strlen($parameter); - } else { - $position = $p_position; - } - } - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - static $prep_statement_counter = 1; - $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand())); - $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']); - if ($pgtypes === false) { - $result = @pg_prepare($connection, $statement_name, $query); - if (!$result) { - $err =& $this->raiseError(null, null, null, - 'Unable to create prepared statement handle', __FUNCTION__); - return $err; - } - } else { - $types_string = ''; - if ($pgtypes) { - $types_string = ' ('.implode(', ', $pgtypes).') '; - } - $query = 'PREPARE '.$statement_name.$types_string.' AS '.$query; - $statement =& $this->_doQuery($query, true, $connection); - if (PEAR::isError($statement)) { - return $statement; - } - } - - $class_name = 'MDB2_Statement_'.$this->phptype; - $obj = new $class_name($this, $statement_name, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); - $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj)); - return $obj; - } - - // }}} - // {{{ function getSequenceName($sqn) - - /** - * adds sequence name formatting to a sequence name - * - * @param string name of the sequence - * - * @return string formatted sequence name - * - * @access public - */ - function getSequenceName($sqn) - { - if (false === $this->options['disable_smart_seqname']) { - if (strpos($sqn, '_') !== false) { - list($table, $field) = explode('_', $sqn, 2); - } - $schema_list = $this->queryOne("SELECT array_to_string(current_schemas(false), ',')"); - if (PEAR::isError($schema_list) || empty($schema_list) || count($schema_list) < 2) { - $order_by = ' a.attnum'; - $schema_clause = ' AND n.nspname=current_schema()'; - } else { - $schemas = explode(',', $schema_list); - $schema_clause = ' AND n.nspname IN ('.$schema_list.')'; - $counter = 1; - $order_by = ' CASE '; - foreach ($schemas as $schema) { - $order_by .= ' WHEN n.nspname='.$schema.' THEN '.$counter++; - } - $order_by .= ' ELSE '.$counter.' END, a.attnum'; - } - - $query = "SELECT substring((SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128) - FROM pg_attrdef d - WHERE d.adrelid = a.attrelid - AND d.adnum = a.attnum - AND a.atthasdef - ) FROM 'nextval[^'']*''([^'']*)') - FROM pg_attribute a - LEFT JOIN pg_class c ON c.oid = a.attrelid - LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef - LEFT JOIN pg_namespace n ON c.relnamespace = n.oid - WHERE (c.relname = ".$this->quote($sqn, 'text'); - if (!empty($field)) { - $query .= " OR (c.relname = ".$this->quote($table, 'text')." AND a.attname = ".$this->quote($field, 'text').")"; - } - $query .= " )" - .$schema_clause." - AND NOT a.attisdropped - AND a.attnum > 0 - AND pg_get_expr(d.adbin, d.adrelid) LIKE 'nextval%' - ORDER BY ".$order_by; - $seqname = $this->queryOne($query); - if (!PEAR::isError($seqname) && !empty($seqname) && is_string($seqname)) { - return $seqname; - } - } - - return parent::getSequenceName($sqn); - } - - // }}} - // {{{ nextID() - - /** - * Returns the next free id of a sequence - * - * @param string $seq_name name of the sequence - * @param boolean $ondemand when true the sequence is - * automatic created, if it - * not exists - * @return mixed MDB2 Error Object or id - * @access public - */ - function nextID($seq_name, $ondemand = true) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - $query = "SELECT NEXTVAL('$sequence_name')"; - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->expectError(MDB2_ERROR_NOSUCHTABLE); - $result = $this->queryOne($query, 'integer'); - $this->popExpect(); - $this->popErrorHandling(); - if (PEAR::isError($result)) { - if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { - $this->loadModule('Manager', null, true); - $result = $this->manager->createSequence($seq_name); - if (PEAR::isError($result)) { - return $this->raiseError($result, null, null, - 'on demand sequence could not be created', __FUNCTION__); - } - return $this->nextId($seq_name, false); - } - } - return $result; - } - - // }}} - // {{{ lastInsertID() - - /** - * Returns the autoincrement ID if supported or $id or fetches the current - * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) - * - * @param string $table name of the table into which a new row was inserted - * @param string $field name of the field into which a new row was inserted - * @return mixed MDB2 Error Object or id - * @access public - */ - function lastInsertID($table = null, $field = null) - { - if (empty($table) && empty($field)) { - return $this->queryOne('SELECT lastval()', 'integer'); - } - $seq = $table.(empty($field) ? '' : '_'.$field); - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq), true); - return $this->queryOne("SELECT currval('$sequence_name')", 'integer'); - } - - // }}} - // {{{ currID() - - /** - * Returns the current id of a sequence - * - * @param string $seq_name name of the sequence - * @return mixed MDB2 Error Object or id - * @access public - */ - function currID($seq_name) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - return $this->queryOne("SELECT last_value FROM $sequence_name", 'integer'); - } -} - -/** - * MDB2 PostGreSQL result driver - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Result_pgsql extends MDB2_Result_Common -{ - // }}} - // {{{ fetchRow() - - /** - * Fetch a row and insert the data into an existing array. - * - * @param int $fetchmode how the array data should be indexed - * @param int $rownum number of the row where the data can be found - * @return int data array on success, a MDB2 error on failure - * @access public - */ - function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) - { - if (!is_null($rownum)) { - $seek = $this->seek($rownum); - if (PEAR::isError($seek)) { - return $seek; - } - } - if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { - $fetchmode = $this->db->fetchmode; - } - if ($fetchmode & MDB2_FETCHMODE_ASSOC) { - $row = @pg_fetch_array($this->result, null, PGSQL_ASSOC); - if (is_array($row) - && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE - ) { - $row = array_change_key_case($row, $this->db->options['field_case']); - } - } else { - $row = @pg_fetch_row($this->result); - } - if (!$row) { - if ($this->result === false) { - $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - return $err; - } - $null = null; - return $null; - } - $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL; - $rtrim = false; - if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { - if (empty($this->types)) { - $mode += MDB2_PORTABILITY_RTRIM; - } else { - $rtrim = true; - } - } - if ($mode) { - $this->db->_fixResultArrayValues($row, $mode); - } - if (!empty($this->types)) { - $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim); - } - if (!empty($this->values)) { - $this->_assignBindColumns($row); - } - if ($fetchmode === MDB2_FETCHMODE_OBJECT) { - $object_class = $this->db->options['fetch_class']; - if ($object_class == 'stdClass') { - $row = (object) $row; - } else { - $row = new $object_class($row); - } - } - ++$this->rownum; - return $row; - } - - // }}} - // {{{ _getColumnNames() - - /** - * Retrieve the names of columns returned by the DBMS in a query result. - * - * @return mixed Array variable that holds the names of columns as keys - * or an MDB2 error on failure. - * Some DBMS may not return any columns when the result set - * does not contain any rows. - * @access private - */ - function _getColumnNames() - { - $columns = array(); - $numcols = $this->numCols(); - if (PEAR::isError($numcols)) { - return $numcols; - } - for ($column = 0; $column < $numcols; $column++) { - $column_name = @pg_field_name($this->result, $column); - $columns[$column_name] = $column; - } - if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $columns = array_change_key_case($columns, $this->db->options['field_case']); - } - return $columns; - } - - // }}} - // {{{ numCols() - - /** - * Count the number of columns returned by the DBMS in a query result. - * - * @access public - * @return mixed integer value with the number of columns, a MDB2 error - * on failure - */ - function numCols() - { - $cols = @pg_num_fields($this->result); - if (is_null($cols)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return count($this->types); - } - return $this->db->raiseError(null, null, null, - 'Could not get column count', __FUNCTION__); - } - return $cols; - } - - // }}} - // {{{ nextResult() - - /** - * Move the internal result pointer to the next available result - * - * @return true on success, false if there is no more result set or an error object on failure - * @access public - */ - function nextResult() - { - $connection = $this->db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - if (!($this->result = @pg_get_result($connection))) { - return false; - } - return MDB2_OK; - } - - // }}} - // {{{ free() - - /** - * Free the internal resources associated with result. - * - * @return boolean true on success, false if result is invalid - * @access public - */ - function free() - { - if (is_resource($this->result) && $this->db->connection) { - $free = @pg_free_result($this->result); - if ($free === false) { - return $this->db->raiseError(null, null, null, - 'Could not free result', __FUNCTION__); - } - } - $this->result = false; - return MDB2_OK; - } -} - -/** - * MDB2 PostGreSQL buffered result driver - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_BufferedResult_pgsql extends MDB2_Result_pgsql -{ - // {{{ seek() - - /** - * Seek to a specific row in a result set - * - * @param int $rownum number of the row where the data can be found - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function seek($rownum = 0) - { - if ($this->rownum != ($rownum - 1) && !@pg_result_seek($this->result, $rownum)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return MDB2_OK; - } - return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, - 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__); - } - $this->rownum = $rownum - 1; - return MDB2_OK; - } - - // }}} - // {{{ 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 - */ - function valid() - { - $numrows = $this->numRows(); - if (PEAR::isError($numrows)) { - return $numrows; - } - return $this->rownum < ($numrows - 1); - } - - // }}} - // {{{ numRows() - - /** - * Returns the number of rows in a result object - * - * @return mixed MDB2 Error Object or the number of rows - * @access public - */ - function numRows() - { - $rows = @pg_num_rows($this->result); - if (is_null($rows)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return 0; - } - return $this->db->raiseError(null, null, null, - 'Could not get row count', __FUNCTION__); - } - return $rows; - } -} - -/** - * MDB2 PostGreSQL statement driver - * - * @package MDB2 - * @category Database - * @author Paul Cooper <pgc@ucecom.com> - */ -class MDB2_Statement_pgsql extends MDB2_Statement_Common -{ - // {{{ _execute() - - /** - * Execute a prepared query statement helper method. - * - * @param mixed $result_class string which specifies which result class to use - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * - * @return mixed MDB2_Result or integer (affected rows) on success, - * a MDB2 error on failure - * @access private - */ - function &_execute($result_class = true, $result_wrap_class = false) - { - if (is_null($this->statement)) { - $result =& parent::_execute($result_class, $result_wrap_class); - return $result; - } - $this->db->last_query = $this->query; - $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values)); - if ($this->db->getOption('disable_query')) { - $result = $this->is_manip ? 0 : null; - return $result; - } - - $connection = $this->db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $query = false; - $parameters = array(); - // todo: disabled until pg_execute() bytea issues are cleared up - if (true || !function_exists('pg_execute')) { - $query = 'EXECUTE '.$this->statement; - } - if (!empty($this->positions)) { - foreach ($this->positions as $parameter) { - if (!array_key_exists($parameter, $this->values)) { - return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); - } - $value = $this->values[$parameter]; - $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; - if (is_resource($value) || $type == 'clob' || $type == 'blob' || $this->db->options['lob_allow_url_include']) { - if (!is_resource($value) && preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { - if ($match[1] == 'file://') { - $value = $match[2]; - } - $value = @fopen($value, 'r'); - $close = true; - } - if (is_resource($value)) { - $data = ''; - while (!@feof($value)) { - $data.= @fread($value, $this->db->options['lob_buffer_length']); - } - if ($close) { - @fclose($value); - } - $value = $data; - } - } - $quoted = $this->db->quote($value, $type, $query); - if (PEAR::isError($quoted)) { - return $quoted; - } - $parameters[] = $quoted; - } - if ($query) { - $query.= ' ('.implode(', ', $parameters).')'; - } - } - - if (!$query) { - $result = @pg_execute($connection, $this->statement, $parameters); - if (!$result) { - $err =& $this->db->raiseError(null, null, null, - 'Unable to execute statement', __FUNCTION__); - return $err; - } - } else { - $result = $this->db->_doQuery($query, $this->is_manip, $connection); - if (PEAR::isError($result)) { - return $result; - } - } - - if ($this->is_manip) { - $affected_rows = $this->db->_affectedRows($connection, $result); - return $affected_rows; - } - - $result =& $this->db->_wrapResult($result, $this->result_types, - $result_class, $result_wrap_class, $this->limit, $this->offset); - $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result)); - return $result; - } - - // }}} - // {{{ free() - - /** - * Release resources allocated for the specified prepared query. - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function free() - { - if (is_null($this->positions)) { - return $this->db->raiseError(MDB2_ERROR, null, null, - 'Prepared statement has already been freed', __FUNCTION__); - } - $result = MDB2_OK; - - if (!is_null($this->statement)) { - $connection = $this->db->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - $query = 'DEALLOCATE PREPARE '.$this->statement; - $result = $this->db->_doQuery($query, true, $connection); - } - - parent::free(); - return $result; - } -} +<?php
+// vim: set et ts=4 sw=4 fdm=marker:
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Paul Cooper <pgc@ucecom.com> |
+// +----------------------------------------------------------------------+
+//
+// $Id: pgsql.php 295587 2010-02-28 17:16:38Z quipo $
+
+/**
+ * MDB2 PostGreSQL driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Driver_pgsql extends MDB2_Driver_Common
+{
+ // {{{ properties
+ var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => '\\');
+
+ var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');
+ // }}}
+ // {{{ constructor
+
+ /**
+ * Constructor
+ */
+ function __construct()
+ {
+ parent::__construct();
+
+ $this->phptype = 'pgsql';
+ $this->dbsyntax = 'pgsql';
+
+ $this->supported['sequences'] = true;
+ $this->supported['indexes'] = true;
+ $this->supported['affected_rows'] = true;
+ $this->supported['summary_functions'] = true;
+ $this->supported['order_by_text'] = true;
+ $this->supported['transactions'] = true;
+ $this->supported['savepoints'] = true;
+ $this->supported['current_id'] = true;
+ $this->supported['limit_queries'] = true;
+ $this->supported['LOBs'] = true;
+ $this->supported['replace'] = 'emulated';
+ $this->supported['sub_selects'] = true;
+ $this->supported['triggers'] = true;
+ $this->supported['auto_increment'] = 'emulated';
+ $this->supported['primary_key'] = true;
+ $this->supported['result_introspection'] = true;
+ $this->supported['prepared_statements'] = true;
+ $this->supported['identifier_quoting'] = true;
+ $this->supported['pattern_escaping'] = true;
+ $this->supported['new_link'] = true;
+
+ $this->options['DBA_username'] = false;
+ $this->options['DBA_password'] = false;
+ $this->options['multi_query'] = false;
+ $this->options['disable_smart_seqname'] = true;
+ $this->options['max_identifiers_length'] = 63;
+ }
+
+ // }}}
+ // {{{ errorInfo()
+
+ /**
+ * This method is used to collect information about an error
+ *
+ * @param integer $error
+ * @return array
+ * @access public
+ */
+ function errorInfo($error = null)
+ {
+ // Fall back to MDB2_ERROR if there was no mapping.
+ $error_code = MDB2_ERROR;
+
+ $native_msg = '';
+ if (is_resource($error)) {
+ $native_msg = @pg_result_error($error);
+ } elseif ($this->connection) {
+ $native_msg = @pg_last_error($this->connection);
+ if (!$native_msg && @pg_connection_status($this->connection) === PGSQL_CONNECTION_BAD) {
+ $native_msg = 'Database connection has been lost.';
+ $error_code = MDB2_ERROR_CONNECT_FAILED;
+ }
+ } else {
+ $native_msg = @pg_last_error();
+ }
+
+ static $error_regexps;
+ if (empty($error_regexps)) {
+ $error_regexps = array(
+ '/column .* (of relation .*)?does not exist/i'
+ => MDB2_ERROR_NOSUCHFIELD,
+ '/(relation|sequence|table).*does not exist|class .* not found/i'
+ => MDB2_ERROR_NOSUCHTABLE,
+ '/database .* does not exist/'
+ => MDB2_ERROR_NOT_FOUND,
+ '/constraint .* does not exist/'
+ => MDB2_ERROR_NOT_FOUND,
+ '/index .* does not exist/'
+ => MDB2_ERROR_NOT_FOUND,
+ '/database .* already exists/i'
+ => MDB2_ERROR_ALREADY_EXISTS,
+ '/relation .* already exists/i'
+ => MDB2_ERROR_ALREADY_EXISTS,
+ '/(divide|division) by zero$/i'
+ => MDB2_ERROR_DIVZERO,
+ '/pg_atoi: error in .*: can\'t parse /i'
+ => MDB2_ERROR_INVALID_NUMBER,
+ '/invalid input syntax for( type)? (integer|numeric)/i'
+ => MDB2_ERROR_INVALID_NUMBER,
+ '/value .* is out of range for type \w*int/i'
+ => MDB2_ERROR_INVALID_NUMBER,
+ '/integer out of range/i'
+ => MDB2_ERROR_INVALID_NUMBER,
+ '/value too long for type character/i'
+ => MDB2_ERROR_INVALID,
+ '/attribute .* not found|relation .* does not have attribute/i'
+ => MDB2_ERROR_NOSUCHFIELD,
+ '/column .* specified in USING clause does not exist in (left|right) table/i'
+ => MDB2_ERROR_NOSUCHFIELD,
+ '/parser: parse error at or near/i'
+ => MDB2_ERROR_SYNTAX,
+ '/syntax error at/'
+ => MDB2_ERROR_SYNTAX,
+ '/column reference .* is ambiguous/i'
+ => MDB2_ERROR_SYNTAX,
+ '/permission denied/'
+ => MDB2_ERROR_ACCESS_VIOLATION,
+ '/violates not-null constraint/'
+ => MDB2_ERROR_CONSTRAINT_NOT_NULL,
+ '/violates [\w ]+ constraint/'
+ => MDB2_ERROR_CONSTRAINT,
+ '/referential integrity violation/'
+ => MDB2_ERROR_CONSTRAINT,
+ '/more expressions than target columns/i'
+ => MDB2_ERROR_VALUE_COUNT_ON_ROW,
+ );
+ }
+ if (is_numeric($error) && $error < 0) {
+ $error_code = $error;
+ } else {
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $native_msg)) {
+ $error_code = $code;
+ break;
+ }
+ }
+ }
+ return array($error_code, null, $native_msg);
+ }
+
+ // }}}
+ // {{{ escape()
+
+ /**
+ * Quotes a string so it can be safely used in a query. It will quote
+ * the text so it can safely be used within a query.
+ *
+ * @param string the input string to quote
+ * @param bool escape wildcards
+ *
+ * @return string quoted string
+ *
+ * @access public
+ */
+ function escape($text, $escape_wildcards = false)
+ {
+ if ($escape_wildcards) {
+ $text = $this->escapePattern($text);
+ }
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ if (is_resource($connection) && version_compare(PHP_VERSION, '5.2.0RC5', '>=')) {
+ $text = @pg_escape_string($connection, $text);
+ } else {
+ $text = @pg_escape_string($text);
+ }
+ return $text;
+ }
+
+ // }}}
+ // {{{ beginTransaction()
+
+ /**
+ * Start a transaction or set a savepoint.
+ *
+ * @param string name of a savepoint to set
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function beginTransaction($savepoint = null)
+ {
+ $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (null !== $savepoint) {
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'savepoint cannot be released when changes are auto committed', __FUNCTION__);
+ }
+ $query = 'SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ }
+ if ($this->in_transaction) {
+ return MDB2_OK; //nothing to do
+ }
+ if (!$this->destructor_registered && $this->opened_persistent) {
+ $this->destructor_registered = true;
+ register_shutdown_function('MDB2_closeOpenTransactions');
+ }
+ $result = $this->_doQuery('BEGIN', true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = true;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ commit()
+
+ /**
+ * Commit the database changes done during a transaction that is in
+ * progress or release a savepoint. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after committing the pending changes.
+ *
+ * @param string name of a savepoint to release
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function commit($savepoint = null)
+ {
+ $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (null !== $savepoint) {
+ $query = 'RELEASE SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ }
+
+ $result = $this->_doQuery('COMMIT', true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ rollback()
+
+ /**
+ * Cancel any database changes done during a transaction or since a specific
+ * savepoint that is in progress. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after canceling the pending changes.
+ *
+ * @param string name of a savepoint to rollback to
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function rollback($savepoint = null)
+ {
+ $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'rollback cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (null !== $savepoint) {
+ $query = 'ROLLBACK TO SAVEPOINT '.$savepoint;
+ return $this->_doQuery($query, true);
+ }
+
+ $query = 'ROLLBACK';
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ function setTransactionIsolation()
+
+ /**
+ * Set the transacton isolation level.
+ *
+ * @param string standard isolation level
+ * READ UNCOMMITTED (allows dirty reads)
+ * READ COMMITTED (prevents dirty reads)
+ * REPEATABLE READ (prevents nonrepeatable reads)
+ * SERIALIZABLE (prevents phantom reads)
+ * @param array some transaction options:
+ * 'wait' => 'WAIT' | 'NO WAIT'
+ * 'rw' => 'READ WRITE' | 'READ ONLY'
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ * @since 2.1.1
+ */
+ function setTransactionIsolation($isolation, $options = array())
+ {
+ $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
+ switch ($isolation) {
+ case 'READ UNCOMMITTED':
+ case 'READ COMMITTED':
+ case 'REPEATABLE READ':
+ case 'SERIALIZABLE':
+ break;
+ default:
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'isolation level is not supported: '.$isolation, __FUNCTION__);
+ }
+
+ $query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL $isolation";
+ return $this->_doQuery($query, true);
+ }
+
+ // }}}
+ // {{{ _doConnect()
+
+ /**
+ * Do the grunt work of connecting to the database
+ *
+ * @return mixed connection resource on success, MDB2 Error Object on failure
+ * @access protected
+ */
+ function _doConnect($username, $password, $database_name, $persistent = false)
+ {
+ if (!PEAR::loadExtension($this->phptype)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
+ }
+
+ if ($database_name == '') {
+ $database_name = 'template1';
+ }
+
+ $protocol = $this->dsn['protocol'] ? $this->dsn['protocol'] : 'tcp';
+
+ $params = array('');
+ if ($protocol == 'tcp') {
+ if ($this->dsn['hostspec']) {
+ $params[0].= 'host=' . $this->dsn['hostspec'];
+ }
+ if ($this->dsn['port']) {
+ $params[0].= ' port=' . $this->dsn['port'];
+ }
+ } elseif ($protocol == 'unix') {
+ // Allow for pg socket in non-standard locations.
+ if ($this->dsn['socket']) {
+ $params[0].= 'host=' . $this->dsn['socket'];
+ }
+ if ($this->dsn['port']) {
+ $params[0].= ' port=' . $this->dsn['port'];
+ }
+ }
+ if ($database_name) {
+ $params[0].= ' dbname=\'' . addslashes($database_name) . '\'';
+ }
+ if ($username) {
+ $params[0].= ' user=\'' . addslashes($username) . '\'';
+ }
+ if ($password) {
+ $params[0].= ' password=\'' . addslashes($password) . '\'';
+ }
+ if (!empty($this->dsn['options'])) {
+ $params[0].= ' options=' . $this->dsn['options'];
+ }
+ if (!empty($this->dsn['tty'])) {
+ $params[0].= ' tty=' . $this->dsn['tty'];
+ }
+ if (!empty($this->dsn['connect_timeout'])) {
+ $params[0].= ' connect_timeout=' . $this->dsn['connect_timeout'];
+ }
+ if (!empty($this->dsn['sslmode'])) {
+ $params[0].= ' sslmode=' . $this->dsn['sslmode'];
+ }
+ if (!empty($this->dsn['service'])) {
+ $params[0].= ' service=' . $this->dsn['service'];
+ }
+
+ if ($this->_isNewLinkSet()) {
+ if (version_compare(phpversion(), '4.3.0', '>=')) {
+ $params[] = PGSQL_CONNECT_FORCE_NEW;
+ }
+ }
+
+ $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
+ $connection = @call_user_func_array($connect_function, $params);
+ if (!$connection) {
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
+ 'unable to establish a connection', __FUNCTION__);
+ }
+
+ if (empty($this->dsn['disable_iso_date'])) {
+ if (!@pg_query($connection, "SET SESSION DATESTYLE = 'ISO'")) {
+ return $this->raiseError(null, null, null,
+ 'Unable to set date style to iso', __FUNCTION__);
+ }
+ }
+
+ if (!empty($this->dsn['charset'])) {
+ $result = $this->setCharset($this->dsn['charset'], $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+
+ // Enable extra compatibility settings on 8.2 and later
+ if (function_exists('pg_parameter_status')) {
+ $version = pg_parameter_status($connection, 'server_version');
+ if ($version == false) {
+ return $this->raiseError(null, null, null,
+ 'Unable to retrieve server version', __FUNCTION__);
+ }
+ $version = explode ('.', $version);
+ if ( $version['0'] > 8
+ || ($version['0'] == 8 && $version['1'] >= 2)
+ ) {
+ if (!@pg_query($connection, "SET SESSION STANDARD_CONFORMING_STRINGS = OFF")) {
+ return $this->raiseError(null, null, null,
+ 'Unable to set standard_conforming_strings to off', __FUNCTION__);
+ }
+
+ if (!@pg_query($connection, "SET SESSION ESCAPE_STRING_WARNING = OFF")) {
+ return $this->raiseError(null, null, null,
+ 'Unable to set escape_string_warning to off', __FUNCTION__);
+ }
+ }
+ }
+
+ return $connection;
+ }
+
+ // }}}
+ // {{{ connect()
+
+ /**
+ * Connect to the database
+ *
+ * @return true on success, MDB2 Error Object on failure
+ * @access public
+ */
+ function connect()
+ {
+ if (is_resource($this->connection)) {
+ //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
+ if (MDB2::areEquals($this->connected_dsn, $this->dsn)
+ && $this->connected_database_name == $this->database_name
+ && ($this->opened_persistent == $this->options['persistent'])
+ ) {
+ return MDB2_OK;
+ }
+ $this->disconnect(false);
+ }
+
+ if ($this->database_name) {
+ $connection = $this->_doConnect($this->dsn['username'],
+ $this->dsn['password'],
+ $this->database_name,
+ $this->options['persistent']);
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $this->connection = $connection;
+ $this->connected_dsn = $this->dsn;
+ $this->connected_database_name = $this->database_name;
+ $this->opened_persistent = $this->options['persistent'];
+ $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
+ }
+
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ setCharset()
+
+ /**
+ * Set the charset on the current connection
+ *
+ * @param string charset
+ * @param resource connection handle
+ *
+ * @return true on success, MDB2 Error Object on failure
+ */
+ function setCharset($charset, $connection = null)
+ {
+ if (null === $connection) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ if (is_array($charset)) {
+ $charset = array_shift($charset);
+ $this->warnings[] = 'postgresql does not support setting client collation';
+ }
+ $result = @pg_set_client_encoding($connection, $charset);
+ if ($result == -1) {
+ return $this->raiseError(null, null, null,
+ 'Unable to set client charset: '.$charset, __FUNCTION__);
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ databaseExists()
+
+ /**
+ * check if given database name is exists?
+ *
+ * @param string $name name of the database that should be checked
+ *
+ * @return mixed true/false on success, a MDB2 error on failure
+ * @access public
+ */
+ function databaseExists($name)
+ {
+ $res = $this->_doConnect($this->dsn['username'],
+ $this->dsn['password'],
+ $this->escape($name),
+ $this->options['persistent']);
+ if (!PEAR::isError($res)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // }}}
+ // {{{ disconnect()
+
+ /**
+ * Log out and disconnect from the database.
+ *
+ * @param boolean $force if the disconnect should be forced even if the
+ * connection is opened persistently
+ * @return mixed true on success, false if not connected and error
+ * object on error
+ * @access public
+ */
+ function disconnect($force = true)
+ {
+ if (is_resource($this->connection)) {
+ if ($this->in_transaction) {
+ $dsn = $this->dsn;
+ $database_name = $this->database_name;
+ $persistent = $this->options['persistent'];
+ $this->dsn = $this->connected_dsn;
+ $this->database_name = $this->connected_database_name;
+ $this->options['persistent'] = $this->opened_persistent;
+ $this->rollback();
+ $this->dsn = $dsn;
+ $this->database_name = $database_name;
+ $this->options['persistent'] = $persistent;
+ }
+
+ if (!$this->opened_persistent || $force) {
+ $ok = @pg_close($this->connection);
+ if (!$ok) {
+ return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED,
+ null, null, null, __FUNCTION__);
+ }
+ }
+ } else {
+ return false;
+ }
+ return parent::disconnect($force);
+ }
+
+ // }}}
+ // {{{ standaloneQuery()
+
+ /**
+ * execute a query as DBA
+ *
+ * @param string $query the SQL query
+ * @param mixed $types array that contains the types of the columns in
+ * the result set
+ * @param boolean $is_manip if the query is a manipulation query
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function standaloneQuery($query, $types = null, $is_manip = false)
+ {
+ $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
+ $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
+ $connection = $this->_doConnect($user, $pass, $this->database_name, $this->options['persistent']);
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $offset = $this->offset;
+ $limit = $this->limit;
+ $this->offset = $this->limit = 0;
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
+
+ $result = $this->_doQuery($query, $is_manip, $connection, $this->database_name);
+ if (!PEAR::isError($result)) {
+ if ($is_manip) {
+ $result = $this->_affectedRows($connection, $result);
+ } else {
+ $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset);
+ }
+ }
+
+ @pg_close($connection);
+ return $result;
+ }
+
+ // }}}
+ // {{{ _doQuery()
+
+ /**
+ * Execute a query
+ * @param string $query query
+ * @param boolean $is_manip if the query is a manipulation query
+ * @param resource $connection
+ * @param string $database_name
+ * @return result or error object
+ * @access protected
+ */
+ function _doQuery($query, $is_manip = false, $connection = null, $database_name = null)
+ {
+ $this->last_query = $query;
+ $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
+ if ($result) {
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = $result;
+ }
+ if ($this->options['disable_query']) {
+ $result = $is_manip ? 0 : null;
+ return $result;
+ }
+
+ if (null === $connection) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+
+ $function = $this->options['multi_query'] ? 'pg_send_query' : 'pg_query';
+ $result = @$function($connection, $query);
+ if (!$result) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not execute statement', __FUNCTION__);
+ return $err;
+ } elseif ($this->options['multi_query']) {
+ if (!($result = @pg_get_result($connection))) {
+ $err = $this->raiseError(null, null, null,
+ 'Could not get the first result from a multi query', __FUNCTION__);
+ return $err;
+ }
+ }
+
+ $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result));
+ return $result;
+ }
+
+ // }}}
+ // {{{ _affectedRows()
+
+ /**
+ * Returns the number of rows affected
+ *
+ * @param resource $result
+ * @param resource $connection
+ * @return mixed MDB2 Error Object or the number of rows affected
+ * @access private
+ */
+ function _affectedRows($connection, $result = null)
+ {
+ if (null === $connection) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ return @pg_affected_rows($result);
+ }
+
+ // }}}
+ // {{{ _modifyQuery()
+
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * @param string $query query to modify
+ * @param boolean $is_manip if it is a DML query
+ * @param integer $limit limit the number of rows
+ * @param integer $offset start reading from given offset
+ * @return string modified query
+ * @access protected
+ */
+ function _modifyQuery($query, $is_manip, $limit, $offset)
+ {
+ if ($limit > 0
+ && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query)
+ ) {
+ $query = rtrim($query);
+ if (substr($query, -1) == ';') {
+ $query = substr($query, 0, -1);
+ }
+ if ($is_manip) {
+ $query = $this->_modifyManipQuery($query, $limit);
+ } else {
+ $query.= " LIMIT $limit OFFSET $offset";
+ }
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ _modifyManipQuery()
+
+ /**
+ * Changes a manip query string for various DBMS specific reasons
+ *
+ * @param string $query query to modify
+ * @param integer $limit limit the number of rows
+ * @return string modified query
+ * @access protected
+ */
+ function _modifyManipQuery($query, $limit)
+ {
+ $pos = strpos(strtolower($query), 'where');
+ $where = $pos ? substr($query, $pos) : '';
+
+ $manip_clause = '(\bDELETE\b\s+(?:\*\s+)?\bFROM\b|\bUPDATE\b)';
+ $from_clause = '([\w\.]+)';
+ $where_clause = '(?:(.*)\bWHERE\b\s+(.*))|(.*)';
+ $pattern = '/^'. $manip_clause . '\s+' . $from_clause .'(?:\s)*(?:'. $where_clause .')?$/i';
+ $matches = preg_match($pattern, $query, $match);
+ if ($matches) {
+ $manip = $match[1];
+ $from = $match[2];
+ $what = (count($matches) == 6) ? $match[5] : $match[3];
+ return $manip.' '.$from.' '.$what.' WHERE ctid=(SELECT ctid FROM '.$from.' '.$where.' LIMIT '.$limit.')';
+ }
+ //return error?
+ return $query;
+ }
+
+ // }}}
+ // {{{ getServerVersion()
+
+ /**
+ * return version information about the server
+ *
+ * @param bool $native determines if the raw version string should be returned
+ * @return mixed array/string with version information or MDB2 error object
+ * @access public
+ */
+ function getServerVersion($native = false)
+ {
+ $query = 'SHOW SERVER_VERSION';
+ if ($this->connected_server_info) {
+ $server_info = $this->connected_server_info;
+ } else {
+ $server_info = $this->queryOne($query, 'text');
+ if (PEAR::isError($server_info)) {
+ return $server_info;
+ }
+ }
+ // cache server_info
+ $this->connected_server_info = $server_info;
+ if (!$native && !PEAR::isError($server_info)) {
+ $tmp = explode('.', $server_info, 3);
+ if (empty($tmp[2])
+ && isset($tmp[1])
+ && preg_match('/(\d+)(.*)/', $tmp[1], $tmp2)
+ ) {
+ $server_info = array(
+ 'major' => $tmp[0],
+ 'minor' => $tmp2[1],
+ 'patch' => null,
+ 'extra' => $tmp2[2],
+ 'native' => $server_info,
+ );
+ } else {
+ $server_info = array(
+ 'major' => isset($tmp[0]) ? $tmp[0] : null,
+ 'minor' => isset($tmp[1]) ? $tmp[1] : null,
+ 'patch' => isset($tmp[2]) ? $tmp[2] : null,
+ 'extra' => null,
+ 'native' => $server_info,
+ );
+ }
+ }
+ return $server_info;
+ }
+
+ // }}}
+ // {{{ prepare()
+
+ /**
+ * Prepares a query for multiple execution with execute().
+ * With some database backends, this is emulated.
+ * prepare() requires a generic query as string like
+ * 'INSERT INTO numbers VALUES(?,?)' or
+ * 'INSERT INTO numbers VALUES(:foo,:bar)'.
+ * The ? and :name and are placeholders which can be set using
+ * bindParam() and the query can be sent off using the execute() method.
+ * The allowed format for :name can be set with the 'bindname_format' option.
+ *
+ * @param string $query the query to prepare
+ * @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 or MDB2_PREPARE_RESULT, if set to
+ * MDB2_PREPARE_MANIP the query is handled as a manipulation query
+ * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders
+ * @return mixed resource handle for the prepared query on success, a MDB2
+ * error on failure
+ * @access public
+ * @see bindParam, execute
+ */
+ function prepare($query, $types = null, $result_types = null, $lobs = array())
+ {
+ if ($this->options['emulate_prepared']) {
+ return parent::prepare($query, $types, $result_types, $lobs);
+ }
+ $is_manip = ($result_types === MDB2_PREPARE_MANIP);
+ $offset = $this->offset;
+ $limit = $this->limit;
+ $this->offset = $this->limit = 0;
+ $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
+ if ($result) {
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = $result;
+ }
+ $pgtypes = function_exists('pg_prepare') ? false : array();
+ if ($pgtypes !== false && !empty($types)) {
+ $this->loadModule('Datatype', null, true);
+ }
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
+ $placeholder_type_guess = $placeholder_type = null;
+ $question = '?';
+ $colon = ':';
+ $positions = array();
+ $position = $parameter = 0;
+ while ($position < strlen($query)) {
+ $q_position = strpos($query, $question, $position);
+ $c_position = strpos($query, $colon, $position);
+ //skip "::type" cast ("select id::varchar(20) from sometable where name=?")
+ $doublecolon_position = strpos($query, '::', $position);
+ if ($doublecolon_position !== false && $doublecolon_position == $c_position) {
+ $c_position = strpos($query, $colon, $position+2);
+ }
+ if ($q_position && $c_position) {
+ $p_position = min($q_position, $c_position);
+ } elseif ($q_position) {
+ $p_position = $q_position;
+ } elseif ($c_position) {
+ $p_position = $c_position;
+ } else {
+ break;
+ }
+ if (null === $placeholder_type) {
+ $placeholder_type_guess = $query[$p_position];
+ }
+
+ $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
+ if (PEAR::isError($new_pos)) {
+ return $new_pos;
+ }
+ if ($new_pos != $position) {
+ $position = $new_pos;
+ continue; //evaluate again starting from the new position
+ }
+
+ if ($query[$position] == $placeholder_type_guess) {
+ if (null === $placeholder_type) {
+ $placeholder_type = $query[$p_position];
+ $question = $colon = $placeholder_type;
+ if (!empty($types) && is_array($types)) {
+ if ($placeholder_type == ':') {
+ } else {
+ $types = array_values($types);
+ }
+ }
+ }
+ if ($placeholder_type_guess == '?') {
+ $length = 1;
+ $name = $parameter;
+ } else {
+ $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s';
+ $param = preg_replace($regexp, '\\1', $query);
+ if ($param === '') {
+ $err = $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
+ 'named parameter name must match "bindname_format" option', __FUNCTION__);
+ return $err;
+ }
+ $length = strlen($param) + 1;
+ $name = $param;
+ }
+ if ($pgtypes !== false) {
+ if (is_array($types) && array_key_exists($name, $types)) {
+ $pgtypes[] = $this->datatype->mapPrepareDatatype($types[$name]);
+ } elseif (is_array($types) && array_key_exists($parameter, $types)) {
+ $pgtypes[] = $this->datatype->mapPrepareDatatype($types[$parameter]);
+ } else {
+ $pgtypes[] = 'text';
+ }
+ }
+ if (($key_parameter = array_search($name, $positions))) {
+ $next_parameter = 1;
+ foreach ($positions as $key => $value) {
+ if ($key_parameter == $key) {
+ break;
+ }
+ ++$next_parameter;
+ }
+ } else {
+ ++$parameter;
+ $next_parameter = $parameter;
+ $positions[] = $name;
+ }
+ $query = substr_replace($query, '$'.$parameter, $position, $length);
+ $position = $p_position + strlen($parameter);
+ } else {
+ $position = $p_position;
+ }
+ }
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ static $prep_statement_counter = 1;
+ $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand()));
+ $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']);
+ if (false === $pgtypes) {
+ $result = @pg_prepare($connection, $statement_name, $query);
+ if (!$result) {
+ $err = $this->raiseError(null, null, null,
+ 'Unable to create prepared statement handle', __FUNCTION__);
+ return $err;
+ }
+ } else {
+ $types_string = '';
+ if ($pgtypes) {
+ $types_string = ' ('.implode(', ', $pgtypes).') ';
+ }
+ $query = 'PREPARE '.$statement_name.$types_string.' AS '.$query;
+ $statement = $this->_doQuery($query, true, $connection);
+ if (PEAR::isError($statement)) {
+ return $statement;
+ }
+ }
+
+ $class_name = 'MDB2_Statement_'.$this->phptype;
+ $obj = new $class_name($this, $statement_name, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
+ $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
+ return $obj;
+ }
+
+ // }}}
+ // {{{ function getSequenceName($sqn)
+
+ /**
+ * adds sequence name formatting to a sequence name
+ *
+ * @param string name of the sequence
+ *
+ * @return string formatted sequence name
+ *
+ * @access public
+ */
+ function getSequenceName($sqn)
+ {
+ if (false === $this->options['disable_smart_seqname']) {
+ if (strpos($sqn, '_') !== false) {
+ list($table, $field) = explode('_', $sqn, 2);
+ }
+ $schema_list = $this->queryOne("SELECT array_to_string(current_schemas(false), ',')");
+ if (PEAR::isError($schema_list) || empty($schema_list) || count($schema_list) < 2) {
+ $order_by = ' a.attnum';
+ $schema_clause = ' AND n.nspname=current_schema()';
+ } else {
+ $schemas = explode(',', $schema_list);
+ $schema_clause = ' AND n.nspname IN ('.$schema_list.')';
+ $counter = 1;
+ $order_by = ' CASE ';
+ foreach ($schemas as $schema) {
+ $order_by .= ' WHEN n.nspname='.$schema.' THEN '.$counter++;
+ }
+ $order_by .= ' ELSE '.$counter.' END, a.attnum';
+ }
+
+ $query = "SELECT substring((SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128)
+ FROM pg_attrdef d
+ WHERE d.adrelid = a.attrelid
+ AND d.adnum = a.attnum
+ AND a.atthasdef
+ ) FROM 'nextval[^'']*''([^'']*)')
+ FROM pg_attribute a
+ LEFT JOIN pg_class c ON c.oid = a.attrelid
+ LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef
+ LEFT JOIN pg_namespace n ON c.relnamespace = n.oid
+ WHERE (c.relname = ".$this->quote($sqn, 'text');
+ if (!empty($field)) {
+ $query .= " OR (c.relname = ".$this->quote($table, 'text')." AND a.attname = ".$this->quote($field, 'text').")";
+ }
+ $query .= " )"
+ .$schema_clause."
+ AND NOT a.attisdropped
+ AND a.attnum > 0
+ AND pg_get_expr(d.adbin, d.adrelid) LIKE 'nextval%'
+ ORDER BY ".$order_by;
+ $seqname = $this->queryOne($query);
+ if (!PEAR::isError($seqname) && !empty($seqname) && is_string($seqname)) {
+ return $seqname;
+ }
+ }
+
+ return parent::getSequenceName($sqn);
+ }
+
+ // }}}
+ // {{{ nextID()
+
+ /**
+ * Returns the next free id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true the sequence is
+ * automatic created, if it
+ * not exists
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function nextID($seq_name, $ondemand = true)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ $query = "SELECT NEXTVAL('$sequence_name')";
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->expectError(MDB2_ERROR_NOSUCHTABLE);
+ $result = $this->queryOne($query, 'integer');
+ $this->popExpect();
+ $this->popErrorHandling();
+ if (PEAR::isError($result)) {
+ if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
+ $this->loadModule('Manager', null, true);
+ $result = $this->manager->createSequence($seq_name);
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result, null, null,
+ 'on demand sequence could not be created', __FUNCTION__);
+ }
+ return $this->nextId($seq_name, false);
+ }
+ }
+ return $result;
+ }
+
+ // }}}
+ // {{{ lastInsertID()
+
+ /**
+ * Returns the autoincrement ID if supported or $id or fetches the current
+ * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param string $field name of the field into which a new row was inserted
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function lastInsertID($table = null, $field = null)
+ {
+ if (empty($table) && empty($field)) {
+ return $this->queryOne('SELECT lastval()', 'integer');
+ }
+ $seq = $table.(empty($field) ? '' : '_'.$field);
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq), true);
+ return $this->queryOne("SELECT currval('$sequence_name')", 'integer');
+ }
+
+ // }}}
+ // {{{ currID()
+
+ /**
+ * Returns the current id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function currID($seq_name)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ return $this->queryOne("SELECT last_value FROM $sequence_name", 'integer');
+ }
+}
+
+/**
+ * MDB2 PostGreSQL result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Result_pgsql extends MDB2_Result_Common
+{
+ // }}}
+ // {{{ fetchRow()
+
+ /**
+ * Fetch a row and insert the data into an existing array.
+ *
+ * @param int $fetchmode how the array data should be indexed
+ * @param int $rownum number of the row where the data can be found
+ * @return int data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
+ {
+ if (null !== $rownum) {
+ $seek = $this->seek($rownum);
+ if (PEAR::isError($seek)) {
+ return $seek;
+ }
+ }
+ if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
+ $fetchmode = $this->db->fetchmode;
+ }
+ if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
+ $row = @pg_fetch_array($this->result, null, PGSQL_ASSOC);
+ if (is_array($row)
+ && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
+ ) {
+ $row = array_change_key_case($row, $this->db->options['field_case']);
+ }
+ } else {
+ $row = @pg_fetch_row($this->result);
+ }
+ if (!$row) {
+ if (false === $this->result) {
+ $err = $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ return $err;
+ }
+ return null;
+ }
+ $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL;
+ $rtrim = false;
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) {
+ if (empty($this->types)) {
+ $mode += MDB2_PORTABILITY_RTRIM;
+ } else {
+ $rtrim = true;
+ }
+ }
+ if ($mode) {
+ $this->db->_fixResultArrayValues($row, $mode);
+ }
+ if (!empty($this->types)) {
+ $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim);
+ }
+ if (!empty($this->values)) {
+ $this->_assignBindColumns($row);
+ }
+ if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
+ $object_class = $this->db->options['fetch_class'];
+ if ($object_class == 'stdClass') {
+ $row = (object) $row;
+ } else {
+ $rowObj = new $object_class($row);
+ $row = $rowObj;
+ }
+ }
+ ++$this->rownum;
+ return $row;
+ }
+
+ // }}}
+ // {{{ _getColumnNames()
+
+ /**
+ * Retrieve the names of columns returned by the DBMS in a query result.
+ *
+ * @return mixed Array variable that holds the names of columns as keys
+ * or an MDB2 error on failure.
+ * Some DBMS may not return any columns when the result set
+ * does not contain any rows.
+ * @access private
+ */
+ function _getColumnNames()
+ {
+ $columns = array();
+ $numcols = $this->numCols();
+ if (PEAR::isError($numcols)) {
+ return $numcols;
+ }
+ for ($column = 0; $column < $numcols; $column++) {
+ $column_name = @pg_field_name($this->result, $column);
+ $columns[$column_name] = $column;
+ }
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $columns = array_change_key_case($columns, $this->db->options['field_case']);
+ }
+ return $columns;
+ }
+
+ // }}}
+ // {{{ numCols()
+
+ /**
+ * Count the number of columns returned by the DBMS in a query result.
+ *
+ * @access public
+ * @return mixed integer value with the number of columns, a MDB2 error
+ * on failure
+ */
+ function numCols()
+ {
+ $cols = @pg_num_fields($this->result);
+ if (null === $cols) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return count($this->types);
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get column count', __FUNCTION__);
+ }
+ return $cols;
+ }
+
+ // }}}
+ // {{{ nextResult()
+
+ /**
+ * Move the internal result pointer to the next available result
+ *
+ * @return true on success, false if there is no more result set or an error object on failure
+ * @access public
+ */
+ function nextResult()
+ {
+ $connection = $this->db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ if (!($this->result = @pg_get_result($connection))) {
+ return false;
+ }
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ free()
+
+ /**
+ * Free the internal resources associated with result.
+ *
+ * @return boolean true on success, false if result is invalid
+ * @access public
+ */
+ function free()
+ {
+ if (is_resource($this->result) && $this->db->connection) {
+ $free = @pg_free_result($this->result);
+ if (false === $free) {
+ return $this->db->raiseError(null, null, null,
+ 'Could not free result', __FUNCTION__);
+ }
+ }
+ $this->result = false;
+ return MDB2_OK;
+ }
+}
+
+/**
+ * MDB2 PostGreSQL buffered result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_BufferedResult_pgsql extends MDB2_Result_pgsql
+{
+ // {{{ seek()
+
+ /**
+ * Seek to a specific row in a result set
+ *
+ * @param int $rownum number of the row where the data can be found
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function seek($rownum = 0)
+ {
+ if ($this->rownum != ($rownum - 1) && !@pg_result_seek($this->result, $rownum)) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return MDB2_OK;
+ }
+ return $this->db->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__);
+ }
+ $this->rownum = $rownum - 1;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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
+ */
+ function valid()
+ {
+ $numrows = $this->numRows();
+ if (PEAR::isError($numrows)) {
+ return $numrows;
+ }
+ return $this->rownum < ($numrows - 1);
+ }
+
+ // }}}
+ // {{{ numRows()
+
+ /**
+ * Returns the number of rows in a result object
+ *
+ * @return mixed MDB2 Error Object or the number of rows
+ * @access public
+ */
+ function numRows()
+ {
+ $rows = @pg_num_rows($this->result);
+ if (null === $rows) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return 0;
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get row count', __FUNCTION__);
+ }
+ return $rows;
+ }
+}
+
+/**
+ * MDB2 PostGreSQL statement driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Paul Cooper <pgc@ucecom.com>
+ */
+class MDB2_Statement_pgsql extends MDB2_Statement_Common
+{
+ // {{{ _execute()
+
+ /**
+ * Execute a prepared query statement helper method.
+ *
+ * @param mixed $result_class string which specifies which result class to use
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in
+ *
+ * @return mixed MDB2_Result or integer (affected rows) on success,
+ * a MDB2 error on failure
+ * @access private
+ */
+ function _execute($result_class = true, $result_wrap_class = false)
+ {
+ if (null === $this->statement) {
+ return parent::_execute($result_class, $result_wrap_class);
+ }
+ $this->db->last_query = $this->query;
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values));
+ if ($this->db->getOption('disable_query')) {
+ $result = $this->is_manip ? 0 : null;
+ return $result;
+ }
+
+ $connection = $this->db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $query = false;
+ $parameters = array();
+ // todo: disabled until pg_execute() bytea issues are cleared up
+ if (true || !function_exists('pg_execute')) {
+ $query = 'EXECUTE '.$this->statement;
+ }
+ if (!empty($this->positions)) {
+ foreach ($this->positions as $parameter) {
+ if (!array_key_exists($parameter, $this->values)) {
+ return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__);
+ }
+ $value = $this->values[$parameter];
+ $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null;
+ if (is_resource($value) || $type == 'clob' || $type == 'blob' || $this->db->options['lob_allow_url_include']) {
+ if (!is_resource($value) && preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
+ if ($match[1] == 'file://') {
+ $value = $match[2];
+ }
+ $value = @fopen($value, 'r');
+ $close = true;
+ }
+ if (is_resource($value)) {
+ $data = '';
+ while (!@feof($value)) {
+ $data.= @fread($value, $this->db->options['lob_buffer_length']);
+ }
+ if ($close) {
+ @fclose($value);
+ }
+ $value = $data;
+ }
+ }
+ $quoted = $this->db->quote($value, $type, $query);
+ if (PEAR::isError($quoted)) {
+ return $quoted;
+ }
+ $parameters[] = $quoted;
+ }
+ if ($query) {
+ $query.= ' ('.implode(', ', $parameters).')';
+ }
+ }
+
+ if (!$query) {
+ $result = @pg_execute($connection, $this->statement, $parameters);
+ if (!$result) {
+ $err = $this->db->raiseError(null, null, null,
+ 'Unable to execute statement', __FUNCTION__);
+ return $err;
+ }
+ } else {
+ $result = $this->db->_doQuery($query, $this->is_manip, $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+
+ if ($this->is_manip) {
+ $affected_rows = $this->db->_affectedRows($connection, $result);
+ return $affected_rows;
+ }
+
+ $result = $this->db->_wrapResult($result, $this->result_types,
+ $result_class, $result_wrap_class, $this->limit, $this->offset);
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result));
+ return $result;
+ }
+
+ // }}}
+ // {{{ free()
+
+ /**
+ * Release resources allocated for the specified prepared query.
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function free()
+ {
+ if (null === $this->positions) {
+ return $this->db->raiseError(MDB2_ERROR, null, null,
+ 'Prepared statement has already been freed', __FUNCTION__);
+ }
+ $result = MDB2_OK;
+
+ if (null !== $this->statement) {
+ $connection = $this->db->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ $query = 'DEALLOCATE PREPARE '.$this->statement;
+ $result = $this->db->_doQuery($query, true, $connection);
+ }
+
+ parent::free();
+ return $result;
+ }
+}
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Driver/sqlite.php b/3rdparty/MDB2/Driver/sqlite.php index 5d2ad27d016..e8f1bba583c 100644 --- a/3rdparty/MDB2/Driver/sqlite.php +++ b/3rdparty/MDB2/Driver/sqlite.php @@ -1,1088 +1,1093 @@ -<?php -// vim: set et ts=4 sw=4 fdm=marker: -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: sqlite.php,v 1.165 2008/11/30 14:28:01 afz Exp $ -// - -/** - * MDB2 SQLite driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Driver_sqlite extends MDB2_Driver_Common -{ - // {{{ properties - var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => false); - - var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"'); - - var $_lasterror = ''; - - var $fix_assoc_fields_names = false; - - // }}} - // {{{ constructor - - /** - * Constructor - */ - function __construct() - { - parent::__construct(); - - $this->phptype = 'sqlite'; - $this->dbsyntax = 'sqlite'; - - $this->supported['sequences'] = 'emulated'; - $this->supported['indexes'] = true; - $this->supported['affected_rows'] = true; - $this->supported['summary_functions'] = true; - $this->supported['order_by_text'] = true; - $this->supported['current_id'] = 'emulated'; - $this->supported['limit_queries'] = true; - $this->supported['LOBs'] = true; - $this->supported['replace'] = true; - $this->supported['transactions'] = true; - $this->supported['savepoints'] = false; - $this->supported['sub_selects'] = true; - $this->supported['triggers'] = true; - $this->supported['auto_increment'] = true; - $this->supported['primary_key'] = false; // requires alter table implementation - $this->supported['result_introspection'] = false; // not implemented - $this->supported['prepared_statements'] = 'emulated'; - $this->supported['identifier_quoting'] = true; - $this->supported['pattern_escaping'] = false; - $this->supported['new_link'] = false; - - $this->options['DBA_username'] = false; - $this->options['DBA_password'] = false; - $this->options['base_transaction_name'] = '___php_MDB2_sqlite_auto_commit_off'; - $this->options['fixed_float'] = 0; - $this->options['database_path'] = ''; - $this->options['database_extension'] = ''; - $this->options['server_version'] = ''; - $this->options['max_identifiers_length'] = 128; //no real limit - } - - // }}} - // {{{ errorInfo() - - /** - * This method is used to collect information about an error - * - * @param integer $error - * @return array - * @access public - */ - function errorInfo($error = null) - { - $native_code = null; - if ($this->connection) { - $native_code = @sqlite_last_error($this->connection); - } - $native_msg = $this->_lasterror - ? html_entity_decode($this->_lasterror) : @sqlite_error_string($native_code); - - // PHP 5.2+ prepends the function name to $php_errormsg, so we need - // this hack to work around it, per bug #9599. - $native_msg = preg_replace('/^sqlite[a-z_]+\(\)[^:]*: /', '', $native_msg); - - if (is_null($error)) { - static $error_regexps; - if (empty($error_regexps)) { - $error_regexps = array( - '/^no such table:/' => MDB2_ERROR_NOSUCHTABLE, - '/^no such index:/' => MDB2_ERROR_NOT_FOUND, - '/^(table|index) .* already exists$/' => MDB2_ERROR_ALREADY_EXISTS, - '/PRIMARY KEY must be unique/i' => MDB2_ERROR_CONSTRAINT, - '/is not unique/' => MDB2_ERROR_CONSTRAINT, - '/columns .* are not unique/i' => MDB2_ERROR_CONSTRAINT, - '/uniqueness constraint failed/' => MDB2_ERROR_CONSTRAINT, - '/may not be NULL/' => MDB2_ERROR_CONSTRAINT_NOT_NULL, - '/^no such column:/' => MDB2_ERROR_NOSUCHFIELD, - '/no column named/' => MDB2_ERROR_NOSUCHFIELD, - '/column not present in both tables/i' => MDB2_ERROR_NOSUCHFIELD, - '/^near ".*": syntax error$/' => MDB2_ERROR_SYNTAX, - '/[0-9]+ values for [0-9]+ columns/i' => MDB2_ERROR_VALUE_COUNT_ON_ROW, - ); - } - foreach ($error_regexps as $regexp => $code) { - if (preg_match($regexp, $native_msg)) { - $error = $code; - break; - } - } - } - return array($error, $native_code, $native_msg); - } - - // }}} - // {{{ escape() - - /** - * Quotes a string so it can be safely used in a query. It will quote - * the text so it can safely be used within a query. - * - * @param string the input string to quote - * @param bool escape wildcards - * - * @return string quoted string - * - * @access public - */ - function escape($text, $escape_wildcards = false) - { - $text = @sqlite_escape_string($text); - return $text; - } - - // }}} - // {{{ beginTransaction() - - /** - * Start a transaction or set a savepoint. - * - * @param string name of a savepoint to set - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function beginTransaction($savepoint = null) - { - $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!is_null($savepoint)) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } elseif ($this->in_transaction) { - return MDB2_OK; //nothing to do - } - if (!$this->destructor_registered && $this->opened_persistent) { - $this->destructor_registered = true; - register_shutdown_function('MDB2_closeOpenTransactions'); - } - $query = 'BEGIN TRANSACTION '.$this->options['base_transaction_name']; - $result =$this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = true; - return MDB2_OK; - } - - // }}} - // {{{ commit() - - /** - * Commit the database changes done during a transaction that is in - * progress or release a savepoint. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after committing the pending changes. - * - * @param string name of a savepoint to release - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function commit($savepoint = null) - { - $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } - - $query = 'COMMIT TRANSACTION '.$this->options['base_transaction_name']; - $result =$this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ - - /** - * Cancel any database changes done during a transaction or since a specific - * savepoint that is in progress. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after canceling the pending changes. - * - * @param string name of a savepoint to rollback to - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function rollback($savepoint = null) - { - $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - if (!$this->in_transaction) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'rollback cannot be done changes are auto committed', __FUNCTION__); - } - if (!is_null($savepoint)) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'savepoints are not supported', __FUNCTION__); - } - - $query = 'ROLLBACK TRANSACTION '.$this->options['base_transaction_name']; - $result =$this->_doQuery($query, true); - if (PEAR::isError($result)) { - return $result; - } - $this->in_transaction = false; - return MDB2_OK; - } - - // }}} - // {{{ function setTransactionIsolation() - - /** - * Set the transacton isolation level. - * - * @param string standard isolation level - * READ UNCOMMITTED (allows dirty reads) - * READ COMMITTED (prevents dirty reads) - * REPEATABLE READ (prevents nonrepeatable reads) - * SERIALIZABLE (prevents phantom reads) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - static function setTransactionIsolation($isolation,$options=array()) - { - $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); - switch ($isolation) { - case 'READ UNCOMMITTED': - $isolation = 0; - break; - case 'READ COMMITTED': - case 'REPEATABLE READ': - case 'SERIALIZABLE': - $isolation = 1; - break; - default: - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'isolation level is not supported: '.$isolation, __FUNCTION__); - } - - $query = "PRAGMA read_uncommitted=$isolation"; - return $this->_doQuery($query, true); - } - - // }}} - // {{{ getDatabaseFile() - - /** - * Builds the string with path+dbname+extension - * - * @return string full database path+file - * @access protected - */ - function _getDatabaseFile($database_name) - { - if ($database_name === '' || $database_name === ':memory:') { - return $database_name; - } - return $this->options['database_path'].$database_name.$this->options['database_extension']; - } - - // }}} - // {{{ connect() - - /** - * Connect to the database - * - * @return true on success, MDB2 Error Object on failure - **/ - function connect() - { - $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - $database_file = $this->_getDatabaseFile($this->database_name); - if (is_resource($this->connection)) { - //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 - if (MDB2::areEquals($this->connected_dsn, $this->dsn) - && $this->connected_database_name == $database_file - && $this->opened_persistent == $this->options['persistent'] - ) { - return MDB2_OK; - } - $this->disconnect(false); - } - - if (!PEAR::loadExtension($this->phptype)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); - } - - if (empty($this->database_name)) { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, - 'unable to establish a connection', __FUNCTION__); - } - - if ($database_file !== ':memory:') { - if(!strpos($database_file,'.db')){ - $database_file="$datadir/$database_file.db"; - } - if (!file_exists($database_file)) { - if (!touch($database_file)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Could not create database file', __FUNCTION__); - } - if (!isset($this->dsn['mode']) - || !is_numeric($this->dsn['mode']) - ) { - $mode = 0644; - } else { - $mode = octdec($this->dsn['mode']); - } - if (!chmod($database_file, $mode)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Could not be chmodded database file', __FUNCTION__); - } - if (!file_exists($database_file)) { - return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Could not be found database file', __FUNCTION__); - } - } - if (!is_file($database_file)) { - return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'Database is a directory name', __FUNCTION__); - } - if (!is_readable($database_file)) { - return $this->raiseError(MDB2_ERROR_ACCESS_VIOLATION, null, null, - 'Could not read database file', __FUNCTION__); - } - } - - $connect_function = ($this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open'); - $php_errormsg = ''; - if (version_compare('5.1.0', PHP_VERSION, '>')) { - @ini_set('track_errors', true); - echo 1; - $connection = @$connect_function($database_file); - echo 2; - @ini_restore('track_errors'); - } else { - $connection = @$connect_function($database_file, 0666, $php_errormsg); - } - $this->_lasterror = $php_errormsg; - if (!$connection) { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, - 'unable to establish a connection', __FUNCTION__); - } - - if ($this->fix_assoc_fields_names || - $this->options['portability'] & MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES) - { - @sqlite_query("PRAGMA short_column_names = 1", $connection); - $this->fix_assoc_fields_names = true; - } - - $this->connection = $connection; - $this->connected_dsn = $this->dsn; - $this->connected_database_name = $database_file; - $this->opened_persistent = $this->getoption('persistent'); - $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; - - return MDB2_OK; - } - - // }}} - // {{{ databaseExists() - - /** - * check if given database name is exists? - * - * @param string $name name of the database that should be checked - * - * @return mixed true/false on success, a MDB2 error on failure - * @access public - */ - function databaseExists($name) - { - $database_file = $this->_getDatabaseFile($name); - $result = file_exists($database_file); - return $result; - } - - // }}} - // {{{ disconnect() - - /** - * Log out and disconnect from the database. - * - * @param boolean $force if the disconnect should be forced even if the - * connection is opened persistently - * @return mixed true on success, false if not connected and error - * object on error - * @access public - */ - function disconnect($force = true) - { - if (is_resource($this->connection)) { - if ($this->in_transaction) { - $dsn = $this->dsn; - $database_name = $this->database_name; - $persistent = $this->options['persistent']; - $this->dsn = $this->connected_dsn; - $this->database_name = $this->connected_database_name; - $this->options['persistent'] = $this->opened_persistent; - $this->rollback(); - $this->dsn = $dsn; - $this->database_name = $database_name; - $this->options['persistent'] = $persistent; - } - - if (!$this->opened_persistent || $force) { - @sqlite_close($this->connection); - } - } else { - return false; - } - return parent::disconnect($force); - } - - // }}} - // {{{ _doQuery() - - /** - * Execute a query - * @param string $query query - * @param boolean $is_manip if the query is a manipulation query - * @param resource $connection - * @param string $database_name - * @return result or error object - * @access protected - */ - function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) - { - $this->last_query = $query; - $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - if ($this->options['disable_query']) { - $result = $is_manip ? 0 : null; - return $result; - } - - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - - $function = $this->options['result_buffering'] - ? 'sqlite_query' : 'sqlite_unbuffered_query'; - $php_errormsg = ''; - if (version_compare('5.1.0', PHP_VERSION, '>')) { - @ini_set('track_errors', true); - do { - $result = @$function($query.';', $connection); - } while (sqlite_last_error($connection) == SQLITE_SCHEMA); - @ini_restore('track_errors'); - } else { - do { - $result = @$function($query.';', $connection, SQLITE_BOTH, $php_errormsg); - } while (sqlite_last_error($connection) == SQLITE_SCHEMA); - } - $this->_lasterror = $php_errormsg; - - if (!$result) { - $err =$this->raiseError(null, null, null, - 'Could not execute statement', __FUNCTION__); - return $err; - } - - $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result)); - return $result; - } - - // }}} - // {{{ _affectedRows() - - /** - * Returns the number of rows affected - * - * @param resource $result - * @param resource $connection - * @return mixed MDB2 Error Object or the number of rows affected - * @access private - */ - function _affectedRows($connection, $result = null) - { - if (is_null($connection)) { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - } - return @sqlite_changes($connection); - } - - // }}} - // {{{ _modifyQuery() - - /** - * Changes a query string for various DBMS specific reasons - * - * @param string $query query to modify - * @param boolean $is_manip if it is a DML query - * @param integer $limit limit the number of rows - * @param integer $offset start reading from given offset - * @return string modified query - * @access protected - */ - function _modifyQuery($query, $is_manip, $limit, $offset) - { - if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) { - if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { - $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', - 'DELETE FROM \1 WHERE 1=1', $query); - } - } - if ($limit > 0 - && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) - ) { - $query = rtrim($query); - if (substr($query, -1) == ';') { - $query = substr($query, 0, -1); - } - if ($is_manip) { - $query.= " LIMIT $limit"; - } else { - $query.= " LIMIT $offset,$limit"; - } - } - return $query; - } - - // }}} - // {{{ getServerVersion() - - /** - * return version information about the server - * - * @param bool $native determines if the raw version string should be returned - * @return mixed array/string with version information or MDB2 error object - * @access public - */ - function getServerVersion($native = false) - { - $server_info = false; - if ($this->connected_server_info) { - $server_info = $this->connected_server_info; - } elseif ($this->options['server_version']) { - $server_info = $this->options['server_version']; - } elseif (function_exists('sqlite_libversion')) { - $server_info = @sqlite_libversion(); - } - if (!$server_info) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'Requires either the "server_version" option or the sqlite_libversion() function', __FUNCTION__); - } - // cache server_info - $this->connected_server_info = $server_info; - if (!$native) { - $tmp = explode('.', $server_info, 3); - $server_info = array( - 'major' => isset($tmp[0]) ? $tmp[0] : null, - 'minor' => isset($tmp[1]) ? $tmp[1] : null, - 'patch' => isset($tmp[2]) ? $tmp[2] : null, - 'extra' => null, - 'native' => $server_info, - ); - } - return $server_info; - } - - // }}} - // {{{ replace() - - /** - * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT - * query, except that if there is already a row in the table with the same - * key field values, the old row is deleted before the new row is inserted. - * - * The REPLACE type of query does not make part of the SQL standards. Since - * practically only SQLite implements it natively, this type of query is - * emulated through this method for other DBMS using standard types of - * queries inside a transaction to assure the atomicity of the operation. - * - * @access public - * - * @param string $table name of the table on which the REPLACE query will - * be executed. - * @param array $fields associative array that describes the fields and the - * values that will be inserted or updated in the specified table. The - * indexes of the array are the names of all the fields of the table. The - * values of the array are also associative arrays that describe the - * values and other properties of the table fields. - * - * Here follows a list of field properties that need to be specified: - * - * value: - * Value to be assigned to the specified field. This value may be - * of specified in database independent type format as this - * function can perform the necessary datatype conversions. - * - * Default: - * this property is required unless the Null property - * is set to 1. - * - * type - * Name of the type of the field. Currently, all types Metabase - * are supported except for clob and blob. - * - * Default: no type conversion - * - * null - * Boolean property that indicates that the value for this field - * should be set to null. - * - * The default value for fields missing in INSERT queries may be - * specified the definition of a table. Often, the default value - * is already null, but since the REPLACE may be emulated using - * an UPDATE query, make sure that all fields of the table are - * listed in this function argument array. - * - * Default: 0 - * - * key - * Boolean property that indicates that this field should be - * handled as a primary key or at least as part of the compound - * unique index of the table that will determine the row that will - * updated if it exists or inserted a new row otherwise. - * - * This function will fail if no key field is specified or if the - * value of a key field is set to null because fields that are - * part of unique index they may not be null. - * - * Default: 0 - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function replace($table, $fields) - { - $count = count($fields); - $query = $values = ''; - $keys = $colnum = 0; - for (reset($fields); $colnum < $count; next($fields), $colnum++) { - $name = key($fields); - if ($colnum > 0) { - $query .= ','; - $values.= ','; - } - $query.= $this->quoteIdentifier($name, true); - if (isset($fields[$name]['null']) && $fields[$name]['null']) { - $value = 'NULL'; - } else { - $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null; - $value = $this->quote($fields[$name]['value'], $type); - if (PEAR::isError($value)) { - return $value; - } - } - $values.= $value; - if (isset($fields[$name]['key']) && $fields[$name]['key']) { - if ($value === 'NULL') { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'key value '.$name.' may not be NULL', __FUNCTION__); - } - $keys++; - } - } - if ($keys == 0) { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'not specified which fields are keys', __FUNCTION__); - } - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $table = $this->quoteIdentifier($table, true); - $query = "REPLACE INTO $table ($query) VALUES ($values)"; - $result =$this->_doQuery($query, true, $connection); - if (PEAR::isError($result)) { - return $result; - } - return $this->_affectedRows($connection, $result); - } - - // }}} - // {{{ nextID() - - /** - * Returns the next free id of a sequence - * - * @param string $seq_name name of the sequence - * @param boolean $ondemand when true the sequence is - * automatic created, if it - * not exists - * - * @return mixed MDB2 Error Object or id - * @access public - */ - function nextID($seq_name, $ondemand = true) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - $seqcol_name = $this->options['seqcol_name']; - $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)"; - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->expectError(MDB2_ERROR_NOSUCHTABLE); - $result =$this->_doQuery($query, true); - $this->popExpect(); - $this->popErrorHandling(); - if (PEAR::isError($result)) { - if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { - $this->loadModule('Manager', null, true); - $result = $this->manager->createSequence($seq_name); - if (PEAR::isError($result)) { - return $this->raiseError($result, null, null, - 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__); - } else { - return $this->nextID($seq_name, false); - } - } - return $result; - } - $value = $this->lastInsertID(); - if (is_numeric($value)) { - $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value"; - $result =$this->_doQuery($query, true); - if (PEAR::isError($result)) { - $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; - } - } - return $value; - } - - // }}} - // {{{ lastInsertID() - - /** - * Returns the autoincrement ID if supported or $id or fetches the current - * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) - * - * @param string $table name of the table into which a new row was inserted - * @param string $field name of the field into which a new row was inserted - * @return mixed MDB2 Error Object or id - * @access public - */ - function lastInsertID($table = null, $field = null) - { - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - $value = @sqlite_last_insert_rowid($connection); - if (!$value) { - return $this->raiseError(null, null, null, - 'Could not get last insert ID', __FUNCTION__); - } - return $value; - } - - // }}} - // {{{ currID() - - /** - * Returns the current id of a sequence - * - * @param string $seq_name name of the sequence - * @return mixed MDB2 Error Object or id - * @access public - */ - function currID($seq_name) - { - $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); - $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); - $query = "SELECT MAX($seqcol_name) FROM $sequence_name"; - return $this->queryOne($query, 'integer'); - } -} - -/** - * MDB2 SQLite result driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Result_sqlite extends MDB2_Result_Common -{ - // }}} - // {{{ fetchRow() - - /** - * Fetch a row and insert the data into an existing array. - * - * @param int $fetchmode how the array data should be indexed - * @param int $rownum number of the row where the data can be found - * @return int data array on success, a MDB2 error on failure - * @access public - */ - function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) - { - if (!is_null($rownum)) { - $seek = $this->seek($rownum); - if (PEAR::isError($seek)) { - return $seek; - } - } - if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { - $fetchmode = $this->db->fetchmode; - } - if ($fetchmode & MDB2_FETCHMODE_ASSOC) { - $row = @sqlite_fetch_array($this->result, SQLITE_ASSOC); - if (is_array($row) - && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE - ) { - $row = array_change_key_case($row, $this->db->options['field_case']); - } - } else { - $row = @sqlite_fetch_array($this->result, SQLITE_NUM); - } - if (!$row) { - if ($this->result === false) { - $err =$this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - return $err; - } - $null = null; - return $null; - } - $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL; - $rtrim = false; - if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { - if (empty($this->types)) { - $mode += MDB2_PORTABILITY_RTRIM; - } else { - $rtrim = true; - } - } - if ($mode) { - $this->db->_fixResultArrayValues($row, $mode); - } - if (!empty($this->types)) { - $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim); - } - if (!empty($this->values)) { - $this->_assignBindColumns($row); - } - if ($fetchmode === MDB2_FETCHMODE_OBJECT) { - $object_class = $this->db->options['fetch_class']; - if ($object_class == 'stdClass') { - $row = (object) $row; - } else { - $row = new $object_class($row); - } - } - ++$this->rownum; - return $row; - } - - // }}} - // {{{ _getColumnNames() - - /** - * Retrieve the names of columns returned by the DBMS in a query result. - * - * @return mixed Array variable that holds the names of columns as keys - * or an MDB2 error on failure. - * Some DBMS may not return any columns when the result set - * does not contain any rows. - * @access private - */ - function _getColumnNames() - { - $columns = array(); - $numcols = $this->numCols(); - if (PEAR::isError($numcols)) { - return $numcols; - } - for ($column = 0; $column < $numcols; $column++) { - $column_name = @sqlite_field_name($this->result, $column); - $columns[$column_name] = $column; - } - if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - $columns = array_change_key_case($columns, $this->db->options['field_case']); - } - return $columns; - } - - // }}} - // {{{ numCols() - - /** - * Count the number of columns returned by the DBMS in a query result. - * - * @access public - * @return mixed integer value with the number of columns, a MDB2 error - * on failure - */ - function numCols() - { - $cols = @sqlite_num_fields($this->result); - if (is_null($cols)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return count($this->types); - } - return $this->db->raiseError(null, null, null, - 'Could not get column count', __FUNCTION__); - } - return $cols; - } -} - -/** - * MDB2 SQLite buffered result driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_BufferedResult_sqlite extends MDB2_Result_sqlite -{ - // {{{ seek() - - /** - * Seek to a specific row in a result set - * - * @param int $rownum number of the row where the data can be found - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function seek($rownum = 0) - { - if (!@sqlite_seek($this->result, $rownum)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return MDB2_OK; - } - return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, - 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__); - } - $this->rownum = $rownum - 1; - return MDB2_OK; - } - - // }}} - // {{{ 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 - */ - function valid() - { - $numrows = $this->numRows(); - if (PEAR::isError($numrows)) { - return $numrows; - } - return $this->rownum < ($numrows - 1); - } - - // }}} - // {{{ numRows() - - /** - * Returns the number of rows in a result object - * - * @return mixed MDB2 Error Object or the number of rows - * @access public - */ - function numRows() - { - $rows = @sqlite_num_rows($this->result); - if (is_null($rows)) { - if ($this->result === false) { - return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'resultset has already been freed', __FUNCTION__); - } elseif (is_null($this->result)) { - return 0; - } - return $this->db->raiseError(null, null, null, - 'Could not get row count', __FUNCTION__); - } - return $rows; - } -} - -/** - * MDB2 SQLite statement driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Statement_sqlite extends MDB2_Statement_Common -{ - -} - -?> +<?php
+// vim: set et ts=4 sw=4 fdm=marker:
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: sqlite.php 295587 2010-02-28 17:16:38Z quipo $
+//
+
+/**
+ * MDB2 SQLite driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Driver_sqlite extends MDB2_Driver_Common
+{
+ // {{{ properties
+ var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => false);
+
+ var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');
+
+ var $_lasterror = '';
+
+ var $fix_assoc_fields_names = false;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * Constructor
+ */
+ function __construct()
+ {
+ parent::__construct();
+
+ $this->phptype = 'sqlite';
+ $this->dbsyntax = 'sqlite';
+
+ $this->supported['sequences'] = 'emulated';
+ $this->supported['indexes'] = true;
+ $this->supported['affected_rows'] = true;
+ $this->supported['summary_functions'] = true;
+ $this->supported['order_by_text'] = true;
+ $this->supported['current_id'] = 'emulated';
+ $this->supported['limit_queries'] = true;
+ $this->supported['LOBs'] = true;
+ $this->supported['replace'] = true;
+ $this->supported['transactions'] = true;
+ $this->supported['savepoints'] = false;
+ $this->supported['sub_selects'] = true;
+ $this->supported['triggers'] = true;
+ $this->supported['auto_increment'] = true;
+ $this->supported['primary_key'] = false; // requires alter table implementation
+ $this->supported['result_introspection'] = false; // not implemented
+ $this->supported['prepared_statements'] = 'emulated';
+ $this->supported['identifier_quoting'] = true;
+ $this->supported['pattern_escaping'] = false;
+ $this->supported['new_link'] = false;
+
+ $this->options['DBA_username'] = false;
+ $this->options['DBA_password'] = false;
+ $this->options['base_transaction_name'] = '___php_MDB2_sqlite_auto_commit_off';
+ $this->options['fixed_float'] = 0;
+ $this->options['database_path'] = '';
+ $this->options['database_extension'] = '';
+ $this->options['server_version'] = '';
+ $this->options['max_identifiers_length'] = 128; //no real limit
+ }
+
+ // }}}
+ // {{{ errorInfo()
+
+ /**
+ * This method is used to collect information about an error
+ *
+ * @param integer $error
+ * @return array
+ * @access public
+ */
+ function errorInfo($error = null)
+ {
+ $native_code = null;
+ if ($this->connection) {
+ $native_code = @sqlite_last_error($this->connection);
+ }
+ $native_msg = $this->_lasterror
+ ? html_entity_decode($this->_lasterror) : @sqlite_error_string($native_code);
+
+ // PHP 5.2+ prepends the function name to $php_errormsg, so we need
+ // this hack to work around it, per bug #9599.
+ $native_msg = preg_replace('/^sqlite[a-z_]+\(\)[^:]*: /', '', $native_msg);
+
+ if (null === $error) {
+ static $error_regexps;
+ if (empty($error_regexps)) {
+ $error_regexps = array(
+ '/^no such table:/' => MDB2_ERROR_NOSUCHTABLE,
+ '/^no such index:/' => MDB2_ERROR_NOT_FOUND,
+ '/^(table|index) .* already exists$/' => MDB2_ERROR_ALREADY_EXISTS,
+ '/PRIMARY KEY must be unique/i' => MDB2_ERROR_CONSTRAINT,
+ '/is not unique/' => MDB2_ERROR_CONSTRAINT,
+ '/columns .* are not unique/i' => MDB2_ERROR_CONSTRAINT,
+ '/uniqueness constraint failed/' => MDB2_ERROR_CONSTRAINT,
+ '/may not be NULL/' => MDB2_ERROR_CONSTRAINT_NOT_NULL,
+ '/^no such column:/' => MDB2_ERROR_NOSUCHFIELD,
+ '/no column named/' => MDB2_ERROR_NOSUCHFIELD,
+ '/column not present in both tables/i' => MDB2_ERROR_NOSUCHFIELD,
+ '/^near ".*": syntax error$/' => MDB2_ERROR_SYNTAX,
+ '/[0-9]+ values for [0-9]+ columns/i' => MDB2_ERROR_VALUE_COUNT_ON_ROW,
+ );
+ }
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match($regexp, $native_msg)) {
+ $error = $code;
+ break;
+ }
+ }
+ }
+ return array($error, $native_code, $native_msg);
+ }
+
+ // }}}
+ // {{{ escape()
+
+ /**
+ * Quotes a string so it can be safely used in a query. It will quote
+ * the text so it can safely be used within a query.
+ *
+ * @param string the input string to quote
+ * @param bool escape wildcards
+ *
+ * @return string quoted string
+ *
+ * @access public
+ */
+ function escape($text, $escape_wildcards = false)
+ {
+ $text = @sqlite_escape_string($text);
+ return $text;
+ }
+
+ // }}}
+ // {{{ beginTransaction()
+
+ /**
+ * Start a transaction or set a savepoint.
+ *
+ * @param string name of a savepoint to set
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function beginTransaction($savepoint = null)
+ {
+ $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (null !== $savepoint) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+ if ($this->in_transaction) {
+ return MDB2_OK; //nothing to do
+ }
+ if (!$this->destructor_registered && $this->opened_persistent) {
+ $this->destructor_registered = true;
+ register_shutdown_function('MDB2_closeOpenTransactions');
+ }
+ $query = 'BEGIN TRANSACTION '.$this->options['base_transaction_name'];
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = true;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ commit()
+
+ /**
+ * Commit the database changes done during a transaction that is in
+ * progress or release a savepoint. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after committing the pending changes.
+ *
+ * @param string name of a savepoint to release
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function commit($savepoint = null)
+ {
+ $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (null !== $savepoint) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+
+ $query = 'COMMIT TRANSACTION '.$this->options['base_transaction_name'];
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{
+
+ /**
+ * Cancel any database changes done during a transaction or since a specific
+ * savepoint that is in progress. This function may only be called when
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new
+ * transaction is implicitly started after canceling the pending changes.
+ *
+ * @param string name of a savepoint to rollback to
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ */
+ function rollback($savepoint = null)
+ {
+ $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
+ if (!$this->in_transaction) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'rollback cannot be done changes are auto committed', __FUNCTION__);
+ }
+ if (null !== $savepoint) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'savepoints are not supported', __FUNCTION__);
+ }
+
+ $query = 'ROLLBACK TRANSACTION '.$this->options['base_transaction_name'];
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $this->in_transaction = false;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ function setTransactionIsolation()
+
+ /**
+ * Set the transacton isolation level.
+ *
+ * @param string standard isolation level
+ * READ UNCOMMITTED (allows dirty reads)
+ * READ COMMITTED (prevents dirty reads)
+ * REPEATABLE READ (prevents nonrepeatable reads)
+ * SERIALIZABLE (prevents phantom reads)
+ * @param array some transaction options:
+ * 'wait' => 'WAIT' | 'NO WAIT'
+ * 'rw' => 'READ WRITE' | 'READ ONLY'
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ *
+ * @access public
+ * @since 2.1.1
+ */
+ function setTransactionIsolation($isolation, $options = array())
+ {
+ $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
+ switch ($isolation) {
+ case 'READ UNCOMMITTED':
+ $isolation = 0;
+ break;
+ case 'READ COMMITTED':
+ case 'REPEATABLE READ':
+ case 'SERIALIZABLE':
+ $isolation = 1;
+ break;
+ default:
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'isolation level is not supported: '.$isolation, __FUNCTION__);
+ }
+
+ $query = "PRAGMA read_uncommitted=$isolation";
+ return $this->_doQuery($query, true);
+ }
+
+ // }}}
+ // {{{ getDatabaseFile()
+
+ /**
+ * Builds the string with path+dbname+extension
+ *
+ * @return string full database path+file
+ * @access protected
+ */
+ function _getDatabaseFile($database_name)
+ {
+ if ($database_name === '' || $database_name === ':memory:') {
+ return $database_name;
+ }
+ return $this->options['database_path'].$database_name.$this->options['database_extension'];
+ }
+
+ // }}}
+ // {{{ connect()
+
+ /**
+ * Connect to the database
+ *
+ * @return true on success, MDB2 Error Object on failure
+ **/
+ function connect()
+ {
+ $database_file = $this->_getDatabaseFile($this->database_name);
+ if (is_resource($this->connection)) {
+ //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
+ if (MDB2::areEquals($this->connected_dsn, $this->dsn)
+ && $this->connected_database_name == $database_file
+ && $this->opened_persistent == $this->options['persistent']
+ ) {
+ return MDB2_OK;
+ }
+ $this->disconnect(false);
+ }
+
+ if (!PEAR::loadExtension($this->phptype)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
+ }
+
+ if (empty($this->database_name)) {
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
+ 'unable to establish a connection', __FUNCTION__);
+ }
+
+ if ($database_file !== ':memory:') {
+ if (!file_exists($database_file)) {
+ if (!touch($database_file)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'Could not create database file', __FUNCTION__);
+ }
+ if (!isset($this->dsn['mode'])
+ || !is_numeric($this->dsn['mode'])
+ ) {
+ $mode = 0644;
+ } else {
+ $mode = octdec($this->dsn['mode']);
+ }
+ if (!chmod($database_file, $mode)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'Could not be chmodded database file', __FUNCTION__);
+ }
+ if (!file_exists($database_file)) {
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
+ 'Could not be found database file', __FUNCTION__);
+ }
+ }
+ if (!is_file($database_file)) {
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'Database is a directory name', __FUNCTION__);
+ }
+ if (!is_readable($database_file)) {
+ return $this->raiseError(MDB2_ERROR_ACCESS_VIOLATION, null, null,
+ 'Could not read database file', __FUNCTION__);
+ }
+ }
+
+ $connect_function = ($this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open');
+ $php_errormsg = '';
+ if (version_compare('5.1.0', PHP_VERSION, '>')) {
+ @ini_set('track_errors', true);
+ $connection = @$connect_function($database_file);
+ @ini_restore('track_errors');
+ } else {
+ $connection = @$connect_function($database_file, 0666, $php_errormsg);
+ }
+ $this->_lasterror = $php_errormsg;
+ if (!$connection) {
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
+ 'unable to establish a connection', __FUNCTION__);
+ }
+
+ if ($this->fix_assoc_fields_names ||
+ $this->options['portability'] & MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES)
+ {
+ @sqlite_query("PRAGMA short_column_names = 1", $connection);
+ $this->fix_assoc_fields_names = true;
+ }
+
+ $this->connection = $connection;
+ $this->connected_dsn = $this->dsn;
+ $this->connected_database_name = $database_file;
+ $this->opened_persistent = $this->getoption('persistent');
+ $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
+
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ databaseExists()
+
+ /**
+ * check if given database name is exists?
+ *
+ * @param string $name name of the database that should be checked
+ *
+ * @return mixed true/false on success, a MDB2 error on failure
+ * @access public
+ */
+ function databaseExists($name)
+ {
+ $database_file = $this->_getDatabaseFile($name);
+ $result = file_exists($database_file);
+ return $result;
+ }
+
+ // }}}
+ // {{{ disconnect()
+
+ /**
+ * Log out and disconnect from the database.
+ *
+ * @param boolean $force if the disconnect should be forced even if the
+ * connection is opened persistently
+ * @return mixed true on success, false if not connected and error
+ * object on error
+ * @access public
+ */
+ function disconnect($force = true)
+ {
+ if (is_resource($this->connection)) {
+ if ($this->in_transaction) {
+ $dsn = $this->dsn;
+ $database_name = $this->database_name;
+ $persistent = $this->options['persistent'];
+ $this->dsn = $this->connected_dsn;
+ $this->database_name = $this->connected_database_name;
+ $this->options['persistent'] = $this->opened_persistent;
+ $this->rollback();
+ $this->dsn = $dsn;
+ $this->database_name = $database_name;
+ $this->options['persistent'] = $persistent;
+ }
+
+ if (!$this->opened_persistent || $force) {
+ @sqlite_close($this->connection);
+ }
+ } else {
+ return false;
+ }
+ return parent::disconnect($force);
+ }
+
+ // }}}
+ // {{{ _doQuery()
+
+ /**
+ * Execute a query
+ * @param string $query query
+ * @param boolean $is_manip if the query is a manipulation query
+ * @param resource $connection
+ * @param string $database_name
+ * @return result or error object
+ * @access protected
+ */
+ function _doQuery($query, $is_manip = false, $connection = null, $database_name = null)
+ {
+ $this->last_query = $query;
+ $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
+ if ($result) {
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ $query = $result;
+ }
+ if ($this->options['disable_query']) {
+ $result = $is_manip ? 0 : null;
+ return $result;
+ }
+
+ if (null === $connection) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+
+ $function = $this->options['result_buffering']
+ ? 'sqlite_query' : 'sqlite_unbuffered_query';
+ $php_errormsg = '';
+ if (version_compare('5.1.0', PHP_VERSION, '>')) {
+ @ini_set('track_errors', true);
+ do {
+ $result = @$function($query.';', $connection);
+ } while (sqlite_last_error($connection) == SQLITE_SCHEMA);
+ @ini_restore('track_errors');
+ } else {
+ do {
+ $result = @$function($query.';', $connection, SQLITE_BOTH, $php_errormsg);
+ } while (sqlite_last_error($connection) == SQLITE_SCHEMA);
+ }
+ $this->_lasterror = $php_errormsg;
+
+ if (!$result) {
+ $code = null;
+ if (0 === strpos($this->_lasterror, 'no such table')) {
+ $code = MDB2_ERROR_NOSUCHTABLE;
+ }
+ $err = $this->raiseError($code, null, null,
+ 'Could not execute statement', __FUNCTION__);
+ return $err;
+ }
+
+ $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result));
+ return $result;
+ }
+
+ // }}}
+ // {{{ _affectedRows()
+
+ /**
+ * Returns the number of rows affected
+ *
+ * @param resource $result
+ * @param resource $connection
+ * @return mixed MDB2 Error Object or the number of rows affected
+ * @access private
+ */
+ function _affectedRows($connection, $result = null)
+ {
+ if (null === $connection) {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ }
+ return @sqlite_changes($connection);
+ }
+
+ // }}}
+ // {{{ _modifyQuery()
+
+ /**
+ * Changes a query string for various DBMS specific reasons
+ *
+ * @param string $query query to modify
+ * @param boolean $is_manip if it is a DML query
+ * @param integer $limit limit the number of rows
+ * @param integer $offset start reading from given offset
+ * @return string modified query
+ * @access protected
+ */
+ function _modifyQuery($query, $is_manip, $limit, $offset)
+ {
+ if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) {
+ if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
+ $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
+ 'DELETE FROM \1 WHERE 1=1', $query);
+ }
+ }
+ if ($limit > 0
+ && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query)
+ ) {
+ $query = rtrim($query);
+ if (substr($query, -1) == ';') {
+ $query = substr($query, 0, -1);
+ }
+ if ($is_manip) {
+ $query.= " LIMIT $limit";
+ } else {
+ $query.= " LIMIT $offset,$limit";
+ }
+ }
+ return $query;
+ }
+
+ // }}}
+ // {{{ getServerVersion()
+
+ /**
+ * return version information about the server
+ *
+ * @param bool $native determines if the raw version string should be returned
+ * @return mixed array/string with version information or MDB2 error object
+ * @access public
+ */
+ function getServerVersion($native = false)
+ {
+ $server_info = false;
+ if ($this->connected_server_info) {
+ $server_info = $this->connected_server_info;
+ } elseif ($this->options['server_version']) {
+ $server_info = $this->options['server_version'];
+ } elseif (function_exists('sqlite_libversion')) {
+ $server_info = @sqlite_libversion();
+ }
+ if (!$server_info) {
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
+ 'Requires either the "server_version" option or the sqlite_libversion() function', __FUNCTION__);
+ }
+ // cache server_info
+ $this->connected_server_info = $server_info;
+ if (!$native) {
+ $tmp = explode('.', $server_info, 3);
+ $server_info = array(
+ 'major' => isset($tmp[0]) ? $tmp[0] : null,
+ 'minor' => isset($tmp[1]) ? $tmp[1] : null,
+ 'patch' => isset($tmp[2]) ? $tmp[2] : null,
+ 'extra' => null,
+ 'native' => $server_info,
+ );
+ }
+ return $server_info;
+ }
+
+ // }}}
+ // {{{ replace()
+
+ /**
+ * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
+ * query, except that if there is already a row in the table with the same
+ * key field values, the old row is deleted before the new row is inserted.
+ *
+ * The REPLACE type of query does not make part of the SQL standards. Since
+ * practically only SQLite implements it natively, this type of query is
+ * emulated through this method for other DBMS using standard types of
+ * queries inside a transaction to assure the atomicity of the operation.
+ *
+ * @access public
+ *
+ * @param string $table name of the table on which the REPLACE query will
+ * be executed.
+ * @param array $fields associative array that describes the fields and the
+ * values that will be inserted or updated in the specified table. The
+ * indexes of the array are the names of all the fields of the table. The
+ * values of the array are also associative arrays that describe the
+ * values and other properties of the table fields.
+ *
+ * Here follows a list of field properties that need to be specified:
+ *
+ * value:
+ * Value to be assigned to the specified field. This value may be
+ * of specified in database independent type format as this
+ * function can perform the necessary datatype conversions.
+ *
+ * Default:
+ * this property is required unless the Null property
+ * is set to 1.
+ *
+ * type
+ * Name of the type of the field. Currently, all types Metabase
+ * are supported except for clob and blob.
+ *
+ * Default: no type conversion
+ *
+ * null
+ * Boolean property that indicates that the value for this field
+ * should be set to null.
+ *
+ * The default value for fields missing in INSERT queries may be
+ * specified the definition of a table. Often, the default value
+ * is already null, but since the REPLACE may be emulated using
+ * an UPDATE query, make sure that all fields of the table are
+ * listed in this function argument array.
+ *
+ * Default: 0
+ *
+ * key
+ * Boolean property that indicates that this field should be
+ * handled as a primary key or at least as part of the compound
+ * unique index of the table that will determine the row that will
+ * updated if it exists or inserted a new row otherwise.
+ *
+ * This function will fail if no key field is specified or if the
+ * value of a key field is set to null because fields that are
+ * part of unique index they may not be null.
+ *
+ * Default: 0
+ *
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ */
+ function replace($table, $fields)
+ {
+ $count = count($fields);
+ $query = $values = '';
+ $keys = $colnum = 0;
+ for (reset($fields); $colnum < $count; next($fields), $colnum++) {
+ $name = key($fields);
+ if ($colnum > 0) {
+ $query .= ',';
+ $values.= ',';
+ }
+ $query.= $this->quoteIdentifier($name, true);
+ if (isset($fields[$name]['null']) && $fields[$name]['null']) {
+ $value = 'NULL';
+ } else {
+ $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
+ $value = $this->quote($fields[$name]['value'], $type);
+ if (PEAR::isError($value)) {
+ return $value;
+ }
+ }
+ $values.= $value;
+ if (isset($fields[$name]['key']) && $fields[$name]['key']) {
+ if ($value === 'NULL') {
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
+ 'key value '.$name.' may not be NULL', __FUNCTION__);
+ }
+ $keys++;
+ }
+ }
+ if ($keys == 0) {
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
+ 'not specified which fields are keys', __FUNCTION__);
+ }
+
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+
+ $table = $this->quoteIdentifier($table, true);
+ $query = "REPLACE INTO $table ($query) VALUES ($values)";
+ $result = $this->_doQuery($query, true, $connection);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return $this->_affectedRows($connection, $result);
+ }
+
+ // }}}
+ // {{{ nextID()
+
+ /**
+ * Returns the next free id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @param boolean $ondemand when true the sequence is
+ * automatic created, if it
+ * not exists
+ *
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function nextID($seq_name, $ondemand = true)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ $seqcol_name = $this->options['seqcol_name'];
+ $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->expectError(MDB2_ERROR_NOSUCHTABLE);
+ $result = $this->_doQuery($query, true);
+ $this->popExpect();
+ $this->popErrorHandling();
+ if (PEAR::isError($result)) {
+ if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
+ $this->loadModule('Manager', null, true);
+ $result = $this->manager->createSequence($seq_name);
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result, null, null,
+ 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__);
+ } else {
+ return $this->nextID($seq_name, false);
+ }
+ }
+ return $result;
+ }
+ $value = $this->lastInsertID();
+ if (is_numeric($value)) {
+ $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
+ $result = $this->_doQuery($query, true);
+ if (PEAR::isError($result)) {
+ $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name;
+ }
+ }
+ return $value;
+ }
+
+ // }}}
+ // {{{ lastInsertID()
+
+ /**
+ * Returns the autoincrement ID if supported or $id or fetches the current
+ * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param string $field name of the field into which a new row was inserted
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function lastInsertID($table = null, $field = null)
+ {
+ $connection = $this->getConnection();
+ if (PEAR::isError($connection)) {
+ return $connection;
+ }
+ $value = @sqlite_last_insert_rowid($connection);
+ if (!$value) {
+ return $this->raiseError(null, null, null,
+ 'Could not get last insert ID', __FUNCTION__);
+ }
+ return $value;
+ }
+
+ // }}}
+ // {{{ currID()
+
+ /**
+ * Returns the current id of a sequence
+ *
+ * @param string $seq_name name of the sequence
+ * @return mixed MDB2 Error Object or id
+ * @access public
+ */
+ function currID($seq_name)
+ {
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
+ $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
+ $query = "SELECT MAX($seqcol_name) FROM $sequence_name";
+ return $this->queryOne($query, 'integer');
+ }
+}
+
+/**
+ * MDB2 SQLite result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Result_sqlite extends MDB2_Result_Common
+{
+ // }}}
+ // {{{ fetchRow()
+
+ /**
+ * Fetch a row and insert the data into an existing array.
+ *
+ * @param int $fetchmode how the array data should be indexed
+ * @param int $rownum number of the row where the data can be found
+ * @return int data array on success, a MDB2 error on failure
+ * @access public
+ */
+ function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null)
+ {
+ if (null !== $rownum) {
+ $seek = $this->seek($rownum);
+ if (PEAR::isError($seek)) {
+ return $seek;
+ }
+ }
+ if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
+ $fetchmode = $this->db->fetchmode;
+ }
+ if ($fetchmode & MDB2_FETCHMODE_ASSOC) {
+ $row = @sqlite_fetch_array($this->result, SQLITE_ASSOC);
+ if (is_array($row)
+ && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
+ ) {
+ $row = array_change_key_case($row, $this->db->options['field_case']);
+ }
+ } else {
+ $row = @sqlite_fetch_array($this->result, SQLITE_NUM);
+ }
+ if (!$row) {
+ if (false === $this->result) {
+ $err = $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ return $err;
+ }
+ return null;
+ }
+ $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL;
+ $rtrim = false;
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) {
+ if (empty($this->types)) {
+ $mode += MDB2_PORTABILITY_RTRIM;
+ } else {
+ $rtrim = true;
+ }
+ }
+ if ($mode) {
+ $this->db->_fixResultArrayValues($row, $mode);
+ }
+ if (!empty($this->types)) {
+ $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim);
+ }
+ if (!empty($this->values)) {
+ $this->_assignBindColumns($row);
+ }
+ if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
+ $object_class = $this->db->options['fetch_class'];
+ if ($object_class == 'stdClass') {
+ $row = (object) $row;
+ } else {
+ $rowObj = new $object_class($row);
+ $row = $rowObj;
+ }
+ }
+ ++$this->rownum;
+ return $row;
+ }
+
+ // }}}
+ // {{{ _getColumnNames()
+
+ /**
+ * Retrieve the names of columns returned by the DBMS in a query result.
+ *
+ * @return mixed Array variable that holds the names of columns as keys
+ * or an MDB2 error on failure.
+ * Some DBMS may not return any columns when the result set
+ * does not contain any rows.
+ * @access private
+ */
+ function _getColumnNames()
+ {
+ $columns = array();
+ $numcols = $this->numCols();
+ if (PEAR::isError($numcols)) {
+ return $numcols;
+ }
+ for ($column = 0; $column < $numcols; $column++) {
+ $column_name = @sqlite_field_name($this->result, $column);
+ $columns[$column_name] = $column;
+ }
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
+ $columns = array_change_key_case($columns, $this->db->options['field_case']);
+ }
+ return $columns;
+ }
+
+ // }}}
+ // {{{ numCols()
+
+ /**
+ * Count the number of columns returned by the DBMS in a query result.
+ *
+ * @access public
+ * @return mixed integer value with the number of columns, a MDB2 error
+ * on failure
+ */
+ function numCols()
+ {
+ $cols = @sqlite_num_fields($this->result);
+ if (null === $cols) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return count($this->types);
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get column count', __FUNCTION__);
+ }
+ return $cols;
+ }
+}
+
+/**
+ * MDB2 SQLite buffered result driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_BufferedResult_sqlite extends MDB2_Result_sqlite
+{
+ // {{{ seek()
+
+ /**
+ * Seek to a specific row in a result set
+ *
+ * @param int $rownum number of the row where the data can be found
+ * @return mixed MDB2_OK on success, a MDB2 error on failure
+ * @access public
+ */
+ function seek($rownum = 0)
+ {
+ if (!@sqlite_seek($this->result, $rownum)) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return MDB2_OK;
+ }
+ return $this->db->raiseError(MDB2_ERROR_INVALID, null, null,
+ 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__);
+ }
+ $this->rownum = $rownum - 1;
+ return MDB2_OK;
+ }
+
+ // }}}
+ // {{{ 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
+ */
+ function valid()
+ {
+ $numrows = $this->numRows();
+ if (PEAR::isError($numrows)) {
+ return $numrows;
+ }
+ return $this->rownum < ($numrows - 1);
+ }
+
+ // }}}
+ // {{{ numRows()
+
+ /**
+ * Returns the number of rows in a result object
+ *
+ * @return mixed MDB2 Error Object or the number of rows
+ * @access public
+ */
+ function numRows()
+ {
+ $rows = @sqlite_num_rows($this->result);
+ if (null === $rows) {
+ if (false === $this->result) {
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'resultset has already been freed', __FUNCTION__);
+ }
+ if (null === $this->result) {
+ return 0;
+ }
+ return $this->db->raiseError(null, null, null,
+ 'Could not get row count', __FUNCTION__);
+ }
+ return $rows;
+ }
+}
+
+/**
+ * MDB2 SQLite statement driver
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Statement_sqlite extends MDB2_Statement_Common
+{
+
+}
+?>
\ No newline at end of file diff --git a/3rdparty/MDB2/Extended.php b/3rdparty/MDB2/Extended.php index 864ab923543..fed82f96598 100644 --- a/3rdparty/MDB2/Extended.php +++ b/3rdparty/MDB2/Extended.php @@ -1,721 +1,720 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP versions 4 and 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Extended.php,v 1.60 2007/11/28 19:49:34 quipo Exp $ - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ - -/** - * Used by autoPrepare() - */ -define('MDB2_AUTOQUERY_INSERT', 1); -define('MDB2_AUTOQUERY_UPDATE', 2); -define('MDB2_AUTOQUERY_DELETE', 3); -define('MDB2_AUTOQUERY_SELECT', 4); - -/** - * MDB2_Extended: class which adds several high level methods to MDB2 - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_Extended extends MDB2_Module_Common -{ - // {{{ autoPrepare() - - /** - * Generate an insert, update or delete query and call prepare() on it - * - * @param string table - * @param array the fields names - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) - * @param array that contains the types of the placeholders - * @param mixed array that contains the types of the columns in - * the result set or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * - * @return resource handle for the query - * @see buildManipSQL - * @access public - */ - function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, - $where = false, $types = null, $result_types = MDB2_PREPARE_MANIP) - { - $query = $this->buildManipSQL($table, $table_fields, $mode, $where); - if (PEAR::isError($query)) { - return $query; - } - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $lobs = array(); - foreach ((array)$types as $param => $type) { - if (($type == 'clob') || ($type == 'blob')) { - $lobs[$param] = $table_fields[$param]; - } - } - return $db->prepare($query, $types, $result_types, $lobs); - } - - // }}} - // {{{ autoExecute() - - /** - * Generate an insert, update or delete query and call prepare() and execute() on it - * - * @param string name of the table - * @param array assoc ($key=>$value) where $key is a field name and $value its value - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) - * @param array that contains the types of the placeholders - * @param string which specifies which result class to use - * @param mixed array that contains the types of the columns in - * the result set or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * - * @return bool|MDB2_Error true on success, a MDB2 error on failure - * @see buildManipSQL - * @see autoPrepare - * @access public - */ - function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT, - $where = false, $types = null, $result_class = true, $result_types = MDB2_PREPARE_MANIP) - { - $fields_values = (array)$fields_values; - if ($mode == MDB2_AUTOQUERY_SELECT) { - if (is_array($result_types)) { - $keys = array_keys($result_types); - } elseif (!empty($fields_values)) { - $keys = $fields_values; - } else { - $keys = array(); - } - } else { - $keys = array_keys($fields_values); - } - $params = array_values($fields_values); - if (empty($params)) { - $query = $this->buildManipSQL($table, $keys, $mode, $where); - - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if ($mode == MDB2_AUTOQUERY_SELECT) { - $result =& $db->query($query, $result_types, $result_class); - } else { - $result = $db->exec($query); - } - } else { - $stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types); - if (PEAR::isError($stmt)) { - return $stmt; - } - $result =& $stmt->execute($params, $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/DELETE query, all - * the records of the table will be updated/deleted ! - * - * @param string name of the table - * @param ordered array containing the fields names - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete 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 ($db->options['quote_identifier']) { - $table = $db->quoteIdentifier($table); - } - - if (!empty($table_fields) && $db->options['quote_identifier']) { - foreach ($table_fields as $key => $field) { - $table_fields[$key] = $db->quoteIdentifier($field); - } - } - - if ($where !== false && !is_null($where)) { - if (is_array($where)) { - $where = implode(' AND ', $where); - } - $where = ' WHERE '.$where; - } - - switch ($mode) { - case MDB2_AUTOQUERY_INSERT: - if (empty($table_fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Insert requires table fields', __FUNCTION__); - } - $cols = implode(', ', $table_fields); - $values = '?'.str_repeat(', ?', (count($table_fields) - 1)); - return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')'; - break; - case MDB2_AUTOQUERY_UPDATE: - if (empty($table_fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Update requires table fields', __FUNCTION__); - } - $set = implode(' = ?, ', $table_fields).' = ?'; - $sql = 'UPDATE '.$table.' SET '.$set.$where; - return $sql; - break; - case MDB2_AUTOQUERY_DELETE: - $sql = 'DELETE FROM '.$table.$where; - return $sql; - break; - case MDB2_AUTOQUERY_SELECT: - $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*'; - $sql = 'SELECT '.$cols.' FROM '.$table.$where; - return $sql; - break; - } - return $db->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'Non existant mode', __FUNCTION__); - } - - // }}} - // {{{ limitQuery() - - /** - * Generates a limited query - * - * @param string query - * @param array that contains the types of the columns in the result set - * @param integer the numbers of rows to fetch - * @param integer the row to start to fetching - * @param string which specifies which result class to use - * @param mixed string which specifies which class to wrap results in - * - * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure - * @access public - */ - function &limitQuery($query, $types, $limit, $offset = 0, $result_class = true, - $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->setLimit($limit, $offset); - if (PEAR::isError($result)) { - return $result; - } - $result =& $db->query($query, $types, $result_class, $result_wrap_class); - return $result; - } - - // }}} - // {{{ execParam() - - /** - * Execute a parameterized DML statement. - * - * @param string the SQL query - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * - * @return int|MDB2_Error affected rows on success, a MDB2 error on failure - * @access public - */ - function execParam($query, $params = array(), $param_types = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - if (empty($params)) { - return $db->exec($query); - } - - $stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (PEAR::isError($result)) { - return $result; - } - - $stmt->free(); - 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 the SQL query - * @param string that contains the type of the column in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int|string which column to return - * - * @return scalar|MDB2_Error 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 (empty($params)) { - return $db->queryOne($query, $type, $colnum); - } - - $stmt = $db->prepare($query, $param_types, $type); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - 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 the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int the fetch mode to use - * - * @return array|MDB2_Error data 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 (empty($params)) { - return $db->queryRow($query, $types, $fetchmode); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - 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 the SQL query - * @param string that contains the type of the column in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int|string which column to return - * - * @return array|MDB2_Error data 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 (empty($params)) { - return $db->queryCol($query, $type, $colnum); - } - - $stmt = $db->prepare($query, $param_types, $type); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - 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 the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int the fetch mode to use - * @param bool if set to true, the $all will have the first - * column as its first dimension - * @param bool $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 bool $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|MDB2_Error data 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 (empty($params)) { - return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - 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 MDB2 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: - * <pre> - * ID TEXT DATE - * -------------------------------- - * 1 'one' 944679408 - * 2 'two' 944679408 - * 3 'three' 944679408 - * </pre> - * Then the call getAssoc('SELECT id,text FROM mytable') returns: - * <pre> - * array( - * '1' => 'one', - * '2' => 'two', - * '3' => 'three', - * ) - * </pre> - * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: - * <pre> - * array( - * '1' => array('one', '944679408'), - * '2' => array('two', '944679408'), - * '3' => array('three', '944679408') - * ) - * </pre> - * - * 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: - * <pre> - * 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') - * ) - * ) - * </pre> - * - * Keep in mind that database functions in PHP usually return string - * values for results regardless of the database's internal type. - * - * @param string the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure - * @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 (empty($params)) { - return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - 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 query handle from prepare() - * @param array numeric array containing the data to insert into the query - * - * @return bool|MDB2_Error true 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++) { - $result = $stmt->execute($params[$i]); - 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 name of the table into which a new row was inserted - * @param string name of the field into which a new row was inserted - * @param bool when true the sequence is automatic created, if it not exists - * @param bool if the returned value should be quoted - * - * @return int|MDB2_Error id on success, a MDB2 error on failure - * @access public - */ - function getBeforeID($table, $field = null, $ondemand = true, $quote = 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 (!$quote || PEAR::isError($id)) { - return $id; - } - return $db->quote($id, 'integer'); - } elseif (!$quote) { - return null; - } - return 'NULL'; - } - - // }}} - // {{{ getAfterID() - - /** - * Returns the autoincrement ID if supported or $id - * - * @param mixed value as returned by getBeforeId() - * @param string name of the table into which a new row was inserted - * @param string name of the field into which a new row was inserted - * - * @return int|MDB2_Error id on success, a MDB2 error on failure - * @access public - */ - function getAfterID($id, $table, $field = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if ($db->supports('auto_increment') !== true) { - return $id; - } - return $db->lastInsertID($table, $field); - } - - // }}} -} +<?php
+// +----------------------------------------------------------------------+
+// | PHP versions 4 and 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Extended.php 302784 2010-08-25 23:29:16Z quipo $
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+
+/**
+ * Used by autoPrepare()
+ */
+define('MDB2_AUTOQUERY_INSERT', 1);
+define('MDB2_AUTOQUERY_UPDATE', 2);
+define('MDB2_AUTOQUERY_DELETE', 3);
+define('MDB2_AUTOQUERY_SELECT', 4);
+
+/**
+ * MDB2_Extended: class which adds several high level methods to MDB2
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_Extended extends MDB2_Module_Common
+{
+ // {{{ autoPrepare()
+
+ /**
+ * Generate an insert, update or delete query and call prepare() on it
+ *
+ * @param string table
+ * @param array the fields names
+ * @param int type of query to build
+ * MDB2_AUTOQUERY_INSERT
+ * MDB2_AUTOQUERY_UPDATE
+ * MDB2_AUTOQUERY_DELETE
+ * MDB2_AUTOQUERY_SELECT
+ * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
+ * @param array that contains the types of the placeholders
+ * @param mixed array that contains the types of the columns in
+ * the result set or MDB2_PREPARE_RESULT, if set to
+ * MDB2_PREPARE_MANIP the query is handled as a manipulation query
+ *
+ * @return resource handle for the query
+ * @see buildManipSQL
+ * @access public
+ */
+ function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT,
+ $where = false, $types = null, $result_types = MDB2_PREPARE_MANIP)
+ {
+ $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
+ if (PEAR::isError($query)) {
+ return $query;
+ }
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ $lobs = array();
+ foreach ((array)$types as $param => $type) {
+ if (($type == 'clob') || ($type == 'blob')) {
+ $lobs[$param] = $table_fields[$param];
+ }
+ }
+ return $db->prepare($query, $types, $result_types, $lobs);
+ }
+
+ // }}}
+ // {{{ autoExecute()
+
+ /**
+ * Generate an insert, update or delete query and call prepare() and execute() on it
+ *
+ * @param string name of the table
+ * @param array assoc ($key=>$value) where $key is a field name and $value its value
+ * @param int type of query to build
+ * MDB2_AUTOQUERY_INSERT
+ * MDB2_AUTOQUERY_UPDATE
+ * MDB2_AUTOQUERY_DELETE
+ * MDB2_AUTOQUERY_SELECT
+ * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
+ * @param array that contains the types of the placeholders
+ * @param string which specifies which result class to use
+ * @param mixed array that contains the types of the columns in
+ * the result set or MDB2_PREPARE_RESULT, if set to
+ * MDB2_PREPARE_MANIP the query is handled as a manipulation query
+ *
+ * @return bool|MDB2_Error true on success, a MDB2 error on failure
+ * @see buildManipSQL
+ * @see autoPrepare
+ * @access public
+ */
+ function autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT,
+ $where = false, $types = null, $result_class = true, $result_types = MDB2_PREPARE_MANIP)
+ {
+ $fields_values = (array)$fields_values;
+ if ($mode == MDB2_AUTOQUERY_SELECT) {
+ if (is_array($result_types)) {
+ $keys = array_keys($result_types);
+ } elseif (!empty($fields_values)) {
+ $keys = $fields_values;
+ } else {
+ $keys = array();
+ }
+ } else {
+ $keys = array_keys($fields_values);
+ }
+ $params = array_values($fields_values);
+ if (empty($params)) {
+ $query = $this->buildManipSQL($table, $keys, $mode, $where);
+
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+ if ($mode == MDB2_AUTOQUERY_SELECT) {
+ $result = $db->query($query, $result_types, $result_class);
+ } else {
+ $result = $db->exec($query);
+ }
+ } else {
+ $stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+ $result = $stmt->execute($params, $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/DELETE query, all
+ * the records of the table will be updated/deleted !
+ *
+ * @param string name of the table
+ * @param ordered array containing the fields names
+ * @param int type of query to build
+ * MDB2_AUTOQUERY_INSERT
+ * MDB2_AUTOQUERY_UPDATE
+ * MDB2_AUTOQUERY_DELETE
+ * MDB2_AUTOQUERY_SELECT
+ * @param string (in case of update and delete 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 ($db->options['quote_identifier']) {
+ $table = $db->quoteIdentifier($table);
+ }
+
+ if (!empty($table_fields) && $db->options['quote_identifier']) {
+ foreach ($table_fields as $key => $field) {
+ $table_fields[$key] = $db->quoteIdentifier($field);
+ }
+ }
+
+ if ((false !== $where) && (null !== $where)) {
+ if (is_array($where)) {
+ $where = implode(' AND ', $where);
+ }
+ $where = ' WHERE '.$where;
+ }
+
+ switch ($mode) {
+ case MDB2_AUTOQUERY_INSERT:
+ if (empty($table_fields)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'Insert requires table fields', __FUNCTION__);
+ }
+ $cols = implode(', ', $table_fields);
+ $values = '?'.str_repeat(', ?', (count($table_fields) - 1));
+ return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')';
+ break;
+ case MDB2_AUTOQUERY_UPDATE:
+ if (empty($table_fields)) {
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
+ 'Update requires table fields', __FUNCTION__);
+ }
+ $set = implode(' = ?, ', $table_fields).' = ?';
+ $sql = 'UPDATE '.$table.' SET '.$set.$where;
+ return $sql;
+ break;
+ case MDB2_AUTOQUERY_DELETE:
+ $sql = 'DELETE FROM '.$table.$where;
+ return $sql;
+ break;
+ case MDB2_AUTOQUERY_SELECT:
+ $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*';
+ $sql = 'SELECT '.$cols.' FROM '.$table.$where;
+ return $sql;
+ break;
+ }
+ return $db->raiseError(MDB2_ERROR_SYNTAX, null, null,
+ 'Non existant mode', __FUNCTION__);
+ }
+
+ // }}}
+ // {{{ limitQuery()
+
+ /**
+ * Generates a limited query
+ *
+ * @param string query
+ * @param array that contains the types of the columns in the result set
+ * @param integer the numbers of rows to fetch
+ * @param integer the row to start to fetching
+ * @param string which specifies which result class to use
+ * @param mixed string which specifies which class to wrap results in
+ *
+ * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure
+ * @access public
+ */
+ function limitQuery($query, $types, $limit, $offset = 0, $result_class = true,
+ $result_wrap_class = false)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ $result = $db->setLimit($limit, $offset);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ return $db->query($query, $types, $result_class, $result_wrap_class);
+ }
+
+ // }}}
+ // {{{ execParam()
+
+ /**
+ * Execute a parameterized DML statement.
+ *
+ * @param string the SQL query
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ *
+ * @return int|MDB2_Error affected rows on success, a MDB2 error on failure
+ * @access public
+ */
+ function execParam($query, $params = array(), $param_types = null)
+ {
+ $db = $this->getDBInstance();
+ if (PEAR::isError($db)) {
+ return $db;
+ }
+
+ settype($params, 'array');
+ if (empty($params)) {
+ return $db->exec($query);
+ }
+
+ $stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ $stmt->free();
+ 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 the SQL query
+ * @param string that contains the type of the column in the result set
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ * @param int|string which column to return
+ *
+ * @return scalar|MDB2_Error 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 (empty($params)) {
+ return $db->queryOne($query, $type, $colnum);
+ }
+
+ $stmt = $db->prepare($query, $param_types, $type);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ 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 the SQL query
+ * @param array that contains the types of the columns in the result set
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ * @param int the fetch mode to use
+ *
+ * @return array|MDB2_Error data 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 (empty($params)) {
+ return $db->queryRow($query, $types, $fetchmode);
+ }
+
+ $stmt = $db->prepare($query, $param_types, $types);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ 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 the SQL query
+ * @param string that contains the type of the column in the result set
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ * @param int|string which column to return
+ *
+ * @return array|MDB2_Error data 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 (empty($params)) {
+ return $db->queryCol($query, $type, $colnum);
+ }
+
+ $stmt = $db->prepare($query, $param_types, $type);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ 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 the SQL query
+ * @param array that contains the types of the columns in the result set
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ * @param int the fetch mode to use
+ * @param bool if set to true, the $all will have the first
+ * column as its first dimension
+ * @param bool $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 bool $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|MDB2_Error data 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 (empty($params)) {
+ return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group);
+ }
+
+ $stmt = $db->prepare($query, $param_types, $types);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ 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 MDB2 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:
+ * <pre>
+ * ID TEXT DATE
+ * --------------------------------
+ * 1 'one' 944679408
+ * 2 'two' 944679408
+ * 3 'three' 944679408
+ * </pre>
+ * Then the call getAssoc('SELECT id,text FROM mytable') returns:
+ * <pre>
+ * array(
+ * '1' => 'one',
+ * '2' => 'two',
+ * '3' => 'three',
+ * )
+ * </pre>
+ * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
+ * <pre>
+ * array(
+ * '1' => array('one', '944679408'),
+ * '2' => array('two', '944679408'),
+ * '3' => array('three', '944679408')
+ * )
+ * </pre>
+ *
+ * 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:
+ * <pre>
+ * 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')
+ * )
+ * )
+ * </pre>
+ *
+ * Keep in mind that database functions in PHP usually return string
+ * values for results regardless of the database's internal type.
+ *
+ * @param string the SQL query
+ * @param array that contains the types of the columns in the result set
+ * @param array if supplied, prepare/execute will be used
+ * with this array as execute parameters
+ * @param array that contains the types of the values defined in $params
+ * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure
+ * @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 (empty($params)) {
+ return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group);
+ }
+
+ $stmt = $db->prepare($query, $param_types, $types);
+ if (PEAR::isError($stmt)) {
+ return $stmt;
+ }
+
+ $result = $stmt->execute($params);
+ 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 query handle from prepare()
+ * @param array numeric array containing the data to insert into the query
+ *
+ * @return bool|MDB2_Error true 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++) {
+ $result = $stmt->execute($params[$i]);
+ 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 name of the table into which a new row was inserted
+ * @param string name of the field into which a new row was inserted
+ * @param bool when true the sequence is automatic created, if it not exists
+ * @param bool if the returned value should be quoted
+ *
+ * @return int|MDB2_Error id on success, a MDB2 error on failure
+ * @access public
+ */
+ function getBeforeID($table, $field = null, $ondemand = true, $quote = 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 (!$quote || PEAR::isError($id)) {
+ return $id;
+ }
+ return $db->quote($id, 'integer');
+ } elseif (!$quote) {
+ return null;
+ }
+ return 'NULL';
+ }
+
+ // }}}
+ // {{{ getAfterID()
+
+ /**
+ * Returns the autoincrement ID if supported or $id
+ *
+ * @param mixed value as returned by getBeforeId()
+ * @param string name of the table into which a new row was inserted
+ * @param string name of the field into which a new row was inserted
+ *
+ * @return int|MDB2_Error id on success, a MDB2 error on failure
+ * @access public
+ */
+ function getAfterID($id, $table, $field = null)
+ {
+ $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/3rdparty/MDB2/Iterator.php b/3rdparty/MDB2/Iterator.php index ca5e7b69c27..8d31919b6de 100644 --- a/3rdparty/MDB2/Iterator.php +++ b/3rdparty/MDB2/Iterator.php @@ -1,259 +1,259 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP version 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: Iterator.php,v 1.22 2006/05/06 14:03:41 lsmith Exp $ - -/** - * PHP5 Iterator - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -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 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 bool true/false, false is also returned on failure - * @access public - */ - public function valid() - { - return (bool)$this->current(); - } - // }}} - - // {{{ free() - - /** - * Free the internal resources associated with result. - * - * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @access public - */ - public function free() - { - if ($this->result) { - return $this->result->free(); - } - $this->result = false; - $this->row = null; - return false; - } - // }}} - - // {{{ key() - - /** - * Returns the row number - * - * @return int|bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @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(); - } - // }}} -} - -/** - * PHP5 buffered Iterator - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator -{ - // {{{ valid() - - /** - * Check if the end of the result set has been reached - * - * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @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 int|MDB2_Error number of rows, false|MDB2_Error if result is invalid - * @access public - */ - public function count() - { - if ($this->result) { - return $this->result->numRows(); - } - return false; - } - // }}} - - // {{{ rewind() - - /** - * Seek to the first row in a result set - * - * @return void - * @access public - */ - public function rewind() - { - $this->seek(0); - } - // }}} -} - +<?php
+// +----------------------------------------------------------------------+
+// | PHP version 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: Iterator.php 295586 2010-02-28 17:04:17Z quipo $
+
+/**
+ * PHP5 Iterator
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+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 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 (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 bool true/false, false is also returned on failure
+ * @access public
+ */
+ public function valid()
+ {
+ return (bool)$this->current();
+ }
+ // }}}
+
+ // {{{ free()
+
+ /**
+ * Free the internal resources associated with result.
+ *
+ * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid
+ * @access public
+ */
+ public function free()
+ {
+ if ($this->result) {
+ return $this->result->free();
+ }
+ $this->result = false;
+ $this->row = null;
+ return false;
+ }
+ // }}}
+
+ // {{{ key()
+
+ /**
+ * Returns the row number
+ *
+ * @return int|bool|MDB2_Error true on success, false|MDB2_Error if result is invalid
+ * @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();
+ }
+ // }}}
+}
+
+/**
+ * PHP5 buffered Iterator
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator
+{
+ // {{{ valid()
+
+ /**
+ * Check if the end of the result set has been reached
+ *
+ * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid
+ * @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 int|MDB2_Error number of rows, false|MDB2_Error if result is invalid
+ * @access public
+ */
+ public function count()
+ {
+ if ($this->result) {
+ return $this->result->numRows();
+ }
+ return false;
+ }
+ // }}}
+
+ // {{{ rewind()
+
+ /**
+ * Seek to the first row in a result set
+ *
+ * @return void
+ * @access public
+ */
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+ // }}}
+}
+
?>
\ No newline at end of file diff --git a/3rdparty/MDB2/LOB.php b/3rdparty/MDB2/LOB.php index ae67224020e..f7df13dc478 100644 --- a/3rdparty/MDB2/LOB.php +++ b/3rdparty/MDB2/LOB.php @@ -1,264 +1,264 @@ -<?php -// +----------------------------------------------------------------------+ -// | PHP version 5 | -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ -// | Author: Lukas Smith <smith@pooteeweet.org> | -// +----------------------------------------------------------------------+ -// -// $Id: LOB.php,v 1.34 2006/10/25 11:52:21 lsmith Exp $ - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ - -require_once('MDB2.php'); - -/** - * MDB2_LOB: user land stream wrapper implementation for LOB support - * - * @package MDB2 - * @category Database - * @author Lukas Smith <smith@pooteeweet.org> - */ -class MDB2_LOB -{ - /** - * contains the key to the global MDB2 instance array of the associated - * MDB2 instance - * - * @var integer - * @access protected - */ - var $db_index; - - /** - * contains the key to the global MDB2_LOB instance array of the associated - * MDB2_LOB instance - * - * @var integer - * @access protected - */ - var $lob_index; - - // {{{ stream_open() - - /** - * open stream - * - * @param string specifies the URL that was passed to fopen() - * @param string the mode used to open the file - * @param int holds additional flags set by the streams API - * @param string not used - * - * @return bool - * @access public - */ - function stream_open($path, $mode, $options, &$opened_path) - { - if (!preg_match('/^rb?\+?$/', $mode)) { - return false; - } - $url = parse_url($path); - if (empty($url['host'])) { - return false; - } - $this->db_index = (int)$url['host']; - if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - return false; - } - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $this->lob_index = (int)$url['user']; - if (!isset($db->datatype->lobs[$this->lob_index])) { - return false; - } - return true; - } - // }}} - - // {{{ stream_read() - - /** - * read stream - * - * @param int number of bytes to read - * - * @return string - * @access public - */ - function stream_read($count) - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $db->datatype->_retrieveLOB($db->datatype->lobs[$this->lob_index]); - - $data = $db->datatype->_readLOB($db->datatype->lobs[$this->lob_index], $count); - $length = strlen($data); - if ($length == 0) { - $db->datatype->lobs[$this->lob_index]['endOfLOB'] = true; - } - $db->datatype->lobs[$this->lob_index]['position'] += $length; - return $data; - } - } - // }}} - - // {{{ stream_write() - - /** - * write stream, note implemented - * - * @param string data - * - * @return int - * @access public - */ - function stream_write($data) - { - return 0; - } - // }}} - - // {{{ stream_tell() - - /** - * return the current position - * - * @return int current position - * @access public - */ - function stream_tell() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - return $db->datatype->lobs[$this->lob_index]['position']; - } - } - // }}} - - // {{{ stream_eof() - - /** - * Check if stream reaches EOF - * - * @return bool - * @access public - */ - function stream_eof() - { - if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - return true; - } - - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $result = $db->datatype->_endOfLOB($db->datatype->lobs[$this->lob_index]); - if (version_compare(phpversion(), "5.0", ">=") - && version_compare(phpversion(), "5.1", "<") - ) { - return !$result; - } - return $result; - } - // }}} - - // {{{ stream_seek() - - /** - * Seek stream, not implemented - * - * @param int offset - * @param int whence - * - * @return bool - * @access public - */ - function stream_seek($offset, $whence) - { - return false; - } - // }}} - - // {{{ stream_stat() - - /** - * return information about stream - * - * @access public - */ - function stream_stat() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - return array( - 'db_index' => $this->db_index, - 'lob_index' => $this->lob_index, - ); - } - } - // }}} - - // {{{ stream_close() - - /** - * close stream - * - * @access public - */ - 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($db->datatype->lobs[$this->lob_index]); - unset($db->datatype->lobs[$this->lob_index]); - } - } - } - // }}} -} - -// register streams wrapper -if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) { - MDB2::raiseError(); - return false; -} - -?> +<?php
+// +----------------------------------------------------------------------+
+// | PHP version 5 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
+// | Stig. S. Bakken, Lukas Smith |
+// | All rights reserved. |
+// +----------------------------------------------------------------------+
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
+// | API as well as database abstraction for PHP applications. |
+// | This LICENSE is in the BSD license style. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | |
+// | Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution. |
+// | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
+// | Lukas Smith nor the names of his contributors may be used to endorse |
+// | or promote products derived from this software without specific prior|
+// | written permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+// | POSSIBILITY OF SUCH DAMAGE. |
+// +----------------------------------------------------------------------+
+// | Author: Lukas Smith <smith@pooteeweet.org> |
+// +----------------------------------------------------------------------+
+//
+// $Id: LOB.php 222350 2006-10-25 11:52:21Z lsmith $
+
+/**
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+
+require_once 'MDB2.php';
+
+/**
+ * MDB2_LOB: user land stream wrapper implementation for LOB support
+ *
+ * @package MDB2
+ * @category Database
+ * @author Lukas Smith <smith@pooteeweet.org>
+ */
+class MDB2_LOB
+{
+ /**
+ * contains the key to the global MDB2 instance array of the associated
+ * MDB2 instance
+ *
+ * @var integer
+ * @access protected
+ */
+ var $db_index;
+
+ /**
+ * contains the key to the global MDB2_LOB instance array of the associated
+ * MDB2_LOB instance
+ *
+ * @var integer
+ * @access protected
+ */
+ var $lob_index;
+
+ // {{{ stream_open()
+
+ /**
+ * open stream
+ *
+ * @param string specifies the URL that was passed to fopen()
+ * @param string the mode used to open the file
+ * @param int holds additional flags set by the streams API
+ * @param string not used
+ *
+ * @return bool
+ * @access public
+ */
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ if (!preg_match('/^rb?\+?$/', $mode)) {
+ return false;
+ }
+ $url = parse_url($path);
+ if (empty($url['host'])) {
+ return false;
+ }
+ $this->db_index = (int)$url['host'];
+ if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
+ return false;
+ }
+ $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
+ $this->lob_index = (int)$url['user'];
+ if (!isset($db->datatype->lobs[$this->lob_index])) {
+ return false;
+ }
+ return true;
+ }
+ // }}}
+
+ // {{{ stream_read()
+
+ /**
+ * read stream
+ *
+ * @param int number of bytes to read
+ *
+ * @return string
+ * @access public
+ */
+ function stream_read($count)
+ {
+ if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
+ $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
+ $db->datatype->_retrieveLOB($db->datatype->lobs[$this->lob_index]);
+
+ $data = $db->datatype->_readLOB($db->datatype->lobs[$this->lob_index], $count);
+ $length = strlen($data);
+ if ($length == 0) {
+ $db->datatype->lobs[$this->lob_index]['endOfLOB'] = true;
+ }
+ $db->datatype->lobs[$this->lob_index]['position'] += $length;
+ return $data;
+ }
+ }
+ // }}}
+
+ // {{{ stream_write()
+
+ /**
+ * write stream, note implemented
+ *
+ * @param string data
+ *
+ * @return int
+ * @access public
+ */
+ function stream_write($data)
+ {
+ return 0;
+ }
+ // }}}
+
+ // {{{ stream_tell()
+
+ /**
+ * return the current position
+ *
+ * @return int current position
+ * @access public
+ */
+ function stream_tell()
+ {
+ if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
+ $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
+ return $db->datatype->lobs[$this->lob_index]['position'];
+ }
+ }
+ // }}}
+
+ // {{{ stream_eof()
+
+ /**
+ * Check if stream reaches EOF
+ *
+ * @return bool
+ * @access public
+ */
+ function stream_eof()
+ {
+ if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
+ return true;
+ }
+
+ $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
+ $result = $db->datatype->_endOfLOB($db->datatype->lobs[$this->lob_index]);
+ if (version_compare(phpversion(), "5.0", ">=")
+ && version_compare(phpversion(), "5.1", "<")
+ ) {
+ return !$result;
+ }
+ return $result;
+ }
+ // }}}
+
+ // {{{ stream_seek()
+
+ /**
+ * Seek stream, not implemented
+ *
+ * @param int offset
+ * @param int whence
+ *
+ * @return bool
+ * @access public
+ */
+ function stream_seek($offset, $whence)
+ {
+ return false;
+ }
+ // }}}
+
+ // {{{ stream_stat()
+
+ /**
+ * return information about stream
+ *
+ * @access public
+ */
+ function stream_stat()
+ {
+ if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
+ $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
+ return array(
+ 'db_index' => $this->db_index,
+ 'lob_index' => $this->lob_index,
+ );
+ }
+ }
+ // }}}
+
+ // {{{ stream_close()
+
+ /**
+ * close stream
+ *
+ * @access public
+ */
+ 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($db->datatype->lobs[$this->lob_index]);
+ unset($db->datatype->lobs[$this->lob_index]);
+ }
+ }
+ }
+ // }}}
+}
+
+// register streams wrapper
+if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) {
+ MDB2::raiseError();
+ return false;
+}
+
+?>
diff --git a/3rdparty/MDB2/Schema.php b/3rdparty/MDB2/Schema.php index 25818460a62..03739701813 100644 --- a/3rdparty/MDB2/Schema.php +++ b/3rdparty/MDB2/Schema.php @@ -51,7 +51,7 @@ * @link http://pear.php.net/packages/MDB2_Schema */ -// require_once('MDB2.php'); +require_once 'MDB2.php'; define('MDB2_SCHEMA_DUMP_ALL', 0); define('MDB2_SCHEMA_DUMP_STRUCTURE', 1); @@ -237,9 +237,10 @@ class MDB2_Schema extends PEAR * @access public * @see MDB2::parseDSN */ - static function factory(&$db, $options = array()) + function &factory(&$db, $options = array()) { - $obj =new MDB2_Schema(); + $obj =& new MDB2_Schema(); + $result = $obj->connect($db, $options); if (PEAR::isError($result)) { return $result; @@ -280,14 +281,16 @@ class MDB2_Schema extends PEAR } } } + $this->disconnect(); if (!MDB2::isConnection($db)) { - $db =MDB2::factory($db, $db_options); + $db =& MDB2::factory($db, $db_options); } if (PEAR::isError($db)) { return $db; } + $this->db =& $db; $this->db->loadModule('Datatype'); $this->db->loadModule('Manager'); @@ -377,7 +380,7 @@ class MDB2_Schema extends PEAR $dtd_file = $this->options['dtd_file']; if ($dtd_file) { include_once 'XML/DTD/XmlValidator.php'; - $dtd =new XML_DTD_XmlValidator; + $dtd =& new XML_DTD_XmlValidator; if (!$dtd->isValid($dtd_file, $input_file)) { return $this->raiseError(MDB2_SCHEMA_ERROR_PARSE, null, null, $dtd->getMessage()); } @@ -390,7 +393,7 @@ class MDB2_Schema extends PEAR return $result; } - $parser =new $class_name($variables, $fail_on_invalid_names, $structure, $this->options['valid_types'], $this->options['force_defaults']); + $parser =& new $class_name($variables, $fail_on_invalid_names, $structure, $this->options['valid_types'], $this->options['force_defaults']); $result = $parser->setInputFile($input_file); if (PEAR::isError($result)) { return $result; @@ -425,6 +428,7 @@ class MDB2_Schema extends PEAR return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null, 'it was not specified a valid database name'); } + $class_name = $this->options['validate']; $result = MDB2::loadClass($class_name, $this->db->getOption('debug')); @@ -432,7 +436,7 @@ class MDB2_Schema extends PEAR return $result; } - $val =new $class_name($this->options['fail_on_invalid_names'], $this->options['valid_types'], $this->options['force_defaults']); + $val =& new $class_name($this->options['fail_on_invalid_names'], $this->options['valid_types'], $this->options['force_defaults']); $database_definition = array( 'name' => $database, @@ -1338,15 +1342,15 @@ class MDB2_Schema extends PEAR if ($dbExists) { $this->db->debug('Database already exists: ' . $db_name, __FUNCTION__); -// if (!empty($dbOptions)) { -// $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NO_PERMISSION); -// $this->db->expectError($errorcodes); -// $result = $this->db->manager->alterDatabase($db_name, $dbOptions); -// $this->db->popExpect(); -// if (PEAR::isError($result) && !MDB2::isError($result, $errorcodes)) { -// return $result; -// } -// } + if (!empty($dbOptions)) { + $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NO_PERMISSION); + $this->db->expectError($errorcodes); + $result = $this->db->manager->alterDatabase($db_name, $dbOptions); + $this->db->popExpect(); + if (PEAR::isError($result) && !MDB2::isError($result, $errorcodes)) { + return $result; + } + } $create = false; } else { $this->db->expectError(MDB2_ERROR_UNSUPPORTED); @@ -2444,7 +2448,7 @@ class MDB2_Schema extends PEAR } } - $writer = new $class_name($this->options['valid_types']); + $writer =& new $class_name($this->options['valid_types']); return $writer->dumpDatabase($database_definition, $arguments, $dump); } @@ -2692,9 +2696,9 @@ class MDB2_Schema extends PEAR * @access public * @see PEAR_Error */ - function raiseError($code = null, $mode = null, $options = null, $userinfo = null,$a=null,$b=null,$c=null) + function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) { - $err =PEAR::raiseError(null, $code, $mode, $options, + $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Schema_Error', true); return $err; } @@ -2713,7 +2717,7 @@ class MDB2_Schema extends PEAR * @return bool true if parameter is an error * @access public */ - static function isError($data, $code = null) + function isError($data, $code = null) { if (is_a($data, 'MDB2_Schema_Error')) { if (is_null($code)) { diff --git a/3rdparty/MDB2/Schema/Parser.php b/3rdparty/MDB2/Schema/Parser.php index b740ef55fa8..9e8e74b6317 100644 --- a/3rdparty/MDB2/Schema/Parser.php +++ b/3rdparty/MDB2/Schema/Parser.php @@ -54,8 +54,8 @@ */ -require_once('XML/Parser.php'); -require_once('MDB2/Schema/Validate.php'); +require_once 'XML/Parser.php'; +require_once 'MDB2/Schema/Validate.php'; /** * Parses an XML schema file @@ -120,11 +120,18 @@ class MDB2_Schema_Parser extends XML_Parser { // force ISO-8859-1 due to different defaults for PHP4 and PHP5 // todo: this probably needs to be investigated some more andcleaned up - parent::__construct('ISO-8859-1'); + parent::XML_Parser('ISO-8859-1'); $this->variables = $variables; $this->structure = $structure; - $this->val =new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults); + $this->val =& new MDB2_Schema_Validate($fail_on_invalid_names, $valid_types, $force_defaults); + } + + function MDB2_Schema_Parser($variables, $fail_on_invalid_names = true, + $structure = false, $valid_types = array(), + $force_defaults = true) + { + $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); } function startHandler($xp, $element, $attribs) @@ -496,7 +503,7 @@ class MDB2_Schema_Parser extends XML_Parser $this->element = implode('-', $this->elements); } - function raiseError($msg = null, $xmlecode = 0, $xp = null, $ecode = MDB2_SCHEMA_ERROR_PARSE,$a=null,$b=null,$c=null) + function &raiseError($msg = null, $xmlecode = 0, $xp = null, $ecode = MDB2_SCHEMA_ERROR_PARSE) { if (is_null($this->error)) { $error = ''; diff --git a/3rdparty/MDB2/Schema/Validate.php b/3rdparty/MDB2/Schema/Validate.php index 217cf51b959..21be024ce9f 100644 --- a/3rdparty/MDB2/Schema/Validate.php +++ b/3rdparty/MDB2/Schema/Validate.php @@ -91,6 +91,11 @@ class MDB2_Schema_Validate $this->force_defaults = $force_defaults; } + function MDB2_Schema_Validate($fail_on_invalid_names = true, $valid_types = array(), $force_defaults = true) + { + $this->__construct($fail_on_invalid_names, $valid_types, $force_defaults); + } + // }}} // {{{ raiseError() |