Created
March 21, 2014 04:59
-
-
Save zenith6/9679810 to your computer and use it in GitHub Desktop.
EC-CUBE 2.13-dev に MySQL 改良版拡張モジュールへの対応を追加するパッチです。https://svn.ec-cube.net/open/branches/version-2_13-dev/?p=23352 に対して適用して下さい。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: data/class/db/SC_DB_DBFactory.php | |
=================================================================== | |
--- data/class/db/SC_DB_DBFactory.php (revision 23352) | |
+++ data/class/db/SC_DB_DBFactory.php (working copy) | |
@@ -40,6 +40,7 @@ | |
{ | |
switch ($db_type) { | |
case 'mysql': | |
+ case 'mysqli': | |
return new SC_DB_DBFactory_MYSQL(); | |
case 'pgsql': | |
Index: data/class_extends/db_extends/SC_DB_DBFactory_Ex.php | |
=================================================================== | |
--- data/class_extends/db_extends/SC_DB_DBFactory_Ex.php (revision 23352) | |
+++ data/class_extends/db_extends/SC_DB_DBFactory_Ex.php (working copy) | |
@@ -34,23 +34,4 @@ | |
*/ | |
class SC_DB_DBFactory_Ex extends SC_DB_DBFactory | |
{ | |
- /** | |
- * DB_TYPE に応じた DBFactory インスタンスを生成する. | |
- * | |
- * @param string $db_type 任意のインスタンスを返したい場合は DB_TYPE 文字列を指定 | |
- * @return mixed DBFactory インスタンス | |
- */ | |
- function getInstance($db_type = DB_TYPE) | |
- { | |
- switch ($db_type) { | |
- case 'mysql': | |
- return new SC_DB_DBFactory_MYSQL_Ex(); | |
- | |
- case 'pgsql': | |
- return new SC_DB_DBFactory_PGSQL_Ex(); | |
- | |
- default: | |
- return new SC_DB_DBFactory_Ex(); | |
- } | |
- } | |
} | |
Index: data/module/MDB2/Driver/Datatype/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/Datatype/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/Datatype/mysqli.php (working copy) | |
@@ -0,0 +1,640 @@ | |
+<?php | |
+// vim: set et ts=4 sw=4 fdm=marker: | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 327310 2012-08-27 15:16:18Z danielc $ | |
+// | |
+ | |
+require_once 'MDB2/Driver/Datatype/Common.php'; | |
+ | |
+/** | |
+ * MDB2 MySQLi driver | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common | |
+{ | |
+ // {{{ _getCharsetFieldDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET | |
+ * of a field declaration to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param string $charset name of the charset | |
+ * @return string DBMS specific SQL code portion needed to set the CHARACTER SET | |
+ * of a field declaration. | |
+ */ | |
+ function _getCharsetFieldDeclaration($charset) | |
+ { | |
+ return 'CHARACTER SET '.$charset; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getCollationFieldDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to set the COLLATION | |
+ * of a field declaration to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param string $collation name of the collation | |
+ * @return string DBMS specific SQL code portion needed to set the COLLATION | |
+ * of a field declaration. | |
+ */ | |
+ function _getCollationFieldDeclaration($collation) | |
+ { | |
+ return 'COLLATE '.$collation; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to declare | |
+ * of the given type | |
+ * | |
+ * @param string $type type to which the value should be converted to | |
+ * @param string $name name the field to be declared. | |
+ * @param string $field definition of the field | |
+ * | |
+ * @return string DBMS-specific SQL code portion that should be used to | |
+ * declare the specified field. | |
+ * @access public | |
+ */ | |
+ function getDeclaration($type, $name, $field) | |
+ { | |
+ // MySQL DDL syntax forbids combining NOT NULL with DEFAULT NULL. | |
+ // To get a default of NULL for NOT NULL columns, omit it. | |
+ if ( isset($field['notnull']) | |
+ && !empty($field['notnull']) | |
+ && array_key_exists('default', $field) // do not use isset() here! | |
+ && null === $field['default'] | |
+ ) { | |
+ unset($field['default']); | |
+ } | |
+ return parent::getDeclaration($type, $name, $field); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getTypeDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to declare an text type | |
+ * field to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param array $field associative array with the name of the properties | |
+ * of the field being declared as array indexes. Currently, the types | |
+ * of supported field properties are as follows: | |
+ * | |
+ * length | |
+ * Integer value that determines the maximum length of the text | |
+ * field. If this argument is missing the field should be | |
+ * declared to have the longest length allowed by the DBMS. | |
+ * | |
+ * default | |
+ * Text value to be used as default for this field. | |
+ * | |
+ * notnull | |
+ * Boolean flag that indicates whether this field is constrained | |
+ * to not be set to null. | |
+ * @return string DBMS specific SQL code portion that should be used to | |
+ * declare the specified field. | |
+ * @access public | |
+ */ | |
+ function getTypeDeclaration($field) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ switch ($field['type']) { | |
+ case 'text': | |
+ if (empty($field['length']) && array_key_exists('default', $field)) { | |
+ $field['length'] = $db->varchar_max_length; | |
+ } | |
+ $length = !empty($field['length']) ? $field['length'] : false; | |
+ $fixed = !empty($field['fixed']) ? $field['fixed'] : false; | |
+ return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)') | |
+ : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); | |
+ case 'clob': | |
+ if (!empty($field['length'])) { | |
+ $length = $field['length']; | |
+ if ($length <= 255) { | |
+ return 'TINYTEXT'; | |
+ } elseif ($length <= 65532) { | |
+ return 'TEXT'; | |
+ } elseif ($length <= 16777215) { | |
+ return 'MEDIUMTEXT'; | |
+ } | |
+ } | |
+ return 'LONGTEXT'; | |
+ case 'blob': | |
+ if (!empty($field['length'])) { | |
+ $length = $field['length']; | |
+ if ($length <= 255) { | |
+ return 'TINYBLOB'; | |
+ } elseif ($length <= 65532) { | |
+ return 'BLOB'; | |
+ } elseif ($length <= 16777215) { | |
+ return 'MEDIUMBLOB'; | |
+ } | |
+ } | |
+ return 'LONGBLOB'; | |
+ case 'integer': | |
+ if (!empty($field['length'])) { | |
+ $length = $field['length']; | |
+ if ($length <= 1) { | |
+ return 'TINYINT'; | |
+ } elseif ($length == 2) { | |
+ return 'SMALLINT'; | |
+ } elseif ($length == 3) { | |
+ return 'MEDIUMINT'; | |
+ } elseif ($length == 4) { | |
+ return 'INT'; | |
+ } elseif ($length > 4) { | |
+ return 'BIGINT'; | |
+ } | |
+ } | |
+ return 'INT'; | |
+ case 'boolean': | |
+ return 'TINYINT(1)'; | |
+ case 'date': | |
+ return 'DATE'; | |
+ case 'time': | |
+ return 'TIME'; | |
+ case 'timestamp': | |
+ return 'DATETIME'; | |
+ case 'float': | |
+ $l = ''; | |
+ if (!empty($field['length'])) { | |
+ $l = '(' . $field['length']; | |
+ if (!empty($field['scale'])) { | |
+ $l .= ',' . $field['scale']; | |
+ } | |
+ $l .= ')'; | |
+ } | |
+ return 'DOUBLE' . $l; | |
+ case 'decimal': | |
+ $length = !empty($field['length']) ? $field['length'] : 18; | |
+ $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places']; | |
+ return 'DECIMAL('.$length.','.$scale.')'; | |
+ } | |
+ return ''; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getIntegerDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to declare an integer type | |
+ * field to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param string $name name the field to be declared. | |
+ * @param string $field associative array with the name of the properties | |
+ * of the field being declared as array indexes. | |
+ * Currently, the types of supported field | |
+ * properties are as follows: | |
+ * | |
+ * unsigned | |
+ * Boolean flag that indicates whether the field | |
+ * should be declared as unsigned integer if | |
+ * possible. | |
+ * | |
+ * default | |
+ * Integer value to be used as default for this | |
+ * field. | |
+ * | |
+ * notnull | |
+ * Boolean flag that indicates whether this field is | |
+ * constrained to not be set to null. | |
+ * @return string DBMS specific SQL code portion that should be used to | |
+ * declare the specified field. | |
+ * @access protected | |
+ */ | |
+ function _getIntegerDeclaration($name, $field) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $default = $autoinc = ''; | |
+ if (!empty($field['autoincrement'])) { | |
+ $autoinc = ' AUTO_INCREMENT PRIMARY KEY'; | |
+ } elseif (array_key_exists('default', $field)) { | |
+ if ($field['default'] === '') { | |
+ $field['default'] = empty($field['notnull']) ? null : 0; | |
+ } | |
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); | |
+ } | |
+ | |
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; | |
+ $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; | |
+ if (empty($default) && empty($notnull)) { | |
+ $default = ' DEFAULT NULL'; | |
+ } | |
+ $name = $db->quoteIdentifier($name, true); | |
+ return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getFloatDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to declare an float type | |
+ * field to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param string $name name the field to be declared. | |
+ * @param string $field associative array with the name of the properties | |
+ * of the field being declared as array indexes. | |
+ * Currently, the types of supported field | |
+ * properties are as follows: | |
+ * | |
+ * unsigned | |
+ * Boolean flag that indicates whether the field | |
+ * should be declared as unsigned float if | |
+ * possible. | |
+ * | |
+ * default | |
+ * float value to be used as default for this | |
+ * field. | |
+ * | |
+ * notnull | |
+ * Boolean flag that indicates whether this field is | |
+ * constrained to not be set to null. | |
+ * @return string DBMS specific SQL code portion that should be used to | |
+ * declare the specified field. | |
+ * @access protected | |
+ */ | |
+ function _getFloatDeclaration($name, $field) | |
+ { | |
+ // Since AUTO_INCREMENT can be used for integer or floating-point types, | |
+ // reuse the INTEGER declaration | |
+ // @see http://bugs.mysql.com/bug.php?id=31032 | |
+ return $this->_getIntegerDeclaration($name, $field); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getDecimalDeclaration() | |
+ | |
+ /** | |
+ * Obtain DBMS specific SQL code portion needed to declare an decimal type | |
+ * field to be used in statements like CREATE TABLE. | |
+ * | |
+ * @param string $name name the field to be declared. | |
+ * @param string $field associative array with the name of the properties | |
+ * of the field being declared as array indexes. | |
+ * Currently, the types of supported field | |
+ * properties are as follows: | |
+ * | |
+ * unsigned | |
+ * Boolean flag that indicates whether the field | |
+ * should be declared as unsigned integer if | |
+ * possible. | |
+ * | |
+ * default | |
+ * Decimal value to be used as default for this | |
+ * field. | |
+ * | |
+ * notnull | |
+ * Boolean flag that indicates whether this field is | |
+ * constrained to not be set to null. | |
+ * @return string DBMS specific SQL code portion that should be used to | |
+ * declare the specified field. | |
+ * @access protected | |
+ */ | |
+ function _getDecimalDeclaration($name, $field) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $default = ''; | |
+ if (array_key_exists('default', $field)) { | |
+ if ($field['default'] === '') { | |
+ $field['default'] = empty($field['notnull']) ? null : 0; | |
+ } | |
+ $default = ' DEFAULT '.$this->quote($field['default'], 'integer'); | |
+ } elseif (empty($field['notnull'])) { | |
+ $default = ' DEFAULT NULL'; | |
+ } | |
+ | |
+ $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; | |
+ $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED'; | |
+ $name = $db->quoteIdentifier($name, true); | |
+ return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ matchPattern() | |
+ | |
+ /** | |
+ * build a pattern matching string | |
+ * | |
+ * @access public | |
+ * | |
+ * @param array $pattern even keys are strings, odd are patterns (% and _) | |
+ * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) | |
+ * @param string $field optional field name that is being matched against | |
+ * (might be required when emulating ILIKE) | |
+ * | |
+ * @return string SQL pattern | |
+ */ | |
+ function matchPattern($pattern, $operator = null, $field = null) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $match = ''; | |
+ if (null !== $operator) { | |
+ $field = (null === $field) ? '' : $field.' '; | |
+ $operator = strtoupper($operator); | |
+ switch ($operator) { | |
+ // case insensitive | |
+ case 'ILIKE': | |
+ $match = $field.'LIKE '; | |
+ break; | |
+ case 'NOT ILIKE': | |
+ $match = $field.'NOT LIKE '; | |
+ break; | |
+ // case sensitive | |
+ case 'LIKE': | |
+ $match = $field.'LIKE BINARY '; | |
+ break; | |
+ case 'NOT LIKE': | |
+ $match = $field.'NOT LIKE BINARY '; | |
+ break; | |
+ default: | |
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'not a supported operator type:'. $operator, __FUNCTION__); | |
+ } | |
+ } | |
+ $match.= "'"; | |
+ foreach ($pattern as $key => $value) { | |
+ if ($key % 2) { | |
+ $match.= $value; | |
+ } else { | |
+ $match.= $db->escapePattern($db->escape($value)); | |
+ } | |
+ } | |
+ $match.= "'"; | |
+ $match.= $this->patternEscapeString(); | |
+ return $match; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _mapNativeDatatype() | |
+ | |
+ /** | |
+ * Maps a native array description of a field to a MDB2 datatype and length | |
+ * | |
+ * @param array $field native field description | |
+ * @return array containing the various possible types, length, sign, fixed | |
+ * @access public | |
+ */ | |
+ function _mapNativeDatatype($field) | |
+ { | |
+ $db_type = strtolower($field['type']); | |
+ $db_type = strtok($db_type, '(), '); | |
+ if ($db_type == 'national') { | |
+ $db_type = strtok('(), '); | |
+ } | |
+ if (!empty($field['length'])) { | |
+ $length = strtok($field['length'], ', '); | |
+ $decimal = strtok(', '); | |
+ } else { | |
+ $length = strtok('(), '); | |
+ $decimal = strtok('(), '); | |
+ } | |
+ $type = array(); | |
+ $unsigned = $fixed = null; | |
+ switch ($db_type) { | |
+ case 'tinyint': | |
+ $type[] = 'integer'; | |
+ $type[] = 'boolean'; | |
+ if (preg_match('/^(is|has)/', $field['name'])) { | |
+ $type = array_reverse($type); | |
+ } | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ $length = 1; | |
+ break; | |
+ case 'smallint': | |
+ $type[] = 'integer'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ $length = 2; | |
+ break; | |
+ case 'mediumint': | |
+ $type[] = 'integer'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ $length = 3; | |
+ break; | |
+ case 'int': | |
+ case 'integer': | |
+ $type[] = 'integer'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ $length = 4; | |
+ break; | |
+ case 'bigint': | |
+ $type[] = 'integer'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ $length = 8; | |
+ break; | |
+ case 'tinytext': | |
+ case 'mediumtext': | |
+ case 'longtext': | |
+ case 'text': | |
+ case 'varchar': | |
+ $fixed = false; | |
+ case 'string': | |
+ case 'char': | |
+ $type[] = 'text'; | |
+ if ($length == '1') { | |
+ $type[] = 'boolean'; | |
+ if (preg_match('/^(is|has)/', $field['name'])) { | |
+ $type = array_reverse($type); | |
+ } | |
+ } elseif (strstr($db_type, 'text')) { | |
+ $type[] = 'clob'; | |
+ if ($decimal == 'binary') { | |
+ $type[] = 'blob'; | |
+ } | |
+ $type = array_reverse($type); | |
+ } | |
+ if ($fixed !== false) { | |
+ $fixed = true; | |
+ } | |
+ break; | |
+ case 'enum': | |
+ $type[] = 'text'; | |
+ preg_match_all('/\'.+\'/U', $field['type'], $matches); | |
+ $length = 0; | |
+ $fixed = false; | |
+ if (is_array($matches)) { | |
+ foreach ($matches[0] as $value) { | |
+ $length = max($length, strlen($value)-2); | |
+ } | |
+ if ($length == '1' && count($matches[0]) == 2) { | |
+ $type[] = 'boolean'; | |
+ if (preg_match('/^(is|has)/', $field['name'])) { | |
+ $type = array_reverse($type); | |
+ } | |
+ } | |
+ } | |
+ $type[] = 'integer'; | |
+ case 'set': | |
+ $fixed = false; | |
+ $type[] = 'text'; | |
+ $type[] = 'integer'; | |
+ break; | |
+ case 'date': | |
+ $type[] = 'date'; | |
+ $length = null; | |
+ break; | |
+ case 'datetime': | |
+ case 'timestamp': | |
+ $type[] = 'timestamp'; | |
+ $length = null; | |
+ break; | |
+ case 'time': | |
+ $type[] = 'time'; | |
+ $length = null; | |
+ break; | |
+ case 'float': | |
+ case 'double': | |
+ case 'real': | |
+ $type[] = 'float'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ if ($decimal !== false) { | |
+ $length = $length.','.$decimal; | |
+ } | |
+ break; | |
+ case 'unknown': | |
+ case 'decimal': | |
+ case 'numeric': | |
+ $type[] = 'decimal'; | |
+ $unsigned = preg_match('/ unsigned/i', $field['type']); | |
+ if ($decimal !== false) { | |
+ $length = $length.','.$decimal; | |
+ } | |
+ break; | |
+ case 'tinyblob': | |
+ case 'mediumblob': | |
+ case 'longblob': | |
+ case 'blob': | |
+ $type[] = 'blob'; | |
+ $length = null; | |
+ break; | |
+ case 'binary': | |
+ case 'varbinary': | |
+ $type[] = 'blob'; | |
+ break; | |
+ case 'year': | |
+ $type[] = 'integer'; | |
+ $type[] = 'date'; | |
+ $length = null; | |
+ break; | |
+ default: | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'unknown database attribute type: '.$db_type, __FUNCTION__); | |
+ } | |
+ | |
+ if ((int)$length <= 0) { | |
+ $length = null; | |
+ } | |
+ | |
+ return array($type, $length, $unsigned, $fixed); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ mapPrepareDatatype() | |
+ | |
+ /** | |
+ * Maps an MDB2 datatype to native prepare type | |
+ * | |
+ * @param string $type | |
+ * @return string | |
+ * @access public | |
+ */ | |
+ function mapPrepareDatatype($type) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ if (!empty($db->options['datatype_map'][$type])) { | |
+ $type = $db->options['datatype_map'][$type]; | |
+ if (!empty($db->options['datatype_map_callback'][$type])) { | |
+ $parameter = array('type' => $type); | |
+ return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); | |
+ } | |
+ } | |
+ | |
+ switch ($type) { | |
+ case 'boolean': | |
+ case 'integer': | |
+ return 'i'; | |
+ case 'float': | |
+ return 'd'; | |
+ case 'blob': | |
+ return 'b'; | |
+ default: | |
+ break; | |
+ } | |
+ return 's'; | |
+ } | |
+ | |
+ // }}} | |
+} | |
+?> | |
Index: data/module/MDB2/Driver/Function/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/Function/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/Function/mysqli.php (working copy) | |
@@ -0,0 +1,144 @@ | |
+<?php | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 327310 2012-08-27 15:16:18Z danielc $ | |
+// | |
+ | |
+require_once 'MDB2/Driver/Function/Common.php'; | |
+ | |
+/** | |
+ * MDB2 MySQLi driver for the function modules | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Driver_Function_mysqli extends MDB2_Driver_Function_Common | |
+{ | |
+ // }}} | |
+ // {{{ executeStoredProc() | |
+ | |
+ /** | |
+ * Execute a stored procedure and return any results | |
+ * | |
+ * @param string $name string that identifies the function to execute | |
+ * @param mixed $params array that contains the paramaters to pass the stored proc | |
+ * @param mixed $types array that contains the types of the columns in | |
+ * the result set | |
+ * @param mixed $result_class string which specifies which result class to use | |
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in | |
+ * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $multi_query = $db->getOption('multi_query'); | |
+ if (!$multi_query) { | |
+ $db->setOption('multi_query', true); | |
+ } | |
+ $query = 'CALL '.$name; | |
+ $query .= $params ? '('.implode(', ', $params).')' : '()'; | |
+ $result = $db->query($query, $types, $result_class, $result_wrap_class); | |
+ if (!$multi_query) { | |
+ $db->setOption('multi_query', false); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ unixtimestamp() | |
+ | |
+ /** | |
+ * return string to call a function to get the unix timestamp from a iso timestamp | |
+ * | |
+ * @param string $expression | |
+ * | |
+ * @return string to call a variable with the timestamp | |
+ * @access public | |
+ */ | |
+ function unixtimestamp($expression) | |
+ { | |
+ return 'UNIX_TIMESTAMP('. $expression.')'; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ concat() | |
+ | |
+ /** | |
+ * Returns string to concatenate two or more string parameters | |
+ * | |
+ * @param string $value1 | |
+ * @param string $value2 | |
+ * @param string $values... | |
+ * @return string to concatenate two strings | |
+ * @access public | |
+ **/ | |
+ function concat($value1, $value2) | |
+ { | |
+ $args = func_get_args(); | |
+ return "CONCAT(".implode(', ', $args).")"; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ guid() | |
+ | |
+ /** | |
+ * Returns global unique identifier | |
+ * | |
+ * @return string to get global unique identifier | |
+ * @access public | |
+ */ | |
+ function guid() | |
+ { | |
+ return 'UUID()'; | |
+ } | |
+ | |
+ // }}} | |
+} | |
+?> | |
Index: data/module/MDB2/Driver/Manager/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/Manager/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/Manager/mysqli.php (working copy) | |
@@ -0,0 +1,1471 @@ | |
+<?php | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 327310 2012-08-27 15:16:18Z danielc $ | |
+// | |
+ | |
+require_once 'MDB2/Driver/Manager/Common.php'; | |
+ | |
+/** | |
+ * MDB2 MySQLi driver for the management modules | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Driver_Manager_mysqli extends MDB2_Driver_Manager_Common | |
+{ | |
+ | |
+ // }}} | |
+ // {{{ createDatabase() | |
+ | |
+ /** | |
+ * create a new database | |
+ * | |
+ * @param string $name name of the database that should be created | |
+ * @param array $options array with charset, collation info | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function createDatabase($name, $options = array()) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $name = $db->quoteIdentifier($name, true); | |
+ $query = 'CREATE DATABASE ' . $name; | |
+ if (!empty($options['charset'])) { | |
+ $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text'); | |
+ } | |
+ if (!empty($options['collation'])) { | |
+ $query .= ' COLLATE ' . $db->quote($options['collation'], 'text'); | |
+ } | |
+ return $db->standaloneQuery($query, null, true); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ alterDatabase() | |
+ | |
+ /** | |
+ * alter an existing database | |
+ * | |
+ * @param string $name name of the database that is intended to be changed | |
+ * @param array $options array with charset, collation info | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function alterDatabase($name, $options = array()) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true); | |
+ if (!empty($options['charset'])) { | |
+ $query .= ' DEFAULT CHARACTER SET ' . $db->quote($options['charset'], 'text'); | |
+ } | |
+ if (!empty($options['collation'])) { | |
+ $query .= ' COLLATE ' . $db->quote($options['collation'], 'text'); | |
+ } | |
+ return $db->standaloneQuery($query, null, true); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ dropDatabase() | |
+ | |
+ /** | |
+ * drop an existing database | |
+ * | |
+ * @param string $name name of the database that should be dropped | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function dropDatabase($name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $name = $db->quoteIdentifier($name, true); | |
+ $query = "DROP DATABASE $name"; | |
+ return $db->standaloneQuery($query, null, true); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getAdvancedFKOptions() | |
+ | |
+ /** | |
+ * Return the FOREIGN KEY query section dealing with non-standard options | |
+ * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... | |
+ * | |
+ * @param array $definition | |
+ * @return string | |
+ * @access protected | |
+ */ | |
+ function _getAdvancedFKOptions($definition) | |
+ { | |
+ $query = ''; | |
+ if (!empty($definition['match'])) { | |
+ $query .= ' MATCH '.$definition['match']; | |
+ } | |
+ if (!empty($definition['onupdate'])) { | |
+ $query .= ' ON UPDATE '.$definition['onupdate']; | |
+ } | |
+ if (!empty($definition['ondelete'])) { | |
+ $query .= ' ON DELETE '.$definition['ondelete']; | |
+ } | |
+ return $query; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ createTable() | |
+ | |
+ /** | |
+ * create a new table | |
+ * | |
+ * @param string $name Name of the database that should be created | |
+ * @param array $fields Associative array that contains the definition of each field of the new table | |
+ * The indexes of the array entries are the names of the fields of the table an | |
+ * the array entry values are associative arrays like those that are meant to be | |
+ * passed with the field definitions to get[Type]Declaration() functions. | |
+ * array( | |
+ * 'id' => array( | |
+ * 'type' => 'integer', | |
+ * 'unsigned' => 1 | |
+ * 'notnull' => 1 | |
+ * 'default' => 0 | |
+ * ), | |
+ * 'name' => array( | |
+ * 'type' => 'text', | |
+ * 'length' => 12 | |
+ * ), | |
+ * 'password' => array( | |
+ * 'type' => 'text', | |
+ * 'length' => 12 | |
+ * ) | |
+ * ); | |
+ * @param array $options An associative array of table options: | |
+ * array( | |
+ * 'comment' => 'Foo', | |
+ * 'charset' => 'utf8', | |
+ * 'collate' => 'utf8_unicode_ci', | |
+ * 'type' => 'innodb', | |
+ * ); | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function createTable($name, $fields, $options = array()) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ // if we have an AUTO_INCREMENT column and a PK on more than one field, | |
+ // we have to handle it differently... | |
+ $autoincrement = null; | |
+ if (empty($options['primary'])) { | |
+ $pk_fields = array(); | |
+ foreach ($fields as $fieldname => $def) { | |
+ if (!empty($def['primary'])) { | |
+ $pk_fields[$fieldname] = true; | |
+ } | |
+ if (!empty($def['autoincrement'])) { | |
+ $autoincrement = $fieldname; | |
+ } | |
+ } | |
+ if ((null !== $autoincrement) && count($pk_fields) > 1) { | |
+ $options['primary'] = $pk_fields; | |
+ } else { | |
+ // the PK constraint is on max one field => OK | |
+ $autoincrement = null; | |
+ } | |
+ } | |
+ | |
+ $query = $this->_getCreateTableQuery($name, $fields, $options); | |
+ if (MDB2::isError($query)) { | |
+ return $query; | |
+ } | |
+ | |
+ if (null !== $autoincrement) { | |
+ // we have to remove the PK clause added by _getIntegerDeclaration() | |
+ $query = str_replace('AUTO_INCREMENT PRIMARY KEY', 'AUTO_INCREMENT', $query); | |
+ } | |
+ | |
+ $options_strings = array(); | |
+ | |
+ if (!empty($options['comment'])) { | |
+ $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); | |
+ } | |
+ | |
+ if (!empty($options['charset'])) { | |
+ $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; | |
+ if (!empty($options['collate'])) { | |
+ $options_strings['charset'].= ' COLLATE '.$options['collate']; | |
+ } | |
+ } | |
+ | |
+ $type = false; | |
+ if (!empty($options['type'])) { | |
+ $type = $options['type']; | |
+ } elseif ($db->options['default_table_type']) { | |
+ $type = $db->options['default_table_type']; | |
+ } | |
+ if ($type) { | |
+ $options_strings[] = "ENGINE = $type"; | |
+ } | |
+ | |
+ if (!empty($options_strings)) { | |
+ $query .= ' '.implode(' ', $options_strings); | |
+ } | |
+ $result = $db->exec($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ dropTable() | |
+ | |
+ /** | |
+ * drop an existing table | |
+ * | |
+ * @param string $name name of the table that should be dropped | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function dropTable($name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ //delete the triggers associated to existing FK constraints | |
+ $constraints = $this->listTableConstraints($name); | |
+ if (!MDB2::isError($constraints) && !empty($constraints)) { | |
+ $db->loadModule('Reverse', null, true); | |
+ foreach ($constraints as $constraint) { | |
+ $definition = $db->reverse->getTableConstraintDefinition($name, $constraint); | |
+ if (!MDB2::isError($definition) && !empty($definition['foreign'])) { | |
+ $result = $this->_dropFKTriggers($name, $constraint, $definition['references']['table']); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ return parent::dropTable($name); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ truncateTable() | |
+ | |
+ /** | |
+ * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, | |
+ * it falls back to a DELETE FROM TABLE query) | |
+ * | |
+ * @param string $name name of the table that should be truncated | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function truncateTable($name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $name = $db->quoteIdentifier($name, true); | |
+ $result = $db->exec("TRUNCATE TABLE $name"); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ vacuum() | |
+ | |
+ /** | |
+ * Optimize (vacuum) all the tables in the db (or only the specified table) | |
+ * and optionally run ANALYZE. | |
+ * | |
+ * @param string $table table name (all the tables if empty) | |
+ * @param array $options an array with driver-specific options: | |
+ * - timeout [int] (in seconds) [mssql-only] | |
+ * - analyze [boolean] [pgsql and mysql] | |
+ * - full [boolean] [pgsql-only] | |
+ * - freeze [boolean] [pgsql-only] | |
+ * | |
+ * @return mixed MDB2_OK success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function vacuum($table = null, $options = array()) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ if (empty($table)) { | |
+ $table = $this->listTables(); | |
+ if (MDB2::isError($table)) { | |
+ return $table; | |
+ } | |
+ } | |
+ if (is_array($table)) { | |
+ foreach (array_keys($table) as $k) { | |
+ $table[$k] = $db->quoteIdentifier($table[$k], true); | |
+ } | |
+ $table = implode(', ', $table); | |
+ } else { | |
+ $table = $db->quoteIdentifier($table, true); | |
+ } | |
+ | |
+ $result = $db->exec('OPTIMIZE TABLE '.$table); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ if (!empty($options['analyze'])) { | |
+ $result = $db->exec('ANALYZE TABLE '.$table); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ alterTable() | |
+ | |
+ /** | |
+ * alter an existing table | |
+ * | |
+ * @param string $name name of the table that is intended to be changed. | |
+ * @param array $changes associative array that contains the details of each type | |
+ * of change that is intended to be performed. The types of | |
+ * changes that are currently supported are defined as follows: | |
+ * | |
+ * name | |
+ * | |
+ * New name for the table. | |
+ * | |
+ * add | |
+ * | |
+ * Associative array with the names of fields to be added as | |
+ * indexes of the array. The value of each entry of the array | |
+ * should be set to another associative array with the properties | |
+ * of the fields to be added. The properties of the fields should | |
+ * be the same as defined by the MDB2 parser. | |
+ * | |
+ * | |
+ * remove | |
+ * | |
+ * Associative array with the names of fields to be removed as indexes | |
+ * of the array. Currently the values assigned to each entry are ignored. | |
+ * An empty array should be used for future compatibility. | |
+ * | |
+ * rename | |
+ * | |
+ * Associative array with the names of fields to be renamed as indexes | |
+ * of the array. The value of each entry of the array should be set to | |
+ * another associative array with the entry named name with the new | |
+ * field name and the entry named Declaration that is expected to contain | |
+ * the portion of the field declaration already in DBMS specific SQL code | |
+ * as it is used in the CREATE TABLE statement. | |
+ * | |
+ * change | |
+ * | |
+ * Associative array with the names of the fields to be changed as indexes | |
+ * of the array. Keep in mind that if it is intended to change either the | |
+ * name of a field and any other properties, the change array entries | |
+ * should have the new names of the fields as array indexes. | |
+ * | |
+ * The value of each entry of the array should be set to another associative | |
+ * array with the properties of the fields to that are meant to be changed as | |
+ * array entries. These entries should be assigned to the new values of the | |
+ * respective properties. The properties of the fields should be the same | |
+ * as defined by the MDB2 parser. | |
+ * | |
+ * Example | |
+ * array( | |
+ * 'name' => 'userlist', | |
+ * 'add' => array( | |
+ * 'quota' => array( | |
+ * 'type' => 'integer', | |
+ * 'unsigned' => 1 | |
+ * ) | |
+ * ), | |
+ * 'remove' => array( | |
+ * 'file_limit' => array(), | |
+ * 'time_limit' => array() | |
+ * ), | |
+ * 'change' => array( | |
+ * 'name' => array( | |
+ * 'length' => '20', | |
+ * 'definition' => array( | |
+ * 'type' => 'text', | |
+ * 'length' => 20, | |
+ * ), | |
+ * ) | |
+ * ), | |
+ * 'rename' => array( | |
+ * 'sex' => array( | |
+ * 'name' => 'gender', | |
+ * 'definition' => array( | |
+ * 'type' => 'text', | |
+ * 'length' => 1, | |
+ * 'default' => 'M', | |
+ * ), | |
+ * ) | |
+ * ) | |
+ * ) | |
+ * | |
+ * @param boolean $check indicates whether the function should just check if the DBMS driver | |
+ * can perform the requested table alterations if the value is true or | |
+ * actually perform them otherwise. | |
+ * @access public | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ */ | |
+ function alterTable($name, $changes, $check) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ foreach ($changes as $change_name => $change) { | |
+ switch ($change_name) { | |
+ case 'add': | |
+ case 'remove': | |
+ case 'change': | |
+ case 'rename': | |
+ case 'name': | |
+ break; | |
+ default: | |
+ return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, | |
+ 'change type "'.$change_name.'" not yet supported', __FUNCTION__); | |
+ } | |
+ } | |
+ | |
+ if ($check) { | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ $query = ''; | |
+ if (!empty($changes['name'])) { | |
+ $change_name = $db->quoteIdentifier($changes['name'], true); | |
+ $query .= 'RENAME TO ' . $change_name; | |
+ } | |
+ | |
+ if (!empty($changes['add']) && is_array($changes['add'])) { | |
+ foreach ($changes['add'] as $field_name => $field) { | |
+ if ($query) { | |
+ $query.= ', '; | |
+ } | |
+ $query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field); | |
+ } | |
+ } | |
+ | |
+ if (!empty($changes['remove']) && is_array($changes['remove'])) { | |
+ foreach ($changes['remove'] as $field_name => $field) { | |
+ if ($query) { | |
+ $query.= ', '; | |
+ } | |
+ $field_name = $db->quoteIdentifier($field_name, true); | |
+ $query.= 'DROP ' . $field_name; | |
+ } | |
+ } | |
+ | |
+ $rename = array(); | |
+ if (!empty($changes['rename']) && is_array($changes['rename'])) { | |
+ foreach ($changes['rename'] as $field_name => $field) { | |
+ $rename[$field['name']] = $field_name; | |
+ } | |
+ } | |
+ | |
+ if (!empty($changes['change']) && is_array($changes['change'])) { | |
+ foreach ($changes['change'] as $field_name => $field) { | |
+ if ($query) { | |
+ $query.= ', '; | |
+ } | |
+ if (isset($rename[$field_name])) { | |
+ $old_field_name = $rename[$field_name]; | |
+ unset($rename[$field_name]); | |
+ } else { | |
+ $old_field_name = $field_name; | |
+ } | |
+ $old_field_name = $db->quoteIdentifier($old_field_name, true); | |
+ $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type'], $field_name, $field['definition']); | |
+ } | |
+ } | |
+ | |
+ if (!empty($rename) && is_array($rename)) { | |
+ foreach ($rename as $rename_name => $renamed_field) { | |
+ if ($query) { | |
+ $query.= ', '; | |
+ } | |
+ $field = $changes['rename'][$renamed_field]; | |
+ $renamed_field = $db->quoteIdentifier($renamed_field, true); | |
+ $query.= 'CHANGE ' . $renamed_field . ' ' . $db->getDeclaration($field['definition']['type'], $field['name'], $field['definition']); | |
+ } | |
+ } | |
+ | |
+ if (!$query) { | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ $name = $db->quoteIdentifier($name, true); | |
+ $result = $db->exec("ALTER TABLE $name $query"); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listDatabases() | |
+ | |
+ /** | |
+ * list all databases | |
+ * | |
+ * @return mixed array of database names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listDatabases() | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $result = $db->queryCol('SHOW DATABASES'); | |
+ if (MDB2::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 (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER'); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listFunctions() | |
+ | |
+ /** | |
+ * list all functions in the current database | |
+ * | |
+ * @return mixed array of function names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listFunctions() | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::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 (MDB2::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 (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $query = 'SHOW TRIGGERS'; | |
+ if (null !== $table) { | |
+ $table = $db->quote($table, 'text'); | |
+ $query .= " LIKE $table"; | |
+ } | |
+ $result = $db->queryCol($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listTables() | |
+ | |
+ /** | |
+ * list all tables in the current database | |
+ * | |
+ * @param string database, the current is default | |
+ * @return mixed array of table names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listTables($database = null) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $query = "SHOW /*!50002 FULL*/ TABLES"; | |
+ if (null !== $database) { | |
+ $query .= " FROM $database"; | |
+ } | |
+ $query.= "/*!50002 WHERE Table_type = 'BASE TABLE'*/"; | |
+ | |
+ $table_names = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED); | |
+ if (MDB2::isError($table_names)) { | |
+ return $table_names; | |
+ } | |
+ | |
+ $result = array(); | |
+ foreach ($table_names as $table) { | |
+ if (!$this->_fixSequenceName($table[0], true)) { | |
+ $result[] = $table[0]; | |
+ } | |
+ } | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listViews() | |
+ | |
+ /** | |
+ * list all views in the current database | |
+ * | |
+ * @param string database, the current is default | |
+ * @return mixed array of view names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listViews($database = null) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $query = 'SHOW FULL TABLES'; | |
+ if (null !== $database) { | |
+ $query.= " FROM $database"; | |
+ } | |
+ $query.= " WHERE Table_type = 'VIEW'"; | |
+ | |
+ $result = $db->queryCol($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listTableFields() | |
+ | |
+ /** | |
+ * list all fields in a table in the current database | |
+ * | |
+ * @param string $table name of table that should be used in method | |
+ * @return mixed array of field names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listTableFields($table) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $result = $db->queryCol("SHOW COLUMNS FROM $table"); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ createIndex() | |
+ | |
+ /** | |
+ * Get the stucture of a field into an array | |
+ * | |
+ * @author Leoncx | |
+ * @param string $table name of the table on which the index is to be created | |
+ * @param string $name name of the index to be created | |
+ * @param array $definition associative array that defines properties of the index to be created. | |
+ * Currently, only one property named FIELDS is supported. This property | |
+ * is also an associative with the names of the index fields as array | |
+ * indexes. Each entry of this array is set to another type of associative | |
+ * array that specifies properties of the index that are specific to | |
+ * each field. | |
+ * | |
+ * Currently, only the sorting property is supported. It should be used | |
+ * to define the sorting direction of the index. It may be set to either | |
+ * ascending or descending. | |
+ * | |
+ * Not all DBMS support index sorting direction configuration. The DBMS | |
+ * drivers of those that do not support it ignore this property. Use the | |
+ * function supports() to determine whether the DBMS driver can manage indexes. | |
+ * | |
+ * Example | |
+ * array( | |
+ * 'fields' => array( | |
+ * 'user_name' => array( | |
+ * 'sorting' => 'ascending' | |
+ * 'length' => 10 | |
+ * ), | |
+ * 'last_login' => array() | |
+ * ) | |
+ * ) | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function createIndex($table, $name, $definition) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $name = $db->quoteIdentifier($db->getIndexName($name), true); | |
+ $query = "CREATE INDEX $name ON $table"; | |
+ $fields = array(); | |
+ foreach ($definition['fields'] as $field => $fieldinfo) { | |
+ if (!empty($fieldinfo['length'])) { | |
+ $fields[] = $db->quoteIdentifier($field, true) . '(' . $fieldinfo['length'] . ')'; | |
+ } else { | |
+ $fields[] = $db->quoteIdentifier($field, true); | |
+ } | |
+ } | |
+ $query .= ' ('. implode(', ', $fields) . ')'; | |
+ $result = $db->exec($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ 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 (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $name = $db->quoteIdentifier($db->getIndexName($name), true); | |
+ $result = $db->exec("DROP INDEX $name ON $table"); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listTableIndexes() | |
+ | |
+ /** | |
+ * list all indexes in a table | |
+ * | |
+ * @param string $table name of table that should be used in method | |
+ * @return mixed array of index names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listTableIndexes($table) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $key_name = 'Key_name'; | |
+ $non_unique = 'Non_unique'; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $key_name = strtolower($key_name); | |
+ $non_unique = strtolower($non_unique); | |
+ } else { | |
+ $key_name = strtoupper($key_name); | |
+ $non_unique = strtoupper($non_unique); | |
+ } | |
+ } | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $query = "SHOW INDEX FROM $table"; | |
+ $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); | |
+ if (MDB2::isError($indexes)) { | |
+ return $indexes; | |
+ } | |
+ | |
+ $result = array(); | |
+ foreach ($indexes as $index_data) { | |
+ if ($index_data[$non_unique] && ($index = $this->_fixIndexName($index_data[$key_name]))) { | |
+ $result[$index] = true; | |
+ } | |
+ } | |
+ | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_change_key_case($result, $db->options['field_case']); | |
+ } | |
+ return array_keys($result); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ createConstraint() | |
+ | |
+ /** | |
+ * create a constraint on a table | |
+ * | |
+ * @param string $table name of the table on which the constraint is to be created | |
+ * @param string $name name of the constraint to be created | |
+ * @param array $definition associative array that defines properties of the constraint to be created. | |
+ * Currently, only one property named FIELDS is supported. This property | |
+ * is also an associative with the names of the constraint fields as array | |
+ * constraints. Each entry of this array is set to another type of associative | |
+ * array that specifies properties of the constraint that are specific to | |
+ * each field. | |
+ * | |
+ * Example | |
+ * array( | |
+ * 'fields' => array( | |
+ * 'user_name' => array(), | |
+ * 'last_login' => array() | |
+ * ) | |
+ * ) | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function createConstraint($table, $name, $definition) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $type = ''; | |
+ $idx_name = $db->quoteIdentifier($db->getIndexName($name), true); | |
+ if (!empty($definition['primary'])) { | |
+ $type = 'PRIMARY'; | |
+ $idx_name = 'KEY'; | |
+ } elseif (!empty($definition['unique'])) { | |
+ $type = 'UNIQUE'; | |
+ } elseif (!empty($definition['foreign'])) { | |
+ $type = 'CONSTRAINT'; | |
+ } | |
+ if (empty($type)) { | |
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'invalid definition, could not create constraint', __FUNCTION__); | |
+ } | |
+ | |
+ $table_quoted = $db->quoteIdentifier($table, true); | |
+ $query = "ALTER TABLE $table_quoted ADD $type $idx_name"; | |
+ if (!empty($definition['foreign'])) { | |
+ $query .= ' FOREIGN KEY'; | |
+ } | |
+ $fields = array(); | |
+ foreach ($definition['fields'] as $field => $fieldinfo) { | |
+ $quoted = $db->quoteIdentifier($field, true); | |
+ if (!empty($fieldinfo['length'])) { | |
+ $quoted .= '(' . $fieldinfo['length'] . ')'; | |
+ } | |
+ $fields[] = $quoted; | |
+ } | |
+ $query .= ' ('. implode(', ', $fields) . ')'; | |
+ if (!empty($definition['foreign'])) { | |
+ $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true); | |
+ $referenced_fields = array(); | |
+ foreach (array_keys($definition['references']['fields']) as $field) { | |
+ $referenced_fields[] = $db->quoteIdentifier($field, true); | |
+ } | |
+ $query .= ' ('. implode(', ', $referenced_fields) . ')'; | |
+ $query .= $this->_getAdvancedFKOptions($definition); | |
+ | |
+ // add index on FK column(s) or we can't add a FK constraint | |
+ // @see http://forums.mysql.com/read.php?22,19755,226009 | |
+ $result = $this->createIndex($table, $name.'_fkidx', $definition); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ $res = $db->exec($query); | |
+ if (MDB2::isError($res)) { | |
+ return $res; | |
+ } | |
+ if (!empty($definition['foreign'])) { | |
+ return $this->_createFKTriggers($table, array($name => $definition)); | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ dropConstraint() | |
+ | |
+ /** | |
+ * drop existing constraint | |
+ * | |
+ * @param string $table name of table that should be used in method | |
+ * @param string $name name of the constraint to be dropped | |
+ * @param string $primary hint if the constraint is primary | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function dropConstraint($table, $name, $primary = false) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ if ($primary || strtolower($name) == 'primary') { | |
+ $query = 'ALTER TABLE '. $db->quoteIdentifier($table, true) .' DROP PRIMARY KEY'; | |
+ $result = $db->exec($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ //is it a FK constraint? If so, also delete the associated triggers | |
+ $db->loadModule('Reverse', null, true); | |
+ $definition = $db->reverse->getTableConstraintDefinition($table, $name); | |
+ if (!MDB2::isError($definition) && !empty($definition['foreign'])) { | |
+ //first drop the FK enforcing triggers | |
+ $result = $this->_dropFKTriggers($table, $name, $definition['references']['table']); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ //then drop the constraint itself | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $name = $db->quoteIdentifier($db->getIndexName($name), true); | |
+ $query = "ALTER TABLE $table DROP FOREIGN KEY $name"; | |
+ $result = $db->exec($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $name = $db->quoteIdentifier($db->getIndexName($name), true); | |
+ $query = "ALTER TABLE $table DROP INDEX $name"; | |
+ $result = $db->exec($query); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _createFKTriggers() | |
+ | |
+ /** | |
+ * Create triggers to enforce the FOREIGN KEY constraint on the table | |
+ * | |
+ * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql, | |
+ * we call a non-existent procedure to raise the FK violation message. | |
+ * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877 | |
+ * | |
+ * @param string $table table name | |
+ * @param array $foreign_keys FOREIGN KEY definitions | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access private | |
+ */ | |
+ function _createFKTriggers($table, $foreign_keys) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ // create triggers to enforce FOREIGN KEY constraints | |
+ if ($db->supports('triggers') && !empty($foreign_keys)) { | |
+ $table_quoted = $db->quoteIdentifier($table, true); | |
+ foreach ($foreign_keys as $fkname => $fkdef) { | |
+ if (empty($fkdef)) { | |
+ continue; | |
+ } | |
+ //set actions to default if not set | |
+ $fkdef['onupdate'] = empty($fkdef['onupdate']) ? $db->options['default_fk_action_onupdate'] : strtoupper($fkdef['onupdate']); | |
+ $fkdef['ondelete'] = empty($fkdef['ondelete']) ? $db->options['default_fk_action_ondelete'] : strtoupper($fkdef['ondelete']); | |
+ | |
+ $trigger_names = array( | |
+ 'insert' => $fkname.'_insert_trg', | |
+ 'update' => $fkname.'_update_trg', | |
+ 'pk_update' => $fkname.'_pk_update_trg', | |
+ 'pk_delete' => $fkname.'_pk_delete_trg', | |
+ ); | |
+ $table_fields = array_keys($fkdef['fields']); | |
+ $referenced_fields = array_keys($fkdef['references']['fields']); | |
+ | |
+ //create the ON [UPDATE|DELETE] triggers on the primary table | |
+ $restrict_action = ' IF (SELECT '; | |
+ $aliased_fields = array(); | |
+ foreach ($table_fields as $field) { | |
+ $aliased_fields[] = $table_quoted .'.'.$field .' AS '.$field; | |
+ } | |
+ $restrict_action .= implode(',', $aliased_fields) | |
+ .' FROM '.$table_quoted | |
+ .' WHERE '; | |
+ $conditions = array(); | |
+ $new_values = array(); | |
+ $null_values = array(); | |
+ for ($i=0; $i<count($table_fields); $i++) { | |
+ $conditions[] = $table_fields[$i] .' = OLD.'.$referenced_fields[$i]; | |
+ $new_values[] = $table_fields[$i] .' = NEW.'.$referenced_fields[$i]; | |
+ $null_values[] = $table_fields[$i] .' = NULL'; | |
+ } | |
+ $conditions2 = array(); | |
+ for ($i=0; $i<count($referenced_fields); $i++) { | |
+ $conditions2[] = 'NEW.'.$referenced_fields[$i] .' <> OLD.'.$referenced_fields[$i]; | |
+ } | |
+ | |
+ $restrict_action .= implode(' AND ', $conditions).') IS NOT NULL'; | |
+ $restrict_action2 = empty($conditions2) ? '' : ' AND (' .implode(' OR ', $conditions2) .')'; | |
+ $restrict_action3 = ' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();' | |
+ .' END IF;'; | |
+ | |
+ $restrict_action_update = $restrict_action . $restrict_action2 . $restrict_action3; | |
+ $restrict_action_delete = $restrict_action . $restrict_action3; // There is no NEW row in on DELETE trigger | |
+ | |
+ $cascade_action_update = 'UPDATE '.$table_quoted.' SET '.implode(', ', $new_values) .' WHERE '.implode(' AND ', $conditions). ';'; | |
+ $cascade_action_delete = 'DELETE FROM '.$table_quoted.' WHERE '.implode(' AND ', $conditions). ';'; | |
+ $setnull_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $null_values).' WHERE '.implode(' AND ', $conditions). ';'; | |
+ | |
+ if ('SET DEFAULT' == $fkdef['onupdate'] || 'SET DEFAULT' == $fkdef['ondelete']) { | |
+ $db->loadModule('Reverse', null, true); | |
+ $default_values = array(); | |
+ foreach ($table_fields as $table_field) { | |
+ $field_definition = $db->reverse->getTableFieldDefinition($table, $field); | |
+ if (MDB2::isError($field_definition)) { | |
+ return $field_definition; | |
+ } | |
+ $default_values[] = $table_field .' = '. $field_definition[0]['default']; | |
+ } | |
+ $setdefault_action = 'UPDATE '.$table_quoted.' SET '.implode(', ', $default_values).' WHERE '.implode(' AND ', $conditions). ';'; | |
+ } | |
+ | |
+ $query = 'CREATE TRIGGER %s' | |
+ .' %s ON '.$fkdef['references']['table'] | |
+ .' FOR EACH ROW BEGIN ' | |
+ .' SET FOREIGN_KEY_CHECKS = 0; '; //only really needed for ON UPDATE CASCADE | |
+ | |
+ if ('CASCADE' == $fkdef['onupdate']) { | |
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $cascade_action_update; | |
+ } elseif ('SET NULL' == $fkdef['onupdate']) { | |
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setnull_action; | |
+ } elseif ('SET DEFAULT' == $fkdef['onupdate']) { | |
+ $sql_update = sprintf($query, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update') . $setdefault_action; | |
+ } elseif ('NO ACTION' == $fkdef['onupdate']) { | |
+ $sql_update = sprintf($query.$restrict_action_update, $trigger_names['pk_update'], 'AFTER UPDATE', 'update'); | |
+ } elseif ('RESTRICT' == $fkdef['onupdate']) { | |
+ $sql_update = sprintf($query.$restrict_action_update, $trigger_names['pk_update'], 'BEFORE UPDATE', 'update'); | |
+ } | |
+ if ('CASCADE' == $fkdef['ondelete']) { | |
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $cascade_action_delete; | |
+ } elseif ('SET NULL' == $fkdef['ondelete']) { | |
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setnull_action; | |
+ } elseif ('SET DEFAULT' == $fkdef['ondelete']) { | |
+ $sql_delete = sprintf($query, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete') . $setdefault_action; | |
+ } elseif ('NO ACTION' == $fkdef['ondelete']) { | |
+ $sql_delete = sprintf($query.$restrict_action_delete, $trigger_names['pk_delete'], 'AFTER DELETE', 'delete'); | |
+ } elseif ('RESTRICT' == $fkdef['ondelete']) { | |
+ $sql_delete = sprintf($query.$restrict_action_delete, $trigger_names['pk_delete'], 'BEFORE DELETE', 'delete'); | |
+ } | |
+ $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;'; | |
+ $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;'; | |
+ | |
+ $db->pushErrorHandling(PEAR_ERROR_RETURN); | |
+ $db->expectError(MDB2_ERROR_CANNOT_CREATE); | |
+ $result = $db->exec($sql_delete); | |
+ $expected_errmsg = 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table'; | |
+ $db->popExpect(); | |
+ $db->popErrorHandling(); | |
+ if (MDB2::isError($result)) { | |
+ if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) { | |
+ return $result; | |
+ } | |
+ $db->warnings[] = $expected_errmsg; | |
+ } | |
+ $db->pushErrorHandling(PEAR_ERROR_RETURN); | |
+ $db->expectError(MDB2_ERROR_CANNOT_CREATE); | |
+ $result = $db->exec($sql_update); | |
+ $db->popExpect(); | |
+ $db->popErrorHandling(); | |
+ if (MDB2::isError($result) && $result->getCode() != MDB2_ERROR_CANNOT_CREATE) { | |
+ if ($result->getCode() != MDB2_ERROR_CANNOT_CREATE) { | |
+ return $result; | |
+ } | |
+ $db->warnings[] = $expected_errmsg; | |
+ } | |
+ } | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _dropFKTriggers() | |
+ | |
+ /** | |
+ * Drop the triggers created to enforce the FOREIGN KEY constraint on the table | |
+ * | |
+ * @param string $table table name | |
+ * @param string $fkname FOREIGN KEY constraint name | |
+ * @param string $referenced_table referenced table name | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access private | |
+ */ | |
+ function _dropFKTriggers($table, $fkname, $referenced_table) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $triggers = $this->listTableTriggers($table); | |
+ $triggers2 = $this->listTableTriggers($referenced_table); | |
+ if (!MDB2::isError($triggers2) && !MDB2::isError($triggers)) { | |
+ $triggers = array_merge($triggers, $triggers2); | |
+ $pattern = '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i'; | |
+ foreach ($triggers as $trigger) { | |
+ if (preg_match($pattern, $trigger)) { | |
+ $result = $db->exec('DROP TRIGGER '.$trigger); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listTableConstraints() | |
+ | |
+ /** | |
+ * list all constraints in a table | |
+ * | |
+ * @param string $table name of table that should be used in method | |
+ * @return mixed array of constraint names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listTableConstraints($table) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $key_name = 'Key_name'; | |
+ $non_unique = 'Non_unique'; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $key_name = strtolower($key_name); | |
+ $non_unique = strtolower($non_unique); | |
+ } else { | |
+ $key_name = strtoupper($key_name); | |
+ $non_unique = strtoupper($non_unique); | |
+ } | |
+ } | |
+ | |
+ $query = 'SHOW INDEX FROM ' . $db->quoteIdentifier($table, true); | |
+ $indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); | |
+ if (MDB2::isError($indexes)) { | |
+ return $indexes; | |
+ } | |
+ | |
+ $result = array(); | |
+ foreach ($indexes as $index_data) { | |
+ if (!$index_data[$non_unique]) { | |
+ if ($index_data[$key_name] !== 'PRIMARY') { | |
+ $index = $this->_fixIndexName($index_data[$key_name]); | |
+ } else { | |
+ $index = 'PRIMARY'; | |
+ } | |
+ if (!empty($index)) { | |
+ $result[$index] = true; | |
+ } | |
+ } | |
+ } | |
+ | |
+ //list FOREIGN KEY constraints... | |
+ $query = 'SHOW CREATE TABLE '. $db->escape($table); | |
+ $definition = $db->queryOne($query, 'text', 1); | |
+ if (!MDB2::isError($definition) && !empty($definition)) { | |
+ $pattern = '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims'; | |
+ if (preg_match_all($pattern, str_replace('`', '', $definition), $matches) > 0) { | |
+ foreach ($matches[1] as $constraint) { | |
+ $result[$constraint] = true; | |
+ } | |
+ } | |
+ } | |
+ | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_change_key_case($result, $db->options['field_case']); | |
+ } | |
+ return array_keys($result); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ createSequence() | |
+ | |
+ /** | |
+ * create sequence | |
+ * | |
+ * @param string $seq_name name of the sequence to be created | |
+ * @param string $start start value of the sequence; default is 1 | |
+ * @param array $options An associative array of table options: | |
+ * array( | |
+ * 'comment' => 'Foo', | |
+ * 'charset' => 'utf8', | |
+ * 'collate' => 'utf8_unicode_ci', | |
+ * 'type' => 'innodb', | |
+ * ); | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function createSequence($seq_name, $start = 1, $options = array()) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); | |
+ $seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true); | |
+ | |
+ $options_strings = array(); | |
+ | |
+ if (!empty($options['comment'])) { | |
+ $options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text'); | |
+ } | |
+ | |
+ if (!empty($options['charset'])) { | |
+ $options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset']; | |
+ if (!empty($options['collate'])) { | |
+ $options_strings['charset'].= ' COLLATE '.$options['collate']; | |
+ } | |
+ } | |
+ | |
+ $type = false; | |
+ if (!empty($options['type'])) { | |
+ $type = $options['type']; | |
+ } elseif ($db->options['default_table_type']) { | |
+ $type = $db->options['default_table_type']; | |
+ } | |
+ if ($type) { | |
+ $options_strings[] = "ENGINE = $type"; | |
+ } | |
+ | |
+ $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))"; | |
+ if (!empty($options_strings)) { | |
+ $query .= ' '.implode(' ', $options_strings); | |
+ } | |
+ $res = $db->exec($query); | |
+ if (MDB2::isError($res)) { | |
+ return $res; | |
+ } | |
+ | |
+ if ($start == 1) { | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')'; | |
+ $res = $db->exec($query); | |
+ if (!MDB2::isError($res)) { | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // Handle error | |
+ $result = $db->exec("DROP TABLE $sequence_name"); | |
+ if (MDB2::isError($result)) { | |
+ return $db->raiseError($result, null, null, | |
+ 'could not drop inconsistent sequence table', __FUNCTION__); | |
+ } | |
+ | |
+ return $db->raiseError($res, null, null, | |
+ 'could not create sequence table', __FUNCTION__); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ dropSequence() | |
+ | |
+ /** | |
+ * drop existing sequence | |
+ * | |
+ * @param string $seq_name name of the sequence to be dropped | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function dropSequence($seq_name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); | |
+ $result = $db->exec("DROP TABLE $sequence_name"); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ listSequences() | |
+ | |
+ /** | |
+ * list all sequences in the current database | |
+ * | |
+ * @param string database, the current is default | |
+ * @return mixed array of sequence names on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function listSequences($database = null) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $query = "SHOW TABLES"; | |
+ if (null !== $database) { | |
+ $query .= " FROM $database"; | |
+ } | |
+ $table_names = $db->queryCol($query); | |
+ if (MDB2::isError($table_names)) { | |
+ return $table_names; | |
+ } | |
+ | |
+ $result = array(); | |
+ foreach ($table_names as $table_name) { | |
+ if ($sqn = $this->_fixSequenceName($table_name, true)) { | |
+ $result[] = $sqn; | |
+ } | |
+ } | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+} | |
+?> | |
Index: data/module/MDB2/Driver/Native/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/Native/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/Native/mysqli.php (working copy) | |
@@ -0,0 +1,60 @@ | |
+<?php | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 215004 2006-06-18 21:59:05Z lsmith $ | |
+// | |
+ | |
+require_once 'MDB2/Driver/Native/Common.php'; | |
+ | |
+/** | |
+ * MDB2 MySQLi driver for the native module | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Driver_Native_mysqli extends MDB2_Driver_Native_Common | |
+{ | |
+} | |
+?> | |
\ No newline at end of file | |
Index: data/module/MDB2/Driver/Reverse/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/Reverse/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/Reverse/mysqli.php (working copy) | |
@@ -0,0 +1,610 @@ | |
+<?php | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 327310 2012-08-27 15:16:18Z danielc $ | |
+// | |
+ | |
+require_once 'MDB2/Driver/Reverse/Common.php'; | |
+ | |
+/** | |
+ * MDB2 MySQLi driver for the schema reverse engineering module | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ * @author Lorenzo Alberton <l.alberton@quipo.it> | |
+ */ | |
+class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common | |
+{ | |
+ /** | |
+ * Array for converting MYSQLI_*_FLAG constants to text values | |
+ * @var array | |
+ * @access public | |
+ */ | |
+ var $flags = array( | |
+ MYSQLI_NOT_NULL_FLAG => 'not_null', | |
+ MYSQLI_PRI_KEY_FLAG => 'primary_key', | |
+ MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', | |
+ MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', | |
+ MYSQLI_BLOB_FLAG => 'blob', | |
+ MYSQLI_UNSIGNED_FLAG => 'unsigned', | |
+ MYSQLI_ZEROFILL_FLAG => 'zerofill', | |
+ MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', | |
+ MYSQLI_TIMESTAMP_FLAG => 'timestamp', | |
+ MYSQLI_SET_FLAG => 'set', | |
+ // MYSQLI_NUM_FLAG => 'numeric', // unnecessary | |
+ // MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie | |
+ MYSQLI_GROUP_FLAG => 'group_by' | |
+ ); | |
+ | |
+ /** | |
+ * Array for converting MYSQLI_TYPE_* constants to text values | |
+ * @var array | |
+ * @access public | |
+ */ | |
+ var $types = array( | |
+ MYSQLI_TYPE_DECIMAL => 'decimal', | |
+ 246 => 'decimal', | |
+ MYSQLI_TYPE_TINY => 'tinyint', | |
+ MYSQLI_TYPE_SHORT => 'int', | |
+ MYSQLI_TYPE_LONG => 'int', | |
+ MYSQLI_TYPE_FLOAT => 'float', | |
+ MYSQLI_TYPE_DOUBLE => 'double', | |
+ // MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it | |
+ MYSQLI_TYPE_TIMESTAMP => 'timestamp', | |
+ MYSQLI_TYPE_LONGLONG => 'bigint', | |
+ MYSQLI_TYPE_INT24 => 'mediumint', | |
+ MYSQLI_TYPE_DATE => 'date', | |
+ MYSQLI_TYPE_TIME => 'time', | |
+ MYSQLI_TYPE_DATETIME => 'datetime', | |
+ MYSQLI_TYPE_YEAR => 'year', | |
+ MYSQLI_TYPE_NEWDATE => 'date', | |
+ MYSQLI_TYPE_ENUM => 'enum', | |
+ MYSQLI_TYPE_SET => 'set', | |
+ MYSQLI_TYPE_TINY_BLOB => 'tinyblob', | |
+ MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', | |
+ MYSQLI_TYPE_LONG_BLOB => 'longblob', | |
+ MYSQLI_TYPE_BLOB => 'blob', | |
+ MYSQLI_TYPE_VAR_STRING => 'varchar', | |
+ MYSQLI_TYPE_STRING => 'char', | |
+ MYSQLI_TYPE_GEOMETRY => 'geometry', | |
+ ); | |
+ | |
+ // {{{ getTableFieldDefinition() | |
+ | |
+ /** | |
+ * Get the structure of a field into an array | |
+ * | |
+ * @param string $table_name name of table that should be used in method | |
+ * @param string $field_name name of field that should be used in method | |
+ * @return mixed data array on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function getTableFieldDefinition($table_name, $field_name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $result = $db->loadModule('Datatype', null, true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ | |
+ list($schema, $table) = $this->splitTableSchema($table_name); | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $query = "SHOW FULL COLUMNS FROM $table LIKE ".$db->quote($field_name); | |
+ $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); | |
+ if (MDB2::isError($columns)) { | |
+ return $columns; | |
+ } | |
+ foreach ($columns as $column) { | |
+ $column = array_change_key_case($column, CASE_LOWER); | |
+ $column['name'] = $column['field']; | |
+ unset($column['field']); | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $column['name'] = strtolower($column['name']); | |
+ } else { | |
+ $column['name'] = strtoupper($column['name']); | |
+ } | |
+ } else { | |
+ $column = array_change_key_case($column, $db->options['field_case']); | |
+ } | |
+ if ($field_name == $column['name']) { | |
+ $mapped_datatype = $db->datatype->mapNativeDatatype($column); | |
+ if (MDB2::isError($mapped_datatype)) { | |
+ return $mapped_datatype; | |
+ } | |
+ list($types, $length, $unsigned, $fixed) = $mapped_datatype; | |
+ $notnull = false; | |
+ if (empty($column['null']) || $column['null'] !== 'YES') { | |
+ $notnull = true; | |
+ } | |
+ $default = false; | |
+ if (array_key_exists('default', $column)) { | |
+ $default = $column['default']; | |
+ if ((null === $default) && $notnull) { | |
+ $default = ''; | |
+ } | |
+ } | |
+ $definition[0] = array( | |
+ 'notnull' => $notnull, | |
+ 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type']) | |
+ ); | |
+ $autoincrement = false; | |
+ if (!empty($column['extra'])) { | |
+ if ($column['extra'] == 'auto_increment') { | |
+ $autoincrement = true; | |
+ } else { | |
+ $definition[0]['extra'] = $column['extra']; | |
+ } | |
+ } | |
+ $collate = null; | |
+ if (!empty($column['collation'])) { | |
+ $collate = $column['collation']; | |
+ $charset = preg_replace('/(.+?)(_.+)?/', '$1', $collate); | |
+ } | |
+ | |
+ if (null !== $length) { | |
+ $definition[0]['length'] = $length; | |
+ } | |
+ if (null !== $unsigned) { | |
+ $definition[0]['unsigned'] = $unsigned; | |
+ } | |
+ if (null !== $fixed) { | |
+ $definition[0]['fixed'] = $fixed; | |
+ } | |
+ if ($default !== false) { | |
+ $definition[0]['default'] = $default; | |
+ } | |
+ if ($autoincrement !== false) { | |
+ $definition[0]['autoincrement'] = $autoincrement; | |
+ } | |
+ if (null !== $collate) { | |
+ $definition[0]['collate'] = $collate; | |
+ $definition[0]['charset'] = $charset; | |
+ } | |
+ foreach ($types as $key => $type) { | |
+ $definition[$key] = $definition[0]; | |
+ if ($type == 'clob' || $type == 'blob') { | |
+ unset($definition[$key]['default']); | |
+ } elseif ($type == 'timestamp' && $notnull && empty($definition[$key]['default'])) { | |
+ $definition[$key]['default'] = '0000-00-00 00:00:00'; | |
+ } | |
+ $definition[$key]['type'] = $type; | |
+ $definition[$key]['mdb2type'] = $type; | |
+ } | |
+ return $definition; | |
+ } | |
+ } | |
+ | |
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ 'it was not specified an existing table column', __FUNCTION__); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getTableIndexDefinition() | |
+ | |
+ /** | |
+ * Get the structure of an index into an array | |
+ * | |
+ * @param string $table_name name of table that should be used in method | |
+ * @param string $index_name name of index that should be used in method | |
+ * @return mixed data array on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function getTableIndexDefinition($table_name, $index_name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ list($schema, $table) = $this->splitTableSchema($table_name); | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; | |
+ $index_name_mdb2 = $db->getIndexName($index_name); | |
+ $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2))); | |
+ if (!MDB2::isError($result) && (null !== $result)) { | |
+ // apply 'idxname_format' only if the query succeeded, otherwise | |
+ // fallback to the given $index_name, without transformation | |
+ $index_name = $index_name_mdb2; | |
+ } | |
+ $result = $db->query(sprintf($query, $db->quote($index_name))); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ $colpos = 1; | |
+ $definition = array(); | |
+ while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { | |
+ $row = array_change_key_case($row, CASE_LOWER); | |
+ $key_name = $row['key_name']; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $key_name = strtolower($key_name); | |
+ } else { | |
+ $key_name = strtoupper($key_name); | |
+ } | |
+ } | |
+ if ($index_name == $key_name) { | |
+ if (!$row['non_unique']) { | |
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ $index_name . ' is not an existing table index', __FUNCTION__); | |
+ } | |
+ $column_name = $row['column_name']; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $column_name = strtolower($column_name); | |
+ } else { | |
+ $column_name = strtoupper($column_name); | |
+ } | |
+ } | |
+ $definition['fields'][$column_name] = array( | |
+ 'position' => $colpos++ | |
+ ); | |
+ if (!empty($row['collation'])) { | |
+ $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' | |
+ ? 'ascending' : 'descending'); | |
+ } | |
+ } | |
+ } | |
+ $result->free(); | |
+ if (empty($definition['fields'])) { | |
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ $index_name . ' is not an existing table index', __FUNCTION__); | |
+ } | |
+ return $definition; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getTableConstraintDefinition() | |
+ | |
+ /** | |
+ * Get the structure of a constraint into an array | |
+ * | |
+ * @param string $table_name name of table that should be used in method | |
+ * @param string $constraint_name name of constraint that should be used in method | |
+ * @return mixed data array on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function getTableConstraintDefinition($table_name, $constraint_name) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ list($schema, $table) = $this->splitTableSchema($table_name); | |
+ $constraint_name_original = $constraint_name; | |
+ | |
+ $table = $db->quoteIdentifier($table, true); | |
+ $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */"; | |
+ if (strtolower($constraint_name) != 'primary') { | |
+ $constraint_name_mdb2 = $db->getIndexName($constraint_name); | |
+ $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2))); | |
+ if (!MDB2::isError($result) && (null !== $result)) { | |
+ // apply 'idxname_format' only if the query succeeded, otherwise | |
+ // fallback to the given $index_name, without transformation | |
+ $constraint_name = $constraint_name_mdb2; | |
+ } | |
+ } | |
+ $result = $db->query(sprintf($query, $db->quote($constraint_name))); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ $colpos = 1; | |
+ //default values, eventually overridden | |
+ $definition = array( | |
+ 'primary' => false, | |
+ 'unique' => false, | |
+ 'foreign' => false, | |
+ 'check' => false, | |
+ 'fields' => array(), | |
+ 'references' => array( | |
+ 'table' => '', | |
+ 'fields' => array(), | |
+ ), | |
+ 'onupdate' => '', | |
+ 'ondelete' => '', | |
+ 'match' => '', | |
+ 'deferrable' => false, | |
+ 'initiallydeferred' => false, | |
+ ); | |
+ while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { | |
+ $row = array_change_key_case($row, CASE_LOWER); | |
+ $key_name = $row['key_name']; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $key_name = strtolower($key_name); | |
+ } else { | |
+ $key_name = strtoupper($key_name); | |
+ } | |
+ } | |
+ if ($constraint_name == $key_name) { | |
+ if ($row['non_unique']) { | |
+ //FOREIGN KEY? | |
+ return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition); | |
+ } | |
+ if ($row['key_name'] == 'PRIMARY') { | |
+ $definition['primary'] = true; | |
+ } elseif (!$row['non_unique']) { | |
+ $definition['unique'] = true; | |
+ } | |
+ $column_name = $row['column_name']; | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $column_name = strtolower($column_name); | |
+ } else { | |
+ $column_name = strtoupper($column_name); | |
+ } | |
+ } | |
+ $definition['fields'][$column_name] = array( | |
+ 'position' => $colpos++ | |
+ ); | |
+ if (!empty($row['collation'])) { | |
+ $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' | |
+ ? 'ascending' : 'descending'); | |
+ } | |
+ } | |
+ } | |
+ $result->free(); | |
+ if (empty($definition['fields'])) { | |
+ return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition); | |
+ } | |
+ return $definition; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getTableFKConstraintDefinition() | |
+ | |
+ /** | |
+ * Get the FK definition from the CREATE TABLE statement | |
+ * | |
+ * @param string $table table name | |
+ * @param string $constraint_name constraint name | |
+ * @param array $definition default values for constraint definition | |
+ * | |
+ * @return array|PEAR_Error | |
+ * @access private | |
+ */ | |
+ function _getTableFKConstraintDefinition($table, $constraint_name, $definition) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ //Use INFORMATION_SCHEMA instead? | |
+ //SELECT * | |
+ // FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS | |
+ // WHERE CONSTRAINT_SCHEMA = '$dbname' | |
+ // AND TABLE_NAME = '$table' | |
+ // AND CONSTRAINT_NAME = '$constraint_name'; | |
+ $query = 'SHOW CREATE TABLE '. $db->escape($table); | |
+ $constraint = $db->queryOne($query, 'text', 1); | |
+ if (!MDB2::isError($constraint) && !empty($constraint)) { | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $constraint = strtolower($constraint); | |
+ } else { | |
+ $constraint = strtoupper($constraint); | |
+ } | |
+ } | |
+ $constraint_name_original = $constraint_name; | |
+ $constraint_name = $db->getIndexName($constraint_name); | |
+ $pattern = '/\bCONSTRAINT\s+'.$constraint_name.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i'; | |
+ if (!preg_match($pattern, str_replace('`', '', $constraint), $matches)) { | |
+ //fallback to original constraint name | |
+ $pattern = '/\bCONSTRAINT\s+'.$constraint_name_original.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i'; | |
+ } | |
+ if (preg_match($pattern, str_replace('`', '', $constraint), $matches)) { | |
+ $definition['foreign'] = true; | |
+ $column_names = explode(',', $matches[1]); | |
+ $referenced_cols = explode(',', $matches[3]); | |
+ $definition['references'] = array( | |
+ 'table' => $matches[2], | |
+ 'fields' => array(), | |
+ ); | |
+ $colpos = 1; | |
+ foreach ($column_names as $column_name) { | |
+ $definition['fields'][trim($column_name)] = array( | |
+ 'position' => $colpos++ | |
+ ); | |
+ } | |
+ $colpos = 1; | |
+ foreach ($referenced_cols as $column_name) { | |
+ $definition['references']['fields'][trim($column_name)] = array( | |
+ 'position' => $colpos++ | |
+ ); | |
+ } | |
+ $definition['ondelete'] = empty($matches[4]) ? 'RESTRICT' : strtoupper($matches[4]); | |
+ $definition['onupdate'] = empty($matches[5]) ? 'RESTRICT' : strtoupper($matches[5]); | |
+ $definition['match'] = 'SIMPLE'; | |
+ return $definition; | |
+ } | |
+ } | |
+ return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ $constraint_name . ' is not an existing table constraint', __FUNCTION__); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getTriggerDefinition() | |
+ | |
+ /** | |
+ * Get the structure of a trigger into an array | |
+ * | |
+ * EXPERIMENTAL | |
+ * | |
+ * WARNING: this function is experimental and may change the returned value | |
+ * at any time until labelled as non-experimental | |
+ * | |
+ * @param string $trigger name of trigger that should be used in method | |
+ * @return mixed data array on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function getTriggerDefinition($trigger) | |
+ { | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::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 (MDB2::isError($def)) { | |
+ return $def; | |
+ } | |
+ $def['trigger_comment'] = ''; | |
+ $def['trigger_enabled'] = true; | |
+ return $def; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ tableInfo() | |
+ | |
+ /** | |
+ * Returns information about a table or a result set | |
+ * | |
+ * @param object|string $result MDB2_result object from a query or a | |
+ * string containing the name of a table. | |
+ * While this also accepts a query result | |
+ * resource identifier, this behavior is | |
+ * deprecated. | |
+ * @param int $mode a valid tableInfo mode | |
+ * | |
+ * @return array an associative array with the information requested. | |
+ * A MDB2_Error object on failure. | |
+ * | |
+ * @see MDB2_Driver_Common::setOption() | |
+ */ | |
+ function tableInfo($result, $mode = null) | |
+ { | |
+ if (is_string($result)) { | |
+ return parent::tableInfo($result, $mode); | |
+ } | |
+ | |
+ $db = $this->getDBInstance(); | |
+ if (MDB2::isError($db)) { | |
+ return $db; | |
+ } | |
+ | |
+ $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result; | |
+ if (!is_object($resource)) { | |
+ return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'Could not generate result resource', __FUNCTION__); | |
+ } | |
+ | |
+ if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ if ($db->options['field_case'] == CASE_LOWER) { | |
+ $case_func = 'strtolower'; | |
+ } else { | |
+ $case_func = 'strtoupper'; | |
+ } | |
+ } else { | |
+ $case_func = 'strval'; | |
+ } | |
+ | |
+ $count = @mysqli_num_fields($resource); | |
+ $res = array(); | |
+ if ($mode) { | |
+ $res['num_fields'] = $count; | |
+ } | |
+ | |
+ $db->loadModule('Datatype', null, true); | |
+ for ($i = 0; $i < $count; $i++) { | |
+ $tmp = @mysqli_fetch_field($resource); | |
+ | |
+ $flags = ''; | |
+ foreach ($this->flags as $const => $means) { | |
+ if ($tmp->flags & $const) { | |
+ $flags.= $means . ' '; | |
+ } | |
+ } | |
+ if ($tmp->def) { | |
+ $flags.= 'default_' . rawurlencode($tmp->def); | |
+ } | |
+ $flags = trim($flags); | |
+ | |
+ $res[$i] = array( | |
+ 'table' => $case_func($tmp->table), | |
+ 'name' => $case_func($tmp->name), | |
+ 'type' => isset($this->types[$tmp->type]) | |
+ ? $this->types[$tmp->type] : 'unknown', | |
+ // http://bugs.php.net/?id=36579 | |
+ 'length' => $tmp->length, | |
+ 'flags' => $flags, | |
+ ); | |
+ $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]); | |
+ if (MDB2::isError($mdb2type_info)) { | |
+ return $mdb2type_info; | |
+ } | |
+ $res[$i]['mdb2type'] = $mdb2type_info[0][0]; | |
+ if ($mode & MDB2_TABLEINFO_ORDER) { | |
+ $res['order'][$res[$i]['name']] = $i; | |
+ } | |
+ if ($mode & MDB2_TABLEINFO_ORDERTABLE) { | |
+ $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; | |
+ } | |
+ } | |
+ | |
+ return $res; | |
+ } | |
+} | |
+?> | |
Index: data/module/MDB2/Driver/mysqli.php | |
=================================================================== | |
--- data/module/MDB2/Driver/mysqli.php (revision 0) | |
+++ data/module/MDB2/Driver/mysqli.php (working copy) | |
@@ -0,0 +1,1905 @@ | |
+<?php | |
+// vim: set et ts=4 sw=4 fdm=marker: | |
+// +----------------------------------------------------------------------+ | |
+// | PHP versions 4 and 5 | | |
+// +----------------------------------------------------------------------+ | |
+// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | | |
+// | Stig. S. Bakken, Lukas Smith | | |
+// | All rights reserved. | | |
+// +----------------------------------------------------------------------+ | |
+// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | | |
+// | API as well as database abstraction for PHP applications. | | |
+// | This LICENSE is in the BSD license style. | | |
+// | | | |
+// | Redistribution and use in source and binary forms, with or without | | |
+// | modification, are permitted provided that the following conditions | | |
+// | are met: | | |
+// | | | |
+// | Redistributions of source code must retain the above copyright | | |
+// | notice, this list of conditions and the following disclaimer. | | |
+// | | | |
+// | Redistributions in binary form must reproduce the above copyright | | |
+// | notice, this list of conditions and the following disclaimer in the | | |
+// | documentation and/or other materials provided with the distribution. | | |
+// | | | |
+// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | | |
+// | Lukas Smith nor the names of his contributors may be used to endorse | | |
+// | or promote products derived from this software without specific prior| | |
+// | written permission. | | |
+// | | | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | |
+// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | |
+// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | |
+// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | |
+// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| | |
+// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | |
+// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | |
+// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| | |
+// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | |
+// | POSSIBILITY OF SUCH DAMAGE. | | |
+// +----------------------------------------------------------------------+ | |
+// | Author: Lukas Smith <smith@pooteeweet.org> | | |
+// +----------------------------------------------------------------------+ | |
+// | |
+// $Id: mysqli.php 327320 2012-08-27 15:52:50Z danielc $ | |
+// | |
+ | |
+/** | |
+ * MDB2 MySQLi driver | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Driver_mysqli extends MDB2_Driver_Common | |
+{ | |
+ // {{{ properties | |
+ | |
+ public $string_quoting = array( | |
+ 'start' => "'", | |
+ 'end' => "'", | |
+ 'escape' => '\\', | |
+ 'escape_pattern' => '\\', | |
+ ); | |
+ | |
+ public $identifier_quoting = array( | |
+ 'start' => '`', | |
+ 'end' => '`', | |
+ 'escape' => '`', | |
+ ); | |
+ | |
+ /** | |
+ * The ouptut of mysqli_errno() in _doQuery(), if any. | |
+ * @var integer | |
+ */ | |
+ protected $_query_errno; | |
+ | |
+ /** | |
+ * The ouptut of mysqli_error() in _doQuery(), if any. | |
+ * @var string | |
+ */ | |
+ protected $_query_error; | |
+ | |
+ public $sql_comments = array( | |
+ array('start' => '-- ', 'end' => "\n", 'escape' => false), | |
+ array('start' => '#', 'end' => "\n", 'escape' => false), | |
+ array('start' => '/*', 'end' => '*/', 'escape' => false), | |
+ ); | |
+ | |
+ protected $server_capabilities_checked = false; | |
+ | |
+ protected $start_transaction = false; | |
+ | |
+ public $varchar_max_length = 255; | |
+ | |
+ // }}} | |
+ // {{{ constructor | |
+ | |
+ /** | |
+ * Constructor | |
+ */ | |
+ function __construct() | |
+ { | |
+ parent::__construct(); | |
+ | |
+ $this->phptype = 'mysqli'; | |
+ $this->dbsyntax = 'mysql'; | |
+ | |
+ $this->supported['sequences'] = 'emulated'; | |
+ $this->supported['indexes'] = true; | |
+ $this->supported['affected_rows'] = true; | |
+ $this->supported['transactions'] = false; | |
+ $this->supported['savepoints'] = false; | |
+ $this->supported['summary_functions'] = true; | |
+ $this->supported['order_by_text'] = true; | |
+ $this->supported['current_id'] = 'emulated'; | |
+ $this->supported['limit_queries'] = true; | |
+ $this->supported['LOBs'] = true; | |
+ $this->supported['replace'] = true; | |
+ $this->supported['sub_selects'] = 'emulated'; | |
+ $this->supported['triggers'] = false; | |
+ $this->supported['auto_increment'] = true; | |
+ $this->supported['primary_key'] = true; | |
+ $this->supported['result_introspection'] = true; | |
+ $this->supported['prepared_statements'] = 'emulated'; | |
+ $this->supported['identifier_quoting'] = true; | |
+ $this->supported['pattern_escaping'] = true; | |
+ $this->supported['new_link'] = true; | |
+ | |
+ $this->options['DBA_username'] = false; | |
+ $this->options['DBA_password'] = false; | |
+ $this->options['default_table_type'] = ''; | |
+ $this->options['multi_query'] = false; | |
+ $this->options['max_identifiers_length'] = 64; | |
+ | |
+ $this->_reCheckSupportedOptions(); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _reCheckSupportedOptions() | |
+ | |
+ /** | |
+ * If the user changes certain options, other capabilities may depend | |
+ * on the new settings, so we need to check them (again). | |
+ * | |
+ * @access private | |
+ */ | |
+ function _reCheckSupportedOptions() | |
+ { | |
+ $this->supported['transactions'] = $this->options['use_transactions']; | |
+ $this->supported['savepoints'] = $this->options['use_transactions']; | |
+ if ($this->options['default_table_type']) { | |
+ switch (strtoupper($this->options['default_table_type'])) { | |
+ case 'BLACKHOLE': | |
+ case 'MEMORY': | |
+ case 'ARCHIVE': | |
+ case 'CSV': | |
+ case 'HEAP': | |
+ case 'ISAM': | |
+ case 'MERGE': | |
+ case 'MRG_ISAM': | |
+ case 'ISAM': | |
+ case 'MRG_MYISAM': | |
+ case 'MYISAM': | |
+ $this->supported['savepoints'] = false; | |
+ $this->supported['transactions'] = false; | |
+ $this->warnings[] = $this->options['default_table_type'] . | |
+ ' is not a supported default table type'; | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ function setOption($option, $value) | |
+ | |
+ /** | |
+ * set the option for the db class | |
+ * | |
+ * @param string option name | |
+ * @param mixed value for the option | |
+ * | |
+ * @return mixed MDB2_OK or MDB2 Error Object | |
+ * | |
+ * @access public | |
+ */ | |
+ function setOption($option, $value) | |
+ { | |
+ $res = parent::setOption($option, $value); | |
+ $this->_reCheckSupportedOptions(); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ errorInfo() | |
+ | |
+ /** | |
+ * This method is used to collect information about an error | |
+ * | |
+ * @param integer $error | |
+ * @return array | |
+ * @access public | |
+ */ | |
+ function errorInfo($error = null) | |
+ { | |
+ if ($this->_query_errno) { | |
+ $native_code = $this->_query_errno; | |
+ $native_msg = $this->_query_error; | |
+ } elseif ($this->connection) { | |
+ $native_code = @mysqli_errno($this->connection); | |
+ $native_msg = @mysqli_error($this->connection); | |
+ } else { | |
+ $native_code = @mysqli_connect_errno(); | |
+ $native_msg = @mysqli_connect_error(); | |
+ } | |
+ if (null === $error) { | |
+ static $ecode_map; | |
+ if (empty($ecode_map)) { | |
+ $ecode_map = array( | |
+ 1000 => MDB2_ERROR_INVALID, //hashchk | |
+ 1001 => MDB2_ERROR_INVALID, //isamchk | |
+ 1004 => MDB2_ERROR_CANNOT_CREATE, | |
+ 1005 => MDB2_ERROR_CANNOT_CREATE, | |
+ 1006 => MDB2_ERROR_CANNOT_CREATE, | |
+ 1007 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1008 => MDB2_ERROR_CANNOT_DROP, | |
+ 1009 => MDB2_ERROR_CANNOT_DROP, | |
+ 1010 => MDB2_ERROR_CANNOT_DROP, | |
+ 1011 => MDB2_ERROR_CANNOT_DELETE, | |
+ 1022 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1029 => MDB2_ERROR_NOT_FOUND, | |
+ 1032 => MDB2_ERROR_NOT_FOUND, | |
+ 1044 => MDB2_ERROR_ACCESS_VIOLATION, | |
+ 1045 => MDB2_ERROR_ACCESS_VIOLATION, | |
+ 1046 => MDB2_ERROR_NODBSELECTED, | |
+ 1048 => MDB2_ERROR_CONSTRAINT, | |
+ 1049 => MDB2_ERROR_NOSUCHDB, | |
+ 1050 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1051 => MDB2_ERROR_NOSUCHTABLE, | |
+ 1054 => MDB2_ERROR_NOSUCHFIELD, | |
+ 1060 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1061 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1062 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1064 => MDB2_ERROR_SYNTAX, | |
+ 1067 => MDB2_ERROR_INVALID, | |
+ 1072 => MDB2_ERROR_NOT_FOUND, | |
+ 1086 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1091 => MDB2_ERROR_NOT_FOUND, | |
+ 1100 => MDB2_ERROR_NOT_LOCKED, | |
+ 1109 => MDB2_ERROR_NOT_FOUND, | |
+ 1125 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1136 => MDB2_ERROR_VALUE_COUNT_ON_ROW, | |
+ 1138 => MDB2_ERROR_INVALID, | |
+ 1142 => MDB2_ERROR_ACCESS_VIOLATION, | |
+ 1143 => MDB2_ERROR_ACCESS_VIOLATION, | |
+ 1146 => MDB2_ERROR_NOSUCHTABLE, | |
+ 1149 => MDB2_ERROR_SYNTAX, | |
+ 1169 => MDB2_ERROR_CONSTRAINT, | |
+ 1176 => MDB2_ERROR_NOT_FOUND, | |
+ 1177 => MDB2_ERROR_NOSUCHTABLE, | |
+ 1213 => MDB2_ERROR_DEADLOCK, | |
+ 1216 => MDB2_ERROR_CONSTRAINT, | |
+ 1217 => MDB2_ERROR_CONSTRAINT, | |
+ 1227 => MDB2_ERROR_ACCESS_VIOLATION, | |
+ 1235 => MDB2_ERROR_CANNOT_CREATE, | |
+ 1299 => MDB2_ERROR_INVALID_DATE, | |
+ 1300 => MDB2_ERROR_INVALID, | |
+ 1304 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1305 => MDB2_ERROR_NOT_FOUND, | |
+ 1306 => MDB2_ERROR_CANNOT_DROP, | |
+ 1307 => MDB2_ERROR_CANNOT_CREATE, | |
+ 1334 => MDB2_ERROR_CANNOT_ALTER, | |
+ 1339 => MDB2_ERROR_NOT_FOUND, | |
+ 1356 => MDB2_ERROR_INVALID, | |
+ 1359 => MDB2_ERROR_ALREADY_EXISTS, | |
+ 1360 => MDB2_ERROR_NOT_FOUND, | |
+ 1363 => MDB2_ERROR_NOT_FOUND, | |
+ 1365 => MDB2_ERROR_DIVZERO, | |
+ 1451 => MDB2_ERROR_CONSTRAINT, | |
+ 1452 => MDB2_ERROR_CONSTRAINT, | |
+ 1542 => MDB2_ERROR_CANNOT_DROP, | |
+ 1546 => MDB2_ERROR_CONSTRAINT, | |
+ 1582 => MDB2_ERROR_CONSTRAINT, | |
+ 2003 => MDB2_ERROR_CONNECT_FAILED, | |
+ 2019 => MDB2_ERROR_INVALID, | |
+ ); | |
+ } | |
+ if ($this->options['portability'] & MDB2_PORTABILITY_ERRORS) { | |
+ $ecode_map[1022] = MDB2_ERROR_CONSTRAINT; | |
+ $ecode_map[1048] = MDB2_ERROR_CONSTRAINT_NOT_NULL; | |
+ $ecode_map[1062] = MDB2_ERROR_CONSTRAINT; | |
+ } else { | |
+ // Doing this in case mode changes during runtime. | |
+ $ecode_map[1022] = MDB2_ERROR_ALREADY_EXISTS; | |
+ $ecode_map[1048] = MDB2_ERROR_CONSTRAINT; | |
+ $ecode_map[1062] = MDB2_ERROR_ALREADY_EXISTS; | |
+ } | |
+ if (isset($ecode_map[$native_code])) { | |
+ $error = $ecode_map[$native_code]; | |
+ } | |
+ } | |
+ return array($error, $native_code, $native_msg); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ escape() | |
+ | |
+ /** | |
+ * Quotes a string so it can be safely used in a query. It will quote | |
+ * the text so it can safely be used within a query. | |
+ * | |
+ * @param string the input string to quote | |
+ * @param bool escape wildcards | |
+ * | |
+ * @return string quoted string | |
+ * | |
+ * @access public | |
+ */ | |
+ function escape($text, $escape_wildcards = false) | |
+ { | |
+ if ($escape_wildcards) { | |
+ $text = $this->escapePattern($text); | |
+ } | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ $text = @mysqli_real_escape_string($connection, $text); | |
+ return $text; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ beginTransaction() | |
+ | |
+ /** | |
+ * Start a transaction or set a savepoint. | |
+ * | |
+ * @param string name of a savepoint to set | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * | |
+ * @access public | |
+ */ | |
+ function beginTransaction($savepoint = null) | |
+ { | |
+ $this->debug('Starting transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); | |
+ $this->_getServerCapabilities(); | |
+ if (null !== $savepoint) { | |
+ if (!$this->supports('savepoints')) { | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'savepoints are not supported', __FUNCTION__); | |
+ } | |
+ if (!$this->in_transaction) { | |
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null, | |
+ 'savepoint cannot be released when changes are auto committed', __FUNCTION__); | |
+ } | |
+ $query = 'SAVEPOINT '.$savepoint; | |
+ return $this->_doQuery($query, true); | |
+ } | |
+ if ($this->in_transaction) { | |
+ return MDB2_OK; //nothing to do | |
+ } | |
+ $query = $this->start_transaction ? 'START TRANSACTION' : 'SET AUTOCOMMIT = 0'; | |
+ $result = $this->_doQuery($query, true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ $this->in_transaction = true; | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ commit() | |
+ | |
+ /** | |
+ * Commit the database changes done during a transaction that is in | |
+ * progress or release a savepoint. This function may only be called when | |
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new | |
+ * transaction is implicitly started after committing the pending changes. | |
+ * | |
+ * @param string name of a savepoint to release | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * | |
+ * @access public | |
+ */ | |
+ function commit($savepoint = null) | |
+ { | |
+ $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); | |
+ if (!$this->in_transaction) { | |
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null, | |
+ 'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__); | |
+ } | |
+ if (null !== $savepoint) { | |
+ if (!$this->supports('savepoints')) { | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'savepoints are not supported', __FUNCTION__); | |
+ } | |
+ $server_info = $this->getServerVersion(); | |
+ if (version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) { | |
+ return MDB2_OK; | |
+ } | |
+ $query = 'RELEASE SAVEPOINT '.$savepoint; | |
+ return $this->_doQuery($query, true); | |
+ } | |
+ | |
+ if (!$this->supports('transactions')) { | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'transactions are not supported', __FUNCTION__); | |
+ } | |
+ | |
+ $result = $this->_doQuery('COMMIT', true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ if (!$this->start_transaction) { | |
+ $query = 'SET AUTOCOMMIT = 1'; | |
+ $result = $this->_doQuery($query, true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ $this->in_transaction = false; | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ rollback() | |
+ | |
+ /** | |
+ * Cancel any database changes done during a transaction or since a specific | |
+ * savepoint that is in progress. This function may only be called when | |
+ * auto-committing is disabled, otherwise it will fail. Therefore, a new | |
+ * transaction is implicitly started after canceling the pending changes. | |
+ * | |
+ * @param string name of a savepoint to rollback to | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * | |
+ * @access public | |
+ */ | |
+ function rollback($savepoint = null) | |
+ { | |
+ $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); | |
+ if (!$this->in_transaction) { | |
+ return $this->raiseError(MDB2_ERROR_INVALID, null, null, | |
+ 'rollback cannot be done changes are auto committed', __FUNCTION__); | |
+ } | |
+ if (null !== $savepoint) { | |
+ if (!$this->supports('savepoints')) { | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'savepoints are not supported', __FUNCTION__); | |
+ } | |
+ $query = 'ROLLBACK TO SAVEPOINT '.$savepoint; | |
+ return $this->_doQuery($query, true); | |
+ } | |
+ | |
+ $query = 'ROLLBACK'; | |
+ $result = $this->_doQuery($query, true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ if (!$this->start_transaction) { | |
+ $query = 'SET AUTOCOMMIT = 1'; | |
+ $result = $this->_doQuery($query, true); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ $this->in_transaction = false; | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ function setTransactionIsolation() | |
+ | |
+ /** | |
+ * Set the transacton isolation level. | |
+ * | |
+ * @param string standard isolation level | |
+ * READ UNCOMMITTED (allows dirty reads) | |
+ * READ COMMITTED (prevents dirty reads) | |
+ * REPEATABLE READ (prevents nonrepeatable reads) | |
+ * SERIALIZABLE (prevents phantom reads) | |
+ * @param array some transaction options: | |
+ * 'wait' => 'WAIT' | 'NO WAIT' | |
+ * 'rw' => 'READ WRITE' | 'READ ONLY' | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * | |
+ * @access public | |
+ * @since 2.1.1 | |
+ */ | |
+ function setTransactionIsolation($isolation, $options = array()) | |
+ { | |
+ $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); | |
+ if (!$this->supports('transactions')) { | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'transactions are not supported', __FUNCTION__); | |
+ } | |
+ switch ($isolation) { | |
+ case 'READ UNCOMMITTED': | |
+ case 'READ COMMITTED': | |
+ case 'REPEATABLE READ': | |
+ case 'SERIALIZABLE': | |
+ break; | |
+ default: | |
+ return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, | |
+ 'isolation level is not supported: '.$isolation, __FUNCTION__); | |
+ } | |
+ | |
+ $query = "SET SESSION TRANSACTION ISOLATION LEVEL $isolation"; | |
+ return $this->_doQuery($query, true); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _doConnect() | |
+ | |
+ /** | |
+ * do the grunt work of the connect | |
+ * | |
+ * @return connection on success or MDB2 Error Object on failure | |
+ * @access protected | |
+ */ | |
+ function _doConnect($username, $password, $persistent = false) | |
+ { | |
+ if (!extension_loaded($this->phptype)) { | |
+ return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ 'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__); | |
+ } | |
+ | |
+ $connection = @mysqli_init(); | |
+ if (!empty($this->dsn['charset']) && defined('MYSQLI_SET_CHARSET_NAME')) { | |
+ @mysqli_options($connection, MYSQLI_SET_CHARSET_NAME, $this->dsn['charset']); | |
+ } | |
+ | |
+ if ($this->options['ssl']) { | |
+ @mysqli_ssl_set( | |
+ $connection, | |
+ empty($this->dsn['key']) ? null : $this->dsn['key'], | |
+ empty($this->dsn['cert']) ? null : $this->dsn['cert'], | |
+ empty($this->dsn['ca']) ? null : $this->dsn['ca'], | |
+ empty($this->dsn['capath']) ? null : $this->dsn['capath'], | |
+ empty($this->dsn['cipher']) ? null : $this->dsn['cipher'] | |
+ ); | |
+ } | |
+ | |
+ if (!mysqli_real_connect( | |
+ $connection, | |
+ $this->dsn['hostspec'], | |
+ $username, | |
+ $password, | |
+ $this->database_name, | |
+ $this->dsn['port'], | |
+ $this->dsn['socket'] | |
+ )) { | |
+ if (($err = @mysqli_connect_error()) != '') { | |
+ return $this->raiseError(null, | |
+ null, null, $err, __FUNCTION__); | |
+ } else { | |
+ return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null, | |
+ 'unable to establish a connection', __FUNCTION__); | |
+ } | |
+ } | |
+ | |
+ if (!empty($this->dsn['charset']) && !defined('MYSQLI_SET_CHARSET_NAME')) { | |
+ $result = $this->setCharset($this->dsn['charset'], $connection); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } | |
+ | |
+ return $connection; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ connect() | |
+ | |
+ /** | |
+ * Connect to the database | |
+ * | |
+ * @return true on success, MDB2 Error Object on failure | |
+ */ | |
+ function connect() | |
+ { | |
+ if (is_object($this->connection)) { | |
+ //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0) { | |
+ if (MDB2::areEquals($this->connected_dsn, $this->dsn)) { | |
+ return MDB2_OK; | |
+ } | |
+ $this->connection = 0; | |
+ } | |
+ | |
+ $connection = $this->_doConnect( | |
+ $this->dsn['username'], | |
+ $this->dsn['password'] | |
+ ); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ $this->connection = $connection; | |
+ $this->connected_dsn = $this->dsn; | |
+ $this->connected_database_name = $this->database_name; | |
+ $this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype; | |
+ | |
+ $this->_getServerCapabilities(); | |
+ | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ setCharset() | |
+ | |
+ /** | |
+ * Set the charset on the current connection | |
+ * | |
+ * @param string charset (or array(charset, collation)) | |
+ * @param resource connection handle | |
+ * | |
+ * @return true on success, MDB2 Error Object on failure | |
+ */ | |
+ function setCharset($charset, $connection = null) | |
+ { | |
+ if (null === $connection) { | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ } | |
+ $collation = null; | |
+ if (is_array($charset) && 2 == count($charset)) { | |
+ $collation = array_pop($charset); | |
+ $charset = array_pop($charset); | |
+ } | |
+ $client_info = mysqli_get_client_version(); | |
+ if (OS_WINDOWS && ((40111 > $client_info) || | |
+ ((50000 <= $client_info) && (50006 > $client_info))) | |
+ ) { | |
+ $query = "SET NAMES '".mysqli_real_escape_string($connection, $charset)."'"; | |
+ if (null !== $collation) { | |
+ $query .= " COLLATE '".mysqli_real_escape_string($connection, $collation)."'"; | |
+ } | |
+ return $this->_doQuery($query, true, $connection); | |
+ } | |
+ if (!$result = mysqli_set_charset($connection, $charset)) { | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Could not set client character set', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ databaseExists() | |
+ | |
+ /** | |
+ * check if given database name is exists? | |
+ * | |
+ * @param string $name name of the database that should be checked | |
+ * | |
+ * @return mixed true/false on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function databaseExists($name) | |
+ { | |
+ $connection = $this->_doConnect($this->dsn['username'], | |
+ $this->dsn['password']); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ $result = @mysqli_select_db($connection, $name); | |
+ @mysqli_close($connection); | |
+ | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ disconnect() | |
+ | |
+ /** | |
+ * Log out and disconnect from the database. | |
+ * | |
+ * @param boolean $force if the disconnect should be forced even if the | |
+ * connection is opened persistently | |
+ * @return mixed true on success, false if not connected and error | |
+ * object on error | |
+ * @access public | |
+ */ | |
+ function disconnect($force = true) | |
+ { | |
+ if (is_object($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 ($force) { | |
+ $ok = @mysqli_close($this->connection); | |
+ if (!$ok) { | |
+ return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED, | |
+ null, null, null, __FUNCTION__); | |
+ } | |
+ } | |
+ } else { | |
+ return false; | |
+ } | |
+ return parent::disconnect($force); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ standaloneQuery() | |
+ | |
+ /** | |
+ * execute a query as DBA | |
+ * | |
+ * @param string $query the SQL query | |
+ * @param mixed $types array that contains the types of the columns in | |
+ * the result set | |
+ * @param boolean $is_manip if the query is a manipulation query | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function standaloneQuery($query, $types = null, $is_manip = false) | |
+ { | |
+ $user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username']; | |
+ $pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password']; | |
+ $connection = $this->_doConnect($user, $pass); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ $offset = $this->offset; | |
+ $limit = $this->limit; | |
+ $this->offset = $this->limit = 0; | |
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); | |
+ | |
+ $result = $this->_doQuery($query, $is_manip, $connection, $this->database_name); | |
+ if (!MDB2::isError($result)) { | |
+ $result = $this->_affectedRows($connection, $result); | |
+ } | |
+ | |
+ @mysqli_close($connection); | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _doQuery() | |
+ | |
+ /** | |
+ * Execute a query | |
+ * @param string $query query | |
+ * @param boolean $is_manip if the query is a manipulation query | |
+ * @param resource $connection | |
+ * @param string $database_name | |
+ * @return result or error object | |
+ * @access protected | |
+ */ | |
+ function _doQuery($query, $is_manip = false, $connection = null, $database_name = null) | |
+ { | |
+ $this->last_query = $query; | |
+ $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); | |
+ if ($result) { | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ $query = $result; | |
+ } | |
+ if ($this->options['disable_query']) { | |
+ $result = $is_manip ? 0 : null; | |
+ return $result; | |
+ } | |
+ | |
+ if (null === $connection) { | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ } | |
+ if (null === $database_name) { | |
+ $database_name = $this->database_name; | |
+ } | |
+ | |
+ if ($database_name) { | |
+ if ($database_name != $this->connected_database_name) { | |
+ if (!@mysqli_select_db($connection, $database_name)) { | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Could not select the database: '.$database_name, __FUNCTION__); | |
+ return $err; | |
+ } | |
+ $this->connected_database_name = $database_name; | |
+ } | |
+ } | |
+ | |
+ if ($this->options['multi_query']) { | |
+ $result = mysqli_multi_query($connection, $query); | |
+ } else { | |
+ $resultmode = $this->options['result_buffering'] ? MYSQLI_USE_RESULT : MYSQLI_USE_RESULT; | |
+ $result = mysqli_query($connection, $query); | |
+ } | |
+ | |
+ if (!$result) { | |
+ // Store now because standaloneQuery throws off $this->connection. | |
+ $this->_query_errno = mysqli_errno($connection); | |
+ if (0 !== $this->_query_errno) { | |
+ $this->_query_error = mysqli_error($connection); | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Could not execute statement', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ } | |
+ | |
+ if ($this->options['multi_query']) { | |
+ if ($this->options['result_buffering']) { | |
+ if (!($result = @mysqli_store_result($connection))) { | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Could not get the first result from a multi query', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ } elseif (!($result = @mysqli_use_result($connection))) { | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Could not get the first result from a multi query', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ } | |
+ | |
+ $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result)); | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _affectedRows() | |
+ | |
+ /** | |
+ * Returns the number of rows affected | |
+ * | |
+ * @param resource $result | |
+ * @param resource $connection | |
+ * @return mixed MDB2 Error Object or the number of rows affected | |
+ * @access private | |
+ */ | |
+ function _affectedRows($connection, $result = null) | |
+ { | |
+ if (null === $connection) { | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ } | |
+ return @mysqli_affected_rows($connection); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _modifyQuery() | |
+ | |
+ /** | |
+ * Changes a query string for various DBMS specific reasons | |
+ * | |
+ * @param string $query query to modify | |
+ * @param boolean $is_manip if it is a DML query | |
+ * @param integer $limit limit the number of rows | |
+ * @param integer $offset start reading from given offset | |
+ * @return string modified query | |
+ * @access protected | |
+ */ | |
+ function _modifyQuery($query, $is_manip, $limit, $offset) | |
+ { | |
+ if ($this->options['portability'] & MDB2_PORTABILITY_DELETE_COUNT) { | |
+ // "DELETE FROM table" gives 0 affected rows in MySQL. | |
+ // This little hack lets you know how many rows were deleted. | |
+ if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { | |
+ $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', | |
+ 'DELETE FROM \1 WHERE 1=1', $query); | |
+ } | |
+ } | |
+ if ($limit > 0 | |
+ && !preg_match('/LIMIT\s*\d(?:\s*(?:,|OFFSET)\s*\d+)?(?:[^\)]*)?$/i', $query) | |
+ ) { | |
+ $query = rtrim($query); | |
+ if (substr($query, -1) == ';') { | |
+ $query = substr($query, 0, -1); | |
+ } | |
+ | |
+ // LIMIT doesn't always come last in the query | |
+ // @see http://dev.mysql.com/doc/refman/5.0/en/select.html | |
+ $after = ''; | |
+ if (preg_match('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', $query, $matches)) { | |
+ $after = $matches[0]; | |
+ $query = preg_replace('/(\s+INTO\s+(?:OUT|DUMP)FILE\s.*)$/ims', '', $query); | |
+ } elseif (preg_match('/(\s+FOR\s+UPDATE\s*)$/i', $query, $matches)) { | |
+ $after = $matches[0]; | |
+ $query = preg_replace('/(\s+FOR\s+UPDATE\s*)$/im', '', $query); | |
+ } elseif (preg_match('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', $query, $matches)) { | |
+ $after = $matches[0]; | |
+ $query = preg_replace('/(\s+LOCK\s+IN\s+SHARE\s+MODE\s*)$/im', '', $query); | |
+ } | |
+ | |
+ if ($is_manip) { | |
+ return $query . " LIMIT $limit" . $after; | |
+ } else { | |
+ return $query . " LIMIT $offset, $limit" . $after; | |
+ } | |
+ } | |
+ return $query; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ getServerVersion() | |
+ | |
+ /** | |
+ * return version information about the server | |
+ * | |
+ * @param bool $native determines if the raw version string should be returned | |
+ * @return mixed array/string with version information or MDB2 error object | |
+ * @access public | |
+ */ | |
+ function getServerVersion($native = false) | |
+ { | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ if ($this->connected_server_info) { | |
+ $server_info = $this->connected_server_info; | |
+ } else { | |
+ $server_info = @mysqli_get_server_info($connection); | |
+ } | |
+ if (!$server_info) { | |
+ return $this->raiseError(null, null, null, | |
+ 'Could not get server information', __FUNCTION__); | |
+ } | |
+ // cache server_info | |
+ $this->connected_server_info = $server_info; | |
+ if (!$native) { | |
+ $tmp = explode('.', $server_info, 3); | |
+ if (isset($tmp[2]) && strpos($tmp[2], '-')) { | |
+ $tmp2 = explode('-', @$tmp[2], 2); | |
+ } else { | |
+ $tmp2[0] = isset($tmp[2]) ? $tmp[2] : null; | |
+ $tmp2[1] = null; | |
+ } | |
+ $server_info = array( | |
+ 'major' => isset($tmp[0]) ? $tmp[0] : null, | |
+ 'minor' => isset($tmp[1]) ? $tmp[1] : null, | |
+ 'patch' => $tmp2[0], | |
+ 'extra' => $tmp2[1], | |
+ 'native' => $server_info, | |
+ ); | |
+ } | |
+ return $server_info; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getServerCapabilities() | |
+ | |
+ /** | |
+ * Fetch some information about the server capabilities | |
+ * (transactions, subselects, prepared statements, etc). | |
+ * | |
+ * @access private | |
+ */ | |
+ function _getServerCapabilities() | |
+ { | |
+ if (!$this->server_capabilities_checked) { | |
+ $this->server_capabilities_checked = true; | |
+ | |
+ //set defaults | |
+ $this->supported['sub_selects'] = 'emulated'; | |
+ $this->supported['prepared_statements'] = 'emulated'; | |
+ $this->supported['triggers'] = false; | |
+ $this->start_transaction = false; | |
+ $this->varchar_max_length = 255; | |
+ | |
+ $server_info = $this->getServerVersion(); | |
+ if (is_array($server_info)) { | |
+ $server_version = $server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch']; | |
+ | |
+ if (!version_compare($server_version, '4.1.0', '<')) { | |
+ $this->supported['sub_selects'] = true; | |
+ $this->supported['prepared_statements'] = true; | |
+ } | |
+ | |
+ // SAVEPOINTs were introduced in MySQL 4.0.14 and 4.1.1 (InnoDB) | |
+ if (version_compare($server_version, '4.1.0', '>=')) { | |
+ if (version_compare($server_version, '4.1.1', '<')) { | |
+ $this->supported['savepoints'] = false; | |
+ } | |
+ } elseif (version_compare($server_version, '4.0.14', '<')) { | |
+ $this->supported['savepoints'] = false; | |
+ } | |
+ | |
+ if (!version_compare($server_version, '4.0.11', '<')) { | |
+ $this->start_transaction = true; | |
+ } | |
+ | |
+ if (!version_compare($server_version, '5.0.3', '<')) { | |
+ $this->varchar_max_length = 65532; | |
+ } | |
+ | |
+ if (!version_compare($server_version, '5.0.2', '<')) { | |
+ $this->supported['triggers'] = true; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ function _skipUserDefinedVariable($query, $position) | |
+ | |
+ /** | |
+ * Utility method, used by prepare() to avoid misinterpreting MySQL user | |
+ * defined variables (SELECT @x:=5) for placeholders. | |
+ * Check if the placeholder is a false positive, i.e. if it is an user defined | |
+ * variable instead. If so, skip it and advance the position, otherwise | |
+ * return the current position, which is valid | |
+ * | |
+ * @param string $query | |
+ * @param integer $position current string cursor position | |
+ * @return integer $new_position | |
+ * @access protected | |
+ */ | |
+ function _skipUserDefinedVariable($query, $position) | |
+ { | |
+ $found = strpos(strrev(substr($query, 0, $position)), '@'); | |
+ if (false === $found) { | |
+ return $position; | |
+ } | |
+ $pos = strlen($query) - strlen(substr($query, $position)) - $found - 1; | |
+ $substring = substr($query, $pos, $position - $pos + 2); | |
+ if (preg_match('/^@\w+\s*:=$/', $substring)) { | |
+ return $position + 1; //found an user defined variable: skip it | |
+ } | |
+ return $position; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ prepare() | |
+ | |
+ /** | |
+ * Prepares a query for multiple execution with execute(). | |
+ * With some database backends, this is emulated. | |
+ * prepare() requires a generic query as string like | |
+ * 'INSERT INTO numbers VALUES(?,?)' or | |
+ * 'INSERT INTO numbers VALUES(:foo,:bar)'. | |
+ * The ? and :name and are placeholders which can be set using | |
+ * bindParam() and the query can be sent off using the execute() method. | |
+ * The allowed format for :name can be set with the 'bindname_format' option. | |
+ * | |
+ * @param string $query the query to prepare | |
+ * @param mixed $types array that contains the types of the placeholders | |
+ * @param mixed $result_types array that contains the types of the columns in | |
+ * the result set or MDB2_PREPARE_RESULT, if set to | |
+ * MDB2_PREPARE_MANIP the query is handled as a manipulation query | |
+ * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders | |
+ * @return mixed resource handle for the prepared query on success, a MDB2 | |
+ * error on failure | |
+ * @access public | |
+ * @see bindParam, execute | |
+ */ | |
+ function prepare($query, $types = null, $result_types = null, $lobs = array()) | |
+ { | |
+ // connect to get server capabilities (http://pear.php.net/bugs/16147) | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ if ($this->options['emulate_prepared'] | |
+ || $this->supported['prepared_statements'] !== true | |
+ ) { | |
+ return parent::prepare($query, $types, $result_types, $lobs); | |
+ } | |
+ $is_manip = ($result_types === MDB2_PREPARE_MANIP); | |
+ $offset = $this->offset; | |
+ $limit = $this->limit; | |
+ $this->offset = $this->limit = 0; | |
+ $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); | |
+ $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); | |
+ if ($result) { | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ $query = $result; | |
+ } | |
+ $placeholder_type_guess = $placeholder_type = null; | |
+ $question = '?'; | |
+ $colon = ':'; | |
+ $positions = array(); | |
+ $position = 0; | |
+ while ($position < strlen($query)) { | |
+ $q_position = strpos($query, $question, $position); | |
+ $c_position = strpos($query, $colon, $position); | |
+ if ($q_position && $c_position) { | |
+ $p_position = min($q_position, $c_position); | |
+ } elseif ($q_position) { | |
+ $p_position = $q_position; | |
+ } elseif ($c_position) { | |
+ $p_position = $c_position; | |
+ } else { | |
+ break; | |
+ } | |
+ if (null === $placeholder_type) { | |
+ $placeholder_type_guess = $query[$p_position]; | |
+ } | |
+ | |
+ $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); | |
+ if (MDB2::isError($new_pos)) { | |
+ return $new_pos; | |
+ } | |
+ if ($new_pos != $position) { | |
+ $position = $new_pos; | |
+ continue; //evaluate again starting from the new position | |
+ } | |
+ | |
+ //make sure this is not part of an user defined variable | |
+ $new_pos = $this->_skipUserDefinedVariable($query, $position); | |
+ if ($new_pos != $position) { | |
+ $position = $new_pos; | |
+ continue; //evaluate again starting from the new position | |
+ } | |
+ | |
+ if ($query[$position] == $placeholder_type_guess) { | |
+ if (null === $placeholder_type) { | |
+ $placeholder_type = $query[$p_position]; | |
+ $question = $colon = $placeholder_type; | |
+ } | |
+ if ($placeholder_type == ':') { | |
+ $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s'; | |
+ $parameter = preg_replace($regexp, '\\1', $query); | |
+ if ($parameter === '') { | |
+ $err = $this->raiseError(MDB2_ERROR_SYNTAX, null, null, | |
+ 'named parameter name must match "bindname_format" option', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ $positions[$p_position] = $parameter; | |
+ $query = substr_replace($query, '?', $position, strlen($parameter)+1); | |
+ } else { | |
+ $positions[$p_position] = count($positions); | |
+ } | |
+ $position = $p_position + 1; | |
+ } else { | |
+ $position = $p_position; | |
+ } | |
+ } | |
+ | |
+ if (!$is_manip) { | |
+ static $prep_statement_counter = 1; | |
+ $statement_name = sprintf($this->options['statement_format'], $this->phptype, $prep_statement_counter++ . sha1(microtime() + mt_rand())); | |
+ $statement_name = substr(strtolower($statement_name), 0, $this->options['max_identifiers_length']); | |
+ $query = "PREPARE $statement_name FROM ".$this->quote($query, 'text'); | |
+ | |
+ $statement = $this->_doQuery($query, true, $connection); | |
+ if (MDB2::isError($statement)) { | |
+ return $statement; | |
+ } | |
+ $statement = $statement_name; | |
+ } else { | |
+ $statement = @mysqli_prepare($connection, $query); | |
+ if (!$statement) { | |
+ $err = $this->raiseError(null, null, null, | |
+ 'Unable to create prepared statement handle', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ } | |
+ | |
+ $class_name = 'MDB2_Statement_'.$this->phptype; | |
+ $obj = new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); | |
+ $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj)); | |
+ return $obj; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ replace() | |
+ | |
+ /** | |
+ * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT | |
+ * query, except that if there is already a row in the table with the same | |
+ * key field values, the old row is deleted before the new row is inserted. | |
+ * | |
+ * The REPLACE type of query does not make part of the SQL standards. Since | |
+ * practically only MySQL implements it natively, this type of query is | |
+ * emulated through this method for other DBMS using standard types of | |
+ * queries inside a transaction to assure the atomicity of the operation. | |
+ * | |
+ * @access public | |
+ * | |
+ * @param string $table name of the table on which the REPLACE query will | |
+ * be executed. | |
+ * @param array $fields associative array that describes the fields and the | |
+ * values that will be inserted or updated in the specified table. The | |
+ * indexes of the array are the names of all the fields of the table. The | |
+ * values of the array are also associative arrays that describe the | |
+ * values and other properties of the table fields. | |
+ * | |
+ * Here follows a list of field properties that need to be specified: | |
+ * | |
+ * value: | |
+ * Value to be assigned to the specified field. This value may be | |
+ * of specified in database independent type format as this | |
+ * function can perform the necessary datatype conversions. | |
+ * | |
+ * Default: | |
+ * this property is required unless the Null property | |
+ * is set to 1. | |
+ * | |
+ * type | |
+ * Name of the type of the field. Currently, all types Metabase | |
+ * are supported except for clob and blob. | |
+ * | |
+ * Default: no type conversion | |
+ * | |
+ * null | |
+ * Boolean property that indicates that the value for this field | |
+ * should be set to null. | |
+ * | |
+ * The default value for fields missing in INSERT queries may be | |
+ * specified the definition of a table. Often, the default value | |
+ * is already null, but since the REPLACE may be emulated using | |
+ * an UPDATE query, make sure that all fields of the table are | |
+ * listed in this function argument array. | |
+ * | |
+ * Default: 0 | |
+ * | |
+ * key | |
+ * Boolean property that indicates that this field should be | |
+ * handled as a primary key or at least as part of the compound | |
+ * unique index of the table that will determine the row that will | |
+ * updated if it exists or inserted a new row otherwise. | |
+ * | |
+ * This function will fail if no key field is specified or if the | |
+ * value of a key field is set to null because fields that are | |
+ * part of unique index they may not be null. | |
+ * | |
+ * Default: 0 | |
+ * | |
+ * @see http://dev.mysql.com/doc/refman/5.0/en/replace.html | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ */ | |
+ function replace($table, $fields) | |
+ { | |
+ $count = count($fields); | |
+ $query = $values = ''; | |
+ $keys = $colnum = 0; | |
+ for (reset($fields); $colnum < $count; next($fields), $colnum++) { | |
+ $name = key($fields); | |
+ if ($colnum > 0) { | |
+ $query .= ','; | |
+ $values.= ','; | |
+ } | |
+ $query.= $this->quoteIdentifier($name, true); | |
+ if (isset($fields[$name]['null']) && $fields[$name]['null']) { | |
+ $value = 'NULL'; | |
+ } else { | |
+ $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null; | |
+ $value = $this->quote($fields[$name]['value'], $type); | |
+ if (MDB2::isError($value)) { | |
+ return $value; | |
+ } | |
+ } | |
+ $values.= $value; | |
+ if (isset($fields[$name]['key']) && $fields[$name]['key']) { | |
+ if ($value === 'NULL') { | |
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, | |
+ 'key value '.$name.' may not be NULL', __FUNCTION__); | |
+ } | |
+ $keys++; | |
+ } | |
+ } | |
+ if ($keys == 0) { | |
+ return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, | |
+ 'not specified which fields are keys', __FUNCTION__); | |
+ } | |
+ | |
+ $connection = $this->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ $table = $this->quoteIdentifier($table, true); | |
+ $query = "REPLACE INTO $table ($query) VALUES ($values)"; | |
+ $result = $this->_doQuery($query, true, $connection); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ return $this->_affectedRows($connection, $result); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ nextID() | |
+ | |
+ /** | |
+ * Returns the next free id of a sequence | |
+ * | |
+ * @param string $seq_name name of the sequence | |
+ * @param boolean $ondemand when true the sequence is | |
+ * automatic created, if it | |
+ * not exists | |
+ * | |
+ * @return mixed MDB2 Error Object or id | |
+ * @access public | |
+ */ | |
+ function nextID($seq_name, $ondemand = true) | |
+ { | |
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); | |
+ $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); | |
+ $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)"; | |
+ $this->pushErrorHandling(PEAR_ERROR_RETURN); | |
+ $this->expectError(MDB2_ERROR_NOSUCHTABLE); | |
+ $result = $this->_doQuery($query, true); | |
+ $this->popExpect(); | |
+ $this->popErrorHandling(); | |
+ if (MDB2::isError($result)) { | |
+ if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) { | |
+ $this->loadModule('Manager', null, true); | |
+ $result = $this->manager->createSequence($seq_name); | |
+ if (MDB2::isError($result)) { | |
+ return $this->raiseError($result, null, null, | |
+ 'on demand sequence '.$seq_name.' could not be created', __FUNCTION__); | |
+ } else { | |
+ return $this->nextID($seq_name, false); | |
+ } | |
+ } | |
+ return $result; | |
+ } | |
+ $value = $this->lastInsertID(); | |
+ if (is_numeric($value)) { | |
+ $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value"; | |
+ $result = $this->_doQuery($query, true); | |
+ if (MDB2::isError($result)) { | |
+ $this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name; | |
+ } | |
+ } | |
+ return $value; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ lastInsertID() | |
+ | |
+ /** | |
+ * Returns the autoincrement ID if supported or $id or fetches the current | |
+ * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) | |
+ * | |
+ * @param string $table name of the table into which a new row was inserted | |
+ * @param string $field name of the field into which a new row was inserted | |
+ * @return mixed MDB2 Error Object or id | |
+ * @access public | |
+ */ | |
+ function lastInsertID($table = null, $field = null) | |
+ { | |
+ // not using mysql_insert_id() due to http://pear.php.net/bugs/bug.php?id=8051 | |
+ // not casting to integer to handle BIGINT http://pear.php.net/bugs/bug.php?id=17650 | |
+ return $this->queryOne('SELECT LAST_INSERT_ID()'); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ currID() | |
+ | |
+ /** | |
+ * Returns the current id of a sequence | |
+ * | |
+ * @param string $seq_name name of the sequence | |
+ * @return mixed MDB2 Error Object or id | |
+ * @access public | |
+ */ | |
+ function currID($seq_name) | |
+ { | |
+ $sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true); | |
+ $seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true); | |
+ $query = "SELECT MAX($seqcol_name) FROM $sequence_name"; | |
+ return $this->queryOne($query, 'integer'); | |
+ } | |
+} | |
+ | |
+/** | |
+ * MDB2 MySQLi result driver | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Result_mysqli extends MDB2_Result_Common | |
+{ | |
+ // }}} | |
+ // {{{ fetchRow() | |
+ | |
+ /** | |
+ * Fetch a row and insert the data into an existing array. | |
+ * | |
+ * @param int $fetchmode how the array data should be indexed | |
+ * @param int $rownum number of the row where the data can be found | |
+ * @return int data array on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) | |
+ { | |
+ if (null !== $rownum) { | |
+ $seek = $this->seek($rownum); | |
+ if (MDB2::isError($seek)) { | |
+ return $seek; | |
+ } | |
+ } | |
+ if ($fetchmode == MDB2_FETCHMODE_DEFAULT) { | |
+ $fetchmode = $this->db->fetchmode; | |
+ } | |
+ if ( $fetchmode == MDB2_FETCHMODE_ASSOC | |
+ || $fetchmode == MDB2_FETCHMODE_OBJECT | |
+ ) { | |
+ $row = @mysqli_fetch_assoc($this->result); | |
+ if (is_array($row) | |
+ && $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE | |
+ ) { | |
+ $row = array_change_key_case($row, $this->db->options['field_case']); | |
+ } | |
+ } else { | |
+ $row = @mysqli_fetch_row($this->result); | |
+ } | |
+ | |
+ if (!$row) { | |
+ if (false === $this->result) { | |
+ $err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'resultset has already been freed', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ return null; | |
+ } | |
+ $mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL; | |
+ $rtrim = false; | |
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) { | |
+ if (empty($this->types)) { | |
+ $mode += MDB2_PORTABILITY_RTRIM; | |
+ } else { | |
+ $rtrim = true; | |
+ } | |
+ } | |
+ if ($mode) { | |
+ $this->db->_fixResultArrayValues($row, $mode); | |
+ } | |
+ if ( ( $fetchmode != MDB2_FETCHMODE_ASSOC | |
+ && $fetchmode != MDB2_FETCHMODE_OBJECT) | |
+ && !empty($this->types) | |
+ ) { | |
+ $row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim); | |
+ } elseif (($fetchmode == MDB2_FETCHMODE_ASSOC | |
+ || $fetchmode == MDB2_FETCHMODE_OBJECT) | |
+ && !empty($this->types_assoc) | |
+ ) { | |
+ $row = $this->db->datatype->convertResultRow($this->types_assoc, $row, $rtrim); | |
+ } | |
+ if (!empty($this->values)) { | |
+ $this->_assignBindColumns($row); | |
+ } | |
+ if ($fetchmode === MDB2_FETCHMODE_OBJECT) { | |
+ $object_class = $this->db->options['fetch_class']; | |
+ if ($object_class == 'stdClass') { | |
+ $row = (object) $row; | |
+ } else { | |
+ $rowObj = new $object_class($row); | |
+ $row = $rowObj; | |
+ } | |
+ } | |
+ ++$this->rownum; | |
+ return $row; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ _getColumnNames() | |
+ | |
+ /** | |
+ * Retrieve the names of columns returned by the DBMS in a query result. | |
+ * | |
+ * @return mixed Array variable that holds the names of columns as keys | |
+ * or an MDB2 error on failure. | |
+ * Some DBMS may not return any columns when the result set | |
+ * does not contain any rows. | |
+ * @access private | |
+ */ | |
+ function _getColumnNames() | |
+ { | |
+ $columns = array(); | |
+ $numcols = $this->numCols(); | |
+ if (MDB2::isError($numcols)) { | |
+ return $numcols; | |
+ } | |
+ for ($column = 0; $column < $numcols; $column++) { | |
+ $column_info = @mysqli_fetch_field_direct($this->result, $column); | |
+ $columns[$column_info->name] = $column; | |
+ } | |
+ if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { | |
+ $columns = array_change_key_case($columns, $this->db->options['field_case']); | |
+ } | |
+ return $columns; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ numCols() | |
+ | |
+ /** | |
+ * Count the number of columns returned by the DBMS in a query result. | |
+ * | |
+ * @return mixed integer value with the number of columns, a MDB2 error | |
+ * on failure | |
+ * @access public | |
+ */ | |
+ function numCols() | |
+ { | |
+ $cols = @mysqli_num_fields($this->result); | |
+ if (null === $cols) { | |
+ if (false === $this->result) { | |
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'resultset has already been freed', __FUNCTION__); | |
+ } | |
+ if (null === $this->result) { | |
+ return count($this->types); | |
+ } | |
+ return $this->db->raiseError(null, null, null, | |
+ 'Could not get column count', __FUNCTION__); | |
+ } | |
+ return $cols; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ nextResult() | |
+ | |
+ /** | |
+ * Move the internal result pointer to the next available result | |
+ * | |
+ * @return true on success, false if there is no more result set or an error object on failure | |
+ * @access public | |
+ */ | |
+ function nextResult() | |
+ { | |
+ $connection = $this->db->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ if (!@mysqli_more_results($connection)) { | |
+ return false; | |
+ } | |
+ if (!@mysqli_next_result($connection)) { | |
+ return false; | |
+ } | |
+ if (!($this->result = @mysqli_use_result($connection))) { | |
+ return false; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ free() | |
+ | |
+ /** | |
+ * Free the internal resources associated with result. | |
+ * | |
+ * @return boolean true on success, false if result is invalid | |
+ * @access public | |
+ */ | |
+ function free() | |
+ { | |
+ do { | |
+ if (is_object($this->result) && $this->db->connection) { | |
+ $free = @mysqli_free_result($this->result); | |
+ if (false === $free) { | |
+ return $this->db->raiseError(null, null, null, | |
+ 'Could not free result', __FUNCTION__); | |
+ } | |
+ } | |
+ } while ($this->result = $this->nextResult()); | |
+ | |
+ $this->result = false; | |
+ return MDB2_OK; | |
+ } | |
+} | |
+ | |
+/** | |
+ * MDB2 MySQLi buffered result driver | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_BufferedResult_mysqli extends MDB2_Result_mysqli | |
+{ | |
+ // }}} | |
+ // {{{ seek() | |
+ | |
+ /** | |
+ * Seek to a specific row in a result set | |
+ * | |
+ * @param int $rownum number of the row where the data can be found | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function seek($rownum = 0) | |
+ { | |
+ if ($this->rownum != ($rownum - 1) && !@mysqli_data_seek($this->result, $rownum)) { | |
+ if (false === $this->result) { | |
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'resultset has already been freed', __FUNCTION__); | |
+ } | |
+ if (null === $this->result) { | |
+ return MDB2_OK; | |
+ } | |
+ return $this->db->raiseError(MDB2_ERROR_INVALID, null, null, | |
+ 'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__); | |
+ } | |
+ $this->rownum = $rownum - 1; | |
+ return MDB2_OK; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ valid() | |
+ | |
+ /** | |
+ * Check if the end of the result set has been reached | |
+ * | |
+ * @return mixed true or false on sucess, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function valid() | |
+ { | |
+ $numrows = $this->numRows(); | |
+ if (MDB2::isError($numrows)) { | |
+ return $numrows; | |
+ } | |
+ return $this->rownum < ($numrows - 1); | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ numRows() | |
+ | |
+ /** | |
+ * Returns the number of rows in a result object | |
+ * | |
+ * @return mixed MDB2 Error Object or the number of rows | |
+ * @access public | |
+ */ | |
+ function numRows() | |
+ { | |
+ $rows = @mysqli_num_rows($this->result); | |
+ if (null === $rows) { | |
+ if (false === $this->result) { | |
+ return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, | |
+ 'resultset has already been freed', __FUNCTION__); | |
+ } | |
+ if (null === $this->result) { | |
+ return 0; | |
+ } | |
+ return $this->db->raiseError(null, null, null, | |
+ 'Could not get row count', __FUNCTION__); | |
+ } | |
+ return $rows; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ nextResult() | |
+ | |
+ /** | |
+ * 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 | |
+ */ | |
+ function nextResult() | |
+ { | |
+ $connection = $this->db->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ if (!@mysqli_more_results($connection)) { | |
+ return false; | |
+ } | |
+ if (!@mysqli_next_result($connection)) { | |
+ return false; | |
+ } | |
+ if (!($this->result = @mysqli_store_result($connection))) { | |
+ return false; | |
+ } | |
+ return MDB2_OK; | |
+ } | |
+} | |
+ | |
+/** | |
+ * MDB2 MySQLi statement driver | |
+ * | |
+ * @package MDB2 | |
+ * @category Database | |
+ * @author Lukas Smith <smith@pooteeweet.org> | |
+ */ | |
+class MDB2_Statement_mysqli extends MDB2_Statement_Common | |
+{ | |
+ // {{{ _execute() | |
+ | |
+ /** | |
+ * Execute a prepared query statement helper method. | |
+ * | |
+ * @param mixed $result_class string which specifies which result class to use | |
+ * @param mixed $result_wrap_class string which specifies which class to wrap results in | |
+ * | |
+ * @return mixed MDB2_Result or integer (affected rows) on success, | |
+ * a MDB2 error on failure | |
+ * @access private | |
+ */ | |
+ function _execute($result_class = true, $result_wrap_class = true) | |
+ { | |
+ if (null === $this->statement) { | |
+ $result = parent::_execute($result_class, $result_wrap_class); | |
+ return $result; | |
+ } | |
+ $this->db->last_query = $this->query; | |
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values)); | |
+ if ($this->db->getOption('disable_query')) { | |
+ $result = $this->is_manip ? 0 : null; | |
+ return $result; | |
+ } | |
+ | |
+ $connection = $this->db->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ if (!is_object($this->statement)) { | |
+ $query = 'EXECUTE '.$this->statement; | |
+ } | |
+ if (!empty($this->positions)) { | |
+ $paramReferences = array(); | |
+ $parameters = array(0 => $this->statement, 1 => ''); | |
+ $lobs = array(); | |
+ $i = 0; | |
+ foreach ($this->positions as $parameter) { | |
+ if (!array_key_exists($parameter, $this->values)) { | |
+ return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, | |
+ 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); | |
+ } | |
+ $value = $this->values[$parameter]; | |
+ $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; | |
+ if (!is_object($this->statement)) { | |
+ if (is_resource($value) || $type == 'clob' || $type == 'blob' && $this->db->options['lob_allow_url_include']) { | |
+ if (!is_resource($value) && preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { | |
+ if ($match[1] == 'file://') { | |
+ $value = $match[2]; | |
+ } | |
+ $value = @fopen($value, 'r'); | |
+ $close = true; | |
+ } | |
+ if (is_resource($value)) { | |
+ $data = ''; | |
+ while (!@feof($value)) { | |
+ $data.= @fread($value, $this->db->options['lob_buffer_length']); | |
+ } | |
+ if ($close) { | |
+ @fclose($value); | |
+ } | |
+ $value = $data; | |
+ } | |
+ } | |
+ $quoted = $this->db->quote($value, $type); | |
+ if (MDB2::isError($quoted)) { | |
+ return $quoted; | |
+ } | |
+ $param_query = 'SET @'.$parameter.' = '.$quoted; | |
+ $result = $this->db->_doQuery($param_query, true, $connection); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ } else { | |
+ if (is_resource($value) || $type == 'clob' || $type == 'blob') { | |
+ $paramReferences[$i] = null; | |
+ // mysqli_stmt_bind_param() requires parameters to be passed by reference | |
+ $parameters[] =& $paramReferences[$i]; | |
+ $parameters[1].= 'b'; | |
+ $lobs[$i] = $parameter; | |
+ } else { | |
+ $paramReferences[$i] = $this->db->quote($value, $type, false); | |
+ if (MDB2::isError($paramReferences[$i])) { | |
+ return $paramReferences[$i]; | |
+ } | |
+ // mysqli_stmt_bind_param() requires parameters to be passed by reference | |
+ $parameters[] =& $paramReferences[$i]; | |
+ $parameters[1].= $this->db->datatype->mapPrepareDatatype($type); | |
+ } | |
+ ++$i; | |
+ } | |
+ } | |
+ | |
+ if (!is_object($this->statement)) { | |
+ $query.= ' USING @'.implode(', @', array_values($this->positions)); | |
+ } else { | |
+ $result = call_user_func_array('mysqli_stmt_bind_param', $parameters); | |
+ if (false === $result) { | |
+ $err = $this->db->raiseError(null, null, null, | |
+ 'Unable to bind parameters', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ | |
+ foreach ($lobs as $i => $parameter) { | |
+ $value = $this->values[$parameter]; | |
+ $close = false; | |
+ if (!is_resource($value)) { | |
+ $close = true; | |
+ if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { | |
+ if ($match[1] == 'file://') { | |
+ $value = $match[2]; | |
+ } | |
+ $value = @fopen($value, 'r'); | |
+ } else { | |
+ $fp = @tmpfile(); | |
+ @fwrite($fp, $value); | |
+ @rewind($fp); | |
+ $value = $fp; | |
+ } | |
+ } | |
+ while (!@feof($value)) { | |
+ $data = @fread($value, $this->db->options['lob_buffer_length']); | |
+ @mysqli_stmt_send_long_data($this->statement, $i, $data); | |
+ } | |
+ if ($close) { | |
+ @fclose($value); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (!is_object($this->statement)) { | |
+ $result = $this->db->_doQuery($query, $this->is_manip, $connection); | |
+ if (MDB2::isError($result)) { | |
+ return $result; | |
+ } | |
+ | |
+ if ($this->is_manip) { | |
+ $affected_rows = $this->db->_affectedRows($connection, $result); | |
+ return $affected_rows; | |
+ } | |
+ | |
+ $result = $this->db->_wrapResult($result, $this->result_types, | |
+ $result_class, $result_wrap_class, $this->limit, $this->offset); | |
+ } else { | |
+ if (!mysqli_stmt_execute($this->statement)) { | |
+ $err = $this->db->raiseError(null, null, null, | |
+ 'Unable to execute statement', __FUNCTION__); | |
+ return $err; | |
+ } | |
+ | |
+ if ($this->is_manip) { | |
+ $affected_rows = @mysqli_stmt_affected_rows($this->statement); | |
+ return $affected_rows; | |
+ } | |
+ | |
+ if ($this->db->options['result_buffering']) { | |
+ @mysqli_stmt_store_result($this->statement); | |
+ } | |
+ | |
+ $result = $this->db->_wrapResult($this->statement, $this->result_types, | |
+ $result_class, $result_wrap_class, $this->limit, $this->offset); | |
+ } | |
+ | |
+ $this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result)); | |
+ return $result; | |
+ } | |
+ | |
+ // }}} | |
+ // {{{ free() | |
+ | |
+ /** | |
+ * Release resources allocated for the specified prepared query. | |
+ * | |
+ * @return mixed MDB2_OK on success, a MDB2 error on failure | |
+ * @access public | |
+ */ | |
+ function free() | |
+ { | |
+ if (null === $this->positions) { | |
+ return $this->db->raiseError(MDB2_ERROR, null, null, | |
+ 'Prepared statement has already been freed', __FUNCTION__); | |
+ } | |
+ $result = MDB2_OK; | |
+ | |
+ if (is_object($this->statement)) { | |
+ if (!@mysqli_stmt_close($this->statement)) { | |
+ $result = $this->db->raiseError(null, null, null, | |
+ 'Could not free statement', __FUNCTION__); | |
+ } | |
+ } elseif (null !== $this->statement) { | |
+ $connection = $this->db->getConnection(); | |
+ if (MDB2::isError($connection)) { | |
+ return $connection; | |
+ } | |
+ | |
+ $query = 'DEALLOCATE PREPARE '.$this->statement; | |
+ $result = $this->db->_doQuery($query, true, $connection); | |
+ } | |
+ | |
+ parent::free(); | |
+ return $result; | |
+ } | |
+} | |
+?> | |
Index: data/module/PEAR.php | |
=================================================================== | |
--- data/module/PEAR.php (revision 23352) | |
+++ data/module/PEAR.php (working copy) | |
@@ -14,7 +14,7 @@ | |
* @author Greg Beaver <cellog@php.net> | |
* @copyright 1997-2010 The Authors | |
* @license http://opensource.org/licenses/bsd-license.php New BSD License | |
- * @version CVS: commit 01071ee7b71e4d38c4e96fdf0ae5e411841eaec7 | |
+ * @version CVS: $Id$ | |
* @link http://pear.php.net/package/PEAR | |
* @since File available since Release 0.1 | |
*/ | |
@@ -78,7 +78,7 @@ | |
* @author Greg Beaver <cellog@php.net> | |
* @copyright 1997-2006 The PHP Group | |
* @license http://opensource.org/licenses/bsd-license.php New BSD License | |
- * @version Release: @package_version@ | |
+ * @version Release: 1.9.4 | |
* @link http://pear.php.net/package/PEAR | |
* @see PEAR_Error | |
* @since Class available since PHP 4.0.2 | |
@@ -249,9 +249,6 @@ | |
*/ | |
function isError($data, $code = null) | |
{ | |
- if (!is_object($data)) { | |
- return false; | |
- } | |
if (!is_a($data, 'PEAR_Error')) { | |
return false; | |
} | |
@@ -487,12 +484,6 @@ | |
$error_class = $message->getType(); | |
$message->error_message_prefix = ''; | |
$message = $message->getMessage(); | |
- | |
- // Make sure right data gets passed. | |
- $r = new ReflectionClass($error_class); | |
- $c = $r->getConstructor(); | |
- $p = array_shift($c->getParameters()); | |
- $skipmsg = ($p->getName() != 'message'); | |
} | |
if ( | |
@@ -797,7 +788,7 @@ | |
* @author Gregory Beaver <cellog@php.net> | |
* @copyright 1997-2006 The PHP Group | |
* @license http://opensource.org/licenses/bsd-license.php New BSD License | |
- * @version Release: @package_version@ | |
+ * @version Release: 1.9.4 | |
* @link http://pear.php.net/manual/en/core.pear.pear-error.php | |
* @see PEAR::raiseError(), PEAR::throwError() | |
* @since Class available since PHP 4.0.2 | |
Index: data/module/PEAR5.php | |
=================================================================== | |
--- data/module/PEAR5.php (revision 23352) | |
+++ data/module/PEAR5.php (working copy) | |
@@ -30,4 +30,4 @@ | |
return $properties[$class][$var]; | |
} | |
-} | |
+} | |
\ No newline at end of file | |
Index: html/install/index.php | |
=================================================================== | |
--- html/install/index.php (revision 23352) | |
+++ html/install/index.php (working copy) | |
@@ -45,12 +45,14 @@ | |
$objPage = new StdClass; | |
$objPage->arrDB_TYPE = array( | |
- 'pgsql' => 'PostgreSQL', | |
- 'mysql' => 'MySQL', | |
+ 'pgsql' => 'PostgreSQL', | |
+ 'mysql' => 'MySQL (use mysql)', | |
+ 'mysqli' => 'MySQL (use mysqli)', | |
); | |
$objPage->arrDB_PORT = array( | |
- 'pgsql' => '', | |
- 'mysql' => '', | |
+ 'pgsql' => '', | |
+ 'mysql' => '', | |
+ 'mysqli' => '', | |
); | |
$objPage->arrMailBackend = array('mail' => 'mail', | |
'smtp' => 'SMTP', | |
@@ -848,9 +850,12 @@ | |
// MySQL 用の初期化 | |
// XXX SC_Query を使うようにすれば、この処理は不要となる | |
- if ($arrDsn['phptype'] === 'mysql') { | |
- $objDB->exec('SET SESSION storage_engine = InnoDB'); | |
- $objDB->exec("SET SESSION sql_mode = 'ANSI'"); | |
+ switch ($arrDsn['phptype']) { | |
+ case 'mysql': | |
+ case 'mysqli': | |
+ $objDB->exec('SET SESSION storage_engine = InnoDB'); | |
+ $objDB->exec("SET SESSION sql_mode = 'ANSI'"); | |
+ break; | |
} | |
$sql_split = split(';', $sql); | |
@@ -1021,6 +1026,10 @@ | |
define('AUTH_MAGIC', $auth_magic); | |
} | |
+ // DB 接続情報 | |
+ $db_port = $objDBParam->getValue('db_port'); | |
+ $db_port = $db_port == '' ? false : $db_port; | |
+ | |
// FIXME 変数出力はエスケープすべき | |
$config_data = "<?php\n" | |
. "define('ECCUBE_INSTALL', 'ON');\n" | |
@@ -1033,7 +1042,7 @@ | |
. "define('DB_PASSWORD', '" . $objDBParam->getValue('db_password') . "');\n" | |
. "define('DB_SERVER', '" . $objDBParam->getValue('db_server') . "');\n" | |
. "define('DB_NAME', '" . $objDBParam->getValue('db_name') . "');\n" | |
- . "define('DB_PORT', '" . $objDBParam->getValue('db_port') . "');\n" | |
+ . "define('DB_PORT', " . var_export($db_port, true) . ");\n" | |
. "define('ADMIN_DIR', '" . $objWebParam->getValue('admin_dir') . "/');\n" | |
. "define('ADMIN_FORCE_SSL', " . $force_ssl . ");\n" | |
. "define('ADMIN_ALLOW_HOSTS', '" . serialize($allow_hosts) . "');\n" | |
@@ -1160,7 +1169,7 @@ | |
'username' => $arrRet['db_user'], | |
'password' => $arrRet['db_password'], | |
'database' => $arrRet['db_name'], | |
- 'port' => $arrRet['db_port'], | |
+ 'port' => $arrRet['db_port'] != '' ? $arrRet['db_port'] : false, | |
); | |
// 文字列形式の DSN との互換処理 | |
Index: html/install/sql/create_table_mysqli.sql | |
=================================================================== | |
--- html/install/sql/create_table_mysqli.sql (revision 0) | |
+++ html/install/sql/create_table_mysqli.sql (working copy) | |
@@ -0,0 +1,1251 @@ | |
+create table dtb_module_update_logs( | |
+ log_id int NOT NULL, | |
+ module_id int NOT NULL, | |
+ buckup_path text, | |
+ error_flg smallint DEFAULT 0, | |
+ error text, | |
+ ok text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (log_id) | |
+); | |
+ | |
+CREATE TABLE dtb_ownersstore_settings ( | |
+ public_key text, | |
+ PRIMARY KEY(public_key(64)) | |
+); | |
+ | |
+CREATE TABLE dtb_kiyaku ( | |
+ kiyaku_id int NOT NULL, | |
+ kiyaku_title text NOT NULL, | |
+ kiyaku_text text NOT NULL, | |
+ rank int NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (kiyaku_id) | |
+); | |
+ | |
+CREATE TABLE dtb_holiday ( | |
+ holiday_id int NOT NULL, | |
+ title text NOT NULL, | |
+ month smallint NOT NULL, | |
+ day smallint NOT NULL, | |
+ rank int NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (holiday_id) | |
+); | |
+ | |
+CREATE TABLE mtb_zip ( | |
+ zip_id int, | |
+ zipcode text, | |
+ state text, | |
+ city text, | |
+ town text, | |
+ PRIMARY KEY (zip_id) | |
+); | |
+ | |
+CREATE TABLE dtb_update ( | |
+ module_id int NOT NULL, | |
+ module_name text NOT NULL, | |
+ now_version text, | |
+ latest_version text NOT NULL, | |
+ module_explain text, | |
+ main_php text NOT NULL, | |
+ extern_php text NOT NULL, | |
+ install_sql text, | |
+ uninstall_sql text, | |
+ other_files text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ release_date datetime NOT NULL, | |
+ PRIMARY KEY (module_id) | |
+); | |
+ | |
+CREATE TABLE dtb_baseinfo ( | |
+ id int, | |
+ company_name text, | |
+ company_kana text, | |
+ zip01 text, | |
+ zip02 text, | |
+ zipcode text, | |
+ country_id int, | |
+ pref smallint, | |
+ addr01 text, | |
+ addr02 text, | |
+ tel01 text, | |
+ tel02 text, | |
+ tel03 text, | |
+ fax01 text, | |
+ fax02 text, | |
+ fax03 text, | |
+ business_hour text, | |
+ law_company text, | |
+ law_manager text, | |
+ law_zip01 text, | |
+ law_zip02 text, | |
+ law_zipcode text, | |
+ law_country_id int, | |
+ law_pref smallint, | |
+ law_addr01 text, | |
+ law_addr02 text, | |
+ law_tel01 text, | |
+ law_tel02 text, | |
+ law_tel03 text, | |
+ law_fax01 text, | |
+ law_fax02 text, | |
+ law_fax03 text, | |
+ law_email text, | |
+ law_url text, | |
+ law_term01 text, | |
+ law_term02 text, | |
+ law_term03 text, | |
+ law_term04 text, | |
+ law_term05 text, | |
+ law_term06 text, | |
+ law_term07 text, | |
+ law_term08 text, | |
+ law_term09 text, | |
+ law_term10 text, | |
+ email01 text, | |
+ email02 text, | |
+ email03 text, | |
+ email04 text, | |
+ free_rule numeric, | |
+ shop_name text, | |
+ shop_kana text, | |
+ shop_name_eng text, | |
+ point_rate numeric NOT NULL DEFAULT 0, | |
+ welcome_point numeric NOT NULL DEFAULT 0, | |
+ update_date timestamp NOT NULL, | |
+ top_tpl text, | |
+ product_tpl text, | |
+ detail_tpl text, | |
+ mypage_tpl text, | |
+ good_traded text, | |
+ message text, | |
+ regular_holiday_ids text, | |
+ latitude text, | |
+ longitude text, | |
+ downloadable_days numeric DEFAULT 30, | |
+ downloadable_days_unlimited smallint, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE dtb_deliv ( | |
+ deliv_id int NOT NULL, | |
+ product_type_id int, | |
+ name text, | |
+ service_name text, | |
+ remark text, | |
+ confirm_url text, | |
+ rank int, | |
+ status smallint NOT NULL DEFAULT 1, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (deliv_id) | |
+); | |
+ | |
+CREATE TABLE dtb_payment_options ( | |
+ deliv_id int NOT NULL, | |
+ payment_id int NOT NULL, | |
+ rank int, | |
+ PRIMARY KEY (deliv_id, payment_id) | |
+); | |
+ | |
+CREATE TABLE dtb_delivtime ( | |
+ deliv_id int NOT NULL, | |
+ time_id int NOT NULL, | |
+ deliv_time text NOT NULL, | |
+ PRIMARY KEY (deliv_id, time_id) | |
+); | |
+ | |
+CREATE TABLE dtb_delivfee ( | |
+ deliv_id int NOT NULL, | |
+ fee_id int NOT NULL, | |
+ fee numeric NOT NULL, | |
+ pref smallint, | |
+ PRIMARY KEY (deliv_id, fee_id) | |
+); | |
+ | |
+CREATE TABLE dtb_payment ( | |
+ payment_id int NOT NULL, | |
+ payment_method text, | |
+ charge numeric, | |
+ rule_max numeric, | |
+ rank int, | |
+ note text, | |
+ fix smallint, | |
+ status smallint NOT NULL DEFAULT 1, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ payment_image text, | |
+ upper_rule numeric, | |
+ charge_flg smallint DEFAULT 1, | |
+ rule_min numeric, | |
+ upper_rule_max numeric, | |
+ module_id int, | |
+ module_path text, | |
+ memo01 text, | |
+ memo02 text, | |
+ memo03 text, | |
+ memo04 text, | |
+ memo05 text, | |
+ memo06 text, | |
+ memo07 text, | |
+ memo08 text, | |
+ memo09 text, | |
+ memo10 text, | |
+ PRIMARY KEY (payment_id) | |
+); | |
+ | |
+CREATE TABLE dtb_mailtemplate ( | |
+ template_id int NOT NULL, | |
+ subject text, | |
+ header text, | |
+ footer text, | |
+ creator_id int NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (template_id) | |
+); | |
+ | |
+CREATE TABLE dtb_mailmaga_template ( | |
+ template_id int NOT NULL, | |
+ subject text, | |
+ mail_method int, | |
+ body text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (template_id) | |
+); | |
+ | |
+CREATE TABLE dtb_send_history ( | |
+ send_id int NOT NULL, | |
+ mail_method smallint, | |
+ subject text, | |
+ body text, | |
+ send_count int, | |
+ complete_count int NOT NULL DEFAULT 0, | |
+ start_date datetime, | |
+ end_date datetime, | |
+ search_data text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (send_id) | |
+); | |
+ | |
+CREATE TABLE dtb_send_customer ( | |
+ customer_id int NOT NULL, | |
+ send_id int NOT NULL, | |
+ email text, | |
+ name text, | |
+ send_flag smallint, | |
+ PRIMARY KEY (send_id, customer_id) | |
+); | |
+ | |
+CREATE TABLE dtb_products ( | |
+ product_id int NOT NULL, | |
+ name text NOT NULL, | |
+ maker_id int, | |
+ status smallint NOT NULL DEFAULT 2, | |
+ comment1 text, | |
+ comment2 text, | |
+ comment3 mediumtext, | |
+ comment4 text, | |
+ comment5 text, | |
+ comment6 text, | |
+ note text, | |
+ main_list_comment text, | |
+ main_list_image text, | |
+ main_comment mediumtext, | |
+ main_image text, | |
+ main_large_image text, | |
+ sub_title1 text, | |
+ sub_comment1 mediumtext, | |
+ sub_image1 text, | |
+ sub_large_image1 text, | |
+ sub_title2 text, | |
+ sub_comment2 mediumtext, | |
+ sub_image2 text, | |
+ sub_large_image2 text, | |
+ sub_title3 text, | |
+ sub_comment3 mediumtext, | |
+ sub_image3 text, | |
+ sub_large_image3 text, | |
+ sub_title4 text, | |
+ sub_comment4 mediumtext, | |
+ sub_image4 text, | |
+ sub_large_image4 text, | |
+ sub_title5 text, | |
+ sub_comment5 mediumtext, | |
+ sub_image5 text, | |
+ sub_large_image5 text, | |
+ sub_title6 text, | |
+ sub_comment6 mediumtext, | |
+ sub_image6 text, | |
+ sub_large_image6 text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ deliv_date_id int, | |
+ PRIMARY KEY (product_id) | |
+); | |
+ | |
+CREATE TABLE dtb_products_class ( | |
+ product_class_id int NOT NULL, | |
+ product_id int NOT NULL, | |
+ classcategory_id1 int NOT NULL DEFAULT 0, | |
+ classcategory_id2 int NOT NULL DEFAULT 0, | |
+ product_type_id int NOT NULL DEFAULT 0, | |
+ product_code text, | |
+ stock numeric, | |
+ stock_unlimited smallint NOT NULL DEFAULT 0, | |
+ sale_limit numeric, | |
+ price01 numeric, | |
+ price02 numeric NOT NULL, | |
+ deliv_fee numeric, | |
+ point_rate numeric NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ down_filename text, | |
+ down_realfilename text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (product_class_id), | |
+ UNIQUE (product_id, classcategory_id1, classcategory_id2) | |
+); | |
+ | |
+CREATE TABLE dtb_class ( | |
+ class_id int NOT NULL, | |
+ name text, | |
+ rank int, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (class_id) | |
+); | |
+ | |
+CREATE TABLE dtb_classcategory ( | |
+ classcategory_id int NOT NULL, | |
+ name text, | |
+ class_id int NOT NULL, | |
+ rank int, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (classcategory_id) | |
+); | |
+ | |
+CREATE TABLE dtb_category ( | |
+ category_id int NOT NULL, | |
+ category_name text, | |
+ parent_category_id int NOT NULL DEFAULT 0, | |
+ level int NOT NULL, | |
+ rank int, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (category_id) | |
+); | |
+ | |
+CREATE TABLE dtb_product_categories ( | |
+ product_id int NOT NULL, | |
+ category_id int NOT NULL, | |
+ rank int NOT NULL, | |
+ PRIMARY KEY(product_id, category_id) | |
+); | |
+ | |
+CREATE TABLE dtb_product_status ( | |
+ product_status_id smallint NOT NULL, | |
+ product_id int NOT NULL, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (product_status_id, product_id) | |
+); | |
+ | |
+CREATE TABLE dtb_recommend_products ( | |
+ product_id int NOT NULL, | |
+ recommend_product_id int NOT NULL, | |
+ rank int NOT NULL, | |
+ comment text, | |
+ status smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (product_id, recommend_product_id) | |
+); | |
+ | |
+CREATE TABLE dtb_review ( | |
+ review_id int NOT NULL, | |
+ product_id int NOT NULL, | |
+ reviewer_name text NOT NULL, | |
+ reviewer_url text, | |
+ sex smallint, | |
+ customer_id int, | |
+ recommend_level smallint NOT NULL, | |
+ title text NOT NULL, | |
+ comment text NOT NULL, | |
+ status smallint DEFAULT 2, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (review_id) | |
+); | |
+ | |
+CREATE TABLE dtb_customer_favorite_products ( | |
+ customer_id int NOT NULL, | |
+ product_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (customer_id, product_id) | |
+); | |
+ | |
+CREATE TABLE dtb_category_count ( | |
+ category_id int NOT NULL, | |
+ product_count int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ PRIMARY KEY (category_id) | |
+); | |
+ | |
+CREATE TABLE dtb_category_total_count ( | |
+ category_id int NOT NULL, | |
+ product_count int, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ PRIMARY KEY (category_id) | |
+); | |
+ | |
+CREATE TABLE dtb_news ( | |
+ news_id int NOT NULL, | |
+ news_date datetime, | |
+ rank int, | |
+ news_title text NOT NULL, | |
+ news_comment text, | |
+ news_url text, | |
+ news_select smallint NOT NULL DEFAULT 0, | |
+ link_method text, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (news_id) | |
+); | |
+ | |
+CREATE TABLE dtb_best_products ( | |
+ best_id int NOT NULL, | |
+ category_id int NOT NULL, | |
+ rank int NOT NULL DEFAULT 0, | |
+ product_id int NOT NULL, | |
+ title text, | |
+ comment text, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (best_id) | |
+); | |
+ | |
+CREATE TABLE dtb_mail_history ( | |
+ send_id int NOT NULL, | |
+ order_id int NOT NULL, | |
+ send_date datetime, | |
+ template_id int, | |
+ creator_id int NOT NULL, | |
+ subject text, | |
+ mail_body text, | |
+ PRIMARY KEY (send_id) | |
+); | |
+ | |
+CREATE TABLE dtb_customer ( | |
+ customer_id int NOT NULL, | |
+ name01 text NOT NULL, | |
+ name02 text NOT NULL, | |
+ kana01 text, | |
+ kana02 text, | |
+ company_name text, | |
+ zip01 text, | |
+ zip02 text, | |
+ zipcode text, | |
+ country_id int, | |
+ pref smallint, | |
+ addr01 text, | |
+ addr02 text, | |
+ email text NOT NULL, | |
+ email_mobile text, | |
+ tel01 text, | |
+ tel02 text, | |
+ tel03 text, | |
+ fax01 text, | |
+ fax02 text, | |
+ fax03 text, | |
+ sex smallint, | |
+ job smallint, | |
+ birth datetime, | |
+ password text, | |
+ reminder smallint, | |
+ reminder_answer text, | |
+ salt text, | |
+ secret_key text NOT NULL, | |
+ first_buy_date datetime, | |
+ last_buy_date datetime, | |
+ buy_times numeric DEFAULT 0, | |
+ buy_total numeric DEFAULT 0, | |
+ point numeric NOT NULL DEFAULT 0, | |
+ note text, | |
+ status smallint NOT NULL DEFAULT 1, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ mobile_phone_id text, | |
+ mailmaga_flg smallint, | |
+ PRIMARY KEY (customer_id), | |
+ UNIQUE (secret_key(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_order ( | |
+ order_id int NOT NULL, | |
+ order_temp_id text, | |
+ customer_id int NOT NULL, | |
+ message text, | |
+ order_name01 text, | |
+ order_name02 text, | |
+ order_kana01 text, | |
+ order_kana02 text, | |
+ order_company_name text, | |
+ order_email text, | |
+ order_tel01 text, | |
+ order_tel02 text, | |
+ order_tel03 text, | |
+ order_fax01 text, | |
+ order_fax02 text, | |
+ order_fax03 text, | |
+ order_zip01 text, | |
+ order_zip02 text, | |
+ order_zipcode text, | |
+ order_country_id int, | |
+ order_pref smallint, | |
+ order_addr01 text, | |
+ order_addr02 text, | |
+ order_sex smallint, | |
+ order_birth datetime, | |
+ order_job int, | |
+ subtotal numeric, | |
+ discount numeric NOT NULL DEFAULT 0, | |
+ deliv_id int, | |
+ deliv_fee numeric, | |
+ charge numeric, | |
+ use_point numeric NOT NULL DEFAULT 0, | |
+ add_point numeric NOT NULL DEFAULT 0, | |
+ birth_point numeric NOT NULL DEFAULT 0, | |
+ tax numeric, | |
+ total numeric, | |
+ payment_total numeric, | |
+ payment_id int, | |
+ payment_method text, | |
+ note text, | |
+ status smallint, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ commit_date datetime, | |
+ payment_date datetime, | |
+ device_type_id int, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ memo01 text, | |
+ memo02 text, | |
+ memo03 text, | |
+ memo04 text, | |
+ memo05 text, | |
+ memo06 text, | |
+ memo07 text, | |
+ memo08 text, | |
+ memo09 text, | |
+ memo10 text, | |
+ PRIMARY KEY (order_id) | |
+); | |
+ | |
+CREATE TABLE dtb_order_temp ( | |
+ order_temp_id text NOT NULL, | |
+ customer_id int NOT NULL, | |
+ message text, | |
+ order_name01 text, | |
+ order_name02 text, | |
+ order_kana01 text, | |
+ order_kana02 text, | |
+ order_company_name text, | |
+ order_email text, | |
+ order_tel01 text, | |
+ order_tel02 text, | |
+ order_tel03 text, | |
+ order_fax01 text, | |
+ order_fax02 text, | |
+ order_fax03 text, | |
+ order_zip01 text, | |
+ order_zip02 text, | |
+ order_zipcode text, | |
+ order_country_id int, | |
+ order_pref smallint, | |
+ order_addr01 text, | |
+ order_addr02 text, | |
+ order_sex smallint, | |
+ order_birth datetime, | |
+ order_job int, | |
+ subtotal numeric, | |
+ discount numeric NOT NULL DEFAULT 0, | |
+ deliv_id int, | |
+ deliv_fee numeric, | |
+ charge numeric, | |
+ use_point numeric NOT NULL DEFAULT 0, | |
+ add_point numeric NOT NULL DEFAULT 0, | |
+ birth_point numeric NOT NULL DEFAULT 0, | |
+ tax numeric, | |
+ total numeric, | |
+ payment_total numeric, | |
+ payment_id int, | |
+ payment_method text, | |
+ note text, | |
+ mail_flag smallint, | |
+ status smallint, | |
+ deliv_check smallint, | |
+ point_check smallint, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ device_type_id int, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ order_id int, | |
+ memo01 text, | |
+ memo02 text, | |
+ memo03 text, | |
+ memo04 text, | |
+ memo05 text, | |
+ memo06 text, | |
+ memo07 text, | |
+ memo08 text, | |
+ memo09 text, | |
+ memo10 text, | |
+ session text, | |
+ PRIMARY KEY (order_temp_id(64)) | |
+); | |
+ | |
+CREATE TABLE dtb_shipping ( | |
+ shipping_id int NOT NULL, | |
+ order_id int NOT NULL, | |
+ shipping_name01 text, | |
+ shipping_name02 text, | |
+ shipping_kana01 text, | |
+ shipping_kana02 text, | |
+ shipping_company_name text, | |
+ shipping_tel01 text, | |
+ shipping_tel02 text, | |
+ shipping_tel03 text, | |
+ shipping_fax01 text, | |
+ shipping_fax02 text, | |
+ shipping_fax03 text, | |
+ shipping_country_id int, | |
+ shipping_pref smallint, | |
+ shipping_zip01 text, | |
+ shipping_zip02 text, | |
+ shipping_zipcode text, | |
+ shipping_addr01 text, | |
+ shipping_addr02 text, | |
+ time_id int, | |
+ shipping_time text, | |
+ shipping_num text, | |
+ shipping_date datetime, | |
+ shipping_commit_date datetime, | |
+ rank int, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (shipping_id, order_id) | |
+); | |
+ | |
+CREATE TABLE dtb_shipment_item ( | |
+ shipping_id int NOT NULL, | |
+ product_class_id int NOT NULL, | |
+ order_id int NOT NULL, | |
+ product_name text NOT NULL, | |
+ product_code text, | |
+ classcategory_name1 text, | |
+ classcategory_name2 text, | |
+ price numeric, | |
+ quantity numeric, | |
+ PRIMARY KEY (shipping_id, product_class_id, order_id) | |
+); | |
+ | |
+CREATE TABLE dtb_other_deliv ( | |
+ other_deliv_id int NOT NULL, | |
+ customer_id int NOT NULL, | |
+ name01 text, | |
+ name02 text, | |
+ kana01 text, | |
+ kana02 text, | |
+ company_name text, | |
+ zip01 text, | |
+ zip02 text, | |
+ zipcode text, | |
+ country_id int, | |
+ pref smallint, | |
+ addr01 text, | |
+ addr02 text, | |
+ tel01 text, | |
+ tel02 text, | |
+ tel03 text, | |
+ fax01 text, | |
+ fax02 text, | |
+ fax03 text, | |
+ PRIMARY KEY (other_deliv_id) | |
+); | |
+ | |
+CREATE TABLE dtb_order_detail ( | |
+ order_detail_id int NOT NULL, | |
+ order_id int NOT NULL, | |
+ product_id int NOT NULL, | |
+ product_class_id int NOT NULL, | |
+ product_name text NOT NULL, | |
+ product_code text, | |
+ classcategory_name1 text, | |
+ classcategory_name2 text, | |
+ price numeric, | |
+ quantity numeric, | |
+ point_rate numeric NOT NULL DEFAULT 0, | |
+ tax_rate numeric, | |
+ tax_rule smallint, | |
+ PRIMARY KEY (order_detail_id) | |
+); | |
+ | |
+CREATE TABLE dtb_member ( | |
+ member_id int NOT NULL, | |
+ name text, | |
+ department text, | |
+ login_id text NOT NULL, | |
+ password text NOT NULL, | |
+ salt text NOT NULL, | |
+ authority smallint NOT NULL, | |
+ rank int NOT NULL DEFAULT 0, | |
+ work smallint NOT NULL DEFAULT 1, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ login_date datetime, | |
+ PRIMARY KEY (member_id) | |
+); | |
+ | |
+CREATE TABLE dtb_pagelayout ( | |
+ device_type_id int NOT NULL, | |
+ page_id int NOT NULL, | |
+ page_name text, | |
+ url text NOT NULL, | |
+ filename text, | |
+ header_chk smallint DEFAULT 1, | |
+ footer_chk smallint DEFAULT 1, | |
+ edit_flg smallint DEFAULT 1, | |
+ author text, | |
+ description text, | |
+ keyword text, | |
+ update_url text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ meta_robots text, | |
+ PRIMARY KEY (device_type_id, page_id) | |
+); | |
+ | |
+CREATE TABLE dtb_bloc ( | |
+ device_type_id int NOT NULL, | |
+ bloc_id int NOT NULL, | |
+ bloc_name text, | |
+ tpl_path text, | |
+ filename text NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ php_path text, | |
+ deletable_flg smallint NOT NULL DEFAULT 1, | |
+ plugin_id int, | |
+ PRIMARY KEY (device_type_id, bloc_id), | |
+ UNIQUE (device_type_id, filename(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_blocposition ( | |
+ device_type_id int NOT NULL, | |
+ page_id int NOT NULL, | |
+ target_id int NOT NULL, | |
+ bloc_id int NOT NULL, | |
+ bloc_row int, | |
+ anywhere smallint DEFAULT 0 NOT NULL, | |
+ PRIMARY KEY (device_type_id, page_id, target_id, bloc_id) | |
+); | |
+ | |
+CREATE TABLE dtb_csv ( | |
+ no int, | |
+ csv_id int NOT NULL, | |
+ col text, | |
+ disp_name text, | |
+ rank int, | |
+ rw_flg smallint DEFAULT 1, | |
+ status smallint NOT NULL DEFAULT 1, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ mb_convert_kana_option text, | |
+ size_const_type text, | |
+ error_check_types text, | |
+ PRIMARY KEY (no) | |
+); | |
+ | |
+CREATE TABLE dtb_csv_sql ( | |
+ sql_id int, | |
+ sql_name text NOT NULL, | |
+ csv_sql text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (sql_id) | |
+); | |
+ | |
+CREATE TABLE dtb_templates ( | |
+ template_code text NOT NULL, | |
+ device_type_id int NOT NULL, | |
+ template_name text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (template_code(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_maker ( | |
+ maker_id int NOT NULL, | |
+ name text NOT NULL, | |
+ rank int NOT NULL DEFAULT 0, | |
+ creator_id int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (maker_id) | |
+); | |
+ | |
+CREATE TABLE dtb_maker_count ( | |
+ maker_id int NOT NULL, | |
+ product_count int NOT NULL, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ PRIMARY KEY (maker_id) | |
+); | |
+ | |
+CREATE TABLE mtb_pref ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_permission ( | |
+ id text, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id(255)) | |
+); | |
+ | |
+CREATE TABLE mtb_disable_logout ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_authority ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_auth_excludes ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_work ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_disp ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_status ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_status_image ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_allowed_tag ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_page_max ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_magazine_type ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_mail_magazine_type ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_recommend ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_taxrule ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_mail_template ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_mail_tpl_path ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_job ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_reminder ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_sex ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_customer_status ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_mail_type ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_order_status ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_product_status_color ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_customer_order_status ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_order_status_color ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_wday ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_delivery_date ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_product_list_max ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_db ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_target ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_review_deny_url ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_mobile_domain ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_ownersstore_err ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_ownersstore_ips ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_constants ( | |
+ id text, | |
+ name text, | |
+ rank smallint NOT NULL DEFAULT 0, | |
+ remarks text, | |
+ PRIMARY KEY (id(255)) | |
+); | |
+ | |
+CREATE TABLE mtb_product_type ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_device_type ( | |
+ id smallint, | |
+ name text, | |
+ rank smallint NOT NULL, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE mtb_country ( | |
+ id int, | |
+ name text, | |
+ rank int NOT NULL, | |
+ PRIMARY KEY (id) | |
+); | |
+ | |
+CREATE TABLE dtb_mobile_ext_session_id ( | |
+ session_id text NOT NULL, | |
+ param_key text, | |
+ param_value text, | |
+ url text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ PRIMARY KEY (session_id(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_module ( | |
+ module_id int NOT NULL, | |
+ module_code text NOT NULL, | |
+ module_name text NOT NULL, | |
+ sub_data text, | |
+ auto_update_flg smallint NOT NULL DEFAULT 0, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (module_id) | |
+); | |
+ | |
+CREATE TABLE dtb_session ( | |
+ sess_id text NOT NULL, | |
+ sess_data text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (sess_id(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_bkup ( | |
+ bkup_name text, | |
+ bkup_memo text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ PRIMARY KEY (bkup_name(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_plugin ( | |
+ plugin_id int NOT NULL, | |
+ plugin_name text NOT NULL, | |
+ plugin_code text NOT NULL, | |
+ class_name text NOT NULL, | |
+ author text, | |
+ author_site_url text, | |
+ plugin_site_url text, | |
+ plugin_version text, | |
+ compliant_version text, | |
+ plugin_description text, | |
+ priority int NOT NULL DEFAULT 0, | |
+ enable smallint NOT NULL DEFAULT 0, | |
+ free_field1 text, | |
+ free_field2 text, | |
+ free_field3 text, | |
+ free_field4 text, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (plugin_id) | |
+); | |
+ | |
+CREATE TABLE dtb_plugin_hookpoint ( | |
+ plugin_hookpoint_id int NOT NULL, | |
+ plugin_id int NOT NULL, | |
+ hook_point text NOT NULL, | |
+ callback text, | |
+ use_flg smallint NOT NULL DEFAULT 1, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (plugin_hookpoint_id) | |
+); | |
+ | |
+CREATE TABLE dtb_index_list ( | |
+ table_name text NOT NULL, | |
+ column_name text NOT NULL, | |
+ recommend_flg smallint NOT NULL DEFAULT 0, | |
+ recommend_comment text, | |
+ PRIMARY KEY (table_name(255), column_name(255)) | |
+); | |
+ | |
+CREATE TABLE dtb_api_config ( | |
+ api_config_id int NOT NULL, | |
+ operation_name text NOT NULL, | |
+ operation_description text, | |
+ auth_types text NOT NULL, | |
+ enable smallint NOT NULL DEFAULT 0, | |
+ is_log smallint NOT NULL DEFAULT 0, | |
+ sub_data text, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (api_config_id) | |
+); | |
+ | |
+CREATE TABLE dtb_api_account ( | |
+ api_account_id int NOT NULL, | |
+ api_access_key text NOT NULL, | |
+ api_secret_key text NOT NULL, | |
+ enable smallint NOT NULL DEFAULT 0, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (api_account_id) | |
+); | |
+ | |
+CREATE TABLE dtb_tax_rule ( | |
+ tax_rule_id int NOT NULL, | |
+ country_id int NOT NULL DEFAULT 0, | |
+ pref_id int NOT NULL DEFAULT 0, | |
+ product_id int NOT NULL DEFAULT 0, | |
+ product_class_id int NOT NULL DEFAULT 0, | |
+ calc_rule smallint NOT NULL DEFAULT 1, | |
+ tax_rate numeric NOT NULL DEFAULT 5, | |
+ tax_adjust numeric NOT NULL DEFAULT 0, | |
+ apply_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
+ member_id int NOT NULL, | |
+ del_flg smallint NOT NULL DEFAULT 0, | |
+ create_date timestamp NOT NULL, | |
+ update_date timestamp NOT NULL, | |
+ PRIMARY KEY (tax_rule_id) | |
+); | |
+ | |
+CREATE INDEX dtb_customer_mobile_phone_id_key ON dtb_customer (mobile_phone_id(255)); | |
+CREATE INDEX dtb_products_class_product_id_key ON dtb_products_class(product_id); | |
+CREATE INDEX dtb_order_detail_product_id_key ON dtb_order_detail(product_id); | |
+CREATE INDEX dtb_send_customer_customer_id_key ON dtb_send_customer(customer_id); | |
+CREATE INDEX dtb_mobile_ext_session_id_param_key_key ON dtb_mobile_ext_session_id (param_key(255)); | |
+CREATE INDEX dtb_mobile_ext_session_id_param_value_key ON dtb_mobile_ext_session_id (param_value(255)); | |
+CREATE INDEX dtb_mobile_ext_session_id_url_key ON dtb_mobile_ext_session_id (url(255)); | |
+CREATE INDEX dtb_mobile_ext_session_id_create_date_key ON dtb_mobile_ext_session_id (create_date); | |
Index: html/install/templates/step2.tpl | |
=================================================================== | |
--- html/install/templates/step2.tpl (revision 23352) | |
+++ html/install/templates/step2.tpl (working copy) | |
@@ -20,16 +20,16 @@ | |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
*}--> | |
<script type="text/javascript"> | |
+var ports = { | |
+ <!--{foreach from=$arrDB_PORT key=type item=port name=ports}--> | |
+ '<!--{$type|escape:'javascript'}-->' : | |
+ '<!--{$port|escape:'javascript'}-->' | |
+ <!--{if !$smarty.foreach.ports.last}-->,<!--{/if}--> | |
+ <!--{/foreach}--> | |
+}; | |
+ | |
function lfnChangePort(db_type) { | |
- type = db_type.value; | |
- | |
- if (type == 'pgsql') { | |
- form1.db_port.value = '<!--{$arrDB_PORT.pgsql}-->'; | |
- } | |
- | |
- if (type == 'mysql') { | |
- form1.db_port.value = '<!--{$arrDB_PORT.mysql}-->'; | |
- } | |
+ form1.db_port.value = ports[db_type.value]; | |
} | |
</script> | |
<form name="form1" id="form1" method="post" action="?"> | |
Index: tests/class/Common_TestCase.php | |
=================================================================== | |
--- tests/class/Common_TestCase.php (revision 23352) | |
+++ tests/class/Common_TestCase.php (working copy) | |
@@ -17,6 +17,17 @@ | |
*/ | |
class Common_TestCase extends PHPUnit_Framework_TestCase | |
{ | |
+ /** | |
+ * MDB2 をグローバル変数のバックアップ対象から除外する。 | |
+ * | |
+ * @var array | |
+ * @see PHPUnit_Framework_TestCase::$backupGlobals | |
+ * @see PHPUnit_Framework_TestCase::$backupGlobalsBlacklist | |
+ */ | |
+ protected $backupGlobalsBlacklist = array( | |
+ '_MDB2_databases', | |
+ '_MDB2_dsninfo_default', | |
+ ); | |
/** SC_Query インスタンス */ | |
protected $objQuery; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment