added all mdb2 drivers
parent
4518342eca
commit
c9462d0c1e
@ -0,0 +1,555 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,659 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,521 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,568 @@
|
|||||||
|
<?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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,607 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,863 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,506 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,609 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,684 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,475 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
?>
|
@ -0,0 +1,749 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,673 @@
|
|||||||
|
<?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;
|
||||||
|
}}
|
||||||
|
?>
|
@ -0,0 +1,570 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,375 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,58 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,80 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,89 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,157 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,238 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,269 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,368 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,178 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,356 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,308 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,695 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,766 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,771 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -0,0 +1,684 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,805 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
Loading…
Reference in New Issue