diff --git a/htdocs/includes/pear/MDB2/Driver/Datatype/Common.php b/htdocs/includes/pear/MDB2/Driver/Datatype/Common.php index 1906a0f1c12..9e57bc08bb8 100644 --- a/htdocs/includes/pear/MDB2/Driver/Datatype/Common.php +++ b/htdocs/includes/pear/MDB2/Driver/Datatype/Common.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -44,8 +44,7 @@ // // $Id$ -//require_once 'MDB2/LOB.php'; -require_once PEAR_PATH."/MDB2/LOB.php"; +require_once 'MDB2/LOB.php'; /** * @package MDB2 @@ -129,7 +128,7 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common * function is not called, the type of all result set columns is assumed * to be text, thus leading to not perform any conversions. * - * @param string $types array variable that lists the + * @param array $types array variable that lists the * data types to be expected in the result set columns. If this array * contains less types than the number of columns that are returned * in the result set, the remaining columns are assumed to be of the @@ -160,11 +159,12 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common // {{{ _baseConvertResult() /** - * general type conversion method + * General type conversion method * - * @param mixed $value refernce to a value to be converted - * @param string $type specifies which type to convert to - * @return object a MDB2 error on failure + * @param mixed $value reference to a value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return object an MDB2 error on failure * @access protected */ function _baseConvertResult($value, $type, $rtrim = true) @@ -219,11 +219,11 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common // {{{ convertResult() /** - * convert a value to a RDBMS indepdenant MDB2 type + * Convert a value to a RDBMS indipendent MDB2 type * - * @param mixed $value value to be converted - * @param string $type specifies which type to convert to - * @param bool $rtrim if to rtrim text values or not + * @param mixed $value value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text * @return mixed converted value * @access public */ @@ -250,34 +250,22 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common // {{{ convertResultRow() /** - * convert a result row + * Convert a result row * - * @param array $types - * @param array $row specifies the types to convert to - * @param bool $rtrim if to rtrim text values or not - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @param array $types + * @param array $row specifies the types to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return mixed MDB2_OK on success, an MDB2 error on failure * @access public */ function convertResultRow($types, $row, $rtrim = true) { - reset($types); - $current_column = -1; + $types = $this->_sortResultFieldTypes(array_keys($row), $types); foreach ($row as $key => $value) { - ++$current_column; - if (!isset($value)) { + if (empty($types[$key])) { continue; } - if (isset($types[$current_column])) { - $type = $types[$current_column]; - } elseif (isset($types[$key])) { - $type = $types[$key]; - } elseif (current($types)) { - $type = current($types); - next($types); - } else { - continue; - } - $value = $this->convertResult($row[$key], $type, $rtrim); + $value = $this->convertResult($row[$key], $types[$key], $rtrim); if (PEAR::isError($value)) { return $value; } @@ -286,6 +274,51 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common return $row; } + // }}} + // {{{ _sortResultFieldTypes() + + /** + * convert a result row + * + * @param array $types + * @param array $row specifies the types to convert to + * @param bool $rtrim if to rtrim text values or not + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function _sortResultFieldTypes($columns, $types) + { + $n_cols = count($columns); + $n_types = count($types); + if ($n_cols > $n_types) { + for ($i= $n_cols - $n_types; $i >= 0; $i--) { + $types[] = null; + } + } + $sorted_types = array(); + foreach ($columns as $col) { + $sorted_types[$col] = null; + } + foreach ($types as $name => $type) { + if (array_key_exists($name, $sorted_types)) { + $sorted_types[$name] = $type; + unset($types[$name]); + } + } + // if there are left types in the array, fill the null values of the + // sorted array with them, in order. + if (count($types)) { + reset($types); + foreach (array_keys($sorted_types) as $k) { + if (is_null($sorted_types[$k])) { + $sorted_types[$k] = current($types); + next($types); + } + } + } + return $sorted_types; + } + // }}} // {{{ getDeclaration() @@ -313,6 +346,7 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common $parameter = array('type' => $type, 'name' => $name, 'field' => $field); return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); } + $field['type'] = $type; } if (!method_exists($this, "_get{$type}Declaration")) { @@ -411,7 +445,7 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common * collation * Text value with the default COLLATION for this field. * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. + * declare the specified field, or a MDB2_Error on failure * @access protected */ function _getDeclaration($name, $field) @@ -421,11 +455,58 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common return $db; } + $name = $db->quoteIdentifier($name, true); + $declaration_options = $db->datatype->_getDeclarationOptions($field); + if (PEAR::isError($declaration_options)) { + return $declaration_options; + } + return $name.' '.$this->getTypeDeclaration($field).$declaration_options; + } + + // }}} + // {{{ _getDeclarationOptions() + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statement like CREATE TABLE, without the field name + * and type values (ie. just the character set, default value, if the + * field is permitted to be NULL or not, and the collation options). + * + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Text value to be used as default for this field. + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field's options. + * @access protected + */ + function _getDeclarationOptions($field) + { + $charset = empty($field['charset']) ? '' : + ' '.$this->_getCharsetFieldDeclaration($field['charset']); + $default = ''; if (array_key_exists('default', $field)) { if ($field['default'] === '') { - $field['default'] = empty($field['notnull']) - ? null : $this->valid_default_values[$field['type']]; + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (empty($field['notnull'])) { + $field['default'] = null; + } else { + $valid_default_values = $this->getValidTypes(); + $field['default'] = $valid_default_values[$field['type']]; + } if ($field['default'] === '' && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) ) { @@ -437,15 +518,11 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common $default = ' DEFAULT NULL'; } - $charset = empty($field['charset']) ? '' : - ' '.$this->_getCharsetFieldDeclaration($field['charset']); + $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; $collation = empty($field['collation']) ? '' : ' '.$this->_getCollationFieldDeclaration($field['collation']); - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$charset.$default.$notnull.$collation; + return $charset.$default.$notnull.$collation; } // }}} @@ -805,7 +882,11 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common if (PEAR::isError($db)) { return $db; } - + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('current' => $current, 'previous' => $previous); + $change = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + return $change; + } return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'type "'.$current['type'].'" is not yet supported', __FUNCTION__); } @@ -1146,6 +1227,9 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common } $value = $db->escape($value, $escape_wildcards); + if (PEAR::isError($value)) { + return $value; + } return "'".$value."'"; } @@ -1208,6 +1292,9 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common function _quoteLOB($value, $quote, $escape_wildcards) { $value = $this->_readFile($value); + if (PEAR::isError($value)) { + return $value; + } return $this->_quoteText($value, $quote, $escape_wildcards); } @@ -1399,6 +1486,7 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common function _quoteDecimal($value, $quote, $escape_wildcards) { $value = (string)$value; + $value = preg_replace('/[^\d\.,\-+eE]/', '', $value); if (preg_match('/[^.0-9]/', $value)) { if (strpos($value, ',')) { // 1000,00 @@ -1617,7 +1705,7 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common 'case insensitive LIKE matching requires passing the field name', __FUNCTION__); } $db->loadModule('Function', null, true); - $match = $db->function->lower($field).' '.'LIKE '; + $match = $db->function->lower($field).' LIKE '; break; // case sensitive case 'LIKE': @@ -1636,7 +1724,11 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common if ($operator === 'ILIKE') { $value = strtolower($value); } - $match.= $db->escapePattern($db->escape($value)); + $escaped = $db->escape($value); + if (PEAR::isError($escaped)) { + return $escaped; + } + $match.= $db->escapePattern($escaped); } } $match.= "'"; @@ -1681,6 +1773,35 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common return $db; } + // If the user has specified an option to map the native field + // type to a custom MDB2 datatype... + $db_type = strtok($field['type'], '(), '); + if (!empty($db->options['nativetype_map_callback'][$db_type])) { + return call_user_func_array($db->options['nativetype_map_callback'][$db_type], array($db, $field)); + } + + // Otherwise perform the built-in (i.e. normal) MDB2 native type to + // MDB2 datatype conversion + return $this->_mapNativeDatatype($field); + } + + // }}} + // {{{ _mapNativeDatatype() + + /** + * Maps a native array description of a field to a MDB2 datatype and length + * + * @param array $field native field description + * @return array containing the various possible types, length, sign, fixed + * @access public + */ + function _mapNativeDatatype($field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'method not implemented', __FUNCTION__); } @@ -1713,5 +1834,4 @@ class MDB2_Driver_Datatype_Common extends MDB2_Module_Common return $type; } } - ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Datatype/mssql.php b/htdocs/includes/pear/MDB2/Driver/Datatype/mssql.php index 837e388d9a7..5b5f417f6b5 100644 --- a/htdocs/includes/pear/MDB2/Driver/Datatype/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/Datatype/mssql.php @@ -3,7 +3,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -40,15 +40,14 @@ // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | // | POSSIBILITY OF SUCH DAMAGE. | // +----------------------------------------------------------------------+ -// | Authors: Lukas Smith | +// | Authors: Lukas Smith | // | Daniel Convissor | // +----------------------------------------------------------------------+ // // $Id$ // -//require_once 'MDB2/Driver/Datatype/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Datatype/Common.php"; +require_once 'MDB2/Driver/Datatype/Common.php'; /** * MDB2 MS SQL driver @@ -59,17 +58,18 @@ require_once PEAR_PATH."/MDB2/Driver/Datatype/Common.php"; */ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common { - // {{{ convertResult() + // {{{ _baseConvertResult() /** - * convert a value to a RDBMS indepdenant MDB2 type + * general type conversion method * - * @param mixed $value value to be converted - * @param int $type constant that specifies which type to convert to - * @return mixed converted value - * @access public + * @param mixed $value refernce to a value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return object a MDB2 error on failure + * @access protected */ - function convertResult($value, $type) + function _baseConvertResult($value, $type, $rtrim = true) { if (is_null($value)) { return null; @@ -87,9 +87,8 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common $value = substr($value,11,8); } return $value; - default: - return $this->_baseConvertResult($value,$type); } + return parent::_baseConvertResult($value, $type, $rtrim); } // }}} // {{{ getTypeDeclaration() @@ -161,11 +160,205 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common return 'FLOAT'; case 'decimal': $length = !empty($field['length']) ? $field['length'] : 18; - return 'DECIMAL('.$length.','.$db->options['decimal_places'].')'; + $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places']; + return 'DECIMAL('.$length.','.$scale.')'; } return ''; } + // }}} + // {{{ _getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDeclarationOptions($field) + { + $charset = empty($field['charset']) ? '' : + ' '.$this->_getCharsetFieldDeclaration($field['charset']); + + $default = ''; + if (array_key_exists('default', $field)) { + if ($field['default'] === '') { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $field['default'] = empty($field['notnull']) + ? null : $this->valid_default_values[$field['type']]; + if ($field['default'] === '' + && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) + ) { + $field['default'] = ' '; + } + } + $default = ' DEFAULT '.$this->quote($field['default'], $field['type']); + } elseif (empty($field['notnull'])) { + $default = ' DEFAULT NULL'; + } + + $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL'; + if ($default == ' DEFAULT NULL' && $notnull == ' NULL') { + $notnull = ''; + } + + $collation = empty($field['collation']) ? '' : + ' '.$this->_getCollationFieldDeclaration($field['collation']); + return $charset.$default.$notnull.$collation; + } + + // }}} + // {{{ _getIntegerDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an integer type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param string $field associative array with the name of the properties + * of the field being declared as array indexes. + * Currently, the types of supported field + * properties are as follows: + * + * unsigned + * Boolean flag that indicates whether the field + * should be declared as unsigned integer if + * possible. + * + * default + * Integer value to be used as default for this + * field. + * + * notnull + * Boolean flag that indicates whether this field is + * constrained to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getIntegerDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $default = $autoinc = '';; + if (!empty($field['autoincrement'])) { + $autoinc = ' IDENTITY PRIMARY KEY'; + } elseif (array_key_exists('default', $field)) { + if ($field['default'] === '') { + $field['default'] = empty($field['notnull']) ? null : 0; + } + $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); + } elseif (empty($field['notnull'])) { + $default = ' DEFAULT NULL'; + } + + $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL'; + if ($default == ' DEFAULT NULL' && $notnull == ' NULL') { + $notnull = ''; + } + if (!empty($field['unsigned'])) { + $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; + } + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$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 array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function _getCLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL'; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + + // }}} + // {{{ _getBLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an binary large + * object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL'; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + // }}} // {{{ _quoteBLOB() @@ -175,11 +368,12 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common * * @param string $value text string value that is intended to be converted. * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards * @return string text string that represents the given argument value in * a DBMS specific format. * @access protected */ - function _quoteBLOB($value, $quote) + function _quoteBLOB($value, $quote, $escape_wildcards) { if (!$quote) { return $value; @@ -189,7 +383,7 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common } // }}} - // {{{ mapNativeDatatype() + // {{{ _mapNativeDatatype() /** * Maps a native array description of a field to a MDB2 datatype and length @@ -198,13 +392,11 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common * @return array containing the various possible types, length, sign, fixed * @access public */ - function mapNativeDatatype($field) + function _mapNativeDatatype($field) { - $db_type = preg_replace('/\d/','', strtolower($field['type']) ); + // todo: handle length of various int variations + $db_type = preg_replace('/\d/', '', strtolower($field['type'])); $length = $field['length']; - if ((int)$length <= 0) { - $length = null; - } $type = array(); // todo: unsigned handling seems to be missing $unsigned = $fixed = null; @@ -212,8 +404,21 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common case 'bit': $type[0] = 'boolean'; break; + case 'tinyint': + $type[0] = 'integer'; + $length = 1; + break; + case 'smallint': + $type[0] = 'integer'; + $length = 2; + break; case 'int': $type[0] = 'integer'; + $length = 4; + break; + case 'bigint': + $type[0] = 'integer'; + $length = 8; break; case 'datetime': $type[0] = 'timestamp'; @@ -226,6 +431,7 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common case 'decimal': case 'money': $type[0] = 'decimal'; + $length = $field['numeric_precision'].','.$field['numeric_scale']; break; case 'text': case 'varchar': @@ -234,7 +440,7 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common $type[0] = 'text'; if ($length == '1') { $type[] = 'boolean'; - if (preg_match('/^[is|has]/', $field['name'])) { + if (preg_match('/^(is|has)/', $field['name'])) { $type = array_reverse($type); } } elseif (strstr($db_type, 'text')) { @@ -254,9 +460,12 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common if (PEAR::isError($db)) { return $db; } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'mapNativeDatatype: unknown database attribute type: '.$db_type); + 'unknown database attribute type: '.$db_type, __FUNCTION__); + } + + if ((int)$length <= 0) { + $length = null; } return array($type, $length, $unsigned, $fixed); @@ -264,4 +473,4 @@ class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common // }}} } -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Datatype/mysql.php b/htdocs/includes/pear/MDB2/Driver/Datatype/mysql.php index 033c27d0c64..20cd094e06e 100644 --- a/htdocs/includes/pear/MDB2/Driver/Datatype/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/Datatype/mysql.php @@ -3,7 +3,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -46,8 +46,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Datatype/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Datatype/Common.php"; +require_once 'MDB2/Driver/Datatype/Common.php'; /** * MDB2 MySQL driver @@ -225,7 +224,7 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common return $db; } - $default = $autoinc = '';; + $default = $autoinc = ''; if (!empty($field['autoincrement'])) { $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; } elseif (array_key_exists('default', $field)) { @@ -302,7 +301,7 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common } // }}} - // {{{ mapNativeDatatype() + // {{{ _mapNativeDatatype() /** * Maps a native array description of a field to a MDB2 datatype and length @@ -311,7 +310,7 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common * @return array containing the various possible types, length, sign, fixed * @access public */ - function mapNativeDatatype($field) + function _mapNativeDatatype($field) { $db_type = strtolower($field['type']); $db_type = strtok($db_type, '(), '); @@ -319,8 +318,8 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common $db_type = strtok('(), '); } if (!empty($field['length'])) { - $length = $field['length']; - $decimal = ''; + $length = strtok($field['length'], ', '); + $decimal = strtok(', '); } else { $length = strtok('(), '); $decimal = strtok('(), '); @@ -429,6 +428,9 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common case 'numeric': $type[] = 'decimal'; $unsigned = preg_match('/ unsigned/i', $field['type']); + if ($decimal !== false) { + $length = $length.','.$decimal; + } break; case 'tinyblob': case 'mediumblob': @@ -437,6 +439,10 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common $type[] = 'blob'; $length = null; break; + case 'binary': + case 'varbinary': + $type[] = 'blob'; + break; case 'year': $type[] = 'integer'; $type[] = 'date'; @@ -452,6 +458,10 @@ class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common 'unknown database attribute type: '.$db_type, __FUNCTION__); } + if ((int)$length <= 0) { + $length = null; + } + return array($type, $length, $unsigned, $fixed); } diff --git a/htdocs/includes/pear/MDB2/Driver/Datatype/mysqli.php b/htdocs/includes/pear/MDB2/Driver/Datatype/mysqli.php index 85920072cc0..6080489fcc3 100644 --- a/htdocs/includes/pear/MDB2/Driver/Datatype/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/Datatype/mysqli.php @@ -3,7 +3,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -46,8 +46,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Datatype/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Datatype/Common.php"; +require_once 'MDB2/Driver/Datatype/Common.php'; /** * MDB2 MySQLi driver @@ -225,7 +224,7 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common return $db; } - $default = $autoinc = '';; + $default = $autoinc = ''; if (!empty($field['autoincrement'])) { $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; } elseif (array_key_exists('default', $field)) { @@ -302,7 +301,7 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common } // }}} - // {{{ mapNativeDatatype() + // {{{ _mapNativeDatatype() /** * Maps a native array description of a field to a MDB2 datatype and length @@ -311,7 +310,7 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common * @return array containing the various possible types, length, sign, fixed * @access public */ - function mapNativeDatatype($field) + function _mapNativeDatatype($field) { $db_type = strtolower($field['type']); $db_type = strtok($db_type, '(), '); @@ -319,8 +318,8 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common $db_type = strtok('(), '); } if (!empty($field['length'])) { - $length = $field['length']; - $decimal = ''; + $length = strtok($field['length'], ', '); + $decimal = strtok(', '); } else { $length = strtok('(), '); $decimal = strtok('(), '); @@ -429,6 +428,9 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common case 'numeric': $type[] = 'decimal'; $unsigned = preg_match('/ unsigned/i', $field['type']); + if ($decimal !== false) { + $length = $length.','.$decimal; + } break; case 'tinyblob': case 'mediumblob': @@ -437,6 +439,10 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common $type[] = 'blob'; $length = null; break; + case 'binary': + case 'varbinary': + $type[] = 'blob'; + break; case 'year': $type[] = 'integer'; $type[] = 'date'; @@ -452,6 +458,10 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common 'unknown database attribute type: '.$db_type, __FUNCTION__); } + if ((int)$length <= 0) { + $length = null; + } + return array($type, $length, $unsigned, $fixed); } @@ -459,7 +469,7 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common // {{{ mapPrepareDatatype() /** - * Maps an mdb2 datatype to native prepare type + * Maps an MDB2 datatype to native prepare type * * @param string $type * @return string @@ -495,5 +505,4 @@ class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common // }}} } - ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Datatype/pgsql.php b/htdocs/includes/pear/MDB2/Driver/Datatype/pgsql.php index cea885af310..6e17c2fb923 100644 --- a/htdocs/includes/pear/MDB2/Driver/Datatype/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/Datatype/pgsql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -44,8 +44,7 @@ // // $Id$ -//require_once 'MDB2/Driver/Datatype/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Datatype/Common.php"; +require_once 'MDB2/Driver/Datatype/Common.php'; /** * MDB2 PostGreSQL driver @@ -59,11 +58,11 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common // {{{ _baseConvertResult() /** - * general type conversion method + * General type conversion method * - * @param mixed $value refernce to a value to be converted - * @param string $type specifies which type to convert to - * @param string $rtrim if text should be rtrimmed + * @param mixed $value refernce to a value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text * @return object a MDB2 error on failure * @access protected */ @@ -383,7 +382,7 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common } // }}} - // {{{ mapNativeDatatype() + // {{{ _mapNativeDatatype() /** * Maps a native array description of a field to a MDB2 datatype and length @@ -392,16 +391,10 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common * @return array containing the various possible types, length, sign, fixed * @access public */ - function mapNativeDatatype($field) + function _mapNativeDatatype($field) { $db_type = strtolower($field['type']); $length = $field['length']; - if ($length == '-1' && !empty($field['atttypmod'])) { - $length = $field['atttypmod'] - 4; - } - if ((int)$length <= 0) { - $length = null; - } $type = array(); $unsigned = $fixed = null; switch ($db_type) { @@ -472,6 +465,7 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common $length = null; break; case 'float': + case 'float8': case 'double': case 'real': $type[] = 'float'; @@ -480,6 +474,9 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common case 'money': case 'numeric': $type[] = 'decimal'; + if ($field['scale']) { + $length = $length.','.$field['scale']; + } break; case 'tinyblob': case 'mediumblob': @@ -504,11 +501,14 @@ class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common if (PEAR::isError($db)) { return $db; } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'unknown database attribute type: '.$db_type, __FUNCTION__); } + if ((int)$length <= 0) { + $length = null; + } + return array($type, $length, $unsigned, $fixed); } diff --git a/htdocs/includes/pear/MDB2/Driver/Function/Common.php b/htdocs/includes/pear/MDB2/Driver/Function/Common.php index afd3f87ff2e..8d675032e2c 100644 --- a/htdocs/includes/pear/MDB2/Driver/Function/Common.php +++ b/htdocs/includes/pear/MDB2/Driver/Function/Common.php @@ -205,6 +205,27 @@ class MDB2_Driver_Function_Common extends MDB2_Module_Common return "UPPER($expression)"; } + // }}} + // {{{ guid() + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + * @access public + */ + function guid() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $error; + } + // }}} } ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Function/mssql.php b/htdocs/includes/pear/MDB2/Driver/Function/mssql.php index 7cdfe35e20d..603adcde8b7 100644 --- a/htdocs/includes/pear/MDB2/Driver/Function/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/Function/mssql.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Function/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Function/Common.php"; +require_once 'MDB2/Driver/Function/Common.php'; // {{{ class MDB2_Driver_Function_mssql /** @@ -144,7 +143,21 @@ class MDB2_Driver_Function_mssql extends MDB2_Driver_Function_Common return "(".implode(' + ', $args).")"; } + // }}} + // {{{ guid() + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + * @access public + */ + function guid() + { + return 'NEWID()'; + } + // }}} } // }}} -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Function/mysql.php b/htdocs/includes/pear/MDB2/Driver/Function/mysql.php index 1705529cc1a..d03cafe563f 100644 --- a/htdocs/includes/pear/MDB2/Driver/Function/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/Function/mysql.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Function/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Function/Common.php"; +require_once 'MDB2/Driver/Function/Common.php'; /** * MDB2 MySQL driver for the function modules @@ -101,5 +100,21 @@ class MDB2_Driver_Function_mysql extends MDB2_Driver_Function_Common $args = func_get_args(); return "CONCAT(".implode(', ', $args).")"; } + + // }}} + // {{{ guid() + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + * @access public + */ + function guid() + { + return 'UUID()'; + } + + // }}} } ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Function/mysqli.php b/htdocs/includes/pear/MDB2/Driver/Function/mysqli.php index 1401cf4c2f3..c2a9eaf4aa3 100644 --- a/htdocs/includes/pear/MDB2/Driver/Function/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/Function/mysqli.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Function/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Function/Common.php"; +require_once 'MDB2/Driver/Function/Common.php'; /** * MDB2 MySQLi driver for the function modules @@ -109,5 +108,21 @@ class MDB2_Driver_Function_mysqli extends MDB2_Driver_Function_Common $args = func_get_args(); return "CONCAT(".implode(', ', $args).")"; } + + // }}} + // {{{ guid() + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + * @access public + */ + function guid() + { + return 'UUID()'; + } + + // }}} } ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Function/pgsql.php b/htdocs/includes/pear/MDB2/Driver/Function/pgsql.php index 86e035fa967..663e58afe9e 100644 --- a/htdocs/includes/pear/MDB2/Driver/Function/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/Function/pgsql.php @@ -44,8 +44,7 @@ // // $Id$ -//require_once 'MDB2/Driver/Function/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Function/Common.php"; +require_once 'MDB2/Driver/Function/Common.php'; /** * MDB2 MySQL driver for the function modules diff --git a/htdocs/includes/pear/MDB2/Driver/Manager/Common.php b/htdocs/includes/pear/MDB2/Driver/Manager/Common.php index 58f803834ef..a6880c451be 100644 --- a/htdocs/includes/pear/MDB2/Driver/Manager/Common.php +++ b/htdocs/includes/pear/MDB2/Driver/Manager/Common.php @@ -60,13 +60,12 @@ */ class MDB2_Driver_Manager_Common extends MDB2_Module_Common { - // }}} // {{{ getFieldDeclarationList() /** * Get declaration of a number of field in bulk * - * @param string $fields a multidimensional associative array. + * @param array $fields a multidimensional associative array. * The first dimension determines the field name, while the second * dimension is keyed with the name of the properties * of the field being declared as array indexes. Currently, the types @@ -93,7 +92,6 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, 'missing any fields', __FUNCTION__); } - foreach ($fields as $field_name => $field) { $query = $db->getDeclaration($field['type'], $field_name, $field); if (PEAR::isError($query)) { @@ -201,7 +199,7 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common } // }}} - // {{{ + // {{{ _getCreateTableQuery() /** * Create a basic SQL query for a new table creation @@ -235,7 +233,34 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common } $name = $db->quoteIdentifier($name, true); - return "CREATE TABLE $name ($query_fields)"; + $result = 'CREATE '; + if (!empty($options['temporary'])) { + $result .= $this->_getTemporaryTableQuery(); + } + $result .= " TABLE $name ($query_fields)"; + return $result; + } + + // }}} + // {{{ _getTemporaryTableQuery() + + /** + * A method to return the required SQL string that fits between CREATE ... TABLE + * to create the table as a temporary table. + * + * Should be overridden in driver classes to return the correct string for the + * specific database type. + * + * The default is to return the string "TEMPORARY" - this will result in a + * SQL error for any database that does not support temporary tables, or that + * requires a different SQL command from "CREATE TEMPORARY TABLE". + * + * @return string The string required to be placed between "CREATE" and "TABLE" + * to generate a temporary table, if possible. + */ + function _getTemporaryTableQuery() + { + return 'TEMPORARY'; } // }}} @@ -266,7 +291,10 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common * ) * ); * @param array $options An associative array of table options: - * + * array( + * 'comment' => 'Foo', + * 'temporary' => true|false, + * ); * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public */ @@ -414,7 +442,7 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common /** * list all databases * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of database names on success, a MDB2 error on failure * @access public */ function listDatabases() @@ -434,7 +462,7 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common /** * list all users * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of user names on success, a MDB2 error on failure * @access public */ function listUsers() @@ -455,7 +483,9 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common * list all views in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * NB: not all the drivers can get the view names from + * a database other than the current one + * @return mixed array of view names on success, a MDB2 error on failure * @access public */ function listViews($database = null) @@ -475,10 +505,10 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common /** * list the views in the database that reference a given table * - * @param string table for which all references views should be found - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @param string table for which all referenced views should be found + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listTableViews($table) { $db =& $this->getDBInstance(); @@ -492,14 +522,13 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common // }}} // {{{ listTableTriggers() + /** - * This function will be called to get all triggers of the - * current database ($db->getDatabase()) + * list all triggers in the database that reference a given table * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure * @access public - * @param string $table The name of the table from the - * previous database to query against. - * @return mixed Array on success or MDB2 error on failure */ function listTableTriggers($table = null) { @@ -511,13 +540,14 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'method not implemented', __FUNCTION__); } + // }}} // {{{ listFunctions() /** * list all functions in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of function names on success, a MDB2 error on failure * @access public */ function listFunctions() @@ -530,14 +560,17 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'method not implemented', __FUNCTION__); } + // }}} // {{{ listTables() /** * list all tables in the current database * - * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * @param string database, the current is default. + * NB: not all the drivers can get the table names from + * a database other than the current one + * @return mixed array of table names on success, a MDB2 error on failure * @access public */ function listTables($database = null) @@ -555,10 +588,10 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common // {{{ listTableFields() /** - * list all fields in a tables in the current database + * list all fields in a table 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 + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) @@ -653,8 +686,8 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common /** * 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 + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) @@ -745,8 +778,8 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common /** * list all constraints 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 + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure * @access public */ function listTableConstraints($table) @@ -810,7 +843,9 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common * list all sequences in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * NB: not all the drivers can get the sequence names from + * a database other than the current one + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public */ function listSequences($database = null) @@ -823,6 +858,7 @@ class MDB2_Driver_Manager_Common extends MDB2_Module_Common return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, 'method not implemented', __FUNCTION__); } -} -?> + // }}} +} +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Manager/mssql.php b/htdocs/includes/pear/MDB2/Driver/Manager/mssql.php index 3d61991c609..80b360f4f89 100644 --- a/htdocs/includes/pear/MDB2/Driver/Manager/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/Manager/mssql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -39,7 +39,9 @@ // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | // | POSSIBILITY OF SUCH DAMAGE. | // +----------------------------------------------------------------------+ -// | Author: Frank M. Kromann | +// | Authors: Frank M. Kromann | +// | David Coallier | +// | Lorenzo Alberton | // +----------------------------------------------------------------------+ // // $Id$ @@ -48,6 +50,7 @@ require_once 'MDB2/Driver/Manager/Common.php'; // {{{ class MDB2_Driver_Manager_mssql + /** * MDB2 MSSQL driver for the management modules * @@ -55,6 +58,7 @@ require_once 'MDB2/Driver/Manager/Common.php'; * @category Database * @author Frank M. Kromann * @author David Coallier + * @author Lorenzo Alberton */ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common { @@ -82,6 +86,7 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return $db->standaloneQuery($query, null, true); } + // }}} // {{{ dropDatabase() @@ -103,6 +108,66 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common return $db->standaloneQuery("DROP DATABASE $name", null, true); } + // }}} + // {{{ _getTemporaryTableQuery() + + /** + * Override the parent method. + * + * @return string The string required to be placed between "CREATE" and "TABLE" + * to generate a temporary table, if possible. + */ + function _getTemporaryTableQuery() + { + return ''; + } + + // }}} + // {{{ 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, + * ) + * ); + * @param array $options An associative array of table options: + * array( + * 'comment' => 'Foo', + * 'temporary' => true|false, + * ); + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createTable($name, $fields, $options = array()) + { + if (!empty($options['temporary'])) { + $name = '#'.$name; + } + return parent::createTable($name, $fields, $options); + } + // }}} // {{{ alterTable() @@ -124,7 +189,7 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common * 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. + * be the same as defined by the MDB2 parser. * * * remove @@ -153,7 +218,7 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common * 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. + * as defined by the MDB2 parser. * * Example * array( @@ -214,7 +279,7 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common case 'change': default: return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, - 'alterTable: change type "'.$change_name.'" not yet supported'); + 'change type "'.$change_name.'" not yet supported', __FUNCTION__); } } @@ -227,8 +292,10 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common foreach ($changes['add'] as $field_name => $field) { if ($query) { $query.= ', '; + } else { + $query.= 'ADD COLUMN '; } - $query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field); + $query.= $db->getDeclaration($field['type'], $field_name, $field); } } @@ -249,12 +316,14 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common $name = $db->quoteIdentifier($name, true); return $db->exec("ALTER TABLE $name $query"); } + // }}} // {{{ listTables() + /** * list all tables in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of table names on success, a MDB2 error on failure * @access public */ function listTables() @@ -282,13 +351,15 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return $result; } + // }}} // {{{ listTableFields() + /** - * list all fields in a tables in the current database + * list all fields in a table 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 + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) @@ -311,14 +382,15 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return array_flip($result); } + // }}} // {{{ listTableIndexes() /** * list all indexes in a table * - * @param string $table name of table that should be used in method - * @return mixed data array on success, a MDB2 error on failure + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) @@ -349,8 +421,8 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common $pk_all = $db->queryCol($query, 'text', $pk_name); $result = array(); foreach ($indexes as $index) { - if (!in_array($index, $pk_all) && $index != null) { - $result[$this->_fixIndexName($index)] = true; + if (!in_array($index, $pk_all) && ($index = $this->_fixIndexName($index))) { + $result[$index] = true; } } @@ -361,21 +433,105 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } // }}} - // {{{ listTableTriggers() + // {{{ listDatabases() + /** - * This function will be called to - * display all the triggers from the current - * database ($db->getDatabase()). + * list all databases * + * @return mixed array of database names on success, a MDB2 error on failure + * @access public + */ + function listDatabases() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->queryCol('SELECT name FROM sys.databases'); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listUsers() + + /** + * list all users + * + * @return mixed array of user names on success, a MDB2 error on failure + * @access public + */ + function listUsers() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->queryCol('SELECT DISTINCT loginame FROM master..sysprocesses'); + if (PEAR::isError($result) || empty($result)) { + return $result; + } + foreach (array_keys($result) as $k) { + $result[$k] = trim($result[$k]); + } + return $result; + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed array of function names on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT name + FROM sysobjects + WHERE objectproperty(id, N'IsMSShipped') = 0 + AND (objectproperty(id, N'IsTableFunction') = 1 + OR objectproperty(id, N'IsScalarFunction') = 1)"; + /* + SELECT ROUTINE_NAME + FROM INFORMATION_SCHEMA.ROUTINES + WHERE ROUTINE_TYPE = 'FUNCTION' + */ + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, otherwise, false which + * could be a db error if the db is not instantiated or could + * be the results of the error that occured during the + * querying of the sysobject module. * @access public - * @param string $table The name of the table from the - * previous database to query against. - * @return mixed Array of the triggers if the query - * is successful, otherwise, false which - * could be a db error if the db is not - * instantiated or could be the results - * of the error that occured during the - * query'ing of the sysobject module. */ function listTableTriggers($table = null) { @@ -385,13 +541,16 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } $table = $db->quote($table, 'text'); - $query = "SELECT name FROM sysobjects WHERE xtype = 'TR'"; + $query = "SELECT o.name + FROM sysobjects o + WHERE xtype = 'TR' + AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0"; if (!is_null($table)) { - $query .= "AND object_name(parent_obj) = $table"; + $query .= " AND object_name(parent_obj) = $table"; } $result = $db->queryCol($query); - if (PEAR::isError($results)) { + if (PEAR::isError($result)) { return $result; } @@ -403,15 +562,16 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return $result; } + // }}} // {{{ listViews() + /** - * This function is a simple method that lists - * all the views that are set on a db instance - * (The db connected to it) + * list all views in the current database * + * @param string database, the current is default + * @return mixed array of view names on success, a MDB2 error on failure * @access public - * @return mixed Error on failure or array of views for a database. */ function listViews() { @@ -423,9 +583,15 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common $query = "SELECT name FROM sysobjects WHERE xtype = 'V'"; + /* + SELECT * + FROM sysobjects + WHERE objectproperty(id, N'IsMSShipped') = 0 + AND objectproperty(id, N'IsView') = 1 + */ $result = $db->queryCol($query); - if (PEAR::isError($results)) { + if (PEAR::isError($result)) { return $result; } @@ -437,8 +603,74 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return $result; } + + // }}} + // {{{ dropIndex() + + /** + * drop existing index + * + * @param string $table name of table that should be used in method + * @param string $name name of the index to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropIndex($table, $name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + return $db->exec("DROP INDEX $table.$name"); + } + + // }}} + // {{{ listTableConstraints() + + /** + * list all constraints in a table + * + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure + * @access public + */ + function listTableConstraints($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $table = $db->quoteIdentifier($table, true); + + $query = "SELECT c.constraint_name + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS c + WHERE c.constraint_catalog = DB_NAME() + AND c.table_name = '$table'"; + $constraints = $db->queryCol($query); + if (PEAR::isError($constraints)) { + return $constraints; + } + + $result = array(); + foreach ($constraints as $constraint) { + $constraint = $this->_fixIndexName($constraint); + if (!empty($constraint)) { + $result[$constraint] = true; + } + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_change_key_case($result, $db->options['field_case']); + } + return array_keys($result); + } + // }}} // {{{ createSequence() + /** * create sequence * @@ -464,11 +696,6 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common 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->exec($query); @@ -480,14 +707,16 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common $result = $db->exec("DROP TABLE $sequence_name"); if (PEAR::isError($result)) { return $db->raiseError($result, null, null, - 'createSequence: could not drop inconsistent sequence table'); + 'could not drop inconsistent sequence table', __FUNCTION__); } return $db->raiseError($res, null, null, - 'createSequence: could not create sequence table'); + 'could not create sequence table', __FUNCTION__); } + // }}} // {{{ dropSequence() + /** * This function drops an existing sequence * @@ -505,12 +734,14 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); return $db->exec("DROP TABLE $sequence_name"); } + // }}} // {{{ listSequences() + /** * list all sequences in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public */ function listSequences() @@ -537,7 +768,9 @@ class MDB2_Driver_Manager_mssql extends MDB2_Driver_Manager_Common } return $result; } + // }}} } + // }}} -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Manager/mysql.php b/htdocs/includes/pear/MDB2/Driver/Manager/mysql.php index 1ca10be27ba..6b8516ea6ba 100644 --- a/htdocs/includes/pear/MDB2/Driver/Manager/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/Manager/mysql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -139,8 +139,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common * @param array $options An associative array of table options: * array( * 'comment' => 'Foo', - * 'character_set' => 'utf8', - * 'collate' => 'utf8_unicode_ci', + * 'charset' => 'utf8', * 'collate' => 'utf8_unicode_ci', * 'type' => 'innodb', * ); @@ -154,6 +153,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common if (PEAR::isError($db)) { return $db; } + $query = $this->_getCreateTableQuery($name, $fields, $options); if (PEAR::isError($query)) { return $query; @@ -183,7 +183,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common } if (!empty($options_strings)) { - $query.= ' '.implode(' ', $options_strings); + $query .= ' '.implode(' ', $options_strings); } return $db->exec($query); } @@ -379,7 +379,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * list all databases * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of database names on success, a MDB2 error on failure * @access public */ function listDatabases() @@ -405,7 +405,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * list all users * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of user names on success, a MDB2 error on failure * @access public */ function listUsers() @@ -415,7 +415,71 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common return $db; } - return $db->queryCol('SELECT DISTINCT USER FROM USER'); + return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER'); + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed array of function names on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT name FROM mysql.proc"; + /* + SELECT ROUTINE_NAME + FROM INFORMATION_SCHEMA.ROUTINES + WHERE ROUTINE_TYPE = 'FUNCTION' + */ + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure + * @access public + */ + function listTableTriggers($table = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SHOW TRIGGERS'; + if (!is_null($table)) { + $table = $db->quote($table, 'text'); + $query .= " LIKE $table"; + } + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} @@ -425,7 +489,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common * list all tables in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of table names on success, a MDB2 error on failure * @access public */ function listTables($database = null) @@ -462,12 +526,12 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common // {{{ listViews() /** - * list the views in the database + * list all views in the current database * * @param string database, the current is default - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listViews($database = null) { $db =& $this->getDBInstance(); @@ -496,10 +560,10 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common // {{{ listTableFields() /** - * list all fields in a tables in the current database + * list all fields in a table 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 + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) @@ -608,8 +672,8 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * 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 + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) @@ -657,22 +721,22 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * create a constraint on a table * - * @param string $table name of the table on which the constraint is to be created + * @param string $table name of the table on which the constraint is to be created * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. + * @param array $definition associative array that defines properties of the constraint to be created. + * Currently, only one property named FIELDS is supported. This property + * is also an associative with the names of the constraint fields as array + * constraints. Each entry of this array is set to another type of associative + * array that specifies properties of the constraint that are specific to + * each field. * - * Example - * array( - * 'fields' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) + * Example + * array( + * 'fields' => array( + * 'user_name' => array(), + * 'last_login' => array() + * ) + * ) * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public */ @@ -691,6 +755,10 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common } elseif (!empty($definition['unique'])) { $type = 'UNIQUE'; } + if (empty($type)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'invalid definition, could not create constraint', __FUNCTION__); + } $table = $db->quoteIdentifier($table, true); $query = "ALTER TABLE $table ADD $type $name"; @@ -737,8 +805,8 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * list all constraints 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 + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure * @access public */ function listTableConstraints($table) @@ -793,12 +861,19 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common /** * create sequence * - * @param string $seq_name name of the sequence to be created - * @param string $start start value of the sequence; default is 1 + * @param string $seq_name name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @param array $options An associative array of table options: + * array( + * 'comment' => 'Foo', + * 'charset' => 'utf8', + * 'collate' => 'utf8_unicode_ci', + * 'type' => 'innodb', + * ); * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public */ - function createSequence($seq_name, $start = 1) + function createSequence($seq_name, $start = 1, $options = array()) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { @@ -807,9 +882,34 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true); + + $options_strings = array(); + + if (!empty($options['comment'])) { + $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); + } + + if (!empty($options['charset'])) { + $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; + if (!empty($options['collate'])) { + $options_strings['charset'].= ' COLLATE '.$options['collate']; + } + } + + $type = false; + if (!empty($options['type'])) { + $type = $options['type']; + } elseif ($db->options['default_table_type']) { + $type = $db->options['default_table_type']; + } + if ($type) { + $options_strings[] = "ENGINE = $type"; + } $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))"; - $query.= strlen($db->options['default_table_type']) ? ' TYPE='.$db->options['default_table_type'] : ''; + if (!empty($options_strings)) { + $query .= ' '.implode(' ', $options_strings); + } $res = $db->exec($query); if (PEAR::isError($res)) { @@ -865,7 +965,7 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common * list all sequences in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public */ function listSequences($database = null) @@ -898,4 +998,4 @@ class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common // }}} } -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Manager/mysqli.php b/htdocs/includes/pear/MDB2/Driver/Manager/mysqli.php index 5490e9ddb2b..05b26894e83 100644 --- a/htdocs/includes/pear/MDB2/Driver/Manager/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/Manager/mysqli.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -139,8 +139,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common * @param array $options An associative array of table options: * array( * 'comment' => 'Foo', - * 'character_set' => 'utf8', - * 'collate' => 'utf8_unicode_ci', + * 'charset' => 'utf8', * 'collate' => 'utf8_unicode_ci', * 'type' => 'innodb', * ); @@ -184,7 +183,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common } if (!empty($options_strings)) { - $query.= ' '.implode(' ', $options_strings); + $query .= ' '.implode(' ', $options_strings); } return $db->exec($query); } @@ -380,7 +379,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common /** * list all databases * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of database names on success, a MDB2 error on failure * @access public */ function listDatabases() @@ -406,7 +405,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common /** * list all users * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of user names on success, a MDB2 error on failure * @access public */ function listUsers() @@ -416,7 +415,71 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common return $db; } - return $db->queryCol('SELECT DISTINCT USER FROM USER'); + return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER'); + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed array of function names on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT name FROM mysql.proc"; + /* + SELECT ROUTINE_NAME + FROM INFORMATION_SCHEMA.ROUTINES + WHERE ROUTINE_TYPE = 'FUNCTION' + */ + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure + * @access public + */ + function listTableTriggers($table = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SHOW TRIGGERS'; + if (!is_null($table)) { + $table = $db->quote($table, 'text'); + $query .= " LIKE $table"; + } + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} @@ -426,7 +489,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common * list all tables in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of table names on success, a MDB2 error on failure * @access public */ function listTables($database = null) @@ -463,12 +526,12 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common // {{{ listViews() /** - * list the views in the database + * list all views in the current database * * @param string database, the current is default - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listViews($database = null) { $db =& $this->getDBInstance(); @@ -497,10 +560,10 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common // {{{ listTableFields() /** - * list all fields in a tables in the current database + * list all fields in a table 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 + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) @@ -609,8 +672,8 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common /** * 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 + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) @@ -692,6 +755,10 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common } elseif (!empty($definition['unique'])) { $type = 'UNIQUE'; } + if (empty($type)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'invalid definition, could not create constraint', __FUNCTION__); + } $table = $db->quoteIdentifier($table, true); $query = "ALTER TABLE $table ADD $type $name"; @@ -738,8 +805,8 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common /** * list all constraints 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 + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure * @access public */ function listTableConstraints($table) @@ -794,12 +861,19 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common /** * create sequence * - * @param string $seq_name name of the sequence to be created - * @param string $start start value of the sequence; default is 1 + * @param string $seq_name name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @param array $options An associative array of table options: + * array( + * 'comment' => 'Foo', + * 'charset' => 'utf8', + * 'collate' => 'utf8_unicode_ci', + * 'type' => 'innodb', + * ); * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public */ - function createSequence($seq_name, $start = 1) + function createSequence($seq_name, $start = 1, $options = array()) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { @@ -808,11 +882,39 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true); + + $options_strings = array(); + + if (!empty($options['comment'])) { + $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); + } + + if (!empty($options['charset'])) { + $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; + if (!empty($options['collate'])) { + $options_strings['charset'].= ' COLLATE '.$options['collate']; + } + } + + $type = false; + if (!empty($options['type'])) { + $type = $options['type']; + } elseif ($db->options['default_table_type']) { + $type = $db->options['default_table_type']; + } + if ($type) { + $options_strings[] = "ENGINE = $type"; + } + + if (!empty($options_strings)) { + $query.= ' '.implode(' ', $options_strings); + } $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))"; - $query.= strlen($db->options['default_table_type']) ? ' TYPE='.$db->options['default_table_type'] : ''; + if (!empty($options_strings)) { + $query .= ' '.implode(' ', $options_strings); + } $res = $db->exec($query); - if (PEAR::isError($res)) { return $res; } @@ -866,7 +968,7 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common * list all sequences in the current database * * @param string database, the current is default - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public */ function listSequences($database = null) @@ -899,4 +1001,4 @@ class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common // }}} } -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Manager/pgsql.php b/htdocs/includes/pear/MDB2/Driver/Manager/pgsql.php index b9a58a90ded..dcdc6126cdf 100644 --- a/htdocs/includes/pear/MDB2/Driver/Manager/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/Manager/pgsql.php @@ -63,7 +63,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common * @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(); @@ -84,7 +84,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common * @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(); @@ -187,7 +187,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common * actually perform them otherwise. * @access public * - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @return mixed MDB2_OK on success, a MDB2 error on failure */ function alterTable($name, $changes, $check) { @@ -299,9 +299,9 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list all databases * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of database names on success, a MDB2 error on failure * @access public - **/ + */ function listDatabases() { $db =& $this->getDBInstance(); @@ -332,9 +332,9 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list all users * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of user names on success, a MDB2 error on failure * @access public - **/ + */ function listUsers() { $db =& $this->getDBInstance(); @@ -357,11 +357,11 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common // {{{ listViews() /** - * list the views in the database + * list all views in the current database * - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listViews() { $db =& $this->getDBInstance(); @@ -369,7 +369,10 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common return $db; } - $query = 'SELECT viewname FROM pg_views'; + $query = "SELECT viewname + FROM pg_views + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') + AND viewname !~ '^pg_'"; $result = $db->queryCol($query); if (PEAR::isError($result)) { return $result; @@ -386,10 +389,10 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list the views in the database that reference a given table * - * @param string table for which all references views should be found - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @param string table for which all referenced views should be found + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listTableViews($table) { $db =& $this->getDBInstance(); @@ -415,7 +418,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list all functions in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of function names on success, a MDB2 error on failure * @access public */ function listFunctions() @@ -447,15 +450,50 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common return $result; } + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure + * @access public + */ + function listTableTriggers($table = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT trg.tgname AS trigger_name + FROM pg_trigger trg, + pg_class tbl + WHERE trg.tgrelid = tbl.oid'; + if (!is_null($table)) { + $table = $db->quote(strtoupper($table), 'text'); + $query .= " AND tbl.relname = $table"; + } + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + // }}} // {{{ listTables() /** * list all tables in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of table names on success, a MDB2 error on failure * @access public - **/ + */ function listTables() { $db =& $this->getDBInstance(); @@ -497,10 +535,10 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common // {{{ listTableFields() /** - * list all fields in a tables in the current database + * list all fields in a table 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 + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) @@ -530,8 +568,8 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * 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 + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) @@ -570,8 +608,8 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list all constraints 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 + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure * @access public */ function listTableConstraints($table) @@ -616,7 +654,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common * @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(); @@ -638,7 +676,7 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common * @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(); @@ -656,9 +694,9 @@ class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common /** * list all sequences in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public - **/ + */ function listSequences() { $db =& $this->getDBInstance(); diff --git a/htdocs/includes/pear/MDB2/Driver/Native/mssql.php b/htdocs/includes/pear/MDB2/Driver/Native/mssql.php index 66ca2a46a96..ec256ff5304 100644 --- a/htdocs/includes/pear/MDB2/Driver/Native/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/Native/mssql.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Native/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Native/Common.php"; +require_once 'MDB2/Driver/Native/Common.php'; /** * MDB2 MSSQL driver for the native module @@ -55,7 +54,7 @@ require_once PEAR_PATH."/MDB2/Driver/Native/Common.php"; * @category Database * @author Lukas Smith */ -class MDB2_Driver_Native_mssql extends MDB2_Module_Common +class MDB2_Driver_Native_mssql extends MDB2_Driver_Native_Common { } ?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Native/mysql.php b/htdocs/includes/pear/MDB2/Driver/Native/mysql.php index 2779deae33e..48e65a05fd2 100644 --- a/htdocs/includes/pear/MDB2/Driver/Native/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/Native/mysql.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Native/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Native/Common.php"; +require_once 'MDB2/Driver/Native/Common.php'; /** * MDB2 MySQL driver for the native module diff --git a/htdocs/includes/pear/MDB2/Driver/Native/mysqli.php b/htdocs/includes/pear/MDB2/Driver/Native/mysqli.php index 0b44a0eb56a..0d6ebc5978e 100644 --- a/htdocs/includes/pear/MDB2/Driver/Native/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/Native/mysqli.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Native/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Native/Common.php"; +require_once 'MDB2/Driver/Native/Common.php'; /** * MDB2 MySQLi driver for the native module diff --git a/htdocs/includes/pear/MDB2/Driver/Native/pgsql.php b/htdocs/includes/pear/MDB2/Driver/Native/pgsql.php index 24b604fb31b..2cea2134369 100644 --- a/htdocs/includes/pear/MDB2/Driver/Native/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/Native/pgsql.php @@ -44,8 +44,7 @@ // // $Id$ -//require_once 'MDB2/Driver/Native/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Native/Common.php"; +require_once 'MDB2/Driver/Native/Common.php'; /** * MDB2 PostGreSQL driver for the native module diff --git a/htdocs/includes/pear/MDB2/Driver/Reverse/Common.php b/htdocs/includes/pear/MDB2/Driver/Reverse/Common.php index 0a0bb24975c..88c77726792 100644 --- a/htdocs/includes/pear/MDB2/Driver/Reverse/Common.php +++ b/htdocs/includes/pear/MDB2/Driver/Reverse/Common.php @@ -73,11 +73,14 @@ class MDB2_Driver_Reverse_Common extends MDB2_Module_Common // {{{ getTableFieldDefinition() /** - * Get the stucture of a field into an array + * Get the structure of a field into an array * - * @param string $table name of table that should be used in method - * @param string $fields name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure + * @param string $table name of table that should be used in method + * @param string $field name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure. + * The returned array contains an array for each field definition, + * with all or some of these indices, depending on the field data type: + * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] * @access public */ function getTableFieldDefinition($table, $field) @@ -95,11 +98,23 @@ class MDB2_Driver_Reverse_Common extends MDB2_Module_Common // {{{ getTableIndexDefinition() /** - * Get the stucture of an index into an array + * Get the structure of an index into an array * * @param string $table name of table that should be used in method * @param string $index name of index that should be used in method * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + * + * array ( + * [fields] => array ( + * [field1name] => array() // one entry per each field covered + * [field2name] => array() // by the index + * [field3name] => array( + * [sorting] => ascending + * ) + * ) + * ); + * * @access public */ function getTableIndexDefinition($table, $index) @@ -117,11 +132,24 @@ class MDB2_Driver_Reverse_Common extends MDB2_Module_Common // {{{ getTableConstraintDefinition() /** - * Get the stucture of an constraints into an array + * Get the structure of an constraints into an array * * @param string $table name of table that should be used in method * @param string $index name of index that should be used in method * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
+     *          array (
+     *              [primary] => 1
+     *              [fields] => array (
+     *                  [field1name] => array() // one entry per each field covered
+     *                  [field2name] => array() // by the index
+     *                  [field3name] => array(
+     *                      [sorting] => ascending
+     *                  )
+     *              )
+     *          );
+     *          
* @access public */ function getTableConstraintDefinition($table, $index) @@ -139,10 +167,16 @@ class MDB2_Driver_Reverse_Common extends MDB2_Module_Common // {{{ getSequenceDefinition() /** - * Get the stucture of a sequence into an array + * Get the structure of a sequence into an array * * @param string $sequence name of sequence that should be used in method * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
+     *          array (
+     *              [start] => n
+     *          );
+     *          
* @access public */ function getSequenceDefinition($sequence) @@ -173,10 +207,29 @@ class MDB2_Driver_Reverse_Common extends MDB2_Module_Common // {{{ getTriggerDefinition() /** - * Get the stucture of an trigger into an array + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental * * @param string $trigger name of trigger that should be used in method * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
+     *          array (
+     *              [trigger_name]    => 'trigger name',
+     *              [table_name]      => 'table name',
+     *              [trigger_body]    => 'trigger body definition',
+     *              [trigger_type]    => 'BEFORE' | 'AFTER',
+     *              [trigger_event]   => 'INSERT' | 'UPDATE' | 'DELETE'
+     *                  //or comma separated list of multiple events, when supported
+     *              [trigger_enabled] => true|false
+     *              [trigger_comment] => 'trigger comment',
+     *          );
+     *          
+ * The oci8 driver also returns a [when_clause] index. * @access public */ function getTriggerDefinition($trigger) diff --git a/htdocs/includes/pear/MDB2/Driver/Reverse/mssql.php b/htdocs/includes/pear/MDB2/Driver/Reverse/mssql.php index 6859f246507..964e4cf4d19 100644 --- a/htdocs/includes/pear/MDB2/Driver/Reverse/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/Reverse/mssql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -39,14 +39,14 @@ // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | // | POSSIBILITY OF SUCH DAMAGE. | // +----------------------------------------------------------------------+ -// | Author: Lukas Smith | +// | Authors: Lukas Smith | +// | Lorenzo Alberton | // +----------------------------------------------------------------------+ // // $Id$ // -//require_once 'MDB2/Driver/Reverse/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; +require_once 'MDB2/Driver/Reverse/Common.php'; /** * MDB2 MSSQL driver for the schema reverse engineering module @@ -54,9 +54,349 @@ require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; * @package MDB2 * @category Database * @author Lukas Smith + * @author Lorenzo Alberton */ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common { + // {{{ getTableFieldDefinition() + + /** + * Get the structure of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $field_name 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', null, true); + if (PEAR::isError($result)) { + return $result; + } + $table = $db->quoteIdentifier($table, true); + $fldname = $db->quoteIdentifier($field_name, true); + + $query = "SELECT t.table_name, + c.column_name 'name', + c.data_type 'type', + CASE c.is_nullable WHEN 'YES' THEN 1 ELSE 0 END AS 'is_nullable', + c.column_default, + c.character_maximum_length 'length', + c.numeric_precision, + c.numeric_scale, + c.character_set_name, + c.collation_name + FROM INFORMATION_SCHEMA.TABLES t, + INFORMATION_SCHEMA.COLUMNS c + WHERE t.table_name = c.table_name + AND t.table_name = '$table' + AND c.column_name = '$fldname' + ORDER BY t.table_name"; + $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($column)) { + return $column; + } + if (empty($column)) { + return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'it was not specified an existing table column', __FUNCTION__); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $column['name'] = strtolower($column['name']); + } else { + $column['name'] = strtoupper($column['name']); + } + } else { + $column = array_change_key_case($column, $db->options['field_case']); + } + $mapped_datatype = $db->datatype->mapNativeDatatype($column); + if (PEAR::IsError($mapped_datatype)) { + return $mapped_datatype; + } + list($types, $length, $unsigned, $fixed) = $mapped_datatype; + $notnull = true; + if ($column['is_nullable']) { + $notnull = false; + } + $default = false; + if (array_key_exists('column_default', $column)) { + $default = $column['column_default']; + if (is_null($default) && $notnull) { + $default = ''; + } elseif (strlen($default) > 4 + && substr($default, 0, 1) == '(' + && substr($default, -1, 1) == ')' + ) { + //mssql wraps the default value in parentheses: "((1234))", "(NULL)" + $default = trim($default, '()'); + if ($default == 'NULL') { + $default = null; + } + } + } + $definition[0] = array( + 'notnull' => $notnull, + 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) + ); + if (!is_null($length)) { + $definition[0]['length'] = $length; + } + if (!is_null($unsigned)) { + $definition[0]['unsigned'] = $unsigned; + } + if (!is_null($fixed)) { + $definition[0]['fixed'] = $fixed; + } + if ($default !== false) { + $definition[0]['default'] = $default; + } + foreach ($types as $key => $type) { + $definition[$key] = $definition[0]; + if ($type == 'clob' || $type == 'blob') { + unset($definition[$key]['default']); + } + $definition[$key]['type'] = $type; + $definition[$key]['mdb2type'] = $type; + } + return $definition; + } + + // }}} + // {{{ getTableIndexDefinition() + + /** + * Get the structure of an index into an array + * + * @param string $table name 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; + } + + $table = $db->quoteIdentifier($table, true); + //$idxname = $db->quoteIdentifier($index_name, true); + + $query = "SELECT OBJECT_NAME(i.id) tablename, + i.name indexname, + c.name field_name, + CASE INDEXKEY_PROPERTY(i.id, i.indid, ik.keyno, 'IsDescending') + WHEN 1 THEN 'DESC' ELSE 'ASC' + END 'collation', + ik.keyno 'position' + FROM sysindexes i + JOIN sysindexkeys ik ON ik.id = i.id AND ik.indid = i.indid + JOIN syscolumns c ON c.id = ik.id AND c.colid = ik.colid + WHERE OBJECT_NAME(i.id) = '$table' + AND i.name = '%s' + AND NOT EXISTS ( + SELECT * + FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k + WHERE k.table_name = OBJECT_NAME(i.id) + AND k.constraint_name = i.name) + ORDER BY tablename, indexname, ik.keyno"; + + $index_name_mdb2 = $db->getIndexName($index_name); + $result = $db->queryRow(sprintf($query, $index_name_mdb2)); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $index_name = $index_name_mdb2; + } + $result = $db->query(sprintf($query, $index_name)); + if (PEAR::isError($result)) { + return $result; + } + + $definition = array(); + while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { + $column_name = $row['field_name']; + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $column_name = strtolower($column_name); + } else { + $column_name = strtoupper($column_name); + } + } + $definition['fields'][$column_name] = array( + 'position' => (int)$row['position'], + ); + if (!empty($row['collation'])) { + $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC' + ? 'ascending' : 'descending'); + } + } + $result->free(); + if (empty($definition['fields'])) { + return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'it was not specified an existing table index', __FUNCTION__); + } + return $definition; + } + + // }}} + // {{{ getTableConstraintDefinition() + + /** + * Get the structure of a constraint into an array + * + * @param string $table name of table that should be used in method + * @param string $constraint_name name of constraint that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableConstraintDefinition($table, $constraint_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $query = "SELECT k.table_name, + k.column_name field_name, + CASE c.constraint_type WHEN 'PRIMARY KEY' THEN 1 ELSE 0 END 'primary', + CASE c.constraint_type WHEN 'UNIQUE' THEN 1 ELSE 0 END 'unique', + CASE c.constraint_type WHEN 'FOREIGN KEY' THEN 1 ELSE 0 END 'foreign', + CASE c.constraint_type WHEN 'CHECK' THEN 1 ELSE 0 END 'check', + k.ordinal_position + FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k + LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c + ON k.table_name = c.table_name + AND k.constraint_name = c.constraint_name + AND k.table_schema = c.table_schema + WHERE k.constraint_catalog = DB_NAME() + AND k.table_name = '$table' + AND k.constraint_name = '%s' + ORDER BY k.constraint_name, + k.ordinal_position"; + + $constraint_name_mdb2 = $db->getIndexName($constraint_name); + $result = $db->queryRow(sprintf($query, $constraint_name_mdb2)); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $constraint_name = $constraint_name_mdb2; + } + $result = $db->query(sprintf($query, $constraint_name)); + if (PEAR::isError($result)) { + return $result; + } + + $definition = array(); + while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { + $column_name = $row['field_name']; + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $column_name = strtolower($column_name); + } else { + $column_name = strtoupper($column_name); + } + } + $definition['fields'][$column_name] = array( + 'position' => (int)$row['ordinal_position'] + ); + /* + if (!empty($row['collation'])) { + $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC' + ? 'ascending' : 'descending'); + } + */ + $definition['primary'] = $row['primary']; + $definition['unique'] = $row['unique']; + $definition['foreign'] = $row['foreign']; + $definition['check'] = $row['check']; + } + $result->free(); + if (empty($definition['fields'])) { + return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + $constraint_name . ' is not an existing table constraint', __FUNCTION__); + } + return $definition; + } + + // }}} + // {{{ getTriggerDefinition() + + /** + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental + * + * @param string $trigger name of trigger that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTriggerDefinition($trigger) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT sys1.name trigger_name, + sys2.name table_name, + c.text trigger_body, + c.encrypted is_encripted, + CASE + WHEN OBJECTPROPERTY(sys1.id, 'ExecIsTriggerDisabled') = 1 + THEN 0 ELSE 1 + END trigger_enabled, + CASE + WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1 + THEN 'INSERT' + WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1 + THEN 'UPDATE' + WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1 + THEN 'DELETE' + END trigger_event, + CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1 + THEN 'INSTEAD OF' ELSE 'AFTER' + END trigger_type, + '' trigger_comment + FROM sysobjects sys1 + JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id + JOIN syscomments c ON sys1.id = c.id + WHERE sys1.xtype = 'TR' + AND sys1.name = ". $db->quote($trigger, 'text'); + + $types = array( + 'trigger_name' => 'text', + 'table_name' => 'text', + 'trigger_body' => 'text', + 'trigger_type' => 'text', + 'trigger_event' => 'text', + 'trigger_comment' => 'text', + 'trigger_enabled' => 'boolean', + 'is_encripted' => 'boolean', + ); + + $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($def)) { + return $def; + } + $trg_body = $db->queryCol('EXEC sp_helptext '. $db->quote($trigger, 'text'), 'text'); + if (!PEAR::isError($trg_body)) { + $def['trigger_body'] = implode('', $trg_body); + } + return $def; + } + // }}} // {{{ tableInfo() @@ -80,42 +420,19 @@ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common */ function tableInfo($result, $mode = null) { + if (is_string($result)) { + return parent::tableInfo($result, $mode); + } + $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - if (is_string($result)) { - /* - * Probably received a table name. - * Create a result resource identifier. - */ - $query = 'SELECT TOP 0 * FROM '.$db->quoteIdentifier($result); - $id =& $db->_doQuery($query, false); - 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); + $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result; + if (!is_resource($resource)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'Could not generate result resource', __FUNCTION__); } if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { @@ -128,7 +445,7 @@ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common $case_func = 'strval'; } - $count = @mssql_num_fields($id); + $count = @mssql_num_fields($resource); $res = array(); if ($mode) { @@ -138,13 +455,11 @@ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common $db->loadModule('Datatype', null, true); 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), - 'length' => @mssql_field_length($id, $i), - // We only support flags for table - 'flags' => $got_string - ? $this->_mssql_field_flags($result, @mssql_field_name($id, $i)) : '', + 'table' => '', + 'name' => $case_func(@mssql_field_name($resource, $i)), + 'type' => @mssql_field_type($resource, $i), + 'length' => @mssql_field_length($resource, $i), + 'flags' => '', ); $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]); if (PEAR::isError($mdb2type_info)) { @@ -159,10 +474,6 @@ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common } } - // free the result only if we were called on a table - if ($got_string) { - @mssql_free_result($id); - } return $res; } @@ -274,5 +585,7 @@ class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common array_push($array, $value); } } + + // }}} } -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/Driver/Reverse/mysql.php b/htdocs/includes/pear/MDB2/Driver/Reverse/mysql.php index aae340390ec..d4614e2e443 100644 --- a/htdocs/includes/pear/MDB2/Driver/Reverse/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/Reverse/mysql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Reverse/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; +require_once 'MDB2/Driver/Reverse/Common.php'; /** * MDB2 MySQL driver for the schema reverse engineering module @@ -54,16 +53,17 @@ require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; * @package MDB2 * @category Database * @author Lukas Smith + * @author Lorenzo Alberton */ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common { // {{{ getTableFieldDefinition() /** - * Get the stucture of a field into an array + * Get the structure of a field into an array * - * @param string $table name of table that should be used in method - * @param string $field_name name of field that should be used in method + * @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 */ @@ -98,7 +98,11 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common $column = array_change_key_case($column, $db->options['field_case']); } if ($field_name == $column['name']) { - list($types, $length, $unsigned, $fixed) = $db->datatype->mapNativeDatatype($column); + $mapped_datatype = $db->datatype->mapNativeDatatype($column); + if (PEAR::IsError($mapped_datatype)) { + return $mapped_datatype; + } + list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (empty($column['null']) || $column['null'] !== 'YES') { $notnull = true; @@ -119,7 +123,7 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common 'notnull' => $notnull, 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) ); - if ($length > 0) { + if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { @@ -154,27 +158,34 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common // {{{ getTableIndexDefinition() /** - * Get the stucture of an index into an array + * Get the structure of an index into an array * * @param string $table name of table that should be used in method - * @param string $index_name name of index that should be used in method + * @param string $constraint_name name of constraint that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ - function getTableIndexDefinition($table, $index_name) + function getTableIndexDefinition($table, $constraint_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $index_name = $db->getIndexName($index_name); $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */"; - $result = $db->query($query); + $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; + $constraint_name_mdb2 = $db->getIndexName($constraint_name); + $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2))); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $constraint_name = $constraint_name_mdb2; + } + $result = $db->query(sprintf($query, $db->quote($constraint_name))); if (PEAR::isError($result)) { return $result; } + $colpos = 1; $definition = array(); while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { $row = array_change_key_case($row, CASE_LOWER); @@ -186,10 +197,10 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common $key_name = strtoupper($key_name); } } - if ($index_name == $key_name) { + if ($constraint_name == $key_name) { if (!$row['non_unique']) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); + $constraint_name . ' is not an existing table constraint', __FUNCTION__); } $column_name = $row['column_name']; if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { @@ -199,7 +210,9 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common $column_name = strtoupper($column_name); } } - $definition['fields'][$column_name] = array(); + $definition['fields'][$column_name] = array( + 'position' => $colpos++ + ); if (!empty($row['collation'])) { $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' ? 'ascending' : 'descending'); @@ -209,7 +222,7 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common $result->free(); if (empty($definition['fields'])) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table index', __FUNCTION__); + $constraint_name . ' is not an existing table constraint', __FUNCTION__); } return $definition; } @@ -218,7 +231,7 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common // {{{ getTableConstraintDefinition() /** - * Get the stucture of a constraint into an array + * Get the structure of a constraint 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 @@ -232,15 +245,22 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common return $db; } - if (strtolower($index_name) != 'primary') { - $index_name = $db->getIndexName($index_name); - } $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */"; - $result = $db->query($query); + $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; + if (strtolower($index_name) != 'primary') { + $index_name_mdb2 = $db->getIndexName($index_name); + $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2))); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $index_name = $index_name_mdb2; + } + } + $result = $db->query(sprintf($query, $db->quote($index_name))); if (PEAR::isError($result)) { return $result; } + $colpos = 1; $definition = array(); while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { $row = array_change_key_case($row, CASE_LOWER); @@ -270,7 +290,9 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common $column_name = strtoupper($column_name); } } - $definition['fields'][$column_name] = array(); + $definition['fields'][$column_name] = array( + 'position' => $colpos++ + ); if (!empty($row['collation'])) { $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' ? 'ascending' : 'descending'); @@ -285,6 +307,51 @@ class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common return $definition; } + // }}} + // {{{ getTriggerDefinition() + + /** + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental + * + * @param string $trigger name of trigger that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTriggerDefinition($trigger) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT trigger_name, + event_object_table AS table_name, + action_statement AS trigger_body, + action_timing AS trigger_type, + event_manipulation AS trigger_event + FROM information_schema.triggers + WHERE trigger_name = '. $db->quote($trigger, 'text'); + $types = array( + 'trigger_name' => 'text', + 'table_name' => 'text', + 'trigger_body' => 'text', + 'trigger_type' => 'text', + 'trigger_event' => 'text', + ); + $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($def)) { + return $def; + } + $def['trigger_comment'] = ''; + $def['trigger_enabled'] = true; + return $def; + } + // }}} // {{{ tableInfo() diff --git a/htdocs/includes/pear/MDB2/Driver/Reverse/mysqli.php b/htdocs/includes/pear/MDB2/Driver/Reverse/mysqli.php index 1516521ef2e..a501a114471 100644 --- a/htdocs/includes/pear/MDB2/Driver/Reverse/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/Reverse/mysqli.php @@ -45,8 +45,7 @@ // $Id$ // -//require_once 'MDB2/Driver/Reverse/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; +require_once 'MDB2/Driver/Reverse/Common.php'; /** * MDB2 MySQLi driver for the schema reverse engineering module @@ -54,6 +53,7 @@ require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; * @package MDB2 * @category Database * @author Lukas Smith + * @author Lorenzo Alberton */ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common { @@ -114,10 +114,10 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common // {{{ getTableFieldDefinition() /** - * Get the stucture of a field into an array + * Get the structure of a field into an array * - * @param string $table name of table that should be used in method - * @param string $field_name name of field that should be used in method + * @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 */ @@ -152,7 +152,11 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common $column = array_change_key_case($column, $db->options['field_case']); } if ($field_name == $column['name']) { - list($types, $length, $unsigned, $fixed) = $db->datatype->mapNativeDatatype($column); + $mapped_datatype = $db->datatype->mapNativeDatatype($column); + if (PEAR::IsError($mapped_datatype)) { + return $mapped_datatype; + } + list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (empty($column['null']) || $column['null'] !== 'YES') { $notnull = true; @@ -173,7 +177,7 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common 'notnull' => $notnull, 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) ); - if ($length > 0) { + if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { @@ -208,7 +212,7 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common // {{{ getTableIndexDefinition() /** - * Get the stucture of an index into an array + * Get the structure of an index into an array * * @param string $table name of table that should be used in method * @param string $index_name name of index that should be used in method @@ -222,13 +226,20 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common return $db; } - $index_name = $db->getIndexName($index_name); $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */"; - $result = $db->query($query); + $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; + $index_name_mdb2 = $db->getIndexName($index_name); + $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2))); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $index_name = $index_name_mdb2; + } + $result = $db->query(sprintf($query, $db->quote($index_name))); if (PEAR::isError($result)) { return $result; } + $colpos = 1; $definition = array(); while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { $row = array_change_key_case($row, CASE_LOWER); @@ -253,7 +264,9 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common $column_name = strtoupper($column_name); } } - $definition['fields'][$column_name] = array(); + $definition['fields'][$column_name] = array( + 'position' => $colpos++ + ); if (!empty($row['collation'])) { $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' ? 'ascending' : 'descending'); @@ -272,29 +285,36 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common // {{{ getTableConstraintDefinition() /** - * Get the stucture of a constraint into an array + * Get the structure of a constraint 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 + * @param string $constraint_name name of constraint that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ - function getTableConstraintDefinition($table, $index_name) + function getTableConstraintDefinition($table, $constraint_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - if (strtolower($index_name) != 'primary') { - $index_name = $db->getIndexName($index_name); - } $table = $db->quoteIdentifier($table, true); - $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */"; - $result = $db->query($query); + $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; + if (strtolower($constraint_name) != 'primary') { + $constraint_name_mdb2 = $db->getIndexName($constraint_name); + $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2))); + if (!PEAR::isError($result) && !is_null($result)) { + // apply 'idxname_format' only if the query succeeded, otherwise + // fallback to the given $index_name, without transformation + $constraint_name = $constraint_name_mdb2; + } + } + $result = $db->query(sprintf($query, $db->quote($constraint_name))); if (PEAR::isError($result)) { return $result; } + $colpos = 1; $definition = array(); while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { $row = array_change_key_case($row, CASE_LOWER); @@ -306,10 +326,10 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common $key_name = strtoupper($key_name); } } - if ($index_name == $key_name) { + if ($constraint_name == $key_name) { if ($row['non_unique']) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table constraint', __FUNCTION__); + $constraint_name . ' is not an existing table constraint', __FUNCTION__); } if ($row['key_name'] == 'PRIMARY') { $definition['primary'] = true; @@ -324,7 +344,9 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common $column_name = strtoupper($column_name); } } - $definition['fields'][$column_name] = array(); + $definition['fields'][$column_name] = array( + 'position' => $colpos++ + ); if (!empty($row['collation'])) { $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' ? 'ascending' : 'descending'); @@ -334,11 +356,56 @@ class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common $result->free(); if (empty($definition['fields'])) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table constraint', __FUNCTION__); + $constraint_name . ' is not an existing table constraint', __FUNCTION__); } return $definition; } + // }}} + // {{{ getTriggerDefinition() + + /** + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental + * + * @param string $trigger name of trigger that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTriggerDefinition($trigger) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT trigger_name, + event_object_table AS table_name, + action_statement AS trigger_body, + action_timing AS trigger_type, + event_manipulation AS trigger_event + FROM information_schema.triggers + WHERE trigger_name = '. $db->quote($trigger, 'text'); + $types = array( + 'trigger_name' => 'text', + 'table_name' => 'text', + 'trigger_body' => 'text', + 'trigger_type' => 'text', + 'trigger_event' => 'text', + ); + $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($def)) { + return $def; + } + $def['trigger_comment'] = ''; + $def['trigger_enabled'] = true; + return $def; + } + // }}} // {{{ tableInfo() diff --git a/htdocs/includes/pear/MDB2/Driver/Reverse/pgsql.php b/htdocs/includes/pear/MDB2/Driver/Reverse/pgsql.php index 8a1c2f9dfab..1bd893dbb9d 100644 --- a/htdocs/includes/pear/MDB2/Driver/Reverse/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/Reverse/pgsql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -39,13 +39,13 @@ // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | // | POSSIBILITY OF SUCH DAMAGE. | // +----------------------------------------------------------------------+ -// | Author: Paul Cooper | +// | Authors: Paul Cooper | +// | Lorenzo Alberton | // +----------------------------------------------------------------------+ // // $Id$ -//require_once 'MDB2/Driver/Reverse/Common.php'; -require_once PEAR_PATH."/MDB2/Driver/Reverse/Common.php"; +require_once 'MDB2/Driver/Reverse/Common.php'; /** * MDB2 PostGreSQL driver for the schema reverse engineering module @@ -59,10 +59,10 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common // {{{ getTableFieldDefinition() /** - * Get the stucture of a field into an array + * Get the structure of a field into an array * - * @param string $table name of table that should be used in method - * @param string $field_name name of field that should be used in method + * @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 */ @@ -78,20 +78,46 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common return $result; } - $query = "SELECT - a.attname AS name, t.typname AS type, a.attlen AS length, a.attnotnull, - a.atttypmod, a.atthasdef, - (SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128) - FROM pg_attrdef d - WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) as default - FROM pg_attribute a, pg_class c, pg_type t - WHERE c.relname = ".$db->quote($table, 'text')." - AND a.atttypid = t.oid - AND c.oid = a.attrelid - AND NOT a.attisdropped - AND a.attnum > 0 - AND a.attname = ".$db->quote($field_name, 'text')." - ORDER BY a.attnum"; + $query = "SELECT a.attname AS name, + t.typname AS type, + CASE a.attlen + WHEN -1 THEN + CASE t.typname + WHEN 'numeric' THEN (a.atttypmod / 65536) + WHEN 'decimal' THEN (a.atttypmod / 65536) + WHEN 'money' THEN (a.atttypmod / 65536) + ELSE CASE a.atttypmod + WHEN -1 THEN NULL + ELSE a.atttypmod - 4 + END + END + ELSE a.attlen + END AS length, + CASE t.typname + WHEN 'numeric' THEN (a.atttypmod % 65536) - 4 + WHEN 'decimal' THEN (a.atttypmod % 65536) - 4 + WHEN 'money' THEN (a.atttypmod % 65536) - 4 + ELSE 0 + END AS scale, + a.attnotnull, + a.atttypmod, + a.atthasdef, + (SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128) + FROM pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) as default + FROM pg_attribute a, + pg_class c, + pg_type t + WHERE c.relname = ".$db->quote($table, 'text')." + AND a.atttypid = t.oid + AND c.oid = a.attrelid + AND NOT a.attisdropped + AND a.attnum > 0 + AND a.attname = ".$db->quote($field_name, 'text')." + ORDER BY a.attnum"; $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($column)) { return $column; @@ -103,7 +129,11 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common } $column = array_change_key_case($column, CASE_LOWER); - list($types, $length, $unsigned, $fixed) = $db->datatype->mapNativeDatatype($column); + $mapped_datatype = $db->datatype->mapNativeDatatype($column); + if (PEAR::IsError($mapped_datatype)) { + return $mapped_datatype; + } + list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (!empty($column['attnotnull']) && $column['attnotnull'] == 't') { $notnull = true; @@ -122,7 +152,7 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common $autoincrement = true; } $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']); - if ($length > 0) { + if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { @@ -151,7 +181,7 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common // }}} // {{{ getTableIndexDefinition() /** - * Get the stucture of an index into an array + * Get the structure of an index into an array * * @param string $table name of table that should be used in method * @param string $index_name name of index that should be used in method @@ -165,12 +195,16 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common return $db; } - $index_name = $db->getIndexName($index_name); $query = 'SELECT relname, indkey FROM pg_index, pg_class'; $query.= ' WHERE pg_class.oid = pg_index.indexrelid'; $query.= " AND indisunique != 't' AND indisprimary != 't'"; - $query.= ' AND pg_class.relname = '.$db->quote($index_name, 'text'); - $row = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); + $query.= ' AND pg_class.relname = %s'; + $index_name_mdb2 = $db->getIndexName($index_name); + $row = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($row) || empty($row)) { + // fallback to the given $index_name, without transformation + $row = $db->queryRow(sprintf($query, $db->quote($index_name, 'text')), null, MDB2_FETCHMODE_ASSOC); + } if (PEAR::isError($row)) { return $row; } @@ -189,8 +223,12 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common $index_column_numbers = explode(' ', $row['indkey']); + $colpos = 1; foreach ($index_column_numbers as $number) { - $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending'); + $definition['fields'][$columns[($number - 1)]] = array( + 'position' => $colpos++, + 'sorting' => 'ascending', + ); } return $definition; } @@ -198,33 +236,37 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common // }}} // {{{ getTableConstraintDefinition() /** - * Get the stucture of a constraint into an array + * Get the structure of a constraint 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 + * @param string $constraint_name name of constraint that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ - function getTableConstraintDefinition($table, $index_name) + function getTableConstraintDefinition($table, $constraint_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - - $index_name = $db->getIndexName($index_name); + $query = 'SELECT relname, indisunique, indisprimary, indkey FROM pg_index, pg_class'; $query.= ' WHERE pg_class.oid = pg_index.indexrelid'; $query.= " AND (indisunique = 't' OR indisprimary = 't')"; - $query.= ' AND pg_class.relname = '.$db->quote($index_name, 'text'); - $row = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); + $query.= ' AND pg_class.relname = %s'; + $constraint_name_mdb2 = $db->getIndexName($constraint_name); + $row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($row) || empty($row)) { + // fallback to the given $index_name, without transformation + $row = $db->queryRow(sprintf($query, $db->quote($constraint_name, 'text')), null, MDB2_FETCHMODE_ASSOC); + } if (PEAR::isError($row)) { return $row; } if (empty($row)) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'it was not specified an existing table constraint', __FUNCTION__); + $constraint_name . ' is not an existing table constraint', __FUNCTION__); } $row = array_change_key_case($row, CASE_LOWER); @@ -241,12 +283,79 @@ class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common $index_column_numbers = explode(' ', $row['indkey']); + $colpos = 1; foreach ($index_column_numbers as $number) { - $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending'); + $definition['fields'][$columns[($number - 1)]] = array( + 'position' => $colpos++, + 'sorting' => 'ascending', + ); } return $definition; } + // }}} + // {{{ getTriggerDefinition() + + /** + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental + * + * @param string $trigger name of trigger that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + * + * @TODO: add support for plsql functions and functions with args + */ + function getTriggerDefinition($trigger) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT trg.tgname AS trigger_name, + tbl.relname AS table_name, + CASE + WHEN p.proname IS NOT NULL THEN 'EXECUTE PROCEDURE ' || p.proname || '();' + ELSE '' + END AS trigger_body, + CASE trg.tgtype & cast(2 as int2) + WHEN 0 THEN 'AFTER' + ELSE 'BEFORE' + END AS trigger_type, + CASE trg.tgtype & cast(28 as int2) + WHEN 16 THEN 'UPDATE' + WHEN 8 THEN 'DELETE' + WHEN 4 THEN 'INSERT' + WHEN 20 THEN 'INSERT, UPDATE' + WHEN 28 THEN 'INSERT, UPDATE, DELETE' + WHEN 24 THEN 'UPDATE, DELETE' + WHEN 12 THEN 'INSERT, DELETE' + END AS trigger_event, + trg.tgenabled AS trigger_enabled, + obj_description(trg.oid, 'pg_trigger') AS trigger_comment + FROM pg_trigger trg, + pg_class tbl, + pg_proc p + WHERE trg.tgrelid = tbl.oid + AND trg.tgfoid = p.oid + AND trg.tgname = ". $db->quote($trigger, 'text'); + $types = array( + 'trigger_name' => 'text', + 'table_name' => 'text', + 'trigger_body' => 'text', + 'trigger_type' => 'text', + 'trigger_event' => 'text', + 'trigger_comment' => 'text', + 'trigger_enabled' => 'boolean', + ); + return $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + } + // }}} // {{{ tableInfo() diff --git a/htdocs/includes/pear/MDB2/Driver/mssql.php b/htdocs/includes/pear/MDB2/Driver/mssql.php index c98cd85daac..7157281152f 100644 --- a/htdocs/includes/pear/MDB2/Driver/mssql.php +++ b/htdocs/includes/pear/MDB2/Driver/mssql.php @@ -56,10 +56,9 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common { // {{{ properties - var $escape_quotes = "'"; - - var $escape_identifier = ''; + var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => false); + var $identifier_quoting = array('start' => '[', 'end' => ']', 'escape' => ']'); // }}} // {{{ constructor @@ -77,6 +76,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common $this->supported['indexes'] = true; $this->supported['affected_rows'] = true; $this->supported['transactions'] = true; + $this->supported['savepoints'] = false; $this->supported['summary_functions'] = true; $this->supported['order_by_text'] = true; $this->supported['current_id'] = 'emulated'; @@ -88,6 +88,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common $this->supported['primary_key'] = true; $this->supported['result_introspection'] = true; $this->supported['prepared_statements'] = 'emulated'; + $this->supported['pattern_escaping'] = true; $this->options['database_device'] = false; $this->options['database_size'] = false; @@ -118,19 +119,40 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common static $ecode_map; if (empty($ecode_map)) { $ecode_map = array( + 102 => MDB2_ERROR_SYNTAX, 110 => MDB2_ERROR_VALUE_COUNT_ON_ROW, 155 => MDB2_ERROR_NOSUCHFIELD, + 156 => MDB2_ERROR_SYNTAX, 170 => MDB2_ERROR_SYNTAX, 207 => MDB2_ERROR_NOSUCHFIELD, 208 => MDB2_ERROR_NOSUCHTABLE, 245 => MDB2_ERROR_INVALID_NUMBER, + 319 => MDB2_ERROR_SYNTAX, + 321 => MDB2_ERROR_NOSUCHFIELD, + 325 => MDB2_ERROR_SYNTAX, + 336 => MDB2_ERROR_SYNTAX, 515 => MDB2_ERROR_CONSTRAINT_NOT_NULL, 547 => MDB2_ERROR_CONSTRAINT, + 1018 => MDB2_ERROR_SYNTAX, + 1035 => MDB2_ERROR_SYNTAX, 1913 => MDB2_ERROR_ALREADY_EXISTS, + 2209 => MDB2_ERROR_SYNTAX, + 2223 => MDB2_ERROR_SYNTAX, + 2248 => MDB2_ERROR_SYNTAX, + 2256 => MDB2_ERROR_SYNTAX, + 2257 => MDB2_ERROR_SYNTAX, 2627 => MDB2_ERROR_CONSTRAINT, 2714 => MDB2_ERROR_ALREADY_EXISTS, + 3607 => MDB2_ERROR_DIVZERO, 3701 => MDB2_ERROR_NOSUCHTABLE, + 7630 => MDB2_ERROR_SYNTAX, 8134 => MDB2_ERROR_DIVZERO, + 9303 => MDB2_ERROR_SYNTAX, + 9317 => MDB2_ERROR_SYNTAX, + 9318 => MDB2_ERROR_SYNTAX, + 9331 => MDB2_ERROR_SYNTAX, + 9332 => MDB2_ERROR_SYNTAX, + 15253 => MDB2_ERROR_SYNTAX, ); } if (isset($ecode_map[$native_code])) { @@ -147,41 +169,48 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common } // }}} - // {{{ quoteIdentifier() + // {{{ function escapePattern($text) /** - * Quote a string so it can be safely used as a table / column name + * Quotes pattern (% and _) characters in a string) * - * Quoting style depends on which database driver is being used. + * @param string the input string to quote * - * @param string $str identifier name to be quoted - * @param bool $check_option check the 'quote_identifier' option + * @return string quoted string * - * @return string quoted identifier string - * - * @access public + * @access public */ - function quoteIdentifier($str, $check_option = false) + function escapePattern($text) { - if ($check_option && !$this->options['quote_identifier']) { - return $str; + $text = str_replace("[", "[ [ ]", $text); + foreach ($this->wildcards as $wildcard) { + $text = str_replace($wildcard, '[' . $wildcard . ']', $text); } - return '[' . str_replace(']', ']]', $str) . ']'; + return $text; } // }}} // {{{ beginTransaction() /** - * Start a transaction. + * Start a transaction or set a savepoint. * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public + * @param string name of a savepoint to set + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public */ - function beginTransaction() + function beginTransaction($savepoint = null) { - $this->debug('starting transaction', 'beginTransaction', false); - if ($this->in_transaction) { + $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + if (!is_null($savepoint)) { + if (!$this->in_transaction) { + return $this->raiseError(MDB2_ERROR_INVALID, null, null, + 'savepoint cannot be released when changes are auto committed', __FUNCTION__); + } + $query = 'SAVE TRANSACTION '.$savepoint; + return $this->_doQuery($query, true); + } elseif ($this->in_transaction) { return MDB2_OK; //nothing to do } if (!$this->destructor_registered && $this->opened_persistent) { @@ -201,18 +230,26 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common /** * Commit the database changes done during a transaction that is in - * progress. + * progress or release a savepoint. This function may only be called when + * auto-committing is disabled, otherwise it will fail. Therefore, a new + * transaction is implicitly started after committing the pending changes. * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public + * @param string name of a savepoint to release + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public */ - function commit() + function commit($savepoint = null) { - $this->debug('commit transaction', 'commit', false); + $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); if (!$this->in_transaction) { return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'commit: transaction changes are being auto committed'); + 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__); } + if (!is_null($savepoint)) { + return MDB2_OK; + } + $result =& $this->_doQuery('COMMIT TRANSACTION', true); if (PEAR::isError($result)) { return $result; @@ -225,19 +262,28 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common // {{{ rollback() /** - * Cancel any database changes done during a transaction that is in - * progress. + * Cancel any database changes done during a transaction or since a specific + * savepoint that is in progress. This function may only be called when + * auto-committing is disabled, otherwise it will fail. Therefore, a new + * transaction is implicitly started after canceling the pending changes. * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public + * @param string name of a savepoint to rollback to + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public */ - function rollback() + function rollback($savepoint = null) { - $this->debug('rolling back transaction', 'rollback', false); + $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); if (!$this->in_transaction) { return $this->raiseError(MDB2_ERROR_INVALID, null, null, - 'rollback: transactions can not be rolled back when changes are auto committed'); + 'rollback cannot be done changes are auto committed', __FUNCTION__); } + if (!is_null($savepoint)) { + $query = 'ROLLBACK TRANSACTION '.$savepoint; + return $this->_doQuery($query, true); + } + $result =& $this->_doQuery('ROLLBACK TRANSACTION', true); if (PEAR::isError($result)) { return $result; @@ -267,7 +313,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common if (!PEAR::loadExtension($this->phptype)) { return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'connect: extension '.$this->phptype.' is not compiled into PHP'); + 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); } $params = array( @@ -283,7 +329,8 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common $connection = @call_user_func_array($connect_function, $params); if ($connection <= 0) { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED); + return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, + 'unable to establish a connection', __FUNCTION__, __FUNCTION__); } if (!empty($this->dsn['charset'])) { @@ -293,16 +340,30 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common } } + if ((bool)ini_get('mssql.datetimeconvert')) { + @ini_set('mssql.datetimeconvert', '0'); + } + + if (empty($this->dsn['disable_iso_date'])) { + @mssql_query('SET DATEFORMAT ymd', $connection); + } + $this->connection = $connection; $this->connected_dsn = $this->dsn; $this->connected_database_name = ''; $this->opened_persistent = $this->options['persistent']; $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; - if ((bool) ini_get('mssql.datetimeconvert')) { - @ini_set('mssql.datetimeconvert', '0'); - } - @mssql_query('SET DATEFORMAT ymd', $connection); + if ($this->database_name) { + if ($this->database_name != $this->connected_database_name) { + if (!@mssql_select_db($this->database_name, $connection)) { + $err = $this->raiseError(null, null, null, + 'Could not select the database: '.$this->database_name, __FUNCTION__); + return $err; + } + $this->connected_database_name = $this->database_name; + } + } return MDB2_OK; } @@ -323,8 +384,18 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common { if (is_resource($this->connection)) { if ($this->in_transaction) { + $dsn = $this->dsn; + $database_name = $this->database_name; + $persistent = $this->options['persistent']; + $this->dsn = $this->connected_dsn; + $this->database_name = $this->connected_database_name; + $this->options['persistent'] = $this->opened_persistent; $this->rollback(); + $this->dsn = $dsn; + $this->database_name = $database_name; + $this->options['persistent'] = $persistent; } + if (!$this->opened_persistent || $force) { @mssql_close($this->connection); } @@ -347,18 +418,16 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) { $this->last_query = $query; - $result = $this->debug($query, 'query', $is_manip); + $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); if ($result) { if (PEAR::isError($result)) { return $result; } $query = $result; } - if ($this->getOption('disable_query')) { - if ($is_manip) { - return 0; - } - return null; + if ($this->options['disable_query']) { + $result = $is_manip ? 0 : null; + return $result; } if (is_null($connection)) { @@ -375,7 +444,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common if ($database_name != $this->connected_database_name) { if (!@mssql_select_db($database_name, $connection)) { $err = $this->raiseError(null, null, null, - '_doQuery: Could not select the database: '.$database_name); + 'Could not select the database: '.$database_name, __FUNCTION__); return $err; } $this->connected_database_name = $database_name; @@ -384,11 +453,12 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common $result = @mssql_query($query, $connection); if (!$result) { - $err = $this->raiseError(null, null, null, - '_doQuery: Could not execute statement'); + $err =& $this->raiseError(null, null, null, + 'Could not execute statement', __FUNCTION__); return $err; } + $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result)); return $result; } @@ -432,8 +502,8 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common if ($limit > 0) { $fetch = $offset + $limit; if (!$is_manip) { - return preg_replace('/^([\s(])*SELECT(?!\s*TOP\s*\()/i', - "\\1SELECT TOP $fetch", $query); + return preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i', + "\\1SELECT\\2 TOP $fetch", $query); } } return $query; @@ -444,7 +514,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common /** * return version information about the server * - * @param string $native determines if the raw version string should be returned + * @param bool $native determines if the raw version string should be returned * @return mixed array/string with version information or MDB2 error object * @access public */ @@ -503,7 +573,7 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common //return $tableExists; return false; } - return true; + return mssql_result($tableExists, 0, 0); } // }}} @@ -525,9 +595,12 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); $this->expectError(MDB2_ERROR_NOSUCHTABLE); - if ($this->_checkSequence($sequence_name)) { - $query = "SET IDENTITY_INSERT $sequence_name ON ". - "INSERT INTO $sequence_name ($seqcol_name) VALUES (0)"; + + $seq_val = $this->_checkSequence($sequence_name); + + if ($seq_val) { + $query = "SET IDENTITY_INSERT $sequence_name OFF ". + "INSERT INTO $sequence_name ($seqcol_name) DEFAULT VALUES"; } else { $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (0)"; } @@ -536,16 +609,12 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common if (PEAR::isError($result)) { if ($ondemand && !$this->_checkSequence($sequence_name)) { $this->loadModule('Manager', null, true); - // 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); + $result = $this->manager->createSequence($seq_name); if (PEAR::isError($result)) { return $this->raiseError($result, null, null, - 'nextID: on demand sequence '.$seq_name.' could not be created'); + 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__); } else { - // First ID of a newly created sequence is 1 - return 1; + return $this->nextID($seq_name, false); } } return $result; @@ -574,12 +643,12 @@ class MDB2_Driver_mssql extends MDB2_Driver_Common function lastInsertID($table = null, $field = null) { $server_info = $this->getServerVersion(); - if (is_array($server_info) - && !is_null($server_info['major']) - && $server_info['major'] >= 8) { - $query = "SELECT SCOPE_IDENTITY()"; + if (is_array($server_info) && !is_null($server_info['major']) + && $server_info['major'] >= 8 + ) { + $query = "SELECT SCOPE_IDENTITY()"; } else { - $query = "SELECT @@IDENTITY"; + $query = "SELECT @@IDENTITY"; } return $this->queryOne($query, 'integer'); @@ -665,21 +734,22 @@ class MDB2_Result_mssql extends MDB2_Result_Common if (!$row) { if ($this->result === false) { $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'fetchRow: resultset has already been freed'); + 'resultset has already been freed', __FUNCTION__); 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); + $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL; + if ($mode) { + $this->db->_fixResultArrayValues($row, $mode); + } + if (!empty($this->types)) { + $row = $this->db->datatype->convertResultRow($this->types, $row, false); } 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') { @@ -737,12 +807,12 @@ class MDB2_Result_mssql extends MDB2_Result_Common if (is_null($cols)) { if ($this->result === false) { return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'numCols: resultset has already been freed'); + 'resultset has already been freed', __FUNCTION__); } elseif (is_null($this->result)) { return count($this->types); } return $this->db->raiseError(null, null, null, - 'numCols: Could not get column count'); + 'Could not get column count', __FUNCTION__); } return $cols; } @@ -760,7 +830,7 @@ class MDB2_Result_mssql extends MDB2_Result_Common { if ($this->result === false) { return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'nextResult: resultset has already been freed'); + 'resultset has already been freed', __FUNCTION__); } elseif (is_null($this->result)) { return false; } @@ -782,7 +852,7 @@ class MDB2_Result_mssql extends MDB2_Result_Common $free = @mssql_free_result($this->result); if ($free === false) { return $this->db->raiseError(null, null, null, - 'free: Could not free result'); + 'Could not free result', __FUNCTION__); } } $this->result = false; @@ -814,12 +884,12 @@ class MDB2_BufferedResult_mssql extends MDB2_Result_mssql if ($this->rownum != ($rownum - 1) && !@mssql_data_seek($this->result, $rownum)) { if ($this->result === false) { return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'seek: resultset has already been freed'); + 'resultset has already been freed', __FUNCTION__); } elseif (is_null($this->result)) { return MDB2_OK; } return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, - 'seek: tried to seek to an invalid row number ('.$rownum.')'); + 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__); } $this->rownum = $rownum - 1; return MDB2_OK; @@ -857,12 +927,12 @@ class MDB2_BufferedResult_mssql extends MDB2_Result_mssql if (is_null($rows)) { if ($this->result === false) { return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'numRows: resultset has already been freed'); + 'resultset has already been freed', __FUNCTION__); } elseif (is_null($this->result)) { return 0; } return $this->db->raiseError(null, null, null, - 'numRows: Could not get row count'); + 'Could not get row count', __FUNCTION__); } if ($this->limit) { $rows -= $this->limit; diff --git a/htdocs/includes/pear/MDB2/Driver/mysql.php b/htdocs/includes/pear/MDB2/Driver/mysql.php index a0c7cf0d369..8ff70569f63 100644 --- a/htdocs/includes/pear/MDB2/Driver/mysql.php +++ b/htdocs/includes/pear/MDB2/Driver/mysql.php @@ -151,6 +151,9 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common 1146 => MDB2_ERROR_NOSUCHTABLE, 1216 => MDB2_ERROR_CONSTRAINT, 1217 => MDB2_ERROR_CONSTRAINT, + 1356 => MDB2_ERROR_DIVZERO, + 1451 => MDB2_ERROR_CONSTRAINT, + 1452 => MDB2_ERROR_CONSTRAINT, ); } if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) { @@ -190,7 +193,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $text = $this->escapePattern($text); } $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } $text = @mysql_real_escape_string($text, $connection); @@ -211,6 +214,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common function beginTransaction($savepoint = null) { $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + $this->_getServerCapabilities(); if (!is_null($savepoint)) { if (!$this->supports('savepoints')) { return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, @@ -231,7 +235,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } $query = $this->start_transaction ? 'START TRANSACTION' : 'SET AUTOCOMMIT = 1'; $result =& $this->_doQuery($query, true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } $this->in_transaction = true; @@ -278,13 +282,13 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } $result =& $this->_doQuery('COMMIT', true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } if (!$this->start_transaction) { $query = 'SET AUTOCOMMIT = 0'; $result =& $this->_doQuery($query, true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } } @@ -324,13 +328,13 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $query = 'ROLLBACK'; $result =& $this->_doQuery($query, true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } if (!$this->start_transaction) { $query = 'SET AUTOCOMMIT = 0'; $result =& $this->_doQuery($query, true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } } @@ -389,13 +393,14 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common if (is_resource($this->connection)) { if (count(array_diff($this->connected_dsn, $this->dsn)) == 0 && $this->opened_persistent == $this->options['persistent'] + && $this->connected_database_name == $this->database_name ) { return MDB2_OK; } $this->disconnect(false); } - if (!DOLIPEAR::loadExtension($this->phptype)) { + if (!PEAR::loadExtension($this->phptype)) { return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); } @@ -440,7 +445,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common if (!empty($this->dsn['charset'])) { $result = $this->setCharset($this->dsn['charset'], $connection); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } } @@ -482,36 +487,12 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common break; } } - - $this->supported['sub_selects'] = 'emulated'; - $this->supported['prepared_statements'] = 'emulated'; - $this->start_transaction = false; - $this->varchar_max_length = 255; - - $server_info = $this->getServerVersion(); - if (is_array($server_info)) { - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) { - $this->supported['sub_selects'] = true; - $this->supported['prepared_statements'] = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<') - || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<') - ) { - $this->supported['savepoints'] = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) { - $this->start_transaction = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { - $this->varchar_max_length = 65532; - } - } + + $this->_getServerCapabilities(); return MDB2_OK; } + // }}} // {{{ setCharset() @@ -527,19 +508,12 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common { if (is_null($connection)) { $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } } - - $query = "SET character_set_client = '".mysql_real_escape_string($charset, $connection)."'"; - $result = @mysql_query($query, $connection); - if (!$result) { - return $this->raiseError(null, null, null, - 'Unable to set client charset: '.$charset, __FUNCTION__); - } - - return MDB2_OK; + $query = "SET NAMES '".mysql_real_escape_string($charset, $connection)."'"; + return $this->_doQuery($query, true, $connection); } // }}} @@ -594,7 +568,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $this->last_query = $query; $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); if ($result) { - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } $query = $result; @@ -606,7 +580,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common if (is_null($connection)) { $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } } @@ -653,7 +627,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common { if (is_null($connection)) { $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } } @@ -684,16 +658,31 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } } if ($limit > 0 - && !preg_match('/LIMIT\s*\d(\s*(,|OFFSET)\s*\d+)?/i', $query) + && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) ) { $query = rtrim($query); if (substr($query, -1) == ';') { $query = substr($query, 0, -1); } + + // LIMIT doesn't always come last in the query + // @see http://dev.mysql.com/doc/refman/5.0/en/select.html + $after = ''; + if (preg_match('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', '', $query); + } elseif (preg_match('/(\s+FOR\s+UPDATE\s*)$/i', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+FOR\s+UPDATE\s*)$/im', '', $query); + } elseif (preg_match('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', '', $query); + } + if ($is_manip) { - return $query . " LIMIT $limit"; + return $query . " LIMIT $limit" . $after; } else { - return $query . " LIMIT $offset, $limit"; + return $query . " LIMIT $offset, $limit" . $after; } } return $query; @@ -705,14 +694,14 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common /** * return version information about the server * - * @param string $native determines if the raw version string should be returned + * @param bool $native determines if the raw version string should be returned * @return mixed array/string with version information or MDB2 error object * @access public */ function getServerVersion($native = false) { $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } if ($this->connected_server_info) { @@ -745,6 +734,80 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common return $server_info; } + // }}} + // {{{ _getServerCapabilities() + + /** + * Fetch some information about the server capabilities + * (transactions, subselects, prepared statements, etc). + * + * @access private + */ + function _getServerCapabilities() + { + static $already_checked = false; + if (!$already_checked) { + $already_checked = true; + + //set defaults + $this->supported['sub_selects'] = 'emulated'; + $this->supported['prepared_statements'] = 'emulated'; + $this->start_transaction = false; + $this->varchar_max_length = 255; + + $server_info = $this->getServerVersion(); + if (is_array($server_info)) { + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) { + $this->supported['sub_selects'] = true; + $this->supported['prepared_statements'] = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<') + || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<') + ) { + $this->supported['savepoints'] = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) { + $this->start_transaction = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { + $this->varchar_max_length = 65532; + } + } + } + } + + // }}} + // {{{ function _skipUserDefinedVariable($query, $position) + + /** + * Utility method, used by prepare() to avoid misinterpreting MySQL user + * defined variables (SELECT @x:=5) for placeholders. + * Check if the placeholder is a false positive, i.e. if it is an user defined + * variable instead. If so, skip it and advance the position, otherwise + * return the current position, which is valid + * + * @param string $query + * @param integer $position current string cursor position + * @return integer $new_position + * @access protected + */ + function _skipUserDefinedVariable($query, $position) + { + $found = strpos(strrev(substr($query, 0, $position)), '@'); + if ($found === false) { + return $position; + } + $pos = strlen($query) - strlen(substr($query, $position)) - $found - 1; + $substring = substr($query, $pos, $position - $pos + 2); + if (preg_match('/^@\w+:=$/', $substring)) { + return $position + 1; //found an user defined variable: skip it + } + return $position; + } + // }}} // {{{ prepare() @@ -783,7 +846,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); if ($result) { - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } $query = $result; @@ -810,7 +873,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); - if (DOLIPEAR::isError($new_pos)) { + if (PEAR::isError($new_pos)) { return $new_pos; } if ($new_pos != $position) { @@ -824,6 +887,12 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $question = $colon = $placeholder_type; } if ($placeholder_type == ':') { + //make sure this is not part of an user defined variable + $new_pos = $this->_skipUserDefinedVariable($query, $position); + if ($new_pos != $position) { + $position = $new_pos; + continue; //evaluate again starting from the new position + } $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); if ($parameter === '') { $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, @@ -841,13 +910,13 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } } $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } $statement_name = sprintf($this->options['statement_format'], $this->phptype, md5(time() + rand())); $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text'); $statement =& $this->_doQuery($query, true, $connection); - if (DOLIPEAR::isError($statement)) { + if (PEAR::isError($statement)) { return $statement; } @@ -957,13 +1026,13 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common } $connection = $this->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } $query = "REPLACE INTO $table ($query) VALUES ($values)"; $result =& $this->_doQuery($query, true, $connection); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } return $this->_affectedRows($connection, $result); @@ -991,11 +1060,11 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common $this->expectError(MDB2_ERROR_NOSUCHTABLE); $result =& $this->_doQuery($query, true); $this->popExpect(); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { $this->loadModule('Manager', null, true); $result = $this->manager->createSequence($seq_name); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $this->raiseError($result, null, null, 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__); } else { @@ -1008,7 +1077,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common if (is_numeric($value)) { $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value"; $result =& $this->_doQuery($query, true); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; } } @@ -1076,7 +1145,7 @@ class MDB2_Result_mysql extends MDB2_Result_Common { if (!is_null($rownum)) { $seek = $this->seek($rownum); - if (DOLIPEAR::isError($seek)) { + if (PEAR::isError($seek)) { return $seek; } } @@ -1141,7 +1210,7 @@ class MDB2_Result_mysql extends MDB2_Result_Common { $columns = array(); $numcols = $this->numCols(); - if (DOLIPEAR::isError($numcols)) { + if (PEAR::isError($numcols)) { return $numcols; } for ($column = 0; $column < $numcols; $column++) { @@ -1250,7 +1319,7 @@ class MDB2_BufferedResult_mysql extends MDB2_Result_mysql function valid() { $numrows = $this->numRows(); - if (DOLIPEAR::isError($numrows)) { + if (PEAR::isError($numrows)) { return $numrows; } return $this->rownum < ($numrows - 1); @@ -1315,7 +1384,7 @@ class MDB2_Statement_mysql extends MDB2_Statement_Common } $connection = $this->db->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } @@ -1348,9 +1417,13 @@ class MDB2_Statement_mysql extends MDB2_Statement_Common $value = $data; } } - $param_query = 'SET @'.$parameter.' = '.$this->db->quote($value, $type); + $quoted = $this->db->quote($value, $type); + if (PEAR::isError($quoted)) { + return $quoted; + } + $param_query = 'SET @'.$parameter.' = '.$quoted; $result = $this->db->_doQuery($param_query, true, $connection); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } } @@ -1358,7 +1431,7 @@ class MDB2_Statement_mysql extends MDB2_Statement_Common } $result = $this->db->_doQuery($query, $this->is_manip, $connection); - if (DOLIPEAR::isError($result)) { + if (PEAR::isError($result)) { return $result; } @@ -1392,7 +1465,7 @@ class MDB2_Statement_mysql extends MDB2_Statement_Common if (!is_null($this->statement)) { $connection = $this->db->getConnection(); - if (DOLIPEAR::isError($connection)) { + if (PEAR::isError($connection)) { return $connection; } $query = 'DEALLOCATE PREPARE '.$this->statement; diff --git a/htdocs/includes/pear/MDB2/Driver/mysqli.php b/htdocs/includes/pear/MDB2/Driver/mysqli.php index 5d08280b0f8..641ed884caa 100644 --- a/htdocs/includes/pear/MDB2/Driver/mysqli.php +++ b/htdocs/includes/pear/MDB2/Driver/mysqli.php @@ -122,8 +122,8 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common $native_code = @mysqli_errno($this->connection); $native_msg = @mysqli_error($this->connection); } else { - $native_code = @mysqli_errno(); - $native_msg = @mysqli_error(); + $native_code = @mysqli_connect_errno(); + $native_msg = @mysqli_connect_error(); } if (is_null($error)) { static $ecode_map; @@ -152,6 +152,9 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common 1146 => MDB2_ERROR_NOSUCHTABLE, 1216 => MDB2_ERROR_CONSTRAINT, 1217 => MDB2_ERROR_CONSTRAINT, + 1356 => MDB2_ERROR_DIVZERO, + 1451 => MDB2_ERROR_CONSTRAINT, + 1452 => MDB2_ERROR_CONSTRAINT, ); } if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) { @@ -212,6 +215,7 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common function beginTransaction($savepoint = null) { $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + $this->_getServerCapabilities(); if (!is_null($savepoint)) { if (!$this->supports('savepoints')) { return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, @@ -429,7 +433,7 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common if (!$connection) { if (($err = @mysqli_connect_error()) != '') { - return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, + return $this->raiseError(null, null, null, $err, __FUNCTION__); } else { return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, @@ -469,33 +473,8 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common break; } } - - $this->supported['sub_selects'] = 'emulated'; - $this->supported['prepared_statements'] = 'emulated'; - $this->start_transaction = false; - $this->varchar_max_length = 255; - - $server_info = $this->getServerVersion(); - if (is_array($server_info)) { - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) { - $this->supported['sub_selects'] = true; - $this->supported['prepared_statements'] = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<') - || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<') - ) { - $this->supported['savepoints'] = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) { - $this->start_transaction = true; - } - - if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { - $this->varchar_max_length = 65532; - } - } + + $this->_getServerCapabilities(); return MDB2_OK; } @@ -519,19 +498,8 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common return $connection; } } - - if (function_exists('mysqli_set_charset')) { - $result = @mysqli_set_charset($connection, $charset); - } else { - $query = "SET character_set_client = '".mysqli_real_escape_string($connection, $charset)."'"; - $result = @mysqli_query($connection, $query); - } - - if (!$result) { - return $this->raiseError(null, null, null, - 'Unable to set client charset: '.$charset, __FUNCTION__); - } - return MDB2_OK; + $query = "SET NAMES '".mysqli_real_escape_string($connection, $charset)."'"; + return $this->_doQuery($query, true, $connection); } // }}} @@ -694,12 +662,27 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common } } if ($limit > 0 - && !preg_match('/LIMIT\s*\d(\s*(,|OFFSET)\s*\d+)?/i', $query) + && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) ) { $query = rtrim($query); if (substr($query, -1) == ';') { $query = substr($query, 0, -1); } + + // LIMIT doesn't always come last in the query + // @see http://dev.mysql.com/doc/refman/5.0/en/select.html + $after = ''; + if (preg_match('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', '', $query); + } elseif (preg_match('/(\s+FOR\s+UPDATE\s*)$/i', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+FOR\s+UPDATE\s*)$/im', '', $query); + } elseif (preg_match('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', $query, $matches)) { + $after = $matches[0]; + $query = preg_replace('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', '', $query); + } + if ($is_manip) { return $query . " LIMIT $limit"; } else { @@ -715,7 +698,7 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common /** * return version information about the server * - * @param string $native determines if the raw version string should be returned + * @param bool $native determines if the raw version string should be returned * @return mixed array/string with version information or MDB2 error object * @access public */ @@ -755,6 +738,80 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common return $server_info; } + // }}} + // {{{ _getServerCapabilities() + + /** + * Fetch some information about the server capabilities + * (transactions, subselects, prepared statements, etc). + * + * @access private + */ + function _getServerCapabilities() + { + static $already_checked = false; + if (!$already_checked) { + $already_checked = true; + + //set defaults + $this->supported['sub_selects'] = 'emulated'; + $this->supported['prepared_statements'] = 'emulated'; + $this->start_transaction = false; + $this->varchar_max_length = 255; + + $server_info = $this->getServerVersion(); + if (is_array($server_info)) { + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) { + $this->supported['sub_selects'] = true; + $this->supported['prepared_statements'] = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<') + || !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<') + ) { + $this->supported['savepoints'] = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) { + $this->start_transaction = true; + } + + if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { + $this->varchar_max_length = 65532; + } + } + } + } + + // }}} + // {{{ function _skipUserDefinedVariable($query, $position) + + /** + * Utility method, used by prepare() to avoid misinterpreting MySQL user + * defined variables (SELECT @x:=5) for placeholders. + * Check if the placeholder is a false positive, i.e. if it is an user defined + * variable instead. If so, skip it and advance the position, otherwise + * return the current position, which is valid + * + * @param string $query + * @param integer $position current string cursor position + * @return integer $new_position + * @access protected + */ + function _skipUserDefinedVariable($query, $position) + { + $found = strpos(strrev(substr($query, 0, $position)), '@'); + if ($found === false) { + return $position; + } + $pos = strlen($query) - strlen(substr($query, $position)) - $found - 1; + $substring = substr($query, $pos, $position - $pos + 2); + if (preg_match('/^@\w+:=$/', $substring)) { + return $position + 1; //found an user defined variable: skip it + } + return $position; + } + // }}} // {{{ prepare() @@ -834,6 +891,12 @@ class MDB2_Driver_mysqli extends MDB2_Driver_Common $question = $colon = $placeholder_type; } if ($placeholder_type == ':') { + //make sure this is not part of an user defined variable + $new_pos = $this->_skipUserDefinedVariable($query, $position); + if ($new_pos != $position) { + $position = $new_pos; + continue; //evaluate again starting from the new position + } $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); if ($parameter === '') { $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, @@ -1208,7 +1271,6 @@ class MDB2_Result_mysqli extends MDB2_Result_Common /** * Move the internal result pointer to the next available result * - * @param a valid result resource * @return true on success, false if there is no more result set or an error object on failure * @access public */ @@ -1433,7 +1495,11 @@ class MDB2_Statement_mysqli extends MDB2_Statement_Common $value = $data; } } - $param_query = 'SET @'.$parameter.' = '.$this->db->quote($value, $type); + $quoted = $this->db->quote($value, $type); + if (PEAR::isError($quoted)) { + return $quoted; + } + $param_query = 'SET @'.$parameter.' = '.$quoted; $result = $this->db->_doQuery($param_query, true, $connection); if (PEAR::isError($result)) { return $result; diff --git a/htdocs/includes/pear/MDB2/Driver/pgsql.php b/htdocs/includes/pear/MDB2/Driver/pgsql.php index 5e66de958d1..745efcbc5d3 100644 --- a/htdocs/includes/pear/MDB2/Driver/pgsql.php +++ b/htdocs/includes/pear/MDB2/Driver/pgsql.php @@ -674,7 +674,7 @@ class MDB2_Driver_pgsql extends MDB2_Driver_Common function _modifyQuery($query, $is_manip, $limit, $offset) { if ($limit > 0 - && !preg_match('/LIMIT\s*\d(\s*(,|OFFSET)\s*\d+)?/i', $query) + && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) ) { $query = rtrim($query); if (substr($query, -1) == ';') { @@ -726,7 +726,7 @@ class MDB2_Driver_pgsql extends MDB2_Driver_Common /** * return version information about the server * - * @param string $native determines if the raw version string should be returned + * @param bool $native determines if the raw version string should be returned * @return mixed array/string with version information or MDB2 error object * @access public */ @@ -927,6 +927,48 @@ class MDB2_Driver_pgsql extends MDB2_Driver_Common return $obj; } + // }}} + // {{{ function getSequenceName($sqn) + + /** + * adds sequence name formatting to a sequence name + * + * @param string name of the sequence + * + * @return string formatted sequence name + * + * @access public + */ + function getSequenceName($sqn) + { + list($table, $field) = explode('_', $sqn); + $query = "SELECT substring((SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128) + FROM pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) FROM 'nextval[^\']*\'([^\']*)') + FROM pg_attribute a + LEFT JOIN pg_class c ON c.oid = a.attrelid + LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef + WHERE (c.relname = ".$this->quote($sqn, 'text'); + if (!empty($field)) { + $query .= " OR (c.relname = ".$this->quote($table, 'text')." AND a.attname = ".$this->quote($field, 'text').")"; + } + $query .= " ) + AND NOT a.attisdropped + AND a.attnum > 0 + AND pg_get_expr(d.adbin, d.adrelid) LIKE 'nextval%' + ORDER BY a.attnum"; + $seqname = $this->queryOne($query); + if (!PEAR::isError($seqname) && !empty($seqname) && is_string($seqname)) { + return $seqname; + } + + return sprintf($this->options['seqname_format'], + preg_replace('/[^\w\$.]/i', '_', $sqn)); + } + // }}} // {{{ nextID() @@ -975,6 +1017,9 @@ class MDB2_Driver_pgsql extends MDB2_Driver_Common */ function lastInsertID($table = null, $field = null) { + if (empty($table) && empty($field)) { + return $this->queryOne('SELECT lastval()', 'integer'); + } $seq = $table.(empty($field) ? '' : '_'.$field); $sequence_name = $this->getSequenceName($seq); return $this->queryOne("SELECT currval('$sequence_name')", 'integer'); @@ -1138,7 +1183,6 @@ class MDB2_Result_pgsql extends MDB2_Result_Common /** * Move the internal result pointer to the next available result * - * @param a valid result resource * @return true on success, false if there is no more result set or an error object on failure * @access public */ diff --git a/htdocs/includes/pear/MDB2/Extended.php b/htdocs/includes/pear/MDB2/Extended.php index 0e2c2d9059b..baac5a9e383 100644 --- a/htdocs/includes/pear/MDB2/Extended.php +++ b/htdocs/includes/pear/MDB2/Extended.php @@ -198,6 +198,10 @@ class MDB2_Extended extends MDB2_Module_Common return $db; } + if ($db->options['quote_identifier']) { + $table = $db->quoteIdentifier($table); + } + if (!empty($table_fields) && $db->options['quote_identifier']) { foreach ($table_fields as $key => $field) { $table_fields[$key] = $db->quoteIdentifier($field); @@ -527,32 +531,35 @@ class MDB2_Extended extends MDB2_Module_Common * columns, a MDB2_ERROR_TRUNCATED error is returned. * * For example, if the table 'mytable' contains: - * + *
      *   ID      TEXT       DATE
      * --------------------------------
      *   1       'one'      944679408
      *   2       'two'      944679408
      *   3       'three'    944679408
