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

Source for file mysql.php

Documentation is available at mysql.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5                                                 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2008 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: mysql.php,v 1.113 2008/11/23 20:30:29 quipo Exp $
  46. //
  47.  
  48. require_once 'MDB2/Driver/Manager/Common.php';
  49.  
  50. /**
  51.  * MDB2 MySQL driver for the management modules
  52.  *
  53.  * @package MDB2
  54.  * @category Database
  55.  * @author  Lukas Smith <smith@pooteeweet.org>
  56.  */
  57. class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common
  58. {
  59.  
  60.     // }}}
  61.     // {{{ createDatabase()
  62.  
  63.     /**
  64.      * create a new database
  65.      *
  66.      * @param string $name    name of the database that should be created
  67.      * @param array  $options array with charset, collation info
  68.      *
  69.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  70.      * @access public
  71.      */
  72.     function createDatabase($name$options = array())
  73.     {
  74.         $db =$this->getDBInstance();
  75.         if (PEAR::isError($db)) {
  76.             return $db;
  77.         }
  78.  
  79.         $name  $db->quoteIdentifier($nametrue);
  80.         $query 'CREATE DATABASE ' $name;
  81.         if (!empty($options['charset'])) {
  82.             $query .= ' DEFAULT CHARACTER SET ' $db->quote($options['charset']'text');
  83.         }
  84.         if (!empty($options['collation'])) {
  85.             $query .= ' COLLATE ' $db->quote($options['collation']'text');
  86.         }
  87.         return $db->standaloneQuery($querynulltrue);
  88.     }
  89.  
  90.     // }}}
  91.     // {{{ alterDatabase()
  92.  
  93.     /**
  94.      * alter an existing database
  95.      *
  96.      * @param string $name    name of the database that is intended to be changed
  97.      * @param array  $options array with charset, collation info
  98.      *
  99.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  100.      * @access public
  101.      */
  102.     function alterDatabase($name$options = array())
  103.     {
  104.         $db =$this->getDBInstance();
  105.         if (PEAR::isError($db)) {
  106.             return $db;
  107.         }
  108.  
  109.         $query 'ALTER DATABASE '$db->quoteIdentifier($nametrue);
  110.         if (!empty($options['charset'])) {
  111.             $query .= ' DEFAULT CHARACTER SET ' $db->quote($options['charset']'text');
  112.         }
  113.         if (!empty($options['collation'])) {
  114.             $query .= ' COLLATE ' $db->quote($options['collation']'text');
  115.         }
  116.         return $db->standaloneQuery($querynulltrue);
  117.     }
  118.  
  119.     // }}}
  120.     // {{{ dropDatabase()
  121.  
  122.     /**
  123.      * drop an existing database
  124.      *
  125.      * @param string $name name of the database that should be dropped
  126.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  127.      * @access public
  128.      */
  129.     function dropDatabase($name)
  130.     {
  131.         $db =$this->getDBInstance();
  132.         if (PEAR::isError($db)) {
  133.             return $db;
  134.         }
  135.  
  136.         $name $db->quoteIdentifier($nametrue);
  137.         $query = "DROP DATABASE $name";
  138.         return $db->standaloneQuery($querynulltrue);
  139.     }
  140.  
  141.     // }}}
  142.     // {{{ _getAdvancedFKOptions()
  143.  
  144.     /**
  145.      * Return the FOREIGN KEY query section dealing with non-standard options
  146.      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
  147.      *
  148.      * @param array $definition 
  149.      * @return string 
  150.      * @access protected
  151.      */
  152.     function _getAdvancedFKOptions($definition)
  153.     {
  154.         $query '';
  155.         if (!empty($definition['match'])) {
  156.             $query .= ' MATCH '.$definition['match'];
  157.         }
  158.         if (!empty($definition['onupdate'])) {
  159.             $query .= ' ON UPDATE '.$definition['onupdate'];
  160.         }
  161.         if (!empty($definition['ondelete'])) {
  162.             $query .= ' ON DELETE '.$definition['ondelete'];
  163.         }
  164.         return $query;
  165.     }
  166.  
  167.     // }}}
  168.     // {{{ createTable()
  169.  
  170.     /**
  171.      * create a new table
  172.      *
  173.      * @param string $name   Name of the database that should be created
  174.      * @param array $fields  Associative array that contains the definition of each field of the new table
  175.      *                        The indexes of the array entries are the names of the fields of the table an
  176.      *                        the array entry values are associative arrays like those that are meant to be
  177.      *                        passed with the field definitions to get[Type]Declaration() functions.
  178.      *                           array(
  179.      *                               'id' => array(
  180.      *                                   'type' => 'integer',
  181.      *                                   'unsigned' => 1
  182.      *                                   'notnull' => 1
  183.      *                                   'default' => 0
  184.      *                               ),
  185.      *                               'name' => array(
  186.      *                                   'type' => 'text',
  187.      *                                   'length' => 12
  188.      *                               ),
  189.      *                               'password' => array(
  190.      *                                   'type' => 'text',
  191.      *                                   'length' => 12
  192.      *                               )
  193.      *                           );
  194.      * @param array $options  An associative array of table options:
  195.      *                           array(
  196.      *                               'comment' => 'Foo',
  197.      *                               'charset' => 'utf8',
  198.      *                               'collate' => 'utf8_unicode_ci',
  199.      *                               'type'    => 'innodb',
  200.      *                           );
  201.      *
  202.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  203.      * @access public
  204.      */
  205.     function createTable($name$fields$options = array())
  206.     {
  207.         $db =$this->getDBInstance();
  208.         if (PEAR::isError($db)) {
  209.             return $db;
  210.         }
  211.  
  212.         // if we have an AUTO_INCREMENT column and a PK on more than one field,
  213.         // we have to handle it differently...
  214.         $autoincrement = null;
  215.         if (empty($options['primary'])) {
  216.             $pk_fields = array();
  217.             foreach ($fields as $fieldname => $def{
  218.                 if (!empty($def['primary'])) {
  219.                     $pk_fields[$fieldname= true;
  220.                 }
  221.                 if (!empty($def['autoincrement'])) {
  222.                     $autoincrement $fieldname;
  223.                 }
  224.             }
  225.             if (!is_null($autoincrement&& count($pk_fields> 1{
  226.                 $options['primary'$pk_fields;
  227.             else {
  228.                 // the PK constraint is on max one field => OK
  229.                 $autoincrement = null;
  230.             }
  231.         }
  232.  
  233.         $query $this->_getCreateTableQuery($name$fields$options);
  234.         if (PEAR::isError($query)) {
  235.             return $query;
  236.         }
  237.  
  238.         if (!is_null($autoincrement)) {
  239.             // we have to remove the PK clause added by _getIntegerDeclaration()
  240.             $query str_replace('AUTO_INCREMENT PRIMARY KEY''AUTO_INCREMENT'$query);
  241.         }
  242.  
  243.         $options_strings = array();
  244.  
  245.         if (!empty($options['comment'])) {
  246.             $options_strings['comment''COMMENT = '.$db->quote($options['comment']'text');
  247.         }
  248.  
  249.         if (!empty($options['charset'])) {
  250.             $options_strings['charset''DEFAULT CHARACTER SET '.$options['charset'];
  251.             if (!empty($options['collate'])) {
  252.                 $options_strings['charset'].= ' COLLATE '.$options['collate'];
  253.             }
  254.         }
  255.  
  256.         $type = false;
  257.         if (!empty($options['type'])) {
  258.             $type $options['type'];
  259.         elseif ($db->options['default_table_type']{
  260.             $type $db->options['default_table_type'];
  261.         }
  262.         if ($type{
  263.             $options_strings[= "ENGINE = $type";
  264.         }
  265.  
  266.         if (!empty($options_strings)) {
  267.             $query .= ' '.implode(' '$options_strings);
  268.         }
  269.         $result $db->exec($query);
  270.         if (PEAR::isError($result)) {
  271.             return $result;
  272.         }
  273.         return MDB2_OK;
  274.     }
  275.  
  276.     // }}}
  277.     // {{{ dropTable()
  278.  
  279.     /**
  280.      * drop an existing table
  281.      *
  282.      * @param string $name name of the table that should be dropped
  283.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  284.      * @access public
  285.      */
  286.     function dropTable($name)
  287.     {
  288.         $db =$this->getDBInstance();
  289.         if (PEAR::isError($db)) {
  290.             return $db;
  291.         }
  292.  
  293.         //delete the triggers associated to existing FK constraints
  294.         $constraints $this->listTableConstraints($name);
  295.         if (!PEAR::isError($constraints&& !empty($constraints)) {
  296.             $db->loadModule('Reverse'nulltrue);
  297.             foreach ($constraints as $constraint{
  298.                 $definition $db->reverse->getTableConstraintDefinition($name$constraint);
  299.                 if (!PEAR::isError($definition&& !empty($definition['foreign'])) {
  300.                     $result $this->_dropFKTriggers($name$constraint$definition['references']['table']);
  301.                     if (PEAR::isError($result)) {
  302.                         return $result;
  303.                     }
  304.                 }
  305.             }
  306.         }
  307.  
  308.         return parent::dropTable($name);
  309.     }
  310.  
  311.     // }}}
  312.     // {{{ truncateTable()
  313.  
  314.     /**
  315.      * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
  316.      * it falls back to a DELETE FROM TABLE query)
  317.      *
  318.      * @param string $name name of the table that should be truncated
  319.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  320.      * @access public
  321.      */
  322.     function truncateTable($name)
  323.     {
  324.         $db =$this->getDBInstance();
  325.         if (PEAR::isError($db)) {
  326.             return $db;
  327.         }
  328.  
  329.         $name $db->quoteIdentifier($nametrue);
  330.         return $db->exec("TRUNCATE TABLE $name");
  331.     }
  332.  
  333.     // }}}
  334.     // {{{ vacuum()
  335.  
  336.     /**
  337.      * Optimize (vacuum) all the tables in the db (or only the specified table)
  338.      * and optionally run ANALYZE.
  339.      *
  340.      * @param string $table table name (all the tables if empty)
  341.      * @param array  $options an array with driver-specific options:
  342.      *                - timeout [int] (in seconds) [mssql-only]
  343.      *                - analyze [boolean] [pgsql and mysql]
  344.      *                - full [boolean] [pgsql-only]
  345.      *                - freeze [boolean] [pgsql-only]
  346.      *
  347.      * @return mixed MDB2_OK success, a MDB2 error on failure
  348.      * @access public
  349.      */
  350.     function vacuum($table = null$options = array())
  351.     {
  352.         $db =$this->getDBInstance();
  353.         if (PEAR::isError($db)) {
  354.             return $db;
  355.         }
  356.  
  357.         if (empty($table)) {
  358.             $table $this->listTables();
  359.             if (PEAR::isError($table)) {
  360.                 return $table;
  361.             }
  362.         }
  363.         if (is_array($table)) {
  364.             foreach (array_keys($tableas $k{
  365.                 $table[$k$db->quoteIdentifier($table[$k]true);
  366.             }
  367.             $table implode(', '$table);
  368.         else {
  369.             $table $db->quoteIdentifier($tabletrue);
  370.         }
  371.         
  372.         $result $db->exec('OPTIMIZE TABLE '.$table);
  373.         if (PEAR::isError($result)) {
  374.             return $result;
  375.         }
  376.         if (!empty($options['analyze'])) {
  377.             return $db->exec('ANALYZE TABLE '.$table);
  378.         }
  379.         return MDB2_OK;
  380.     }
  381.  
  382.     // }}}
  383.     // {{{ alterTable()
  384.  
  385.     /**
  386.      * alter an existing table
  387.      *
  388.      * @param string $name         name of the table that is intended to be changed.
  389.      * @param array $changes     associative array that contains the details of each type
  390.      *                              of change that is intended to be performed. The types of
  391.      *                              changes that are currently supported are defined as follows:
  392.      *
  393.      *                              name
  394.      *
  395.      *                                 New name for the table.
  396.      *
  397.      *                             add
  398.      *
  399.      *                                 Associative array with the names of fields to be added as
  400.      *                                  indexes of the array. The value of each entry of the array
  401.      *                                  should be set to another associative array with the properties
  402.      *                                  of the fields to be added. The properties of the fields should
  403.      *                                  be the same as defined by the MDB2 parser.
  404.      *
  405.      *
  406.      *                             remove
  407.      *
  408.      *                                 Associative array with the names of fields to be removed as indexes
  409.      *                                  of the array. Currently the values assigned to each entry are ignored.
  410.      *                                  An empty array should be used for future compatibility.
  411.      *
  412.      *                             rename
  413.      *
  414.      *                                 Associative array with the names of fields to be renamed as indexes
  415.      *                                  of the array. The value of each entry of the array should be set to
  416.      *                                  another associative array with the entry named name with the new
  417.      *                                  field name and the entry named Declaration that is expected to contain
  418.      *                                  the portion of the field declaration already in DBMS specific SQL code
  419.      *                                  as it is used in the CREATE TABLE statement.
  420.      *
  421.      *                             change
  422.      *
  423.      *                                 Associative array with the names of the fields to be changed as indexes
  424.      *                                  of the array. Keep in mind that if it is intended to change either the
  425.      *                                  name of a field and any other properties, the change array entries
  426.      *                                  should have the new names of the fields as array indexes.
  427.      *
  428.      *                                 The value of each entry of the array should be set to another associative
  429.      *                                  array with the properties of the fields to that are meant to be changed as
  430.      *                                  array entries. These entries should be assigned to the new values of the
  431.      *                                  respective properties. The properties of the fields should be the same
  432.      *                                  as defined by the MDB2 parser.
  433.      *
  434.      *                             Example
  435.      *                                 array(
  436.      *                                     'name' => 'userlist',
  437.      *                                     'add' => array(
  438.      *                                         'quota' => array(
  439.      *                                             'type' => 'integer',
  440.      *                                             'unsigned' => 1
  441.      *                                         )
  442.      *                                     ),
  443.      *                                     'remove' => array(
  444.      *                                         'file_limit' => array(),
  445.      *                                         'time_limit' => array()
  446.      *                                     ),
  447.      *                                     'change' => array(
  448.      *                                         'name' => array(
  449.      *                                             'length' => '20',
  450.      *                                             'definition' => array(
  451.      *                                                 'type' => 'text',
  452.      *                                                 'length' => 20,
  453.      *                                             ),
  454.      *                                         )
  455.      *                                     ),
  456.      *                                     'rename' => array(
  457.      *                                         'sex' => array(
  458.      *                                             'name' => 'gender',
  459.      *                                             'definition' => array(
  460.      *                                                 'type' => 'text',
  461.      *                                                 'length' => 1,
  462.      *                                                 'default' => 'M',
  463.      *                                             ),
  464.      *                                         )
  465.      *                                     )
  466.      *                                 )
  467.      *
  468.      * @param boolean $check     indicates whether the function should just check if the DBMS driver
  469.      *                              can perform the requested table alterations if the value is true or
  470.      *                              actually perform them otherwise.
  471.      * @access public
  472.      *
  473.       * @return mixed MDB2_OK on success, a MDB2 error on failure
  474.      */
  475.     function alterTable($name$changes$check)
  476.     {
  477.         $db =$this->getDBInstance();
  478.         if (PEAR::isError($db)) {
  479.             return $db;
  480.         }
  481.  
  482.         foreach ($changes as $change_name => $change{
  483.             switch ($change_name{
  484.             case 'add':
  485.             case 'remove':
  486.             case 'change':
  487.             case 'rename':
  488.             case 'name':
  489.                 break;
  490.             default:
  491.                 return $db->raiseError(MDB2_ERROR_CANNOT_ALTERnullnull,
  492.                     'change type "'.$change_name.'" not yet supported'__FUNCTION__);
  493.             }
  494.         }
  495.  
  496.         if ($check{
  497.             return MDB2_OK;
  498.         }
  499.  
  500.         $query '';
  501.         if (!empty($changes['name'])) {
  502.             $change_name $db->quoteIdentifier($changes['name']true);
  503.             $query .= 'RENAME TO ' $change_name;
  504.         }
  505.  
  506.         if (!empty($changes['add']&& is_array($changes['add'])) {
  507.             foreach ($changes['add'as $field_name => $field{
  508.                 if ($query{
  509.                     $query.= ', ';
  510.                 }
  511.                 $query.= 'ADD ' $db->getDeclaration($field['type']$field_name$field);
  512.             }
  513.         }
  514.  
  515.         if (!empty($changes['remove']&& is_array($changes['remove'])) {
  516.             foreach ($changes['remove'as $field_name => $field{
  517.                 if ($query{
  518.                     $query.= ', ';
  519.                 }
  520.                 $field_name $db->quoteIdentifier($field_nametrue);
  521.                 $query.= 'DROP ' $field_name;
  522.             }
  523.         }
  524.  
  525.         $rename = array();
  526.         if (!empty($changes['rename']&& is_array($changes['rename'])) {
  527.             foreach ($changes['rename'as $field_name => $field{
  528.                 $rename[$field['name']] $field_name;
  529.             }
  530.         }
  531.  
  532.         if (!empty($changes['change']&& is_array($changes['change'])) {
  533.             foreach ($changes['change'as $field_name => $field{
  534.                 if ($query{
  535.                     $query.= ', ';
  536.                 }
  537.                 if (isset($rename[$field_name])) {
  538.                     $old_field_name $rename[$field_name];
  539.                     unset($rename[$field_name]);
  540.                 else {
  541.                     $old_field_name $field_name;
  542.                 }
  543.                 $old_field_name $db->quoteIdentifier($old_field_nametrue);
  544.                 $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type']$field_name$field['definition']);
  545.             }
  546.         }
  547.  
  548.         if (!empty($rename&& is_array($rename)) {
  549.             foreach ($rename as $rename_name => $renamed_field{
  550.                 if ($query{
  551.                     $query.= ', ';
  552.                 }
  553.                 $field $changes['rename'][$renamed_field];
  554.                 $renamed_field $db->quoteIdentifier($renamed_fieldtrue);
  555.                 $query.= 'CHANGE ' $renamed_field ' ' $db->getDeclaration($field['definition']['type']$field['name']$field['definition']);
  556.             }
  557.         }
  558.  
  559.         if (!$query{
  560.             return MDB2_OK;
  561.         }
  562.  
  563.         $name $db->quoteIdentifier($nametrue);
  564.         return $db->exec("ALTER TABLE $name $query");
  565.     }
  566.  
  567.     // }}}
  568.     // {{{ listDatabases()
  569.  
  570.     /**
  571.      * list all databases
  572.      *
  573.      * @return mixed array of database names on success, a MDB2 error on failure
  574.      * @access public
  575.      */
  576.     function listDatabases()
  577.     {
  578.         $db =$this->getDBInstance();
  579.         if (PEAR::isError($db)) {
  580.             return $db;
  581.         }
  582.  
  583.         $result $db->queryCol('SHOW DATABASES');
  584.         if (PEAR::isError($result)) {
  585.             return $result;
  586.         }
  587.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  588.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  589.         }
  590.         return $result;
  591.     }
  592.  
  593.     // }}}
  594.     // {{{ listUsers()
  595.  
  596.     /**
  597.      * list all users
  598.      *
  599.      * @return mixed array of user names on success, a MDB2 error on failure
  600.      * @access public
  601.      */
  602.     function listUsers()
  603.     {
  604.         $db =$this->getDBInstance();
  605.         if (PEAR::isError($db)) {
  606.             return $db;
  607.         }
  608.  
  609.         return $db->queryCol('SELECT DISTINCT USER FROM mysql.USER');
  610.     }
  611.  
  612.     // }}}
  613.     // {{{ listFunctions()
  614.  
  615.     /**
  616.      * list all functions in the current database
  617.      *
  618.      * @return mixed array of function names on success, a MDB2 error on failure
  619.      * @access public
  620.      */
  621.     function listFunctions()
  622.     {
  623.         $db =$this->getDBInstance();
  624.         if (PEAR::isError($db)) {
  625.             return $db;
  626.         }
  627.  
  628.         $query "SELECT name FROM mysql.proc";
  629.         /*
  630.         SELECT ROUTINE_NAME
  631.           FROM INFORMATION_SCHEMA.ROUTINES
  632.          WHERE ROUTINE_TYPE = 'FUNCTION'
  633.         */
  634.         $result $db->queryCol($query);
  635.         if (PEAR::isError($result)) {
  636.             return $result;
  637.         }
  638.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  639.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  640.         }
  641.         return $result;
  642.     }
  643.  
  644.     // }}}
  645.     // {{{ listTableTriggers()
  646.  
  647.     /**
  648.      * list all triggers in the database that reference a given table
  649.      *
  650.      * @param string table for which all referenced triggers should be found
  651.      * @return mixed array of trigger names on success, a MDB2 error on failure
  652.      * @access public
  653.      */
  654.     function listTableTriggers($table = null)
  655.     {
  656.         $db =$this->getDBInstance();
  657.         if (PEAR::isError($db)) {
  658.             return $db;
  659.         }
  660.  
  661.         $query 'SHOW TRIGGERS';
  662.         if (!is_null($table)) {
  663.             $table $db->quote($table'text');
  664.             $query .= " LIKE $table";
  665.         }
  666.         $result $db->queryCol($query);
  667.         if (PEAR::isError($result)) {
  668.             return $result;
  669.         }
  670.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  671.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  672.         }
  673.         return $result;
  674.     }
  675.  
  676.     // }}}
  677.     // {{{ listTables()
  678.  
  679.     /**
  680.      * list all tables in the current database
  681.      *
  682.      * @param string database, the current is default
  683.      * @return mixed array of table names on success, a MDB2 error on failure
  684.      * @access public
  685.      */
  686.     function listTables($database = null)
  687.     {
  688.         $db =$this->getDBInstance();
  689.         if (PEAR::isError($db)) {
  690.             return $db;
  691.         }
  692.  
  693.         $query "SHOW /*!50002 FULL*/ TABLES";
  694.         if (!is_null($database)) {
  695.             $query .= " FROM $database";
  696.         }
  697.         $query.= "/*!50002  WHERE Table_type = 'BASE TABLE'*/";
  698.  
  699.         $table_names $db->queryAll($querynullMDB2_FETCHMODE_ORDERED);
  700.         if (PEAR::isError($table_names)) {
  701.             return $table_names;
  702.         }
  703.  
  704.         $result = array();
  705.         foreach ($table_names as $table{
  706.             if (!$this->_fixSequenceName($table[0]true)) {
  707.                 $result[$table[0];
  708.             }
  709.         }
  710.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  711.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  712.         }
  713.         return $result;
  714.     }
  715.  
  716.     // }}}
  717.     // {{{ listViews()
  718.  
  719.     /**
  720.      * list all views in the current database
  721.      *
  722.      * @param string database, the current is default
  723.      * @return mixed array of view names on success, a MDB2 error on failure
  724.      * @access public
  725.      */
  726.     function listViews($database = null)
  727.     {
  728.         $db =$this->getDBInstance();
  729.         if (PEAR::isError($db)) {
  730.             return $db;
  731.         }
  732.  
  733.         $query 'SHOW FULL TABLES';
  734.         if (!is_null($database)) {
  735.             $query.= " FROM $database";
  736.         }
  737.         $query.= " WHERE Table_type = 'VIEW'";
  738.  
  739.         $result $db->queryCol($query);
  740.         if (PEAR::isError($result)) {
  741.             return $result;
  742.         }
  743.  
  744.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  745.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  746.         }
  747.         return $result;
  748.     }
  749.  
  750.     // }}}
  751.     // {{{ listTableFields()
  752.  
  753.     /**
  754.      * list all fields in a table in the current database
  755.      *
  756.      * @param string $table name of table that should be used in method
  757.      * @return mixed array of field names on success, a MDB2 error on failure
  758.      * @access public
  759.      */
  760.     function listTableFields($table)
  761.     {
  762.         $db =$this->getDBInstance();
  763.         if (PEAR::isError($db)) {
  764.             return $db;
  765.         }
  766.  
  767.         $table $db->quoteIdentifier($tabletrue);
  768.         $result $db->queryCol("SHOW COLUMNS FROM $table");
  769.         if (PEAR::isError($result)) {
  770.             return $result;
  771.         }
  772.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  773.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  774.         }
  775.         return $result;
  776.     }
  777.  
  778.     // }}}
  779.     // {{{ createIndex()
  780.  
  781.     /**
  782.      * Get the stucture of a field into an array
  783.      *
  784.      * @author Leoncx
  785.      * @param string $table      name of the table on which the index is to be created
  786.      * @param string $name       name of the index to be created
  787.      * @param array  $definition associative array that defines properties of the index to be created.
  788.      *                            Currently, only one property named FIELDS is supported. This property
  789.      *                            is also an associative with the names of the index fields as array
  790.      *                            indexes. Each entry of this array is set to another type of associative
  791.      *                            array that specifies properties of the index that are specific to
  792.      *                            each field.
  793.      *
  794.      *                            Currently, only the sorting property is supported. It should be used
  795.      *                            to define the sorting direction of the index. It may be set to either
  796.      *                            ascending or descending.
  797.      *
  798.      *                            Not all DBMS support index sorting direction configuration. The DBMS
  799.      *                            drivers of those that do not support it ignore this property. Use the
  800.      *                            function supports() to determine whether the DBMS driver can manage indexes.
  801.      *
  802.      *                            Example
  803.      *                                array(
  804.      *                                    'fields' => array(
  805.      *                                        'user_name' => array(
  806.      *                                            'sorting' => 'ascending'
  807.      *                                            'length' => 10
  808.      *                                        ),
  809.      *                                        'last_login' => array()
  810.      *                                     )
  811.      *                                 )
  812.      *
  813.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  814.      * @access public
  815.      */
  816.     function createIndex($table$name$definition)
  817.     {
  818.         $db =$this->getDBInstance();
  819.         if (PEAR::isError($db)) {
  820.             return $db;
  821.         }
  822.  
  823.         $table $db->quoteIdentifier($tabletrue);
  824.         $name $db->quoteIdentifier($db->getIndexName($name)true);
  825.         $query = "CREATE INDEX $name ON $table";
  826.         $fields = array();
  827.         foreach ($definition['fields'as $field => $fieldinfo{
  828.             if (!empty($fieldinfo['length'])) {
  829.                 $fields[$db->quoteIdentifier($fieldtrue'(' $fieldinfo['length'')';
  830.             else {
  831.                 $fields[$db->quoteIdentifier($fieldtrue);
  832.             }
  833.         }
  834.         $query .= ' ('implode(', '$fields')';
  835.         return $db->exec($query);
  836.     }
  837.  
  838.     // }}}
  839.     // {{{ dropIndex()
  840.  
  841.     /**
  842.      * drop existing index
  843.      *
  844.      * @param string    $table         name of table that should be used in method
  845.      * @param string    $name         name of the index to be dropped
  846.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  847.      * @access public
  848.      */
  849.     function dropIndex($table$name)
  850.     {
  851.         $db =$this->getDBInstance();
  852.         if (PEAR::isError($db)) {
  853.             return $db;
  854.         }
  855.  
  856.         $table $db->quoteIdentifier($tabletrue);
  857.         $name $db->quoteIdentifier($db->getIndexName($name)true);
  858.         return $db->exec("DROP INDEX $name ON $table");
  859.     }
  860.  
  861.     // }}}
  862.     // {{{ listTableIndexes()
  863.  
  864.     /**
  865.      * list all indexes in a table
  866.      *
  867.      * @param string $table name of table that should be used in method
  868.      * @return mixed array of index names on success, a MDB2 error on failure
  869.      * @access public
  870.      */
  871.     function listTableIndexes($table)
  872.     {
  873.         $db =$this->getDBInstance();
  874.         if (PEAR::isError($db)) {
  875.             return $db;
  876.         }
  877.  
  878.         $key_name 'Key_name';
  879.         $non_unique 'Non_unique';
  880.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  881.             if ($db->options['field_case'== CASE_LOWER{
  882.                 $key_name strtolower($key_name);
  883.                 $non_unique strtolower($non_unique);
  884.             else {
  885.                 $key_name strtoupper($key_name);
  886.                 $non_unique strtoupper($non_unique);
  887.             }
  888.         }
  889.  
  890.         $table $db->quoteIdentifier($tabletrue);
  891.         $query = "SHOW INDEX FROM $table";
  892.         $indexes $db->queryAll($querynullMDB2_FETCHMODE_ASSOC);
  893.         if (PEAR::isError($indexes)) {
  894.             return $indexes;
  895.         }
  896.  
  897.         $result = array();
  898.         foreach ($indexes as $index_data{
  899.             if ($index_data[$non_unique&& ($index $this->_fixIndexName($index_data[$key_name]))) {
  900.                 $result[$index= true;
  901.             }
  902.         }
  903.  
  904.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  905.             $result array_change_key_case($result$db->options['field_case']);
  906.         }
  907.         return array_keys($result);
  908.     }
  909.  
  910.     // }}}
  911.     // {{{ createConstraint()
  912.  
  913.     /**
  914.      * create a constraint on a table
  915.      *
  916.      * @param string    $table        name of the table on which the constraint is to be created
  917.      * @param string    $name         name of the constraint to be created
  918.      * @param array     $definition   associative array that defines properties of the constraint to be created.
  919.      *                                 Currently, only one property named FIELDS is supported. This property
  920.      *                                 is also an associative with the names of the constraint fields as array
  921.      *                                 constraints. Each entry of this array is set to another type of associative
  922.      *                                 array that specifies properties of the constraint that are specific to
  923.      *                                 each field.
  924.      *
  925.      *                                 Example
  926.      *                                    array(
  927.      *                                        'fields' => array(
  928.      *                                            'user_name' => array(),
  929.      *                                            'last_login' => array()
  930.      *                                        )
  931.      *                                    )
  932.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  933.      * @access public
  934.      */
  935.     function createConstraint($table$name$definition)
  936.     {
  937.         $db =$this->getDBInstance();
  938.         if (PEAR::isError($db)) {
  939.             return $db;
  940.         }
  941.  
  942.         $type '';
  943.         $idx_name $db->quoteIdentifier($db->getIndexName($name)true);
  944.         if (!empty($definition['primary'])) {
  945.             $type 'PRIMARY';
  946.             $idx_name 'KEY';
  947.         elseif (!empty($definition['unique'])) {
  948.             $type 'UNIQUE';
  949.         elseif (!empty($definition['foreign'])) {
  950.             $type 'CONSTRAINT';
  951.         }
  952.         if (empty($type)) {
  953.             return $db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  954.                 'invalid definition, could not create constraint'__FUNCTION__);
  955.         }
  956.  
  957.         $table_quoted $db->quoteIdentifier($tabletrue);
  958.         $query = "ALTER TABLE $table_quoted ADD $type $idx_name";
  959.         if (!empty($definition['foreign'])) {
  960.             $query .= ' FOREIGN KEY';
  961.         }
  962.         $fields = array();
  963.         foreach ($definition['fields'as $field => $fieldinfo{
  964.             $quoted $db->quoteIdentifier($fieldtrue);
  965.             if (!empty($fieldinfo['length'])) {
  966.                 $quoted .= '(' $fieldinfo['length'')';
  967.             }
  968.             $fields[$quoted;
  969.         }
  970.         $query .= ' ('implode(', '$fields')';
  971.         if (!empty($definition['foreign'])) {
  972.             $query.= ' REFERENCES ' $db->quoteIdentifier($definition['references']['table']true);
  973.             $referenced_fields = array();
  974.             foreach (array_keys($definition['references']['fields']as $field{
  975.                 $referenced_fields[$db->quoteIdentifier($fieldtrue);
  976.             }
  977.             $query .= ' ('implode(', '$referenced_fields')';
  978.             $query .= $this->_getAdvancedFKOptions($definition);
  979.  
  980.             // add index on FK column(s) or we can't add a FK constraint
  981.             // @see http://forums.mysql.com/read.php?22,19755,226009
  982.             $result $this->createIndex($table$name.'_fkidx'$definition);
  983.             if (PEAR::isError($result)) {
  984.                 return $result;
  985.             }
  986.         }
  987.         $res $db->exec($query);
  988.         if (PEAR::isError($res)) {
  989.             return $res;
  990.         }
  991.         if (!empty($definition['foreign'])) {
  992.             return $this->_createFKTriggers($tablearray($name => $definition));
  993.         }
  994.         return MDB2_OK;
  995.     }
  996.  
  997.     // }}}
  998.     // {{{ dropConstraint()
  999.  
  1000.     /**
  1001.      * drop existing constraint
  1002.      *
  1003.      * @param string    $table        name of table that should be used in method
  1004.      * @param string    $name         name of the constraint to be dropped
  1005.      * @param string    $primary      hint if the constraint is primary
  1006.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1007.      * @access public
  1008.      */
  1009.     function dropConstraint($table$name$primary = false)
  1010.     {
  1011.         $db =$this->getDBInstance();
  1012.         if (PEAR::isError($db)) {
  1013.             return $db;
  1014.         }
  1015.  
  1016.         if ($primary || strtolower($name== 'primary'{
  1017.             $query 'ALTER TABLE '$db->quoteIdentifier($tabletrue.' DROP PRIMARY KEY';
  1018.             return $db->exec($query);
  1019.         }
  1020.  
  1021.         //is it a FK constraint? If so, also delete the associated triggers
  1022.         $db->loadModule('Reverse'nulltrue);
  1023.         $definition $db->reverse->getTableConstraintDefinition($table$name);
  1024.         if (!PEAR::isError($definition&& !empty($definition['foreign'])) {
  1025.             //first drop the FK enforcing triggers
  1026.             $result $this->_dropFKTriggers($table$name$definition['references']['table']);
  1027.             if (PEAR::isError($result)) {
  1028.                 return $result;
  1029.             }
  1030.             //then drop the constraint itself
  1031.             $table $db->quoteIdentifier($tabletrue);
  1032.             $name $db->quoteIdentifier($db->getIndexName($name)true);
  1033.             $query = "ALTER TABLE $table DROP FOREIGN KEY $name";
  1034.             return $db->exec($query);
  1035.         }
  1036.  
  1037.         $table $db->quoteIdentifier($tabletrue);
  1038.         $name $db->quoteIdentifier($db->getIndexName($name)true);
  1039.         $query = "ALTER TABLE $table DROP INDEX $name";
  1040.         return $db->exec($query);
  1041.     }
  1042.  
  1043.     // }}}
  1044.     // {{{ _createFKTriggers()
  1045.  
  1046.     /**
  1047.      * Create triggers to enforce the FOREIGN KEY constraint on the table
  1048.      *
  1049.      * NB: since there's no RAISE_APPLICATION_ERROR facility in mysql,
  1050.      * we call a non-existent procedure to raise the FK violation message.
  1051.      * @see http://forums.mysql.com/read.php?99,55108,71877#msg-71877
  1052.      *
  1053.      * @param string $table        table name
  1054.      * @param array  $foreign_keys FOREIGN KEY definitions
  1055.      *
  1056.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1057.      * @access private
  1058.      */
  1059.     function _createFKTriggers($table$foreign_keys)
  1060.     {
  1061.         $db =$this->getDBInstance();
  1062.         if (PEAR::isError($db)) {
  1063.             return $db;
  1064.         }
  1065.         // create triggers to enforce FOREIGN KEY constraints
  1066.         if ($db->supports('triggers'&& !empty($foreign_keys)) {
  1067.             $table_quoted $db->quoteIdentifier($tabletrue);
  1068.             foreach ($foreign_keys as $fkname => $fkdef{
  1069.                 if (empty($fkdef)) {
  1070.                     continue;
  1071.                 }
  1072.                 //set actions to default if not set
  1073.                 $fkdef['onupdate'= empty($fkdef['onupdate']$db->options['default_fk_action_onupdate'strtoupper($fkdef['onupdate']);
  1074.                 $fkdef['ondelete'= empty($fkdef['ondelete']$db->options['default_fk_action_ondelete'strtoupper($fkdef['ondelete']);
  1075.  
  1076.                 $trigger_names = array(
  1077.                     'insert'    => $fkname.'_insert_trg',
  1078.                     'update'    => $fkname.'_update_trg',
  1079.                     'pk_update' => $fkname.'_pk_update_trg',
  1080.                     'pk_delete' => $fkname.'_pk_delete_trg',
  1081.                 );
  1082.                 $table_fields array_keys($fkdef['fields']);
  1083.                 $referenced_fields array_keys($fkdef['references']['fields']);
  1084.  
  1085.                 //create the ON [UPDATE|DELETE] triggers on the primary table
  1086.                 $restrict_action ' IF (SELECT ';
  1087.                 $aliased_fields = array();
  1088.                 foreach ($table_fields as $field{
  1089.                     $aliased_fields[$table_quoted .'.'.$field .' AS '.$field;
  1090.                 }
  1091.                 $restrict_action .= implode(','$aliased_fields)
  1092.                        .' FROM '.$table_quoted
  1093.                        .' WHERE ';
  1094.                 $conditions  = array();
  1095.                 $new_values  = array();
  1096.                 $null_values = array();
  1097.                 for ($i=0; $i<count($table_fields)$i++{
  1098.                     $conditions[]  $table_fields[$i.' = OLD.'.$referenced_fields[$i];
  1099.                     $new_values[]  $table_fields[$i.' = NEW.'.$referenced_fields[$i];
  1100.                     $null_values[$table_fields[$i.' = NULL';
  1101.                 }
  1102.                 $conditions2 = array();
  1103.                 for ($i=0; $i<count($referenced_fields)$i++{
  1104.                     $conditions2[]  'NEW.'.$referenced_fields[$i.' <> OLD.'.$referenced_fields[$i];
  1105.                 }
  1106.                 $restrict_action .= implode(' AND '$conditions).') IS NOT NULL'
  1107.                                 .' AND (' .implode(' OR '$conditions2.')'
  1108.                                 .' THEN CALL %s_ON_TABLE_'.$table.'_VIOLATES_FOREIGN_KEY_CONSTRAINT();'
  1109.                                 .' END IF;';
  1110.  
  1111.                 $cascade_action_update 'UPDATE '.$table_quoted.' SET '.implode(', '$new_values.' WHERE '.implode(' AND '$conditions)';';
  1112.                 $cascade_action_delete 'DELETE FROM '.$table_quoted.' WHERE '.implode(' AND '$conditions)';';
  1113.                 $setnull_action        'UPDATE '.$table_quoted.' SET '.implode(', '$null_values).' WHERE '.implode(' AND '$conditions)';';
  1114.  
  1115.                 if ('SET DEFAULT' == $fkdef['onupdate'|| 'SET DEFAULT' == $fkdef['ondelete']{
  1116.                     $db->loadModule('Reverse'nulltrue);
  1117.                     $default_values = array();
  1118.                     foreach ($table_fields as $table_field{
  1119.                         $field_definition $db->reverse->getTableFieldDefinition($table$field);
  1120.                         if (PEAR::isError($field_definition)) {
  1121.                             return $field_definition;
  1122.                         }
  1123.                         $default_values[$table_field .' = '$field_definition[0]['default'];
  1124.                     }
  1125.                     $setdefault_action 'UPDATE '.$table_quoted.' SET '.implode(', '$default_values).' WHERE '.implode(' AND '$conditions)';';
  1126.                 }
  1127.  
  1128.                 $query 'CREATE TRIGGER %s'
  1129.                         .' %s ON '.$fkdef['references']['table']
  1130.                         .' FOR EACH ROW BEGIN '
  1131.                         .' SET FOREIGN_KEY_CHECKS = 0; ';  //only really needed for ON UPDATE CASCADE
  1132.  
  1133.                 if ('CASCADE' == $fkdef['onupdate']{
  1134.                     $sql_update sprintf($query$trigger_names['pk_update']'BEFORE UPDATE',  'update'$cascade_action_update;
  1135.                 elseif ('SET NULL' == $fkdef['onupdate']{
  1136.                     $sql_update sprintf($query$trigger_names['pk_update']'BEFORE UPDATE''update'$setnull_action;
  1137.                 elseif ('SET DEFAULT' == $fkdef['onupdate']{
  1138.                     $sql_update sprintf($query$trigger_names['pk_update']'BEFORE UPDATE''update'$setdefault_action;
  1139.                 elseif ('NO ACTION' == $fkdef['onupdate']{
  1140.                     $sql_update sprintf($query.$restrict_action$trigger_names['pk_update']'AFTER UPDATE''update');
  1141.                 elseif ('RESTRICT' == $fkdef['onupdate']{
  1142.                     $sql_update sprintf($query.$restrict_action$trigger_names['pk_update']'BEFORE UPDATE''update');
  1143.                 }
  1144.                 if ('CASCADE' == $fkdef['ondelete']{
  1145.                     $sql_delete sprintf($query$trigger_names['pk_delete']'BEFORE DELETE',  'delete'$cascade_action_delete;
  1146.                 elseif ('SET NULL' == $fkdef['ondelete']{
  1147.                     $sql_delete sprintf($query$trigger_names['pk_delete']'BEFORE DELETE''delete'$setnull_action;
  1148.                 elseif ('SET DEFAULT' == $fkdef['ondelete']{
  1149.                     $sql_delete sprintf($query$trigger_names['pk_delete']'BEFORE DELETE''delete'$setdefault_action;
  1150.                 elseif ('NO ACTION' == $fkdef['ondelete']{
  1151.                     $sql_delete sprintf($query.$restrict_action$trigger_names['pk_delete']'AFTER DELETE''delete');
  1152.                 elseif ('RESTRICT' == $fkdef['ondelete']{
  1153.                     $sql_delete sprintf($query.$restrict_action$trigger_names['pk_delete']'BEFORE DELETE''delete');
  1154.                 }
  1155.                 $sql_update .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
  1156.                 $sql_delete .= ' SET FOREIGN_KEY_CHECKS = 1; END;';
  1157.  
  1158.                 $db->pushErrorHandling(PEAR_ERROR_RETURN);
  1159.                 $db->expectError(MDB2_ERROR_CANNOT_CREATE);
  1160.                 $result $db->exec($sql_delete);
  1161.                 $expected_errmsg 'This MySQL version doesn\'t support multiple triggers with the same action time and event for one table';
  1162.                 $db->popExpect();
  1163.                 $db->popErrorHandling();
  1164.                 if (PEAR::isError($result)) {
  1165.                     if ($result->getCode(!= MDB2_ERROR_CANNOT_CREATE{
  1166.                         return $result;
  1167.                     }
  1168.                     $db->warnings[$expected_errmsg;
  1169.                 }
  1170.                 $db->pushErrorHandling(PEAR_ERROR_RETURN);
  1171.                 $db->expectError(MDB2_ERROR_CANNOT_CREATE);
  1172.                 $result $db->exec($sql_update);
  1173.                 $db->popExpect();
  1174.                 $db->popErrorHandling();
  1175.                 if (PEAR::isError($result&& $result->getCode(!= MDB2_ERROR_CANNOT_CREATE{
  1176.                     if ($result->getCode(!= MDB2_ERROR_CANNOT_CREATE{
  1177.                         return $result;
  1178.                     }
  1179.                     $db->warnings[$expected_errmsg;
  1180.                 }
  1181.             }
  1182.         }
  1183.         return MDB2_OK;
  1184.     }
  1185.  
  1186.     // }}}
  1187.     // {{{ _dropFKTriggers()
  1188.  
  1189.     /**
  1190.      * Drop the triggers created to enforce the FOREIGN KEY constraint on the table
  1191.      *
  1192.      * @param string $table            table name
  1193.      * @param string $fkname           FOREIGN KEY constraint name
  1194.      * @param string $referenced_table referenced table name
  1195.      *
  1196.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1197.      * @access private
  1198.      */
  1199.     function _dropFKTriggers($table$fkname$referenced_table)
  1200.     {
  1201.         $db =$this->getDBInstance();
  1202.         if (PEAR::isError($db)) {
  1203.             return $db;
  1204.         }
  1205.  
  1206.         $triggers  $this->listTableTriggers($table);
  1207.         $triggers2 $this->listTableTriggers($referenced_table);
  1208.         if (!PEAR::isError($triggers2&& !PEAR::isError($triggers)) {
  1209.             $triggers array_merge($triggers$triggers2);
  1210.             $pattern '/^'.$fkname.'(_pk)?_(insert|update|delete)_trg$/i';
  1211.             foreach ($triggers as $trigger{
  1212.                 if (preg_match($pattern$trigger)) {
  1213.                     $result $db->exec('DROP TRIGGER '.$trigger);
  1214.                     if (PEAR::isError($result)) {
  1215.                         return $result;
  1216.                     }
  1217.                 }
  1218.             }
  1219.         }
  1220.         return MDB2_OK;
  1221.     }
  1222.  
  1223.     // }}}
  1224.     // {{{ listTableConstraints()
  1225.  
  1226.     /**
  1227.      * list all constraints in a table
  1228.      *
  1229.      * @param string $table name of table that should be used in method
  1230.      * @return mixed array of constraint names on success, a MDB2 error on failure
  1231.      * @access public
  1232.      */
  1233.     function listTableConstraints($table)
  1234.     {
  1235.         $db =$this->getDBInstance();
  1236.         if (PEAR::isError($db)) {
  1237.             return $db;
  1238.         }
  1239.  
  1240.         $key_name 'Key_name';
  1241.         $non_unique 'Non_unique';
  1242.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1243.             if ($db->options['field_case'== CASE_LOWER{
  1244.                 $key_name strtolower($key_name);
  1245.                 $non_unique strtolower($non_unique);
  1246.             else {
  1247.                 $key_name strtoupper($key_name);
  1248.                 $non_unique strtoupper($non_unique);
  1249.             }
  1250.         }
  1251.  
  1252.         $query 'SHOW INDEX FROM ' $db->quoteIdentifier($tabletrue);
  1253.         $indexes $db->queryAll($querynullMDB2_FETCHMODE_ASSOC);
  1254.         if (PEAR::isError($indexes)) {
  1255.             return $indexes;
  1256.         }
  1257.  
  1258.         $result = array();
  1259.         foreach ($indexes as $index_data{
  1260.             if (!$index_data[$non_unique]{
  1261.                 if ($index_data[$key_name!== 'PRIMARY'{
  1262.                     $index $this->_fixIndexName($index_data[$key_name]);
  1263.                 else {
  1264.                     $index 'PRIMARY';
  1265.                 }
  1266.                 if (!empty($index)) {
  1267.                     $result[$index= true;
  1268.                 }
  1269.             }
  1270.         }
  1271.         
  1272.         //list FOREIGN KEY constraints...
  1273.         $query 'SHOW CREATE TABLE '$db->escape($table);
  1274.         $definition $db->queryOne($query'text'1);
  1275.         if (!PEAR::isError($definition&& !empty($definition)) {
  1276.             $pattern '/\bCONSTRAINT\b\s+([^\s]+)\s+\bFOREIGN KEY\b/Uims';
  1277.             if (preg_match_all($patternstr_replace('`'''$definition)$matches> 0{
  1278.                 foreach ($matches[1as $constraint{
  1279.                     $result[$constraint= true;
  1280.                 }
  1281.             }
  1282.         }
  1283.  
  1284.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1285.             $result array_change_key_case($result$db->options['field_case']);
  1286.         }
  1287.         return array_keys($result);
  1288.     }
  1289.  
  1290.     // }}}
  1291.     // {{{ createSequence()
  1292.  
  1293.     /**
  1294.      * create sequence
  1295.      *
  1296.      * @param string    $seq_name name of the sequence to be created
  1297.      * @param string    $start    start value of the sequence; default is 1
  1298.      * @param array     $options  An associative array of table options:
  1299.      *                           array(
  1300.      *                               'comment' => 'Foo',
  1301.      *                               'charset' => 'utf8',
  1302.      *                               'collate' => 'utf8_unicode_ci',
  1303.      *                               'type'    => 'innodb',
  1304.      *                           );
  1305.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1306.      * @access public
  1307.      */
  1308.     function createSequence($seq_name$start = 1$options = array())
  1309.     {
  1310.         $db =$this->getDBInstance();
  1311.         if (PEAR::isError($db)) {
  1312.             return $db;
  1313.         }
  1314.  
  1315.         $sequence_name $db->quoteIdentifier($db->getSequenceName($seq_name)true);
  1316.         $seqcol_name $db->quoteIdentifier($db->options['seqcol_name']true);
  1317.         
  1318.         $options_strings = array();
  1319.  
  1320.         if (!empty($options['comment'])) {
  1321.             $options_strings['comment''COMMENT = '.$db->quote($options['comment']'text');
  1322.         }
  1323.  
  1324.         if (!empty($options['charset'])) {
  1325.             $options_strings['charset''DEFAULT CHARACTER SET '.$options['charset'];
  1326.             if (!empty($options['collate'])) {
  1327.                 $options_strings['charset'].= ' COLLATE '.$options['collate'];
  1328.             }
  1329.         }
  1330.  
  1331.         $type = false;
  1332.         if (!empty($options['type'])) {
  1333.             $type $options['type'];
  1334.         elseif ($db->options['default_table_type']{
  1335.             $type $db->options['default_table_type'];
  1336.         }
  1337.         if ($type{
  1338.             $options_strings[= "ENGINE = $type";
  1339.         }
  1340.  
  1341.         $query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))";
  1342.         if (!empty($options_strings)) {
  1343.             $query .= ' '.implode(' '$options_strings);
  1344.         }
  1345.         $res $db->exec($query);
  1346.         if (PEAR::isError($res)) {
  1347.             return $res;
  1348.         }
  1349.  
  1350.         if ($start == 1{
  1351.             return MDB2_OK;
  1352.         }
  1353.  
  1354.         $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')';
  1355.         $res $db->exec($query);
  1356.         if (!PEAR::isError($res)) {
  1357.             return MDB2_OK;
  1358.         }
  1359.  
  1360.         // Handle error
  1361.         $result $db->exec("DROP TABLE $sequence_name");
  1362.         if (PEAR::isError($result)) {
  1363.             return $db->raiseError($resultnullnull,
  1364.                 'could not drop inconsistent sequence table'__FUNCTION__);
  1365.         }
  1366.  
  1367.         return $db->raiseError($resnullnull,
  1368.             'could not create sequence table'__FUNCTION__);
  1369.     }
  1370.  
  1371.     // }}}
  1372.     // {{{ dropSequence()
  1373.  
  1374.     /**
  1375.      * drop existing sequence
  1376.      *
  1377.      * @param string    $seq_name     name of the sequence to be dropped
  1378.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1379.      * @access public
  1380.      */
  1381.     function dropSequence($seq_name)
  1382.     {
  1383.         $db =$this->getDBInstance();
  1384.         if (PEAR::isError($db)) {
  1385.             return $db;
  1386.         }
  1387.  
  1388.         $sequence_name $db->quoteIdentifier($db->getSequenceName($seq_name)true);
  1389.         return $db->exec("DROP TABLE $sequence_name");
  1390.     }
  1391.  
  1392.     // }}}
  1393.     // {{{ listSequences()
  1394.  
  1395.     /**
  1396.      * list all sequences in the current database
  1397.      *
  1398.      * @param string database, the current is default
  1399.      * @return mixed array of sequence names on success, a MDB2 error on failure
  1400.      * @access public
  1401.      */
  1402.     function listSequences($database = null)
  1403.     {
  1404.         $db =$this->getDBInstance();
  1405.         if (PEAR::isError($db)) {
  1406.             return $db;
  1407.         }
  1408.  
  1409.         $query "SHOW TABLES";
  1410.         if (!is_null($database)) {
  1411.             $query .= " FROM $database";
  1412.         }
  1413.         $table_names $db->queryCol($query);
  1414.         if (PEAR::isError($table_names)) {
  1415.             return $table_names;
  1416.         }
  1417.  
  1418.         $result = array();
  1419.         foreach ($table_names as $table_name{
  1420.             if ($sqn $this->_fixSequenceName($table_nametrue)) {
  1421.                 $result[$sqn;
  1422.             }
  1423.         }
  1424.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1425.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  1426.         }
  1427.         return $result;
  1428.     }
  1429.  
  1430.     // }}}
  1431. }
  1432. ?>

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