/inc/MDB2/Schema.php
PHP | 2152 lines | 1495 code | 152 blank | 505 comment | 408 complexity | 38ce94d8f46ae98d2ee5e0cd61af9058 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, Apache-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php
- // +----------------------------------------------------------------------+
- // | PHP versions 4 and 5 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, |
- // | Stig. S. Bakken, Lukas Smith |
- // | All rights reserved. |
- // +----------------------------------------------------------------------+
- // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
- // | API as well as database abstraction for PHP applications. |
- // | This LICENSE is in the BSD license style. |
- // | |
- // | Redistribution and use in source and binary forms, with or without |
- // | modification, are permitted provided that the following conditions |
- // | are met: |
- // | |
- // | Redistributions of source code must retain the above copyright |
- // | notice, this list of conditions and the following disclaimer. |
- // | |
- // | Redistributions in binary form must reproduce the above copyright |
- // | notice, this list of conditions and the following disclaimer in the |
- // | documentation and/or other materials provided with the distribution. |
- // | |
- // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
- // | Lukas Smith nor the names of his contributors may be used to endorse |
- // | or promote products derived from this software without specific prior|
- // | written permission. |
- // | |
- // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
- // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
- // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
- // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
- // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
- // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
- // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
- // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
- // | POSSIBILITY OF SUCH DAMAGE. |
- // +----------------------------------------------------------------------+
- // | Author: Lukas Smith <smith@pooteeweet.org> |
- // +----------------------------------------------------------------------+
- //
- // $Id: Schema.php,v 1.54 2006/01/13 09:58:37 lsmith Exp $
- //
- require_once 'MDB2.php';
- define('MDB2_SCHEMA_DUMP_ALL', 0);
- define('MDB2_SCHEMA_DUMP_STRUCTURE', 1);
- define('MDB2_SCHEMA_DUMP_CONTENT', 2);
- /**
- * The method mapErrorCode in each MDB2_Schema_dbtype implementation maps
- * native error codes to one of these.
- *
- * If you add an error code here, make sure you also add a textual
- * version of it in MDB2_Schema::errorMessage().
- */
- define('MDB2_SCHEMA_ERROR', -1);
- define('MDB2_SCHEMA_ERROR_PARSE', -2);
- define('MDB2_SCHEMA_ERROR_NOT_CAPABLE', -3);
- define('MDB2_SCHEMA_ERROR_UNSUPPORTED', -4); // Driver does not support this function
- define('MDB2_SCHEMA_ERROR_INVALID', -5); // Invalid attribute value
- define('MDB2_SCHEMA_ERROR_NODBSELECTED', -6);
- /**
- * The database manager is a class that provides a set of database
- * management services like installing, altering and dumping the data
- * structures of databases.
- *
- * @package MDB2_Schema
- * @category Database
- * @author Lukas Smith <smith@pooteeweet.org>
- */
- class MDB2_Schema extends PEAR
- {
- // {{{ properties
- var $db;
- var $warnings = array();
- var $options = array(
- 'fail_on_invalid_names' => true,
- 'dtd_file' => false,
- );
- var $database_definition = array(
- 'name' => '',
- 'create' => false,
- 'tables' => array()
- );
- // }}}
- // {{{ apiVersion()
- /**
- * Return the MDB2 API version
- *
- * @return string the MDB2 API version number
- * @access public
- */
- function apiVersion()
- {
- return '0.4.0';
- }
- // }}}
- // {{{ resetWarnings()
- /**
- * reset the warning array
- *
- * @access public
- */
- function resetWarnings()
- {
- $this->warnings = array();
- }
- // }}}
- // {{{ getWarnings()
- /**
- * get all warnings in reverse order.
- * This means that the last warning is the first element in the array
- *
- * @return array with warnings
- * @access public
- * @see resetWarnings()
- */
- function getWarnings()
- {
- return array_reverse($this->warnings);
- }
- // }}}
- // {{{ setOption()
- /**
- * set the option for the db class
- *
- * @param string $option option name
- * @param mixed $value value for the option
- * @return mixed MDB2_OK or MDB2 Error Object
- * @access public
- */
- function setOption($option, $value)
- {
- if (isset($this->options[$option])) {
- if (is_null($value)) {
- return $this->raiseError(MDB2_SCHEMA_ERROR, null, null,
- 'may not set an option to value null');
- }
- $this->options[$option] = $value;
- return MDB2_OK;
- }
- return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED, null, null,
- "unknown option $option");
- }
- // }}}
- // {{{ getOption()
- /**
- * returns the value of an option
- *
- * @param string $option option name
- * @return mixed the option value or error object
- * @access public
- */
- function getOption($option)
- {
- if (isset($this->options[$option])) {
- return $this->options[$option];
- }
- return $this->raiseError(MDB2_SCHEMA_ERROR_UNSUPPORTED,
- null, null, "unknown option $option");
- }
- // }}}
- // {{{ factory()
- /**
- * Create a new MDB2 object for the specified database type
- * type
- *
- * @param mixed $db 'data source name', see the MDB2::parseDSN
- * method for a description of the dsn format.
- * Can also be specified as an array of the
- * format returned by MDB2::parseDSN.
- * Finally you can also pass an existing db
- * object to be used.
- * @param mixed $options An associative array of option names and
- * their values.
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- * @see MDB2::parseDSN
- */
- function &factory(&$db, $options = array())
- {
- $obj =& new MDB2_Schema();
- $err = $obj->connect($db, $options);
- if (PEAR::isError($err)) {
- return $err;
- }
- return $obj;
- }
- // }}}
- // {{{ connect()
- /**
- * Create a new MDB2 connection object and connect to the specified
- * database
- *
- * @param mixed $db 'data source name', see the MDB2::parseDSN
- * method for a description of the dsn format.
- * Can also be specified as an array of the
- * format returned by MDB2::parseDSN.
- * Finally you can also pass an existing db
- * object to be used.
- * @param mixed $options An associative array of option names and
- * their values.
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- * @see MDB2::parseDSN
- */
- function connect(&$db, $options = array())
- {
- $db_options = array();
- if (is_array($options) && !empty($options)) {
- foreach ($options as $option => $value) {
- if (array_key_exists($option, $this->options)) {
- $err = $this->setOption($option, $value);
- if (PEAR::isError($err)) {
- return $err;
- }
- } else {
- $db_options[$option] = $value;
- }
- }
- }
- $this->disconnect();
- if (!MDB2::isConnection($db)) {
- $db =& MDB2::factory($db, $db_options);
- }
- if (PEAR::isError($db)) {
- return $db;
- }
- $this->db =& $db;
- $this->db->loadModule('Manager');
- $this->db->loadModule('Reverse');
- return MDB2_OK;
- }
- // }}}
- // {{{ disconnect()
- /**
- * Log out and disconnect from the database.
- *
- * @access public
- */
- function disconnect()
- {
- if (MDB2::isConnection($this->db)) {
- $this->db->disconnect();
- unset($this->db);
- }
- }
- // }}}
- // {{{ parseDatabaseDefinitionFile()
- /**
- * Parse a database definition file by creating a Metabase schema format
- * parser object and passing the file contents as parser input data stream.
- *
- * @param string $input_file the path of the database schema file.
- * @param array $variables an associative array that the defines the text
- * string values that are meant to be used to replace the variables that are
- * used in the schema description.
- * @param bool $fail_on_invalid_names (optional) make function fail on invalid
- * names
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- */
- function parseDatabaseDefinitionFile($input_file, $variables = array(),
- $fail_on_invalid_names = true, $structure = false)
- {
- $dtd_file = $this->getOption('dtd_file');
- if ($dtd_file) {
- require_once 'XML/DTD/XmlValidator.php';
- $dtd =& new XML_DTD_XmlValidator;
- if (!$dtd->isValid($dtd_file, $input_file)) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_PARSE, null, null, $dtd->getMessage());
- }
- }
- require_once 'MDB2/Schema/Parser.php';
- $parser =& new MDB2_Schema_Parser($variables, $fail_on_invalid_names, $structure);
- $result = $parser->setInputFile($input_file);
- if (PEAR::isError($result)) {
- return $result;
- }
- $result = $parser->parse();
- if (PEAR::isError($result)) {
- return $result;
- }
- if (PEAR::isError($parser->error)) {
- return $parser->error;
- }
- return $parser->database_definition;
- }
- // }}}
- // {{{ getDefinitionFromDatabase()
- /**
- * Attempt to reverse engineer a schema structure from an existing MDB2
- * This method can be used if no xml schema file exists yet.
- * The resulting xml schema file may need some manual adjustments.
- *
- * @return mixed MDB2_OK or array with all ambiguities on success, or a MDB2 error object
- * @access public
- */
- function getDefinitionFromDatabase()
- {
- $database = $this->db->database_name;
- if (empty($database)) {
- return $this->raiseError('it was not specified a valid database name');
- }
- $this->database_definition = array(
- 'name' => $database,
- 'create' => true,
- 'tables' => array(),
- 'sequences' => array(),
- );
- $tables = $this->db->manager->listTables();
- if (PEAR::isError($tables)) {
- return $tables;
- }
- foreach ($tables as $table_name) {
- $fields = $this->db->manager->listTableFields($table_name);
- if (PEAR::isError($fields)) {
- return $fields;
- }
- $this->database_definition['tables'][$table_name] = array('fields' => array());
- $table_definition =& $this->database_definition['tables'][$table_name];
- foreach ($fields as $field_name) {
- $definition = $this->db->reverse->getTableFieldDefinition($table_name, $field_name);
- if (PEAR::isError($definition)) {
- return $definition;
- }
- if (array_key_exists('autoincrement', $definition[0])
- && $definition[0]['autoincrement']
- ) {
- $definition[0]['default'] = 0;
- }
- $table_definition['fields'][$field_name] = $definition[0];
- $field_choices = count($definition);
- if ($field_choices > 1) {
- $warning = "There are $field_choices type choices in the table $table_name field $field_name (#1 is the default): ";
- $field_choice_cnt = 1;
- $table_definition['fields'][$field_name]['choices'] = array();
- foreach ($definition as $field_choice) {
- $table_definition['fields'][$field_name]['choices'][] = $field_choice;
- $warning .= 'choice #'.($field_choice_cnt).': '.serialize($field_choice);
- $field_choice_cnt++;
- }
- $this->warnings[] = $warning;
- }
- }
- $index_definitions = array();
- $indexes = $this->db->manager->listTableIndexes($table_name);
- if (PEAR::isError($indexes)) {
- return $indexes;
- }
- if (is_array($indexes) && !empty($indexes)
- && !array_key_exists('indexes', $table_definition)
- ) {
- $table_definition['indexes'] = array();
- foreach ($indexes as $index_name) {
- $this->db->expectError(MDB2_ERROR_NOT_FOUND);
- $definition = $this->db->reverse->getTableIndexDefinition($table_name, $index_name);
- $this->db->popExpect();
- if (PEAR::isError($definition, MDB2_ERROR_NOT_FOUND)) {
- continue;
- }
- if (PEAR::isError($definition)) {
- return $definition;
- }
- $index_definitions[$index_name] = $definition;
- }
- }
- $constraints = $this->db->manager->listTableConstraints($table_name);
- if (PEAR::isError($constraints)) {
- return $constraints;
- }
- if (is_array($constraints) && !empty($constraints)
- && !array_key_exists('indexes', $table_definition)
- ) {
- $table_definition['indexes'] = array();
- foreach ($constraints as $index_name) {
- $this->db->expectError(MDB2_ERROR_NOT_FOUND);
- $definition = $this->db->reverse->getTableConstraintDefinition($table_name, $index_name);
- $this->db->popExpect();
- if (PEAR::isError($definition, MDB2_ERROR_NOT_FOUND)) {
- continue;
- }
- if (PEAR::isError($definition)) {
- return $definition;
- }
- $index_definitions[$index_name] = $definition;
- }
- }
- if (!empty($index_definitions)) {
- $table_definition['indexes'] = $index_definitions;
- }
- }
- $sequences = $this->db->manager->listSequences();
- if (PEAR::isError($sequences)) {
- return $sequences;
- }
- if (is_array($sequences) && !empty($sequences)) {
- foreach ($sequences as $sequence_name) {
- $definition = $this->db->reverse->getSequenceDefinition($sequence_name);
- if (PEAR::isError($definition)) {
- return $definition;
- }
- $this->database_definition['sequences'][$sequence_name] = $definition;
- }
- }
- return MDB2_OK;
- }
- // }}}
- // {{{ createTableIndexes()
- /**
- * create a indexes om a table
- *
- * @param string $table_name name of the table
- * @param array $indexes indexes to be created
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @param boolean $overwrite determine if the table/index should be
- overwritten if it already exists
- * @access public
- */
- function createTableIndexes($table_name, $indexes, $overwrite = false)
- {
- if (!$this->db->supports('indexes')) {
- $this->db->debug('Indexes are not supported');
- return MDB2_OK;
- }
- $supports_primary_key = $this->db->supports('primary_key');
- foreach ($indexes as $index_name => $index) {
- $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE);
- $this->db->expectError($errorcodes);
- if (array_key_exists('primary', $index) || array_key_exists('unique', $index)) {
- $indexes = $this->db->manager->listTableConstraints($table_name);
- } else {
- $indexes = $this->db->manager->listTableIndexes($table_name);
- }
- $this->db->popExpect();
- if (PEAR::isError($indexes)) {
- if (!MDB2::isError($indexes, $errorcodes)) {
- return $indexes;
- }
- } elseif (is_array($indexes) && in_array($index_name, $indexes)) {
- if (!$overwrite) {
- $this->db->debug('Index already exists: '.$index_name);
- return MDB2_OK;
- }
- if (array_key_exists('primary', $index) || array_key_exists('unique', $index)) {
- $result = $this->db->manager->dropConstraint($table_name, $index_name);
- } else {
- $result = $this->db->manager->dropIndex($table_name, $index_name);
- }
- if (PEAR::isError($result)) {
- return $result;
- }
- $this->db->debug('Overwritting index: '.$index_name);
- }
- // check if primary is being used and if it's supported
- if (array_key_exists('primary', $index) && !$supports_primary_key) {
- /**
- * Primary not supported so we fallback to UNIQUE
- * and making the field NOT NULL
- */
- unset($index['primary']);
- $index['unique'] = true;
- $fields = $index['fields'];
- $changes = array();
- foreach ($fields as $field => $empty) {
- $field_info = $this->db->reverse->getTableFieldDefinition($table_name, $field);
- if (PEAR::isError($field_info)) {
- return $field_info;
- }
- $changes['change'][$field] = $field_info[0][0];
- $changes['change'][$field]['notnull'] = true;
- }
- $this->db->manager->alterTable($table_name, $changes, false);
- }
- if (array_key_exists('primary', $index) || array_key_exists('unique', $index)) {
- $result = $this->db->manager->createConstraint($table_name, $index_name, $index);
- } else {
- $result = $this->db->manager->createIndex($table_name, $index_name, $index);
- }
- if (PEAR::isError($result)) {
- return $result;
- }
- }
- return MDB2_OK;
- }
- // }}}
- // {{{ createTable()
- /**
- * create a table and inititialize the table if data is available
- *
- * @param string $table_name name of the table to be created
- * @param array $table multi dimensional array that containts the
- * structure and optional data of the table
- * @param boolean $overwrite determine if the table/index should be
- overwritten if it already exists
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- */
- function createTable($table_name, $table, $overwrite = false)
- {
- $create = true;
- $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE);
- $this->db->expectError($errorcodes);
- $tables = $this->db->manager->listTables();
- $this->db->popExpect();
- if (PEAR::isError($tables)) {
- if (!MDB2::isError($tables, $errorcodes)) {
- return $tables;
- }
- } elseif (is_array($tables) && in_array($table_name, $tables)) {
- if (!$overwrite) {
- $create = false;
- $this->db->debug('Table already exists: '.$table_name);
- } else {
- $result = $this->db->manager->dropTable($table_name);
- if (PEAR::isError($result)) {
- return $result;
- }
- $this->db->debug('Overwritting table: '.$table_name);
- }
- }
- if ($create) {
- $result = $this->db->manager->createTable($table_name, $table['fields']);
- if (PEAR::isError($result)) {
- return $result;
- }
- }
- if (array_key_exists('initialization', $table) && is_array($table['initialization'])) {
- $result = $this->initializeTable($table_name, $table);
- if (PEAR::isError($result)) {
- return $result;
- }
- }
- if (array_key_exists('indexes', $table) && is_array($table['indexes'])) {
- $result = $this->createTableIndexes($table_name, $table['indexes'], $overwrite);
- if (PEAR::isError($result)) {
- return $result;
- }
- }
- return MDB2_OK;
- }
- // }}}
- // {{{ initializeTable()
- /**
- * inititialize the table with data
- *
- * @param string $table_name name of the table
- * @param array $table multi dimensional array that containts the
- * structure and optional data of the table
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- */
- function initializeTable($table_name, $table)
- {
- foreach ($table['fields'] as $field_name => $field) {
- $placeholders[$field_name] = ':'.$field_name;
- $types[$field_name] = $field['type'];
- }
- $fields = implode(',', array_keys($table['fields']));
- $placeholders = implode(',', $placeholders);
- $query = "INSERT INTO $table_name ($fields) VALUES ($placeholders)";
- $stmt = $this->db->prepare($query, $types, null, true);
- if (PEAR::isError($stmt)) {
- return $stmt;
- }
- foreach ($table['initialization'] as $instruction) {
- switch ($instruction['type']) {
- case 'insert':
- if (array_key_exists('fields', $instruction) && is_array($instruction['fields'])) {
- $result = $stmt->bindParamArray($instruction['fields']);
- if (PEAR::isError($result)) {
- return $result;
- }
- $result = $stmt->execute();
- if (PEAR::isError($result)) {
- return $result;
- }
- }
- break;
- }
- }
- return $stmt->free();
- }
- // }}}
- // {{{ createSequence()
- /**
- * create a sequence
- *
- * @param string $sequence_name name of the sequence to be created
- * @param array $sequence multi dimensional array that containts the
- * structure and optional data of the table
- * @param boolean $overwrite determine if the sequence should be overwritten
- if it already exists
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- */
- function createSequence($sequence_name, $sequence, $overwrite = false)
- {
- if (!$this->db->supports('sequences')) {
- $this->db->debug('Sequences are not supported');
- return MDB2_OK;
- }
- $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE);
- $this->db->expectError($errorcodes);
- $sequences = $this->db->manager->listSequences();
- $this->db->popExpect();
- if (PEAR::isError($sequences)) {
- if (!MDB2::isError($sequences, $errorcodes)) {
- return $sequences;
- }
- } elseif (is_array($sequence) && in_array($sequence_name, $sequences)) {
- if (!$overwrite) {
- $this->db->debug('Sequence already exists: '.$sequence_name);
- return MDB2_OK;
- }
- $result = $this->db->manager->dropSequence($sequence_name);
- if (PEAR::isError($result)) {
- return $result;
- }
- $this->db->debug('Overwritting sequence: '.$sequence_name);
- }
- $start = 1;
- $field = '';
- if (array_key_exists('on', $sequence)) {
- $table = $sequence['on']['table'];
- $field = $sequence['on']['field'];
- $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE);
- $this->db->expectError($errorcodes);
- $tables = $this->db->manager->listTables();
- $this->db->popExpect();
- if (PEAR::isError($tables) && !MDB2::isError($tables, $errorcodes)) {
- return $tables;
- }
- if (!PEAR::isError($tables) &&
- is_array($tables) && in_array($table, $tables)
- ) {
- if ($this->db->supports('summary_functions')) {
- $query = "SELECT MAX($field) FROM $table";
- } else {
- $query = "SELECT $field FROM $table ORDER BY $field DESC";
- }
- $start = $this->db->queryOne($query, 'integer');
- if (PEAR::isError($start)) {
- return $start;
- }
- ++$start;
- } else {
- $this->warnings[] = 'Could not sync sequence: '.$sequence_name;
- }
- } elseif (array_key_exists('start', $sequence) && is_numeric($sequence['start'])) {
- $start = $sequence['start'];
- $table = '';
- }
- $result = $this->db->manager->createSequence($sequence_name, $start);
- if (PEAR::isError($result)) {
- return $result;
- }
- return MDB2_OK;
- }
- // }}}
- // {{{ createDatabase()
- /**
- * Create a database space within which may be created database objects
- * like tables, indexes and sequences. The implementation of this function
- * is highly DBMS specific and may require special permissions to run
- * successfully. Consult the documentation or the DBMS drivers that you
- * use to be aware of eventual configuration requirements.
- *
- * @return mixed MDB2_OK on success, or a MDB2 error object
- * @access public
- */
- function createDatabase()
- {
- if (!isset($this->database_definition['name']) || !$this->database_definition['name']) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'no valid database name specified');
- }
- $create = (isset($this->database_definition['create']) && $this->database_definition['create']);
- $overwrite = (isset($this->database_definition['overwrite']) && $this->database_definition['overwrite']);
- if ($create) {
- $errorcodes = array(MDB2_ERROR_UNSUPPORTED, MDB2_ERROR_NOT_CAPABLE);
- $this->db->expectError($errorcodes);
- $databases = $this->db->manager->listDatabases();
- // Lower / Upper case the db name if the portability deems so.
- if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
- $func = $this->db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper';
- $db_name = $func($this->database_definition['name']);
- }
- $this->db->popExpect();
- if (PEAR::isError($databases)) {
- if (!MDB2::isError($databases, $errorcodes)) {
- return $databases;
- }
- } elseif (is_array($databases) && in_array($db_name, $databases)) {
- if (!$overwrite) {
- $this->db->debug('Database already exists: ' . $this->database_definition['name']);
- $create = false;
- } else {
- $result = $this->db->manager->dropDatabase($this->database_definition['name']);
- if (PEAR::isError($result)) {
- return $result;
- }
- $this->db->debug('Overwritting database: '.$this->database_definition['name']);
- }
- }
- if ($create) {
- $this->db->expectError(MDB2_ERROR_ALREADY_EXISTS);
- $result = $this->db->manager->createDatabase($this->database_definition['name']);
- $this->db->popExpect();
- if (PEAR::isError($result) && !MDB2::isError($result, MDB2_ERROR_ALREADY_EXISTS)) {
- return $result;
- }
- }
- }
- $previous_database_name = $this->db->setDatabase($this->database_definition['name']);
- if (($support_transactions = $this->db->supports('transactions'))
- && PEAR::isError($result = $this->db->beginTransaction())
- ) {
- return $result;
- }
- $created_objects = 0;
- if (isset($this->database_definition['tables'])
- && is_array($this->database_definition['tables'])
- ) {
- foreach ($this->database_definition['tables'] as $table_name => $table) {
- $result = $this->createTable($table_name, $table, $overwrite);
- if (PEAR::isError($result)) {
- break;
- }
- $created_objects++;
- }
- }
- if (!PEAR::isError($result)
- && isset($this->database_definition['sequences'])
- && is_array($this->database_definition['sequences'])
- ) {
- foreach ($this->database_definition['sequences'] as $sequence_name => $sequence) {
- $result = $this->createSequence($sequence_name, $sequence, false, $overwrite);
- if (PEAR::isError($result)) {
- break;
- }
- $created_objects++;
- }
- }
- if (PEAR::isError($result)) {
- if ($created_objects) {
- if ($support_transactions) {
- $res = $this->db->rollback();
- if (PEAR::isError($res))
- $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null,
- 'Could not rollback the partially created database alterations ('.
- $result->getMessage().' ('.$result->getUserinfo().'))');
- } else {
- $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null,
- 'the database was only partially created ('.
- $result->getMessage().' ('.$result->getUserinfo().'))');
- }
- }
- } else {
- if ($support_transactions) {
- $res = $this->db->commit();
- if (PEAR::isError($res))
- $result = $this->raiseError(MDB2_SCHEMA_ERROR, null, null,
- 'Could not end transaction after successfully created the database ('.
- $res->getMessage().' ('.$res->getUserinfo().'))');
- }
- }
- $this->db->setDatabase($previous_database_name);
- if (PEAR::isError($result) && $create
- && PEAR::isError($result2 = $this->db->manager->dropDatabase($this->database_definition['name']))
- ) {
- return $this->raiseError(MDB2_SCHEMA_ERROR, null, null,
- 'Could not drop the created database after unsuccessful creation attempt ('.
- $result2->getMessage().' ('.$result2->getUserinfo().'))');
- }
- return $result;
- }
- // }}}
- // {{{ compareDefinitions()
- /**
- * compare a previous definition with the currenlty parsed definition
- *
- * @param array multi dimensional array that contains the previous definition
- * @param array multi dimensional array that contains the current definition
- * @return mixed array of changes on success, or a MDB2 error object
- * @access public
- */
- function compareDefinitions($previous_definition, $current_definition = null)
- {
- $current_definition = $current_definition ? $current_definition : $this->database_definition;
- $changes = array();
- if (array_key_exists('tables', $current_definition) && is_array($current_definition['tables'])) {
- $changes['tables'] = $defined_tables = array();
- foreach ($current_definition['tables'] as $table_name => $table) {
- $previous_tables = array();
- if (array_key_exists('tables', $previous_definition) && is_array($previous_definition)) {
- $previous_tables = $previous_definition['tables'];
- }
- $change = $this->compareTableDefinitions($table_name, $previous_tables, $table, $defined_tables);
- if (PEAR::isError($change)) {
- return $change;
- }
- if (!empty($change)) {
- $changes['tables']+= $change;
- }
- }
- if (array_key_exists('tables', $previous_definition) && is_array($previous_definition['tables'])) {
- foreach ($previous_definition['tables'] as $table_name => $table) {
- if (!array_key_exists($table_name, $defined_tables)) {
- $changes['remove'][$table_name] = true;
- }
- }
- }
- }
- if (array_key_exists('sequences', $current_definition) && is_array($current_definition['sequences'])) {
- $changes['sequences'] = $defined_sequences = array();
- foreach ($current_definition['sequences'] as $sequence_name => $sequence) {
- $previous_sequences = array();
- if (array_key_exists('sequences', $previous_definition) && is_array($previous_definition)) {
- $previous_sequences = $previous_definition['sequences'];
- }
- $change = $this->compareSequenceDefinitions(
- $sequence_name,
- $previous_sequences,
- $sequence,
- $defined_sequences
- );
- if (PEAR::isError($change)) {
- return $change;
- }
- if (!empty($change)) {
- $changes['sequences']+= $change;
- }
- }
- if (array_key_exists('sequences', $previous_definition) && is_array($previous_definition['sequences'])) {
- foreach ($previous_definition['sequences'] as $sequence_name => $sequence) {
- if (!array_key_exists($sequence_name, $defined_sequences)) {
- $changes['remove'][$sequence_name] = true;
- }
- }
- }
- }
- return $changes;
- }
- // }}}
- // {{{ compareTableFieldsDefinitions()
- /**
- * compare a previous definition with the currenlty parsed definition
- *
- * @param string $table_name name of the table
- * @param array multi dimensional array that contains the previous definition
- * @param array multi dimensional array that contains the current definition
- * @return mixed array of changes on success, or a MDB2 error object
- * @access public
- */
- function compareTableFieldsDefinitions($table_name, $previous_definition,
- $current_definition, &$defined_fields)
- {
- $changes = array();
- if (is_array($current_definition)) {
- foreach ($current_definition as $field_name => $field) {
- $was_field_name = $field['was'];
- if (array_key_exists($field_name, $previous_definition)
- && isset($previous_definition[$field_name]['was'])
- && $previous_definition[$field_name]['was'] == $was_field_name
- ) {
- $was_field_name = $field_name;
- }
- if (array_key_exists($was_field_name, $previous_definition)) {
- if ($was_field_name != $field_name) {
- $changes['rename'][$was_field_name] = array('name' => $field_name, 'definition' => $field);
- }
- if (array_key_exists($was_field_name, $defined_fields)) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'the field "'.$was_field_name.
- '" was specified as base of more than one field of table');
- }
- $defined_fields[$was_field_name] = true;
- $change = $this->db->compareDefinition($field, $previous_definition[$was_field_name]);
- if (PEAR::isError($change)) {
- return $change;
- }
- if (!empty($change)) {
- $change['definition'] = $field;
- $changes['change'][$field_name] = $change;
- }
- } else {
- if ($field_name != $was_field_name) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'it was specified a previous field name ("'.
- $was_field_name.'") for field "'.$field_name.'" of table "'.
- $table_name.'" that does not exist');
- }
- $changes['add'][$field_name] = $field;
- }
- }
- }
- if (isset($previous_definition) && is_array($previous_definition)) {
- foreach ($previous_definition as $field_previous_name => $field_previous) {
- if (!array_key_exists($field_previous_name, $defined_fields)) {
- $changes['remove'][$field_previous_name] = true;
- }
- }
- }
- return $changes;
- }
- // }}}
- // {{{ compareTableIndexesDefinitions()
- /**
- * compare a previous definition with the currenlty parsed definition
- *
- * @param string $table_name name of the table
- * @param array multi dimensional array that contains the previous definition
- * @param array multi dimensional array that contains the current definition
- * @return mixed array of changes on success, or a MDB2 error object
- * @access public
- */
- function compareTableIndexesDefinitions($table_name, $previous_definition,
- $current_definition, &$defined_indexes)
- {
- $changes = array();
- if (is_array($current_definition)) {
- foreach ($current_definition as $index_name => $index) {
- $was_index_name = $index['was'];
- if (array_key_exists($index_name, $previous_definition)
- && isset($previous_definition[$index_name]['was'])
- && $previous_definition[$index_name]['was'] == $was_index_name
- ) {
- $was_index_name = $index_name;
- }
- if (array_key_exists($was_index_name, $previous_definition)) {
- $change = array();
- if ($was_index_name != $index_name) {
- $change['name'] = $was_index_name;
- }
- if (array_key_exists($was_index_name, $defined_indexes)) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'the index "'.$was_index_name.'" was specified as base of'.
- ' more than one index of table "'.$table_name.'"');
- }
- $defined_indexes[$was_index_name] = true;
- $previous_unique = isset($previous_definition[$was_index_name]['unique']);
- $unique = array_key_exists('unique', $index);
- if ($previous_unique != $unique) {
- $change['unique'] = $unique;
- }
- $defined_fields = array();
- $previous_fields = $previous_definition[$was_index_name]['fields'];
- if (array_key_exists('fields', $index) && is_array($index['fields'])) {
- foreach ($index['fields'] as $field_name => $field) {
- if (array_key_exists($field_name, $previous_fields)) {
- $defined_fields[$field_name] = true;
- $sorting = (array_key_exists('sorting', $field) ? $field['sorting'] : '');
- $previous_sorting = (isset($previous_fields[$field_name]['sorting'])
- ? $previous_fields[$field_name]['sorting'] : '');
- if ($sorting != $previous_sorting) {
- $change['change'] = true;
- }
- } else {
- $change['change'] = true;
- }
- }
- }
- if (isset($previous_fields) && is_array($previous_fields)) {
- foreach ($previous_fields as $field_name => $field) {
- if (!array_key_exists($field_name, $defined_fields)) {
- $change['change'] = true;
- }
- }
- }
- if (!empty($change)) {
- $changes['change'][$index_name] = $change;
- }
- } else {
- if ($index_name != $was_index_name) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'it was specified a previous index name ("'.$was_index_name.
- ') for index "'.$index_name.'" of table "'.$table_name.'" that does not exist');
- }
- $changes['add'][$index_name] = $current_definition[$index_name];
- }
- }
- }
- foreach ($previous_definition as $index_previous_name => $index_previous) {
- if (!array_key_exists($index_previous_name, $defined_indexes)) {
- $changes['remove'][$index_previous_name] = true;
- }
- }
- return $changes;
- }
- // }}}
- // {{{ compareTableDefinitions()
- /**
- * compare a previous definition with the currenlty parsed definition
- *
- * @param string $table_name name of the table
- * @param array multi dimensional array that contains the previous definition
- * @param array multi dimensional array that contains the current definition
- * @return mixed array of changes on success, or a MDB2 error object
- * @access public
- */
- function compareTableDefinitions($table_name, $previous_definition,
- $current_definition, &$defined_tables)
- {
- $changes = array();
- if (is_array($current_definition)) {
- $was_table_name = $table_name;
- if (array_key_exists('was', $current_definition)) {
- $was_table_name = $current_definition['was'];
- }
- if (array_key_exists($was_table_name, $previous_definition)) {
- $changes['change'][$was_table_name] = array();
- if ($was_table_name != $table_name) {
- $changes['change'][$was_table_name]+= array('name' => $table_name);
- }
- if (array_key_exists($was_table_name, $defined_tables)) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'the table "'.$was_table_name.
- '" was specified as base of more than of table of the database');
- }
- $defined_tables[$was_table_name] = true;
- if (array_key_exists('fields', $current_definition) && is_array($current_definition['fields'])) {
- $previous_fields = array();
- if (isset($previous_definition[$was_table_name]['fields'])
- && is_array($previous_definition[$was_table_name]['fields'])
- ) {
- $previous_fields = $previous_definition[$was_table_name]['fields'];
- }
- $defined_fields = array();
- $change = $this->compareTableFieldsDefinitions(
- $table_name,
- $previous_fields,
- $current_definition['fields'],
- $defined_fields
- );
- if (PEAR::isError($change)) {
- return $change;
- }
- if (!empty($change)) {
- $changes['change'][$was_table_name]+= $change;
- }
- }
- if (array_key_exists('indexes', $current_definition) && is_array($current_definition['indexes'])) {
- $previous_indexes = array();
- if (isset($previous_definition[$was_table_name]['indexes'])
- && is_array($previous_definition[$was_table_name]['indexes'])
- ) {
- $previous_indexes = $previous_definition[$was_table_name]['indexes'];
- }
- $defined_indexes = array();
- $change = $this->compareTableIndexesDefinitions(
- $table_name,
- $previous_indexes,
- $current_definition['indexes'],
- $defined_indexes
- );
- if (PEAR::isError($change)) {
- return $change;
- }
- if (!empty($change)) {
- if (isset($changes['change'][$was_table_name]['indexes'])) {
- $changes['change'][$was_table_name]['indexes']+= $change;
- } else {
- $changes['change'][$was_table_name]['indexes'] = $change;
- }
- }
- }
- if (empty($changes['change'][$was_table_name])) {
- unset($changes['change'][$was_table_name]);
- }
- if (empty($changes['change'])) {
- unset($changes['change']);
- }
- } else {
- if ($table_name != $was_table_name) {
- return $this->raiseError(MDB2_SCHEMA_ERROR_INVALID, null, null,
- 'it was specified a previous table name ("'.$was_table_name.
- '") for table "'.$table_name.'" that does not exist');
- }
- $changes['add'][$table_name] = true;
- }
- }
- return $changes;
- }
- // }}}
- // {{{ compareSequenceDefinitions()
- /**
- * compare a previous definition with the currenlty parsed definition
- *
- * @param array multi dimensional array that contains the previous definition
- * @param array multi dimensional array that contains the current definition
- * @return mixed array of changes on success, or a MDB2 error object
- * @access public
- */
- function compareSequenceDefinitions($sequence_name, $previous_definition,
- $current_definition, &$defined_sequences)
- {
- $changes = array();
- if (is_array($current_definition)) {
- $was_sequence_name = $sequence_name;
- if (array_key_exists($sequence_name, $previous_definition)
- && isset($previous_definition[$sequence_name]['was'])
- && $previous_definition[$sequence_name]['was'] == $was_sequence_name
- ) {
- $was_sequence_name = $sequence_name;
- } elseif (array_key_exists('was', $current_definition)) {
- $was_sequence_name = $current_definition['was'];
- }
- if (array_key_exists($was_sequence_name, $previous_definition)) {
- if ($was_sequence_name != $sequence_name) {
- $changes['change'][$was_sequence_name]['name'] = $sequence_name;
- }
- if (array_key_exists($was_sequence_name, $defined_sequences)) {
- …
Large files files are truncated, but you can click here to view the full file