-     *
+     * 
* Then the call getAssoc('SELECT id,text FROM mytable') returns: + *
      *    array(
      *      '1' => 'one',
      *      '2' => 'two',
      *      '3' => 'three',
      *    )
-     *
+     * 
* ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: + *
      *    array(
      *      '1' => array('one', '944679408'),
      *      '2' => array('two', '944679408'),
      *      '3' => array('three', '944679408')
      *    )
+     * 
* * If the more than one row occurs with the same value in the * first column, the last row overwrites all previous ones by * default. Use the $group parameter if you don't want to * overwrite like this. Example: - * + *
      * getAssoc('SELECT category,id,name FROM mytable', null, null
      *           MDB2_FETCHMODE_ASSOC, false, true) returns:
      *    array(
@@ -563,6 +570,7 @@ class MDB2_Extended extends MDB2_Module_Common
      *                   array('id' => '6', 'name' => 'number six')
      *             )
      *    )
+     * 
* * Keep in mind that database functions in PHP usually return string * values for results regardless of the database's internal type. @@ -703,4 +711,4 @@ class MDB2_Extended extends MDB2_Module_Common } // }}} } -?> +?> \ No newline at end of file diff --git a/htdocs/includes/pear/MDB2/LOB.php b/htdocs/includes/pear/MDB2/LOB.php index 043d96af57e..537a77e546b 100644 --- a/htdocs/includes/pear/MDB2/LOB.php +++ b/htdocs/includes/pear/MDB2/LOB.php @@ -50,8 +50,7 @@ * @author Lukas Smith */ -//require_once 'MDB2.php'; -require_once PEAR_PATH."/MDB2.php"; +require_once 'MDB2.php'; /** * MDB2_LOB: user land stream wrapper implementation for LOB support