MDB2
[ class tree: MDB2 ] [ index: MDB2 ] [ all elements ]

Source for file Manager.php

Documentation is available at Manager.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5                                                 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
  6. // | Stig. S. Bakken, Lukas Smith                                         |
  7. // | All rights reserved.                                                 |
  8. // +----------------------------------------------------------------------+
  9. // | MDB2 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.29 2005/02/22 09:53:35 lsmith Exp $
  46. //
  47.  
  48. require_once 'MDB2/Tools/Manager/Parser.php';
  49. require_once 'MDB2/Tools/Manager/Writer.php';
  50.  
  51. define('MDB2_MANAGER_DUMP_ALL',          0);
  52. define('MDB2_MANAGER_DUMP_STRUCTURE',    1);
  53. define('MDB2_MANAGER_DUMP_CONTENT',      2);
  54.  
  55. /**
  56.  * The database manager is a class that provides a set of database
  57.  * management services like installing, altering and dumping the data
  58.  * structures of databases.
  59.  *
  60.  * @package MDB2
  61.  * @category Database
  62.  * @author  Lukas Smith <smith@backendmedia.com>
  63.  */
  64. class MDB2_Tools_Manager extends PEAR
  65. {
  66.     // {{{ properties
  67.  
  68.     var $db;
  69.  
  70.     var $warnings = array();
  71.  
  72.     var $options = array(
  73.         'fail_on_invalid_names' => true,
  74.     );
  75.  
  76.     var $invalid_names = array(
  77.         'user' => array(),
  78.         'is' => array(),
  79.         'file' => array(
  80.             'oci' => array(),
  81.             'oracle' => array()
  82.         ),
  83.         'notify' => array(
  84.             'pgsql' => array()
  85.         ),
  86.         'restrict' => array(
  87.             'mysql' => array()
  88.         ),
  89.         'password' => array(
  90.             'ibase' => array()
  91.         )
  92.     );
  93.  
  94.     var $default_values = array(
  95.         'integer' => 0,
  96.         'float' => 0,
  97.         'decimal' => 0,
  98.         'text' => '',
  99.         'timestamp' => '0001-01-01 00:00:00',
  100.         'date' => '0001-01-01',
  101.         'time' => '00:00:00'
  102.     );
  103.  
  104.     var $database_definition = array(
  105.         'name' => '',
  106.         'create' => 0,
  107.         'tables' => array()
  108.     );
  109.  
  110.     // }}}
  111.     // {{{ raiseError()
  112.  
  113.     /**
  114.      * This method is used to communicate an error and invoke error
  115.      * callbacks etc.  Basically a wrapper for PEAR::raiseError
  116.      * without the message string.
  117.      *
  118.      * @param mixed $code integer error code, or a PEAR error object (all
  119.      *       other parameters are ignored if this parameter is an object
  120.      * @param int $mode error mode, see PEAR_Error docs
  121.      * @param mixed $options If error mode is PEAR_ERROR_TRIGGER, this is the
  122.      *       error level (E_USER_NOTICE etc).  If error mode is
  123.      *       PEAR_ERROR_CALLBACK, this is the callback function, either as a
  124.      *       function name, or as an array of an object and method name. For
  125.      *       other error modes this parameter is ignored.
  126.      * @param string $userinfo Extra debug information.  Defaults to the last
  127.      *       query and native error code.
  128.      * @param mixed $nativecode Native error code, integer or string depending
  129.      *       the backend.
  130.      * @return object PEAR error object
  131.      * @access public
  132.      * @see PEAR_Error
  133.      */
  134.     function &raiseError($code = null$mode = null$options = null$userinfo = null)
  135.     {
  136.         return MDB2_Driver_Common::raiseError($code$mode$options$userinfo);
  137.     }
  138.  
  139.     // }}}
  140.     // {{{ debugOutput()
  141.  
  142.     /**
  143.      * output debug info
  144.      *
  145.      * @return string content of the debug_output class variable
  146.      * @access public
  147.      */
  148.     function debugOutput()
  149.     {
  150.         return $this->db->debugOutput();
  151.     }
  152.  
  153.     // }}}
  154.     // {{{ resetWarnings()
  155.  
  156.     /**
  157.      * reset the warning array
  158.      *
  159.      * @access public
  160.      */
  161.     function resetWarnings()
  162.     {
  163.         $this->warnings = array();
  164.     }
  165.  
  166.     // }}}
  167.     // {{{ getWarnings()
  168.  
  169.     /**
  170.      * get all warnings in reverse order.
  171.      * This means that the last warning is the first element in the array
  172.      *
  173.      * @return array with warnings
  174.      * @access public
  175.      * @see resetWarnings()
  176.      */
  177.     function getWarnings()
  178.     {
  179.         return array_reverse($this->warnings);
  180.     }
  181.  
  182.     // }}}
  183.     // {{{ setOption()
  184.  
  185.     /**
  186.      * set the option for the db class
  187.      *
  188.      * @param string $option option name
  189.      * @param mixed $value value for the option
  190.      * @return mixed MDB2_OK or MDB2 Error Object
  191.      * @access public
  192.      */
  193.     function setOption($option$value)
  194.     {
  195.         if (isset($this->options[$option])) {
  196.             if (is_null($value)) {
  197.                 return $this->raiseError(MDB2_ERRORnullnull,
  198.                     'may not set an option to value null');
  199.             }
  200.             $this->options[$option$value;
  201.             return MDB2_OK;
  202.         }
  203.         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  204.             "unknown option $option");
  205.     }
  206.  
  207.     // }}}
  208.     // {{{ getOption()
  209.  
  210.     /**
  211.      * returns the value of an option
  212.      *
  213.      * @param string $option option name
  214.      * @return mixed the option value or error object
  215.      * @access public
  216.      */
  217.     function getOption($option)
  218.     {
  219.         if (isset($this->options[$option])) {
  220.             return $this->options[$option];
  221.         }
  222.         return $this->raiseError(MDB2_ERROR_UNSUPPORTED,
  223.             nullnull"unknown option $option");
  224.     }
  225.  
  226.     // }}}
  227.     // {{{ connect()
  228.  
  229.     /**
  230.      * Create a new MDB2 connection object and connect to the specified
  231.      * database
  232.      *
  233.      * @param   mixed   $dbinfo   'data source name', see the MDB2::parseDSN
  234.      *                             method for a description of the dsn format.
  235.      *                             Can also be specified as an array of the
  236.      *                             format returned by MDB2::parseDSN.
  237.      *                             Finally you can also pass an existing db
  238.      *                             object to be used.
  239.      * @param   mixed   $options  An associative array of option names and
  240.      *                             their values.
  241.      * @return  mixed MDB2_OK on success, or a MDB2 error object
  242.      * @access  public
  243.      * @see     MDB2::parseDSN
  244.      */
  245.     function connect(&$dbinfo$options = false)
  246.     {
  247.         if (is_object($this->db&& !MDB2::isError($this->db)) {
  248.             $this->disconnect();
  249.         }
  250.         if (is_object($dbinfo)) {
  251.              $this->db =$dbinfo;
  252.         else {
  253.             $this->db =MDB2::connect($dbinfo$options);
  254.             if (MDB2::isError($this->db)) {
  255.                 return $this->db;
  256.             }
  257.         }
  258.         if (is_array($options)) {
  259.             $this->options = array_merge($options$this->options);
  260.         }
  261.         $this->db->loadModule('Manager');
  262.         return MDB2_OK;
  263.     }
  264.  
  265.     // }}}
  266.     // {{{ disconnect()
  267.  
  268.     /**
  269.      * Log out and disconnect from the database.
  270.      *
  271.      * @access public
  272.      */
  273.     function disconnect()
  274.     {
  275.         if (MDB2::isConnection($this->db&& !MDB2::isError($this->db)) {
  276.             $this->db->disconnect();
  277.             unset($this->db);
  278.         }
  279.     }
  280.  
  281.     // }}}
  282.     // {{{ setDatabase()
  283.  
  284.     /**
  285.      * Select a different database
  286.      *
  287.      * @param string $name name of the database that should be selected
  288.      * @return string name of the database previously connected to
  289.      * @access public
  290.      */
  291.     function setDatabase($name)
  292.     {
  293.         return $this->db->setDatabase($name);
  294.     }
  295.  
  296.     // }}}
  297.     // {{{ parseDatabaseDefinitionFile()
  298.  
  299.     /**
  300.      * Parse a database definition file by creating a Metabase schema format
  301.      * parser object and passing the file contents as parser input data stream.
  302.      *
  303.      * @param string $input_file the path of the database schema file.
  304.      * @param array $variables an associative array that the defines the text
  305.      *  string values that are meant to be used to replace the variables that are
  306.      *  used in the schema description.
  307.      * @param bool $fail_on_invalid_names (optional) make function fail on invalid
  308.      *  names
  309.      * @return mixed MDB2_OK on success, or a MDB2 error object
  310.      * @access public
  311.      */
  312.     function parseDatabaseDefinitionFile($input_file$variables$fail_on_invalid_names = true)
  313.     {
  314.         $parser =new MDB2_Tools_Parser($variables$fail_on_invalid_names);
  315.         $result $parser->setInputFile($input_file);
  316.         if (MDB2::isError($result)) {
  317.             return $result;
  318.         }
  319.         $result $parser->parse();
  320.         if (MDB2::isError($result)) {
  321.             return $result;
  322.         }
  323.         if (!$result || MDB2::isError($parser->error)) {
  324.             return $parser->error;
  325.         }
  326.         return $parser->database_definition;
  327.     }
  328.  
  329.     // }}}
  330.     // {{{ getDefinitionFromDatabase()
  331.  
  332.     /**
  333.      * Attempt to reverse engineer a schema structure from an existing MDB2
  334.      * This method can be used if no xml schema file exists yet.
  335.      * The resulting xml schema file may need some manual adjustments.
  336.      *
  337.      * @return mixed MDB2_OK or array with all ambiguities on success, or a MDB2 error object
  338.      * @access public
  339.      */
  340.     function getDefinitionFromDatabase()
  341.     {
  342.         $this->db->loadModule('Reverse');
  343.         $database $this->db->database_name;
  344.         if (strlen($database== 0{
  345.             return $this->raiseError('it was not specified a valid database name');
  346.         }
  347.         $this->database_definition = array(
  348.             'name' => $database,
  349.             'create' => 1,
  350.             'tables' => array(),
  351.         );
  352.         $tables $this->db->manager->listTables();
  353.         if (MDB2::isError($tables)) {
  354.             return $tables;
  355.         }
  356.  
  357.         for ($table = 0; $table count($tables)$table++{
  358.             $table_name $tables[$table];
  359.             $fields $this->db->manager->listTableFields($table_name);
  360.             if (MDB2::isError($fields)) {
  361.                 return $fields;
  362.             }
  363.             $this->database_definition['tables'][$table_name= array('fields' => array());
  364.             $table_definition =$this->database_definition['tables'][$table_name];
  365.             for ($field = 0; $field count($fields)$field++{
  366.                 $field_name $fields[$field];
  367.                 $definition $this->db->reverse->getTableFieldDefinition($table_name$field_name);
  368.                 if (MDB2::isError($definition)) {
  369.                     return $definition;
  370.                 }
  371.                 $table_definition['fields'][$field_name$definition[0][0];
  372.                 $field_choices count($definition[0]);
  373.                 if ($field_choices > 1{
  374.                     $warning = "There are $field_choices type choices in the table $table_name field $field_name (#1 is the default): ";
  375.                     $field_choice_cnt = 1;
  376.                     $table_definition['fields'][$field_name]['choices'= array();
  377.                     foreach ($definition[0as $field_choice{
  378.                         $table_definition['fields'][$field_name]['choices'][$field_choice;
  379.                         $warning .= 'choice #'.($field_choice_cnt).': '.serialize($field_choice);
  380.                         $field_choice_cnt++;
  381.                     }
  382.                     $this->warnings[$warning;
  383.                 }
  384.                 if (isset($definition[1])) {
  385.                     $sequence $definition[1]['definition'];
  386.                     $sequence_name $definition[1]['name'];
  387.                     $this->db->debug('Implicitly defining sequence: '.$sequence_name);
  388.                     if (!isset($this->database_definition['sequences'])) {
  389.                         $this->database_definition['sequences'= array();
  390.                     }
  391.                     $this->database_definition['sequences'][$sequence_name$sequence;
  392.                 }
  393.                 if (isset($definition[2])) {
  394.                     $index $definition[2]['definition'];
  395.                     $index_name $definition[2]['name'];
  396.                     $this->db->debug('Implicitly defining index: '.$index_name);
  397.                     if (!isset($table_definition['indexes'])) {
  398.                         $table_definition['indexes'= array();
  399.                     }
  400.                     $table_definition['indexes'][$index_name$index;
  401.                 }
  402.             }
  403.             $indexes $this->db->manager->listTableIndexes($table_name);
  404.             if (MDB2::isError($indexes)) {
  405.                 return $indexes;
  406.             }
  407.             if (is_array($indexes&& count($indexes> 0
  408.                 && !isset($table_definition['indexes'])
  409.             {
  410.                 $table_definition['indexes'= array();
  411.             }
  412.             for ($index = 0$index_cnt count($indexes)$index $index_cnt$index++{
  413.                 $index_name $indexes[$index];
  414.                 $definition $this->db->reverse->getTableIndexDefinition($table_name$index_name);
  415.                 if (MDB2::isError($definition)) {
  416.                     return $definition;
  417.                 }
  418.                $table_definition['indexes'][$index_name$definition;
  419.             }
  420.             // ensure that all fields that have an index on them are set to NOT NULL
  421.             if (isset($table_definition['indexes'])
  422.                 && is_array($table_definition['indexes'])
  423.                 && count($table_definition['indexes'])
  424.             {
  425.                 foreach ($table_definition['indexes'as $index_check_null{
  426.                     foreach ($index_check_null['fields'as $field_name_check_null => $field_check_null{
  427.                         $table_definition['fields'][$field_name_check_null]['notnull'= true;
  428.                     }
  429.                 }
  430.             }
  431.             // ensure that all fields that are set to NOT NULL also have a default value
  432.             if (is_array($table_definition['fields']&& count($table_definition['fields'])) {
  433.                 foreach ($table_definition['fields'as $field_set_default_name => $field_set_default{
  434.                     if (isset($field_set_default['notnull']&& $field_set_default['notnull']
  435.                         && !isset($field_set_default['default'])
  436.                     {
  437.                         $table_field_definition[$field_set_default_name]['default']  '';
  438.                         if (isset($this->default_values[$field_set_default['type']])) {
  439.                             $table_field_definition[$field_set_default_name]['default']
  440.                                 = $this->default_values[$field_set_default['type']];
  441.                         }
  442.                     }
  443.                     if (isset($field_set_default['choices']&& is_array($field_set_default['choices'])) {
  444.                         foreach ($field_set_default['choices'as $choice_name => $choice_default{
  445.                             if (isset($choice_default['notnull'])
  446.                                 && $choice_default['notnull']
  447.                                 && !isset($choice_default['default'])
  448.                             {
  449.                                 $table_field_definition[$field_set_default_name]['choices'][$choices_name]['default''';
  450.                                 if (isset($this->default_values[$choice_default['type']])) {
  451.                                     $table_field_definition[$field_set_default_name]['choices'][$choice_name]['default']
  452.                                         = $this->default_values[$choice_default['type']];
  453.                                 }
  454.                             }
  455.                         }
  456.                     }
  457.                 }
  458.             }
  459.         }
  460.  
  461.         $sequences $this->db->manager->listSequences();
  462.         if (MDB2::isError($sequences)) {
  463.             return $sequences;
  464.         }
  465.         if (is_array($sequences&& count($sequences> 0 && !isset($this->database_definition['sequences'])) {
  466.             $this->database_definition['sequences'= array();
  467.         }
  468.         for ($sequence = 0; $sequence count($sequences)$sequence++{
  469.             $sequence_name $sequences[$sequence];
  470.             $definition $this->db->reverse->getSequenceDefinition($sequence_name);
  471.             if (MDB2::isError($definition)) {
  472.                 return $definition;
  473.             }
  474.             $this->database_definition['sequences'][$sequence_name$definition;
  475.         }
  476.         return MDB2_OK;
  477.     }
  478.  
  479.     // }}}
  480.     // {{{ createTableIndexes()
  481.  
  482.     /**
  483.      * create a indexes om a table
  484.      *
  485.      * @param string $table_name  name of the table
  486.      * @param array  $indexes     indexes to be created
  487.      * @return mixed MDB2_OK on success, or a MDB2 error object
  488.      * @param boolean $overwrite  determine if the table/index should be
  489.                                   overwritten if it already exists
  490.      * @access public
  491.      */
  492.     function createTableIndexes($table_name$indexes$overwrite)
  493.     {
  494.         if (!$this->db->supports('indexes')) {
  495.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  496.                 'indexes are not supported');
  497.         }
  498.         $result MDB2_OK;
  499.         foreach ($indexes as $index_name => $index{
  500.             $this->expectError(MDB2_ERROR_ALREADY_EXISTS);
  501.             $result $this->db->manager->createIndex($table_name$index_name$index);
  502.             $this->popExpect();
  503.             if (MDB2::isError($result)) {
  504.                 if ($result->getCode(=== MDB2_ERROR_ALREADY_EXISTS{
  505.                     $this->warnings['Index already exists: '.$index_name;
  506.                     if ($overwrite{
  507.                         $this->db->debug('Overwritting Index');
  508.                         $result $this->db->manager->dropIndex($table_name$index_name);
  509.                         if (!MDB2::isError($result)) {
  510.                             $result $this->db->manager->createIndex($table_name$index_name$index);
  511.                         }
  512.                     else {
  513.                         $result MDB2_OK;
  514.                     }
  515.                 }
  516.                 if (MDB2::isError($result)) {
  517.                     $this->db->debug('Create index error: '.$table_name);
  518.                     break;
  519.                 }
  520.             }
  521.         }
  522.         return $result;
  523.     }
  524.  
  525.     // }}}
  526.     // {{{ createTable()
  527.  
  528.     /**
  529.      * create a table and inititialize the table if data is available
  530.      *
  531.      * @param string $table_name  name of the table to be created
  532.      * @param array  $table       multi dimensional array that containts the
  533.      *                             structure and optional data of the table
  534.      * @param boolean $overwrite  determine if the table/index should be
  535.                                   overwritten if it already exists
  536.      * @return mixed MDB2_OK on success, or a MDB2 error object
  537.      * @access public
  538.      */
  539.     function createTable($table_name$table$overwrite = false)
  540.     {
  541.         $this->expectError(MDB2_ERROR_ALREADY_EXISTS);
  542.         $result $this->db->manager->createTable($table_name$table['fields']);
  543.         $this->popExpect();
  544.         if (MDB2::isError($result)) {
  545.             if ($result->getCode(=== MDB2_ERROR_ALREADY_EXISTS{
  546.                 $this->warnings['Table already exists: '.$table_name;
  547.                 if ($overwrite{
  548.                     $this->db->debug('Overwritting Table');
  549.                     $result $this->dropTable($table_name);
  550.                     if (!MDB2::isError($result)) {
  551.                         $result $this->db->manager->createTable($table_name$table['fields']);
  552.                     }
  553.                 else {
  554.                     $result MDB2_OK;
  555.                 }
  556.             }
  557.             if (MDB2::isError($result)) {
  558.                 $this->db->debug('Create table error: '.$table_name);
  559.                 return $result;
  560.             }
  561.         }
  562.         if (isset($table['initialization']&& is_array($table['initialization'])) {
  563.             $result $this->initializeTable($table_name$table);
  564.         }
  565.         if (!MDB2::isError($result&& isset($table['indexes']&& is_array($table['indexes'])) {
  566.             $result $this->createTableIndexes($table_name$table['indexes']$overwrite);
  567.         }
  568.         if (MDB2::isError($result)) {
  569.             $result $this->dropTable($table_name);
  570.             if (MDB2::isError($result)) {
  571.                 $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  572.                     'could not drop the table ('.$result->getMessage().
  573.                     ' ('.$result->getUserinfo().'))');
  574.             }
  575.             return $result;
  576.         }
  577.         return MDB2_OK;
  578.     }
  579.  
  580.     // }}}
  581.     // {{{ initializeTable()
  582.  
  583.     /**
  584.      * inititialize the table with data
  585.      *
  586.      * @param string $table_name        name of the table
  587.      * @param array  $table       multi dimensional array that containts the
  588.      *                             structure and optional data of the table
  589.      * @return mixed MDB2_OK on success, or a MDB2 error object
  590.      * @access public
  591.      */
  592.     function initializeTable($table_name$table)
  593.     {
  594.         $result MDB2_OK;
  595.         foreach ($table['initialization'as $instruction{
  596.             switch ($instruction['type']{
  597.             case 'insert':
  598.                 $query_fields $query_values = array();
  599.                 if (isset($instruction['fields']&& is_array($instruction['fields'])) {
  600.                     foreach ($instruction['fields'as $field_name => $field{
  601.                         $query_fields[$field_name;
  602.                         $query_values['?';
  603.                         $query_types[$table['fields'][$field_name]['type'];
  604.                     }
  605.                     $query_fields implode(',',$query_fields);
  606.                     $query_values implode(',',$query_values);
  607.                     $stmt $this->db->prepare(
  608.                         "INSERT INTO $table_name ($query_fields) VALUES ($query_values)"$query_types);
  609.                     if (MDB2::isError($stmt)) {
  610.                         return $stmt;
  611.                     }
  612.                     $result $stmt->bindParamArray(array_values($instruction['fields']));
  613.                     if (MDB2::isError($result)) {
  614.                         return $result;
  615.                     }
  616.                     $result $stmt->execute();
  617.                     $stmt->free();
  618.                 }
  619.                 break;
  620.             }
  621.         }
  622.         return $result;
  623.     }
  624.  
  625.     // }}}
  626.     // {{{ dropTable()
  627.  
  628.     /**
  629.      * drop a table
  630.      *
  631.      * @param string $table_name    name of the table to be dropped
  632.      * @return mixed MDB2_OK on success, or a MDB2 error object
  633.      * @access public
  634.      */
  635.     function dropTable($table_name)
  636.     {
  637.         return $this->db->manager->dropTable($table_name);
  638.     }
  639.  
  640.     // }}}
  641.     // {{{ createSequence()
  642.  
  643.     /**
  644.      * create a sequence
  645.      *
  646.      * @param string $sequence_name  name of the sequence to be created
  647.      * @param array  $sequence       multi dimensional array that containts the
  648.      *                                structure and optional data of the table
  649.      * @param boolean $overwrite    determine if the sequence should be overwritten
  650.                                     if it already exists
  651.      * @return mixed MDB2_OK on success, or a MDB2 error object
  652.      * @access private
  653.      */
  654.     function createSequence($sequence_name$sequence$overwrite = false)
  655.     {
  656.         if (!$this->db->supports('sequences')) {
  657.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  658.                 'sequences are not supported');
  659.         }
  660.         if (!isset($sequence_name|| $sequence_name == ''{
  661.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  662.                 'no valid sequence name specified');
  663.         }
  664.         $this->db->debug('Create sequence: '.$sequence_name);
  665.         $start = 1;
  666.         if (isset($sequence['on'])) {
  667.             $table $sequence['on']['table'];
  668.             $field $sequence['on']['field'];
  669.             if ($this->db->supports('summary_functions')) {
  670.                 $query = "SELECT MAX($field) FROM $table";
  671.             else {
  672.                 $query = "SELECT $field FROM $table ORDER BY $field DESC";
  673.             }
  674.             $start $this->db->queryOne($query'integer');
  675.             if (MDB2::isError($start)) {
  676.                 return $start;
  677.             }
  678.             $start++;
  679.         elseif (isset($sequence['start']&& is_numeric($sequence['start'])) {
  680.             $start $sequence['start'];
  681.         }
  682.         $this->expectError(MDB2_ERROR_ALREADY_EXISTS);
  683.         $result $this->db->manager->createSequence($sequence_name$start);
  684.         $this->popExpect();
  685.         if (MDB2::isError($result)) {
  686.             if ($result->getCode(=== MDB2_ERROR_ALREADY_EXISTS{
  687.                 $this->warnings['Sequence already exists: '.$sequence_name;
  688.                 if ($overwrite{
  689.                     $this->db->debug('Overwritting Sequence');
  690.                     $result $this->dropSequence($sequence_name);
  691.                     if (!MDB2::isError($result)) {
  692.                         $result $this->db->manager->createSequence($sequence_name$start);
  693.                     }
  694.                     if (MDB2::isError($result)) {
  695.                         return $result;
  696.                     }
  697.                 else {
  698.                     return MDB2_OK;
  699.                 }
  700.             }
  701.             if (MDB2::isError($result)) {
  702.                 $this->db->debug('Create sequence error: '.$sequence_name);
  703.                 return $result;
  704.             }
  705.         }
  706.         return MDB2_OK;
  707.     }
  708.  
  709.     // }}}
  710.     // {{{ dropSequence()
  711.  
  712.     /**
  713.      * drop a table
  714.      *
  715.      * @param string $sequence_name    name of the sequence to be dropped
  716.      * @return mixed MDB2_OK on success, or a MDB2 error object
  717.      * @access public
  718.      */
  719.     function dropSequence($sequence_name)
  720.     {
  721.         if (!$this->db->supports('sequences')) {
  722.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  723.                 'sequences are not supported');
  724.         }
  725.         $this->db->debug('Dropping sequence: '.$sequence_name);
  726.         if (!isset($sequence_name|| $sequence_name == ''{
  727.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  728.                 'no valid sequence name specified');
  729.         }
  730.         return $this->db->manager->dropSequence($sequence_name);
  731.     }
  732.  
  733.     // }}}
  734.     // {{{ createDatabase()
  735.  
  736.     /**
  737.      * Create a database space within which may be created database objects
  738.      * like tables, indexes and sequences. The implementation of this function
  739.      * is highly DBMS specific and may require special permissions to run
  740.      * successfully. Consult the documentation or the DBMS drivers that you
  741.      * use to be aware of eventual configuration requirements.
  742.      *
  743.      * @return mixed MDB2_OK on success, or a MDB2 error object
  744.      * @access public
  745.      */
  746.     function createDatabase()
  747.     {
  748.         if (!isset($this->database_definition['name']|| !$this->database_definition['name']{
  749.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  750.                 'no valid database name specified');
  751.         }
  752.         $create (isset($this->database_definition['create']&& $this->database_definition['create']);
  753.         $overwrite (isset($this->database_definition['overwrite']&& $this->database_definition['overwrite']);
  754.         if ($create{
  755.             $this->db->debug('Create database: '.$this->database_definition['name']);
  756.             $this->expectError(MDB2_ERROR_ALREADY_EXISTS);
  757.             $result $this->db->manager->createDatabase($this->database_definition['name']);
  758.             $this->popExpect();
  759.             if (MDB2::isError($result)) {
  760.                 if ($result->getCode(=== MDB2_ERROR_ALREADY_EXISTS{
  761.                     $this->warnings['Database already exists: '.$this->database_definition['name'];
  762.                     if ($overwrite{
  763.                         $this->db->debug('Overwritting Database');
  764.                         $result $this->db->manager->dropDatabase($this->database_definition['name']);
  765.                         if (!MDB2::isError($result)) {
  766.                             $result $this->db->manager->createDatabase($this->database_definition['name']);
  767.                         }
  768.                         if (MDB2::isError($result)) {
  769.                             return $result;
  770.                         }
  771.                     else {
  772.                         $result MDB2_OK;
  773.                     }
  774.                 }
  775.                 if (MDB2::isError($result)) {
  776.                     $this->db->debug('Create database error.');
  777.                     return $result;
  778.                 }
  779.             }
  780.         }
  781.         $previous_database_name $this->db->setDatabase($this->database_definition['name']);
  782.         if (($support_transactions $this->db->supports('transactions'))
  783.             && MDB2::isError($result $this->db->beginTransaction())
  784.         {
  785.             return $result;
  786.         }
  787.  
  788.         $created_objects = 0;
  789.         if (isset($this->database_definition['tables'])
  790.             && is_array($this->database_definition['tables'])
  791.         {
  792.             foreach ($this->database_definition['tables'as $table_name => $table{
  793.                 $result $this->createTable($table_name$table$overwrite);
  794.                 if (MDB2::isError($result)) {
  795.                     break;
  796.                 }
  797.                 $created_objects++;
  798.             }
  799.         }
  800.         if (!MDB2::isError($result)
  801.             && isset($this->database_definition['sequences'])
  802.             && is_array($this->database_definition['sequences'])
  803.         {
  804.             foreach ($this->database_definition['sequences'as $sequence_name => $sequence{
  805.                 $result $this->createSequence($sequence_name$sequencefalse$overwrite);
  806.  
  807.                 if (MDB2::isError($result)) {
  808.                     break;
  809.                 }
  810.                 $created_objects++;
  811.             }
  812.         }
  813.  
  814.         if (MDB2::isError($result)) {
  815.             if ($created_objects{
  816.                 if ($support_transactions{
  817.                     $res $this->db->rollback();
  818.                     if (MDB2::isError($res))
  819.                         $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  820.                             'Could not rollback the partially created database alterations ('.
  821.                             $result->getMessage().' ('.$result->getUserinfo().'))');
  822.                 else {
  823.                     $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  824.                         'the database was only partially created ('.
  825.                         $result->getMessage().' ('.$result->getUserinfo().'))');
  826.                 }
  827.             }
  828.         else {
  829.             if ($support_transactions{
  830.                 $res $this->db->commit();
  831.                 if (MDB2::isError($res))
  832.                     $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  833.                         'Could not end transaction after successfully created the database ('.
  834.                         $res->getMessage().' ('.$res->getUserinfo().'))');
  835.             }
  836.         }
  837.  
  838.         $this->db->setDatabase($previous_database_name);
  839.  
  840.         if (MDB2::isError($result&& $create
  841.             && MDB2::isError($result2 $this->db->manager->dropDatabase($this->database_definition['name']))
  842.         {
  843.             return $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  844.                 'Could not drop the created database after unsuccessful creation attempt ('.
  845.                 $result2->getMessage().' ('.$result2->getUserinfo().'))');
  846.         }
  847.  
  848.         return $result;
  849.     }
  850.  
  851.     // }}}
  852.     // {{{ compareDefinitions()
  853.  
  854.     /**
  855.      * compare a previous definition with the currenlty parsed definition
  856.      *
  857.      * @param array multi dimensional array that contains the previous definition
  858.      * @param array multi dimensional array that contains the current definition
  859.      * @return mixed array of changes on success, or a MDB2 error object
  860.      * @access public
  861.      */
  862.     function compareDefinitions($previous_definition$current_definition = null)
  863.     {
  864.         $current_definition $current_definition $current_definition $this->database_definition;
  865.         $changes = array();
  866.         if (isset($current_definition['tables']&& is_array($current_definition['tables'])) {
  867.             $defined_tables = array();
  868.             foreach ($current_definition['tables'as $table_name => $table{
  869.                 $previous_tables = array();
  870.                 if (isset($previous_definition['tables']&& is_array($previous_definition)) {
  871.                     $previous_tables $previous_definition['tables'];
  872.                 }
  873.                 $change $this->compareTableDefinitions($table_name$previous_tables$table$defined_tables);
  874.                 if (MDB2::isError($change)) {
  875.                     return $change;
  876.                 }
  877.                 if (count($change)) {
  878.                     $changes['tables'$change;
  879.                 }
  880.             }
  881.             if (isset($previous_definition['tables']&& is_array($previous_definition['tables'])) {
  882.                 foreach ($previous_definition['tables'as $table_name => $table{
  883.                     if (!isset($defined_tables[$table_name])) {
  884.                         $changes[$table_name]['remove'= true;
  885.                         $this->db->debug("Removed table '$table_name'");
  886.                     }
  887.                 }
  888.             }
  889.         }
  890.         if (isset($current_definition['sequences']&& is_array($current_definition['sequences'])) {
  891.            $defined_sequences = array();
  892.             foreach ($current_definition['sequences'as $sequence_name => $sequence{
  893.                 $previous_sequences = array();
  894.                 if (isset($previous_definition['sequences']&& is_array($previous_definition)) {
  895.                     $previous_sequences $previous_definition['sequences'];
  896.                 }
  897.                 $change $this->compareSequenceDefinitions($sequence_name$previous_sequences$sequence$defined_sequences);
  898.                 if (MDB2::isError($change)) {
  899.                     return $change;
  900.                 }
  901.                 if (count($change)) {
  902.                     $changes['sequences'$change;
  903.                 }
  904.             }
  905.             if (isset($previous_definition['sequences']&& is_array($previous_definition['sequences'])) {
  906.                 foreach ($previous_definition['sequences'as $sequence_name => $sequence{
  907.                     if (!isset($defined_sequences[$sequence_name])) {
  908.                         $changes[$sequence_name]['remove'= true;
  909.                         $this->db->debug("Removed sequence '$sequence_name'");
  910.                     }
  911.                 }
  912.             }
  913.         }
  914.         return $changes;
  915.     }
  916.  
  917.     // }}}
  918.     // {{{ compareTableFieldsDefinitions()
  919.  
  920.     /**
  921.      * compare a previous definition with the currenlty parsed definition
  922.      *
  923.      * @param string $table_name    name of the table
  924.      * @param array multi dimensional array that contains the previous definition
  925.      * @param array multi dimensional array that contains the current definition
  926.      * @return mixed array of changes on success, or a MDB2 error object
  927.      * @access public
  928.      */
  929.     function compareTableFieldsDefinitions($table_name$previous_definition$current_definition&$defined_fields)
  930.     {
  931.         $changes = array();
  932.         if (is_array($current_definition)) {
  933.             foreach ($current_definition as $field_name => $field{
  934.                 $was_field_name $field['was'];
  935.                 if (isset($previous_definition[$field_name])
  936.                     && isset($previous_definition[$field_name]['was'])
  937.                     && $previous_definition[$field_name]['was'== $was_field_name
  938.                 {
  939.                     $was_field_name $field_name;
  940.                 }
  941.                 if (isset($previous_definition[$was_field_name])) {
  942.                     if ($was_field_name != $field_name{
  943.                         $declaration $this->db->getDeclaration($field['type']$field_name$field);
  944.                         if (MDB2::isError($declaration)) {
  945.                             return $declaration;
  946.                         }
  947.                         $changes['renamed_fields'][$was_field_name= array(
  948.                             'name' => $field_name,
  949.                             'declaration' => $declaration,
  950.                         );
  951.                         $this->db->debug("Renamed field '$was_field_name' to '$field_name' in table '$table_name'");
  952.                     }
  953.                     if (isset($defined_fields[$was_field_name])) {
  954.                         return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  955.                             'the field "'.$was_field_name.
  956.                             '" was specified as base of more than one field of table');
  957.                     }
  958.                     $defined_fields[$was_field_name= true;
  959.                     $change = array();
  960.                     if ($field['type'== $previous_definition[$was_field_name]['type']{
  961.                         switch ($field['type']{
  962.                         case 'integer':
  963.                             $previous_unsigned = isset($previous_definition[$was_field_name]['unsigned']);
  964.                             $unsigned = isset($field['unsigned']);
  965.                             if ($previous_unsigned != $unsigned{
  966.                                 $change['unsigned'$unsigned;
  967.                                 $this->db->debug("Changed field '$field_name' type from '".($previous_unsigned 'unsigned ' '').$previous_definition[$was_field_name]['type']."' to '".($unsigned 'unsigned ' '').$field['type']."' in table '$table_name'");
  968.                             }
  969.                             break;
  970.                         case 'text':
  971.                         case 'clob':
  972.                         case 'blob':
  973.                             $previous_length (isset($previous_definition[$was_field_name]['length']$previous_definition[$was_field_name]['length': 0);
  974.                             $length (isset($field['length']$field['length': 0);
  975.                             if ($previous_length != $length{
  976.                                 $change['length'$length;
  977.                                 $this->db->debug("Changed field '$field_name' length from '".$previous_definition[$was_field_name]['type'].($previous_length == 0 ? ' no length' : "($previous_length)")."' to '".$field['type'].($length == 0 ? ' no length' : "($length)")."' in table '$table_name'");
  978.                             }
  979.                             break;
  980.                         case 'date':
  981.                         case 'timestamp':
  982.                         case 'time':
  983.                         case 'boolean':
  984.                         case 'float':
  985.                         case 'decimal':
  986.                             break;
  987.                         default:
  988.                             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  989.                                 'type "'.$field['type'].'" is not yet supported');
  990.                         }
  991.  
  992.                         $previous_notnull = isset($previous_definition[$was_field_name]['notnull']);
  993.                         $notnull = isset($field['notnull']);
  994.                         if ($previous_notnull != $notnull{
  995.                             $change['changed_not_null'= true;
  996.                             if ($notnull{
  997.                                 $change['notnull'= isset($field['notnull']);
  998.                             }
  999.                             $this->db->debug("Changed field '$field_name' notnull from $previous_notnull to $notnull in table '$table_name'");
  1000.                         }
  1001.  
  1002.                         $previous_default = isset($previous_definition[$was_field_name]['default']);
  1003.                         $default = isset($field['default']);
  1004.                         if ($previous_default != $default{
  1005.                             $change['changed_default'= true;
  1006.                             if ($default{
  1007.                                 $change['default'$field['default'];
  1008.                             }
  1009.                             $this->db->debug("Changed field '$field_name' default from ".
  1010.                                 ($previous_default "'".$previous_definition[$was_field_name]['default']."'" 'NULL').' TO '.($default "'".$field['default']."'" 'NULL')." IN TABLE '$table_name'");
  1011.                         else {
  1012.                             if ($default && $previous_definition[$was_field_name]['default']!= $field['default']{
  1013.                                 $change['changed_default'= true;
  1014.                                 $change['default'$field['default'];
  1015.                                 $this->db->debug("Changed field '$field_name' default from '".$previous_definition[$was_field_name]['default']."' to '".$field['default']."' in table '$table_name'");
  1016.                             }
  1017.                         }
  1018.                     else {
  1019.                         $change['type'$field['type'];
  1020.                         $this->db->debug("Changed field '$field_name' type from '".$previous_definition[$was_field_name]['type']."' to '".$field['type']."' in table '$table_name'");
  1021.                     }
  1022.                     if (count($change)) {
  1023.                         $declaration $this->db->getDeclaration($field['type']$field_name$field);
  1024.                         if (MDB2::isError($declaration)) {
  1025.                             return $declaration;
  1026.                         }
  1027.                         $change['declaration'$declaration;
  1028.                         $change['definition'$field;
  1029.                         $changes['changed_fields'][$field_name$change;
  1030.                     }
  1031.                 else {
  1032.                     if ($field_name != $was_field_name{
  1033.                         return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1034.                             'it was specified a previous field name ("'.
  1035.                             $was_field_name.'") for field "'.$field_name.'" of table "'.
  1036.                             $table_name.'" that does not exist');
  1037.                     }
  1038.                     $declaration $this->db->getDeclaration($field['type']$field_name$field);
  1039.                     if (MDB2::isError($declaration)) {
  1040.                         return $declaration;
  1041.                     }
  1042.                     $change['declaration'$declaration;
  1043.                     $changes['added_fields'][$field_name$change;
  1044.                     $this->db->debug("Added field '$field_name' to table '$table_name'");
  1045.                 }
  1046.             }
  1047.         }
  1048.         if (isset($previous_definition&& is_array($previous_definition)) {
  1049.             foreach ($previous_definition as $field_previous_name => $field_previous{
  1050.                 if (!isset($defined_fields[$field_previous_name])) {
  1051.                     $changes['removed_fields'][$field_previous_name= true;
  1052.                     $this->db->debug("Removed field '$field_name' from table '$table_name'");
  1053.                 }
  1054.             }
  1055.         }
  1056.         return $changes;
  1057.     }
  1058.  
  1059.     // }}}
  1060.     // {{{ compareTableIndexesDefinitions()
  1061.  
  1062.     /**
  1063.      * compare a previous definition with the currenlty parsed definition
  1064.      *
  1065.      * @param string $table_name    name of the table
  1066.      * @param array multi dimensional array that contains the previous definition
  1067.      * @param array multi dimensional array that contains the current definition
  1068.      * @return mixed array of changes on success, or a MDB2 error object
  1069.      * @access public
  1070.      */
  1071.     function compareTableIndexesDefinitions($table_name$previous_definition$current_definition&$defined_indexes)
  1072.     {
  1073.         $changes = array();
  1074.         if (is_array($current_definition)) {
  1075.             foreach ($current_definition as $index_name => $index{
  1076.                 $was_index_name $index['was'];
  1077.                 if (isset($previous_definition[$index_name])
  1078.                     && isset($previous_definition[$index_name]['was'])
  1079.                     && $previous_definition[$index_name]['was'== $was_index_name
  1080.                 {
  1081.                     $was_index_name $index_name;
  1082.                 }
  1083.                 if (isset($previous_definition[$was_index_name])) {
  1084.                     $change = array();
  1085.  
  1086.                     if ($was_index_name != $index_name{
  1087.                         $change['name'$was_index_name;
  1088.                         $this->db->debug("Changed index '$was_index_name' name to '$index_name' in table '$table_name'");
  1089.                     }
  1090.                     if (isset($defined_indexes[$was_index_name])) {
  1091.                         return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1092.                             'the index "'.$was_index_name.'" was specified as base of'.
  1093.                             ' more than one index of table "'.$table_name.'"');
  1094.                     }
  1095.                     $defined_indexes[$was_index_name= true;
  1096.  
  1097.                     $previous_unique = isset($previous_definition[$was_index_name]['unique']);
  1098.                     $unique = isset($index['unique']);
  1099.                     if ($previous_unique != $unique{
  1100.                         $change['changed_unique'= true;
  1101.                         if ($unique{
  1102.                             $change['unique'$unique;
  1103.                         }
  1104.                         $this->db->debug("Changed index '$index_name' unique from $previous_unique to $unique in table '$table_name'");
  1105.                     }
  1106.                     $defined_fields = array();
  1107.                     $previous_fields $previous_definition[$was_index_name]['fields'];
  1108.                     if (isset($index['fields']&& is_array($index['fields'])) {
  1109.                         foreach ($index['fields'as $field_name => $field{
  1110.                             if (isset($previous_fields[$field_name])) {
  1111.                                 $defined_fields[$field_name= true;
  1112.                                 $sorting (isset($field['sorting']$field['sorting''');
  1113.                                 $previous_sorting (isset($previous_fields[$field_name]['sorting']$previous_fields[$field_name]['sorting''');
  1114.                                 if ($sorting != $previous_sorting{
  1115.                                     $this->db->debug("Changed index field '$field_name' sorting default from '$previous_sorting' to '$sorting' in table '$table_name'");
  1116.                                     $change['changed_fields'= true;
  1117.                                 }
  1118.                             else {
  1119.                                 $change['changed_fields'= true;
  1120.                                 $this->db->debug("Added field '$field_name' to index '$index_name' of table '$table_name'");
  1121.                             }
  1122.                         }
  1123.                     }
  1124.                     if (isset($previous_fields&& is_array($previous_fields)) {
  1125.                         foreach ($previous_fields as $field_name => $field{
  1126.                             if (!isset($defined_fields[$field_name])) {
  1127.                                 $change['changed_fields'= true;
  1128.                                 $this->db->debug("Removed field '$field_name' from index '$index_name' of table '$table_name'");
  1129.                             }
  1130.                         }
  1131.                     }
  1132.                     if (count($change)) {
  1133.                         $changes['changed_indexes'][$index_name$change;
  1134.                     }
  1135.                 else {
  1136.                     if ($index_name != $was_index_name{
  1137.                         return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1138.                             'it was specified a previous index name ("'.$was_index_name.
  1139.                             ') for index "'.$index_name.'" of table "'.$table_name.'" that does not exist');
  1140.                     }
  1141.                     $changes['added_indexes'][$index_name$current_definition[$index_name];
  1142.                     $this->db->debug("Added index '$index_name' to table '$table_name'");
  1143.                 }
  1144.             }
  1145.         }
  1146.         foreach ($previous_definition as $index_previous_name => $index_previous{
  1147.             if (!isset($defined_indexes[$index_previous_name])) {
  1148.                 $changes['removed_indexes'][$index_previous_name= true;
  1149.                 $this->db->debug("Removed index '$index_name' from table '$table_name'");
  1150.             }
  1151.         }
  1152.         return $changes;
  1153.     }
  1154.  
  1155.     // }}}
  1156.     // {{{ compareTableDefinitions()
  1157.  
  1158.     /**
  1159.      * compare a previous definition with the currenlty parsed definition
  1160.      *
  1161.      * @param string $table_name    name of the table
  1162.      * @param array multi dimensional array that contains the previous definition
  1163.      * @param array multi dimensional array that contains the current definition
  1164.      * @return mixed array of changes on success, or a MDB2 error object
  1165.      * @access public
  1166.      */
  1167.     function compareTableDefinitions($table_name$previous_definition$current_definition&$defined_tables)
  1168.     {
  1169.         $changes = array();
  1170.  
  1171.         if (is_array($current_definition)) {
  1172.             $was_table_name $table_name;
  1173.             if (isset($current_definition['was'])) {
  1174.                 $was_table_name $current_definition['was'];
  1175.             }
  1176.             if (isset($previous_definition[$was_table_name])) {
  1177.                 $changes[$was_table_name= array();
  1178.                 if ($was_table_name != $table_name{
  1179.                     $changes[$was_table_name]+= array('name' => $table_name);
  1180.                     $this->db->debug("Renamed table '$was_table_name' to '$table_name'");
  1181.                 }
  1182.                 if (isset($defined_tables[$was_table_name])) {
  1183.                     return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1184.                         'the table "'.$was_table_name.
  1185.                         '" was specified as base of more than of table of the database');
  1186.                 }
  1187.                 $defined_tables[$was_table_name= true;
  1188.                 if (isset($current_definition['fields']&& is_array($current_definition['fields'])) {
  1189.                     $previous_fields = array();
  1190.                     if (isset($previous_definition[$was_table_name]['fields'])
  1191.                         && is_array($previous_definition[$was_table_name]['fields'])
  1192.                     {
  1193.                         $previous_fields $previous_definition[$was_table_name]['fields'];
  1194.                     }
  1195.                     $defined_fields = array();
  1196.                     $change $this->compareTableFieldsDefinitions($table_name$previous_fields$current_definition['fields']$defined_fields);
  1197.                     if (MDB2::isError($change)) {
  1198.                         return $change;
  1199.                     }
  1200.                     if (count($change)) {
  1201.                         $changes[$was_table_name]+= $change;
  1202.                     }
  1203.                 }
  1204.                 if (isset($current_definition['indexes']&& is_array($current_definition['indexes'])) {
  1205.                     $previous_indexes = array();
  1206.                     if (isset($previous_definition[$was_table_name]['indexes'])
  1207.                         && is_array($previous_definition[$was_table_name]['indexes'])
  1208.                     {
  1209.                         $previous_indexes $previous_definition[$was_table_name]['indexes'];
  1210.                     }
  1211.                     $defined_indexes = array();
  1212.                     $change $this->compareTableIndexesDefinitions($table_name$previous_indexes$current_definition['indexes']$defined_indexes);
  1213.                     if (MDB2::isError($change)) {
  1214.                         return $change;
  1215.                     }
  1216.                     if (count($change)) {
  1217.                         $changes[$was_table_name]+= $change;
  1218.                     }
  1219.                 }
  1220.                 if (empty($changes[$was_table_name])) {
  1221.                     unset($changes[$was_table_name]);
  1222.                 }
  1223.             else {
  1224.                 if ($table_name != $was_table_name{
  1225.                     return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1226.                         'it was specified a previous table name ("'.
  1227.                         $was_table_name.'") for table "'.$table_name.
  1228.                         '" that does not exist');
  1229.                 }
  1230.                 $changes[$table_name]['add'= true;
  1231.                 $this->db->debug("Added table '$table_name'");
  1232.             }
  1233.         }
  1234.  
  1235.         return $changes;
  1236.     }
  1237.  
  1238.     // }}}
  1239.     // {{{ compareSequenceDefinitions()
  1240.  
  1241.     /**
  1242.      * compare a previous definition with the currenlty parsed definition
  1243.      *
  1244.      * @param array multi dimensional array that contains the previous definition
  1245.      * @param array multi dimensional array that contains the current definition
  1246.      * @return mixed array of changes on success, or a MDB2 error object
  1247.      * @access public
  1248.      */
  1249.     function compareSequenceDefinitions($sequence_name$previous_definition$current_definition&$defined_sequences)
  1250.     {
  1251.         $changes = array();
  1252.         if (is_array($current_definition)) {
  1253.             $was_sequence_name $sequence_name;
  1254.             if (isset($previous_definition[$sequence_name])
  1255.                 && isset($previous_definition[$sequence_name]['was'])
  1256.                 && $previous_definition[$sequence_name]['was'== $was_sequence_name
  1257.             {
  1258.                 $was_sequence_name $sequence_name;
  1259.             elseif (isset($current_definition['was'])) {
  1260.                 $was_sequence_name $current_definition['was'];
  1261.             }
  1262.             if (isset($previous_definition[$was_sequence_name])) {
  1263.                 if ($was_sequence_name != $sequence_name{
  1264.                     $changes[$was_sequence_name]['name'$sequence_name;
  1265.                     $this->db->debug("Renamed sequence '$was_sequence_name' to '$sequence_name'");
  1266.                 }
  1267.                 if (isset($defined_sequences[$was_sequence_name])) {
  1268.                     return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1269.                         'the sequence "'.$was_sequence_name.'" was specified as base'.
  1270.                         ' of more than of sequence of the database');
  1271.                 }
  1272.                 $defined_sequences[$was_sequence_name= true;
  1273.                 $change = array();
  1274.                 if (isset($current_definition['start'])
  1275.                     && isset($previous_definition[$was_sequence_name]['start'])
  1276.                     && $current_definition['start'!= $previous_definition[$was_sequence_name]['start']
  1277.                 {
  1278.                     $change['start'$previous_definition[$sequence_name]['start'];
  1279.                     $this->db->debug("Changed sequence '$sequence_name' start from '".$previous_definition[$was_sequence_name]['start']."' to '".$this->database_definition['sequences'][$sequence_name]['start']."'");
  1280.                 }
  1281.                 if (isset($current_definition['on']['table'])
  1282.                     && isset($previous_definition[$was_sequence_name]['on']['table'])
  1283.                     && $current_definition['on']['table'!= $previous_definition[$was_sequence_name]['on']['table']
  1284.                     && isset($current_definition['on']['field'])
  1285.                     && isset($previous_definition[$was_sequence_name]['on']['field'])
  1286.                     && $current_definition['on']['field'!= $previous_definition[$was_sequence_name]['on']['field']
  1287.                 {
  1288.                     $change['on'$current_definition['on'];
  1289.                     $this->db->debug("Changed sequence '$sequence_name' on table field from '".$previous_definition[$was_sequence_name]['on']['table'].'.'.$previous_definition[$was_sequence_name]['on']['field']."' to '".$this->database_definition['sequences'][$sequence_name]['on']['table'].'.'.$this->database_definition['sequences'][$sequence_name]['on']['field']."'");
  1290.                 }
  1291.                 if (count($change)) {
  1292.                     $changes[$was_sequence_name]['change'][$sequence_name$change;
  1293.                 }
  1294.             else {
  1295.                 if ($sequence_name != $was_sequence_name{
  1296.                     return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  1297.                         'it was specified a previous sequence name ("'.$was_sequence_name.
  1298.                         '") for sequence "'.$sequence_name.'" that does not exist');
  1299.                 }
  1300.                 $changes[$sequence_name]['add'= true;
  1301.                 $this->db->debug("Added sequence '$sequence_name'");
  1302.             }
  1303.         }
  1304.         return $changes;
  1305.     }
  1306.     // }}}
  1307.     // {{{ verifyAlterDatabase()
  1308.  
  1309.     /**
  1310.      * verify that the changes requested are supported
  1311.      *
  1312.      * @param array $changes an associative array that contains the definition of
  1313.      *  the changes that are meant to be applied to the database structure.
  1314.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1315.      * @access public
  1316.      */
  1317.     function verifyAlterDatabase($changes)
  1318.     {
  1319.         if (isset($changes['tables']&& is_array($changes['tables'])) {
  1320.             foreach ($changes['tables'as $table_name => $table{
  1321.                 if (isset($table['add']|| isset($table['remove'])) {
  1322.                     continue;
  1323.                 }
  1324.                 if (isset($table['indexes']&& is_array($table['indexes'])) {
  1325.                     if (!$this->db->supports('indexes')) {
  1326.                         return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1327.                             'indexes are not supported');
  1328.                     }
  1329.                     foreach ($table['indexes'as $index{
  1330.                         $table_changes count($index);
  1331.                         if (isset($index['add'])) {
  1332.                             $table_changes--;
  1333.                         }
  1334.                         if (isset($index['remove'])) {
  1335.                             $table_changes--;
  1336.                         }
  1337.                         if (isset($index['change'])) {
  1338.                             $table_changes--;
  1339.                         }
  1340.                         if ($table_changes{
  1341.                             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1342.                                 'index alteration not yet supported');
  1343.                         }
  1344.                     }
  1345.                 }
  1346.                 $result $this->db->manager->alterTable($table_name$tabletrue);
  1347.                 if (MDB2::isError($result)) {
  1348.                     return $result;
  1349.                 }
  1350.             }
  1351.         }
  1352.         if (isset($changes['sequences']&& is_array($changes['sequences'])) {
  1353.             if (!$this->db->supports('sequences')) {
  1354.                 return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1355.                     'sequences are not supported');
  1356.             }
  1357.             foreach ($changes['sequences'as $sequence{
  1358.                 if (isset($sequence['add']|| isset($sequence['remove']|| isset($sequence['change'])) {
  1359.                     continue;
  1360.                 }
  1361.                 return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  1362.                     'some sequences changes are not yet supported');
  1363.             }
  1364.         }
  1365.         return MDB2_OK;
  1366.     }
  1367.  
  1368.     // }}}
  1369.     // {{{ alterDatabaseSequences()
  1370.  
  1371.     /**
  1372.      * Execute the necessary actions to implement the requested changes
  1373.      * in the indexes inside a database structure.
  1374.      *
  1375.      * @param string name of the table
  1376.      * @param array $changes an associative array that contains the definition of
  1377.      *  the changes that are meant to be applied to the database structure.
  1378.      * @param array multi dimensional array that contains the current definition
  1379.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1380.      * @access public
  1381.      */
  1382.     function alterDatabaseIndexes($table_name$changes$current_definition)
  1383.     {
  1384.         $alterations = 0;
  1385.         if (is_array($changes)) {
  1386.             if (isset($changes['change'])) {
  1387.                 foreach ($changes['change'as $index_name => $index{
  1388.                     $result $this->db->manager->createIndex($table_name$index_name,
  1389.                         $current_definition[$index_name]);
  1390.                     if (MDB2::isError($result)) {
  1391.                         return $result;
  1392.                     }
  1393.                     $alterations++;
  1394.                 }
  1395.             }
  1396.             if (isset($changes['add'])) {
  1397.                 foreach ($changes['add'as $index_name => $index{
  1398.                     $result $this->db->manager->createIndex($table_name$index_name,
  1399.                         $current_definition[$index_name]);
  1400.                     if (MDB2::isError($result)) {
  1401.                         return $result;
  1402.                     }
  1403.                     $alterations++;
  1404.                 }
  1405.             }
  1406.         }
  1407.         return $alterations;
  1408.     }
  1409.  
  1410.     // }}}
  1411.     // {{{ alterDatabaseTables()
  1412.  
  1413.     /**
  1414.      * Execute the necessary actions to implement the requested changes
  1415.      * in the tables inside a database structure.
  1416.      *
  1417.      * @param array $changes an associative array that contains the definition of
  1418.      *  the changes that are meant to be applied to the database structure.
  1419.      * @param array multi dimensional array that contains the current definition
  1420.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1421.      * @access public
  1422.      */
  1423.     function alterDatabaseTables($changes$current_definition)
  1424.     {
  1425.         $alterations = 0;
  1426.         if (is_array($changes)) {
  1427.             foreach ($changes as $table_name => $table{
  1428.                 if (isset($table['remove'])) {
  1429.                     $result $this->dropTable($table_name);
  1430.                     if (MDB2::isError($result)) {
  1431.                         return $result;
  1432.                     }
  1433.                     $alterations++;
  1434.                 elseif (isset($table['add'])) {
  1435.                     $result $this->createTable($table_name$current_definition[$table_name]);
  1436.                     if (MDB2::isError($result)) {
  1437.                         return $result;
  1438.                     }
  1439.                     $alterations++;
  1440.                 else {
  1441.                     $result $this->db->manager->alterTable($table_name$changes[$table_name]false);
  1442.                     if (MDB2::isError($result)) {
  1443.                         return $result;
  1444.                     }
  1445.                     $alterations++;
  1446.                 }
  1447.                 if (isset($table['indexes']&& isset($current_definition[$table_name]['indexes'])) {
  1448.                     $result $this->alterDatabaseTables($table_name$table['indexes']$current_definition[$table_name]['indexes']);
  1449.                     if (MDB2::isError($result)) {
  1450.                         return $result;
  1451.                     }
  1452.                     $alterations += $result;
  1453.                 }
  1454.             }
  1455.         }
  1456.         return $alterations;
  1457.     }
  1458.  
  1459.     // }}}
  1460.     // {{{ alterDatabaseSequences()
  1461.  
  1462.     /**
  1463.      * Execute the necessary actions to implement the requested changes
  1464.      * in the sequences inside a database structure.
  1465.      *
  1466.      * @param array $changes an associative array that contains the definition of
  1467.      *  the changes that are meant to be applied to the database structure.
  1468.      * @param array multi dimensional array that contains the current definition
  1469.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1470.      * @access public
  1471.      */
  1472.     function alterDatabaseSequences($changes$current_definition)
  1473.     {
  1474.         $alterations = 0;
  1475.         if (is_array($changes)) {
  1476.             foreach ($changes as $sequence_name => $sequence{
  1477.                 if (isset($sequence['add'])) {
  1478.                     $result $this->createSequence($sequence_name,
  1479.                         $current_definition[$sequence_name]);
  1480.                     if (MDB2::isError($result)) {
  1481.                         return $result;
  1482.                     }
  1483.                     $alterations++;
  1484.                 elseif (isset($sequence['remove'])) {
  1485.                     $result $this->dropSequence($sequence_name);
  1486.                     if (MDB2::isError($result)) {
  1487.                         return $result;
  1488.                     }
  1489.                     $alterations++;
  1490.                 elseif (isset($sequence['change'])) {
  1491.                     $result $this->dropSequence($current_definition[$sequence_name]['was']);
  1492.                     if (MDB2::isError($result)) {
  1493.                         return $result;
  1494.                     }
  1495.                     $result $this->createSequence($sequence_name$current_definition[$sequence_name]);
  1496.                     if (MDB2::isError($result)) {
  1497.                         return $result;
  1498.                     }
  1499.                     $alterations++;
  1500.                 }
  1501.             }
  1502.         }
  1503.         return $alterations;
  1504.     }
  1505.  
  1506.     // }}}
  1507.     // {{{ alterDatabase()
  1508.  
  1509.     /**
  1510.      * Execute the necessary actions to implement the requested changes
  1511.      * in a database structure.
  1512.      *
  1513.      * @param array $changes an associative array that contains the definition of
  1514.      *  the changes that are meant to be applied to the database structure.
  1515.      * @param array multi dimensional array that contains the current definition
  1516.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1517.      * @access public
  1518.      */
  1519.     function alterDatabase($changes$current_definition = null)
  1520.     {
  1521.         $current_definition $current_definition $current_definition $this->database_definition;
  1522.  
  1523.         $result $this->verifyAlterDatabase($changes);
  1524.  
  1525.         if (isset($current_definition['name'])) {
  1526.             $previous_database_name $this->db->setDatabase($current_definition['name']);
  1527.         else {
  1528.             $previous_database_name $this->db->getDatabase();
  1529.         }
  1530.         if (($support_transactions $this->db->supports('transactions'))
  1531.             && MDB2::isError($result $this->db->beginTransaction())
  1532.         {
  1533.             return $result;
  1534.         }
  1535.  
  1536.         $alterations = 0;
  1537.  
  1538.         if (isset($changes['tables']&& isset($current_definition['tables'])) {
  1539.             $result $this->alterDatabaseTables($changes['tables']$current_definition['tables']);
  1540.             if (is_numeric($result)) {
  1541.                 $alterations += $result;
  1542.             }
  1543.         }
  1544.         if (!MDB2::isError($result&& isset($changes['sequences']&& isset($current_definition['sequences'])) {
  1545.             $result $this->alterDatabaseSequences($changes['sequences']$current_definition['sequences']);
  1546.             if (is_numeric($result)) {
  1547.                 $alterations += $result;
  1548.             }
  1549.         }
  1550.  
  1551.         if (MDB2::isError($result)) {
  1552.             if ($support_transactions{
  1553.                 $res $this->db->rollback();
  1554.                 if (MDB2::isError($res))
  1555.                     $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  1556.                         'Could not rollback the partially created database alterations ('.
  1557.                         $result->getMessage().' ('.$result->getUserinfo().'))');
  1558.             else {
  1559.                 $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  1560.                     'the requested database alterations were only partially implemented ('.
  1561.                     $result->getMessage().' ('.$result->getUserinfo().'))');
  1562.             }
  1563.         }
  1564.         if ($support_transactions{
  1565.             $result $this->db->commit();
  1566.             if (MDB2::isError($result)) {
  1567.                 $result $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  1568.                     'Could not end transaction after successfully implemented the requested database alterations ('.
  1569.                     $result->getMessage().' ('.$result->getUserinfo().'))');
  1570.             }
  1571.         }
  1572.         $this->db->setDatabase($previous_database_name);
  1573.         return $result;
  1574.     }
  1575.  
  1576.     // }}}
  1577.     // {{{ dumpDatabaseChanges()
  1578.  
  1579.     /**
  1580.      * Dump the changes between two database definitions.
  1581.      *
  1582.      * @param array $changes an associative array that specifies the list
  1583.      *  of database definitions changes as returned by the _compareDefinitions
  1584.      *  manager class function.
  1585.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1586.      * @access public
  1587.      */
  1588.     function dumpDatabaseChanges($changes)
  1589.     {
  1590.         if (isset($changes['tables'])) {
  1591.             foreach ($changes['tables'as $table_name => $table{
  1592.                 $this->db->debug("$table_name:");
  1593.                 if (isset($table['add'])) {
  1594.                     $this->db->debug("\tAdded table '$table_name'");
  1595.                 elseif (isset($table['remove'])) {
  1596.                     $this->db->debug("\tRemoved table '$table_name'");
  1597.                 else {
  1598.                     if (isset($table['name'])) {
  1599.                         $this->db->debug("\tRenamed table '$table_name' to '".
  1600.                             $table['name']."'");
  1601.                     }
  1602.                     if (isset($table['added_fields'])) {
  1603.                         foreach ($table['added_fields'as $field_name => $field{
  1604.                             $this->db->debug("\tAdded field '".$field_name."'");
  1605.                         }
  1606.                     }
  1607.                     if (isset($table['removed_fields'])) {
  1608.                         foreach ($table['removed_fields'as $field_name => $field{
  1609.                             $this->db->debug("\tRemoved field '".$field_name."'");
  1610.                         }
  1611.                     }
  1612.                     if (isset($table['renamed_fields'])) {
  1613.                         foreach ($table['renamed_fields'as $field_name => $field{
  1614.                             $this->db->debug("\tRenamed field '".$field_name."' to '".
  1615.                                 $field['name']."'");
  1616.                         }
  1617.                     }
  1618.                     if (isset($table['changed_fields'])) {
  1619.                         foreach ($table['changed_fields'as $field_name => $field{
  1620.                             if (isset($field['type'])) {
  1621.                                 $this->db->debug(
  1622.                                     "\tChanged field '$field_name' type to '".
  1623.                                         $field['type']."'");
  1624.                             }
  1625.                             if (isset($field['unsigned'])) {
  1626.                                 $this->db->debug(
  1627.                                     "\tChanged field '$field_name' type to '".
  1628.                                     ($field['unsigned''' 'not ')."unsigned'");
  1629.                             }
  1630.                             if (isset($field['length'])) {
  1631.                                 $this->db->debug(
  1632.                                     "\tChanged field '$field_name' length to '".
  1633.                                     ($field['length'== 0 ? 'no length' $field['length'])."'");
  1634.                             }
  1635.                             if (isset($field['changed_default'])) {
  1636.                                 $this->db->debug(
  1637.                                     "\tChanged field '$field_name' default to ".
  1638.                                     (isset($field['default']"'".$field['default']."'" 'NULL'));
  1639.                             }
  1640.                             if (isset($field['changed_not_null'])) {
  1641.                                 $this->db->debug(
  1642.                                    "\tChanged field '$field_name' notnull to ".(isset($field['notnull']"'1'" '0'));
  1643.                             }
  1644.                         }
  1645.                     }
  1646.                 }
  1647.             }
  1648.         }
  1649.         if (isset($changes['sequences'])) {
  1650.             foreach ($changes['sequences'as $sequence_name => $sequence{
  1651.                 $this->db->debug("$sequence_name:");
  1652.                 if (isset($sequence['add'])) {
  1653.                     $this->db->debug("\tAdded sequence '$sequence_name'");
  1654.                 elseif (isset($sequence['remove'])) {
  1655.                     $this->db->debug("\tRemoved sequence '$sequence_name'");
  1656.                 else {
  1657.                     if (isset($sequence['name'])) {
  1658.                         $this->db->debug(
  1659.                             "\tRenamed sequence '$sequence_name' to '".
  1660.                             $sequence['name']."'");
  1661.                     }
  1662.                     if (isset($sequence['change'])) {
  1663.                         foreach ($sequence['change'as $sequence_name => $sequence{
  1664.                             if (isset($sequence['start'])) {
  1665.                                 $this->db->debug(
  1666.                                     "\tChanged sequence '$sequence_name' start to '".
  1667.                                     $sequence['start']."'");
  1668.                             }
  1669.                         }
  1670.                     }
  1671.                 }
  1672.             }
  1673.         }
  1674.         if (isset($changes['indexes'])) {
  1675.             foreach ($changes['indexes'as $table_name => $table{
  1676.                 $this->db->debug("$table_name:");
  1677.                 if (isset($table['added_indexes'])) {
  1678.                     foreach ($table['added_indexes'as $index_name => $index{
  1679.                         $this->db->debug("\tAdded index '".$index_name.
  1680.                             "' of table '$table_name'");
  1681.                     }
  1682.                 }
  1683.                 if (isset($table['removed_indexes'])) {
  1684.                     foreach ($table['removed_indexes'as $index_name => $index{
  1685.                         $this->db->debug("\tRemoved index '".$index_name.
  1686.                             "' of table '$table_name'");
  1687.                     }
  1688.                 }
  1689.                 if (isset($table['changed_indexes'])) {
  1690.                     foreach ($table['changed_indexes'as $index_name => $index{
  1691.                         if (isset($index['name'])) {
  1692.                             $this->db->debug(
  1693.                                 "\tRenamed index '".$index_name."' to '".$index['name'].
  1694.                                 "' on table '$table_name'");
  1695.                         }
  1696.                         if (isset($index['changed_unique'])) {
  1697.                             $this->db->debug(
  1698.                                 "\tChanged index '".$index_name."' unique to '".
  1699.                                 isset($index['unique'])."' on table '$table_name'");
  1700.                         }
  1701.                         if (isset($index['changed_fields'])) {
  1702.                             $this->db->debug("\tChanged index '".$index_name.
  1703.                                 "' on table '$table_name'");
  1704.                         }
  1705.                     }
  1706.                 }
  1707.             }
  1708.         }
  1709.         return MDB2_OK;
  1710.     }
  1711.  
  1712.     // }}}
  1713.     // {{{ dumpDatabase()
  1714.  
  1715.     /**
  1716.      * Dump a previously parsed database structure in the Metabase schema
  1717.      * XML based format suitable for the Metabase parser. This function
  1718.      * may optionally dump the database definition with initialization
  1719.      * commands that specify the data that is currently present in the tables.
  1720.      *
  1721.      * @param array $arguments an associative array that takes pairs of tag
  1722.      *  names and values that define dump options.
  1723.      *                  array (
  1724.      *                      'definition'    =>    Boolean
  1725.      *                          true   :  dump currently parsed definition
  1726.      *                          default:  dump currently connected database
  1727.      *                      'output_mode'    =>    String
  1728.      *                          'file' :   dump into a file
  1729.      *                          default:   dump using a function
  1730.      *                      'output'        =>    String
  1731.      *                          depending on the 'Output_Mode'
  1732.      *                                   name of the file
  1733.      *                                   name of the function
  1734.      *                      'end_of_line'        =>    String
  1735.      *                          end of line delimiter that should be used
  1736.      *                          default: "\n"
  1737.      *                  );
  1738.      * @param integer $dump constant that determines what data to dump
  1739.      *                       MDB2_MANAGER_DUMP_ALL       : the entire db
  1740.      *                       MDB2_MANAGER_DUMP_STRUCTURE : only the structure of the db
  1741.      *                       MDB2_MANAGER_DUMP_CONTENT   : only the content of the db
  1742.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1743.      * @access public
  1744.      */
  1745.     function dumpDatabase($arguments$dump = MDB2_MANAGER_DUMP_ALL)
  1746.     {
  1747.         if (!isset($arguments['definition']|| !$arguments['definition']{
  1748.             if (!$this->db{
  1749.                 return $this->raiseError(MDB2_ERROR_NODBSELECTED,
  1750.                     nullnull'please connect to a RDBMS first');
  1751.             }
  1752.             $error $this->getDefinitionFromDatabase();
  1753.             if (MDB2::isError($error)) {
  1754.                 return $error;
  1755.             }
  1756.  
  1757.             // get initialization data
  1758.             if (isset($this->database_definition['tables']&& is_array($this->database_definition['tables'])) {
  1759.                 foreach ($this->database_definition['tables'as $table_name => $table{
  1760.                     if ($dump == MDB2_MANAGER_DUMP_ALL || $dump == MDB2_MANAGER_DUMP_CONTENT{
  1761.                         $types = array();
  1762.                         foreach ($table['fields'as $field{
  1763.                             $types[$field['type'];
  1764.                         }
  1765.                         $query 'SELECT '.implode(',',array_keys($table['fields']))." FROM $table_name";
  1766.                         $data $this->db->queryAll($query$typesMDB2_FETCHMODE_ASSOC);
  1767.                         if (MDB2::isError($data)) {
  1768.                             return $data;
  1769.                         }
  1770.                         $rows count($data);
  1771.                         if ($rows > 0{
  1772.                             $table['initialization'= array();
  1773.                             for ($row = 0; $row $rows$row++{
  1774.                                 if (!is_array($data[$row])) {
  1775.                                     break;
  1776.                                 }
  1777.                                 $instruction = array('type' => 'insert''fields' => $data[$row]);
  1778.                                 $this->database_definition['tables'][$table_name]['initialization'][$instruction;
  1779.                             }
  1780.                         }
  1781.                     }
  1782.                 }
  1783.             }
  1784.             $previous_database_name ($this->database_definition['name'!= ''$this->db->setDatabase($this->database_definition['name']'';
  1785.         }
  1786.  
  1787.         $writer =new MDB2_Tools_Manager_Writer();
  1788.         $return $writer->dumpDatabase($this->database_definition$arguments$dump);
  1789.  
  1790.         if (isset($previous_database_name&& $previous_database_name != ''{
  1791.             $this->db->setDatabase($previous_database_name);
  1792.         }
  1793.  
  1794.         return $return;
  1795.     }
  1796.  
  1797.     // }}}
  1798.     // {{{ updateDatabase()
  1799.  
  1800.     /**
  1801.      * Compare the correspondent files of two versions of a database schema
  1802.      * definition: the previously installed and the one that defines the schema
  1803.      * that is meant to update the database.
  1804.      * If the specified previous definition file does not exist, this function
  1805.      * will create the database from the definition specified in the current
  1806.      * schema file.
  1807.      * If both files exist, the function assumes that the database was previously
  1808.      * installed based on the previous schema file and will update it by just
  1809.      * applying the changes.
  1810.      * If this function succeeds, the contents of the current schema file are
  1811.      * copied to replace the previous schema file contents. Any subsequent schema
  1812.      * changes should only be done on the file specified by the $current_schema_file
  1813.      * to let this function make a consistent evaluation of the exact changes that
  1814.      * need to be applied.
  1815.      *
  1816.      * @param string $current_schema_file name of the updated database schema
  1817.      *  definition file.
  1818.      * @param string $previous_schema_file name the previously installed database
  1819.      *  schema definition file.
  1820.      * @param array $variables an associative array that is passed to the argument
  1821.      *  of the same name to the parseDatabaseDefinitionFile function. (there third
  1822.      *  param)
  1823.      * @return mixed MDB2_OK on success, or a MDB2 error object
  1824.      * @access public
  1825.      */
  1826.     function updateDatabase($current_schema_file$previous_schema_file = false$variables = array())
  1827.     {
  1828.         $database_definition $this->parseDatabaseDefinitionFile($current_schema_file,
  1829.             $variables$this->options['fail_on_invalid_names']);
  1830.         if (MDB2::isError($database_definition)) {
  1831.             return $database_definition;
  1832.         }
  1833.         $this->database_definition = $database_definition;
  1834.         $copy = false;
  1835.  
  1836.         if ($previous_schema_file && file_exists($previous_schema_file)) {
  1837.             $errorcodes = array(MDB2_ERROR_UNSUPPORTEDMDB2_ERROR_NOT_CAPABLE);
  1838.             $this->db->expectError($errorcodes);
  1839.             $databases $this->db->manager->listDatabases();
  1840.             $this->db->popExpect();
  1841.             if (MDB2::isError($databases&& !in_array($databases->getCode()$errorcodes)) {
  1842.                 return $databases;
  1843.             }
  1844.             if (!MDB2::isError($databases)
  1845.                 && !is_array($databases&& !in_array($this->database_definition['name']$databases)
  1846.             {
  1847.                 return $this->raiseError(MDB2_ERRORnullnull,
  1848.                     'database to update does not exist: '.$this->database_definition['name']);
  1849.             }
  1850.             $previous_definition $this->parseDatabaseDefinitionFile($previous_schema_file$variables0);
  1851.             if (MDB2::isError($previous_definition)) {
  1852.                 return $previous_definition;
  1853.             }
  1854.             $changes $this->compareDefinitions($previous_definition);
  1855.             if (MDB2::isError($changes)) {
  1856.                 return $changes;
  1857.             }
  1858.  
  1859.             if (is_array($changes)) {
  1860.                 $result $this->alterDatabase($changes$previous_definition);
  1861.                 if (MDB2::isError($result)) {
  1862.                     return $result;
  1863.                 }
  1864.                 $copy = true;
  1865.                 if ($this->db->options['debug']{
  1866.                     $result $this->dumpDatabaseChanges($changes);
  1867.                     if (MDB2::isError($result)) {
  1868.                         return $result;
  1869.                     }
  1870.                 }
  1871.             }
  1872.         else {
  1873.             $result $this->createDatabase();
  1874.             if (MDB2::isError($result)) {
  1875.                 return $result;
  1876.             }
  1877.             $copy = true;
  1878.         }
  1879.         if ($copy && $previous_schema_file && !copy($current_schema_file$previous_schema_file)) {
  1880.             return $this->raiseError(MDB2_ERROR_MANAGERnullnull,
  1881.                 'Could not copy the new database definition file to the current file');
  1882.         }
  1883.         return MDB2_OK;
  1884.     }
  1885.  
  1886.     // }}}
  1887. }
  1888. ?>

Documentation generated on Mon, 11 Mar 2019 14:28:17 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.