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

Source for file Schema.php

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

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