New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 FrontbaseSQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Datatype_fbsql extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // }}} |
| | | // {{{ convertResult() |
| | | |
| | | /** |
| | | * convert a value to a RDBMS indepdenant MDB2 type |
| | | * |
| | | * @param mixed $value value to be converted |
| | | * @param int $type constant that specifies which type to convert to |
| | | * @return mixed converted value |
| | | * @access public |
| | | */ |
| | | function convertResult($value, $type) |
| | | { |
| | | if (is_null($value)) { |
| | | return null; |
| | | } |
| | | switch ($type) { |
| | | case 'boolean': |
| | | return $value == 'T'; |
| | | case 'time': |
| | | if ($value[0] == '+') { |
| | | return substr($value, 1); |
| | | } else { |
| | | return $value; |
| | | } |
| | | default: |
| | | return $this->_baseConvertResult($value, $type); |
| | | } |
| | | return $this->_baseConvertResult($value, $type); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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) |
| | | { |
| | | if (array_key_exists('unsigned', $field) && $field['unsigned']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $db->warnings[] = "unsigned integer field \"$name\" is being |
| | | declared as signed integer"; |
| | | } |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' INT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTextDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an text type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the text |
| | | * field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * default |
| | | * Text value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to NULL. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTextDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'text') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | $length = array_key_exists('length', $field) ? $field['length'] : 32768; |
| | | return $name.' VARCHAR ('.$length.')'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field |
| | | * is constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | return "$name CLOB".((array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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 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: |
| | | * |
| | | * 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) |
| | | { |
| | | return "$name BLOB".((array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBooleanDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a boolean type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Boolean value to be used as default for this field. |
| | | * |
| | | * notnullL |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to NULL. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getBooleanDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'boolean') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' BOOLEAN)'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an date 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: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT DATE '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATE'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an timestamp |
| | | * 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: |
| | | * |
| | | * default |
| | | * Time stamp value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT TIMESTAMP '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' TIMESTAMP'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an time 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: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT TIME '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' TIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getFloatDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' FLOAT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $type = 'DECIMAL(18,'.$db->options['decimal_places'].')'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | $value = $this->_readFile($value); |
| | | return "'".addslashes($value)."'"; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBoolean() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBoolean($value) |
| | | { |
| | | return ($value ? 'True' : 'False'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDate() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDate($value) |
| | | { |
| | | return 'DATE'.$this->_quoteText($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteTimestamp() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteTimestamp($value) |
| | | { |
| | | return 'TIMESTAMP'.$this->_quoteText($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteTime() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteTime($value) |
| | | { |
| | | return 'TIME'.$this->_quoteText($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($value); |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // | Lorenzo Alberton <l.alberton@quipo.it> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 Firebird/Interbase driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | * @author Lorenzo Alberton <l.alberton@quipo.it> |
| | | */ |
| | | class MDB2_Driver_Datatype_ibase extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // {{{ convertResult() |
| | | |
| | | /** |
| | | * convert a value to a RDBMS independent MDB2 type |
| | | * |
| | | * @param mixed $value value to be converted |
| | | * @param int $type constant that specifies which type to convert to |
| | | * @return mixed converted value or a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function convertResult($value, $type) |
| | | { |
| | | if (is_null($value)) { |
| | | return null; |
| | | } |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | switch ($type) { |
| | | case 'decimal': |
| | | return sprintf('%.'.$db->options['decimal_places'].'f', doubleval($value)/pow(10.0, $db->options['decimal_places'])); |
| | | case 'timestamp': |
| | | return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS')); |
| | | default: |
| | | return $this->_baseConvertResult($value, $type); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 = (array_key_exists('length', $field) ? $field['length'] : (!PEAR::isError($length = $db->options['default_text_field_length']) ? $length : 4000)); |
| | | return 'VARCHAR ('.$length.')'; |
| | | case 'clob': |
| | | return 'BLOB SUB_TYPE 1'; |
| | | case 'blob': |
| | | return 'BLOB SUB_TYPE 0'; |
| | | case 'integer': |
| | | return 'INTEGER'; |
| | | case 'boolean': |
| | | return 'CHAR (1)'; |
| | | case 'date': |
| | | return 'DATE'; |
| | | case 'time': |
| | | return 'TIME'; |
| | | case 'timestamp': |
| | | return 'TIMESTAMP'; |
| | | case 'float': |
| | | return 'DOUBLE PRECISION'; |
| | | case 'decimal': |
| | | return 'DECIMAL(18,'.$db->options['decimal_places'].')'; |
| | | } |
| | | 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 (array_key_exists('unsigned', $field) && $field['unsigned']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; |
| | | } |
| | | |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | return $name.' PRIMARY KEY'; |
| | | } |
| | | |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' INT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTextDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a 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) |
| | | { |
| | | $type = $this->getTypeDeclaration($field); |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'text') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the large |
| | | * object field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the large |
| | | * object field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getBLOBDeclaration($name, $field) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a date type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a time |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a timestamp |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Timestamp value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getFloatDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a float type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Float value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getFloatDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDecimalDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a decimal type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Decimal value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDecimalDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteLOB($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (PEAR::isError($connect = $db->connect())) { |
| | | return $connect; |
| | | } |
| | | $close = true; |
| | | if (is_resource($value)) { |
| | | $close = false; |
| | | } elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { |
| | | if ($match[1] == 'file://') { |
| | | $value = $match[2]; |
| | | } |
| | | $value = @fopen($value, 'r'); |
| | | } else { |
| | | $fp = @tmpfile(); |
| | | @fwrite($fp, $value); |
| | | @rewind($fp); |
| | | $value = $fp; |
| | | } |
| | | if ($db->in_transaction) { |
| | | $blob_id = @ibase_blob_import($db->transaction_id, $value); |
| | | } else { |
| | | $blob_id = @ibase_blob_import($db->connection, $value); |
| | | } |
| | | if ($close) { |
| | | @fclose($value); |
| | | } |
| | | return $blob_id; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return (strval(round($value*pow(10.0, $db->options['decimal_places'])))); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _retrieveLOB() |
| | | |
| | | /** |
| | | * retrieve LOB from the database |
| | | * |
| | | * @param resource $lob stream handle |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _retrieveLOB(&$lob) |
| | | { |
| | | if (!array_key_exists('handle', $lob)) { |
| | | $lob['handle'] = @ibase_blob_open($lob['ressource']); |
| | | if (!$lob['handle']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_retrieveLOB: Could not open fetched large object field' . @ibase_errmsg()); |
| | | } |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _readLOB() |
| | | |
| | | /** |
| | | * Read data from large object input stream. |
| | | * |
| | | * @param resource $lob stream handle |
| | | * @param blob $data reference to a variable that will hold data to be |
| | | * read from the large object input stream |
| | | * @param int $length integer value that indicates the largest ammount of |
| | | * data to be read from the large object input stream. |
| | | * @return mixed length on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _readLOB($lob, $length) |
| | | { |
| | | $data = ibase_blob_get($lob['handle'], $length); |
| | | if (!is_string($data)) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'Read Result LOB: ' . @ibase_errmsg()); |
| | | } |
| | | return $data; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _destroyLOB() |
| | | |
| | | /** |
| | | * Free any resources allocated during the lifetime of the large object |
| | | * handler object. |
| | | * |
| | | * @param resource $lob stream handle |
| | | * @access protected |
| | | */ |
| | | function _destroyLOB($lob_index) |
| | | { |
| | | if (isset($this->lobs[$lob_index]['handle'])) { |
| | | @ibase_blob_close($this->lobs[$lob_index]['handle']); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 and the length |
| | | * @access public |
| | | */ |
| | | function mapNativeDatatype($field) |
| | | { |
| | | $db_type = preg_replace('/\d/','', strtolower($field['typname']) ); |
| | | $length = $field['attlen']; |
| | | if ($length == '-1') { |
| | | $length = $field['atttypmod']-4; |
| | | } |
| | | if ((int)$length <= 0) { |
| | | $length = null; |
| | | } |
| | | $type = array(); |
| | | switch ($db_type) { |
| | | case 'smallint': |
| | | case 'integer': |
| | | $type[] = 'integer'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | } |
| | | break; |
| | | case 'char': |
| | | case 'varchar': |
| | | $type[] = 'text'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | } |
| | | break; |
| | | case 'date': |
| | | $type[] = 'date'; |
| | | $length = null; |
| | | break; |
| | | case 'timestamp': |
| | | $type[] = 'timestamp'; |
| | | $length = null; |
| | | break; |
| | | case 'time': |
| | | $type[] = 'time'; |
| | | $length = null; |
| | | break; |
| | | case 'float': |
| | | case 'double precision': |
| | | $type[] = 'float'; |
| | | break; |
| | | case 'decimal': |
| | | case 'numeric': |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'blob': |
| | | $type[] = 'blob'; |
| | | $length = null; |
| | | break; |
| | | default: |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: unknown database attribute type'); |
| | | } |
| | | |
| | | return array($type, $length); |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Authors: Lukas Smith <smith@pooteeweet.org> | |
| | | // | Daniel Convissor <danielc@php.net> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MS SQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // {{{ convertResult() |
| | | |
| | | /** |
| | | * convert a value to a RDBMS indepdenant MDB2 type |
| | | * |
| | | * @param mixed $value value to be converted |
| | | * @param int $type constant that specifies which type to convert to |
| | | * @return mixed converted value |
| | | * @access public |
| | | */ |
| | | function convertResult($value, $type) |
| | | { |
| | | if (is_null($value)) { |
| | | return null; |
| | | } |
| | | switch ($type) { |
| | | case 'boolean': |
| | | return $value == '1'; |
| | | case 'date': |
| | | if (strlen($value) > 10) { |
| | | $value = substr($value,0,10); |
| | | } |
| | | return $value; |
| | | case 'time': |
| | | if (strlen($value) > 8) { |
| | | $value = substr($value,11,8); |
| | | } |
| | | return $value; |
| | | default: |
| | | return $this->_baseConvertResult($value,$type); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getIntegerDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an integer type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * unsigned |
| | | * Boolean flag that indicates whether the field should be |
| | | * declared as unsigned integer if possible. |
| | | * |
| | | * default |
| | | * Integer value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getIntegerDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('unsigned', $field) && $field['unsigned']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; |
| | | } |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' INT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTextDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an text type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the text |
| | | * field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * default |
| | | * Text value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTextDeclaration($name, $field) |
| | | { |
| | | $type = array_key_exists('length', $field) ? 'VARCHAR ('.$field['length'].')' : 'TEXT'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'text') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field |
| | | * is constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 8000) { |
| | | $type = "VARCHAR($length)"; |
| | | } else { |
| | | $type = 'TEXT'; |
| | | } |
| | | } else { |
| | | $type = 'TEXT'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * 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) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 8000) { |
| | | $type = "VARBINARY($length)"; |
| | | } else { |
| | | $type = 'IMAGE'; |
| | | } |
| | | } else { |
| | | $type = 'IMAGE'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBooleanDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a boolean type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Boolean value to be used as default for this field. |
| | | * |
| | | * 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 _getBooleanDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'boolean') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' BIT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a date type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' CHAR ('.strlen('YYYY-MM-DD').')'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a timestamp |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Timestamp value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a time |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' CHAR ('.strlen('HH:MM:SS').')'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getFloatDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' FLOAT'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $type = 'DECIMAL(18,'.$db->options['decimal_places'].')'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ' NULL'; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | $value = $this->_readFile($value); |
| | | return bin2hex("0x".$value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBoolean() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBoolean($value) |
| | | { |
| | | return ($value ? 1 : 0); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($value); |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // }}} |
| | | // {{{ _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) |
| | | { |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; |
| | | $default = ''; |
| | | } else { |
| | | $autoinc = ''; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | } |
| | | |
| | | $unsigned = (array_key_exists('unsigned', $field) && $field['unsigned']) ? ' UNSIGNED' : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' INT'.$unsigned.$default.$notnull.$autoinc; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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 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: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field |
| | | * is constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYTEXT'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'TEXT'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMTEXT'; |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * 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) |
| | | { |
| | | if (array_key_exists('length', $field)) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYBLOB'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'BLOB'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMBLOB'; |
| | | } else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an date 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: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATE'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an timestamp |
| | | * 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: |
| | | * |
| | | * default |
| | | * Time stamp value to be used as default for this |
| | | * field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATETIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an time 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: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is |
| | | * constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' TIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getFloatDeclaration($name, $field) |
| | | { |
| | | $type = 'DOUBLE'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $type = 'DECIMAL(18,'.$db->options['decimal_places'].')'; |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | $value = $this->_readFile($value); |
| | | return "'".addslashes($value)."'"; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 and the length |
| | | * @access public |
| | | */ |
| | | function mapNativeDatatype($field) |
| | | { |
| | | $db_type = strtolower($field['type']); |
| | | $db_type = strtok($db_type, '(), '); |
| | | if ($db_type == 'national') { |
| | | $db_type = strtok('(), '); |
| | | } |
| | | $length = strtok('(), '); |
| | | $decimal = strtok('(), '); |
| | | $type = array(); |
| | | switch ($db_type) { |
| | | case 'tinyint': |
| | | case 'smallint': |
| | | case 'mediumint': |
| | | case 'int': |
| | | case 'integer': |
| | | case 'bigint': |
| | | $type[] = 'integer'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | if (preg_match('/^[is|has]/', $field['field'])) { |
| | | $type = array_reverse($type); |
| | | } |
| | | } |
| | | break; |
| | | case 'char': |
| | | case 'varchar': |
| | | $type[] = 'text'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | if (preg_match('/[is|has]/', $field['field'])) { |
| | | $type = array_reverse($type); |
| | | } |
| | | } |
| | | break; |
| | | case 'enum': |
| | | preg_match_all('/\'.+\'/U', $field['type'], $matches); |
| | | $length = 0; |
| | | if (is_array($matches)) { |
| | | foreach ($matches[0] as $value) { |
| | | $length = max($length, strlen($value)-2); |
| | | } |
| | | } |
| | | case 'set': |
| | | $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'; |
| | | break; |
| | | case 'decimal': |
| | | case 'numeric': |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'tinytext': |
| | | case 'mediumtext': |
| | | case 'longtext': |
| | | case 'text': |
| | | if ($decimal == 'binary') { |
| | | $type[] = 'blob'; |
| | | } |
| | | $type[] = 'clob'; |
| | | $type[] = 'text'; |
| | | break; |
| | | case 'tinyblob': |
| | | case 'mediumblob': |
| | | case 'longblob': |
| | | case 'blob': |
| | | $type[] = 'blob'; |
| | | $type[] = 'text'; |
| | | $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, null, null, |
| | | 'getTableFieldDefinition: unknown database attribute type'); |
| | | } |
| | | |
| | | return array($type, $length); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ mapPrepareDatatype() |
| | | |
| | | /** |
| | | * Maps an mdb2 datatype to mysqli prepare type |
| | | * |
| | | * @param string $type |
| | | * @return string |
| | | * @access public |
| | | */ |
| | | function mapPrepareDatatype($type) |
| | | { |
| | | switch($type) { |
| | | case 'integer': |
| | | return 'i'; |
| | | case 'float': |
| | | return 'd'; |
| | | case 'blob': |
| | | return 'b'; |
| | | default: |
| | | break; |
| | | } |
| | | return 's'; |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | |
| | | // $Id$ |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 OCI8 driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Datatype_oci8 extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // {{{ convertResult() |
| | | |
| | | /** |
| | | * convert a value to a RDBMS indepdenant MDB2 type |
| | | * |
| | | * @param mixed $value value to be converted |
| | | * @param int $type constant that specifies which type to convert to |
| | | * @return mixed converted value |
| | | * @access public |
| | | */ |
| | | function convertResult($value, $type) |
| | | { |
| | | if (is_null($value)) { |
| | | return null; |
| | | } |
| | | switch ($type) { |
| | | case 'date': |
| | | return substr($value, 0, strlen('YYYY-MM-DD')); |
| | | case 'time': |
| | | return substr($value, strlen('YYYY-MM-DD '), strlen('HH:MI:SS')); |
| | | default: |
| | | return $this->_baseConvertResult($value, $type); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 = (array_key_exists('length', $field) ? $field['length'] : (($length = $db->options['default_text_field_length']) ? $length : 4000)); |
| | | return 'VARCHAR ('.$length.')'; |
| | | case 'clob': |
| | | return 'CLOB'; |
| | | case 'blob': |
| | | return 'BLOB'; |
| | | case 'integer': |
| | | return 'INT'; |
| | | case 'boolean': |
| | | return 'CHAR (1)'; |
| | | case 'date': |
| | | case 'time': |
| | | case 'timestamp': |
| | | return 'DATE'; |
| | | case 'float': |
| | | return 'NUMBER'; |
| | | case 'decimal': |
| | | return 'NUMBER(*,'.$db->options['decimal_places'].')'; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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. |
| | | * @param string $table name of the current table being processed |
| | | * by alterTable(), used for autoincrement emulation |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getIntegerDeclaration($name, $field, $table = null) |
| | | { |
| | | if (array_key_exists('unsigned', $field) && $field['unsigned']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | $db->warning[] = "unsigned integer field \"$name\" is being declared as signed integer"; |
| | | } |
| | | |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTextDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an text type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the text |
| | | * field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * default |
| | | * Text value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTextDeclaration($name, $field) |
| | | { |
| | | $type = $this->getTypeDeclaration($field); |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'text') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the large |
| | | * object field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access public |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | 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) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a date type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a timestamp |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Timestamp value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a time |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getFloatDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a float type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Float value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getFloatDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDecimalDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a decimal type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Decimal value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDecimalDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteCLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteCLOB($value) |
| | | { |
| | | return 'EMPTY_CLOB()'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | return 'EMPTY_BLOB()'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDate() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDate($value) |
| | | { |
| | | return $this->_quoteText("$value 00:00:00"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteTimestamp() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteTimestamp($value) |
| | | { |
| | | return $this->_quoteText($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteTime() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteTime($value) |
| | | { |
| | | return $this->_quoteText("0001-01-01 $value"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($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) |
| | | { |
| | | $lob_data = stream_get_meta_data($lob); |
| | | $lob_index = $lob_data['wrapper_data']->lob_index; |
| | | if (!@$this->lobs[$lob_index]['value']->writelobtofile($file)) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _retrieveLOB() |
| | | |
| | | /** |
| | | * retrieve LOB from the database |
| | | * |
| | | * @param int $lob_index from the lob array |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _retrieveLOB(&$lob) |
| | | { |
| | | if (!array_key_exists('loaded', $lob)) { |
| | | if (!is_object($lob['ressource'])) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'attemped to retrieve LOB from non existing or NULL column'); |
| | | } |
| | | $lob['value'] = $lob['ressource']->load(); |
| | | $lob['loaded'] = true; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Paul Cooper <pgc@ucecom.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | 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 |
| | | { |
| | | // {{{ convertResult() |
| | | |
| | | /** |
| | | * convert a value to a RDBMS independent MDB2 type |
| | | * |
| | | * @param mixed $value value to be converted |
| | | * @param int $type constant that specifies which type to convert to |
| | | * @return mixed converted value or a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function convertResult($value, $type) |
| | | { |
| | | if (is_null($value)) { |
| | | return null; |
| | | } |
| | | switch ($type) { |
| | | case 'boolean': |
| | | return $value == 't'; |
| | | case 'float': |
| | | return doubleval($value); |
| | | case 'date': |
| | | return $value; |
| | | case 'time': |
| | | return $value; |
| | | case 'timestamp': |
| | | return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS')); |
| | | default: |
| | | return $this->_baseConvertResult($value, $type); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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': |
| | | return array_key_exists('length', $field) ? 'VARCHAR ('.$field['length'].')' : 'TEXT'; |
| | | case 'clob': |
| | | return 'OID'; |
| | | case 'blob': |
| | | return 'OID'; |
| | | case 'integer': |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | return 'SERIAL PRIMARY KEY'; |
| | | } |
| | | 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': |
| | | return 'NUMERIC(18, '.$db->options['decimal_places'].')'; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getIntegerDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an integer type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * unsigned |
| | | * Boolean flag that indicates whether the field should be |
| | | * declared as unsigned integer if possible. |
| | | * |
| | | * default |
| | | * Integer value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getIntegerDeclaration($name, $field) |
| | | { |
| | | if (array_key_exists('unsigned', $field) && $field['unsigned']) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; |
| | | } |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | return $name.' '.$this->getTypeDeclaration($field); |
| | | } |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTextDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a text type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the text |
| | | * field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * default |
| | | * Text value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTextDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'text') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the large |
| | | * object field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length of the large |
| | | * object field. If this argument is missing the field should be |
| | | * declared to have the longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getBLOBDeclaration($name, $field) |
| | | { |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | 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) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'boolean') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a date type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Date value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDateDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a time |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Time value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimeDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a timestamp |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Timestamp value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getTimestampDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getFloatDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a float type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Float value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getFloatDeclaration($name, $field) |
| | | { |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDecimalDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare a decimal type |
| | | * field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param array $field associative array with the name of the properties |
| | | * of the field being declared as array indexes. Currently, the types |
| | | * of supported field properties are as follows: |
| | | * |
| | | * default |
| | | * Decimal value to be used as default for this field. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field is constrained |
| | | * to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $default = array_key_exists('default', $field) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteLOB($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $connect = $db->connect(); |
| | | if (PEAR::isError($connect)) { |
| | | return $connect; |
| | | } |
| | | if (!$db->in_transaction && !@pg_query($db->connection, 'BEGIN')) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'error starting transaction'); |
| | | } |
| | | if (is_resource($value)) { |
| | | $close = false; |
| | | } elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { |
| | | $close = true; |
| | | if ($match[1] == 'file://') { |
| | | $value = $match[2]; |
| | | } |
| | | // disabled use of pg_lo_import() for now with the following line |
| | | $value = @fopen($value, 'r'); |
| | | } else { |
| | | $close = true; |
| | | $fp = @tmpfile(); |
| | | @fwrite($fp, $value); |
| | | @rewind($fp); |
| | | $value = $fp; |
| | | } |
| | | $result = false; |
| | | if (is_resource($value)) { |
| | | if (($lo = @pg_lo_create($db->connection))) { |
| | | if (($handle = @pg_lo_open($db->connection, $lo, 'w'))) { |
| | | while (!@feof($value)) { |
| | | $data = @fread($value, $db->options['lob_buffer_length']); |
| | | if ($data === '') { |
| | | break; |
| | | } |
| | | if (!@pg_lo_write($handle, $data)) { |
| | | $result = $db->raiseError(); |
| | | break; |
| | | } |
| | | } |
| | | if (!PEAR::isError($result)) { |
| | | $result = strval($lo); |
| | | } |
| | | @pg_lo_close($handle); |
| | | } else { |
| | | $result = $db->raiseError(); |
| | | @pg_lo_unlink($db->connection, $lo); |
| | | } |
| | | } |
| | | if ($close) { |
| | | @fclose($value); |
| | | } |
| | | } else { |
| | | if (!@pg_lo_import($db->connection, $value)) { |
| | | $result = $db->raiseError(); |
| | | } |
| | | } |
| | | if (!$db->in_transaction) { |
| | | if (PEAR::isError($result)) { |
| | | @pg_query($db->connection, 'ROLLBACK'); |
| | | } else { |
| | | @pg_query($db->connection, 'COMMIT'); |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteCLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteCLOB($value) |
| | | { |
| | | return $this->_quoteLOB($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBLOB() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param $value |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBLOB($value) |
| | | { |
| | | return $this->_quoteLOB($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteBoolean() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteBoolean($value) |
| | | { |
| | | return ($value ? "'t'" : "'f'"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->escape($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; |
| | | } |
| | | |
| | | $lob_data = stream_get_meta_data($lob); |
| | | $lob_index = $lob_data['wrapper_data']->lob_index; |
| | | if (!pg_lo_export($db->connection, $this->lobs[$lob_index]['ressource'], $file)) { |
| | | return $db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _retrieveLOB() |
| | | |
| | | /** |
| | | * retrieve LOB from the database |
| | | * |
| | | * @param resource $lob stream handle |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _retrieveLOB(&$lob) |
| | | { |
| | | if (!array_key_exists('handle', $lob)) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | if (!$db->in_transaction) { |
| | | if (!@pg_query($db->connection, 'BEGIN')) { |
| | | return $db->raiseError(); |
| | | } |
| | | $lob['in_transaction'] = true; |
| | | } |
| | | $lob['handle'] = @pg_lo_open($db->connection, $lob['ressource'], 'r'); |
| | | if (!$lob['handle']) { |
| | | if (array_key_exists('in_transaction', $lob)) { |
| | | @pg_query($db->connection, 'END'); |
| | | unset($lob['in_transaction']); |
| | | } |
| | | return $db->raiseError(); |
| | | } |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _readLOB() |
| | | |
| | | /** |
| | | * Read data from large object input stream. |
| | | * |
| | | * @param resource $lob stream handle |
| | | * @param blob $data reference to a variable that will hold data to be |
| | | * read from the large object input stream |
| | | * @param int $length integer value that indicates the largest ammount of |
| | | * data to be read from the large object input stream. |
| | | * @return mixed length on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _readLOB($lob, $length) |
| | | { |
| | | $data = @pg_lo_read($lob['handle'], $length); |
| | | if (!is_string($data)) { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(); |
| | | } |
| | | return $data; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _destroyLOB() |
| | | |
| | | /** |
| | | * Free any resources allocated during the lifetime of the large object |
| | | * handler object. |
| | | * |
| | | * @param int $lob_index from the lob array |
| | | * @access protected |
| | | */ |
| | | function _destroyLOB($lob_index) |
| | | { |
| | | if (isset($this->lobs[$lob_index]['handle'])) { |
| | | @pg_lo_close($this->lobs[$lob_index]['handle']); |
| | | unset($this->lobs[$lob_index]['handle']); |
| | | if (isset($this->lobs[$lob_index]['in_transaction'])) { |
| | | /* |
| | | for some reason this piece of code causes an apache crash |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | @pg_query($db->connection, 'END'); |
| | | */ |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 and the length |
| | | * @access public |
| | | */ |
| | | function mapNativeDatatype($field) |
| | | { |
| | | $db_type = preg_replace('/\d/','', strtolower($field['typname']) ); |
| | | $length = $field['attlen']; |
| | | if ($length == '-1') { |
| | | $length = $field['atttypmod']-4; |
| | | } |
| | | if ((int)$length <= 0) { |
| | | $length = null; |
| | | } |
| | | $type = array(); |
| | | switch ($db_type) { |
| | | case 'int': |
| | | $type[] = 'integer'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | } |
| | | break; |
| | | case 'bool': |
| | | $type[] = 'boolean'; |
| | | $length = null; |
| | | break; |
| | | case 'text': |
| | | case 'char': |
| | | case 'varchar': |
| | | case 'bpchar': |
| | | $type[] = 'text'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | } elseif (strstr($db_type, 'text')) |
| | | $type[] = 'clob'; |
| | | 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 'money': |
| | | case 'numeric': |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'tinyblob': |
| | | case 'mediumblob': |
| | | case 'longblob': |
| | | case 'blob': |
| | | $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, null, null, |
| | | 'getTableFieldDefinition: unknown database attribute type'); |
| | | } |
| | | |
| | | return array($type, $length); |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@backendmedia.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Datatype/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 SQLite driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@backendmedia.com> |
| | | */ |
| | | class MDB2_Driver_Datatype_sqlite extends MDB2_Driver_Datatype_Common |
| | | { |
| | | // }}} |
| | | // {{{ _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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $unsigned = (isset($field['unsigned']) && $field['unsigned']) ? ' UNSIGNED' : ''; |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'integer') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' INT'.$unsigned.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getCLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an character |
| | | * large object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * length |
| | | * Integer value that determines the maximum length |
| | | * of the large object field. If this argument is |
| | | * missing the field should be declared to have the |
| | | * longest length allowed by the DBMS. |
| | | * |
| | | * notnull |
| | | * Boolean flag that indicates whether this field |
| | | * is constrained to not be set to null. |
| | | * @return string DBMS specific SQL code portion that should be used to |
| | | * declare the specified field. |
| | | * @access protected |
| | | */ |
| | | function _getCLOBDeclaration($name, $field) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | if (isset($field['length'])) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYTEXT'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'TEXT'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMTEXT'; |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | $type = 'LONGTEXT'; |
| | | } |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBLOBDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an binary large |
| | | * object type field to be used in statements like CREATE TABLE. |
| | | * |
| | | * @param string $name name the field to be declared. |
| | | * @param 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: |
| | | * |
| | | * 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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | if (isset($field['length'])) { |
| | | $length = $field['length']; |
| | | if ($length <= 255) { |
| | | $type = 'TINYBLOB'; |
| | | } else { |
| | | if ($length <= 65535) { |
| | | $type = 'BLOB'; |
| | | } else { |
| | | if ($length <= 16777215) { |
| | | $type = 'MEDIUMBLOB'; |
| | | } else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | $type = 'LONGBLOB'; |
| | | } |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getDateDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an date 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: |
| | | * |
| | | * 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) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'date') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATE'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimestampDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an timestamp |
| | | * 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: |
| | | * |
| | | * default |
| | | * Time stamp 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) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'timestamp') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' DATETIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getTimeDeclaration() |
| | | |
| | | /** |
| | | * Obtain DBMS specific SQL code portion needed to declare an time 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: |
| | | * |
| | | * 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) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'time') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' TIME'.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getFloatDeclaration($name, $field) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $type = 'DOUBLE'.($db->options['fixed_float'] ? '('. |
| | | ($db->options['fixed_float']+2).','.$db->options['fixed_float'].')' : ''); |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'float') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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: |
| | | * |
| | | * 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 _getDecimalDeclaration($name, $field) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $type = 'BIGINT'; |
| | | $default = isset($field['default']) ? ' DEFAULT '. |
| | | $this->quote($field['default'], 'decimal') : ''; |
| | | $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; |
| | | return $name.' '.$type.$default.$notnull; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteFloat() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteFloat($value) |
| | | { |
| | | return (float)$value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _quoteDecimal() |
| | | |
| | | /** |
| | | * Convert a text value into a DBMS specific format that is suitable to |
| | | * compose query statements. |
| | | * |
| | | * @param string $value text string value that is intended to be converted. |
| | | * @return string text string that represents the given argument value in |
| | | * a DBMS specific format. |
| | | * @access protected |
| | | */ |
| | | function _quoteDecimal($value) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | return $db->escape($value); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 and the length |
| | | * @access public |
| | | */ |
| | | function mapNativeDatatype($field) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $db_type = $field['type']; |
| | | $length = isset($field['length']) ? $field['length'] : null; |
| | | $type = array(); |
| | | switch ($db_type) { |
| | | case 'tinyint': |
| | | case 'smallint': |
| | | case 'mediumint': |
| | | case 'int': |
| | | case 'integer': |
| | | case 'bigint': |
| | | $type[] = 'integer'; |
| | | if ($length == '1') { |
| | | $type[] = 'boolean'; |
| | | if (preg_match('/^[is|has]/', $field['name'])) { |
| | | $type = array_reverse($type); |
| | | } |
| | | } |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'tinytext': |
| | | case 'mediumtext': |
| | | case 'longtext': |
| | | case 'text': |
| | | case 'char': |
| | | case 'varchar': |
| | | case "varchar2": |
| | | $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'; |
| | | break; |
| | | case 'enum': |
| | | preg_match_all('/\'.+\'/U',$row[$type_column], $matches); |
| | | $length = 0; |
| | | if (is_array($matches)) { |
| | | foreach ($matches[0] as $value) { |
| | | $length = max($length, strlen($value)-2); |
| | | } |
| | | } |
| | | case 'set': |
| | | $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'; |
| | | break; |
| | | case 'decimal': |
| | | case 'numeric': |
| | | $type[] = 'decimal'; |
| | | break; |
| | | case 'tinyblob': |
| | | case 'mediumblob': |
| | | case 'longblob': |
| | | case 'blob': |
| | | $type[] = 'text'; |
| | | $length = null; |
| | | break; |
| | | case 'year': |
| | | $type[] = 'integer'; |
| | | $type[] = 'date'; |
| | | $length = null; |
| | | break; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: unknown database attribute type'); |
| | | } |
| | | |
| | | return array($type, $length); |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 FrontBase driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Frank M. Kromann <frank@kromann.info> |
| | | */ |
| | | class MDB2_Driver_Manager_fbsql extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (PEAR::isError($result = $db->connect())) { |
| | | return $result; |
| | | } |
| | | $query = "CREATE DATABASE $name"; |
| | | if (PEAR::isError($result = $db->query($query))) { |
| | | return $result; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | if (PEAR::isError($result = $db->connect())) { |
| | | return $result; |
| | | } |
| | | $query = "DELETE DATABASE $name"; |
| | | if (PEAR::isError($result = $db->query($query))) { |
| | | return $result; |
| | | } |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropTable() |
| | | |
| | | /** |
| | | * drop an existing table |
| | | * |
| | | * @param object $dbs database object that is extended by this class |
| | | * @param string $name name of the table that should be dropped |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function dropTable($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->query("DROP TABLE $name CASCADE"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @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, |
| | | 'alterTable: change type "'.$change_name.'" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = (array_key_exists('name', $changes) ? 'RENAME AS '.$changes['name'] : ''); |
| | | |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD ' . $type_declaration; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP ' . $field_name; |
| | | } |
| | | } |
| | | |
| | | $rename = array(); |
| | | if (array_key_exists('rename', $changes)) { |
| | | foreach ($changes['rename'] as $field_name => $field) { |
| | | $rename[$field['name']] = $field_name; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | 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; |
| | | } |
| | | $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!empty($rename)) { |
| | | foreach ($rename as $renamed_field_name => $renamed_field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $old_field_name = $rename[$renamed_field_name]; |
| | | $field = $changes['rename'][$old_field_name]; |
| | | $query.= 'CHANGE ' . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listDatabases() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR_NOT_CAPABLE); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listUsers() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->queryCol('SELECT "user_name" FROM information_schema.users'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SELECT "table_name"' |
| | | . ' FROM information_schema.tables' |
| | | . ' t0, information_schema.schemata t1' |
| | | . ' WHERE t0.schema_pk=t1.schema_pk AND' |
| | | . ' "table_type" = \'BASE TABLE\'' |
| | | . ' AND "schema_name" = current_schema'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | for ($i = 0, $j = count($table_names), $tables = array(); $i < $j; ++$i) { |
| | | if (!$this->_isSequenceName($table_names[$i])) |
| | | $tables[] = $table_names[$i]; |
| | | } |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $fields = $db->queryCol("SHOW COLUMNS FROM $table"); |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $fields = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $fields); |
| | | } |
| | | return $fields; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | $query = "CREATE ".(array_key_exists('unique', $definition) ? 'UNIQUE INDEX' : 'INDEX')." $name on $table ("; |
| | | $query.= implode(', ', array_keys($definition['fields'])); |
| | | $query.= ')'; |
| | | return $db->query($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; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $table DROP INDEX $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $key_name = '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); |
| | | } |
| | | } |
| | | |
| | | $query = "SHOW INDEX FROM $table"; |
| | | $indexes_all = $db->queryCol($query, 'text', $key_name); |
| | | if (PEAR::isError($indexes_all)) { |
| | | return $indexes_all; |
| | | } |
| | | |
| | | $indexes = array_unique($indexes_all); |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $indexes = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $indexes); |
| | | } |
| | | |
| | | return $indexes; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | $seqcol_name = $db->options['seqcol_name']; |
| | | $query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER DEFAULT UNIQUE, PRIMARY KEY($seqcol_name))"; |
| | | $res = $db->query($query); |
| | | $res = $db->query("SET UNIQUE = 1 FOR $sequence_name"); |
| | | if (PEAR::isError($res)) { |
| | | return $res; |
| | | } |
| | | if ($start == 1) { |
| | | return MDB2_OK; |
| | | } |
| | | $res = $db->query("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'); |
| | | if (!PEAR::isError($res)) { |
| | | return MDB2_OK; |
| | | } |
| | | // Handle error |
| | | $result = $db->query("DROP TABLE $sequence_name"); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not drop inconsistent sequence table ('. |
| | | $result->getMessage().' ('.$result->getUserinfo().'))'); |
| | | } |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not create sequence table ('. |
| | | $res->getMessage().' ('.$res->getUserinfo().'))'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $db->query("DROP TABLE $sequence_name CASCADE"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SHOW TABLES', 'text'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) |
| | | $sequences[] = $sqn; |
| | | } |
| | | return $sequences; |
| | | } |
| | | // }}} |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lorenzo Alberton <l.alberton@quipo.it> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 FireBird/InterBase driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lorenzo Alberton <l.alberton@quipo.it> |
| | | */ |
| | | class MDB2_Driver_Manager_ibase extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'Create database', |
| | | 'createDatabase: PHP Interbase API does not support direct queries. You have to '. |
| | | 'create the db manually by using isql command or a similar program'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'Drop database', |
| | | 'dropDatabase: PHP Interbase API does not support direct queries. You have '. |
| | | 'to drop the db manually by using isql command or a similar program'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _makeAutoincrement() |
| | | |
| | | /** |
| | | * add an autoincrement sequence + trigger |
| | | * |
| | | * @param string $name name of the PK field |
| | | * @param string $table name of the table |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _makeAutoincrement($name, $table, $start = 1) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->manager->createSequence($table, $start); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_makeAutoincrement: sequence for autoincrement PK could not be created'); |
| | | } |
| | | |
| | | $sequence_name = $db->getSequenceName($table); |
| | | $trigger_name = $table . '_autoincrement_pk'; |
| | | $trigger_sql = 'CREATE TRIGGER ' . $trigger_name . ' FOR ' . $table . ' |
| | | ACTIVE BEFORE INSERT POSITION 0 |
| | | AS |
| | | BEGIN |
| | | IF (NEW.' . $name . ' IS NULL) THEN |
| | | NEW.' . $name . ' = GEN_ID('.strtoupper($sequence_name).', 1); |
| | | END'; |
| | | |
| | | return $db->query($trigger_sql); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _dropAutoincrement() |
| | | |
| | | /** |
| | | * drop an existing autoincrement PK / trigger |
| | | * |
| | | * @param string $name name of the PK field |
| | | * @param string $table name of the table |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _dropAutoincrement($name, $table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->manager->dropSequence($table); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_dropAutoincrement: sequence for autoincrement PK could not be dropped'); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createTable() |
| | | |
| | | /** |
| | | * create a new table |
| | | * |
| | | * @param string $name Name of the database that should be created |
| | | * @param array $fields Associative array that contains the definition of each field of the new table |
| | | * The indexes of the array entries are the names of the fields of the table an |
| | | * the array entry values are associative arrays like those that are meant to be |
| | | * passed with the field definitions to get[Type]Declaration() functions. |
| | | * |
| | | * Example |
| | | * array( |
| | | * |
| | | * 'id' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1, |
| | | * 'notnull' => 1, |
| | | * 'default' => 0, |
| | | * ), |
| | | * 'name' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12, |
| | | * ), |
| | | * 'description' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12, |
| | | * ) |
| | | * ); |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createTable($name, $fields) |
| | | { |
| | | $result = parent::createTable($name, $fields); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | foreach($fields as $field_name => $field) { |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | return $this->_makeAutoincrement($field_name, $name); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ checkSupportedChanges() |
| | | |
| | | /** |
| | | * check if planned changes are supported |
| | | * |
| | | * @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 checkSupportedChanges(&$changes) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | foreach ($changes as $change_name => $change) { |
| | | switch ($change_name) { |
| | | case 'notnull': |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'checkSupportedChanges: it is not supported changes to field not null constraint'); |
| | | case 'default': |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'checkSupportedChanges: it is not supported changes to field default value'); |
| | | case 'length': |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'checkSupportedChanges: it is not supported changes to field default length'); |
| | | case 'unsigned': |
| | | case 'type': |
| | | case 'declaration': |
| | | case 'definition': |
| | | break; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'checkSupportedChanges: it is not supported change of type' . $change_name); |
| | | } |
| | | } |
| | | 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) |
| | | { |
| | | //remove triggers associated with the table |
| | | $name = strtoupper($name); |
| | | $triggers = $db->queryCol("SELECT RDB\$TRIGGER_NAME FROM RDB\$TRIGGERS WHERE RDB\$RELATION_NAME='$name'"); |
| | | if (PEAR::isError($triggers)) { |
| | | return $triggers; |
| | | } |
| | | foreach ($triggers as $trigger) { |
| | | $result = $db->query('DROP TRIGGER ' . $trigger); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | } |
| | | |
| | | return parent::dropTable($name); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function alterTable($name, $changes, $check) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | foreach ($changes as $change_name => $change) { |
| | | switch ($change_name) { |
| | | case 'add': |
| | | case 'remove': |
| | | case 'rename': |
| | | break; |
| | | case 'change': |
| | | foreach ($changes['change'] as $field) { |
| | | if (PEAR::isError($err = $this->checkSupportedChanges($field))) { |
| | | return $err; |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'alterTable: change type ' . $change_name . ' not yet supported'); |
| | | } |
| | | } |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | $query = ''; |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field, $name); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | if (strlen($query)) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD ' . $type_declaration; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if (strlen($query)) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP ' . $field_name; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('rename', $changes)) { |
| | | foreach ($changes['rename'] as $field_name => $field) { |
| | | if (strlen($query)) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ALTER ' . $field_name . ' TO ' . $field['name']; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | // missing support to change DEFAULT and NULLability |
| | | foreach ($changes['change'] as $field_name => $field) { |
| | | if (PEAR::isError($err = $this->checkSupportedChanges($field))) { |
| | | return $err; |
| | | } |
| | | if (strlen($query)) { |
| | | $query.= ', '; |
| | | } |
| | | $db->loadModule('Datatype'); |
| | | $query.= 'ALTER ' . $field_name.' TYPE ' . $db->datatype->getTypeDeclaration($field); |
| | | } |
| | | } |
| | | |
| | | if (!strlen($query)) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | $query = 'SELECT DISTINCT R.RDB$RELATION_NAME FROM RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0'; |
| | | $tables = $db->queryCol($query); |
| | | if (PEAR::isError($tables)) { |
| | | return $tables; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $tables = array_flip(array_change_key_case(array_flip($tables), $db->options['field_case'])); |
| | | } |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | $table = strtoupper($table); |
| | | $query = "SELECT RDB\$FIELD_NAME FROM RDB\$RELATION_FIELDS WHERE RDB\$RELATION_NAME='$table'"; |
| | | $columns = $db->queryCol($query); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $columns = array_flip(array_change_key_case(array_flip($columns), $db->options['field_case'])); |
| | | } |
| | | return $columns; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listViews() |
| | | |
| | | /** |
| | | * list the views in the database |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listViews() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->queryCol('SELECT RDB$VIEW_NAME'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | if (array_key_exists('primary', $definition) && $definition['primary']) { |
| | | $query = "ALTER TABLE $table ADD CONSTRAINT $name PRIMARY KEY ("; |
| | | } else { |
| | | $query = 'CREATE'; |
| | | if (array_key_exists('unique', $definition) && $definition['unique']) { |
| | | $query.= ' UNIQUE'; |
| | | } |
| | | $query_sort = ''; |
| | | foreach ($definition['fields'] as $field) { |
| | | if (!strcmp($query_sort, '') && isset($field['sorting'])) { |
| | | switch ($field['sorting']) { |
| | | case 'ascending': |
| | | $query_sort = ' ASC'; |
| | | break; |
| | | case 'descending': |
| | | $query_sort = ' DESC'; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | $query .= $query_sort. " INDEX $name ON $table ("; |
| | | } |
| | | $query .= implode(', ', array_keys($definition['fields'])) . ')'; |
| | | |
| | | return $db->query($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | return $db->queryCol("SELECT RDB\$INDEX_NAME FROM RDB\$INDICES WHERE RDB\$RELATION_NAME='$table'"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | if (PEAR::isError($result = $db->query('CREATE GENERATOR '.strtoupper($sequence_name)))) { |
| | | return $result; |
| | | } |
| | | if (PEAR::isError($result = $db->query('SET GENERATOR '.strtoupper($sequence_name).' TO '.($start-1)))) { |
| | | if (PEAR::isError($err = $db->dropSequence($seq_name))) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: Could not setup sequence start value and then it was not possible to drop it: '. |
| | | $err->getMessage().' - ' .$err->getUserInfo()); |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $db->query('DELETE FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME=\''.strtoupper($sequence_name).'\''); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS'; |
| | | $table_names = $db->queryCol($query); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) |
| | | $sequences[] = $sqn; |
| | | } |
| | | return $sequences; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Frank M. Kromann <frank@kromann.info> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | // {{{ class MDB2_Driver_Manager_mssql |
| | | /** |
| | | * MDB2 MSSQL driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Frank M. Kromann <frank@kromann.info> |
| | | */ |
| | | class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = "CREATE DATABASE $name"; |
| | | if($db->options['database_device']) { |
| | | $query.= ' ON '.$db->options['database_device']; |
| | | $query.= $db->options['database_size'] ? '='.$db->options['database_size'] : ''; |
| | | } |
| | | return $db->standaloneQuery($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | return $db->standaloneQuery("DROP DATABASE $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ), |
| | | * ) |
| | | * |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @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': |
| | | break; |
| | | case 'remove': |
| | | break; |
| | | case 'name': |
| | | case 'rename': |
| | | case 'change': |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, |
| | | 'alterTable: change type "'.$change_name.'" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = ''; |
| | | if (array_key_exists('add', $changes)) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD '; |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= $db->getDeclaration($field['type'], $field_name, $field); |
| | | } |
| | | } |
| | | if(array_key_exists('remove', $changes)) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP COLUMN'; |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= $db->getDeclaration($field['type'], $field_name, $field); |
| | | } |
| | | } |
| | | |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'EXEC sp_tables @table_type = "\'TABLE\'"'; |
| | | $table_names = $db->queryCol($query, null, 2); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | |
| | | $tables = array(); |
| | | for ($i = 0, $j = count($table_names); $i <$j; ++$i) { |
| | | if (!$this->_isSequenceName($db, $table_names[$i])) { |
| | | $tables[] = $table_names[$i]; |
| | | } |
| | | } |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->query("SELECT * FROM [$table]"); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $result->getColumnNames(); |
| | | $result->free(); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | return array_flip($columns); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $key_name = 'INDEX_NAME'; |
| | | $pk_name = 'PK_NAME'; |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $key_name = strtolower($key_name); |
| | | $pk_name = strtolower($pk_name); |
| | | } else { |
| | | $key_name = strtoupper($key_name); |
| | | $pk_name = strtoupper($pk_name); |
| | | } |
| | | } |
| | | $query = "EXEC sp_statistics @table_name='$table'"; |
| | | $indexes_all = $db->queryCol($query, 'text', $key_name); |
| | | if (PEAR::isError($indexes_all)) { |
| | | return $indexes_all; |
| | | } |
| | | $query = "EXEC sp_pkeys @table_name='$table'"; |
| | | $pk_all = $db->queryCol($query, 'text', $pk_name); |
| | | $found = $indexes = array(); |
| | | for ($index = 0, $j = count($indexes_all); $index < $j; ++$index) { |
| | | if (!in_array($indexes_all[$index], $pk_all) |
| | | && $indexes_all[$index] != null |
| | | && !isset($found[$indexes_all[$index]]) |
| | | ) { |
| | | $indexes[] = $indexes_all[$index]; |
| | | $found[$indexes_all[$index]] = 1; |
| | | } |
| | | } |
| | | return $indexes; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | $seqcol_name = $db->options['seqcol_name']; |
| | | $query = "CREATE TABLE $sequence_name ($seqcol_name " . |
| | | "INT PRIMARY KEY CLUSTERED IDENTITY($start,1) NOT NULL)"; |
| | | |
| | | $res = $db->query($query); |
| | | if(PEAR::isError($res)) { |
| | | return $res; |
| | | } |
| | | |
| | | if ($start == 1) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = "SET IDENTITY_INSERT $sequence_name ON ". |
| | | "INSERT INTO $sequence_name ($seqcol_name) VALUES ($start)"; |
| | | $res = $db->query($query); |
| | | |
| | | if(!PEAR::isError($res)) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $result = $db->query("DROP TABLE $sequence_name"); |
| | | if(PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not drop inconsistent sequence table ('. |
| | | $result->getMessage().' ('.$result->getUserInfo(). '))'); |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not create sequence table ('. |
| | | $res->getMessage(). ' ('.$res->getUserInfo(). '))'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createIndex() |
| | | /** |
| | | * Adds an index to a table. |
| | | * |
| | | * @param string $table The name of the table |
| | | * @param string $name The name of the field |
| | | * @param array $definition The definition of the new field. |
| | | */ |
| | | function createIndex($table, $name, $definition) |
| | | { |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $db->query("DROP TABLE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = "SELECT name FROM sysobjects WHERE xtype = 'U'"; |
| | | $table_names = $db->queryCol($query); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i <$j; ++$i) { |
| | | if ($this->_isSequenceName($db, $table_names[$i])) { |
| | | $sequences[] = $table_names[$i]; |
| | | } |
| | | } |
| | | return $sequences; |
| | | } |
| | | // }}} |
| | | } |
| | | // }}} |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQLi driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ properties |
| | | var $verified_table_types = array();# |
| | | // }}} |
| | | |
| | | // }}} |
| | | // {{{ _verifyTableType() |
| | | |
| | | /** |
| | | * verify that chosen transactional table hanlder is available in the database |
| | | * |
| | | * @param string $table_type name of the table handler |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _verifyTableType($table_type) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | switch (strtoupper($table_type)) { |
| | | case 'BERKELEYDB': |
| | | case 'BDB': |
| | | $check = array('have_bdb'); |
| | | break; |
| | | case 'INNODB': |
| | | $check = array('have_innobase', 'have_innodb'); |
| | | break; |
| | | case 'GEMINI': |
| | | $check = array('have_gemini'); |
| | | break; |
| | | case 'HEAP': |
| | | case 'ISAM': |
| | | case 'MERGE': |
| | | case 'MRG_MYISAM': |
| | | case 'MYISAM': |
| | | case '': |
| | | return MDB2_OK; |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | $table_type.' is not a supported table type'); |
| | | } |
| | | if (isset($this->verified_table_types[$table_type]) |
| | | && $this->verified_table_types[$table_type] == $db->connection |
| | | ) { |
| | | return MDB2_OK; |
| | | } |
| | | $not_supported = false; |
| | | for ($i = 0, $j = count($check); $i < $j; ++$i) { |
| | | $query = 'SHOW VARIABLES LIKE '.$db->quote($check[$i], 'text'); |
| | | $has = $db->queryRow($query, null, MDB2_FETCHMODE_ORDERED); |
| | | if (PEAR::isError($has)) { |
| | | return $has; |
| | | } |
| | | if (is_array($has)) { |
| | | $not_supported = true; |
| | | if ($has[1] == 'YES') { |
| | | $this->verified_table_types[$table_type] = $db->connection; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | } |
| | | if ($not_supported) { |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | $table_type.' is not a supported table type by this MySQL database server'); |
| | | } |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'could not tell if '.$table_type.' is a supported table type'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'CREATE DATABASE '.$name; |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | $query = 'DROP DATABASE '.$name; |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createTable() |
| | | |
| | | /** |
| | | * create a new table |
| | | * |
| | | * @param string $name Name of the database that should be created |
| | | * @param array $fields Associative array that contains the definition of each field of the new table |
| | | * The indexes of the array entries are the names of the fields of the table an |
| | | * the array entry values are associative arrays like those that are meant to be |
| | | * passed with the field definitions to get[Type]Declaration() functions. |
| | | * |
| | | * Example |
| | | * array( |
| | | * |
| | | * 'id' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * 'notnull' => 1 |
| | | * 'default' => 0 |
| | | * ), |
| | | * 'name' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ), |
| | | * 'password' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ) |
| | | * ); |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createTable($name, $fields) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (!$name) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: no valid table name specified'); |
| | | } |
| | | if (empty($fields)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: no fields specified for table "'.$name.'"'); |
| | | } |
| | | $verify = $this->_verifyTableType($db->options['default_table_type']); |
| | | if (PEAR::isError($verify)) { |
| | | return $verify; |
| | | } |
| | | $query_fields = $this->getFieldDeclarationList($fields); |
| | | if (PEAR::isError($query_fields)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createTable: '.$this->getUserinfo()); |
| | | } |
| | | $query = "CREATE TABLE $name ($query_fields)".(strlen($db->options['default_table_type']) |
| | | ? ' TYPE='.$db->options['default_table_type'] : ''); |
| | | |
| | | return $db->query($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 Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @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, |
| | | 'alterTable: change type "'.$change_name.'" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = (array_key_exists('name', $changes) ? 'RENAME AS '.$changes['name'] : ''); |
| | | |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD ' . $type_declaration; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP ' . $field_name; |
| | | } |
| | | } |
| | | |
| | | $rename = array(); |
| | | if (array_key_exists('rename', $changes)) { |
| | | foreach ($changes['rename'] as $field_name => $field) { |
| | | $rename[$field['name']] = $field_name; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | 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; |
| | | } |
| | | $query.= "CHANGE $field_name " . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!empty($rename)) { |
| | | foreach ($rename as $rename_name => $renamed_field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $old_field_name = $renamed_field; |
| | | $field = $changes['rename'][$old_field_name]; |
| | | $query.= 'CHANGE ' . $db->getDeclaration($field['type'], $old_field_name, $field); |
| | | } |
| | | } |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listDatabases() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $databases = $db->queryCol('SHOW DATABASES'); |
| | | return $databases; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listUsers() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $users = $db->queryCol('SELECT DISTINCT USER FROM USER'); |
| | | return $users; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SHOW TABLES'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | |
| | | $tables = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if (!$this->_isSequenceName($table_names[$i])) |
| | | $tables[] = $table_names[$i]; |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $tables = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $tables); |
| | | } |
| | | |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $fields = $db->queryCol("SHOW COLUMNS FROM $table"); |
| | | if (PEAR::isError($fields)) { |
| | | return $fields; |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $fields = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $fields); |
| | | } |
| | | |
| | | return $fields; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | if (array_key_exists('primary', $definition) && $definition['primary']) { |
| | | $type = 'PRIMARY'; |
| | | $name = 'KEY'; |
| | | } elseif (array_key_exists('unique', $definition) && $definition['unique']) { |
| | | $type = 'UNIQUE'; |
| | | } else { |
| | | $type = 'INDEX'; |
| | | } |
| | | |
| | | $query = "ALTER TABLE $table ADD $type $name ("; |
| | | $query.= implode(', ', array_keys($definition['fields'])); |
| | | $query.= ')'; |
| | | |
| | | return $db->query($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; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $table DROP INDEX $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $key_name = '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); |
| | | } |
| | | } |
| | | |
| | | $query = "SHOW INDEX FROM $table"; |
| | | $indexes_all = $db->queryCol($query, 'text', $key_name); |
| | | if (PEAR::isError($indexes_all)) { |
| | | return $indexes_all; |
| | | } |
| | | |
| | | $indexes = array_unique($indexes_all); |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | $indexes = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $indexes); |
| | | } |
| | | |
| | | return $indexes; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | $seqcol_name = $db->options['seqcol_name']; |
| | | $result = $this->_verifyTableType($db->options['default_table_type']); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $res = $db->query("CREATE TABLE $sequence_name". |
| | | "($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))". |
| | | (strlen($db->options['default_table_type']) ? ' TYPE='.$db->options['default_table_type'] : '') |
| | | ); |
| | | |
| | | if (PEAR::isError($res)) { |
| | | return $res; |
| | | } |
| | | |
| | | if ($start == 1) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $res = $db->query("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'); |
| | | if (!PEAR::isError($res)) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // Handle error |
| | | $result = $db->query("DROP TABLE $sequence_name"); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not drop inconsistent sequence table ('. |
| | | $result->getMessage().' ('.$result->getUserinfo().'))'); |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not create sequence table ('. |
| | | $res->getMessage().' ('.$res->getUserinfo().'))'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $db->query("DROP TABLE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table_names = $db->queryCol('SHOW TABLES'); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) { |
| | | $sequences[] = $sqn; |
| | | } |
| | | } |
| | | |
| | | return $sequences; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | |
| | | // $Id$ |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 oci8 driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Manager_oci8 extends MDB2_Driver_Manager_Common |
| | | { |
| | | // {{{ createDatabase() |
| | | |
| | | /** |
| | | * create a new database |
| | | * |
| | | * @param object $db database object that is extended by this class |
| | | * @param string $name name of the database that should be created |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $username = $db->options['database_name_prefix'].$name; |
| | | $password = $db->dsn['password'] ? $db->dsn['password'] : $name; |
| | | $tablespace = $db->options['default_tablespace'] |
| | | ? ' DEFAULT TABLESPACE '.$db->options['default_tablespace'] : ''; |
| | | |
| | | $query = 'CREATE USER '.$username.' IDENTIFIED BY '.$password.$tablespace; |
| | | $result = $db->standaloneQuery($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE TO '.$username; |
| | | $result = $db->standaloneQuery($query); |
| | | if (PEAR::isError($result)) { |
| | | $query = 'DROP USER '.$username.' CASCADE'; |
| | | $result2 = $db->standaloneQuery($query); |
| | | if (PEAR::isError($result2)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createDatabase: could not setup the database user ('.$result->getUserinfo(). |
| | | ') and then could drop its records ('.$result2->getUserinfo().')'); |
| | | } |
| | | return $result; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropDatabase() |
| | | |
| | | /** |
| | | * drop an existing database |
| | | * |
| | | * @param object $db database object that is extended by this class |
| | | * @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; |
| | | } |
| | | |
| | | $username = $db->options['database_name_prefix'].$name; |
| | | return $db->standaloneQuery('DROP USER '.$username.' CASCADE'); |
| | | } |
| | | |
| | | function _makeAutoincrement($name, $table, $start = 1) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $index_name = $table . '_autoincrement_pk'; |
| | | $definition = array( |
| | | 'primary' => true, |
| | | 'fields' => array($name), |
| | | ); |
| | | $result = $db->manager->createIndex($table, $index_name, $definition); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_makeAutoincrement: primary key for autoincrement PK could not be created'); |
| | | } |
| | | |
| | | $result = $db->manager->createSequence($table, $start); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_makeAutoincrement: sequence for autoincrement PK could not be created'); |
| | | } |
| | | |
| | | $sequence_name = $db->getSequenceName($table); |
| | | $trigger_name = $table . '_autoincrement_pk'; |
| | | $trigger_sql = "CREATE TRIGGER $trigger_name BEFORE INSERT ON $table"; |
| | | $trigger_sql.= " FOR EACH ROW BEGIN IF (:new.$name IS NULL) THEN SELECT "; |
| | | $trigger_sql.= "$sequence_name.NEXTVAL INTO :new.$name FROM DUAL; END IF; END;"; |
| | | |
| | | return $db->query($trigger_sql); |
| | | } |
| | | |
| | | function _dropAutoincrement($name, $table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->manager->dropSequence($table); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | '_dropAutoincrement: sequence for autoincrement PK could not be dropped'); |
| | | } |
| | | |
| | | $sequence_name = $db->getSequenceName($table); |
| | | $trigger_name = $table . '_autoincrement_pk'; |
| | | $trigger_sql = 'DROP TRIGGER ' . $trigger_name; |
| | | |
| | | return $db->query($trigger_sql); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createTable() |
| | | |
| | | /** |
| | | * create a new table |
| | | * |
| | | * @param string $name Name of the database that should be created |
| | | * @param array $fields Associative array that contains the definition of each field of the new table |
| | | * The indexes of the array entries are the names of the fields of the table an |
| | | * the array entry values are associative arrays like those that are meant to be |
| | | * passed with the field definitions to get[Type]Declaration() functions. |
| | | * |
| | | * Example |
| | | * array( |
| | | * |
| | | * 'id' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * 'notnull' => 1 |
| | | * 'default' => 0 |
| | | * ), |
| | | * 'name' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ), |
| | | * 'password' => array( |
| | | * 'type' => 'text', |
| | | * 'length' => 12 |
| | | * ) |
| | | * ); |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createTable($name, $fields) |
| | | { |
| | | $result = parent::createTable($name, $fields); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | foreach($fields as $field_name => $field) { |
| | | if (array_key_exists('autoincrement', $field) && $field['autoincrement']) { |
| | | return $this->_makeAutoincrement($field_name, $name); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param object $db database object that is extended by this class |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @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': |
| | | break; |
| | | case 'rename': |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'alterTable: change type "'.$change_name.'" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | $query = ' DROP ('; |
| | | $fields = $changes['remove']; |
| | | $query.= implode(', ', array_keys($fields)); |
| | | $query.= ')'; |
| | | if (PEAR::isError($result = $db->query("ALTER TABLE $name $query"))) { |
| | | return $result; |
| | | } |
| | | $query = ''; |
| | | } |
| | | |
| | | $query = (array_key_exists('name', $changes) ? 'RENAME TO '.$changes['name'] : ''); |
| | | |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | $query.= ' ADD (' . $type_declaration . ')'; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | foreach ($changes['change'] as $field_name => $field) { |
| | | $query.= "MODIFY ($field_name " . $db->getDeclaration($field['type'], $field_name, $field).')'; |
| | | } |
| | | } |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listDatabases() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if ($db->options['database_name_prefix']) { |
| | | $query = 'SELECT SUBSTR(username, ' |
| | | .(strlen($db->options['database_name_prefix'])+1) |
| | | .") FROM sys.dba_users WHERE username LIKE '" |
| | | .$db->options['database_name_prefix']."%'"; |
| | | } else { |
| | | $query = 'SELECT username FROM sys.dba_users'; |
| | | } |
| | | $result = $db->standaloneQuery($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $databases = $result->fetchCol(); |
| | | if (PEAR::isError($databases)) { |
| | | return $databases; |
| | | } |
| | | // is it legit to force this to lowercase? |
| | | $databases = array_keys(array_change_key_case(array_flip($databases), $db->options['field_case'])); |
| | | $result->free(); |
| | | return $databases; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listUsers() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'SELECT username FROM sys.all_users'; |
| | | $users = $db->queryCol($query); |
| | | if (PEAR::isError($users)) { |
| | | return $users; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | && $db->options['field_case'] == CASE_LOWER |
| | | ) { |
| | | $users = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $users); |
| | | } |
| | | return $users; |
| | | } |
| | | // }}} |
| | | // {{{ listViews() |
| | | |
| | | /** |
| | | * list all views in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listViews() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'SELECT view_name FROM sys.user_views'; |
| | | $views = $db->queryCol($query); |
| | | if (PEAR::isError($views)) { |
| | | return $views; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | && $db->options['field_case'] == CASE_LOWER |
| | | ) { |
| | | $views = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $views); |
| | | } |
| | | return $views; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listFunctions() |
| | | |
| | | /** |
| | | * list all functions in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listFunctions() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = "SELECT name FROM sys.user_source WHERE line = 1 AND type = 'FUNCTION'"; |
| | | $functions = $db->queryCol($query); |
| | | if (PEAR::isError($functions)) { |
| | | return $functions; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | && $db->options['field_case'] == CASE_LOWER |
| | | ) { |
| | | $functions = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $functions); |
| | | } |
| | | return $functions; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB error on failure |
| | | * @access public |
| | | **/ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'SELECT table_name FROM sys.user_tables'; |
| | | return $db->queryCol($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $table = strtoupper($table); |
| | | $query = "SELECT column_name FROM user_tab_columns WHERE table_name='$table' ORDER BY column_id"; |
| | | $fields = $db->queryCol($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | && $db->options['field_case'] == CASE_LOWER |
| | | ) { |
| | | $fields = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $fields); |
| | | } |
| | | return $fields; |
| | | } |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | if (array_key_exists('primary', $definition) && $definition['primary']) { |
| | | $query = "ALTER TABLE $table ADD CONSTRAINT $name PRIMARY KEY ("; |
| | | } else { |
| | | $query = 'CREATE'; |
| | | if (array_key_exists('unique', $definition) && $definition['unique']) { |
| | | $query.= ' UNIQUE'; |
| | | } |
| | | $query .= " INDEX $name ON $table ("; |
| | | } |
| | | $query .= implode(', ', array_keys($definition['fields'])) . ')'; |
| | | |
| | | return $db->query($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ createSequence() |
| | | |
| | | /** |
| | | * create sequence |
| | | * |
| | | * @param object $db database object that is extended by this class |
| | | * @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->getSequenceName($seq_name); |
| | | return $db->query("CREATE SEQUENCE $sequence_name START WITH $start INCREMENT BY 1". |
| | | ($start < 1 ? " MINVALUE $start" : '')); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ dropSequence() |
| | | |
| | | /** |
| | | * drop existing sequence |
| | | * |
| | | * @param object $db database object that is extended by this class |
| | | * @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->getSequenceName($seq_name); |
| | | return $db->query("DROP SEQUENCE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = "SELECT sequence_name FROM sys.user_sequences"; |
| | | $table_names = $db->queryCol($query); |
| | | if (PEAR::isError($table_names)) { |
| | | return $table_names; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) |
| | | $sequences[] = $sqn; |
| | | } |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | && $db->options['field_case'] == CASE_LOWER |
| | | ) { |
| | | $sequences = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $sequences); |
| | | } |
| | | return $sequences; |
| | | }} |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Paul Cooper <pgc@ucecom.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | 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 |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | return $db->standaloneQuery("CREATE DATABASE $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | return $db->standaloneQuery("DROP DATABASE $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ alterTable() |
| | | |
| | | /** |
| | | * alter an existing table |
| | | * |
| | | * @param string $name name of the table that is intended to be changed. |
| | | * @param array $changes associative array that contains the details of each type |
| | | * of change that is intended to be performed. The types of |
| | | * changes that are currently supported are defined as follows: |
| | | * |
| | | * name |
| | | * |
| | | * New name for the table. |
| | | * |
| | | * add |
| | | * |
| | | * Associative array with the names of fields to be added as |
| | | * indexes of the array. The value of each entry of the array |
| | | * should be set to another associative array with the properties |
| | | * of the fields to be added. The properties of the fields should |
| | | * be the same as defined by the Metabase parser. |
| | | * |
| | | * |
| | | * remove |
| | | * |
| | | * Associative array with the names of fields to be removed as indexes |
| | | * of the array. Currently the values assigned to each entry are ignored. |
| | | * An empty array should be used for future compatibility. |
| | | * |
| | | * rename |
| | | * |
| | | * Associative array with the names of fields to be renamed as indexes |
| | | * of the array. The value of each entry of the array should be set to |
| | | * another associative array with the entry named name with the new |
| | | * field name and the entry named Declaration that is expected to contain |
| | | * the portion of the field declaration already in DBMS specific SQL code |
| | | * as it is used in the CREATE TABLE statement. |
| | | * |
| | | * change |
| | | * |
| | | * Associative array with the names of the fields to be changed as indexes |
| | | * of the array. Keep in mind that if it is intended to change either the |
| | | * name of a field and any other properties, the change array entries |
| | | * should have the new names of the fields as array indexes. |
| | | * |
| | | * The value of each entry of the array should be set to another associative |
| | | * array with the properties of the fields to that are meant to be changed as |
| | | * array entries. These entries should be assigned to the new values of the |
| | | * respective properties. The properties of the fields should be the same |
| | | * as defined by the Metabase parser. |
| | | * |
| | | * Example |
| | | * array( |
| | | * 'name' => 'userlist', |
| | | * 'add' => array( |
| | | * 'quota' => array( |
| | | * 'type' => 'integer', |
| | | * 'unsigned' => 1 |
| | | * ) |
| | | * ), |
| | | * 'remove' => array( |
| | | * 'file_limit' => array(), |
| | | * 'time_limit' => array() |
| | | * ), |
| | | * 'change' => array( |
| | | * 'gender' => array( |
| | | * 'default' => 'M', |
| | | * ) |
| | | * ), |
| | | * 'rename' => array( |
| | | * 'sex' => array( |
| | | * 'name' => 'gender', |
| | | * ) |
| | | * ) |
| | | * ) |
| | | * @param boolean $check indicates whether the function should just check if the DBMS driver |
| | | * can perform the requested table alterations if the value is true or |
| | | * actually perform them otherwise. |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function alterTable($name, $changes, $check) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | foreach ($changes as $change_name => $change) { |
| | | switch ($change_name) { |
| | | case 'add': |
| | | case 'remove': |
| | | case 'change': |
| | | case 'name': |
| | | break; |
| | | case 'rename': |
| | | default: |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'alterTable: change type "'.$change_name.'\" not yet supported'); |
| | | } |
| | | } |
| | | |
| | | if ($check) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | $query = (array_key_exists('name', $changes) ? 'RENAME TO '.$changes['name'] : ''); |
| | | |
| | | if (array_key_exists('add', $changes)) { |
| | | foreach ($changes['add'] as $field_name => $field) { |
| | | $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); |
| | | if (PEAR::isError($type_declaration)) { |
| | | return $err; |
| | | } |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'ADD ' . $type_declaration; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('remove', $changes)) { |
| | | foreach ($changes['remove'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $query.= 'DROP ' . $field_name; |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('change', $changes)) { |
| | | // missing support to change DEFAULT and NULLability |
| | | foreach ($changes['change'] as $field_name => $field) { |
| | | if ($query) { |
| | | $query.= ', '; |
| | | } |
| | | $db->loadModule('Datatype'); |
| | | $query.= "ALTER $field_name TYPE ".$db->datatype->getTypeDeclaration($field); |
| | | } |
| | | } |
| | | |
| | | if (!$query) { |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | return $db->query("ALTER TABLE $name $query"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function listDatabases() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->standaloneQuery('SELECT datname FROM pg_database'); |
| | | if (!MDB2::isResultCommon($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $col = $result->fetchCol(); |
| | | $result->free(); |
| | | return $col; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function listUsers() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->standaloneQuery('SELECT usename FROM pg_user'); |
| | | if (!MDB2::isResultCommon($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $col = $result->fetchCol(); |
| | | $result->free(); |
| | | return $col; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listViews() |
| | | |
| | | /** |
| | | * list the views in the database |
| | | * |
| | | * @return mixed MDB2_OK 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'; |
| | | return $db->queryCol($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listFunctions() |
| | | |
| | | /** |
| | | * list all functions in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listFunctions() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $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')"; |
| | | return $db->queryCol($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function listTables() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | // 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_'"; |
| | | return $db->queryCol($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->query("SELECT * FROM $table"); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $result->getColumnNames(); |
| | | $result->free(); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | return array_flip($columns); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | |
| | | if (array_key_exists('primary', $definition) && $definition['primary']) { |
| | | $query = "ALTER TABLE $table ADD CONSTRAINT $name PRIMARY KEY ("; |
| | | } else { |
| | | $query = 'CREATE'; |
| | | if (array_key_exists('unique', $definition) && $definition['unique']) { |
| | | $query.= ' UNIQUE'; |
| | | } |
| | | $query.= " INDEX $name ON $table ("; |
| | | } |
| | | $query.= implode(', ', array_keys($definition['fields'])); |
| | | $query.= ')'; |
| | | |
| | | return $db->query($query); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $subquery = "SELECT indexrelid FROM pg_index, pg_class"; |
| | | $subquery.= " WHERE (pg_class.relname='$table') AND (pg_class.oid=pg_index.indrelid)"; |
| | | return $db->queryCol("SELECT relname FROM pg_class WHERE oid IN ($subquery)"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $db->query("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->getSequenceName($seq_name); |
| | | return $db->query("DROP SEQUENCE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | **/ |
| | | function listSequences() |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $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; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) |
| | | $sequences[] = $sqn; |
| | | } |
| | | return $sequences; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@backendmedia.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Manager/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 SQLite driver for the management modules |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@backendmedia.com> |
| | | */ |
| | | 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 |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function createDatabase($name) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $database_file = $db->_getDatabaseFile($name); |
| | | if (file_exists($database_file)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createDatabase: database already exists'); |
| | | } |
| | | $php_errormsg = ''; |
| | | $handle = @sqlite_open($database_file, $db->dsn['mode'], $php_errormsg); |
| | | if (!$handle) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, |
| | | 'createDatabase: '.(isset($php_errormsg) ? $php_errormsg : 'could not create the database file')); |
| | | } |
| | | @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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $database_file = $db->_getDatabaseFile($name); |
| | | if (!@file_exists($database_file)) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null, |
| | | 'dropDatabase: database does not exist'); |
| | | } |
| | | $result = @unlink($database_file); |
| | | if (!$result) { |
| | | return $db->raiseError(MDB2_ERROR_CANNOT_DROP, null, null, |
| | | 'dropDatabase: '.(isset($php_errormsg) ? $php_errormsg : 'could not remove the database file')); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listDatabases() |
| | | |
| | | /** |
| | | * list all databases |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listDatabases() |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'listDatabases: list databases is not supported'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listUsers() |
| | | |
| | | /** |
| | | * list all users |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listUsers() |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | return $db->queryCol('SELECT DISTINCT USER FROM USER'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTables() |
| | | |
| | | /** |
| | | * list all tables in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTables() |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $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; |
| | | } |
| | | $tables = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if (!$this->_isSequenceName($table_names[$i])) |
| | | $tables[] = $table_names[$i]; |
| | | } |
| | | return $tables; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableFields() |
| | | |
| | | /** |
| | | * list all fields in a tables in the current database |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableFields($table) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $query = "SELECT * FROM $table"; |
| | | $db->setLimit(1); |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $result->getColumnNames(); |
| | | $result->free(); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | return array_flip($columns); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $query = 'CREATE '.(isset($definition['unique']) ? 'UNIQUE' : '')." INDEX $name ON $table ("; |
| | | $skipped_first = false; |
| | | foreach ($definition['fields'] as $field_name => $field) { |
| | | if ($skipped_first) { |
| | | $query .= ','; |
| | | } |
| | | $query .= $field_name; |
| | | $skipped_first = true; |
| | | } |
| | | $query .= ')'; |
| | | return $db->query($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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | return $db->query("DROP INDEX $name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listTableIndexes() |
| | | |
| | | /** |
| | | * list all indexes in a table |
| | | * |
| | | * @param string $table name of table that should be used in method |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listTableIndexes($table) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $query = "SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='$table' AND sql NOT NULL ORDER BY name"; |
| | | $indexes_all = $db->queryCol($query); |
| | | if (PEAR::isError($indexes_all)) { |
| | | return $indexes_all; |
| | | } |
| | | $found = $indexes = array(); |
| | | foreach ($indexes_all as $index => $index_name) { |
| | | if ($indexes_all[$index] != 'PRIMARY' && !isset($found[$index_name])) { |
| | | $indexes[] = $index_name; |
| | | $found[$index_name] = true; |
| | | } |
| | | } |
| | | return $indexes; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $sequence_name = $db->getSequenceName($seq_name); |
| | | $seqcol_name = $db->options['seqcol_name']; |
| | | $query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER PRIMARY KEY DEFAULT 0 NOT NULL)"; |
| | | $res = $db->query($query); |
| | | if (PEAR::isError($res)) { |
| | | return $res; |
| | | } |
| | | if ($start == 1) { |
| | | return MDB2_OK; |
| | | } |
| | | $res = $db->query("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'); |
| | | if (!PEAR::isError($res)) { |
| | | return MDB2_OK; |
| | | } |
| | | // Handle error |
| | | $result = $db->query("DROP TABLE $sequence_name"); |
| | | if (PEAR::isError($result)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not drop inconsistent sequence table ('. |
| | | $result->getMessage().' ('.$result->getUserinfo().'))'); |
| | | } |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'createSequence: could not create sequence table ('. |
| | | $res->getMessage().' ('.$res->getUserinfo().'))'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $sequence_name = $db->getSequenceName($seq_name); |
| | | return $db->query("DROP TABLE $sequence_name"); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ listSequences() |
| | | |
| | | /** |
| | | * list all sequences in the current database |
| | | * |
| | | * @return mixed data array on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function listSequences() |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $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; |
| | | } |
| | | $sequences = array(); |
| | | for ($i = 0, $j = count($table_names); $i < $j; ++$i) { |
| | | if ($sqn = $this->_isSequenceName($table_names[$i])) |
| | | $sequences[] = $sqn; |
| | | } |
| | | return $sequences; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 FrontBase driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Native_fbsql extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 InterbaseBase driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Native_ibase extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 MSSQL driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Native_mssql extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 MySQL driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Native_mysqli extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 Oracle driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Native_oci8 extends MDB2_Module_Common |
| | | { |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Paul Cooper <pgc@ucecom.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | /** |
| | | * MDB2 PostGreSQL driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Paul Cooper <pgc@ucecom.com> |
| | | */ |
| | | class MDB2_Driver_Native_pgsql extends MDB2_Module_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; |
| | | } |
| | | |
| | | if (!@pg_lo_unlink($db->connection, $OID)) { |
| | | return $db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@backendmedia.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 SQLite driver for the native module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@backendmedia.com> |
| | | */ |
| | | class MDB2_Driver_Native_sqlite |
| | | { |
| | | var $db_index; |
| | | |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct($db_index) |
| | | { |
| | | $this->db_index = $db_index; |
| | | } |
| | | |
| | | function MDB2_Driver_Native_sqlite($db_index) |
| | | { |
| | | $this->__construct($db_index); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getInsertID() |
| | | |
| | | /** |
| | | * get last insert ID |
| | | * |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function getInsertID() |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | return @sqlite_last_insert_rowid($db->connection); |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 FrontBase driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Reverse_fbsql extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // }}} |
| | | // {{{ 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::tableInfo() |
| | | */ |
| | | function tableInfo($result, $mode = null) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | |
| | | $connected = $db->connect(); |
| | | if (PEAR::isError($connected)) { |
| | | return $connected; |
| | | } |
| | | $id = @fbsql_list_fields($db->database_name, $result, $db->connection); |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_resource($id)) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | 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 = @fbsql_num_fields($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $res[$i] = array( |
| | | 'table' => $case_func(@fbsql_field_table($id, $i)), |
| | | 'name' => $case_func(@fbsql_field_name($id, $i)), |
| | | 'type' => @fbsql_field_type($id, $i), |
| | | 'len' => @fbsql_field_len($id, $i), |
| | | 'flags' => @fbsql_field_flags($id, $i), |
| | | ); |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @fbsql_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 InterbaseBase driver for the reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Reverse_ibase extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // }}} |
| | | // {{{ 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) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $id = $db->_doQuery("SELECT * FROM $result WHERE 1=0"); |
| | | if (PEAR::isError($id)) { |
| | | return $id; |
| | | } |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_resource($id)) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | 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 = @ibase_num_fields($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $info = @ibase_field_info($id, $i); |
| | | $res[$i] = array( |
| | | 'table' => $got_string ? $case_func($result) : '', |
| | | 'name' => $case_func($info['name']), |
| | | 'type' => $info['type'], |
| | | 'len' => $info['length'], |
| | | 'flags' => ($got_string) |
| | | ? $this->_ibaseFieldFlags($info['name'], $result) : '', |
| | | ); |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @ibase_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _ibaseFieldFlags() |
| | | |
| | | /** |
| | | * Get the column's flags |
| | | * |
| | | * Supports "primary_key", "unique_key", "not_null", "default", |
| | | * "computed" and "blob". |
| | | * |
| | | * @param string $field_name the name of the field |
| | | * @param string $table_name the name of the table |
| | | * |
| | | * @return string the flags |
| | | * |
| | | * @access protected |
| | | */ |
| | | function _ibaseFieldFlags($field_name, $table_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE' |
| | | .' FROM RDB$INDEX_SEGMENTS I' |
| | | .' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME' |
| | | .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\'' |
| | | .' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''; |
| | | |
| | | $result = $db->_doQuery($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $flags = ''; |
| | | if ($obj = @ibase_fetch_object($result)) { |
| | | @ibase_free_result($result); |
| | | if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') { |
| | | $flags.= 'primary_key '; |
| | | } |
| | | if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') { |
| | | $flags.= 'unique_key '; |
| | | } |
| | | } |
| | | |
| | | $query = 'SELECT R.RDB$NULL_FLAG AS NFLAG,' |
| | | .' R.RDB$DEFAULT_SOURCE AS DSOURCE,' |
| | | .' F.RDB$FIELD_TYPE AS FTYPE,' |
| | | .' F.RDB$COMPUTED_SOURCE AS CSOURCE' |
| | | .' FROM RDB$RELATION_FIELDS R ' |
| | | .' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME' |
| | | .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'' |
| | | .' AND R.RDB$FIELD_NAME=\'' . $field_name . '\''; |
| | | |
| | | $result = $db->_doQuery($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | if ($obj = @ibase_fetch_object($result)) { |
| | | @ibase_free_result($result); |
| | | if (isset($obj->NFLAG)) { |
| | | $flags.= 'not_null '; |
| | | } |
| | | if (isset($obj->DSOURCE)) { |
| | | $flags.= 'default '; |
| | | } |
| | | if (isset($obj->CSOURCE)) { |
| | | $flags.= 'computed '; |
| | | } |
| | | if (isset($obj->FTYPE) && $obj->FTYPE == 261) { |
| | | $flags.= 'blob '; |
| | | } |
| | | } |
| | | |
| | | return trim($flags); |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MSSQL driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // }}} |
| | | // {{{ 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) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $id = $db->_doQuery("SELECT TOP 0 * FROM [$result]"); |
| | | if (PEAR::isError($id)) { |
| | | return $id; |
| | | } |
| | | |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_resource($id)) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | 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 = @mssql_num_fields($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $res[$i] = array( |
| | | 'table' => $got_string ? $case_func($result) : '', |
| | | 'name' => $case_func(@mssql_field_name($id, $i)), |
| | | 'type' => @mssql_field_type($id, $i), |
| | | 'len' => @mssql_field_length($id, $i), |
| | | // We only support flags for table |
| | | 'flags' => $got_string |
| | | ? $this->_mssql_field_flags($result, @mssql_field_name($id, $i)) : '', |
| | | ); |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @mssql_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _mssql_field_flags() |
| | | |
| | | /** |
| | | * Get a column's flags |
| | | * |
| | | * Supports "not_null", "primary_key", |
| | | * "auto_increment" (mssql identity), "timestamp" (mssql timestamp), |
| | | * "unique_key" (mssql unique index, unique check or primary_key) and |
| | | * "multiple_key" (multikey index) |
| | | * |
| | | * mssql timestamp is NOT similar to the mysql timestamp so this is maybe |
| | | * not useful at all - is the behaviour of mysql_field_flags that primary |
| | | * keys are alway unique? is the interpretation of multiple_key correct? |
| | | * |
| | | * @param string $table the table name |
| | | * @param string $column the field name |
| | | * |
| | | * @return string the flags |
| | | * |
| | | * @access protected |
| | | * @author Joern Barthel <j_barthel@web.de> |
| | | */ |
| | | function _mssql_field_flags($table, $column) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | static $tableName = null; |
| | | static $flags = array(); |
| | | |
| | | if ($table != $tableName) { |
| | | |
| | | $flags = array(); |
| | | $tableName = $table; |
| | | |
| | | // get unique and primary keys |
| | | $res = $db->queryAll("EXEC SP_HELPINDEX[$table]", null, MDB2_FETCHMODE_ASSOC); |
| | | |
| | | foreach ($res as $val) { |
| | | $keys = explode(', ', $val['index_keys']); |
| | | |
| | | if (sizeof($keys) > 1) { |
| | | foreach ($keys as $key) { |
| | | $this->_add_flag($flags[$key], 'multiple_key'); |
| | | } |
| | | } |
| | | |
| | | if (strpos($val['index_description'], 'primary key')) { |
| | | foreach ($keys as $key) { |
| | | $this->_add_flag($flags[$key], 'primary_key'); |
| | | } |
| | | } elseif (strpos($val['index_description'], 'unique')) { |
| | | foreach ($keys as $key) { |
| | | $this->_add_flag($flags[$key], 'unique_key'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // get auto_increment, not_null and timestamp |
| | | $res = $db->queryAll("EXEC SP_COLUMNS[$table]", null, MDB2_FETCHMODE_ASSOC); |
| | | |
| | | foreach ($res as $val) { |
| | | $val = array_change_key_case($val, $db->options['field_case']); |
| | | if ($val['nullable'] == '0') { |
| | | $this->_add_flag($flags[$val['column_name']], 'not_null'); |
| | | } |
| | | if (strpos($val['type_name'], 'identity')) { |
| | | $this->_add_flag($flags[$val['column_name']], 'auto_increment'); |
| | | } |
| | | if (strpos($val['type_name'], 'timestamp')) { |
| | | $this->_add_flag($flags[$val['column_name']], 'timestamp'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists($column, $flags)) { |
| | | return(implode(' ', $flags[$column])); |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _add_flag() |
| | | |
| | | /** |
| | | * Adds a string to the flags array if the flag is not yet in there |
| | | * - if there is no flag present the array is created |
| | | * |
| | | * @param array &$array the reference to the flag-array |
| | | * @param string $value the flag value |
| | | * |
| | | * @return void |
| | | * |
| | | * @access protected |
| | | * @author Joern Barthel <j_barthel@web.de> |
| | | */ |
| | | function _add_flag(&$array, $value) |
| | | { |
| | | if (!is_array($array)) { |
| | | $array = array($value); |
| | | } elseif (!in_array($value, $array)) { |
| | | array_push($array, $value); |
| | | } |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 MySQL driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common |
| | | { |
| | | /** |
| | | * Array for converting MYSQLI_*_FLAG constants to text values |
| | | * @var array |
| | | * @access public |
| | | * @since Property available since Release 1.6.5 |
| | | */ |
| | | var $flags = array( |
| | | MYSQLI_NOT_NULL_FLAG => 'not_null', |
| | | MYSQLI_PRI_KEY_FLAG => 'primary_key', |
| | | MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', |
| | | MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', |
| | | MYSQLI_BLOB_FLAG => 'blob', |
| | | MYSQLI_UNSIGNED_FLAG => 'unsigned', |
| | | MYSQLI_ZEROFILL_FLAG => 'zerofill', |
| | | MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', |
| | | MYSQLI_TIMESTAMP_FLAG => 'timestamp', |
| | | MYSQLI_SET_FLAG => 'set', |
| | | // MYSQLI_NUM_FLAG => 'numeric', // unnecessary |
| | | // MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie |
| | | MYSQLI_GROUP_FLAG => 'group_by' |
| | | ); |
| | | |
| | | /** |
| | | * Array for converting MYSQLI_TYPE_* constants to text values |
| | | * @var array |
| | | * @access public |
| | | * @since Property available since Release 1.6.5 |
| | | */ |
| | | var $types = array( |
| | | MYSQLI_TYPE_DECIMAL => 'decimal', |
| | | MYSQLI_TYPE_TINY => 'tinyint', |
| | | MYSQLI_TYPE_SHORT => 'int', |
| | | MYSQLI_TYPE_LONG => 'int', |
| | | MYSQLI_TYPE_FLOAT => 'float', |
| | | MYSQLI_TYPE_DOUBLE => 'double', |
| | | // MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it |
| | | MYSQLI_TYPE_TIMESTAMP => 'timestamp', |
| | | MYSQLI_TYPE_LONGLONG => 'bigint', |
| | | MYSQLI_TYPE_INT24 => 'mediumint', |
| | | MYSQLI_TYPE_DATE => 'date', |
| | | MYSQLI_TYPE_TIME => 'time', |
| | | MYSQLI_TYPE_DATETIME => 'datetime', |
| | | MYSQLI_TYPE_YEAR => 'year', |
| | | MYSQLI_TYPE_NEWDATE => 'date', |
| | | MYSQLI_TYPE_ENUM => 'enum', |
| | | MYSQLI_TYPE_SET => 'set', |
| | | MYSQLI_TYPE_TINY_BLOB => 'tinyblob', |
| | | MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', |
| | | MYSQLI_TYPE_LONG_BLOB => 'longblob', |
| | | MYSQLI_TYPE_BLOB => 'blob', |
| | | MYSQLI_TYPE_VAR_STRING => 'varchar', |
| | | MYSQLI_TYPE_STRING => 'char', |
| | | MYSQLI_TYPE_GEOMETRY => 'geometry', |
| | | ); |
| | | |
| | | // {{{ getTableFieldDefinition() |
| | | |
| | | /** |
| | | * get the stucture of a field into an array |
| | | * |
| | | * @param string $table 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, $field_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->loadModule('Datatype'); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $db->queryAll("SHOW COLUMNS FROM $table", null, MDB2_FETCHMODE_ASSOC); |
| | | if (PEAR::isError($columns)) { |
| | | return $columns; |
| | | } |
| | | foreach ($columns as $column) { |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { |
| | | if ($db->options['field_case'] == CASE_LOWER) { |
| | | $column['field'] = strtolower($column['field']); |
| | | } else { |
| | | $column['field'] = strtoupper($column['field']); |
| | | } |
| | | } else { |
| | | $column = array_change_key_case($column, $db->options['field_case']); |
| | | } |
| | | if ($field_name == $column['field']) { |
| | | list($types, $length) = $db->datatype->mapNativeDatatype($column); |
| | | $notnull = false; |
| | | if (array_key_exists('null', $column) && $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 (array_key_exists('extra', $column) && $column['extra'] == 'auto_increment') { |
| | | $autoincrement = true; |
| | | } |
| | | $definition = array(); |
| | | foreach ($types as $key => $type) { |
| | | $definition[$key] = array( |
| | | 'type' => $type, |
| | | 'notnull' => $notnull, |
| | | ); |
| | | if ($length > 0) { |
| | | $definition[$key]['length'] = $length; |
| | | } |
| | | if ($default !== false) { |
| | | $definition[$key]['default'] = $default; |
| | | } |
| | | if ($autoincrement !== false) { |
| | | $definition[$key]['autoincrement'] = $autoincrement; |
| | | } |
| | | } |
| | | return $definition; |
| | | } |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: it was not specified an existing table column'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getTableIndexDefinition() |
| | | |
| | | /** |
| | | * get the stucture of an index into an array |
| | | * |
| | | * @param string $table 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, $index_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->query("SHOW INDEX FROM $table"); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $definition = array(); |
| | | while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { |
| | | if (!($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) |
| | | || $db->options['field_case'] != CASE_LOWER |
| | | ) { |
| | | $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['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(); |
| | | if (array_key_exists('collation', $row)) { |
| | | $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' |
| | | ? 'ascending' : 'descending'); |
| | | } |
| | | } |
| | | } |
| | | $result->free(); |
| | | if (!array_key_exists('fields', $definition)) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableIndexDefinition: it was not specified an existing table index'); |
| | | } |
| | | return $definition; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $id = $db->_doQuery("SELECT * FROM $result LIMIT 0"); |
| | | if (PEAR::isError($id)) { |
| | | return $id; |
| | | } |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_a($id, 'mysqli_result')) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | 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 = @mysqli_num_fields($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $tmp = @mysqli_fetch_field($id); |
| | | |
| | | $flags = ''; |
| | | foreach ($this->flags as $const => $means) { |
| | | if ($tmp->flags & $const) { |
| | | $flags.= $means . ' '; |
| | | } |
| | | } |
| | | if ($tmp->def) { |
| | | $flags.= 'default_' . rawurlencode($tmp->def); |
| | | } |
| | | $flags = trim($flags); |
| | | |
| | | $res[$i] = array( |
| | | 'table' => $case_func($tmp->table), |
| | | 'name' => $case_func($tmp->name), |
| | | 'type' => isset($this->types[$tmp->type]) |
| | | ? $this->types[$tmp->type] |
| | | : 'unknown', |
| | | 'len' => $tmp->max_length, |
| | | 'flags' => $flags, |
| | | ); |
| | | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @mysqli_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 Oracle driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@dybnet.de> |
| | | */ |
| | | class MDB2_Driver_Reverse_oci8 extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // }}} |
| | | // {{{ tableInfo() |
| | | |
| | | /** |
| | | * Returns information about a table or a result set |
| | | * |
| | | * NOTE: only supports 'table' and 'flags' if <var>$result</var> |
| | | * is a table name. |
| | | * |
| | | * NOTE: flags won't contain index information. |
| | | * |
| | | * @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) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | 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'; |
| | | } |
| | | |
| | | $res = array(); |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $result = strtoupper($result); |
| | | $query = 'SELECT column_name, data_type, data_length, ' |
| | | . 'nullable ' |
| | | . 'FROM user_tab_columns ' |
| | | . "WHERE table_name='$result' ORDER BY column_id"; |
| | | |
| | | $stmt = $db->_doQuery($query); |
| | | if (PEAR::isError($stmt)) { |
| | | return $stmt; |
| | | } |
| | | |
| | | $i = 0; |
| | | while (@OCIFetch($stmt)) { |
| | | $res[$i] = array( |
| | | 'table' => $case_func($result), |
| | | 'name' => $case_func(@OCIResult($stmt, 1)), |
| | | 'type' => @OCIResult($stmt, 2), |
| | | 'len' => @OCIResult($stmt, 3), |
| | | 'flags' => (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '', |
| | | ); |
| | | 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; |
| | | } |
| | | $i++; |
| | | } |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $i; |
| | | } |
| | | @OCIFreeStatement($stmt); |
| | | |
| | | } else { |
| | | if (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $result = $result->getResource(); |
| | | } |
| | | |
| | | $res = array(); |
| | | |
| | | if ($result === $db->last_stmt) { |
| | | $count = @OCINumCols($result); |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $res[$i] = array( |
| | | 'table' => '', |
| | | 'name' => $case_func(@OCIColumnName($result, $i+1)), |
| | | 'type' => @OCIColumnType($result, $i+1), |
| | | 'len' => @OCIColumnSize($result, $i+1), |
| | | 'flags' => '', |
| | | ); |
| | | 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; |
| | | } |
| | | } |
| | | } else { |
| | | return $db->raiseError(MDB2_ERROR_NOT_CAPABLE); |
| | | } |
| | | } |
| | | return $res; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Paul Cooper <pgc@ucecom.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | 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> |
| | | */ |
| | | class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common |
| | | { |
| | | // {{{ getTableFieldDefinition() |
| | | |
| | | /** |
| | | * get the stucture of a field into an array |
| | | * |
| | | * @param string $table 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, $field_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $result = $db->loadModule('Datatype'); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | $column = $db->queryRow("SELECT |
| | | attnum,attname,typname,attlen,attnotnull, |
| | | atttypmod,usename,usesysid,pg_class.oid,relpages, |
| | | reltuples,relhaspkey,relhasrules,relacl,adsrc |
| | | FROM pg_class,pg_user,pg_type, |
| | | pg_attribute left outer join pg_attrdef on |
| | | pg_attribute.attrelid=pg_attrdef.adrelid |
| | | WHERE (pg_class.relname='$table') |
| | | and (pg_class.oid=pg_attribute.attrelid) |
| | | and (pg_class.relowner=pg_user.usesysid) |
| | | and (pg_attribute.atttypid=pg_type.oid) |
| | | and attnum > 0 |
| | | and attname = '$field_name' |
| | | ORDER BY attnum |
| | | ", null, MDB2_FETCHMODE_ASSOC); |
| | | if (PEAR::isError($column)) { |
| | | return $column; |
| | | } |
| | | |
| | | list($types, $length) = $db->datatype->mapNativeDatatype($column); |
| | | $notnull = false; |
| | | if (array_key_exists('attnotnull', $column) && $column['attnotnull'] == 't') { |
| | | $notnull = true; |
| | | } |
| | | $default = false; |
| | | // todo .. check how default look like |
| | | if (!preg_match("/nextval\('([^']+)'/", $column['adsrc']) |
| | | && strlen($column['adsrc']) > 2 |
| | | ) { |
| | | $default = substr($column['adsrc'], 1, -1); |
| | | if (is_null($default) && $notnull) { |
| | | $default = ''; |
| | | } |
| | | } |
| | | $autoincrement = false; |
| | | if (preg_match("/nextval\('([^']+)'/", $column['adsrc'], $nextvals)) { |
| | | $autoincrement = true; |
| | | } |
| | | $definition = array(); |
| | | foreach ($types as $key => $type) { |
| | | $definition[$key] = array( |
| | | 'type' => $type, |
| | | 'notnull' => $notnull, |
| | | ); |
| | | if ($length > 0) { |
| | | $definition[$key]['length'] = $length; |
| | | } |
| | | if ($default !== false) { |
| | | $definition[$key]['default'] = $default; |
| | | } |
| | | if ($autoincrement !== false) { |
| | | $definition[$key]['autoincrement'] = $autoincrement; |
| | | } |
| | | } |
| | | return $definition; |
| | | } |
| | | |
| | | |
| | | // }}} |
| | | // {{{ getTableIndexDefinition() |
| | | /** |
| | | * get the stucture of an index into an array |
| | | * |
| | | * @param string $table 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, $index_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $query = "SELECT * FROM pg_index, pg_class |
| | | WHERE (pg_class.relname='$index_name') AND (pg_class.oid=pg_index.indexrelid)"; |
| | | $row = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); |
| | | if (PEAR::isError($row)) { |
| | | return $row; |
| | | } |
| | | if ($row['relname'] != $index_name) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableIndexDefinition: it was not specified an existing table index'); |
| | | } |
| | | |
| | | $db->loadModule('Manager'); |
| | | $columns = $db->manager->listTableFields($table); |
| | | |
| | | $definition = array(); |
| | | if ($row['indisunique'] == 't') { |
| | | $definition['unique'] = true; |
| | | } |
| | | |
| | | $index_column_numbers = explode(' ', $row['indkey']); |
| | | |
| | | foreach ($index_column_numbers as $number) { |
| | | $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending'); |
| | | } |
| | | return $definition; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $id = $db->_doQuery("SELECT * FROM $result LIMIT 0"); |
| | | if (PEAR::isError($id)) { |
| | | return $id; |
| | | } |
| | | $got_string = true; |
| | | } elseif (MDB2::isResultCommon($result)) { |
| | | /* |
| | | * Probably received a result object. |
| | | * Extract the result resource identifier. |
| | | */ |
| | | $id = $result->getResource(); |
| | | $got_string = false; |
| | | } else { |
| | | /* |
| | | * Probably received a result resource identifier. |
| | | * Copy it. |
| | | * Deprecated. Here for compatibility only. |
| | | */ |
| | | $id = $result; |
| | | $got_string = false; |
| | | } |
| | | |
| | | if (!is_resource($id)) { |
| | | return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); |
| | | } |
| | | |
| | | 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($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | $res[$i] = array( |
| | | 'table' => $got_string ? $case_func($result) : '', |
| | | 'name' => $case_func(@pg_field_name($id, $i)), |
| | | 'type' => @pg_field_type($id, $i), |
| | | 'len' => @pg_field_size($id, $i), |
| | | 'flags' => $got_string |
| | | ? $this->_pgFieldFlags($id, $i, $result) |
| | | : '', |
| | | ); |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | // free the result only if we were called on a table |
| | | if ($got_string) { |
| | | @pg_free_result($id); |
| | | } |
| | | return $res; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _pgFieldFlags() |
| | | |
| | | /** |
| | | * Get a column's flags |
| | | * |
| | | * Supports "not_null", "default_value", "primary_key", "unique_key" |
| | | * and "multiple_key". The default value is passed through |
| | | * rawurlencode() in case there are spaces in it. |
| | | * |
| | | * @param int $resource the PostgreSQL result identifier |
| | | * @param int $num_field the field number |
| | | * |
| | | * @return string the flags |
| | | * |
| | | * @access protected |
| | | */ |
| | | function _pgFieldFlags($resource, $num_field, $table_name) |
| | | { |
| | | $db =& $this->getDBInstance(); |
| | | if (PEAR::isError($db)) { |
| | | return $db; |
| | | } |
| | | |
| | | $field_name = @pg_field_name($resource, $num_field); |
| | | |
| | | $result = @pg_query($db->connection, "SELECT f.attnotnull, f.atthasdef |
| | | FROM pg_attribute f, pg_class tab, pg_type typ |
| | | WHERE tab.relname = typ.typname |
| | | AND typ.typrelid = f.attrelid |
| | | AND f.attname = '$field_name' |
| | | AND tab.relname = '$table_name'"); |
| | | if (@pg_num_rows($result) > 0) { |
| | | $row = @pg_fetch_row($result, 0); |
| | | $flags = ($row[0] == 't') ? 'not_null ' : ''; |
| | | |
| | | if ($row[1] == 't') { |
| | | $result = @pg_query($db->connection, "SELECT a.adsrc |
| | | FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a |
| | | WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid |
| | | AND f.attrelid = a.adrelid AND f.attname = '$field_name' |
| | | AND tab.relname = '$table_name' AND f.attnum = a.adnum"); |
| | | $row = @pg_fetch_row($result, 0); |
| | | $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); |
| | | $flags.= 'default_' . rawurlencode($num) . ' '; |
| | | } |
| | | } else { |
| | | $flags = ''; |
| | | } |
| | | $result = @pg_query($db->connection, "SELECT i.indisunique, i.indisprimary, i.indkey |
| | | FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i |
| | | WHERE tab.relname = typ.typname |
| | | AND typ.typrelid = f.attrelid |
| | | AND f.attrelid = i.indrelid |
| | | AND f.attname = '$field_name' |
| | | AND tab.relname = '$table_name'"); |
| | | $count = @pg_num_rows($result); |
| | | |
| | | for ($i = 0; $i < $count ; $i++) { |
| | | $row = @pg_fetch_row($result, $i); |
| | | $keys = explode(' ', $row[2]); |
| | | |
| | | if (in_array($num_field + 1, $keys)) { |
| | | $flags.= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; |
| | | $flags.= ($row[1] == 't') ? 'primary_key ' : ''; |
| | | if (count($keys) > 1) |
| | | $flags.= 'multiple_key '; |
| | | } |
| | | } |
| | | |
| | | return trim($flags); |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@backendmedia.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | require_once 'MDB2/Driver/Reverse/Common.php'; |
| | | |
| | | /** |
| | | * MDB2 SQlite driver for the schema reverse engineering module |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@backendmedia.com> |
| | | */ |
| | | class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common |
| | | { |
| | | |
| | | function _getTableColumns($query) |
| | | { |
| | | $start_pos = strpos($query, '('); |
| | | $end_pos = strrpos($query, ')'); |
| | | $column_def = substr($query, $start_pos+1, $end_pos-$start_pos-1); |
| | | $column_sql = split(',', $column_def); |
| | | $columns = array(); |
| | | $count = count($column_sql); |
| | | if ($count == 0) { |
| | | return $db->raiseError('unexpected empty table column definition list'); |
| | | } |
| | | $regexp = '/^([^ ]+) (CHAR|VARCHAR|VARCHAR2|TEXT|INT|INTEGER|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( PRIMARY)?( \(([1-9][0-9]*)(,([1-9][0-9]*))?\))?( DEFAULT (\'[^\']*\'|[^ ]+))?( NOT NULL)?$/i'; |
| | | for ($i=0, $j=0; $i<$count; ++$i) { |
| | | if (!preg_match($regexp, $column_sql[$i], $matches)) { |
| | | return $db->raiseError('unexpected table column SQL definition'); |
| | | } |
| | | $columns[$j]['name'] = $matches[1]; |
| | | $columns[$j]['type'] = strtolower($matches[2]); |
| | | if (isset($matches[5]) && strlen($matches[5])) { |
| | | $columns[$j]['length'] = $matches[5]; |
| | | } |
| | | if (isset($matches[7]) && strlen($matches[7])) { |
| | | $columns[$j]['decimal'] = $matches[7]; |
| | | } |
| | | if (isset($matches[9]) && strlen($matches[9])) { |
| | | $default = $matches[9]; |
| | | if (strlen($default) && $default[0]=="'") { |
| | | $default = str_replace("''", "'", substr($default, 1, strlen($default)-2)); |
| | | } |
| | | $columns[$j]['default'] = $default; |
| | | } |
| | | if (isset($matches[10]) && strlen($matches[10])) { |
| | | $columns[$j]['notnull'] = true; |
| | | } |
| | | ++$j; |
| | | } |
| | | return $columns; |
| | | } |
| | | |
| | | // {{{ getTableFieldDefinition() |
| | | |
| | | /** |
| | | * get the stucture of a field into an array |
| | | * |
| | | * @param string $table 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, $field_name) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | $result = $db->loadModule('Datatype'); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $query = "SELECT sql FROM sqlite_master WHERE type='table' AND name='$table'"; |
| | | $query = $db->queryOne($query); |
| | | if (PEAR::isError($query)) { |
| | | return $query; |
| | | } |
| | | if (PEAR::isError($columns = $this->_getTableColumns($query))) { |
| | | return $columns; |
| | | } |
| | | foreach ($columns as $column) { |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) { |
| | | $column['name'] = strtolower($column['name']); |
| | | } else { |
| | | $column = array_change_key_case($column, CASE_LOWER); |
| | | } |
| | | if ($field_name == $column['name']) { |
| | | list($types, $length) = $db->datatype->mapNativeDatatype($column); |
| | | unset($notnull); |
| | | if (isset($column['null']) && $column['null'] != 'YES') { |
| | | $notnull = true; |
| | | } |
| | | unset($default); |
| | | if (isset($column['default'])) { |
| | | $default = $column['default']; |
| | | } |
| | | $definition = array(); |
| | | foreach ($types as $key => $type) { |
| | | $definition[0][$key] = array('type' => $type); |
| | | if (isset($notnull)) { |
| | | $definition[0][$key]['notnull'] = true; |
| | | } |
| | | if (isset($default)) { |
| | | $definition[0][$key]['default'] = $default; |
| | | } |
| | | if (isset($length)) { |
| | | $definition[0][$key]['length'] = $length; |
| | | } |
| | | } |
| | | // todo .. handle auto_inrement and primary keys |
| | | return $definition; |
| | | } |
| | | } |
| | | |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableFieldDefinition: it was not specified an existing table column'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getTableIndexDefinition() |
| | | |
| | | /** |
| | | * get the stucture of an index into an array |
| | | * |
| | | * @param string $table 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, $index_name) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | if ($index_name == 'PRIMARY') { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableIndexDefinition: PRIMARY is an hidden index'); |
| | | } |
| | | $query = "SELECT sql FROM sqlite_master WHERE type='index' AND name='$index_name' AND tbl_name='$table' AND sql NOT NULL ORDER BY name"; |
| | | $result = $db->query($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $columns = $result->getColumnNames(); |
| | | $column = 'sql'; |
| | | if (!isset($columns[$column])) { |
| | | $result->free(); |
| | | return $db->raiseError('getTableIndexDefinition: show index does not return the table creation sql'); |
| | | } |
| | | |
| | | $query = strtolower($result->fetchOne()); |
| | | $unique = strstr($query, ' unique '); |
| | | $key_name = $index_name; |
| | | $start_pos = strpos($query, '('); |
| | | $end_pos = strrpos($query, ')'); |
| | | $column_names = substr($query, $start_pos+1, $end_pos-$start_pos-1); |
| | | $column_names = split(',', $column_names); |
| | | |
| | | $definition = array(); |
| | | if ($unique) { |
| | | $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(); |
| | | if (!empty($collation)) { |
| | | $definition['fields'][$column_name]['sorting'] = ($collation=='ASC' ? 'ascending' : 'descending'); |
| | | } |
| | | } |
| | | |
| | | $result->free(); |
| | | if (!isset($definition['fields'])) { |
| | | return $db->raiseError(MDB2_ERROR, null, null, |
| | | 'getTableIndexDefinition: it was not specified an existing table index'); |
| | | } |
| | | return $definition; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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_common::tableInfo() |
| | | * @since Method available since Release 1.7.0 |
| | | */ |
| | | function tableInfo($result, $mode = null) |
| | | { |
| | | $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; |
| | | if (is_string($result)) { |
| | | /* |
| | | * Probably received a table name. |
| | | * Create a result resource identifier. |
| | | */ |
| | | $id = $db->queryAll("PRAGMA table_info('$result');", null, MDB2_FETCHMODE_ASSOC); |
| | | $got_string = true; |
| | | } else { |
| | | return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null, |
| | | 'This DBMS can not obtain tableInfo' . |
| | | ' from result sets'); |
| | | } |
| | | |
| | | if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) { |
| | | $case_func = 'strtolower'; |
| | | } else { |
| | | $case_func = 'strval'; |
| | | } |
| | | |
| | | $count = count($id); |
| | | $res = array(); |
| | | |
| | | if ($mode) { |
| | | $res['num_fields'] = $count; |
| | | } |
| | | |
| | | for ($i = 0; $i < $count; $i++) { |
| | | if (strpos($id[$i]['type'], '(') !== false) { |
| | | $bits = explode('(', $id[$i]['type']); |
| | | $type = $bits[0]; |
| | | $len = rtrim($bits[1],')'); |
| | | } else { |
| | | $type = $id[$i]['type']; |
| | | $len = 0; |
| | | } |
| | | |
| | | $flags = ''; |
| | | if ($id[$i]['pk']) { |
| | | $flags .= 'primary_key '; |
| | | } |
| | | if ($id[$i]['notnull']) { |
| | | $flags .= 'not_null '; |
| | | } |
| | | if ($id[$i]['dflt_value'] !== null) { |
| | | $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); |
| | | } |
| | | $flags = trim($flags); |
| | | |
| | | $res[$i] = array( |
| | | 'table' => $case_func($result), |
| | | 'name' => $case_func($id[$i]['name']), |
| | | 'type' => $type, |
| | | 'len' => $len, |
| | | 'flags' => $flags, |
| | | ); |
| | | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 FrontBase driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | * @author Frank M. Kromann <frank@kromann.info> |
| | | */ |
| | | class MDB2_Driver_fbsql extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "'"; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'fbsql'; |
| | | $this->dbsyntax = 'fbsql'; |
| | | |
| | | $this->supported['sequences'] = 'emulated'; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = true; |
| | | $this->supported['transactions'] = true; |
| | | $this->supported['summary_functions'] = true; |
| | | $this->supported['order_by_text'] = true; |
| | | $this->supported['current_id'] = 'emulated'; |
| | | $this->supported['limit_queries'] = 'emulated'; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] ='emulated'; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = false; // not implemented |
| | | $this->supported['primary_key'] = false; // not implemented |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 = @fbsql_errno($this->connection); |
| | | $native_msg = @fbsql_error($this->connection); |
| | | } else { |
| | | $native_code = @fbsql_errno(); |
| | | $native_msg = @fbsql_error(); |
| | | } |
| | | if (is_null($error)) { |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | 22 => MDB2_ERROR_SYNTAX, |
| | | 85 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 108 => MDB2_ERROR_SYNTAX, |
| | | 116 => MDB2_ERROR_NOSUCHTABLE, |
| | | 124 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | 215 => MDB2_ERROR_NOSUCHFIELD, |
| | | 217 => MDB2_ERROR_INVALID_NUMBER, |
| | | 226 => MDB2_ERROR_NOSUCHFIELD, |
| | | 231 => MDB2_ERROR_INVALID, |
| | | 239 => MDB2_ERROR_TRUNCATED, |
| | | 251 => MDB2_ERROR_SYNTAX, |
| | | 266 => MDB2_ERROR_NOT_FOUND, |
| | | 357 => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | 358 => MDB2_ERROR_CONSTRAINT, |
| | | 360 => MDB2_ERROR_CONSTRAINT, |
| | | 361 => MDB2_ERROR_CONSTRAINT, |
| | | ); |
| | | } |
| | | if (isset($ecode_map[$native_code])) { |
| | | $error = $ecode_map[$native_code]; |
| | | } |
| | | } |
| | | return array($error, $native_code, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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('SET COMMIT FALSE;', 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. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto commited'); |
| | | } |
| | | $result = $this->_doQuery('COMMIT;', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET COMMIT TRUE;', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $result = $this->_doQuery('ROLLBACK;', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET COMMIT TRUE;', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return true on success, MDB2 Error Object on failure |
| | | **/ |
| | | function connect() |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 |
| | | && $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, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | $params = array( |
| | | $this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost', |
| | | $this->dsn['username'] ? $this->dsn['username'] : null, |
| | | $this->dsn['password'] ? $this->dsn['password'] : null, |
| | | ); |
| | | |
| | | $connect_function = $this->options['persistent'] ? 'fbsql_pconnect' : 'fbsql_connect'; |
| | | |
| | | @ini_set('track_errors', true); |
| | | $php_errormsg = ''; |
| | | $connection = @call_user_func_array($connect_function, $params); |
| | | @ini_restore('track_errors'); |
| | | if ($connection <= 0) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); |
| | | } |
| | | |
| | | $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; |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | @fbsql_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | if (is_null($database_name)) { |
| | | $database_name = $this->database_name; |
| | | } |
| | | |
| | | if ($database_name) { |
| | | if ($database_name != $this->connected_database_name) { |
| | | if (!@fbsql_select_db($database_name, $connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->connected_database_name = $database_name; |
| | | } |
| | | } |
| | | |
| | | $result = @fbsql_query($query, $connection); |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @fbsql_affected_rows($connection); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $limit, $offset) |
| | | { |
| | | if ($limit > 0) { |
| | | if ($isManip) { |
| | | return preg_replace('/^([\s(])*SELECT(?!\s*TOP\s*\()/i', |
| | | "\\1SELECT TOP($limit)", $query); |
| | | } else { |
| | | return preg_replace('/([\s(])*SELECT(?!\s*TOP\s*\()/i', |
| | | "\\1SELECT TOP($offset,$limit)", $query); |
| | | } |
| | | } |
| | | // Add ; to the end of the query. This is required by FrontBase |
| | | return $query.';'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (NULL);"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->_doQuery($query, true); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence '.$seq_name.' could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | return 1; |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | $value = $this->queryOne("SELECT UNIQUE FROM $sequence_name", 'integer'); |
| | | if (is_numeric($value)) { |
| | | $query = "DELETE FROM $sequence_name WHERE ".$this->options['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 |
| | | * |
| | | * @param mixed $id value as returned by getBeforeId() |
| | | * @param string $table name of the table into which a new row was inserted |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function lastInsertID($table = null, $field = null) |
| | | { |
| | | $value = @fbsql_insert_id($this->connection); |
| | | if (!$value) { |
| | | return $this->raiseError(); |
| | | } |
| | | 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->getSequenceName($seq_name); |
| | | $query = "SELECT MAX(".$this->options['seqcol_name'].") FROM $sequence_name"; |
| | | return $this->queryOne($query, 'integer'); |
| | | } |
| | | } |
| | | |
| | | class MDB2_Result_fbsql 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 = @fbsql_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 = @fbsql_fetch_row($this->result); |
| | | } |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _getColumnNames() |
| | | { |
| | | $columns = array(); |
| | | $numcols = $this->numCols(); |
| | | if (PEAR::isError($numcols)) { |
| | | return $numcols; |
| | | } |
| | | for ($column = 0; $column < $numcols; $column++) { |
| | | $column_name = @fbsql_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 = @fbsql_num_fields($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextResult() |
| | | |
| | | /** |
| | | * Move the internal result pointer to the next available result |
| | | * Currently not supported |
| | | * |
| | | * @return true if a result is available otherwise return false |
| | | * @access public |
| | | */ |
| | | function nextResult() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'nextResult: resultset has already been freed'); |
| | | } |
| | | return @fbsql_next_result($this->result); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with result. |
| | | * |
| | | * @return boolean true on success, false if result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $free = @fbsql_free_result($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_fbsql extends MDB2_Result_fbsql |
| | | { |
| | | // }}} |
| | | // {{{ 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) && !@fbsql_data_seek($this->result, $rownum)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $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 = @fbsql_num_rows($this->result); |
| | | if (is_null($rows)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_fbsql extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lorenzo Alberton <l.alberton@quipo.it> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | /** |
| | | * MDB2 FireBird/InterBase driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lorenzo Alberton <l.alberton@quipo.it> |
| | | */ |
| | | class MDB2_Driver_ibase extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "'"; |
| | | |
| | | var $transaction_id = 0; |
| | | |
| | | var $query_parameters = array(); |
| | | var $query_parameter_values = array(); |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'ibase'; |
| | | $this->dbsyntax = 'ibase'; |
| | | |
| | | $this->supported['sequences'] = true; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = function_exists('ibase_affected_rows'); |
| | | $this->supported['summary_functions'] = true; |
| | | $this->supported['order_by_text'] = true; |
| | | $this->supported['transactions'] = true; |
| | | $this->supported['current_id'] = true; |
| | | // maybe this needs different handling for ibase and firebird? |
| | | $this->supported['limit_queries'] = 'emulated'; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = false; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = true; |
| | | $this->supported['primary_key'] = true; |
| | | |
| | | $this->options['database_path'] = ''; |
| | | $this->options['database_extension'] = '.gdb'; |
| | | $this->options['default_text_field_length'] = 4096; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ errorInfo() |
| | | |
| | | /** |
| | | * This method is used to collect information about an error |
| | | * |
| | | * @param integer $error |
| | | * @return array |
| | | * @access public |
| | | */ |
| | | function errorInfo($error = null) |
| | | { |
| | | $native_msg = @ibase_errmsg(); |
| | | |
| | | if (function_exists('ibase_errcode')) { |
| | | $native_code = @ibase_errcode(); |
| | | } else { |
| | | // memo for the interbase php module hackers: we need something similar |
| | | // to mysql_errno() to retrieve error codes instead of this ugly hack |
| | | if (preg_match('/^([^0-9\-]+)([0-9\-]+)\s+(.*)$/', $native_msg, $m)) { |
| | | $native_code = (int)$m[2]; |
| | | } else { |
| | | $native_code = null; |
| | | } |
| | | } |
| | | if (is_null($error)) { |
| | | $error = MDB2_ERROR; |
| | | if ($native_code) { |
| | | // try to interpret Interbase error code (that's why we need ibase_errno() |
| | | // in the interbase module to return the real error code) |
| | | switch ($native_code) { |
| | | case -204: |
| | | if (isset($m[3]) && is_int(strpos($m[3], 'Table unknown'))) { |
| | | $errno = MDB2_ERROR_NOSUCHTABLE; |
| | | } |
| | | break; |
| | | default: |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | -104 => MDB2_ERROR_SYNTAX, |
| | | -150 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | -151 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | -155 => MDB2_ERROR_NOSUCHTABLE, |
| | | -157 => MDB2_ERROR_NOSUCHFIELD, |
| | | -158 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | -170 => MDB2_ERROR_MISMATCH, |
| | | -171 => MDB2_ERROR_MISMATCH, |
| | | -172 => MDB2_ERROR_INVALID, |
| | | // -204 => // Covers too many errors, need to use regex on msg |
| | | -205 => MDB2_ERROR_NOSUCHFIELD, |
| | | -206 => MDB2_ERROR_NOSUCHFIELD, |
| | | -208 => MDB2_ERROR_INVALID, |
| | | -219 => MDB2_ERROR_NOSUCHTABLE, |
| | | -297 => MDB2_ERROR_CONSTRAINT, |
| | | -303 => MDB2_ERROR_INVALID, |
| | | -413 => MDB2_ERROR_INVALID_NUMBER, |
| | | -530 => MDB2_ERROR_CONSTRAINT, |
| | | -551 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | -552 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | // -607 => // Covers too many errors, need to use regex on msg |
| | | -625 => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | -803 => MDB2_ERROR_CONSTRAINT, |
| | | -804 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | -904 => MDB2_ERROR_CONNECT_FAILED, |
| | | -922 => MDB2_ERROR_NOSUCHDB, |
| | | -923 => MDB2_ERROR_CONNECT_FAILED, |
| | | -924 => MDB2_ERROR_CONNECT_FAILED |
| | | ); |
| | | } |
| | | if (isset($ecode_map[$native_code])) { |
| | | $error = $ecode_map[$native_code]; |
| | | } |
| | | break; |
| | | } |
| | | } else { |
| | | static $error_regexps; |
| | | if (!isset($error_regexps)) { |
| | | $error_regexps = array( |
| | | '/generator .* is not defined/' |
| | | => MDB2_ERROR_SYNTAX, // for compat. w ibase_errcode() |
| | | '/table.*(not exist|not found|unknown)/i' |
| | | => MDB2_ERROR_NOSUCHTABLE, |
| | | '/table .* already exists/i' |
| | | => MDB2_ERROR_ALREADY_EXISTS, |
| | | '/unsuccessful metadata update .* failed attempt to store duplicate value/i' |
| | | => MDB2_ERROR_ALREADY_EXISTS, |
| | | '/unsuccessful metadata update .* not found/i' |
| | | => MDB2_ERROR_NOT_FOUND, |
| | | '/validation error for column .* value "\*\*\* null/i' |
| | | => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | '/violation of [\w ]+ constraint/i' |
| | | => MDB2_ERROR_CONSTRAINT, |
| | | '/conversion error from string/i' |
| | | => MDB2_ERROR_INVALID_NUMBER, |
| | | '/no permission for/i' |
| | | => MDB2_ERROR_ACCESS_VIOLATION, |
| | | '/arithmetic exception, numeric overflow, or string truncation/i' |
| | | => MDB2_ERROR_INVALID, |
| | | ); |
| | | } |
| | | foreach ($error_regexps as $regexp => $code) { |
| | | if (preg_match($regexp, $native_msg, $m)) { |
| | | $error = $code; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return array($error, $native_code, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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 = ibase_trans(); |
| | | if (!$result) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'beginTransaction: could not start a transaction'); |
| | | } |
| | | $this->transaction_id = $result; |
| | | $this->in_transaction = true; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ commit() |
| | | |
| | | /** |
| | | * Commit the database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | if (!ibase_commit($this->transaction_id)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: could not commit a transaction'); |
| | | } |
| | | $this->in_transaction = false; |
| | | //$this->transaction_id = 0; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | if ($this->transaction_id && !ibase_rollback($this->transaction_id)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: Could not rollback a pending transaction: '.ibase_errmsg()); |
| | | } |
| | | $this->in_transaction = false; |
| | | $this->transaction_id = 0; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getDatabaseFile() |
| | | |
| | | /** |
| | | * Builds the string with path+dbname+extension |
| | | * |
| | | * @return string full database path+file |
| | | * @access protected |
| | | */ |
| | | function _getDatabaseFile($database_name) |
| | | { |
| | | if ($database_name == '') { |
| | | return $database_name; |
| | | } |
| | | return $this->options['database_path'].$database_name.$this->options['database_extension']; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doConnect() |
| | | |
| | | /** |
| | | * Does the grunt work of connecting to the database |
| | | * |
| | | * @return mixed connection resource on success, MDB2 Error Object on failure |
| | | * @access protected |
| | | */ |
| | | function _doConnect($database_name, $persistent = false) |
| | | { |
| | | $user = $this->dsn['username']; |
| | | $pw = $this->dsn['password']; |
| | | $dbhost = $this->dsn['hostspec'] ? |
| | | ($this->dsn['hostspec'].':'.$database_name) : $database_name; |
| | | |
| | | $params = array(); |
| | | $params[] = $dbhost; |
| | | $params[] = !empty($user) ? $user : null; |
| | | $params[] = !empty($pw) ? $pw : null; |
| | | $params[] = isset($this->dsn['charset']) ? $this->dsn['charset'] : null; |
| | | $params[] = isset($this->dsn['buffers']) ? $this->dsn['buffers'] : null; |
| | | $params[] = isset($this->dsn['dialect']) ? $this->dsn['dialect'] : null; |
| | | $params[] = isset($this->dsn['role']) ? $this->dsn['role'] : null; |
| | | |
| | | $connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect'; |
| | | |
| | | $connection = @call_user_func_array($connect_function, $params); |
| | | if ($connection <= 0) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); |
| | | } |
| | | if (function_exists('ibase_timefmt')) { |
| | | @ibase_timefmt("%Y-%m-%d %H:%M:%S", IBASE_TIMESTAMP); |
| | | @ibase_timefmt("%Y-%m-%d", IBASE_DATE); |
| | | } else { |
| | | @ini_set("ibase.timestampformat", "%Y-%m-%d %H:%M:%S"); |
| | | //@ini_set("ibase.timeformat", "%H:%M:%S"); |
| | | @ini_set("ibase.dateformat", "%Y-%m-%d"); |
| | | } |
| | | |
| | | return $connection; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return true on success, MDB2 Error Object on failure |
| | | * @access public |
| | | */ |
| | | function connect() |
| | | { |
| | | $database_file = $this->_getDatabaseFile($this->database_name); |
| | | if (is_resource($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 |
| | | && $this->connected_database_name == $database_file |
| | | && $this->opened_persistent == $this->options['persistent'] |
| | | ) { |
| | | return MDB2_OK; |
| | | } |
| | | $this->disconnect(false); |
| | | } |
| | | |
| | | if (!PEAR::loadExtension('interbase')) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | if (!empty($this->database_name)) { |
| | | $connection = $this->_doConnect($database_file, $this->options['persistent']); |
| | | if (PEAR::isError($connection)) { |
| | | return $connection; |
| | | } |
| | | $this->connection =& $connection; |
| | | $this->connected_dsn = $this->dsn; |
| | | $this->connected_database_name = $database_file; |
| | | $this->opened_persistent = $this->options['persistent']; |
| | | $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | @ibase_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | if ($this->in_transaction) { |
| | | $connection = $this->transaction_id; |
| | | } else { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | } |
| | | $result = ibase_query($connection, $query); |
| | | |
| | | if ($result === false) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | //return $result; |
| | | return (function_exists('ibase_affected_rows') ? ibase_affected_rows($connection) : 0); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $limit, $offset) |
| | | { |
| | | if ($limit > 0 && $this->dsn['dbsyntax'] == 'firebird') { |
| | | $query = preg_replace('/^([\s(])*SELECT(?!\s*FIRST\s*\d+)/i', |
| | | "SELECT FIRST $limit SKIP $offset", $query); |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 :[a-zA-Z] and are placeholders which can be set using |
| | | * bindParam() and the query can be send off using the execute() method. |
| | | * |
| | | * @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 |
| | | * @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) |
| | | { |
| | | $this->debug($query, 'prepare'); |
| | | $placeholder_type_guess = $placeholder_type = null; |
| | | $question = '?'; |
| | | $colon = ':'; |
| | | $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]; |
| | | } |
| | | if (is_int($quote = strpos($query, "'", $position)) && $quote < $p_position) { |
| | | if (!is_int($end_quote = strpos($query, "'", $quote + 1))) { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: query with an unterminated text string specified'); |
| | | return $err; |
| | | } |
| | | switch ($this->escape_quotes) { |
| | | case '': |
| | | case "'": |
| | | $position = $end_quote + 1; |
| | | break; |
| | | default: |
| | | if ($end_quote == $quote + 1) { |
| | | $position = $end_quote + 1; |
| | | } else { |
| | | if ($query[$end_quote-1] == $this->escape_quotes) { |
| | | $position = $end_quote; |
| | | } else { |
| | | $position = $end_quote + 1; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } elseif ($query[$position] == $placeholder_type_guess) { |
| | | if ($placeholder_type_guess == '?') { |
| | | break; |
| | | } |
| | | if (is_null($placeholder_type)) { |
| | | $placeholder_type = $query[$p_position]; |
| | | $question = $colon = $placeholder_type; |
| | | } |
| | | $name = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); |
| | | if ($name === '') { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: named parameter with an empty name'); |
| | | return $err; |
| | | } |
| | | $query = substr_replace($query, '?', $position, strlen($name)+1); |
| | | $position = $p_position + 1; |
| | | } else { |
| | | $position = $p_position; |
| | | } |
| | | } |
| | | $connection = ($this->in_transaction ? $this->transaction_id : $this->connection); |
| | | $statement = ibase_prepare($connection, $query); |
| | | |
| | | $class_name = 'MDB2_Statement_'.$this->phptype; |
| | | $obj =& new $class_name($this, $statement, $query, $types, $result_types, $this->row_limit, $this->row_offset); |
| | | return $obj; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = 'SELECT GEN_ID('.strtoupper($sequence_name).', 1) as the_value FROM RDB$DATABASE'; |
| | | $this->expectError('*'); |
| | | $result = $this->queryOne($query, 'integer'); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | // return 1; |
| | | // BUT generators are not always reset, so return the actual value |
| | | return $this->currID($seq_name); |
| | | } |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | $query = 'SELECT GEN_ID('.strtoupper($sequence_name).', 0) as the_value FROM RDB$DATABASE'; |
| | | $value = @$this->queryOne($query); |
| | | if (PEAR::isError($value)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'currID: Unable to select from ' . $seq_name) ; |
| | | } |
| | | if (!is_numeric($value)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'currID: could not find value in sequence table'); |
| | | } |
| | | return $value; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | class MDB2_Result_ibase extends MDB2_Result_Common |
| | | { |
| | | // {{{ _skipLimitOffset() |
| | | |
| | | /** |
| | | * Skip the first row of a result set. |
| | | * |
| | | * @param resource $result |
| | | * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _skipLimitOffset() |
| | | { |
| | | if ($this->db->dsn['dbsyntax'] == 'firebird') { |
| | | return true; |
| | | } |
| | | if ($this->limit) { |
| | | if ($this->rownum > $this->limit) { |
| | | return false; |
| | | } |
| | | } |
| | | if ($this->offset) { |
| | | while ($this->offset_count < $this->offset) { |
| | | ++$this->offset_count; |
| | | if (!is_array(@ibase_fetch_row($this->result))) { |
| | | $this->offset_count = $this->offset; |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 ($this->result === true) { |
| | | //query successfully executed, but without results... |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if (!$this->_skipLimitOffset()) { |
| | | $null = null; |
| | | return $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 = @ibase_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 = @ibase_fetch_row($this->result); |
| | | } |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if (($mode = ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) |
| | | + ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) |
| | | ) { |
| | | $this->db->_fixResultArrayValues($row, $mode); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 associative array variable |
| | | * that holds the names of columns. The indexes of the array are |
| | | * the column names mapped to lower case and the values are the |
| | | * respective numbers of the columns starting from 0. 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_info = @ibase_field_info($this->result, $column); |
| | | $columns[$column_info['alias']] = $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() |
| | | { |
| | | if ($this->result === true) { |
| | | //query successfully executed, but without results... |
| | | return 0; |
| | | } |
| | | |
| | | if (!is_resource($this->result)) { |
| | | return $this->db->raiseError('numCols(): not a valid ibase resource'); |
| | | } |
| | | $cols = @ibase_num_fields($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | 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)) { |
| | | $free = @ibase_free_result($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | class MDB2_BufferedResult_ibase extends MDB2_Result_ibase |
| | | { |
| | | // {{{ class vars |
| | | |
| | | var $buffer; |
| | | var $buffer_rownum = - 1; |
| | | |
| | | // }}} |
| | | // {{{ _fillBuffer() |
| | | |
| | | /** |
| | | * Fill the row buffer |
| | | * |
| | | * @param int $rownum row number upto which the buffer should be filled |
| | | * if the row number is null all rows are ready into the buffer |
| | | * @return boolean true on success, false on failure |
| | | * @access protected |
| | | */ |
| | | function _fillBuffer($rownum = null) |
| | | { |
| | | if (isset($this->buffer) && is_array($this->buffer)) { |
| | | if (is_null($rownum)) { |
| | | if (!end($this->buffer)) { |
| | | return false; |
| | | } |
| | | } elseif (isset($this->buffer[$rownum])) { |
| | | return (bool) $this->buffer[$rownum]; |
| | | } |
| | | } |
| | | |
| | | if (!$this->_skipLimitOffset()) { |
| | | return false; |
| | | } |
| | | |
| | | $buffer = true; |
| | | while ((is_null($rownum) || $this->buffer_rownum < $rownum) |
| | | && (!$this->limit || $this->buffer_rownum < $this->limit) |
| | | && ($buffer = @ibase_fetch_row($this->result)) |
| | | ) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = $buffer; |
| | | } |
| | | |
| | | if (!$buffer) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = false; |
| | | return false; |
| | | } elseif ($this->limit && $this->buffer_rownum >= $this->limit) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 ($this->result === true) { |
| | | //query successfully executed, but without results... |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | if (!is_null($rownum)) { |
| | | $seek = $this->seek($rownum); |
| | | if (PEAR::isError($seek)) { |
| | | return $seek; |
| | | } |
| | | } |
| | | $target_rownum = $this->rownum + 1; |
| | | if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { |
| | | $fetchmode = $this->db->fetchmode; |
| | | } |
| | | if (!$this->_fillBuffer($target_rownum)) { |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | $row = $this->buffer[$target_rownum]; |
| | | if ($fetchmode & MDB2_FETCHMODE_ASSOC) { |
| | | $column_names = $this->getColumnNames(); |
| | | foreach ($column_names as $name => $i) { |
| | | $column_names[$name] = $row[$i]; |
| | | } |
| | | $row = $column_names; |
| | | } |
| | | if (($mode = ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) |
| | | + ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) |
| | | ) { |
| | | $this->db->_fixResultArrayValues($row, $mode); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | $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() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'valid: resultset has already been freed'); |
| | | } |
| | | if ($this->_fillBuffer($this->rownum + 1)) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ numRows() |
| | | |
| | | /** |
| | | * returns the number of rows in a result object |
| | | * |
| | | * @return mixed MDB2 Error Object or the number of rows |
| | | * @access public |
| | | */ |
| | | function numRows() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | $this->_fillBuffer(); |
| | | return $this->buffer_rownum; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with $result. |
| | | * |
| | | * @return boolean true on success, false if $result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $this->buffer = null; |
| | | $this->buffer_rownum = null; |
| | | $free = parent::free(); |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | class MDB2_Statement_ibase 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 a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function &_execute($result_class = true, $result_wrap_class = false) |
| | | { |
| | | $isManip = MDB2::isManip($this->query); |
| | | $this->db->last_query = $this->query; |
| | | $this->db->debug($this->query, 'execute'); |
| | | if ($this->db->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | $return = 0; |
| | | return $return; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | |
| | | $connected = $this->db->connect(); |
| | | if (PEAR::isError($connected)) { |
| | | return $connected; |
| | | } |
| | | $connection = $this->db->in_transaction |
| | | ? $this->db->transaction_id : $this->db->connection; |
| | | |
| | | $parameters = array(0 => $this->statement); |
| | | $i = 0; |
| | | foreach ($this->values as $parameter => $value) { |
| | | $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; |
| | | $parameters[] = $this->db->quote($value, $type, false); |
| | | ++$i; |
| | | } |
| | | |
| | | $result = call_user_func_array('ibase_execute', $parameters); |
| | | if ($result === false) { |
| | | $err =& $this->db->raiseError(); |
| | | return $err; |
| | | } |
| | | |
| | | if ($isManip) { |
| | | $affected_rows = (function_exists('ibase_affected_rows') ? ibase_affected_rows($connection) : 0); |
| | | return $affected_rows; |
| | | } |
| | | |
| | | $result =& $this->db->_wrapResult($result, $this->types, |
| | | $result_class, $result_wrap_class, $this->row_limit, $this->row_offset); |
| | | 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 (!@ibase_free_query($this->statement)) { |
| | | return $this->db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | |
| | | // | 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: Frank M. Kromann <frank@kromann.info> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | // {{{ Class MDB2_Driver_mssql |
| | | /** |
| | | * MDB2 MSSQL Server driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Frank M. Kromann <frank@kromann.info> |
| | | */ |
| | | class MDB2_Driver_mssql extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "'"; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'mssql'; |
| | | $this->dbsyntax = 'mssql'; |
| | | |
| | | $this->supported['sequences'] = 'emulated'; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = true; |
| | | $this->supported['transactions'] = true; |
| | | $this->supported['summary_functions'] = true; |
| | | $this->supported['order_by_text'] = true; |
| | | $this->supported['current_id'] = 'emulated'; |
| | | $this->supported['limit_queries'] = 'emulated'; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = 'emulated'; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = true; |
| | | $this->supported['primary_key'] = true; |
| | | |
| | | $this->options['database_device'] = false; |
| | | $this->options['database_size'] = false; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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) { |
| | | $result = @mssql_query('select @@ERROR as ErrorCode', $this->connection); |
| | | if ($result) { |
| | | $native_code = @mssql_result($result, 0, 0); |
| | | @mssql_free_result($result); |
| | | } |
| | | } |
| | | $native_msg = @mssql_get_last_message(); |
| | | if (is_null($error)) { |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | 110 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | 155 => MDB2_ERROR_NOSUCHFIELD, |
| | | 170 => MDB2_ERROR_SYNTAX, |
| | | 207 => MDB2_ERROR_NOSUCHFIELD, |
| | | 208 => MDB2_ERROR_NOSUCHTABLE, |
| | | 245 => MDB2_ERROR_INVALID_NUMBER, |
| | | 515 => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | 547 => MDB2_ERROR_CONSTRAINT, |
| | | 1913 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 2627 => MDB2_ERROR_CONSTRAINT, |
| | | 2714 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 3701 => MDB2_ERROR_NOSUCHTABLE, |
| | | 8134 => MDB2_ERROR_DIVZERO, |
| | | ); |
| | | } |
| | | if (isset($ecode_map[$native_code])) { |
| | | if ($native_code == 3701 |
| | | && preg_match('/Cannot drop the index/i', $native_msg) |
| | | ) { |
| | | $error = MDB2_ERROR_NOT_FOUND; |
| | | } else { |
| | | $error = $ecode_map[$native_code]; |
| | | } |
| | | } |
| | | } |
| | | return array($error, $native_code, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ quoteIdentifier() |
| | | |
| | | /** |
| | | * Quote a string so it can be safely used as a table / column name |
| | | * |
| | | * Quoting style depends on which database driver is being used. |
| | | * |
| | | * @param string $str identifier name to be quoted |
| | | * |
| | | * @return string quoted identifier string |
| | | * |
| | | * @since 1.6.0 |
| | | * @access public |
| | | */ |
| | | function quoteIdentifier($str) |
| | | { |
| | | return '[' . str_replace(']', ']]', $str) . ']'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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 TRANSACTION', 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. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | $result = $this->_doQuery('COMMIT TRANSACTION', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $result = $this->_doQuery('ROLLBACK TRANSACTION', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return true on success, MDB2 Error Object on failure |
| | | */ |
| | | function connect() |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 |
| | | && $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, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | $params = array( |
| | | $this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost', |
| | | $this->dsn['username'] ? $this->dsn['username'] : null, |
| | | $this->dsn['password'] ? $this->dsn['password'] : null, |
| | | ); |
| | | if ($this->dsn['port']) { |
| | | $params[0].= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':') |
| | | . $this->dsn['port']; |
| | | } |
| | | |
| | | $connect_function = $this->options['persistent'] ? 'mssql_pconnect' : 'mssql_connect'; |
| | | |
| | | $connection = @call_user_func_array($connect_function, $params); |
| | | if ($connection <= 0) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); |
| | | } |
| | | |
| | | $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 ((bool) ini_get('mssql.datetimeconvert')) { |
| | | ini_set('mssql.datetimeconvert', '0'); |
| | | } |
| | | @mssql_query('SET DATEFORMAT ymd', $this->connection); |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | @mssql_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | if (is_null($database_name)) { |
| | | $database_name = $this->database_name; |
| | | } |
| | | |
| | | if ($database_name) { |
| | | if ($database_name != $this->connected_database_name) { |
| | | if (!@mssql_select_db($database_name, $connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->connected_database_name = $database_name; |
| | | } |
| | | } |
| | | |
| | | $result = @mssql_query($query, $connection); |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @mssql_rows_affected($connection); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $limit, $offset) |
| | | { |
| | | if ($limit > 0) { |
| | | $fetch = $offset + $limit; |
| | | if (!$isManip) { |
| | | return preg_replace('/^([\s(])*SELECT(?!\s*TOP\s*\()/i', |
| | | "\\1SELECT TOP $fetch", $query); |
| | | } |
| | | } |
| | | return $query; |
| | | } |
| | | // }}} |
| | | // {{{ _checkSequence |
| | | /** |
| | | * Checks if there's a sequence that exists. |
| | | * |
| | | * @param string $seq_name The sequence name to verify. |
| | | * @return bool $tableExists The value if the table exists or not |
| | | * @access private |
| | | */ |
| | | function _checkSequence($seq_name) |
| | | { |
| | | $query = "SELECT * FROM $seq_name"; |
| | | $tableExists = $this->_doQuery($query, true); |
| | | if (PEAR::isError($tableExists)) { |
| | | if ($tableExists->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | return 0; |
| | | } |
| | | } else { |
| | | return 1; |
| | | } |
| | | } |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | if (!$this->_checkSequence($sequence_name)) { |
| | | $query = "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (0)"; |
| | | } else { |
| | | $query = "SET IDENTITY_INSERT $sequence_name ON ". |
| | | "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (0)"; |
| | | } |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->_doQuery($query, true); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && !$this->_checkSequence($sequence_name)) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence '.$seq_name.' could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | return 1; |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // TODO: Make sure that this works. |
| | | $value = $this->queryRow("SELECT @@IDENTITY", 'integer'); |
| | | if (is_numeric($value)) { |
| | | $query = "DELETE FROM $sequence_name WHERE ". |
| | | $this->options['seqcol_name']." < $value"; |
| | | $result = $this->_doQuery($query, true); |
| | | |
| | | if (PEAR::isError($result)) { |
| | | $this->warnings[] = 'nextID: could not delete previous sequence table values'; |
| | | } |
| | | } |
| | | return $value; |
| | | } |
| | | // }}} |
| | | // {{{ lastInsertID() |
| | | /** |
| | | * returns the autoincrement ID if supported or $id |
| | | * |
| | | * @param mixed $id value as returned by getBeforeId() |
| | | * @param string $table name of the table into which a new row was inserted |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function lastInsertID($table = null, $field = null) |
| | | { |
| | | return $this->queryOne("SELECT @@IDENTITY FROM $table", 'integer'); |
| | | } |
| | | // }}} |
| | | } |
| | | // }}} |
| | | // {{{ Class MDB2_Result_mssql |
| | | |
| | | class MDB2_Result_mssql extends MDB2_Result_Common |
| | | { |
| | | // {{{ _skipLimitOffset() |
| | | |
| | | /** |
| | | * Skip the first row of a result set. |
| | | * |
| | | * @param resource $result |
| | | * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _skipLimitOffset() |
| | | { |
| | | if ($this->limit) { |
| | | if ($this->rownum >= $this->limit) { |
| | | return false; |
| | | } |
| | | } |
| | | if ($this->offset) { |
| | | while ($this->offset_count < $this->offset) { |
| | | ++$this->offset_count; |
| | | if (!is_array(@mysql_fetch_row($this->result))) { |
| | | $this->offset_count = $this->limit; |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 (!$this->_skipLimitOffset()) { |
| | | $null = null; |
| | | return $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 = @mssql_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 = @mssql_fetch_row($this->result); |
| | | } |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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. |
| | | * |
| | | * @param resource $result result identifier |
| | | * @return mixed an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _getColumnNames() |
| | | { |
| | | $columns = array(); |
| | | $numcols = $this->numCols(); |
| | | if (PEAR::isError($numcols)) { |
| | | return $numcols; |
| | | } |
| | | for ($column = 0; $column < $numcols; $column++) { |
| | | $column_name = @mssql_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 = @mssql_num_fields($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextResult() |
| | | |
| | | /** |
| | | * Move the internal result pointer to the next available result |
| | | * Currently not supported |
| | | * |
| | | * @return true if a result is available otherwise return false |
| | | * @access public |
| | | */ |
| | | function nextResult() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'nextResult: resultset has already been freed'); |
| | | } |
| | | return @mssql_next_result($this->result); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with $result. |
| | | * |
| | | * @return boolean true on success, false if $result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $free = @mssql_free_result($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_mssql extends MDB2_Result_mssql |
| | | { |
| | | // }}} |
| | | // {{{ 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) && !@mssql_data_seek($this->result, $rownum)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $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 = @mssql_num_rows($this->result); |
| | | if (is_null($rows)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | if ($this->limit) { |
| | | $rows -= $this->limit; |
| | | if ($rows < 0) { |
| | | $rows = 0; |
| | | } |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | // }}} |
| | | // {{{ MDB2_Statement_mssql |
| | | class MDB2_Statement_mssql extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 MySQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_mysqli extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "\\"; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'mysqli'; |
| | | $this->dbsyntax = 'mysqli'; |
| | | |
| | | $this->supported['sequences'] = 'emulated'; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = true; |
| | | $this->supported['transactions'] = 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'] = false; |
| | | $this->supported['auto_increment'] = true; |
| | | $this->supported['primary_key'] = true; |
| | | |
| | | $this->options['default_table_type'] = null; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 = @mysqli_errno($this->connection); |
| | | $native_msg = @mysqli_error($this->connection); |
| | | } else { |
| | | $native_code = @mysqli_errno(); |
| | | $native_msg = @mysqli_error(); |
| | | } |
| | | if (is_null($error)) { |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | 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, |
| | | 1022 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1044 => 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, |
| | | 1061 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1062 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1064 => MDB2_ERROR_SYNTAX, |
| | | 1091 => MDB2_ERROR_NOT_FOUND, |
| | | 1100 => MDB2_ERROR_NOT_LOCKED, |
| | | 1136 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | 1142 => MDB2_ERROR_ACCESS_VIOLATION, |
| | | 1146 => MDB2_ERROR_NOSUCHTABLE, |
| | | 1216 => MDB2_ERROR_CONSTRAINT, |
| | | 1217 => MDB2_ERROR_CONSTRAINT, |
| | | ); |
| | | } |
| | | 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 $text the input string to quote |
| | | * @return string quoted string |
| | | * @access public |
| | | */ |
| | | function escape($text) |
| | | { |
| | | return @mysqli_escape_string($this->connection, $text); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ quoteIdentifier() |
| | | |
| | | /** |
| | | * Quote a string so it can be safely used as a table or column name |
| | | * |
| | | * Quoting style depends on which database driver is being used. |
| | | * |
| | | * MySQL can't handle the backtick character (<kbd>`</kbd>) in |
| | | * table or column names. |
| | | * |
| | | * @param string $str identifier name to be quoted |
| | | * |
| | | * @return string quoted identifier string |
| | | * |
| | | * @access public |
| | | * @internal |
| | | */ |
| | | function quoteIdentifier($str) |
| | | { |
| | | return '`' . $str . '`'; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'beginTransaction: transactions are not in use'); |
| | | } |
| | | if ($this->in_transaction) { |
| | | return MDB2_OK; //nothing to do |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 0', 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. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'commit: transactions are not in use'); |
| | | } |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | $result = $this->_doQuery('COMMIT', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 1', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->supports('transactions')) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, |
| | | 'rollback: transactions are not in use'); |
| | | } |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $result = $this->_doQuery('ROLLBACK', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $result = $this->_doQuery('SET AUTOCOMMIT = 1', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return true on success, MDB2 Error Object on failure |
| | | */ |
| | | function connect() |
| | | { |
| | | if (is_object($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0) { |
| | | return MDB2_OK; |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | |
| | | if (!PEAR::loadExtension($this->phptype)) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | @ini_set('track_errors', true); |
| | | $php_errormsg = ''; |
| | | |
| | | if ($this->options['ssl'] === true) { |
| | | $init = @mysqli_init(); |
| | | @mysqli_ssl_set( |
| | | $init, |
| | | empty($this->dsn['key']) ? null : $this->dsn['key'], |
| | | empty($this->dsn['cert']) ? null : $this->dsn['cert'], |
| | | empty($this->dsn['ca']) ? null : $this->dsn['ca'], |
| | | empty($this->dsn['capath']) ? null : $this->dsn['capath'], |
| | | empty($this->dsn['cipher']) ? null : $this->dsn['cipher'] |
| | | ); |
| | | if ($connection = @mysqli_real_connect( |
| | | $init, |
| | | $this->dsn['hostspec'], |
| | | $this->dsn['username'], |
| | | $this->dsn['password'], |
| | | $this->database_name, |
| | | $this->dsn['port'], |
| | | $this->dsn['socket'])) |
| | | { |
| | | $connection = $init; |
| | | } |
| | | } else { |
| | | $connection = @mysqli_connect( |
| | | $this->dsn['hostspec'], |
| | | $this->dsn['username'], |
| | | $this->dsn['password'], |
| | | $this->database_name, |
| | | $this->dsn['port'], |
| | | $this->dsn['socket'] |
| | | ); |
| | | } |
| | | |
| | | @ini_restore('track_errors'); |
| | | |
| | | if (!$connection) { |
| | | if (($err = @mysqli_connect_error()) != '') { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, $err); |
| | | } else { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, $php_errormsg); |
| | | } |
| | | } |
| | | |
| | | $this->connection = $connection; |
| | | $this->connected_dsn = $this->dsn; |
| | | $this->connected_database_name = $this->database_name; |
| | | $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; |
| | | |
| | | $this->supported['transactions'] = false; |
| | | if ($this->options['default_table_type']) { |
| | | switch (strtoupper($this->options['default_table_type'])) { |
| | | case 'BERKELEYDB': |
| | | $this->options['default_table_type'] = 'BDB'; |
| | | case 'BDB': |
| | | case 'INNODB': |
| | | case 'GEMINI': |
| | | $this->supported['transactions'] = true; |
| | | break; |
| | | case 'HEAP': |
| | | case 'ISAM': |
| | | case 'MERGE': |
| | | case 'MRG_MYISAM': |
| | | case 'MYISAM': |
| | | break; |
| | | default: |
| | | $this->warnings[] = $default_table_type. |
| | | ' is not a supported default table type'; |
| | | } |
| | | } |
| | | |
| | | if ($this->options['use_transactions'] && !$this->supports('transactions')) { |
| | | $this->warnings[] = $this->options['default_table_type']. |
| | | ' is not a transaction-safe default table type; switched to INNODB'; |
| | | $this->options['default_table_type'] = 'INNODB'; |
| | | $this->supported['transactions'] = true; |
| | | } |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @return mixed true on success, false if not connected and error |
| | | * object on error |
| | | * @access public |
| | | */ |
| | | function disconnect($force = true) |
| | | { |
| | | if (is_object($this->connection)) { |
| | | if ($force) { |
| | | @mysqli_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | if (is_null($database_name)) { |
| | | $database_name = $this->database_name; |
| | | } |
| | | |
| | | if ($database_name) { |
| | | if ($database_name != $this->connected_database_name) { |
| | | if (!@mysqli_select_db($connection, $database_name)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->connected_database_name = $database_name; |
| | | } |
| | | } |
| | | |
| | | $function = $this->options['result_buffering'] |
| | | ? 'mysqli_query' : 'mysqli_unbuffered_query'; |
| | | $result = @$function($connection, $query); |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @mysqli_affected_rows($connection); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $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 ($isManip) { |
| | | return $query . " LIMIT $limit"; |
| | | } else { |
| | | return $query . " LIMIT $offset, $limit"; |
| | | } |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 :[a-zA-Z] and are placeholders which can be set using |
| | | * bindParam() and the query can be send off using the execute() method. |
| | | * |
| | | * @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 |
| | | * @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) |
| | | { |
| | | $isManip = MDB2::isManip($query); |
| | | $query = $this->_modifyQuery($query, $isManip, $this->row_limit, $this->row_offset); |
| | | $this->debug($query, 'prepare'); |
| | | $placeholder_type_guess = $placeholder_type = null; |
| | | $question = '?'; |
| | | $colon = ':'; |
| | | $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]; |
| | | } |
| | | if (is_int($quote = strpos($query, "'", $position)) && $quote < $p_position) { |
| | | if (!is_int($end_quote = strpos($query, "'", $quote + 1))) { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: query with an unterminated text string specified'); |
| | | return $err; |
| | | } |
| | | switch ($this->escape_quotes) { |
| | | case '': |
| | | case "'": |
| | | $position = $end_quote + 1; |
| | | break; |
| | | default: |
| | | if ($end_quote == $quote + 1) { |
| | | $position = $end_quote + 1; |
| | | } else { |
| | | if ($query[$end_quote-1] == $this->escape_quotes) { |
| | | $position = $end_quote; |
| | | } else { |
| | | $position = $end_quote + 1; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } elseif ($query[$position] == $placeholder_type_guess) { |
| | | if ($placeholder_type_guess == '?') { |
| | | break; |
| | | } |
| | | if (is_null($placeholder_type)) { |
| | | $placeholder_type = $query[$p_position]; |
| | | $question = $colon = $placeholder_type; |
| | | } |
| | | $name = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); |
| | | if ($name === '') { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: named parameter with an empty name'); |
| | | return $err; |
| | | } |
| | | $query = substr_replace($query, '?', $position, strlen($name)+1); |
| | | $position = $p_position + 1; |
| | | } else { |
| | | $position = $p_position; |
| | | } |
| | | } |
| | | $statement = @mysqli_prepare($this->connection, $query); |
| | | $class_name = 'MDB2_Statement_'.$this->phptype; |
| | | $obj =& new $class_name($this, $statement, $query, $types, $result_types); |
| | | 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 REPLACE query just updates its values instead of |
| | | * inserting a new row. |
| | | * |
| | | * 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 |
| | | * |
| | | * @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.= $name; |
| | | if (isset($fields[$name]['null']) && $fields[$name]['null']) { |
| | | $value = 'NULL'; |
| | | } else { |
| | | $value = $this->quote($fields[$name]['value'], $fields[$name]['type']); |
| | | } |
| | | $values.= $value; |
| | | if (isset($fields[$name]['key']) && $fields[$name]['key']) { |
| | | if ($value === 'NULL') { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: key value '.$name.' may not be NULL'); |
| | | } |
| | | $keys++; |
| | | } |
| | | } |
| | | if ($keys == 0) { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: not specified which fields are keys'); |
| | | } |
| | | $query = "REPLACE INTO $table ($query) VALUES ($values)"; |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | return $this->_doQuery($query, true); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (NULL)"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->_doQuery($query, true); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence '.$seq_name.' could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | return 1; |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | $value = @mysqli_insert_id($this->connection); |
| | | if (is_numeric($value)) { |
| | | $query = "DELETE FROM $sequence_name WHERE ".$this->options['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 |
| | | * |
| | | * @param mixed $id value as returned by getBeforeId() |
| | | * @param string $table name of the table into which a new row was inserted |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function lastInsertID($table = null, $field = null) |
| | | { |
| | | $value = @mysqli_insert_id($this->connection); |
| | | if (!$value) { |
| | | return $this->raiseError(); |
| | | } |
| | | 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->getSequenceName($seq_name); |
| | | $query = "SELECT MAX(".$this->options['seqcol_name'].") FROM $sequence_name"; |
| | | return $this->queryOne($query, 'integer'); |
| | | } |
| | | } |
| | | |
| | | class MDB2_Result_mysqli 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 = @mysqli_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 = @mysqli_fetch_row($this->result); |
| | | } |
| | | |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _getColumnNames() |
| | | { |
| | | $columns = array(); |
| | | $numcols = $this->numCols(); |
| | | if (PEAR::isError($numcols)) { |
| | | return $numcols; |
| | | } |
| | | for ($column = 0; $column < $numcols; $column++) { |
| | | $column_info = @mysqli_fetch_field_direct($this->result, $column); |
| | | $columns[$column_info->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 = @mysqli_num_fields($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with result. |
| | | * |
| | | * @return boolean true on success, false if result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | @mysqli_free_result($this->result); |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_mysqli extends MDB2_Result_mysqli |
| | | { |
| | | // }}} |
| | | // {{{ 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) && !@mysqli_data_seek($this->result, $rownum)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $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 = @mysqli_num_rows($this->result); |
| | | if (is_null($rows)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_mysqli 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 a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function &_execute($result_class = true, $result_wrap_class = false) |
| | | { |
| | | $isManip = MDB2::isManip($this->query); |
| | | $this->db->last_query = $this->query; |
| | | $this->db->debug($this->query, 'execute'); |
| | | if ($this->db->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | $return = 0; |
| | | return $return; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | |
| | | $connected = $this->db->connect(); |
| | | if (PEAR::isError($connected)) { |
| | | return $connected; |
| | | } |
| | | |
| | | if (!empty($this->values)) { |
| | | $parameters = array(0 => $this->statement, 1 => ''); |
| | | $i = 0; |
| | | foreach ($this->values as $parameter => $value) { |
| | | $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; |
| | | $close = false; |
| | | if ($type == 'clob' || $type == 'blob') { |
| | | if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { |
| | | $close = true; |
| | | if ($match[1] == 'file://') { |
| | | $value = $match[2]; |
| | | } |
| | | $value = @fopen($value, 'r'); |
| | | } |
| | | } |
| | | if (is_resource($value)) { |
| | | while (!@feof($value)) { |
| | | $data = @fread($value, $this->db->options['lob_buffer_length']); |
| | | @mysqli_stmt_send_long_data($this->statement, $i, $data); |
| | | } |
| | | if ($close) { |
| | | @fclose($value); |
| | | } |
| | | $parameters[] = null; |
| | | $parameters[1].= 'b'; |
| | | } elseif ($type == 'clob' || $type == 'blob') { |
| | | do { |
| | | $data = substr($value, 0, $this->db->options['lob_buffer_length']); |
| | | $value = substr($value, $this->db->options['lob_buffer_length']); |
| | | @mysqli_stmt_send_long_data($this->statement, $i, $data); |
| | | } while ($value); |
| | | $parameters[] = null; |
| | | $parameters[1].= 'b'; |
| | | } else { |
| | | $parameters[] = $this->db->quote($value, $type, false); |
| | | $parameters[1].= $this->db->datatype->mapPrepareDatatype($type); |
| | | } |
| | | ++$i; |
| | | } |
| | | $result = @call_user_func_array('mysqli_stmt_bind_param', $parameters); |
| | | if ($result === false) { |
| | | $err =& $this->db->raiseError(); |
| | | return $err; |
| | | } |
| | | } |
| | | |
| | | if (!@mysqli_stmt_execute($this->statement)) { |
| | | $err =& $this->db->raiseError(); |
| | | return $err; |
| | | } |
| | | |
| | | if (!mysqli_stmt_result_metadata($this->statement)) { |
| | | $result = @mysqli_stmt_affected_rows($this->statement); |
| | | return $result; |
| | | } |
| | | |
| | | if ($this->db->options['result_buffering']) { |
| | | mysqli_stmt_store_result($this->statement); |
| | | } |
| | | |
| | | $result &= $this->db->_wrapResult($result, $this->types, |
| | | $result_class, $result_wrap_class); |
| | | 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 (!@mysqli_stmt_close($this->statement)) { |
| | | return $this->db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@pooteeweet.org> | |
| | | // +----------------------------------------------------------------------+ |
| | | |
| | | // $Id$ |
| | | |
| | | /** |
| | | * MDB2 OCI8 driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@pooteeweet.org> |
| | | */ |
| | | class MDB2_Driver_oci8 extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "'"; |
| | | |
| | | var $uncommitedqueries = 0; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'oci8'; |
| | | $this->dbsyntax = 'oci8'; |
| | | |
| | | $this->supported['sequences'] = true; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['summary_functions'] = true; |
| | | $this->supported['order_by_text'] = true; |
| | | $this->supported['current_id'] = true; |
| | | $this->supported['affected_rows'] = true; |
| | | $this->supported['transactions'] = true; |
| | | $this->supported['limit_queries'] = 'emulated'; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = 'emulated'; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = false; // not implemented |
| | | $this->supported['primary_key'] = false; // not implemented |
| | | |
| | | $this->options['DBA_username'] = false; |
| | | $this->options['DBA_password'] = false; |
| | | $this->options['database_name_prefix'] = false; |
| | | $this->options['emulate_database'] = true; |
| | | $this->options['default_tablespace'] = false; |
| | | $this->options['default_text_field_length'] = 4000; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ errorInfo() |
| | | |
| | | /** |
| | | * This method is used to collect information about an error |
| | | * |
| | | * @param integer $error |
| | | * @return array |
| | | * @access public |
| | | */ |
| | | function errorInfo($error = null) |
| | | { |
| | | if (is_resource($error)) { |
| | | $error_data = @OCIError($error); |
| | | $error = null; |
| | | } elseif ($this->connection) { |
| | | $error_data = @OCIError($this->connection); |
| | | } else { |
| | | $error_data = @OCIError(); |
| | | } |
| | | $native_code = $error_data['code']; |
| | | $native_msg = $error_data['message']; |
| | | if (is_null($error)) { |
| | | static $ecode_map; |
| | | if (empty($ecode_map)) { |
| | | $ecode_map = array( |
| | | 1 => MDB2_ERROR_CONSTRAINT, |
| | | 900 => MDB2_ERROR_SYNTAX, |
| | | 904 => MDB2_ERROR_NOSUCHFIELD, |
| | | 913 => MDB2_ERROR_VALUE_COUNT_ON_ROW, |
| | | 921 => MDB2_ERROR_SYNTAX, |
| | | 923 => MDB2_ERROR_SYNTAX, |
| | | 942 => MDB2_ERROR_NOSUCHTABLE, |
| | | 955 => MDB2_ERROR_ALREADY_EXISTS, |
| | | 1400 => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | 1401 => MDB2_ERROR_INVALID, |
| | | 1407 => MDB2_ERROR_CONSTRAINT_NOT_NULL, |
| | | 1418 => MDB2_ERROR_NOT_FOUND, |
| | | 1476 => MDB2_ERROR_DIVZERO, |
| | | 1722 => MDB2_ERROR_INVALID_NUMBER, |
| | | 2289 => MDB2_ERROR_NOSUCHTABLE, |
| | | 2291 => MDB2_ERROR_CONSTRAINT, |
| | | 2292 => MDB2_ERROR_CONSTRAINT, |
| | | 2449 => MDB2_ERROR_CONSTRAINT, |
| | | ); |
| | | } |
| | | if (isset($ecode_map[$native_code])) { |
| | | $error = $ecode_map[$native_code]; |
| | | } |
| | | } |
| | | return array($error, $native_code, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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'); |
| | | } |
| | | $this->in_transaction = true; |
| | | ++$this->uncommitedqueries; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ commit() |
| | | |
| | | /** |
| | | * Commit the database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | if ($this->uncommitedqueries) { |
| | | if (!@OCICommit($this->connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->uncommitedqueries = 0; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | if ($this->uncommitedqueries) { |
| | | if (!@OCIRollback($this->connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | $this->uncommitedqueries = 0; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _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'); |
| | | } |
| | | |
| | | if (isset($this->dsn['hostspec'])) { |
| | | $sid = $this->dsn['hostspec']; |
| | | } else { |
| | | $sid = getenv('ORACLE_SID'); |
| | | } |
| | | if (empty($sid)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'it was not specified a valid Oracle Service Identifier (SID)'); |
| | | } |
| | | |
| | | if (function_exists('oci_connect')) { |
| | | if (isset($this->dsn['new_link']) |
| | | && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true) |
| | | ) { |
| | | $connect_function = 'oci_new_connect'; |
| | | } else { |
| | | $connect_function = $persistent ? 'oci_pconnect' : 'oci_connect'; |
| | | } |
| | | |
| | | $charset = empty($this->dsn['charset']) ? null : $this->dsn['charset']; |
| | | $connection = @$connect_function($username, $password, $sid, $charset); |
| | | $error = @OCIError(); |
| | | if (isset($error['code']) && $error['code'] == 12541) { |
| | | // Couldn't find TNS listener. Try direct connection. |
| | | $connection = @$connect_function($username, $password, null, $charset); |
| | | } |
| | | } else { |
| | | $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon'; |
| | | $connection = @$connect_function($username, $password, $sid); |
| | | } |
| | | |
| | | if (!$connection) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); |
| | | } |
| | | |
| | | return $connection; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Connect to the database |
| | | * |
| | | * @return MDB2_OK on success, MDB2 Error Object on failure |
| | | * @access public |
| | | */ |
| | | function connect() |
| | | { |
| | | if ($this->database_name && $this->options['emulate_database']) { |
| | | $this->dsn['username'] = $this->options['database_name_prefix'].$this->database_name; |
| | | } |
| | | if (is_resource($this->connection)) { |
| | | if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 |
| | | && $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->opened_persistent = $this->options['persistent']; |
| | | $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; |
| | | |
| | | $query = "ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"; |
| | | $err = $this->_doQuery($query, true); |
| | | if (PEAR::isError($err)) { |
| | | $this->disconnect(false); |
| | | return $err; |
| | | } |
| | | |
| | | $query = "ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '"; |
| | | $err = $this->_doQuery($query, true); |
| | | if (PEAR::isError($err)) { |
| | | $this->disconnect(false); |
| | | return $err; |
| | | } |
| | | |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | if (function_exists('oci_close')) { |
| | | @oci_close($this->connection); |
| | | } else { |
| | | @OCILogOff($this->connection); |
| | | } |
| | | } |
| | | $this->connection = 0; |
| | | $this->uncommitedqueries = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function &standaloneQuery($query, $types = null) |
| | | { |
| | | $connection = $this->_doConnect( |
| | | $this->options['DBA_username'], |
| | | $this->options['DBA_password'], |
| | | $this->options['persistent'] |
| | | ); |
| | | if (PEAR::isError($connection)) { |
| | | return $connection; |
| | | } |
| | | |
| | | $isManip = MDB2::isManip($query); |
| | | $offset = $this->row_offset; |
| | | $limit = $this->row_limit; |
| | | $this->row_offset = $this->row_limit = 0; |
| | | $query = $this->_modifyQuery($query, $isManip, $limit, $offset); |
| | | |
| | | $result = $this->_doQuery($query, $isManip, $connection, false); |
| | | |
| | | @OCILogOff($connection); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return $result; |
| | | } |
| | | $return =& $this->_wrapResult($result, $types, true, false, $limit, $offset); |
| | | return $return; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query) |
| | | { |
| | | // "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle |
| | | if (preg_match('/^\s*SELECT/i', $query) |
| | | && !preg_match('/\sFROM\s/i', $query) |
| | | ) { |
| | | $query.= " FROM dual"; |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | |
| | | $result = @OCIParse($connection, $query); |
| | | if (!$result) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'Could not create statement'); |
| | | } |
| | | |
| | | $mode = $this->in_transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS; |
| | | if (!@OCIExecute($result, $mode)) { |
| | | return $this->raiseError($result); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @OCIRowCount($result); |
| | | } |
| | | |
| | | if (is_numeric($this->options['result_buffering'])) { |
| | | @ocisetprefetch($result, $this->options['result_buffering']); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 :[a-zA-Z] and are placeholders which can be set using |
| | | * bindParam() and the query can be send off using the execute() method. |
| | | * |
| | | * @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 |
| | | * @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) |
| | | { |
| | | $this->debug($query, 'prepare'); |
| | | $query = $this->_modifyQuery($query); |
| | | $contains_lobs = false; |
| | | if (is_array($types)) { |
| | | $columns = $variables = ''; |
| | | foreach ($types as $parameter => $type) { |
| | | if ($type == 'clob' || $type == 'blob') { |
| | | $contains_lobs = true; |
| | | $columns.= ($columns ? ', ' : ' RETURNING ').$parameter; |
| | | $variables.= ($variables ? ', ' : ' INTO ').':'.$parameter; |
| | | } |
| | | } |
| | | } |
| | | $placeholder_type_guess = $placeholder_type = null; |
| | | $question = '?'; |
| | | $colon = ':'; |
| | | $position = 0; |
| | | $parameter = -1; |
| | | 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]; |
| | | } |
| | | if (is_int($quote = strpos($query, "'", $position)) && $quote < $p_position) { |
| | | if (!is_int($end_quote = strpos($query, "'", $quote + 1))) { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: query with an unterminated text string specified'); |
| | | return $err; |
| | | } |
| | | switch ($this->escape_quotes) { |
| | | case '': |
| | | case "'": |
| | | $position = $end_quote + 1; |
| | | break; |
| | | default: |
| | | if ($end_quote == $quote + 1) { |
| | | $position = $end_quote + 1; |
| | | } else { |
| | | if ($query[$end_quote-1] == $this->escape_quotes) { |
| | | $position = $end_quote; |
| | | } else { |
| | | $position = $end_quote + 1; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } elseif ($query[$position] == $placeholder_type_guess) { |
| | | if ($placeholder_type_guess == ':' && !$contains_lobs) { |
| | | break; |
| | | } |
| | | if (is_null($placeholder_type)) { |
| | | $placeholder_type = $query[$p_position]; |
| | | $question = $colon = $placeholder_type; |
| | | } |
| | | if ($contains_lobs) { |
| | | if ($placeholder_type == ':') { |
| | | $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); |
| | | if ($parameter === '') { |
| | | $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'prepare: named parameter with an empty name'); |
| | | return $err; |
| | | } |
| | | $length = strlen($parameter)+1; |
| | | } else { |
| | | ++$parameter; |
| | | $length = strlen($parameter); |
| | | } |
| | | if (isset($types[$parameter]) |
| | | && ($types[$parameter] == 'clob' || $types[$parameter] == 'blob') |
| | | ) { |
| | | $value = $this->quote(true, $types[$parameter]); |
| | | $query = substr_replace($query, $value, $p_position, $length); |
| | | $position = $p_position + strlen($value) - 1; |
| | | } elseif ($placeholder_type == '?') { |
| | | $query = substr_replace($query, ':'.$parameter, $p_position, 1); |
| | | $position = $p_position + strlen($parameter); |
| | | } |
| | | } else { |
| | | $query = substr_replace($query, ':'.++$parameter, $p_position, 1); |
| | | $position = $p_position + strlen($parameter); |
| | | } |
| | | } else { |
| | | $position = $p_position; |
| | | } |
| | | } |
| | | if (is_array($types)) { |
| | | $query.= $columns.$variables; |
| | | } |
| | | $statement = @OCIParse($this->connection, $query); |
| | | if (!$statement) { |
| | | $err =& $this->raiseError(MDB2_ERROR, null, null, |
| | | 'Could not create statement'); |
| | | return $err; |
| | | } |
| | | |
| | | $class_name = 'MDB2_Statement_'.$this->phptype; |
| | | $obj =& new $class_name($this, $statement, $query, $types, $result_types, $this->row_limit, $this->row_offset); |
| | | return $obj; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = "SELECT $sequence_name.nextval FROM DUAL"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->queryOne($query, 'integer'); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | $result = $this->manager->createSequence($seq_name, 1); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | return $this->nextId($seq_name, false); |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ currId() |
| | | |
| | | /** |
| | | * returns the current id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @return mixed MDB2_Error or id |
| | | * @access public |
| | | */ |
| | | function currId($seq_name) |
| | | { |
| | | $sequence_name = $this->getSequenceName($seq_name); |
| | | return $this->queryOne("SELECT $sequence_name.currval FROM DUAL"); |
| | | } |
| | | } |
| | | |
| | | class MDB2_Result_oci8 extends MDB2_Result_Common |
| | | { |
| | | // {{{ _skipLimitOffset() |
| | | |
| | | /** |
| | | * Skip the first row of a result set. |
| | | * |
| | | * @param resource $result |
| | | * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access protected |
| | | */ |
| | | function _skipLimitOffset() |
| | | { |
| | | if ($this->limit) { |
| | | if ($this->rownum > $this->limit) { |
| | | return false; |
| | | } |
| | | } |
| | | if ($this->offset) { |
| | | while ($this->offset_count < $this->offset) { |
| | | ++$this->offset_count; |
| | | if (!@OCIFetchInto($this->result, $row, OCI_RETURN_NULLS)) { |
| | | $this->offset_count = $this->offset; |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 (!$this->_skipLimitOffset()) { |
| | | $null = null; |
| | | return $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) { |
| | | @OCIFetchInto($this->result, $row, OCI_ASSOC+OCI_RETURN_NULLS); |
| | | if (is_array($row) |
| | | && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE |
| | | ) { |
| | | $row = array_change_key_case($row, $this->db->options['field_case']); |
| | | } |
| | | } else { |
| | | @OCIFetchInto($this->result, $row, OCI_RETURN_NULLS); |
| | | } |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_RTRIM); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 associative array variable |
| | | * that holds the names of columns. The indexes of the array are |
| | | * the column names mapped to lower case and the values are the |
| | | * respective numbers of the columns starting from 0. 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 = @OCIColumnName($this->result, $column + 1); |
| | | $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 = @OCINumCols($this->result); |
| | | if (is_null($cols)) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with $result. |
| | | * |
| | | * @return boolean true on success, false if $result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $free = @OCIFreeCursor($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_oci8 extends MDB2_Result_oci8 |
| | | { |
| | | var $buffer; |
| | | var $buffer_rownum = - 1; |
| | | |
| | | // {{{ _fillBuffer() |
| | | |
| | | /** |
| | | * Fill the row buffer |
| | | * |
| | | * @param int $rownum row number upto which the buffer should be filled |
| | | if the row number is null all rows are ready into the buffer |
| | | * @return boolean true on success, false on failure |
| | | * @access protected |
| | | */ |
| | | function _fillBuffer($rownum = null) |
| | | { |
| | | if (isset($this->buffer) && is_array($this->buffer)) { |
| | | if (is_null($rownum)) { |
| | | if (!end($this->buffer)) { |
| | | return false; |
| | | } |
| | | } elseif (isset($this->buffer[$rownum])) { |
| | | return (bool)$this->buffer[$rownum]; |
| | | } |
| | | } |
| | | |
| | | if (!$this->_skipLimitOffset()) { |
| | | return false; |
| | | } |
| | | |
| | | $row = true; |
| | | while ((is_null($rownum) || $this->buffer_rownum < $rownum) |
| | | && (!$this->limit || $this->buffer_rownum < $this->limit) |
| | | && ($row = @OCIFetchInto($this->result, $buffer, OCI_RETURN_NULLS)) |
| | | ) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = $buffer; |
| | | } |
| | | |
| | | if (!$row) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = false; |
| | | return false; |
| | | } elseif ($this->limit && $this->buffer_rownum >= $this->limit) { |
| | | ++$this->buffer_rownum; |
| | | $this->buffer[$this->buffer_rownum] = false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | if (!is_null($rownum)) { |
| | | $seek = $this->seek($rownum); |
| | | if (PEAR::isError($seek)) { |
| | | return $seek; |
| | | } |
| | | } |
| | | $target_rownum = $this->rownum + 1; |
| | | if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { |
| | | $fetchmode = $this->db->fetchmode; |
| | | } |
| | | if (!$this->_fillBuffer($target_rownum)) { |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | $row = $this->buffer[$target_rownum]; |
| | | if ($fetchmode & MDB2_FETCHMODE_ASSOC) { |
| | | $column_names = $this->getColumnNames(); |
| | | foreach ($column_names as $name => $i) { |
| | | $column_names[$name] = $row[$i]; |
| | | } |
| | | $row = $column_names; |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $row); |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_RTRIM); |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | $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() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'valid: resultset has already been freed'); |
| | | } |
| | | if ($this->_fillBuffer($this->rownum + 1)) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ numRows() |
| | | |
| | | /** |
| | | * returns the number of rows in a result object |
| | | * |
| | | * @return mixed MDB2 Error Object or the number of rows |
| | | * @access public |
| | | */ |
| | | function numRows() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | $this->_fillBuffer(); |
| | | return $this->buffer_rownum; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with $result. |
| | | * |
| | | * @return boolean true on success, false if $result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $this->buffer = null; |
| | | $this->buffer_rownum = null; |
| | | $free = parent::free(); |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_oci8 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 a result handle or MDB2_OK on success, a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function &_execute($result_class = true, $result_wrap_class = false) |
| | | { |
| | | $isManip = MDB2::isManip($this->query); |
| | | $this->db->last_query = $this->query; |
| | | $this->db->debug($this->query, 'execute'); |
| | | if ($this->db->getOption('disable_query')) { |
| | | if ($isManip) { |
| | | $return = 0; |
| | | return $return; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | |
| | | $connected = $this->db->connect(); |
| | | if (PEAR::isError($connected)) { |
| | | return $connected; |
| | | } |
| | | |
| | | $result = MDB2_OK; |
| | | $lobs = $quoted_values = array(); |
| | | $i = 0; |
| | | foreach ($this->values as $parameter => $value) { |
| | | $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; |
| | | if ($type == 'clob' || $type == 'blob') { |
| | | $lobs[$i]['file'] = false; |
| | | if (is_resource($value)) { |
| | | $fp = $value; |
| | | $value = ''; |
| | | while (!feof($fp)) { |
| | | $value.= fread($fp, 8192); |
| | | } |
| | | } elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { |
| | | $lobs[$i]['file'] = true; |
| | | if ($match[1] == 'file://') { |
| | | $value = $match[2]; |
| | | } |
| | | } |
| | | $lobs[$i]['value'] = $value; |
| | | $lobs[$i]['descriptor'] = @OCINewDescriptor($this->db->connection, OCI_D_LOB); |
| | | if (!is_object($lobs[$i]['descriptor'])) { |
| | | $result = $this->db->raiseError(); |
| | | break; |
| | | } |
| | | $lob_type = ($type == 'blob' ? OCI_B_BLOB : OCI_B_CLOB); |
| | | if (!@OCIBindByName($this->statement, ':'.$parameter, $lobs[$i]['descriptor'], -1, $lob_type)) { |
| | | $result = $this->db->raiseError($this->statement); |
| | | break; |
| | | } |
| | | } else { |
| | | $quoted_values[$i] = $this->db->quote($value, $type, false); |
| | | if (PEAR::isError($quoted_values[$i])) { |
| | | return $quoted_values[$i]; |
| | | } |
| | | if (!@OCIBindByName($this->statement, ':'.$parameter, $quoted_values[$i])) { |
| | | $result = $this->db->raiseError($this->statement); |
| | | break; |
| | | } |
| | | } |
| | | ++$i; |
| | | } |
| | | |
| | | if (!PEAR::isError($result)) { |
| | | $mode = (!empty($lobs) || $this->db->in_transaction) ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS; |
| | | if (!@OCIExecute($this->statement, $mode)) { |
| | | $err =& $this->db->raiseError($this->statement); |
| | | return $err; |
| | | } |
| | | |
| | | if (!empty($lobs)) { |
| | | foreach ($lobs as $i => $stream) { |
| | | if (!is_null($stream['value']) && $stream['value'] !== '') { |
| | | if ($stream['file']) { |
| | | $result = $lobs[$i]['descriptor']->savefile($stream['value']); |
| | | } else { |
| | | $result = $lobs[$i]['descriptor']->save($stream['value']); |
| | | } |
| | | if (!$result) { |
| | | $result = $this->db->raiseError(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!PEAR::isError($result)) { |
| | | if (!$this->db->in_transaction) { |
| | | if (!@OCICommit($this->db->connection)) { |
| | | $result = $this->db->raiseError(); |
| | | } |
| | | } else { |
| | | ++$this->db->uncommitedqueries; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | $keys = array_keys($lobs); |
| | | foreach ($keys as $key) { |
| | | $lobs[$key]['descriptor']->free(); |
| | | } |
| | | |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | if ($isManip) { |
| | | $return = @OCIRowCount($this->statement); |
| | | } else { |
| | | $return = $this->db->_wrapResult($this->statement, $isManip, $this->types, |
| | | $result_class, $result_wrap_class, $this->row_offset, $this->row_limit); |
| | | } |
| | | return $return; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 (!@OCIFreeStatement($this->statement)) { |
| | | return $this->db->raiseError(); |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Paul Cooper <pgc@ucecom.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | |
| | | /** |
| | | * MDB2 PostGreSQL driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Paul Cooper <pgc@ucecom.com> |
| | | */ |
| | | class MDB2_Driver_pgsql extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "\\"; |
| | | |
| | | // }}} |
| | | // {{{ 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['current_id'] = true; |
| | | $this->supported['limit_queries'] = true; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = 'emulated'; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = 'emulated'; |
| | | $this->supported['primary_key'] = true; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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; |
| | | } |
| | | } |
| | | |
| | | 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, |
| | | '/index .* does not exist/' |
| | | => MDB2_ERROR_NOT_FOUND, |
| | | '/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, |
| | | ); |
| | | } |
| | | foreach ($error_regexps as $regexp => $code) { |
| | | if (preg_match($regexp, $native_msg)) { |
| | | $error_code = $code; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return array($error_code, null, $native_msg); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | $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 that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $result = $this->_doQuery('ROLLBACK', true); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | $this->in_transaction = false; |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doConnect() |
| | | |
| | | /** |
| | | * Does the grunt work of connecting to the database |
| | | * |
| | | * @return mixed connection resource on success, MDB2 Error Object on failure |
| | | * @access protected |
| | | **/ |
| | | function _doConnect($database_name, $persistent = false) |
| | | { |
| | | 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 ($this->dsn['username']) { |
| | | $params[0].= ' user=\'' . addslashes($this->dsn['username']) . '\''; |
| | | } |
| | | if ($this->dsn['password']) { |
| | | $params[0].= ' password=\'' . addslashes($this->dsn['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 (isset($this->dsn['new_link']) |
| | | && ($this->dsn['new_link'] == 'true' || $this->dsn['new_link'] === true)) |
| | | { |
| | | if (version_compare(phpversion(), '4.3.0', '>=')) { |
| | | $params[] = PGSQL_CONNECT_FORCE_NEW; |
| | | } |
| | | } |
| | | |
| | | $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; |
| | | |
| | | putenv('PGDATESTYLE=ISO'); |
| | | |
| | | @ini_set('track_errors', true); |
| | | $php_errormsg = ''; |
| | | $connection = @call_user_func_array($connect_function, $params); |
| | | @ini_restore('track_errors'); |
| | | if (!$connection) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, |
| | | null, null, strip_tags($php_errormsg)); |
| | | } |
| | | 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 |
| | | && $this->connected_database_name == $this->database_name |
| | | && ($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, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | if ($this->database_name) { |
| | | $connection = $this->_doConnect($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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | @pg_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function &standaloneQuery($query, $types = null) |
| | | { |
| | | $connection = $this->_doConnect('template1', false); |
| | | if (PEAR::isError($connection)) { |
| | | $err =& $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, |
| | | 'Cannot connect to template1'); |
| | | return $err; |
| | | } |
| | | |
| | | $isManip = MDB2::isManip($query); |
| | | $offset = $this->row_offset; |
| | | $limit = $this->row_limit; |
| | | $this->row_offset = $this->row_limit = 0; |
| | | $query = $this->_modifyQuery($query, $isManip, $limit, $offset); |
| | | |
| | | $result = $this->_doQuery($query, $isManip, $connection, false); |
| | | @pg_close($connection); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return $result; |
| | | } |
| | | |
| | | $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset); |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | if ($isManip) { |
| | | return 0; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $err = $this->connect(); |
| | | if (PEAR::isError($err)) { |
| | | return $err; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | |
| | | $result = @pg_query($connection, $query); |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @pg_affected_rows($result); |
| | | } elseif (!preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si', $query)) { |
| | | return 0; |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $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 ($isManip) { |
| | | $manip = preg_replace('/^(DELETE FROM|UPDATE).*$/', '\\1', $query); |
| | | $from = $match[2]; |
| | | $where = $match[3]; |
| | | $query = $manip.' '.$from.' WHERE ctid=(SELECT ctid FROM '.$from.' '.$where.' LIMIT '.$limit.')'; |
| | | } else { |
| | | $query.= " LIMIT $limit OFFSET $offset"; |
| | | } |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = "SELECT NEXTVAL('$sequence_name')"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->queryOne($query, 'integer'); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | $result = $this->manager->createSequence($seq_name, 1); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence could not be created'); |
| | | } |
| | | return $this->nextId($seq_name, false); |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $this->queryOne("SELECT last_value FROM $sequence_name", 'integer'); |
| | | } |
| | | } |
| | | |
| | | 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 (is_null($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_fixResultArrayValues($row, MDB2_PORTABILITY_EMPTY_TO_NULL); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ free() |
| | | |
| | | /** |
| | | * Free the internal resources associated with result. |
| | | * |
| | | * @return boolean true on success, false if result is invalid |
| | | * @access public |
| | | */ |
| | | function free() |
| | | { |
| | | $free = @pg_free_result($this->result); |
| | | if (!$free) { |
| | | if (is_null($this->result)) { |
| | | return MDB2_OK; |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | $this->result = null; |
| | | return MDB2_OK; |
| | | } |
| | | } |
| | | |
| | | 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_pgsql extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Original QuerySim Concept & ColdFusion Author: Hal Helms | |
| | | // | <hal.helms@teamallaire.com> | |
| | | // | Bert Dawson <bdawson@redbanner.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Original PHP Author: Alan Richmond <arichmond@bigfoot.com> | |
| | | // | David Huyck <b@bombusbee.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Special note concerning code documentation: | |
| | | // | QuerySim was originally created for use during development of | |
| | | // | applications built using the Fusebox framework. (www.fusebox.org) | |
| | | // | Fusebox uses an XML style of documentation called Fusedoc. (Which | |
| | | // | is admittedly not well suited to documenting classes and functions. | |
| | | // | This short-coming is being addressed by the Fusebox community.) PEAR | |
| | | // | uses a Javadoc style of documentation called PHPDoc. (www.phpdoc.de) | |
| | | // | Since this class extension spans two groups of users, it is asked | |
| | | // | that the members of each respect the documentation standard of the | |
| | | // | other. So it is a further requirement that both documentation | |
| | | // | standards be included and maintained. If assistance is required | |
| | | // | please contact Alan Richmond. | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /* |
| | | <fusedoc fuse="querysim.php" language="PHP"> |
| | | <responsibilities> |
| | | I take information and turn it into a recordset that can be accessed |
| | | through the PEAR MDB2 API. Based on Hal Helms' QuerySim.cfm ColdFusion |
| | | custom tag available at halhelms.com. |
| | | </responsibilities> |
| | | <properties> |
| | | <property name="API" value="PEAR MDB2" /> |
| | | <property name="version" value="0.2.1" /> |
| | | <property name="status" value="beta" /> |
| | | <history author="Hal Helms" email="hal.helms@teamallaire.com" type="Create" /> |
| | | <history author="Bert Dawson" email="bdawson@redbanner.com" type="Update"> |
| | | Extensive revision that is backwardly compatible but eliminates the |
| | | need for a separate .sim file. |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Create" date="10-July-2002"> |
| | | Rewrote in PHP as an extention to the PEAR DB API. |
| | | Functions supported: |
| | | connect, disconnect, query, fetchRow, freeResult, |
| | | numCols, numRows, getSpecialQuery |
| | | David Huyck (bombusbee.com) added ability to escape special |
| | | characters (i.e., delimiters) using a '\'. |
| | | Extended PEAR DB options[] for adding incoming parameters. Added |
| | | options: columnDelim, dataDelim, eolDelim |
| | | </history> |
| | | <history author="David Huyck" email="b@bombusbee.com" type="Update" date="19-July-2002"> |
| | | Added the ability to set the QuerySim options at runtime. |
| | | Default options are: |
| | | 'columnDelim' => ',', // Commas split the column names |
| | | 'dataDelim' => '|', // Pipes split the data fields |
| | | 'eolDelim' => chr(13).chr(10) // Carriage returns split the |
| | | // lines of data |
| | | Affected functions are: |
| | | DB_querysim(): set the default options when the |
| | | constructor method is called |
| | | _parseQuerySim($query): altered the parsing of lines, column |
| | | names, and data fields |
| | | _empty2null: altered the way this function is called |
| | | to simplify calling it |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="24-July-2002"> |
| | | Added error catching for malformed QuerySim text. |
| | | Bug fix _empty2null(): altered version was returning unmodified |
| | | lineData. |
| | | Cleanup: |
| | | PEAR compliant formatting, finished PHPDocs and added 'out' to |
| | | Fusedoc 'io'. |
| | | Broke up _parseQuerySim() into _buildResult() and _parseOnDelim() |
| | | to containerize duplicate parse code. |
| | | </history> |
| | | <history author="David Huyck" email="b@bombusbee.com" type="Update" date="25-July-2002"> |
| | | Edited the _buildResult() and _parseOnDelim() functions to improve |
| | | reliability of special character escaping. |
| | | Re-introduced a custom setOption() method to throw an error when a |
| | | person tries to set one of the delimiters to '\'. |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="27-July-2002"> |
| | | Added '/' delimiter param to preg_quote() in _empty2null() and |
| | | _parseOnDelim() so '/' can be used as a delimiter. |
| | | Added error check for columnDelim == eolDelim or dataDelim == eolDelim. |
| | | Renamed some variables for consistancy. |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="30-July-2002"> |
| | | Removed protected function _empty2null(). Turns out preg_split() |
| | | deals with empty elemants by making them zero length strings, just |
| | | what they ended up being anyway. This should speed things up a little. |
| | | Affected functions: |
| | | _parseOnDelim() perform trim on line here, instead of in |
| | | _empty2null(). |
| | | _buildResult() remove call to _empty2null(). |
| | | _empty2null() removed function. |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="1-Jan-2003"> |
| | | Ported to PEAR MDB2. |
| | | Methods supported: |
| | | connect, query, getColumnNames, numCols, valid, fetch, |
| | | numRows, free, fetchRow, nextResult, setLimit |
| | | (inherited). |
| | | </history> |
| | | <history |
| | | Removed array_change_key_case() work around for <4.2.0 in |
| | | getColumnNames(), found it already done in MDB2/Common.php. |
| | | </history> |
| | | <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="3-Feb-2003"> |
| | | Changed default eolDelim to a *nix file eol, since we're trimming |
| | | the result anyway, it makes no difference for Windows. Now only |
| | | Mac file eols should need to be set (and other kinds of chars). |
| | | </history> |
| | | <note author="Alan Richmond"> |
| | | Got WAY too long. See querysim_readme.txt for instructions and some |
| | | examples. |
| | | io section only documents elements of DB_result that DB_querysim uses, |
| | | adds or changes; see MDB2 and MDB2_Driver_Common for more info. |
| | | io section uses some elements that are not Fusedoc 2.0 compliant: |
| | | object and resource. |
| | | </note> |
| | | </properties> |
| | | <io> |
| | | <in> |
| | | <file path="MDB2/Common.php" action="require_once" /> |
| | | </in> |
| | | <out> |
| | | <object name="MDB2_querysim" extends="MDB2_Driver_Common" instantiatedby="MDB2::connect()"> |
| | | <resource type="file" name="connection" oncondition="source is external file" scope="class" /> |
| | | <string name="phptype" default="querysim" /> |
| | | <string name="dbsyntax" default="querysim" /> |
| | | <array name="supported" comments="most of these don't actually do anything, they are enabled to simulate the option being available if checked"> |
| | | <boolean name="sequences" default="true" /> |
| | | <boolean name="indexes" default="true" /> |
| | | <boolean name="affected_rows" default="true" /> |
| | | <boolean name="summary_functions" default="true" /> |
| | | <boolean name="order_by_text" default="true" /> |
| | | <boolean name="current_id" default="true" /> |
| | | <boolean name="limit_querys" default="true" comments="this one is functional" /> |
| | | <boolean name="LOBs" default="true" /> |
| | | <boolean name="replace" default="true" /> |
| | | <boolean name="sub_selects" default="true" /> |
| | | <boolean name="transactions" default="true" /> |
| | | </array> |
| | | <string name="last_query" comments="last value passed in with query()" /> |
| | | <array name="options" comments="these can be changed at run time"> |
| | | <string name="columnDelim" default="," /> |
| | | <string name="dataDelim" default="|" /> |
| | | <string name="eolDelim" default="chr(13).chr(10)" /> |
| | | </array> |
| | | </object> |
| | | <array name="result" comments="the simulated record set returned by ::query()"> |
| | | <array comments="columns"> |
| | | <string comments="column name" /> |
| | | </array> |
| | | <array comments="data"> |
| | | <array comments="row"> |
| | | <string comments="data element" /> |
| | | </array> |
| | | </array> |
| | | </array> |
| | | </out> |
| | | </io> |
| | | </fusedoc> |
| | | */ |
| | | |
| | | /** |
| | | * MDB2 QuerySim driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Alan Richmond <arichmond@bigfoot.com> |
| | | */ |
| | | class MDB2_Driver_querysim extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "\\"; |
| | | // }}} |
| | | |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'querysim'; |
| | | $this->dbsyntax = 'querysim'; |
| | | |
| | | // Most of these are dummies to simulate availability if checked |
| | | $this->supported['sequences'] = 'emulated'; |
| | | $this->supported['indexes'] = true; |
| | | $this->supported['affected_rows'] = false; |
| | | $this->supported['summary_functions'] = false; |
| | | $this->supported['order_by_text'] = false; |
| | | $this->supported['current_id'] = 'emulated'; |
| | | $this->supported['limit_queries'] = true;// this one is real |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = 'emulated'; |
| | | $this->supported['sub_selects'] = 'emulated'; |
| | | $this->supported['transactions'] = false; |
| | | $this->supported['auto_increment'] = false; |
| | | $this->supported['primary_key'] = false; |
| | | |
| | | $this->options['columnDelim'] = ','; |
| | | $this->options['dataDelim'] = '|'; |
| | | $this->options['eolDelim'] = "\n"; |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | // {{{ connect() |
| | | |
| | | /** |
| | | * Open a file or simulate a successful database connect |
| | | * |
| | | * @access public |
| | | * |
| | | * @return mixed MDB2_OK string on success, a MDB2 error object on failure |
| | | */ |
| | | function connect() |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if ($this->connected_database_name == $this->database_name |
| | | && ($this->opened_persistent == $this->options['persistent']) |
| | | ) { |
| | | return MDB2_OK; |
| | | } |
| | | if ($this->connected_database_name) { |
| | | $this->_close($this->connection); |
| | | } |
| | | $this->disconnect(); |
| | | } |
| | | |
| | | $connection = 1;// sim connect |
| | | // if external, check file... |
| | | if ($this->database_name) { |
| | | $file = $this->database_name; |
| | | if (!file_exists($file)) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'file not found'); |
| | | } |
| | | if (!is_file($file)) { |
| | | return $this->raiseError(MDB2_ERROR_INVALID, null, null, 'not a file'); |
| | | } |
| | | if (!is_readable($file)) { |
| | | return $this->raiseError(MDB2_ERROR_ACCESS_VIOLATION, null, null, |
| | | 'could not open file - check permissions'); |
| | | } |
| | | // ...and open if persistent |
| | | if ($this->options['persistent']) { |
| | | $connection = @fopen($file, 'r'); |
| | | } |
| | | } |
| | | $this->connection = $connection; |
| | | $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; |
| | | } |
| | | // }}} |
| | | |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @return mixed true on success, false if not connected and error |
| | | * object on error |
| | | * @access public |
| | | */ |
| | | function disconnect() |
| | | { |
| | | if (is_resource($this->connection)) { |
| | | if (($this->opened_persistent) && (is_resource($this->connection))) { |
| | | if (!@fclose($this->connection)) { |
| | | return $this->raiseError(); |
| | | } |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | // }}} |
| | | |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | if ($isManip) { |
| | | return $this->raiseError(MDB2_ERROR_UNSUPPORTED); |
| | | } |
| | | |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | return null; |
| | | } |
| | | |
| | | $result = $this->_buildResult($query); |
| | | if (PEAR::isError($result)) { |
| | | return $result; |
| | | } |
| | | |
| | | if ($limit > 0) { |
| | | $result[1] = array_slice($result[1], $offset-1, $limit); |
| | | } |
| | | return $result; |
| | | } |
| | | // }}} |
| | | |
| | | // {{{ _readFile() |
| | | |
| | | /** |
| | | * Read an external file |
| | | * |
| | | * @param string filepath/filename |
| | | * |
| | | * @access protected |
| | | * |
| | | * @return string the contents of a file |
| | | */ |
| | | function _readFile() |
| | | { |
| | | $buffer = ''; |
| | | if ($this->opened_persistent) { |
| | | while (!feof($this->connection)) { |
| | | $buffer.= fgets($this->connection, 1024); |
| | | } |
| | | } else { |
| | | $this->connection = @fopen($this->connected_database_name, 'r'); |
| | | while (!feof($this->connection)) { |
| | | $buffer.= fgets($this->connection, 1024); |
| | | } |
| | | $this->connection = @fclose($this->connection); |
| | | } |
| | | return $buffer; |
| | | } |
| | | // }}} |
| | | |
| | | // {{{ _buildResult() |
| | | |
| | | /** |
| | | * Convert QuerySim text into an array |
| | | * |
| | | * @param string Text of simulated query |
| | | * |
| | | * @access protected |
| | | * |
| | | * @return multi-dimensional array containing the column names and data |
| | | * from the QuerySim |
| | | */ |
| | | function _buildResult($query) |
| | | { |
| | | $eolDelim = $this->options['eolDelim']; |
| | | $columnDelim = $this->options['columnDelim']; |
| | | $dataDelim = $this->options['dataDelim']; |
| | | |
| | | $columnNames = array(); |
| | | $data = array(); |
| | | |
| | | if ($columnDelim == $eolDelim) { |
| | | return $this->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'columnDelim and eolDelim must be different'); |
| | | } elseif ($dataDelim == $eolDelim){ |
| | | return $this->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'dataDelim and eolDelim must be different'); |
| | | } |
| | | |
| | | $query = trim($query); |
| | | //tokenize escaped slashes |
| | | $query = str_replace('\\\\', '[$double-slash$]', $query); |
| | | |
| | | if (!strlen($query)) { |
| | | return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'empty querysim text'); |
| | | } |
| | | $lineData = $this->_parseOnDelim($query, $eolDelim); |
| | | //kill the empty last row created by final eol char if it exists |
| | | if (!strlen(trim($lineData[count($lineData) - 1]))) { |
| | | unset($lineData[count($lineData) - 1]); |
| | | } |
| | | //populate columnNames array |
| | | $thisLine = each($lineData); |
| | | $columnNames = $this->_parseOnDelim($thisLine[1], $columnDelim); |
| | | if ((in_array('', $columnNames)) || (in_array('NULL', $columnNames))) { |
| | | return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | 'all column names must be defined'); |
| | | } |
| | | //replace double-slash tokens with single-slash |
| | | $columnNames = str_replace('[$double-slash$]', '\\', $columnNames); |
| | | $columnCount = count($columnNames); |
| | | $rowNum = 0; |
| | | //loop through data lines |
| | | if (count($lineData) > 1) { |
| | | while ($thisLine = each($lineData)) { |
| | | $thisData = $this->_parseOnDelim($thisLine[1], $dataDelim); |
| | | $thisDataCount = count($thisData); |
| | | if ($thisDataCount != $columnCount) { |
| | | $fileLineNo = $rowNum + 2; |
| | | return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, |
| | | "number of data elements ($thisDataCount) in line $fileLineNo not equal to number of defined columns ($columnCount)"); |
| | | } |
| | | //loop through data elements in data line |
| | | foreach ($thisData as $thisElement) { |
| | | if (strtoupper($thisElement) == 'NULL'){ |
| | | $thisElement = ''; |
| | | } |
| | | //replace double-slash tokens with single-slash |
| | | $data[$rowNum][] = str_replace('[$double-slash$]', '\\', $thisElement); |
| | | }//end foreach |
| | | ++$rowNum; |
| | | }//end while |
| | | }//end if |
| | | return array($columnNames, $data); |
| | | }//end function _buildResult() |
| | | // }}} |
| | | |
| | | // {{{ _parseOnDelim() |
| | | |
| | | /** |
| | | * Split QuerySim string into an array on a delimiter |
| | | * |
| | | * @param string $thisLine Text of simulated query |
| | | * @param string $delim The delimiter to split on |
| | | * |
| | | * @access protected |
| | | * |
| | | * @return array containing parsed string |
| | | */ |
| | | function _parseOnDelim($thisLine, $delim) |
| | | { |
| | | $delimQuoted = preg_quote($delim, '/'); |
| | | $thisLine = trim($thisLine); |
| | | |
| | | $parsed = preg_split('/(?<!\\\\)' .$delimQuoted. '/', $thisLine); |
| | | //replaces escaped delimiters |
| | | $parsed = preg_replace('/\\\\' .$delimQuoted. '/', $delim, $parsed); |
| | | if ($delim != $this->options['eolDelim']) { |
| | | //replaces escape chars |
| | | $parsed = preg_replace('/\\\\/', '', $parsed); |
| | | } |
| | | return $parsed; |
| | | } |
| | | // }}} |
| | | } |
| | | |
| | | class MDB2_Result_querysim 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($this->result)) { |
| | | $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | return $err; |
| | | } |
| | | if (!is_null($rownum)) { |
| | | $seek = $this->seek($rownum); |
| | | if (PEAR::isError($seek)) { |
| | | return $seek; |
| | | } |
| | | } |
| | | $target_rownum = $this->rownum + 1; |
| | | if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { |
| | | $fetchmode = $this->db->fetchmode; |
| | | } |
| | | if (!isset($this->result[1][$target_rownum])) { |
| | | $null = null; |
| | | return $null; |
| | | } |
| | | $row = $this->result[1][$target_rownum]; |
| | | // make row associative |
| | | if ($fetchmode & MDB2_FETCHMODE_ASSOC) { |
| | | $column_names = $this->getColumnNames(); |
| | | foreach ($column_names as $name => $i) { |
| | | $column_names[$name] = $row[$i]; |
| | | } |
| | | $row = $column_names; |
| | | } |
| | | if (($mode = ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) |
| | | + ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) |
| | | ) { |
| | | $this->db->_fixResultArrayValues($row, $mode); |
| | | } |
| | | if (!empty($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (!empty($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @access private |
| | | */ |
| | | function _getColumnNames() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'getColumnNames: resultset has already been freed'); |
| | | } |
| | | $columns = array_flip($this->result[0]); |
| | | 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() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | $cols = count($this->result[0]); |
| | | return $cols; |
| | | } |
| | | } |
| | | |
| | | class MDB2_BufferedResult_querysim extends MDB2_Result_querysim |
| | | { |
| | | // {{{ 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | $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() |
| | | { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | $rows = count($this->result[1]); |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | |
| | | class MDB2_Statement_querysim extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // vim: set et ts=4 sw=4 fdm=marker: |
| | | // +----------------------------------------------------------------------+ |
| | | // | PHP versions 4 and 5 | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | |
| | | // | Stig. S. Bakken, Lukas Smith | |
| | | // | All rights reserved. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | |
| | | // | API as well as database abstraction for PHP applications. | |
| | | // | This LICENSE is in the BSD license style. | |
| | | // | | |
| | | // | Redistribution and use in source and binary forms, with or without | |
| | | // | modification, are permitted provided that the following conditions | |
| | | // | are met: | |
| | | // | | |
| | | // | Redistributions of source code must retain the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer. | |
| | | // | | |
| | | // | Redistributions in binary form must reproduce the above copyright | |
| | | // | notice, this list of conditions and the following disclaimer in the | |
| | | // | documentation and/or other materials provided with the distribution. | |
| | | // | | |
| | | // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | |
| | | // | Lukas Smith nor the names of his contributors may be used to endorse | |
| | | // | or promote products derived from this software without specific prior| |
| | | // | written permission. | |
| | | // | | |
| | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| | | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| | | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| | | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| | | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| |
| | | // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| | | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| | | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| |
| | | // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| | | // | POSSIBILITY OF SUCH DAMAGE. | |
| | | // +----------------------------------------------------------------------+ |
| | | // | Author: Lukas Smith <smith@backendmedia.com> | |
| | | // +----------------------------------------------------------------------+ |
| | | // |
| | | // $Id$ |
| | | // |
| | | |
| | | /** |
| | | * MDB2 SQLite driver |
| | | * |
| | | * @package MDB2 |
| | | * @category Database |
| | | * @author Lukas Smith <smith@backendmedia.com> |
| | | */ |
| | | class MDB2_Driver_sqlite extends MDB2_Driver_Common |
| | | { |
| | | // {{{ properties |
| | | var $escape_quotes = "'"; |
| | | |
| | | var $_lasterror = ''; |
| | | |
| | | // }}} |
| | | // {{{ constructor |
| | | |
| | | /** |
| | | * Constructor |
| | | */ |
| | | function __construct() |
| | | { |
| | | parent::__construct(); |
| | | |
| | | $this->phptype = 'sqlite'; |
| | | $this->dbsyntax = 'sqlite'; |
| | | |
| | | $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['current_id'] = true; |
| | | $this->supported['limit_queries'] = true; |
| | | $this->supported['LOBs'] = true; |
| | | $this->supported['replace'] = true; |
| | | $this->supported['transactions'] = true; |
| | | $this->supported['sub_selects'] = true; |
| | | $this->supported['auto_increment'] = true; |
| | | |
| | | $this->options['base_transaction_name'] = '___php_MDB2_sqlite_auto_commit_off'; |
| | | $this->options['fixed_float'] = 0; |
| | | $this->options['database_path'] = ''; |
| | | $this->options['database_extension'] = ''; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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 = @sqlite_error_string($native_code); |
| | | |
| | | 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, |
| | | '/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, $this->_lasterror)) { |
| | | $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 $text the input string to quote |
| | | * @return string quoted string |
| | | * @access public |
| | | */ |
| | | function escape($text) |
| | | { |
| | | return @sqlite_escape_string($text); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ beginTransaction() |
| | | |
| | | /** |
| | | * Start a transaction. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function beginTransaction() |
| | | { |
| | | $this->debug('starting transaction', 'beginTransaction'); |
| | | 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. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function commit() |
| | | { |
| | | $this->debug('commit transaction', 'commit'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'commit: transaction changes are being auto committed'); |
| | | } |
| | | $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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ rollback() |
| | | |
| | | /** |
| | | * Cancel any database changes done during a transaction that is in |
| | | * progress. |
| | | * |
| | | * @return mixed MDB2_OK on success, a MDB2 error on failure |
| | | * @access public |
| | | */ |
| | | function rollback() |
| | | { |
| | | $this->debug('rolling back transaction', 'rollback'); |
| | | if (!$this->in_transaction) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'rollback: transactions can not be rolled back when changes are auto committed'); |
| | | } |
| | | $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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getDatabaseFile() |
| | | |
| | | /** |
| | | * Builds the string with path+dbname+extension |
| | | * |
| | | * @return string full database path+file |
| | | * @access protected |
| | | */ |
| | | function _getDatabaseFile($database_name) |
| | | { |
| | | if ($database_name == '') { |
| | | 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 |
| | | && $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, |
| | | 'connect: extension '.$this->phptype.' is not compiled into PHP'); |
| | | } |
| | | |
| | | if (!empty($this->database_name)) { |
| | | if (!file_exists($database_file)) { |
| | | if (!touch($database_file)) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND); |
| | | } |
| | | 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); |
| | | } |
| | | if (!file_exists($database_file)) { |
| | | return $this->raiseError(MDB2_ERROR_NOT_FOUND); |
| | | } |
| | | } |
| | | if (!is_file($database_file)) { |
| | | return $this->raiseError(MDB2_ERROR_INVALID); |
| | | } |
| | | if (!is_readable($database_file)) { |
| | | return $this->raiseError(MDB2_ERROR_ACCESS_VIOLATION); |
| | | } |
| | | |
| | | $connect_function = ($this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open'); |
| | | $php_errormsg = ''; |
| | | @ini_set('track_errors', true); |
| | | $connection = @$connect_function($database_file); |
| | | @ini_restore('track_errors'); |
| | | $this->_lasterror = isset($php_errormsg) ? $php_errormsg : ''; |
| | | if (!$connection) { |
| | | return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); |
| | | } |
| | | $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; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ disconnect() |
| | | |
| | | /** |
| | | * Log out and disconnect from the database. |
| | | * |
| | | * @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->opened_persistent || $force) { |
| | | @sqlite_close($this->connection); |
| | | } |
| | | $this->connection = 0; |
| | | } |
| | | return MDB2_OK; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _doQuery() |
| | | |
| | | /** |
| | | * Execute a query |
| | | * @param string $query query |
| | | * @param boolean $isManip if the query is a manipulation query |
| | | * @param resource $connection |
| | | * @param string $database_name |
| | | * @return result or error object |
| | | * @access protected |
| | | */ |
| | | function _doQuery($query, $isManip = false, $connection = null, $database_name = null) |
| | | { |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | if ($this->options['disable_query']) { |
| | | if ($isManip) { |
| | | return MDB2_OK; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | if (is_null($connection)) { |
| | | $error = $this->connect(); |
| | | if (PEAR::isError($error)) { |
| | | return $error; |
| | | } |
| | | $connection = $this->connection; |
| | | } |
| | | |
| | | $function = $this->options['result_buffering'] |
| | | ? 'sqlite_query' : 'sqlite_unbuffered_query'; |
| | | $php_errormsg = ''; |
| | | ini_set('track_errors', true); |
| | | $result = @$function($query.';', $connection); |
| | | ini_restore('track_errors'); |
| | | $this->_lasterror = isset($php_errormsg) ? $php_errormsg : ''; |
| | | |
| | | if (!$result) { |
| | | return $this->raiseError(); |
| | | } |
| | | |
| | | if ($isManip) { |
| | | return @sqlite_changes($connection); |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _modifyQuery() |
| | | |
| | | /** |
| | | * Changes a query string for various DBMS specific reasons |
| | | * |
| | | * @param string $query query to modify |
| | | * @return the new (modified) query |
| | | * @access protected |
| | | */ |
| | | function _modifyQuery($query, $isManip, $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 ($isManip) { |
| | | $query .= " LIMIT $limit"; |
| | | } else { |
| | | $query .= " LIMIT $offset,$limit"; |
| | | } |
| | | } |
| | | return $query; |
| | | } |
| | | |
| | | |
| | | // }}} |
| | | // {{{ 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 REPLACE query just updates its values instead of |
| | | * inserting a new row. |
| | | * |
| | | * 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 .= $name; |
| | | if (isset($fields[$name]['null']) && $fields[$name]['null']) { |
| | | $value = 'NULL'; |
| | | } else { |
| | | $value = $this->quote($fields[$name]['value'], $fields[$name]['type']); |
| | | } |
| | | $values .= $value; |
| | | if (isset($fields[$name]['key']) && $fields[$name]['key']) { |
| | | if ($value === 'NULL') { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: key value '.$name.' may not be NULL'); |
| | | } |
| | | $keys++; |
| | | } |
| | | } |
| | | if ($keys == 0) { |
| | | return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, |
| | | 'replace: not specified which fields are keys'); |
| | | } |
| | | $query = "REPLACE INTO $table ($query) VALUES ($values)"; |
| | | $this->last_query = $query; |
| | | $this->debug($query, 'query'); |
| | | return $this->_doQuery($query, true); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ nextID() |
| | | |
| | | /** |
| | | * returns the next free id of a sequence |
| | | * |
| | | * @param string $seq_name name of the sequence |
| | | * @param boolean $ondemand when true the seqence 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->getSequenceName($seq_name); |
| | | $query = "INSERT INTO $sequence_name (".$this->options['seqcol_name'].") VALUES (NULL)"; |
| | | $this->expectError(MDB2_ERROR_NOSUCHTABLE); |
| | | $result = $this->_doQuery($query, true); |
| | | $this->popExpect(); |
| | | if (PEAR::isError($result)) { |
| | | if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { |
| | | $this->loadModule('Manager'); |
| | | // Since we are creating the sequence on demand |
| | | // we know the first id = 1 so initialize the |
| | | // sequence at 2 |
| | | $result = $this->manager->createSequence($seq_name, 2); |
| | | if (PEAR::isError($result)) { |
| | | return $this->raiseError(MDB2_ERROR, null, null, |
| | | 'nextID: on demand sequence '.$seq_name.' could not be created'); |
| | | } else { |
| | | // First ID of a newly created sequence is 1 |
| | | return 1; |
| | | } |
| | | } |
| | | return $result; |
| | | } |
| | | $value = @sqlite_last_insert_rowid($this->connection); |
| | | if (is_numeric($value) |
| | | && PEAR::isError($this->_doQuery("DELETE FROM $sequence_name WHERE ".$this->options['seqcol_name']." < $value", true)) |
| | | ) { |
| | | $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; |
| | | } |
| | | return $value; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getAfterID() |
| | | |
| | | /** |
| | | * returns the autoincrement ID if supported or $id |
| | | * |
| | | * @param mixed $id value as returned by getBeforeId() |
| | | * @param string $table name of the table into which a new row was inserted |
| | | * @return mixed MDB2 Error Object or id |
| | | * @access public |
| | | */ |
| | | function getAfterID($id, $table) |
| | | { |
| | | $this->loadModule('Native'); |
| | | return $this->native->getInsertID(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ 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->getSequenceName($seq_name); |
| | | return $this->queryOne("SELECT MAX(".$this->options['seqcol_name'].") FROM $sequence_name", 'integer'); |
| | | } |
| | | } |
| | | |
| | | 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_LOWERCASE |
| | | ) { |
| | | $row = array_change_key_case($row, CASE_LOWER); |
| | | } |
| | | } else { |
| | | $row = @sqlite_fetch_array($this->result, SQLITE_NUM); |
| | | } |
| | | if (!$row) { |
| | | if (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'fetchRow: resultset has already been freed'); |
| | | } |
| | | return null; |
| | | } |
| | | if ($this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) { |
| | | $this->db->_convertEmptyArrayValuesToNull($row); |
| | | } |
| | | if (isset($this->values)) { |
| | | $this->_assignBindColumns($row); |
| | | } |
| | | if (isset($this->types)) { |
| | | $row = $this->db->datatype->convertResultRow($this->types, $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 an associative array variable |
| | | * that will hold the names of columns. The |
| | | * indexes of the array are the column names |
| | | * mapped to lower case and the values are the |
| | | * respective numbers of the columns starting |
| | | * from 0. Some DBMS may not return any |
| | | * columns when the result set does not |
| | | * contain any rows. |
| | | * |
| | | * a MDB2 error on failure |
| | | * @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_LOWERCASE) { |
| | | $columns = array_change_key_case($columns, CASE_LOWER); |
| | | } |
| | | 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numCols: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(); |
| | | } |
| | | return $cols; |
| | | } |
| | | } |
| | | |
| | | 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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'seek: resultset has already been freed'); |
| | | } |
| | | return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, |
| | | 'seek: tried to seek to an invalid row number ('.$rownum.')'); |
| | | } |
| | | $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 (is_null($this->result)) { |
| | | return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, |
| | | 'numRows: resultset has already been freed'); |
| | | } |
| | | return $this->raiseError(); |
| | | } |
| | | return $rows; |
| | | } |
| | | } |
| | | |
| | | class MDB2_Statement_sqlite extends MDB2_Statement_Common |
| | | { |
| | | |
| | | } |
| | | |
| | | ?> |