PageRenderTime 82ms CodeModel.GetById 22ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/php/MDB/Manager.php

https://bitbucket.org/adarshj/convenient_website
PHP | 2148 lines | 1657 code | 85 blank | 406 comment | 439 complexity | bd1ebbc794ec7f9e153393dfd80db32c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2// +----------------------------------------------------------------------+
   3// | PHP Version 4                                                        |
   4// +----------------------------------------------------------------------+
   5// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
   6// | Stig. S. Bakken, Lukas Smith                                         |
   7// | All rights reserved.                                                 |
   8// +----------------------------------------------------------------------+
   9// | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
  10// | API as well as database abstraction for PHP applications.            |
  11// | This LICENSE is in the BSD license style.                            |
  12// |                                                                      |
  13// | Redistribution and use in source and binary forms, with or without   |
  14// | modification, are permitted provided that the following conditions   |
  15// | are met:                                                             |
  16// |                                                                      |
  17// | Redistributions of source code must retain the above copyright       |
  18// | notice, this list of conditions and the following disclaimer.        |
  19// |                                                                      |
  20// | Redistributions in binary form must reproduce the above copyright    |
  21// | notice, this list of conditions and the following disclaimer in the  |
  22// | documentation and/or other materials provided with the distribution. |
  23// |                                                                      |
  24// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  25// | Lukas Smith nor the names of his contributors may be used to endorse |
  26// | or promote products derived from this software without specific prior|
  27// | written permission.                                                  |
  28// |                                                                      |
  29// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  30// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  31// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  32// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  33// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  34// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  37// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  38// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  40// | POSSIBILITY OF SUCH DAMAGE.                                          |
  41// +----------------------------------------------------------------------+
  42// | Author: Lukas Smith <smith@backendmedia.com>                         |
  43// +----------------------------------------------------------------------+
  44//
  45// $Id: Manager.php,v 1.75.4.4 2004/03/10 14:42:59 lsmith Exp $
  46//
  47
  48require_once('MDB/Parser.php');
  49
  50define('MDB_MANAGER_DUMP_ALL',          0);
  51define('MDB_MANAGER_DUMP_STRUCTURE',    1);
  52define('MDB_MANAGER_DUMP_CONTENT',      2);
  53
  54/**
  55 * The database manager is a class that provides a set of database
  56 * management services like installing, altering and dumping the data
  57 * structures of databases.
  58 *
  59 * @package MDB
  60 * @category Database
  61 * @author  Lukas Smith <smith@backendmedia.com>
  62 */
  63class MDB_Manager extends PEAR
  64{
  65    // {{{ properties
  66
  67    var $database;
  68
  69    var $options = array(
  70            'fail_on_invalid_names' => 1,
  71            'debug' => 0
  72        );
  73    var $invalid_names = array(
  74        'user' => array(),
  75        'is' => array(),
  76        'file' => array(
  77            'oci' => array(),
  78            'oracle' => array()
  79        ),
  80        'notify' => array(
  81            'pgsql' => array()
  82        ),
  83        'restrict' => array(
  84            'mysql' => array()
  85        ),
  86        'password' => array(
  87            'ibase' => array()
  88        )
  89    );
  90    var $default_values = array(
  91        'integer' => 0,
  92        'float' => 0,
  93        'decimal' => 0,
  94        'text' => '',
  95        'timestamp' => '0001-01-01 00:00:00',
  96        'date' => '0001-01-01',
  97        'time' => '00:00:00'
  98    );
  99
 100    var $warnings = array();
 101
 102    var $database_definition = array(
 103        'name' => '',
 104        'create' => 0,
 105        'TABLES' => array()
 106    );
 107
 108    // }}}
 109    // {{{ raiseError()
 110
 111    /**
 112     * This method is used to communicate an error and invoke error
 113     * callbacks etc.  Basically a wrapper for PEAR::raiseError
 114     * without the message string.
 115     *
 116     * @param mixed $code integer error code, or a PEAR error object (all
 117     *      other parameters are ignored if this parameter is an object
 118     * @param int $mode error mode, see PEAR_Error docs
 119     * @param mixed $options If error mode is PEAR_ERROR_TRIGGER, this is the
 120     *      error level (E_USER_NOTICE etc).  If error mode is
 121     *      PEAR_ERROR_CALLBACK, this is the callback function, either as a
 122     *      function name, or as an array of an object and method name. For
 123     *      other error modes this parameter is ignored.
 124     * @param string $userinfo Extra debug information.  Defaults to the last
 125     *      query and native error code.
 126     * @param mixed $nativecode Native error code, integer or string depending
 127     *      the backend.
 128     * @return object a PEAR error object
 129     * @access public
 130     * @see PEAR_Error
 131     */
 132    function &raiseError($code = MDB_MANAGER_ERROR, $mode = NULL, $options = NULL,
 133        $userinfo = NULL, $nativecode = NULL)
 134    {
 135        // The error is yet a MDB error object
 136        if(is_object($code)) {
 137            $err = PEAR::raiseError($code, NULL, NULL, NULL, NULL, NULL, TRUE);
 138            return($err);
 139        }
 140        
 141        $err = PEAR::raiseError(NULL, $code, $mode, $options, $userinfo,
 142            'MDB_Error', TRUE);
 143        return($err);
 144    }
 145
 146    // }}}
 147    // {{{ captureDebugOutput()
 148
 149    /**
 150     * set a debug handler
 151     *
 152     * @param string $capture name of the function that should be used in
 153     *     debug()
 154     * @access public
 155     * @see debug()
 156     */
 157    function captureDebugOutput($capture)
 158    {
 159        $this->options['debug'] = $capture;
 160        $this->database->captureDebugOutput(1);
 161    }
 162
 163    // }}}
 164    // {{{ debugOutput()
 165
 166    /**
 167     * output debug info
 168     *
 169     * @return string content of the debug_output class variable
 170     * @access public
 171     */
 172    function debugOutput()
 173    {
 174        return($this->database->debugOutput());
 175    }
 176
 177    // }}}
 178    // {{{ resetWarnings()
 179
 180    /**
 181     * reset the warning array
 182     *
 183     * @access public
 184     */
 185    function resetWarnings()
 186    {
 187        $this->warnings = array();
 188    }
 189
 190    // }}}
 191    // {{{ getWarnings()
 192
 193    /**
 194     * get all warnings in reverse order.
 195     * This means that the last warning is the first element in the array
 196     *
 197     * @return array with warnings
 198     * @access public
 199     * @see resetWarnings()
 200     */
 201    function getWarnings()
 202    {
 203        return array_reverse($this->warnings);
 204    }
 205
 206    // }}}
 207    // {{{ setOption()
 208
 209    /**
 210     * set the option for the db class
 211     *
 212     * @param string $option option name
 213     * @param mixed $value value for the option
 214     * @return mixed MDB_OK or MDB_Error
 215     * @access public
 216     */
 217    function setOption($option, $value)
 218    {
 219        if(isset($this->options[$option])) {
 220            $this->options[$option] = $value;
 221            return(MDB_OK);
 222        }
 223        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, "unknown option $option"));
 224    }
 225
 226    // }}}
 227    // {{{ getOption()
 228
 229    /**
 230     * returns the value of an option
 231     *
 232     * @param string $option option name
 233     * @return mixed the option value or error object
 234     * @access public
 235     */
 236    function getOption($option)
 237    {
 238        if(isset($this->options[$option])) {
 239            return($this->options[$option]);
 240        }
 241        return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, "unknown option $option"));
 242    }
 243
 244    // }}}
 245    // {{{ connect()
 246
 247    /**
 248     * Create a new MDB connection object and connect to the specified
 249     * database
 250     *
 251     * @param   mixed   $dbinfo   'data source name', see the MDB::parseDSN
 252     *                            method for a description of the dsn format.
 253     *                            Can also be specified as an array of the
 254     *                            format returned by MDB::parseDSN.
 255     *                            Finally you can also pass an existing db
 256     *                            object to be used.
 257     * @param   mixed   $options  An associative array of option names and
 258     *                            their values.
 259     * @return  mixed MDB_OK on success, or a MDB error object
 260     * @access  public
 261     * @see     MDB::parseDSN
 262     */
 263    function &connect(&$dbinfo, $options = FALSE)
 264    {
 265        if(is_object($this->database) && !MDB::isError($this->database)) {
 266            $this->disconnect();
 267        }
 268        if(is_object($dbinfo)) {
 269             $this->database =& $dbinfo;
 270        } else {
 271            $this->database =& MDB::connect($dbinfo, $options);
 272            if(MDB::isError($this->database)) {
 273                return($this->database);
 274            }
 275        }
 276        if(is_array($options)) {
 277            $this->options = array_merge($options, $this->options);
 278        }
 279        return(MDB_OK);
 280    }
 281
 282    // }}}
 283    // {{{ disconnect()
 284
 285    /**
 286     * Log out and disconnect from the database.
 287     *
 288     * @access public
 289     */
 290    function disconnect()
 291    {
 292        if(is_object($this->database) && !MDB::isError($this->database)) {
 293            $this->database->disconnect();
 294            unset($this->database);
 295        }
 296    }
 297
 298    // }}}
 299    // {{{ setDatabase()
 300
 301    /**
 302     * Select a different database
 303     *
 304     * @param string $name name of the database that should be selected
 305     * @return string name of the database previously connected to
 306     * @access public
 307     */
 308    function setDatabase($name)
 309    {
 310        return($this->database->setDatabase($name));
 311    }
 312
 313    // }}}
 314    // {{{ _createTable()
 315
 316    /**
 317     * create a table and inititialize the table if data is available
 318     *
 319     * @param string $table_name  name of the table to be created
 320     * @param array  $table       multi dimensional array that containts the
 321     *                            structure and optional data of the table
 322     * @param boolean $overwrite  determine if the table/index should be
 323                                  overwritten if it already exists
 324     * @return mixed MDB_OK on success, or a MDB error object
 325     * @access private
 326     */
 327    function _createTable($table_name, $table, $overwrite = FALSE)
 328    {
 329        $this->expectError(MDB_ERROR_ALREADY_EXISTS);
 330        $result = $this->database->createTable($table_name, $table['FIELDS']);
 331        $this->popExpect();
 332        if(MDB::isError($result)) {
 333            if($result->getCode() === MDB_ERROR_ALREADY_EXISTS) {
 334                $this->warnings[] = 'Table already exists: '.$table_name;
 335                if($overwrite) {
 336                    $this->database->debug('Overwritting Table');
 337                    $result = $this->database->dropTable($table_name);
 338                    if(MDB::isError($result)) {
 339                        return($result);
 340                    }
 341                    $result = $this->database->createTable($table_name, $table['FIELDS']);
 342                    if(MDB::isError($result)) {
 343                        return($result);
 344                    }
 345                } else {
 346                    $result = MDB_OK;
 347                }
 348            } else {
 349                $this->database->debug('Create table error: '.$table_name);
 350                return($result);
 351            }
 352        }
 353        if(isset($table['initialization']) && is_array($table['initialization'])) {
 354            foreach($table['initialization'] as $instruction) {
 355                switch($instruction['type']) {
 356                    case 'insert':
 357                        $query_fields = $query_values = array();
 358                        if(isset($instruction['FIELDS']) && is_array($instruction['FIELDS'])) {
 359                            foreach($instruction['FIELDS'] as $field_name => $field) {
 360                                $query_fields[] = $field_name;
 361                                $query_values[] = '?';
 362                            }
 363                            $query_fields = implode(',',$query_fields);
 364                            $query_values = implode(',',$query_values);
 365                            $result = $prepared_query = $this->database->prepareQuery(
 366                                "INSERT INTO $table_name ($query_fields) VALUES ($query_values)");
 367                        }
 368                        if(!MDB::isError($prepared_query)) {
 369                            if(isset($instruction['FIELDS']) && is_array($instruction['FIELDS'])) {
 370                                $lobs = array();
 371                                $field_number = 0;
 372                                foreach($instruction['FIELDS'] as $field_name => $field) {
 373                                    $field_number++;
 374                                    $query = $field_name;
 375                                    switch($table['FIELDS'][$field_name]['type']) {
 376                                        case 'integer':
 377                                            $result = $this->database->setParamInteger($prepared_query,
 378                                                $field_number, intval($field));
 379                                            break;
 380                                        case 'text':
 381                                            $result = $this->database->setParamText($prepared_query,
 382                                                $field_number, $field);
 383                                            break;
 384                                        case 'clob':
 385                                            $lob_definition = array(
 386                                                'Database' => $this->database,
 387                                                'Error' => '',
 388                                                'Data' => $field
 389                                            );
 390                                            if(MDB::isError($result = $this->database->createLob($lob_definition)))
 391                                            {
 392                                                break;
 393                                            }
 394                                            $lob = count($lobs);
 395                                            $lobs[$lob] = $result;
 396                                            $result = $this->database->setParamClob($prepared_query,
 397                                                $field_number, $lobs[$lob], $field_name);
 398                                            break;
 399                                        case 'blob':
 400                                            $lob_definition = array(
 401                                                'Database' => $this->database,
 402                                                'Error' => '',
 403                                                'Data' => $field
 404                                            );
 405                                            if(MDB::isError($result = $this->database->createLob($lob_definition))) {
 406                                                break;
 407                                            }
 408                                            $lob = count($lobs);
 409                                            $lobs[$lob] = $result;
 410                                            $result = $this->database->setParamBlob($prepared_query,
 411                                                $field_number, $lobs[$lob], $field_name);
 412                                            break;
 413                                        case 'boolean':
 414                                            $result = $this->database->setParamBoolean($prepared_query,
 415                                                $field_number, intval($field));
 416                                            break;
 417                                        case 'date':
 418                                            $result = $this->database->setParamDate($prepared_query,
 419                                                $field_number, $field);
 420                                            break;
 421                                        case 'timestamp':
 422                                            $result = $this->database->setParamTimestamp($prepared_query,
 423                                                $field_number, $field);
 424                                            break;
 425                                        case 'time':
 426                                            $result = $this->database->setParamTime($prepared_query,
 427                                                $field_number, $field);
 428                                            break;
 429                                        case 'float':
 430                                            $result = $this->database->setParamFloat($prepared_query,
 431                                                $field_number, doubleval($field));
 432                                            break;
 433                                        case 'decimal':
 434                                            $result = $this->database->setParamDecimal($prepared_query,
 435                                                $field_number, $field);
 436                                            break;
 437                                        default:
 438                                            $result = $this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 439                                                'type "'.$field['type'].'" is not yet supported');
 440                                            break;
 441                                    }
 442                                    if(MDB::isError($result)) {
 443                                        break;
 444                                    }
 445                                }
 446                            }
 447                            if(!MDB::isError($result)) {
 448                                $result = $this->database->executeQuery($prepared_query);
 449                            }
 450                            for($lob = 0; $lob < count($lobs); $lob++) {
 451                                $this->database->destroyLOB($lobs[$lob]);
 452                            }
 453                            $this->database->freePreparedQuery($prepared_query);
 454                        }
 455                        break;
 456                }
 457            }
 458        };
 459        if(!MDB::isError($result) && isset($table['INDEXES']) && is_array($table['INDEXES'])) {
 460            if(!$this->database->support('Indexes')) {
 461                return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
 462                    'indexes are not supported'));
 463            }
 464            foreach($table['INDEXES'] as $index_name => $index) {
 465                $this->expectError(MDB_ERROR_ALREADY_EXISTS);
 466                $result = $this->database->createIndex($table_name, $index_name, $index);
 467                $this->popExpect();
 468                if(MDB::isError($result)) {
 469                    if($result->getCode() === MDB_ERROR_ALREADY_EXISTS) {
 470                        $this->warnings[] = 'Index already exists: '.$index_name;
 471                        if($overwrite) {
 472                            $this->database->debug('Overwritting Index');
 473                            $result = $this->database->dropIndex($table_name, $index_name);
 474                            if(MDB::isError($result)) {
 475                                break;
 476                            }
 477                            $result = $this->database->createIndex($table_name, $index_name, $index);
 478                            if(MDB::isError($result)) {
 479                                break;
 480                            }
 481                        } else {
 482                            $result = MDB_OK;
 483                        }
 484                    } else {
 485                        $this->database->debug('Create index error: '.$table_name);
 486                        break;
 487                    }
 488                }
 489            }
 490        }
 491        if(MDB::isError($result)) {
 492            $result = $this->database->dropTable($table_name);
 493            if(MDB::isError($result)) {
 494                $result = $this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 495                    'could not drop the table ('
 496                    .$result->getMessage().' ('.$result->getUserinfo(),'))',
 497                    'MDB_Error', TRUE);
 498            }
 499            return($result);
 500        }
 501        return(MDB_OK);
 502    }
 503
 504    // }}}
 505    // {{{ _dropTable()
 506
 507    /**
 508     * drop a table
 509     *
 510     * @param string $table_name    name of the table to be dropped
 511     * @return mixed MDB_OK on success, or a MDB error object
 512     * @access private
 513     */
 514    function _dropTable($table_name)
 515    {
 516        return($this->database->dropTable($table_name));
 517    }
 518
 519    // }}}
 520    // {{{ _createSequence()
 521
 522    /**
 523     * create a sequence
 524     *
 525     * @param string $sequence_name  name of the sequence to be created
 526     * @param array  $sequence       multi dimensional array that containts the
 527     *                               structure and optional data of the table
 528     * @param string $created_on_table
 529     * @param boolean $overwrite    determine if the sequence should be overwritten
 530                                    if it already exists
 531     * @return mixed MDB_OK on success, or a MDB error object
 532     * @access private
 533     */
 534    function _createSequence($sequence_name, $sequence, $created_on_table, $overwrite = FALSE)
 535    {
 536        if(!$this->database->support('Sequences')) {
 537            return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
 538                'sequences are not supported'));
 539        }
 540        if(!isset($sequence_name) || !strcmp($sequence_name, '')) {
 541            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 542                'no valid sequence name specified'));
 543        }
 544        $this->database->debug('Create sequence: '.$sequence_name);
 545        if(isset($sequence['start']) && $sequence['start'] != '') {
 546            $start = $sequence['start'];
 547        } else if(isset($sequence['on']) && !$created_on_table) {
 548            $table = $sequence['on']['table'];
 549            $field = $sequence['on']['field'];
 550            if($this->database->support('Summaryfunctions')) {
 551                $field = "MAX($field)";
 552            }
 553            $start = $this->database->queryOne("SELECT $field FROM $table");
 554            if(MDB::isError($start)) {
 555                return($start);
 556            }
 557        } else {
 558            $start = 1;
 559        }
 560        
 561        $this->expectError(MDB_ERROR_ALREADY_EXISTS);
 562        $result = $this->database->createSequence($sequence_name, $start);
 563        $this->popExpect();
 564        if(MDB::isError($result)) {
 565            if($result->getCode() === MDB_ERROR_ALREADY_EXISTS) {
 566                $this->warnings[] = 'Sequence already exists: '.$sequence_name;
 567                if($overwrite) {
 568                    $this->database->debug('Overwritting Sequence');
 569                    $result = $this->database->dropSequence($sequence_name);
 570                    if(MDB::isError($result)) {
 571                        return($result);
 572                    }
 573                    $result = $this->database->createSequence($sequence_name, $start);
 574                    if(MDB::isError($result)) {
 575                        return($result);
 576                    }
 577                } else {
 578                    return(MDB_OK);
 579                }
 580            } else {
 581                $this->database->debug('Create sequence error: '.$sequence_name);
 582                return($result);
 583            }
 584        }
 585    }
 586
 587    // }}}
 588    // {{{ _dropSequence()
 589
 590    /**
 591     * drop a table
 592     *
 593     * @param string $sequence_name    name of the sequence to be dropped
 594     * @return mixed MDB_OK on success, or a MDB error object
 595     * @access private
 596     */
 597    function _dropSequence($sequence_name)
 598    {
 599        if(!$this->database->support('Sequences')) {
 600            return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
 601                'sequences are not supported'));
 602        }
 603        $this->database->debug('Dropping sequence: '.$sequence_name);
 604        if(!isset($sequence_name) || !strcmp($sequence_name, '')) {
 605            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 606                'no valid sequence name specified'));
 607        }
 608        return($this->database->dropSequence($sequence_name));
 609    }
 610
 611    // }}}
 612    // {{{ _createDatabase()
 613
 614    /**
 615     * Create a database space within which may be created database objects
 616     * like tables, indexes and sequences. The implementation of this function
 617     * is highly DBMS specific and may require special permissions to run
 618     * successfully. Consult the documentation or the DBMS drivers that you
 619     * use to be aware of eventual configuration requirements.
 620     *
 621     * @return mixed MDB_OK on success, or a MDB error object
 622     * @access private
 623     */
 624    function _createDatabase()
 625    {
 626        if(!isset($this->database_definition['name'])
 627            || !strcmp($this->database_definition['name'], '')
 628        ) {
 629            return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 630                'no valid database name specified'));
 631        }
 632        $create = (isset($this->database_definition['create']) && $this->database_definition['create']);
 633        $overwrite = (isset($this->database_definition['overwrite']) && $this->database_definition['overwrite']);
 634        if($create) {
 635            $this->database->debug('Create database: '.$this->database_definition['name']);
 636            $this->expectError(MDB_ERROR_ALREADY_EXISTS);
 637            $result = $this->database->createDatabase($this->database_definition['name']);
 638            $this->popExpect();
 639            if(MDB::isError($result)) {
 640                if($result->getCode() === MDB_ERROR_ALREADY_EXISTS) {
 641                    $this->warnings[] = 'Database already exists: '.$this->database_definition['name'];
 642                    if($overwrite) {
 643                        $this->database->debug('Overwritting Database');
 644                        $result = $this->database->dropDatabase($this->database_definition['name']);
 645                        if(MDB::isError($result)) {
 646                            return($result);
 647                        }
 648                        $result = $this->database->createDatabase($this->database_definition['name']);
 649                        if(MDB::isError($result)) {
 650                            return($result);
 651                        }
 652                    } else {
 653                        $result = MDB_OK;
 654                    }
 655                } else {
 656                    $this->database->debug('Create database error.');
 657                    return($result);
 658                }
 659            }
 660        }
 661        $previous_database_name = $this->database->setDatabase($this->database_definition['name']);
 662        if(($support_transactions = $this->database->support('Transactions'))
 663            && MDB::isError($result = $this->database->autoCommit(FALSE))
 664        ) {
 665            return($result);
 666        }
 667
 668        $created_objects = 0;
 669        if(isset($this->database_definition['TABLES'])
 670            && is_array($this->database_definition['TABLES'])
 671        ) {
 672            foreach($this->database_definition['TABLES'] as $table_name => $table) {
 673                $result = $this->_createTable($table_name, $table, $overwrite);
 674                if(MDB::isError($result)) {
 675                    break;
 676                }
 677                $created_objects++;
 678            }
 679        }
 680        if(!MDB::isError($result) 
 681            && isset($this->database_definition['SEQUENCES'])
 682            && is_array($this->database_definition['SEQUENCES'])
 683        ) {
 684            foreach($this->database_definition['SEQUENCES'] as $sequence_name => $sequence) {
 685                $result = $this->_createSequence($sequence_name, $sequence, 0, $overwrite);
 686                
 687                if(MDB::isError($result)) {
 688                    break;
 689                }
 690                $created_objects++;
 691            }
 692        }
 693        
 694        if(MDB::isError($result)) {
 695            if($created_objects) {
 696                if($support_transactions) {
 697                    $res = $this->database->rollback();
 698                    if(MDB::isError($res))
 699                        $result = $this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 700                            'Could not rollback the partially created database alterations ('
 701                            .$result->getMessage().' ('.$result->getUserinfo(),'))',
 702                            'MDB_Error', TRUE);
 703                } else {
 704                    $result = $this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 705                        'the database was only partially created ('
 706                        .$result->getMessage().' ('.$result->getUserinfo(),'))',
 707                        'MDB_Error', TRUE);
 708                }
 709            }
 710        } else {
 711            if($support_transactions) {
 712                $res = $this->database->autoCommit(TRUE);
 713                if(MDB::isError($res))
 714                    $result = $this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 715                        'Could not end transaction after successfully created the database ('
 716                        .$res->getMessage().' ('.$res->getUserinfo(),'))',
 717                        'MDB_Error', TRUE);
 718            }
 719        }
 720        
 721        $this->database->setDatabase($previous_database_name);
 722        
 723        if(MDB::isError($result)
 724            && $create
 725            && MDB::isError($res = $this->database->dropDatabase($this->database_definition['name']))
 726        ) {
 727            return($this->raiseError(MDB_ERROR_MANAGER, NULL, NULL,
 728                'Could not drop the created database after unsuccessful creation attempt ('
 729                .$res->getMessage().' ('.$res->getUserinfo(),'))',
 730                'MDB_Error', TRUE));
 731        }
 732        
 733        if(MDB::isError($result)) {
 734            return($result);
 735        }
 736        
 737        return(MDB_OK);
 738    }
 739
 740    // }}}
 741    // {{{ _addDefinitionChange()
 742
 743    /**
 744     * add change to an array of multiple changes
 745     *
 746     * @param array  &$changes
 747     * @param string $definition
 748     * @param string $item
 749     * @param array  $change
 750     * @return mixed MDB_OK on success, or a MDB error object
 751     * @access private
 752     */
 753    function _addDefinitionChange(&$changes, $definition, $item, $change)
 754    {
 755        if(!isset($changes[$definition][$item])) {
 756            $changes[$definition][$item] = array();
 757        }
 758        foreach($change as $change_data_name => $change_data) {
 759            if(isset($change_data) && is_array($change_data)) {
 760                if(!isset($changes[$definition][$item][$change_data_name])) {
 761                    $changes[$definition][$item][$change_data_name] = array();
 762                }
 763                foreach($change_data as $change_part_name => $change_part) {
 764                    $changes[$definition][$item][$change_data_name][$change_part_name] = $change_part;
 765                }
 766            } else {
 767                $changes[$definition][$item][$change_data_name] = $change_data;
 768            }
 769        }
 770        return(MDB_OK);
 771    }
 772
 773    // }}}
 774    // {{{ _compareDefinitions()
 775
 776    /**
 777     * compare a previous definition with the currenlty parsed definition
 778     *
 779     * @param array multi dimensional array that contains the previous definition
 780     * @return mixed array of changes on success, or a MDB error object
 781     * @access private
 782     */
 783    function _compareDefinitions($previous_definition)
 784    {
 785        $defined_tables = $changes = array();
 786        if(isset($this->database_definition['TABLES']) && is_array($this->database_definition['TABLES'])) {
 787            foreach($this->database_definition['TABLES'] as $table_name => $table) {
 788                $was_table_name = $table['was'];
 789                if(isset($previous_definition['TABLES'][$table_name])
 790                    && isset($previous_definition['TABLES'][$table_name]['was'])
 791                    && !strcmp($previous_definition['TABLES'][$table_name]['was'], $was_table_name)
 792                ) {
 793                    $was_table_name = $table_name;
 794                }
 795                if(isset($previous_definition['TABLES'][$was_table_name])) {
 796                    if(strcmp($was_table_name, $table_name)) {
 797                        $this->_addDefinitionChange($changes, 'TABLES', $was_table_name, array('name' => $table_name));
 798                        $this->database->debug("Renamed table '$was_table_name' to '$table_name'");
 799                    }
 800                    if(isset($defined_tables[$was_table_name])) {
 801                        return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 802                            'the table "'.$was_table_name.'" was specified as base of more than of table of the database',
 803                            'MDB_Error', TRUE));
 804                    }
 805                    $defined_tables[$was_table_name] = 1;
 806                    
 807                    $previous_fields = $previous_definition['TABLES'][$was_table_name]['FIELDS'];
 808                    $defined_fields = array();
 809                    if(isset($table['FIELDS']) && is_array($table['FIELDS'])) {
 810                        foreach($table['FIELDS'] as $field_name => $field) {
 811                            $was_field_name = $field['was'];
 812                            if(isset($previous_fields[$field_name])
 813                                && isset($previous_fields[$field_name]['was'])
 814                                && !strcmp($previous_fields[$field_name]['was'], $was_field_name)
 815                            ) {
 816                                $was_field_name = $field_name;
 817                            }
 818                            if(isset($previous_fields[$was_field_name])) {
 819                                if(strcmp($was_field_name, $field_name)) {
 820                                    $query = $this->database->getFieldDeclaration($field_name, $field);
 821                                    if(MDB::isError($query)) {
 822                                        return($query);
 823                                    }
 824                                    $this->_addDefinitionChange($changes, 'TABLES', $was_table_name,
 825                                        array(
 826                                            'RenamedFields' => array(
 827                                                $was_field_name => array(
 828                                                    'name' => $field_name,
 829                                                    'Declaration' => $query
 830                                                )
 831                                            )
 832                                        )
 833                                    );
 834                                    $this->database->debug("Renamed field '$was_field_name' to '$field_name' in table '$table_name'");
 835                                }
 836                                if(isset($defined_fields[$was_field_name])) {
 837                                    return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 838                                        'the field "'.$was_table_name.'" was specified as base of more than one field of table',
 839                                        'MDB_Error', TRUE));
 840                                }
 841                                $defined_fields[$was_field_name] = 1;
 842                                $change = array();
 843                                if($field['type'] == $previous_fields[$was_field_name]['type']) {
 844                                    switch($field['type']) {
 845                                        case 'integer':
 846                                            $previous_unsigned = isset($previous_fields[$was_field_name]['unsigned']);
 847                                            $unsigned = isset($fields[$field_name]['unsigned']);
 848                                            if(strcmp($previous_unsigned, $unsigned)) {
 849                                                $change['unsigned'] = $unsigned;
 850                                                $this->database->debug("Changed field '$field_name' type from '".($previous_unsigned ? 'unsigned ' : '').$previous_fields[$was_field_name]['type']."' to '".($unsigned ? 'unsigned ' : '').$field['type']."' in table '$table_name'");
 851                                            }
 852                                            break;
 853                                        case 'text':
 854                                        case 'clob':
 855                                        case 'blob':
 856                                            $previous_length = (isset($previous_fields[$was_field_name]['length']) ? $previous_fields[$was_field_name]['length'] : 0);
 857                                            $length = (isset($field['length']) ? $field['length'] : 0);
 858                                            if(strcmp($previous_length, $length)) {
 859                                                $change['length'] = $length;
 860                                                $this->database->debug("Changed field '$field_name' length from '".$previous_fields[$was_field_name]['type'].($previous_length == 0 ? ' no length' : "($previous_length)")."' to '".$field['type'].($length == 0 ? ' no length' : "($length)")."' in table '$table_name'");
 861                                            }
 862                                            break;
 863                                        case 'date':
 864                                        case 'timestamp':
 865                                        case 'time':
 866                                        case 'boolean':
 867                                        case 'float':
 868                                        case 'decimal':
 869                                            break;
 870                                        default:
 871                                            return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
 872                                                'type "'.$field['type'].'" is not yet supported',
 873                                                'MDB_Error', TRUE));
 874                                    }
 875                                    
 876                                    $previous_notnull = isset($previous_fields[$was_field_name]['notnull']);
 877                                    $notnull = isset($field['notnull']);
 878                                    if($previous_notnull != $notnull) {
 879                                        $change['ChangedNotNull'] = 1;
 880                                        if($notnull) {
 881                                            $change['notnull'] = isset($field['notnull']);
 882                                        }
 883                                        $this->database->debug("Changed field '$field_name' notnull from $previous_notnull to $notnull in table '$table_name'");
 884                                    }
 885                                    
 886                                    $previous_default = isset($previous_fields[$was_field_name]['default']);
 887                                    $default = isset($field['default']);
 888                                    if(strcmp($previous_default, $default)) {
 889                                        $change['ChangedDefault'] = 1;
 890                                        if($default) {
 891                                            $change['default'] = $field['default'];
 892                                        }
 893                                        $this->database->debug("Changed field '$field_name' default from ".($previous_default ? "'".$previous_fields[$was_field_name]['default']."'" : 'NULL').' TO '.($default ? "'".$fields[$field_name]['default']."'" : 'NULL')." IN TABLE '$table_name'");
 894                                    } else {
 895                                        if($default
 896                                            && strcmp($previous_fields[$was_field_name]['default'], $field['default'])
 897                                        ) {
 898                                            $change['ChangedDefault'] = 1;
 899                                            $change['default'] = $field['default'];
 900                                            $this->database->debug("Changed field '$field_name' default from '".$previous_fields[$was_field_name]['default']."' to '".$fields[$field_name]['default']."' in table '$table_name'");
 901                                        }
 902                                    }
 903                                } else {
 904                                    $change['type'] = $field['type'];
 905                                    $this->database->debug("Changed field '$field_name' type from '".$previous_fields[$was_field_name]['type']."' to '".$fields[$field_name]['type']."' in table '$table_name'");
 906                                }
 907                                if(count($change)) {
 908                                    $query = $this->database->getFieldDeclaration($field_name, $field);
 909                                    if(MDB::isError($query)) {
 910                                        return($query);
 911                                    }
 912                                    $change['Declaration'] = $query;
 913                                    $change['Definition'] = $field;
 914                                    $this->_addDefinitionChange($changes, 'TABLES', $was_table_name, array('ChangedFields' => array($field_name => $change)));
 915                                }
 916                            } else {
 917                                if(strcmp($field_name, $was_field_name)) {
 918                                    return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 919                                        'it was specified a previous field name ("'
 920                                        .$was_field_name.'") for field "'.$field_name.'" of table "'
 921                                        .$table_name.'" that does not exist',
 922                                        'MDB_Error', TRUE));
 923                                }
 924                                $query = $this->database->getFieldDeclaration($field_name, $field);
 925                                if(MDB::isError($query)) {
 926                                    return($query);
 927                                }
 928                                $change['Declaration'] = $query;
 929                                $this->_addDefinitionChange($changes, 'TABLES', $table_name, array('AddedFields' => array($field_name => $change)));
 930                                $this->database->debug("Added field '$field_name' to table '$table_name'");
 931                            }
 932                        }
 933                    }
 934                    if(isset($previous_fields) && is_array($previous_fields)) {
 935                        foreach ($previous_fields as $field_previous_name => $field_previous) {
 936                            if(!isset($defined_fields[$field_previous_name])) {
 937                                $this->_addDefinitionChange($changes, 'TABLES', $table_name, array('RemovedFields' => array($field_previous_name => array())));
 938                                $this->database->debug("Removed field '$field_name' from table '$table_name'");
 939                            }
 940                        }
 941                    }
 942                    $indexes = array();
 943                    if(isset($this->database_definition['TABLES'][$table_name]['INDEXES'])
 944                        && is_array($this->database_definition['TABLES'][$table_name]['INDEXES'])
 945                    ) {
 946                        $indexes = $this->database_definition['TABLES'][$table_name]['INDEXES'];
 947                    }
 948                    $previous_indexes = array();
 949                    if(isset($previous_definition['TABLES'][$was_table_name]['INDEXES'])
 950                        && is_array($previous_definition['TABLES'][$was_table_name]['INDEXES'])
 951                    ) {
 952                        $previous_indexes = $previous_definition['TABLES'][$was_table_name]['INDEXES'];
 953                    }
 954                    $defined_indexes = array();
 955                    foreach($indexes as $index_name => $index) {
 956                        $was_index_name = $index['was'];
 957                        if(isset($previous_indexes[$index_name])
 958                            && isset($previous_indexes[$index_name]['was'])
 959                            && !strcmp($previous_indexes[$index_name]['was'], $was_index_name)
 960                        ) {
 961                            $was_index_name = $index_name;
 962                        }
 963                        if(isset($previous_indexes[$was_index_name])) {
 964                            $change = array();
 965                            
 966                            if(strcmp($was_index_name, $index_name)) {
 967                                $change['name'] = $was_index_name;
 968                                $this->database->debug("Changed index '$was_index_name' name to '$index_name' in table '$table_name'");
 969                            }
 970                            if(isset($defined_indexes[$was_index_name])) {
 971                                return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 972                                    'the index "'.$was_index_name.'" was specified as base of'
 973                                    .' more than one index of table "'.$table_name.'"',
 974                                    'MDB_Error', TRUE));
 975                            }
 976                            $defined_indexes[$was_index_name] = 1;
 977                            
 978                            $previous_unique = isset($previous_indexes[$was_index_name]['unique']);
 979                            $unique = isset($index['unique']);
 980                            if($previous_unique != $unique) {
 981                                $change['ChangedUnique'] = 1;
 982                                if($unique) {
 983                                    $change['unique'] = $unique;
 984                                }
 985                                $this->database->debug("Changed index '$index_name' unique from $previous_unique to $unique in table '$table_name'");
 986                            }
 987                            $defined_fields = array();
 988                            $previous_fields = $previous_indexes[$was_index_name]['FIELDS'];
 989                            if(isset($index['FIELDS']) && is_array($index['FIELDS'])) {
 990                                foreach($index['FIELDS'] as $field_name => $field) {
 991                                    if(isset($previous_fields[$field_name])) {
 992                                        $defined_fields[$field_name] = 1;
 993                                        $sorting = (isset($field['sorting']) ? $field['sorting'] : '');
 994                                        $previous_sorting = (isset($previous_fields[$field_name]['sorting']) ? $previous_fields[$field_name]['sorting'] : '');
 995                                        if(strcmp($sorting, $previous_sorting)) {
 996                                            $this->database->debug("Changed index field '$field_name' sorting default from '$previous_sorting' to '$sorting' in table '$table_name'");
 997                                            $change['ChangedFields'] = 1;
 998                                        }
 999                                    } else {
1000                                        $change['ChangedFields'] = 1;
1001                                        $this->database->debug("Added field '$field_name' to index '$index_name' of table '$table_name'");
1002                                    }
1003                                }
1004                            }
1005                            if(isset($previous_fields) && is_array($previous_fields)) {
1006                                foreach($previous_fields as $field_name => $field) {
1007                                    if(!isset($defined_fields[$field_name])) {
1008                                        $change['ChangedFields'] = 1;
1009                                        $this->database->debug("Removed field '$field_name' from index '$index_name' of table '$table_name'");
1010                                    }
1011                                }
1012                            }
1013                            
1014                            if(count($change)) {
1015                                $this->_addDefinitionChange($changes, 'INDEXES', $table_name,array('ChangedIndexes' => array($index_name => $change)));
1016                            }
1017                        } else {
1018                            if(strcmp($index_name, $was_index_name)) {
1019                                return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
1020                                    'it was specified a previous index name ("'.$was_index_name
1021                                    .') for index "'.$index_name.'" of table "'.$table_name.'" that does not exist',
1022                                    'MDB_Error', TRUE));
1023                            }
1024                            $this->_addDefinitionChange($changes, 'INDEXES', $table_name,array('AddedIndexes' => array($index_name => $indexes[$index_name])));
1025                            $this->database->debug("Added index '$index_name' to table '$table_name'");
1026                        }
1027                    }
1028           

Large files files are truncated, but you can click here to view the full file