added all mdb2 drivers

release-0.6
svncommit 19 years ago
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…
Cancel
Save