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

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