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

Source for file mysqli.php

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

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