home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / DB / Table / Manager.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  67.5 KB  |  2,344 lines

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * Creates, checks or alters tables from DB_Table definitions.
  7.  * 
  8.  * DB_Table_Manager provides database automated table creation
  9.  * facilities.
  10.  * 
  11.  * PHP versions 4 and 5
  12.  *
  13.  * LICENSE:
  14.  * 
  15.  * Copyright (c) 1997-2007, Paul M. Jones <pmjones@php.net>
  16.  *                          David C. Morse <morse@php.net>
  17.  *                          Mark Wiesemann <wiesemann@php.net>
  18.  * All rights reserved.
  19.  *
  20.  * Redistribution and use in source and binary forms, with or without
  21.  * modification, are permitted provided that the following conditions
  22.  * are met:
  23.  *
  24.  *    * Redistributions of source code must retain the above copyright
  25.  *      notice, this list of conditions and the following disclaimer.
  26.  *    * Redistributions in binary form must reproduce the above copyright
  27.  *      notice, this list of conditions and the following disclaimer in the 
  28.  *      documentation and/or other materials provided with the distribution.
  29.  *    * The names of the authors may not be used to endorse or promote products 
  30.  *      derived from this software without specific prior written permission.
  31.  *
  32.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  33.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  34.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  35.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  37.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  38.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  39.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  40.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  41.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  *
  44.  * @category Database
  45.  * @package  DB_Table
  46.  * @author   Paul M. Jones <pmjones@php.net>
  47.  * @author   David C. Morse <morse@php.net>
  48.  * @author   Mark Wiesemann <wiesemann@php.net>
  49.  * @license  http://opensource.org/licenses/bsd-license.php New BSD License
  50.  * @version  CVS: $Id: Manager.php,v 1.39 2008/06/08 17:49:28 wiesemann Exp $
  51.  * @link     http://pear.php.net/package/DB_Table
  52.  */
  53.  
  54. require_once 'DB/Table.php';
  55.  
  56.  
  57. /**
  58. * Valid types for the different data types in the different DBMS.
  59. */
  60. $GLOBALS['_DB_TABLE']['valid_type'] = array(
  61.     'fbsql' => array(  // currently not supported
  62.         'boolean'   => '',
  63.         'char'      => '',
  64.         'varchar'   => '',
  65.         'smallint'  => '',
  66.         'integer'   => '',
  67.         'bigint'    => '',
  68.         'decimal'   => '',
  69.         'single'    => '',
  70.         'double'    => '',
  71.         'clob'      => '',
  72.         'date'      => '',
  73.         'time'      => '',
  74.         'timestamp' => ''
  75.     ),
  76.     'ibase' => array(
  77.         'boolean'   => array('char', 'integer', 'real', 'smallint'),
  78.         'char'      => array('char', 'varchar'),
  79.         'varchar'   => 'varchar',
  80.         'smallint'  => array('integer', 'smallint'),
  81.         'integer'   => 'integer',
  82.         'bigint'    => array('bigint', 'integer'),
  83.         'decimal'   => 'numeric',
  84.         'single'    => array('double precision', 'float'),
  85.         'double'    => 'double precision',
  86.         'clob'      => 'blob',
  87.         'date'      => 'date',
  88.         'time'      => 'time',
  89.         'timestamp' => 'timestamp'
  90.     ),
  91.     'mssql' => array(  // currently not supported
  92.         'boolean'   => '',
  93.         'char'      => '',
  94.         'varchar'   => '',
  95.         'smallint'  => '',
  96.         'integer'   => '',
  97.         'bigint'    => '',
  98.         'decimal'   => '',
  99.         'single'    => '',
  100.         'double'    => '',
  101.         'clob'      => '',
  102.         'date'      => '',
  103.         'time'      => '',
  104.         'timestamp' => ''
  105.     ),
  106.     'mysql' => array(
  107.         'boolean'   => array('char', 'decimal', 'int', 'real', 'tinyint'),
  108.         'char'      => array('char', 'string', 'varchar'),
  109.         'varchar'   => array('char', 'string', 'varchar'),
  110.         'smallint'  => array('smallint', 'int'),
  111.         'integer'   => 'int',
  112.         'bigint'    => array('int', 'bigint'),
  113.         'decimal'   => array('decimal', 'real'),
  114.         'single'    => array('double', 'real'),
  115.         'double'    => array('double', 'real'),
  116.         'clob'      => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
  117.         'date'      => array('char', 'date', 'string'),
  118.         'time'      => array('char', 'string', 'time'),
  119.         'timestamp' => array('char', 'datetime', 'string')
  120.     ),
  121.     'mysqli' => array(
  122.         'boolean'   => array('char', 'decimal', 'tinyint'),
  123.         'char'      => array('char', 'varchar'),
  124.         'varchar'   => array('char', 'varchar'),
  125.         'smallint'  => array('smallint', 'int'),
  126.         'integer'   => 'int',
  127.         'bigint'    => array('int', 'bigint'),
  128.         'decimal'   => 'decimal',
  129.         'single'    => array('double', 'float'),
  130.         'double'    => 'double',
  131.         'clob'      => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
  132.         'date'      => array('char', 'date', 'varchar'),
  133.         'time'      => array('char', 'time', 'varchar'),
  134.         'timestamp' => array('char', 'datetime', 'varchar')
  135.     ),
  136.     'oci8' => array(
  137.         'boolean'   => 'number',
  138.         'char'      => array('char', 'varchar2'),
  139.         'varchar'   => 'varchar2',
  140.         'smallint'  => 'number',
  141.         'integer'   => 'number',
  142.         'bigint'    => 'number',
  143.         'decimal'   => 'number',
  144.         'single'    => array('float', 'number'),
  145.         'double'    => array('float', 'number'),
  146.         'clob'      => 'clob',
  147.         'date'      => array('char', 'date'),
  148.         'time'      => array('char', 'date'),
  149.         'timestamp' => array('char', 'date')
  150.     ),
  151.     'pgsql' => array(
  152.         'boolean'   => array('bool', 'numeric'),
  153.         'char'      => array('bpchar', 'varchar'),
  154.         'varchar'   => 'varchar',
  155.         'smallint'  => array('int2', 'int4'),
  156.         'integer'   => 'int4',
  157.         'bigint'    => array('int4', 'int8'),
  158.         'decimal'   => 'numeric',
  159.         'single'    => array('float4', 'float8'),
  160.         'double'    => 'float8',
  161.         'clob'      => array('oid', 'text'),
  162.         'date'      => array('bpchar', 'date'),
  163.         'time'      => array('bpchar', 'time'),
  164.         'timestamp' => array('bpchar', 'timestamp')
  165.     ),
  166.     'sqlite' => array(
  167.         'boolean'   => 'boolean',
  168.         'char'      => 'char',
  169.         'varchar'   => array('char', 'varchar'),
  170.         'smallint'  => array('int', 'smallint'),
  171.         'integer'   => array('int', 'integer'),
  172.         'bigint'    => array('int', 'bigint'),
  173.         'decimal'   => array('decimal', 'numeric'),
  174.         'single'    => array('double', 'float'),
  175.         'double'    => 'double',
  176.         'clob'      => array('clob', 'longtext'),
  177.         'date'      => 'date',
  178.         'time'      => 'time',
  179.         'timestamp' => array('datetime', 'timestamp')
  180.     ),
  181. );
  182.  
  183. /**
  184. * Mapping between DB_Table and MDB2 data types.
  185. */
  186. $GLOBALS['_DB_TABLE']['mdb2_type'] = array(
  187.     'boolean'   => 'boolean',
  188.     'char'      => 'text',
  189.     'varchar'   => 'text',
  190.     'smallint'  => 'integer',
  191.     'integer'   => 'integer',
  192.     'bigint'    => 'integer',
  193.     'decimal'   => 'decimal',
  194.     'single'    => 'float',
  195.     'double'    => 'float',
  196.     'clob'      => 'clob',
  197.     'date'      => 'date',
  198.     'time'      => 'time',
  199.     'timestamp' => 'timestamp'
  200. );
  201.  
  202. /**
  203.  * Creates, checks or alters tables from DB_Table definitions.
  204.  * 
  205.  * DB_Table_Manager provides database automated table creation
  206.  * facilities.
  207.  * 
  208.  * @category Database
  209.  * @package  DB_Table
  210.  * @author   Paul M. Jones <pmjones@php.net>
  211.  * @author   David C. Morse <morse@php.net>
  212.  * @author   Mark Wiesemann <wiesemann@php.net>
  213.  * @version  Release: 1.5.5
  214.  * @link     http://pear.php.net/package/DB_Table
  215.  */
  216. class DB_Table_Manager {
  217.  
  218.  
  219.    /**
  220.     * 
  221.     * Create the table based on DB_Table column and index arrays.
  222.     * 
  223.     * @static
  224.     * 
  225.     * @access public
  226.     * 
  227.     * @param object &$db A PEAR DB/MDB2 object.
  228.     * 
  229.     * @param string $table The table name to connect to in the database.
  230.     * 
  231.     * @param mixed $column_set A DB_Table $this->col array.
  232.     * 
  233.     * @param mixed $index_set A DB_Table $this->idx array.
  234.     * 
  235.     * @return mixed Boolean false if there was no attempt to create the
  236.     * table, boolean true if the attempt succeeded, and a PEAR_Error if
  237.     * the attempt failed.
  238.     * 
  239.     */
  240.  
  241.     function create(&$db, $table, $column_set, $index_set)
  242.     {
  243.         if (is_subclass_of($db, 'db_common')) {
  244.             $backend = 'db';
  245.         } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
  246.             $backend = 'mdb2';
  247.             $db->loadModule('Manager');
  248.         }
  249.         $phptype = $db->phptype;
  250.  
  251.         // columns to be created
  252.         $column = array();
  253.  
  254.         // max. value for scope (only used with MDB2 as backend)
  255.         $max_scope = 0;
  256.         
  257.         // indexes to be created
  258.         $indexes = array();
  259.         
  260.         // check the table name
  261.         $name_check = DB_Table_Manager::_validateTableName($table);
  262.         if (PEAR::isError($name_check)) {
  263.             return $name_check;
  264.         }
  265.         
  266.         
  267.         // -------------------------------------------------------------
  268.         // 
  269.         // validate each column mapping and build the individual
  270.         // definitions, and note column indexes as we go.
  271.         //
  272.         
  273.         if (is_null($column_set)) {
  274.             $column_set = array();
  275.         }
  276.         
  277.         foreach ($column_set as $colname => $val) {
  278.             
  279.             $colname = trim($colname);
  280.             
  281.             // check the column name
  282.             $name_check = DB_Table_Manager::_validateColumnName($colname);
  283.             if (PEAR::isError($name_check)) {
  284.                 return $name_check;
  285.             }
  286.             
  287.             
  288.             // prepare variables
  289.             $type    = (isset($val['type']))    ? $val['type']    : null;
  290.             $size    = (isset($val['size']))    ? $val['size']    : null;
  291.             $scope   = (isset($val['scope']))   ? $val['scope']   : null;
  292.             $require = (isset($val['require'])) ? $val['require'] : null;
  293.             $default = (isset($val['default'])) ? $val['default'] : null;
  294.  
  295.             if ($backend == 'mdb2') {
  296.  
  297.                 // get the declaration string
  298.                 $result = DB_Table_Manager::getDeclareMDB2($type,
  299.                     $size, $scope, $require, $default, $max_scope);
  300.  
  301.                 // did it work?
  302.                 if (PEAR::isError($result)) {
  303.                     $result->userinfo .= " ('$colname')";
  304.                     return $result;
  305.                 }
  306.  
  307.                 // add the declaration to the array of all columns
  308.                 $column[$colname] = $result;
  309.  
  310.             } else {
  311.  
  312.                 // get the declaration string
  313.                 $result = DB_Table_Manager::getDeclare($phptype, $type,
  314.                     $size, $scope, $require, $default);
  315.  
  316.                 // did it work?
  317.                 if (PEAR::isError($result)) {
  318.                     $result->userinfo .= " ('$colname')";
  319.                     return $result;
  320.                 }
  321.  
  322.                 // add the declaration to the array of all columns
  323.                 $column[] = "$colname $result";
  324.  
  325.             }
  326.  
  327.         }
  328.         
  329.         
  330.         // -------------------------------------------------------------
  331.         // 
  332.         // validate the indexes.
  333.         //
  334.         
  335.         if (is_null($index_set)) {
  336.             $index_set = array();
  337.         }
  338.  
  339.         $count_primary_keys = 0;
  340.  
  341.         foreach ($index_set as $idxname => $val) {
  342.             
  343.             list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
  344.  
  345.             $newIdxName = '';
  346.  
  347.             // check the index definition
  348.             $index_check = DB_Table_Manager::_validateIndexName($idxname,
  349.                 $table, $phptype, $type, $cols, $column_set, $newIdxName);
  350.             if (PEAR::isError($index_check)) {
  351.                 return $index_check;
  352.             }
  353.  
  354.             // check number of primary keys (only one is allowed)
  355.             if ($type == 'primary') {
  356.                 // SQLite does not support primary keys
  357.                 if ($phptype == 'sqlite') {
  358.                     return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIM_SQLITE);
  359.                 }
  360.                 $count_primary_keys++;
  361.             }
  362.             if ($count_primary_keys > 1) {
  363.                 return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIMARY);
  364.             }
  365.  
  366.             // create index entry
  367.             if ($backend == 'mdb2') {
  368.  
  369.                 // array with column names as keys
  370.                 $idx_cols = array();
  371.                 foreach ($cols as $col) {
  372.                     $idx_cols[$col] = array();
  373.                 }
  374.  
  375.                 switch ($type) {
  376.                     case 'primary':
  377.                         $indexes['primary'][$newIdxName] =
  378.                             array('fields'  => $idx_cols,
  379.                                   'primary' => true);
  380.                         break;
  381.                     case 'unique':
  382.                         $indexes['unique'][$newIdxName] =
  383.                             array('fields' => $idx_cols,
  384.                                   'unique' => true);
  385.                         break;
  386.                     case 'normal':
  387.                         $indexes['normal'][$newIdxName] =
  388.                             array('fields' => $idx_cols);
  389.                         break;
  390.                 }
  391.                 
  392.             } else {
  393.  
  394.                 $indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
  395.                     $type, $newIdxName, $table, $cols);
  396.  
  397.             }
  398.             
  399.         }
  400.         
  401.         
  402.         // -------------------------------------------------------------
  403.         // 
  404.         // now for the real action: create the table and indexes!
  405.         //
  406.         if ($backend == 'mdb2') {
  407.  
  408.             // save user defined 'decimal_places' option
  409.             $decimal_places = $db->getOption('decimal_places');
  410.             $db->setOption('decimal_places', $max_scope);
  411.  
  412.             // attempt to create the table
  413.             $result = $db->manager->createTable($table, $column);
  414.             // restore user defined 'decimal_places' option
  415.             $db->setOption('decimal_places', $decimal_places);
  416.             if (PEAR::isError($result)) {
  417.                 return $result;
  418.             }
  419.  
  420.         } else {
  421.  
  422.             // build the CREATE TABLE command
  423.             $cmd = "CREATE TABLE $table (\n\t";
  424.             $cmd .= implode(",\n\t", $column);
  425.             $cmd .= "\n)";
  426.  
  427.             // attempt to create the table
  428.             $result = $db->query($cmd);
  429.             if (PEAR::isError($result)) {
  430.                 return $result;
  431.             }
  432.  
  433.         }
  434.  
  435.         $result = DB_Table_Manager::_createIndexesAndContraints($db, $backend,
  436.                                                                 $table, $indexes);
  437.         if (PEAR::isError($result)) {
  438.             return $result;
  439.         }
  440.  
  441.         // we're done!
  442.         return true;
  443.     }
  444.  
  445.  
  446.    /**
  447.     * 
  448.     * Verify whether the table and columns exist, whether the columns
  449.     * have the right type and whether the indexes exist.
  450.     * 
  451.     * @static
  452.     * 
  453.     * @access public
  454.     * 
  455.     * @param object &$db A PEAR DB/MDB2 object.
  456.     * 
  457.     * @param string $table The table name to connect to in the database.
  458.     * 
  459.     * @param mixed $column_set A DB_Table $this->col array.
  460.     * 
  461.     * @param mixed $index_set A DB_Table $this->idx array.
  462.     * 
  463.     * @return mixed Boolean true if the verification was successful, and a
  464.     * PEAR_Error if verification failed.
  465.     * 
  466.     */
  467.  
  468.     function verify(&$db, $table, $column_set, $index_set)
  469.     {
  470.         if (is_subclass_of($db, 'db_common')) {
  471.             $backend = 'db';
  472.             $reverse =& $db;
  473.             $table_info_mode = DB_TABLEINFO_FULL;
  474.             $table_info_error = DB_ERROR_NEED_MORE_DATA;
  475.         } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
  476.             $backend = 'mdb2';
  477.             $reverse =& $this->db->loadModule('Reverse');
  478.             $table_info_mode = MDB2_TABLEINFO_FULL;
  479.             $table_info_error = MDB2_ERROR_NEED_MORE_DATA;
  480.         }
  481.         $phptype = $db->phptype;
  482.  
  483.         // check #1: does the table exist?
  484.  
  485.         // check the table name
  486.         $name_check = DB_Table_Manager::_validateTableName($table);
  487.         if (PEAR::isError($name_check)) {
  488.             return $name_check;
  489.         }
  490.  
  491.         // get table info
  492.         $tableInfo = $reverse->tableInfo($table, $table_info_mode);
  493.         if (PEAR::isError($tableInfo)) {
  494.             if ($tableInfo->getCode() == $table_info_error) {
  495.                 return DB_Table::throwError(
  496.                     DB_TABLE_ERR_VER_TABLE_MISSING,
  497.                     "(table='$table')"
  498.                 );
  499.             }
  500.             return $tableInfo;
  501.         }
  502.         $tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
  503.  
  504.         if (is_null($column_set)) {
  505.             $column_set = array();
  506.         }
  507.  
  508.         foreach ($column_set as $colname => $val) {
  509.             $colname = strtolower(trim($colname));
  510.             
  511.             // check the column name
  512.             $name_check = DB_Table_Manager::_validateColumnName($colname);
  513.             if (PEAR::isError($name_check)) {
  514.                 return $name_check;
  515.             }
  516.  
  517.             // check #2: do all columns exist?
  518.             $column_exists = DB_Table_Manager::_columnExists($colname,
  519.                 $tableInfoOrder, 'verify');
  520.             if (PEAR::isError($column_exists)) {
  521.                 return $column_exists;
  522.             }
  523.  
  524.             // check #3: do all columns have the right type?
  525.  
  526.             // check whether the column type is a known type
  527.             $type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
  528.             if (PEAR::isError($type_check)) {
  529.                 return $type_check;
  530.             }
  531.  
  532.             // check whether the column has the right type
  533.             $type_check = DB_Table_Manager::_checkColumnType($phptype,
  534.                 $colname, $val['type'], $tableInfoOrder, $tableInfo, 'verify');
  535.             if (PEAR::isError($type_check)) {
  536.                 return $type_check;
  537.             }
  538.  
  539.         }
  540.  
  541.         // check #4: do all indexes exist?
  542.         $table_indexes = DB_Table_Manager::getIndexes($db, $table);
  543.         if (PEAR::isError($table_indexes)) {
  544.             return $table_indexes;
  545.         }
  546.  
  547.         if (is_null($index_set)) {
  548.             $index_set = array();
  549.         }
  550.         
  551.         foreach ($index_set as $idxname => $val) {
  552.           
  553.             list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
  554.  
  555.             $newIdxName = '';
  556.  
  557.             // check the index definition
  558.             $index_check = DB_Table_Manager::_validateIndexName($idxname,
  559.                 $table, $phptype, $type, $cols, $column_set, $newIdxName);
  560.             if (PEAR::isError($index_check)) {
  561.                 return $index_check;
  562.             }
  563.  
  564.             // check whether the index has the right type and has all
  565.             // specified columns
  566.             $index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
  567.                 $type, $cols, $table_indexes, 'verify');
  568.             if (PEAR::isError($index_check)) {
  569.                 return $index_check;
  570.             }
  571.  
  572.         }
  573.  
  574.         return true;
  575.     }
  576.  
  577.  
  578.    /**
  579.     * 
  580.     * Alter columns and indexes of a table based on DB_Table column and index
  581.     * arrays.
  582.     * 
  583.     * @static
  584.     * 
  585.     * @access public
  586.     * 
  587.     * @param object &$db A PEAR DB/MDB2 object.
  588.     * 
  589.     * @param string $table The table name to connect to in the database.
  590.     * 
  591.     * @param mixed $column_set A DB_Table $this->col array.
  592.     * 
  593.     * @param mixed $index_set A DB_Table $this->idx array.
  594.     * 
  595.     * @return bool|object True if altering was successful or a PEAR_Error on
  596.     * failure.
  597.     * 
  598.     */
  599.  
  600.     function alter(&$db, $table, $column_set, $index_set)
  601.     {
  602.         $phptype = $db->phptype;
  603.  
  604.         if (is_subclass_of($db, 'db_common')) {
  605.             $backend = 'db';
  606.             $reverse =& $db;
  607.             // workaround for missing index and constraint information methods
  608.             // in PEAR::DB ==> use adopted code from MDB2's driver classes
  609.             require_once 'DB/Table/Manager/' . $phptype . '.php';
  610.             $classname = 'DB_Table_Manager_' . $phptype;
  611.             $dbtm =& new $classname();
  612.             $dbtm->_db =& $db;  // pass database instance to the 'workaround' class
  613.             $manager =& $dbtm;
  614.             $table_info_mode = DB_TABLEINFO_FULL;
  615.             $ok_const = DB_OK;
  616.         } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
  617.             $backend = 'mdb2';
  618.             $db->loadModule('Reverse');
  619.             $manager =& $db->manager;
  620.             $reverse =& $db->reverse;
  621.             $table_info_mode = MDB2_TABLEINFO_FULL;
  622.             $ok_const = MDB2_OK;
  623.         }
  624.  
  625.         // get table info
  626.         $tableInfo = $reverse->tableInfo($table, $table_info_mode);
  627.         if (PEAR::isError($tableInfo)) {
  628.             return $tableInfo;
  629.         }
  630.         $tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
  631.  
  632.         // emulate MDB2 Reverse extension for PEAR::DB as backend
  633.         if (is_subclass_of($db, 'db_common')) {
  634.             $reverse =& $dbtm;
  635.         }
  636.  
  637.         // check (and alter) columns
  638.         if (is_null($column_set)) {
  639.             $column_set = array();
  640.         }
  641.  
  642.         foreach ($column_set as $colname => $val) {
  643.             $colname = strtolower(trim($colname));
  644.             
  645.             // check the column name
  646.             $name_check = DB_Table_Manager::_validateColumnName($colname);
  647.             if (PEAR::isError($name_check)) {
  648.                 return $name_check;
  649.             }
  650.  
  651.             // check the column's existence
  652.             $column_exists = DB_Table_Manager::_columnExists($colname,
  653.                 $tableInfoOrder, 'alter');
  654.             if (PEAR::isError($column_exists)) {
  655.                 return $column_exists;
  656.             }
  657.             if ($column_exists === false) {  // add the column
  658.                 $definition = DB_Table_Manager::_getColumnDefinition($backend,
  659.                     $phptype, $val);
  660.                 if (PEAR::isError($definition)) {
  661.                     return $definition;
  662.                 }
  663.                 $changes = array('add' => array($colname => $definition));
  664.                 if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
  665.                     echo "(alter) New table field will be added ($colname):\n";
  666.                     var_dump($changes);
  667.                     echo "\n";
  668.                 }
  669.                 $result = $manager->alterTable($table, $changes, false);
  670.                 if (PEAR::isError($result)) {
  671.                     return $result;
  672.                 }
  673.                 continue;
  674.             }
  675.  
  676.             // check whether the column type is a known type
  677.             $type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
  678.             if (PEAR::isError($type_check)) {
  679.                 return $type_check;
  680.             }
  681.  
  682.             // check whether the column has the right type
  683.             $type_check = DB_Table_Manager::_checkColumnType($phptype,
  684.                 $colname, $val['type'], $tableInfoOrder, $tableInfo, 'alter');
  685.             if (PEAR::isError($type_check)) {
  686.                 return $type_check;
  687.             }
  688.             if ($type_check === false) {  // change the column type
  689.                 $definition = DB_Table_Manager::_getColumnDefinition($backend,
  690.                     $phptype, $val);
  691.                 if (PEAR::isError($definition)) {
  692.                     return $definition;
  693.                 }
  694.                 $changes = array('change' =>
  695.                     array($colname => array('type' => null,
  696.                                             'definition' => $definition)));
  697.                 if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
  698.                     echo "(alter) Table field's type will be changed ($colname):\n";
  699.                     var_dump($changes);
  700.                     echo "\n";
  701.                 }
  702.                 $result = $manager->alterTable($table, $changes, false);
  703.                 if (PEAR::isError($result)) {
  704.                     return $result;
  705.                 }
  706.                 continue;
  707.             }
  708.  
  709.         }
  710.  
  711.         // get information about indexes / constraints
  712.         $table_indexes = DB_Table_Manager::getIndexes($db, $table);
  713.         if (PEAR::isError($table_indexes)) {
  714.             return $table_indexes;
  715.         }
  716.  
  717.         // check (and alter) indexes / constraints
  718.         if (is_null($index_set)) {
  719.             $index_set = array();
  720.         }
  721.         
  722.         foreach ($index_set as $idxname => $val) {
  723.           
  724.             list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
  725.  
  726.             $newIdxName = '';
  727.  
  728.             // check the index definition
  729.             $index_check = DB_Table_Manager::_validateIndexName($idxname,
  730.                 $table, $phptype, $type, $cols, $column_set, $newIdxName);
  731.             if (PEAR::isError($index_check)) {
  732.                 return $index_check;
  733.             }
  734.  
  735.             // check whether the index has the right type and has all
  736.             // specified columns
  737.             $index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
  738.                 $type, $cols, $table_indexes, 'alter');
  739.             if (PEAR::isError($index_check)) {
  740.                 return $index_check;
  741.             }
  742.             if ($index_check === false) {  // (1) drop wrong index/constraint
  743.                                            // (2) add right index/constraint
  744.                 if ($backend == 'mdb2') {
  745.                     // save user defined 'idxname_format' option
  746.                     $idxname_format = $db->getOption('idxname_format');
  747.                     $db->setOption('idxname_format', '%s');
  748.                 }
  749.                 // drop index/constraint only if it exists
  750.                 foreach (array('normal', 'unique', 'primary') as $idx_type) {
  751.                     if (array_key_exists(strtolower($newIdxName),
  752.                                          $table_indexes[$idx_type])) {
  753.                         if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
  754.                             echo "(alter) Index/constraint will be deleted (name: '$newIdxName', type: '$idx_type').\n";
  755.                         }
  756.                         if ($idx_type == 'normal') {
  757.                             $result = $manager->dropIndex($table, $newIdxName);
  758.                         } else {
  759.                             $result = $manager->dropConstraint($table, $newIdxName);
  760.                         }
  761.                         if (PEAR::isError($result)) {
  762.                             if ($backend == 'mdb2') {
  763.                                 // restore user defined 'idxname_format' option
  764.                                 $db->setOption('idxname_format', $idxname_format);
  765.                             }
  766.                             return $result;
  767.                         }
  768.                         break;
  769.                     }
  770.                 }
  771.  
  772.                 // prepare index/constraint definition
  773.                 $indexes = array();
  774.                 if ($backend == 'mdb2') {
  775.  
  776.                     // array with column names as keys
  777.                     $idx_cols = array();
  778.                     foreach ($cols as $col) {
  779.                         $idx_cols[$col] = array();
  780.                     }
  781.  
  782.                     switch ($type) {
  783.                         case 'primary':
  784.                             $indexes['primary'][$newIdxName] =
  785.                                 array('fields'  => $idx_cols,
  786.                                       'primary' => true);
  787.                             break;
  788.                         case 'unique':
  789.                             $indexes['unique'][$newIdxName] =
  790.                                 array('fields' => $idx_cols,
  791.                                       'unique' => true);
  792.                             break;
  793.                         case 'normal':
  794.                             $indexes['normal'][$newIdxName] =
  795.                                 array('fields' => $idx_cols);
  796.                             break;
  797.                     }
  798.  
  799.                 } else {
  800.  
  801.                     $indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
  802.                         $type, $newIdxName, $table, $cols);
  803.  
  804.                 }
  805.  
  806.                 // create index/constraint
  807.                 if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
  808.                     echo "(alter) New index/constraint will be created (name: '$newIdxName', type: '$type'):\n";
  809.                     var_dump($indexes);
  810.                     echo "\n";
  811.                 }
  812.                 $result = DB_Table_Manager::_createIndexesAndContraints(
  813.                     $db, $backend, $table, $indexes);
  814.                 if ($backend == 'mdb2') {
  815.                     // restore user defined 'idxname_format' option
  816.                     $db->setOption('idxname_format', $idxname_format);
  817.                 }
  818.                 if (PEAR::isError($result)) {
  819.                     return $result;
  820.                 }
  821.  
  822.                 continue;
  823.             }
  824.  
  825.         }
  826.  
  827.         return true;
  828.     }
  829.  
  830.  
  831.    /**
  832.     * 
  833.     * Check whether a table exists.
  834.     * 
  835.     * @static
  836.     * 
  837.     * @access public
  838.     * 
  839.     * @param object &$db A PEAR DB/MDB2 object.
  840.     * 
  841.     * @param string $table The table name that should be checked.
  842.     * 
  843.     * @return bool|object True if the table exists, false if not, or a
  844.     * PEAR_Error on failure.
  845.     * 
  846.     */
  847.  
  848.     function tableExists(&$db, $table)
  849.     {
  850.         if (is_subclass_of($db, 'db_common')) {
  851.             $list = $db->getListOf('tables');
  852.         } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
  853.             $db->loadModule('Manager');
  854.             $list = $db->manager->listTables();
  855.         }
  856.         if (PEAR::isError($list)) {
  857.             return $list;
  858.         }
  859.         array_walk($list, create_function('&$value,$key',
  860.                                           '$value = trim(strtolower($value));'));
  861.         return in_array(strtolower($table), $list);
  862.     }
  863.  
  864.  
  865.    /**
  866.     * 
  867.     * Get the column declaration string for a DB_Table column.
  868.     * 
  869.     * @static
  870.     * 
  871.     * @access public
  872.     * 
  873.     * @param string $phptype The DB/MDB2 phptype key.
  874.     * 
  875.     * @param string $coltype The DB_Table column type.
  876.     * 
  877.     * @param int $size The size for the column (needed for string and
  878.     * decimal).
  879.     * 
  880.     * @param int $scope The scope for the column (needed for decimal).
  881.     * 
  882.     * @param bool $require True if the column should be NOT NULL, false
  883.     * allowed to be NULL.
  884.     * 
  885.     * @param string $default The SQL calculation for a default value.
  886.     * 
  887.     * @return string|object A declaration string on success, or a
  888.     * PEAR_Error on failure.
  889.     * 
  890.     */
  891.  
  892.     function getDeclare($phptype, $coltype, $size = null, $scope = null,
  893.         $require = null, $default = null)
  894.     {
  895.         // validate char/varchar/decimal type declaration
  896.         $validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
  897.                                                                  $scope);
  898.         if (PEAR::isError($validation)) {
  899.             return $validation;
  900.         }
  901.         
  902.         // map of column types and declarations for this RDBMS
  903.         $map = $GLOBALS['_DB_TABLE']['type'][$phptype];
  904.         
  905.         // is it a recognized column type?
  906.         $types = array_keys($map);
  907.         if (! in_array($coltype, $types)) {
  908.             return DB_Table::throwError(
  909.                 DB_TABLE_ERR_DECLARE_TYPE,
  910.                 "('$coltype')"
  911.             );
  912.         }
  913.         
  914.         // basic declaration
  915.         switch ($coltype) {
  916.     
  917.         case 'char':
  918.         case 'varchar':
  919.             $declare = $map[$coltype] . "($size)";
  920.             break;
  921.         
  922.         case 'decimal':
  923.             $declare = $map[$coltype] . "($size,$scope)";
  924.             break;
  925.         
  926.         default:
  927.             $declare = $map[$coltype];
  928.             break;
  929.         
  930.         }
  931.         
  932.         // set the "NULL"/"NOT NULL" portion
  933.         $null = ' NULL';
  934.         if ($phptype == 'ibase') {  // Firebird does not like 'NULL'
  935.             $null = '';             // in CREATE TABLE
  936.         }
  937.         if ($phptype == 'pgsql') {  // PostgreSQL does not like 'NULL'
  938.             $null = '';             // in ALTER TABLE
  939.         }
  940.         $declare .= ($require) ? ' NOT NULL' : $null;
  941.         
  942.         // set the "DEFAULT" portion
  943.         if ($default) {
  944.             switch ($coltype) {        
  945.                 case 'char':
  946.                 case 'varchar':
  947.                 case 'clob':
  948.                     $declare .= " DEFAULT '$default'";
  949.                     break;
  950.  
  951.                 default:
  952.                     $declare .= " DEFAULT $default";
  953.                     break;
  954.             }
  955.         }
  956.         
  957.         // done
  958.         return $declare;
  959.     }
  960.  
  961.  
  962.    /**
  963.     * 
  964.     * Get the column declaration string for a DB_Table column.
  965.     * 
  966.     * @static
  967.     * 
  968.     * @access public
  969.     * 
  970.     * @param string $coltype The DB_Table column type.
  971.     * 
  972.     * @param int $size The size for the column (needed for string and
  973.     * decimal).
  974.     * 
  975.     * @param int $scope The scope for the column (needed for decimal).
  976.     * 
  977.     * @param bool $require True if the column should be NOT NULL, false
  978.     * allowed to be NULL.
  979.     * 
  980.     * @param string $default The SQL calculation for a default value.
  981.     * 
  982.     * @param int $max_scope The maximal scope for all table column
  983.     * (pass-by-reference).
  984.     * 
  985.     * @return string|object A MDB2 column definition array on success, or a
  986.     * PEAR_Error on failure.
  987.     * 
  988.     */
  989.  
  990.     function getDeclareMDB2($coltype, $size = null, $scope = null,
  991.         $require = null, $default = null, &$max_scope)
  992.     {
  993.         // validate char/varchar/decimal type declaration
  994.         $validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
  995.                                                                  $scope);
  996.         if (PEAR::isError($validation)) {
  997.             return $validation;
  998.         }
  999.  
  1000.         // map of MDB2 column types
  1001.         $map = $GLOBALS['_DB_TABLE']['mdb2_type'];
  1002.         
  1003.         // is it a recognized column type?
  1004.         $types = array_keys($map);
  1005.         if (! in_array($coltype, $types)) {
  1006.             return DB_Table::throwError(
  1007.                 DB_TABLE_ERR_DECLARE_TYPE,
  1008.                 "('$coltype')"
  1009.             );
  1010.         }
  1011.  
  1012.         // build declaration array
  1013.         $new_column = array(
  1014.             'type'    => $map[$coltype],
  1015.             'notnull' => $require
  1016.         );
  1017.  
  1018.         if ($size) {
  1019.             $new_column['length'] = $size;
  1020.         }
  1021.  
  1022.         // determine integer length to be used in MDB2
  1023.         if (in_array($coltype, array('smallint', 'integer', 'bigint'))) {
  1024.             switch ($coltype) {
  1025.                 case 'smallint':
  1026.                     $new_column['length'] = 2;
  1027.                     break;
  1028.                 case 'integer':
  1029.                     $new_column['length'] = 4;
  1030.                     break;
  1031.                 case 'bigint':
  1032.                     $new_column['length'] = 5;
  1033.                     break;
  1034.             }
  1035.         }
  1036.  
  1037.         if ($scope) {
  1038.             $max_scope = max($max_scope, $scope);
  1039.         }
  1040.  
  1041.         if ($default) {
  1042.             $new_column['default'] = $default;
  1043.         }
  1044.  
  1045.         return $new_column;
  1046.     }
  1047.  
  1048.  
  1049.    /**
  1050.     * 
  1051.     * Get the index declaration string for a DB_Table index.
  1052.     * 
  1053.     * @static
  1054.     * 
  1055.     * @access public
  1056.     * 
  1057.     * @param string $phptype The DB phptype key.
  1058.     * 
  1059.     * @param string $type The index type.
  1060.     * 
  1061.     * @param string $idxname The index name.
  1062.     * 
  1063.     * @param string $table The table name.
  1064.     * 
  1065.     * @param mixed $cols Array with the column names for the index.
  1066.     * 
  1067.     * @return string A declaration string.
  1068.     * 
  1069.     */
  1070.  
  1071.     function getDeclareForIndex($phptype, $type, $idxname, $table, $cols)
  1072.     {
  1073.         // string of column names
  1074.         $colstring = implode(', ', $cols);
  1075.  
  1076.         switch ($type) {
  1077.  
  1078.             case 'primary':
  1079.                 switch ($phptype) {
  1080.                     case 'ibase':
  1081.                     case 'oci8':
  1082.                     case 'pgsql':
  1083.                         $declare  = "ALTER TABLE $table ADD";
  1084.                         $declare .= " CONSTRAINT $idxname";
  1085.                         $declare .= " PRIMARY KEY ($colstring)";
  1086.                         break;
  1087.                     case 'mysql':
  1088.                     case 'mysqli':
  1089.                         $declare  = "ALTER TABLE $table ADD PRIMARY KEY";
  1090.                         $declare .= " ($colstring)";
  1091.                         break;
  1092.                     case 'sqlite':
  1093.                         // currently not possible
  1094.                         break;
  1095.                 }
  1096.                 break;
  1097.  
  1098.             case 'unique':
  1099.                 $declare = "CREATE UNIQUE INDEX $idxname ON $table ($colstring)";
  1100.                 break;
  1101.  
  1102.             case 'normal':
  1103.                 $declare = "CREATE INDEX $idxname ON $table ($colstring)";
  1104.                 break;
  1105.  
  1106.         }
  1107.         
  1108.         return $declare;
  1109.     }
  1110.  
  1111.  
  1112.    /**
  1113.     * 
  1114.     * Return the definition array for a column.
  1115.     * 
  1116.     * @access private
  1117.     * 
  1118.     * @param string $backend The name of the backend ('db' or 'mdb2').
  1119.     * 
  1120.     * @param string $phptype The DB/MDB2 phptype key.
  1121.     * 
  1122.     * @param mixed $column A single DB_Table column definition array.
  1123.     * 
  1124.     * @return mixed|object Declaration string (DB), declaration array (MDB2) or a
  1125.     * PEAR_Error with a description about the invalidity, otherwise.
  1126.     * 
  1127.     */
  1128.  
  1129.     function _getColumnDefinition($backend, $phptype, $column)
  1130.     {
  1131.         static $max_scope;
  1132.  
  1133.         // prepare variables
  1134.         $type    = (isset($column['type']))    ? $column['type']    : null;
  1135.         $size    = (isset($column['size']))    ? $column['size']    : null;
  1136.         $scope   = (isset($column['scope']))   ? $column['scope']   : null;
  1137.         $require = (isset($column['require'])) ? $column['require'] : null;
  1138.         $default = (isset($column['default'])) ? $column['default'] : null;
  1139.  
  1140.         if ($backend == 'db') {
  1141.             return DB_Table_Manager::getDeclare($phptype, $type,
  1142.                     $size, $scope, $require, $default);
  1143.         } else {
  1144.             return DB_Table_Manager::getDeclareMDB2($type,
  1145.                     $size, $scope, $require, $default, $max_scope);
  1146.         }
  1147.     }
  1148.  
  1149.  
  1150.    /**
  1151.     * 
  1152.     * Check char/varchar/decimal type declarations for validity.
  1153.     * 
  1154.     * @access private
  1155.     * 
  1156.     * @param string $coltype The DB_Table column type.
  1157.     * 
  1158.     * @param int $size The size for the column (needed for string and
  1159.     * decimal).
  1160.     * 
  1161.     * @param int $scope The scope for the column (needed for decimal).
  1162.     * 
  1163.     * @return bool|object Boolean true if the type declaration is valid or a
  1164.     * PEAR_Error with a description about the invalidity, otherwise.
  1165.     * 
  1166.     */
  1167.  
  1168.     function _validateTypeDeclaration($coltype, $size, $scope)
  1169.     {
  1170.         // validate char and varchar: does it have a size?
  1171.         if (($coltype == 'char' || $coltype == 'varchar') &&
  1172.             ($size < 1 || $size > 255) ) {
  1173.             return DB_Table::throwError(
  1174.                 DB_TABLE_ERR_DECLARE_STRING,
  1175.                 "(size='$size')"
  1176.             );
  1177.         }
  1178.         
  1179.         // validate decimal: does it have a size and scope?
  1180.         if ($coltype == 'decimal' &&
  1181.             ($size < 1 || $size > 255 || $scope < 0 || $scope > $size)) {
  1182.             return DB_Table::throwError(
  1183.                 DB_TABLE_ERR_DECLARE_DECIMAL,
  1184.                 "(size='$size' scope='$scope')"
  1185.             );
  1186.         }
  1187.  
  1188.         return true;
  1189.     }
  1190.  
  1191.  
  1192.    /**
  1193.     * 
  1194.     * Check a table name for validity.
  1195.     * 
  1196.     * @access private
  1197.     * 
  1198.     * @param string $tablename The table name.
  1199.     * 
  1200.     * @return bool|object Boolean true if the table name is valid or a
  1201.     * PEAR_Error with a description about the invalidity, otherwise.
  1202.     * 
  1203.     */
  1204.  
  1205.     function _validateTableName($tablename)
  1206.     {
  1207.         // is the table name too long?
  1208.         if (strlen($tablename) > 30) {
  1209.             return DB_Table::throwError(
  1210.                 DB_TABLE_ERR_TABLE_STRLEN,
  1211.                 " ('$tablename')"
  1212.             );
  1213.         }
  1214.  
  1215.         return true;
  1216.     }
  1217.  
  1218.  
  1219.    /**
  1220.     * 
  1221.     * Check a column name for validity.
  1222.     * 
  1223.     * @access private
  1224.     * 
  1225.     * @param string $colname The column name.
  1226.     * 
  1227.     * @return bool|object Boolean true if the column name is valid or a
  1228.     * PEAR_Error with a description about the invalidity, otherwise.
  1229.     * 
  1230.     */
  1231.  
  1232.     function _validateColumnName($colname)
  1233.     {
  1234.         // column name cannot be a reserved keyword
  1235.         $reserved = in_array(
  1236.             strtoupper($colname),
  1237.             $GLOBALS['_DB_TABLE']['reserved']
  1238.         );
  1239.  
  1240.         if ($reserved) {
  1241.             return DB_Table::throwError(
  1242.                 DB_TABLE_ERR_DECLARE_COLNAME,
  1243.                 " ('$colname')"
  1244.             );
  1245.         }
  1246.  
  1247.         // column name must be no longer than 30 chars
  1248.         if (strlen($colname) > 30) {
  1249.             return DB_Table::throwError(
  1250.                 DB_TABLE_ERR_DECLARE_STRLEN,
  1251.                 "('$colname')"
  1252.             );
  1253.         }
  1254.  
  1255.         return true;
  1256.     }
  1257.  
  1258.  
  1259.    /**
  1260.     * 
  1261.     * Check whether a column exists.
  1262.     * 
  1263.     * @access private
  1264.     * 
  1265.     * @param string $colname The column name.
  1266.     * 
  1267.     * @param mixed $tableInfoOrder Array with columns in the table (result
  1268.     * from tableInfo(), shortened to key 'order').
  1269.     * 
  1270.     * @param string $mode The name of the calling function, this can be either
  1271.     * 'verify' or 'alter'.
  1272.     * 
  1273.     * @return bool|object Boolean true if the column exists.
  1274.     * Otherwise, either boolean false (case 'alter') or a PEAR_Error
  1275.     * (case 'verify').
  1276.     * 
  1277.     */
  1278.  
  1279.     function _columnExists($colname, $tableInfoOrder, $mode)
  1280.     {
  1281.         if (array_key_exists($colname, $tableInfoOrder)) {
  1282.             return true;
  1283.         }
  1284.  
  1285.         switch ($mode) {
  1286.  
  1287.             case 'alter':
  1288.                 return false;
  1289.  
  1290.             case 'verify':
  1291.                 return DB_Table::throwError(
  1292.                     DB_TABLE_ERR_VER_COLUMN_MISSING,
  1293.                     "(column='$colname')"
  1294.                 );
  1295.  
  1296.         }
  1297.     }
  1298.  
  1299.  
  1300.    /**
  1301.     * 
  1302.     * Check whether a column type is a known type.
  1303.     * 
  1304.     * @access private
  1305.     * 
  1306.     * @param string $phptype The DB/MDB2 phptype key.
  1307.     * 
  1308.     * @param string $type The column type.
  1309.     * 
  1310.     * @return bool|object Boolean true if the column type is a known type
  1311.     * or a PEAR_Error, otherwise.
  1312.     * 
  1313.     */
  1314.  
  1315.     function _validateColumnType($phptype, $type)
  1316.     {
  1317.         // map of valid types for the current RDBMS
  1318.         $map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
  1319.  
  1320.         // is it a recognized column type?
  1321.         $types = array_keys($map);
  1322.         if (!in_array($type, $types)) {
  1323.             return DB_Table::throwError(
  1324.                 DB_TABLE_ERR_DECLARE_TYPE,
  1325.                 "('" . $type . "')"
  1326.             );
  1327.         }
  1328.  
  1329.         return true;
  1330.     }
  1331.  
  1332.  
  1333.    /**
  1334.     * 
  1335.     * Check whether a column has the right type.
  1336.     * 
  1337.     * @access private
  1338.     * 
  1339.     * @param string $phptype The DB/MDB2 phptype key.
  1340.     *
  1341.     * @param string $colname The column name.
  1342.     * 
  1343.     * @param string $coltype The column type.
  1344.     * 
  1345.     * @param mixed $tableInfoOrder Array with columns in the table (result
  1346.     * from tableInfo(), shortened to key 'order').
  1347.     * 
  1348.     * @param mixed $tableInfo Array with information about the table (result
  1349.     * from tableInfo()).
  1350.     * 
  1351.     * @param string $mode The name of the calling function, this can be either
  1352.     * 'verify' or 'alter'.
  1353.     * 
  1354.     * @return bool|object Boolean true if the column has the right type.
  1355.     * Otherwise, either boolean false (case 'alter') or a PEAR_Error
  1356.     * (case 'verify').
  1357.     * 
  1358.     */
  1359.  
  1360.     function _checkColumnType($phptype, $colname, $coltype, $tableInfoOrder,
  1361.         $tableInfo, $mode)
  1362.     {
  1363.         // map of valid types for the current RDBMS
  1364.         $map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
  1365.  
  1366.         // get the column type from tableInfo()
  1367.         $colindex = $tableInfoOrder[$colname];
  1368.         $type = strtolower($tableInfo[$colindex]['type']);
  1369.  
  1370.         // workaround for possibly wrong detected column type (taken from MDB2)
  1371.         if ($type == 'unknown' && ($phptype == 'mysql' || $phptype == 'mysqli')) {
  1372.             $type = 'decimal';
  1373.         }
  1374.  
  1375.         // strip size information (e.g. NUMERIC(9,2) => NUMERIC) if given
  1376.         if (($pos = strpos($type, '(')) !== false) {
  1377.             $type = substr($type, 0, $pos);
  1378.         }
  1379.  
  1380.         // is the type valid for the given DB_Table column type?
  1381.         if (in_array($type, (array)$map[$coltype])) {
  1382.             return true;
  1383.         }
  1384.  
  1385.         switch ($mode) {
  1386.  
  1387.             case 'alter':
  1388.                 return false;
  1389.  
  1390.             case 'verify':
  1391.                 return DB_Table::throwError(
  1392.                     DB_TABLE_ERR_VER_COLUMN_TYPE,
  1393.                     "(column='$colname', type='$type')"
  1394.                 );
  1395.  
  1396.         }
  1397.     }
  1398.  
  1399.  
  1400.    /**
  1401.     * 
  1402.     * Return the index type and the columns belonging to this index.
  1403.     * 
  1404.     * @access private
  1405.     * 
  1406.     * @param mixed $idx_def The index definition.
  1407.     * 
  1408.     * @return mixed Array with the index type and the columns belonging to
  1409.     * this index.
  1410.     * 
  1411.     */
  1412.  
  1413.     function _getIndexTypeAndColumns($idx_def, $idxname)
  1414.     {
  1415.         $type = '';
  1416.         $cols = '';
  1417.         if (is_string($idx_def)) {
  1418.             // shorthand for index names: colname => index_type
  1419.             $type = trim($idx_def);
  1420.             $cols = trim($idxname);
  1421.         } elseif (is_array($idx_def)) {
  1422.             // normal: index_name => array('type' => ..., 'cols' => ...)
  1423.             $type = (isset($idx_def['type'])) ? $idx_def['type'] : 'normal';
  1424.             $cols = (isset($idx_def['cols'])) ? $idx_def['cols'] : null;
  1425.         }
  1426.  
  1427.         return array($type, $cols);
  1428.     }
  1429.  
  1430.  
  1431.    /**
  1432.     * 
  1433.     * Check an index name for validity.
  1434.     * 
  1435.     * @access private
  1436.     * 
  1437.     * @param string $idxname The index name.
  1438.     * 
  1439.     * @param string $table The table name.
  1440.     * 
  1441.     * @param string $phptype The DB/MDB2 phptype key.
  1442.     * 
  1443.     * @param string $type The index type.
  1444.     * 
  1445.     * @param mixed $cols The column names for the index. Will become an array
  1446.     * if it is not an array.
  1447.     * 
  1448.     * @param mixed $column_set A DB_Table $this->col array.
  1449.     * 
  1450.     * @param string $newIdxName The new index name (prefixed with the table
  1451.     * name, suffixed with '_idx').
  1452.     * 
  1453.     * @return bool|object Boolean true if the index name is valid or a
  1454.     * PEAR_Error with a description about the invalidity, otherwise.
  1455.     * 
  1456.     */
  1457.  
  1458.     function _validateIndexName($idxname, $table, $phptype, $type, &$cols,
  1459.                                 $column_set, &$newIdxName)
  1460.     {
  1461.         // index name cannot be a reserved keyword
  1462.         $reserved = in_array(
  1463.             strtoupper($idxname),
  1464.             $GLOBALS['_DB_TABLE']['reserved']
  1465.         );
  1466.  
  1467.         if ($reserved && !($type == 'primary' && $idxname == 'PRIMARY')) {
  1468.             return DB_Table::throwError(
  1469.                 DB_TABLE_ERR_DECLARE_IDXNAME,
  1470.                 "('$idxname')"
  1471.             );
  1472.         }
  1473.  
  1474.         // are there any columns for the index?
  1475.         if (! $cols) {
  1476.             return DB_Table::throwError(
  1477.                 DB_TABLE_ERR_IDX_NO_COLS,
  1478.                 "('$idxname')"
  1479.             );
  1480.         }
  1481.  
  1482.         // are there any CLOB columns, or any columns that are not
  1483.         // in the schema?
  1484.         settype($cols, 'array');
  1485.         $valid_cols = array_keys($column_set);
  1486.         foreach ($cols as $colname) {
  1487.  
  1488.             if (! in_array($colname, $valid_cols)) {
  1489.                 return DB_Table::throwError(
  1490.                     DB_TABLE_ERR_IDX_COL_UNDEF,
  1491.                     "'$idxname' ('$colname')"
  1492.                 );
  1493.             }
  1494.  
  1495.             if ($column_set[$colname]['type'] == 'clob') {
  1496.                 return DB_Table::throwError(
  1497.                     DB_TABLE_ERR_IDX_COL_CLOB,
  1498.                     "'$idxname' ('$colname')"
  1499.                 );
  1500.             }
  1501.  
  1502.         }
  1503.  
  1504.         // we prefix all index names with the table name,
  1505.         // and suffix all index names with '_idx'.  this
  1506.         // is to soothe PostgreSQL, which demands that index
  1507.         // names not collide, even when they indexes are on
  1508.         // different tables.
  1509.         $newIdxName = $table . '_' . $idxname . '_idx';
  1510.  
  1511.         // MySQL requires the primary key to be named 'primary', therefore let's
  1512.         // ignore the user defined name
  1513.         if (($phptype == 'mysql' || $phptype == 'mysqli') && $type == 'primary') {
  1514.             $newIdxName = 'primary';
  1515.         }
  1516.             
  1517.         // now check the length; must be under 30 chars to
  1518.         // soothe Oracle.
  1519.         if (strlen($newIdxName) > 30) {
  1520.             return DB_Table::throwError(
  1521.                 DB_TABLE_ERR_IDX_STRLEN,
  1522.                 "'$idxname' ('$newIdxName')"
  1523.             );
  1524.         }
  1525.  
  1526.         // check index type
  1527.         if ($type != 'primary' && $type != 'unique' && $type != 'normal') {
  1528.             return DB_Table::throwError(
  1529.                 DB_TABLE_ERR_IDX_TYPE,
  1530.                 "'$idxname' ('$type')"
  1531.             );
  1532.         }
  1533.  
  1534.         return true;
  1535.     }
  1536.  
  1537.  
  1538.    /**
  1539.     * 
  1540.     * Return all indexes for a table.
  1541.     * 
  1542.     * @access public
  1543.     * 
  1544.     * @param object &$db A PEAR DB/MDB2 object.
  1545.     * 
  1546.     * @param string $table The table name.
  1547.     * 
  1548.     * @return mixed Array with all indexes or a PEAR_Error when an error
  1549.     * occured.
  1550.     * 
  1551.     */
  1552.  
  1553.     function getIndexes(&$db, $table)
  1554.     {
  1555.         if (is_subclass_of($db, 'db_common')) {
  1556.             $backend = 'db';
  1557.             // workaround for missing index and constraint information methods
  1558.             // in PEAR::DB ==> use adopted code from MDB2's driver classes
  1559.             require_once 'DB/Table/Manager/' . $db->phptype . '.php';
  1560.             $classname = 'DB_Table_Manager_' . $db->phptype;
  1561.             $dbtm =& new $classname();
  1562.             $dbtm->_db =& $db;  // pass database instance to the 'workaround' class
  1563.             $manager =& $dbtm;
  1564.             $reverse =& $dbtm;
  1565.         } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
  1566.             $backend = 'mdb2';
  1567.             $manager =& $db->manager;
  1568.             $reverse =& $db->reverse;
  1569.         }
  1570.  
  1571.         $indexes = array('normal'  => array(),
  1572.                          'primary' => array(),
  1573.                          'unique'  => array()
  1574.                         );
  1575.  
  1576.         // save user defined 'idxname_format' option (MDB2 only)
  1577.         if ($backend == 'mdb2') {
  1578.             $idxname_format = $db->getOption('idxname_format');
  1579.             $db->setOption('idxname_format', '%s');
  1580.         }
  1581.  
  1582.         // get table constraints
  1583.         $table_indexes_tmp = $manager->listTableConstraints($table);
  1584.         if (PEAR::isError($table_indexes_tmp)) {
  1585.             // restore user defined 'idxname_format' option (MDB2 only)
  1586.             if ($backend == 'mdb2') {
  1587.                $db->setOption('idxname_format', $idxname_format);
  1588.             }
  1589.             return $table_indexes_tmp;
  1590.         }
  1591.  
  1592.         // get fields of table constraints
  1593.         foreach ($table_indexes_tmp as $table_idx_tmp) {
  1594.             $index_fields = $reverse->getTableConstraintDefinition($table,
  1595.                                                               $table_idx_tmp);
  1596.             if (PEAR::isError($index_fields)) {
  1597.                 // restore user defined 'idxname_format' option (MDB2 only)
  1598.                 if ($backend == 'mdb2') {
  1599.                     $db->setOption('idxname_format', $idxname_format);
  1600.                 }
  1601.                 return $index_fields;
  1602.             }
  1603.             // get the first key of $index_fields that has boolean true value
  1604.             foreach ($index_fields as $index_type => $value) {
  1605.                 if ($value === true) {
  1606.                     break;
  1607.                 }
  1608.             }
  1609.             $indexes[$index_type][$table_idx_tmp] = array_keys($index_fields['fields']);
  1610.         }
  1611.  
  1612.         // get table indexes
  1613.         $table_indexes_tmp = $manager->listTableIndexes($table);
  1614.         if (PEAR::isError($table_indexes_tmp)) {
  1615.             // restore user defined 'idxname_format' option (MDB2 only)
  1616.             if ($backend == 'mdb2') {
  1617.                 $db->setOption('idxname_format', $idxname_format);
  1618.             }
  1619.             return $table_indexes_tmp;
  1620.         }
  1621.  
  1622.         // get fields of table indexes
  1623.         foreach ($table_indexes_tmp as $table_idx_tmp) {
  1624.             $index_fields = $reverse->getTableIndexDefinition($table,
  1625.                                                          $table_idx_tmp);
  1626.             if (PEAR::isError($index_fields)) {
  1627.                 // restore user defined 'idxname_format' option (MDB2 only)
  1628.                 if ($backend == 'mdb2') {
  1629.                     $db->setOption('idxname_format', $idxname_format);
  1630.                 }
  1631.                 return $index_fields;
  1632.             }
  1633.             $indexes['normal'][$table_idx_tmp] = array_keys($index_fields['fields']);
  1634.         }
  1635.  
  1636.         // restore user defined 'idxname_format' option (MDB2 only)
  1637.         if ($backend == 'mdb2') {
  1638.             $db->setOption('idxname_format', $idxname_format);
  1639.         }
  1640.  
  1641.         return $indexes;
  1642.     }
  1643.  
  1644.  
  1645.    /**
  1646.     * 
  1647.     * Check whether an index has the right type and has all specified columns.
  1648.     * 
  1649.     * @access private
  1650.     * 
  1651.     * @param string $idxname The index name.
  1652.     * 
  1653.     * @param string $newIdxName The prefixed and suffixed index name.
  1654.     * 
  1655.     * @param string $type The index type.
  1656.     * 
  1657.     * @param mixed $cols The column names for the index.
  1658.     * 
  1659.     * @param mixed $table_indexes Array with all indexes of the table.
  1660.     * 
  1661.     * @param string $mode The name of the calling function, this can be either
  1662.     * 'verify' or 'alter'.
  1663.     * 
  1664.     * @return bool|object Boolean true if the index has the right type and all
  1665.     * specified columns. Otherwise, either boolean false (case 'alter') or a
  1666.     * PEAR_Error (case 'verify').
  1667.     * 
  1668.     */
  1669.  
  1670.     function _checkIndex($idxname, $newIdxName, $type, $cols, &$table_indexes, $mode)
  1671.     {
  1672.         $index_found = false;
  1673.  
  1674.         foreach ($table_indexes[$type] as $index_name => $index_fields) {
  1675.             if (strtolower($index_name) == strtolower($newIdxName)) {
  1676.                 $index_found = true;
  1677.                 array_walk($cols, create_function('&$value,$key',
  1678.                                   '$value = trim(strtolower($value));'));
  1679.                 array_walk($index_fields, create_function('&$value,$key',
  1680.                                   '$value = trim(strtolower($value));'));
  1681.                 foreach ($index_fields as $index_field) {
  1682.                     if (($key = array_search($index_field, $cols)) !== false) {
  1683.                         unset($cols[$key]);
  1684.                     }
  1685.                 }
  1686.                 break;
  1687.             }
  1688.         }
  1689.  
  1690.         if (!$index_found) {
  1691.             return ($mode == 'alter') ? false : DB_Table::throwError(
  1692.                 DB_TABLE_ERR_VER_IDX_MISSING,
  1693.                 "'$idxname' ('$newIdxName')"
  1694.             );
  1695.         }
  1696.  
  1697.         if (count($cols) > 0) {
  1698.             // string of column names
  1699.             $colstring = implode(', ', $cols);
  1700.             return ($mode == 'alter') ? false : DB_Table::throwError(
  1701.                 DB_TABLE_ERR_VER_IDX_COL_MISSING,
  1702.                 "'$idxname' ($colstring)"
  1703.             );
  1704.         }
  1705.  
  1706.         return true;
  1707.     }
  1708.  
  1709.  
  1710.    /**
  1711.     * 
  1712.     * Create indexes and contraints.
  1713.     * 
  1714.     * @access private
  1715.     * 
  1716.     * @param object &$db A PEAR DB/MDB2 object.
  1717.     * 
  1718.     * @param string $backend The name of the backend ('db' or 'mdb2').
  1719.     * 
  1720.     * @param string $table The table name.
  1721.     * 
  1722.     * @param mixed $indexes An array with index and constraint definitions.
  1723.     * 
  1724.     * @return bool|object Boolean true on success or a PEAR_Error with a
  1725.     * description about the invalidity, otherwise.
  1726.     * 
  1727.     */
  1728.  
  1729.     function _createIndexesAndContraints($db, $backend, $table, $indexes)
  1730.     {
  1731.         if ($backend == 'mdb2') {
  1732.  
  1733.             // save user defined 'idxname_format' option
  1734.             $idxname_format = $db->getOption('idxname_format');
  1735.             $db->setOption('idxname_format', '%s');
  1736.  
  1737.             // attempt to create the primary key
  1738.             if (!array_key_exists('primary', $indexes)) {
  1739.                 $indexes['primary'] = array();
  1740.             }
  1741.             foreach ($indexes['primary'] as $name => $definition) {
  1742.                 $result = $db->manager->createConstraint($table, $name, $definition);
  1743.                 if (PEAR::isError($result)) {
  1744.                     // restore user defined 'idxname_format' option
  1745.                     $db->setOption('idxname_format', $idxname_format);
  1746.                     return $result;
  1747.                 }
  1748.             }
  1749.  
  1750.             // attempt to create the unique indexes / constraints
  1751.             if (!array_key_exists('unique', $indexes)) {
  1752.                 $indexes['unique'] = array();
  1753.             }
  1754.             foreach ($indexes['unique'] as $name => $definition) {
  1755.                 $result = $db->manager->createConstraint($table, $name, $definition);
  1756.                 if (PEAR::isError($result)) {
  1757.                     // restore user defined 'idxname_format' option
  1758.                     $db->setOption('idxname_format', $idxname_format);
  1759.                     return $result;
  1760.                 }
  1761.             }
  1762.  
  1763.             // attempt to create the normal indexes
  1764.             if (!array_key_exists('normal', $indexes)) {
  1765.                 $indexes['normal'] = array();
  1766.             }
  1767.             foreach ($indexes['normal'] as $name => $definition) {
  1768.                 $result = $db->manager->createIndex($table, $name, $definition);
  1769.                 if (PEAR::isError($result)) {
  1770.                     // restore user defined 'idxname_format' option
  1771.                     $db->setOption('idxname_format', $idxname_format);
  1772.                     return $result;
  1773.                 }
  1774.             }
  1775.  
  1776.             // restore user defined 'idxname_format' option
  1777.             $db->setOption('idxname_format', $idxname_format);
  1778.  
  1779.         } else {
  1780.  
  1781.             // attempt to create the indexes
  1782.             foreach ($indexes as $cmd) {
  1783.                 $result = $db->query($cmd);
  1784.                 if (PEAR::isError($result)) {
  1785.                     return $result;
  1786.                 }
  1787.             }
  1788.  
  1789.         }
  1790.  
  1791.         return true;
  1792.  
  1793.     }
  1794.  
  1795. }
  1796.  
  1797.  
  1798. /**
  1799. * List of all reserved words for all supported databases. Yes, this is a
  1800. * monster of a list.
  1801. */
  1802. if (! isset($GLOBALS['_DB_TABLE']['reserved'])) {
  1803.     $GLOBALS['_DB_TABLE']['reserved'] = array(
  1804.         '_ROWID_',
  1805.         'ABSOLUTE',
  1806.         'ACCESS',
  1807.         'ACTION',
  1808.         'ADD',
  1809.         'ADMIN',
  1810.         'AFTER',
  1811.         'AGGREGATE',
  1812.         'ALIAS',
  1813.         'ALL',
  1814.         'ALLOCATE',
  1815.         'ALTER',
  1816.         'ANALYSE',
  1817.         'ANALYZE',
  1818.         'AND',
  1819.         'ANY',
  1820.         'ARE',
  1821.         'ARRAY',
  1822.         'AS',
  1823.         'ASC',
  1824.         'ASENSITIVE',
  1825.         'ASSERTION',
  1826.         'AT',
  1827.         'AUDIT',
  1828.         'AUTHORIZATION',
  1829.         'AUTO_INCREMENT',
  1830.         'AVG',
  1831.         'BACKUP',
  1832.         'BDB',
  1833.         'BEFORE',
  1834.         'BEGIN',
  1835.         'BERKELEYDB',
  1836.         'BETWEEN',
  1837.         'BIGINT',
  1838.         'BINARY',
  1839.         'BIT',
  1840.         'BIT_LENGTH',
  1841.         'BLOB',
  1842.         'BOOLEAN',
  1843.         'BOTH',
  1844.         'BREADTH',
  1845.         'BREAK',
  1846.         'BROWSE',
  1847.         'BULK',
  1848.         'BY',
  1849.         'CALL',
  1850.         'CASCADE',
  1851.         'CASCADED',
  1852.         'CASE',
  1853.         'CAST',
  1854.         'CATALOG',
  1855.         'CHANGE',
  1856.         'CHAR',
  1857.         'CHAR_LENGTH',
  1858.         'CHARACTER',
  1859.         'CHARACTER_LENGTH',
  1860.         'CHECK',
  1861.         'CHECKPOINT',
  1862.         'CLASS',
  1863.         'CLOB',
  1864.         'CLOSE',
  1865.         'CLUSTER',
  1866.         'CLUSTERED',
  1867.         'COALESCE',
  1868.         'COLLATE',
  1869.         'COLLATION',
  1870.         'COLUMN',
  1871.         'COLUMNS',
  1872.         'COMMENT',
  1873.         'COMMIT',
  1874.         'COMPLETION',
  1875.         'COMPRESS',
  1876.         'COMPUTE',
  1877.         'CONDITION',
  1878.         'CONNECT',
  1879.         'CONNECTION',
  1880.         'CONSTRAINT',
  1881.         'CONSTRAINTS',
  1882.         'CONSTRUCTOR',
  1883.         'CONTAINS',
  1884.         'CONTAINSTABLE',
  1885.         'CONTINUE',
  1886.         'CONVERT',
  1887.         'CORRESPONDING',
  1888.         'COUNT',
  1889.         'CREATE',
  1890.         'CROSS',
  1891.         'CUBE',
  1892.         'CURRENT',
  1893.         'CURRENT_DATE',
  1894.         'CURRENT_PATH',
  1895.         'CURRENT_ROLE',
  1896.         'CURRENT_TIME',
  1897.         'CURRENT_TIMESTAMP',
  1898.         'CURRENT_USER',
  1899.         'CURSOR',
  1900.         'CYCLE',
  1901.         'DATA',
  1902.         'DATABASE',
  1903.         'DATABASES',
  1904.         'DATE',
  1905.         'DAY',
  1906.         'DAY_HOUR',
  1907.         'DAY_MICROSECOND',
  1908.         'DAY_MINUTE',
  1909.         'DAY_SECOND',
  1910.         'DBCC',
  1911.         'DEALLOCATE',
  1912.         'DEC',
  1913.         'DECIMAL',
  1914.         'DECLARE',
  1915.         'DEFAULT',
  1916.         'DEFERRABLE',
  1917.         'DEFERRED',
  1918.         'DELAYED',
  1919.         'DELETE',
  1920.         'DENY',
  1921.         'DEPTH',
  1922.         'DEREF',
  1923.         'DESC',
  1924.         'DESCRIBE',
  1925.         'DESCRIPTOR',
  1926.         'DESTROY',
  1927.         'DESTRUCTOR',
  1928.         'DETERMINISTIC',
  1929.         'DIAGNOSTICS',
  1930.         'DICTIONARY',
  1931.         'DISCONNECT',
  1932.         'DISK',
  1933.         'DISTINCT',
  1934.         'DISTINCTROW',
  1935.         'DISTRIBUTED',
  1936.         'DIV',
  1937.         'DO',
  1938.         'DOMAIN',
  1939.         'DOUBLE',
  1940.         'DROP',
  1941.         'DUMMY',
  1942.         'DUMP',
  1943.         'DYNAMIC',
  1944.         'EACH',
  1945.         'ELSE',
  1946.         'ELSEIF',
  1947.         'ENCLOSED',
  1948.         'END',
  1949.         'END-EXEC',
  1950.         'EQUALS',
  1951.         'ERRLVL',
  1952.         'ESCAPE',
  1953.         'ESCAPED',
  1954.         'EVERY',
  1955.         'EXCEPT',
  1956.         'EXCEPTION',
  1957.         'EXCLUSIVE',
  1958.         'EXEC',
  1959.         'EXECUTE',
  1960.         'EXISTS',
  1961.         'EXIT',
  1962.         'EXPLAIN',
  1963.         'EXTERNAL',
  1964.         'EXTRACT',
  1965.         'FALSE',
  1966.         'FETCH',
  1967.         'FIELDS',
  1968.         'FILE',
  1969.         'FILLFACTOR',
  1970.         'FIRST',
  1971.         'FLOAT',
  1972.         'FOR',
  1973.         'FORCE',
  1974.         'FOREIGN',
  1975.         'FOUND',
  1976.         'FRAC_SECOND',
  1977.         'FREE',
  1978.         'FREETEXT',
  1979.         'FREETEXTTABLE',
  1980.         'FREEZE',
  1981.         'FROM',
  1982.         'FULL',
  1983.         'FULLTEXT',
  1984.         'FUNCTION',
  1985.         'GENERAL',
  1986.         'GET',
  1987.         'GLOB',
  1988.         'GLOBAL',
  1989.         'GO',
  1990.         'GOTO',
  1991.         'GRANT',
  1992.         'GROUP',
  1993.         'GROUPING',
  1994.         'HAVING',
  1995.         'HIGH_PRIORITY',
  1996.         'HOLDLOCK',
  1997.         'HOST',
  1998.         'HOUR',
  1999.         'HOUR_MICROSECOND',
  2000.         'HOUR_MINUTE',
  2001.         'HOUR_SECOND',
  2002.         'IDENTIFIED',
  2003.         'IDENTITY',
  2004.         'IDENTITY_INSERT',
  2005.         'IDENTITYCOL',
  2006.         'IF',
  2007.         'IGNORE',
  2008.         'ILIKE',
  2009.         'IMMEDIATE',
  2010.         'IN',
  2011.         'INCREMENT',
  2012.         'INDEX',
  2013.         'INDICATOR',
  2014.         'INFILE',
  2015.         'INITIAL',
  2016.         'INITIALIZE',
  2017.         'INITIALLY',
  2018.         'INNER',
  2019.         'INNODB',
  2020.         'INOUT',
  2021.         'INPUT',
  2022.         'INSENSITIVE',
  2023.         'INSERT',
  2024.         'INT',
  2025.         'INTEGER',
  2026.         'INTERSECT',
  2027.         'INTERVAL',
  2028.         'INTO',
  2029.         'IO_THREAD',
  2030.         'IS',
  2031.         'ISNULL',
  2032.         'ISOLATION',
  2033.         'ITERATE',
  2034.         'JOIN',
  2035.         'KEY',
  2036.         'KEYS',
  2037.         'KILL',
  2038.         'LANGUAGE',
  2039.         'LARGE',
  2040.         'LAST',
  2041.         'LATERAL',
  2042.         'LEADING',
  2043.         'LEAVE',
  2044.         'LEFT',
  2045.         'LESS',
  2046.         'LEVEL',
  2047.         'LIKE',
  2048.         'LIMIT',
  2049.         'LINENO',
  2050.         'LINES',
  2051.         'LOAD',
  2052.         'LOCAL',
  2053.         'LOCALTIME',
  2054.         'LOCALTIMESTAMP',
  2055.         'LOCATOR',
  2056.         'LOCK',
  2057.         'LONG',
  2058.         'LONGBLOB',
  2059.         'LONGTEXT',
  2060.         'LOOP',
  2061.         'LOW_PRIORITY',
  2062.         'LOWER',
  2063.         'MAIN',
  2064.         'MAP',
  2065.         'MASTER_SERVER_ID',
  2066.         'MATCH',
  2067.         'MAX',
  2068.         'MAXEXTENTS',
  2069.         'MEDIUMBLOB',
  2070.         'MEDIUMINT',
  2071.         'MEDIUMTEXT',
  2072.         'MIDDLEINT',
  2073.         'MIN',
  2074.         'MINUS',
  2075.         'MINUTE',
  2076.         'MINUTE_MICROSECOND',
  2077.         'MINUTE_SECOND',
  2078.         'MLSLABEL',
  2079.         'MOD',
  2080.         'MODE',
  2081.         'MODIFIES',
  2082.         'MODIFY',
  2083.         'MODULE',
  2084.         'MONTH',
  2085.         'NAMES',
  2086.         'NATIONAL',
  2087.         'NATURAL',
  2088.         'NCHAR',
  2089.         'NCLOB',
  2090.         'NEW',
  2091.         'NEXT',
  2092.         'NO',
  2093.         'NO_WRITE_TO_BINLOG',
  2094.         'NOAUDIT',
  2095.         'NOCHECK',
  2096.         'NOCOMPRESS',
  2097.         'NONCLUSTERED',
  2098.         'NONE',
  2099.         'NOT',
  2100.         'NOTNULL',
  2101.         'NOWAIT',
  2102.         'NULL',
  2103.         'NULLIF',
  2104.         'NUMBER',
  2105.         'NUMERIC',
  2106.         'OBJECT',
  2107.         'OCTET_LENGTH',
  2108.         'OF',
  2109.         'OFF',
  2110.         'OFFLINE',
  2111.         'OFFSET',
  2112.         'OFFSETS',
  2113.         'OID',
  2114.         'OLD',
  2115.         'ON',
  2116.         'ONLINE',
  2117.         'ONLY',
  2118.         'OPEN',
  2119.         'OPENDATASOURCE',
  2120.         'OPENQUERY',
  2121.         'OPENROWSET',
  2122.         'OPENXML',
  2123.         'OPERATION',
  2124.         'OPTIMIZE',
  2125.         'OPTION',
  2126.         'OPTIONALLY',
  2127.         'OR',
  2128.         'ORDER',
  2129.         'ORDINALITY',
  2130.         'OUT',
  2131.         'OUTER',
  2132.         'OUTFILE',
  2133.         'OUTPUT',
  2134.         'OVER',
  2135.         'OVERLAPS',
  2136.         'PAD',
  2137.         'PARAMETER',
  2138.         'PARAMETERS',
  2139.         'PARTIAL',
  2140.         'PATH',
  2141.         'PCTFREE',
  2142.         'PERCENT',
  2143.         'PLACING',
  2144.         'PLAN',
  2145.         'POSITION',
  2146.         'POSTFIX',
  2147.         'PRECISION',
  2148.         'PREFIX',
  2149.         'PREORDER',
  2150.         'PREPARE',
  2151.         'PRESERVE',
  2152.         'PRIMARY',
  2153.         'PRINT',
  2154.         'PRIOR',
  2155.         'PRIVILEGES',
  2156.         'PROC',
  2157.         'PROCEDURE',
  2158.         'PUBLIC',
  2159.         'PURGE',
  2160.         'RAISERROR',
  2161.         'RAW',
  2162.         'READ',
  2163.         'READS',
  2164.         'READTEXT',
  2165.         'REAL',
  2166.         'RECONFIGURE',
  2167.         'RECURSIVE',
  2168.         'REF',
  2169.         'REFERENCES',
  2170.         'REFERENCING',
  2171.         'REGEXP',
  2172.         'RELATIVE',
  2173.         'RENAME',
  2174.         'REPEAT',
  2175.         'REPLACE',
  2176.         'REPLICATION',
  2177.         'REQUIRE',
  2178.         'RESOURCE',
  2179.         'RESTORE',
  2180.         'RESTRICT',
  2181.         'RESULT',
  2182.         'RETURN',
  2183.         'RETURNS',
  2184.         'REVOKE',
  2185.         'RIGHT',
  2186.         'RLIKE',
  2187.         'ROLE',
  2188.         'ROLLBACK',
  2189.         'ROLLUP',
  2190.         'ROUTINE',
  2191.         'ROW',
  2192.         'ROWCOUNT',
  2193.         'ROWGUIDCOL',
  2194.         'ROWID',
  2195.         'ROWNUM',
  2196.         'ROWS',
  2197.         'RULE',
  2198.         'SAVE',
  2199.         'SAVEPOINT',
  2200.         'SCHEMA',
  2201.         'SCOPE',
  2202.         'SCROLL',
  2203.         'SEARCH',
  2204.         'SECOND',
  2205.         'SECOND_MICROSECOND',
  2206.         'SECTION',
  2207.         'SELECT',
  2208.         'SENSITIVE',
  2209.         'SEPARATOR',
  2210.         'SEQUENCE',
  2211.         'SESSION',
  2212.         'SESSION_USER',
  2213.         'SET',
  2214.         'SETS',
  2215.         'SETUSER',
  2216.         'SHARE',
  2217.         'SHOW',
  2218.         'SHUTDOWN',
  2219.         'SIMILAR',
  2220.         'SIZE',
  2221.         'SMALLINT',
  2222.         'SOME',
  2223.         'SONAME',
  2224.         'SPACE',
  2225.         'SPATIAL',
  2226.         'SPECIFIC',
  2227.         'SPECIFICTYPE',
  2228.         'SQL',
  2229.         'SQL_BIG_RESULT',
  2230.         'SQL_CALC_FOUND_ROWS',
  2231.         'SQL_SMALL_RESULT',
  2232.         'SQL_TSI_DAY',
  2233.         'SQL_TSI_FRAC_SECOND',
  2234.         'SQL_TSI_HOUR',
  2235.         'SQL_TSI_MINUTE',
  2236.         'SQL_TSI_MONTH',
  2237.         'SQL_TSI_QUARTER',
  2238.         'SQL_TSI_SECOND',
  2239.         'SQL_TSI_WEEK',
  2240.         'SQL_TSI_YEAR',
  2241.         'SQLCODE',
  2242.         'SQLERROR',
  2243.         'SQLEXCEPTION',
  2244.         'SQLITE_MASTER',
  2245.         'SQLITE_TEMP_MASTER',
  2246.         'SQLSTATE',
  2247.         'SQLWARNING',
  2248.         'SSL',
  2249.         'START',
  2250.         'STARTING',
  2251.         'STATE',
  2252.         'STATEMENT',
  2253.         'STATIC',
  2254.         'STATISTICS',
  2255.         'STRAIGHT_JOIN',
  2256.         'STRIPED',
  2257.         'STRUCTURE',
  2258.         'SUBSTRING',
  2259.         'SUCCESSFUL',
  2260.         'SUM',
  2261.         'SYNONYM',
  2262.         'SYSDATE',
  2263.         'SYSTEM_USER',
  2264.         'TABLE',
  2265.         'TABLES',
  2266.         'TEMPORARY',
  2267.         'TERMINATE',
  2268.         'TERMINATED',
  2269.         'TEXTSIZE',
  2270.         'THAN',
  2271.         'THEN',
  2272.         'TIME',
  2273.         'TIMESTAMP',
  2274.         'TIMESTAMPADD',
  2275.         'TIMESTAMPDIFF',
  2276.         'TIMEZONE_HOUR',
  2277.         'TIMEZONE_MINUTE',
  2278.         'TINYBLOB',
  2279.         'TINYINT',
  2280.         'TINYTEXT',
  2281.         'TO',
  2282.         'TOP',
  2283.         'TRAILING',
  2284.         'TRAN',
  2285.         'TRANSACTION',
  2286.         'TRANSLATE',
  2287.         'TRANSLATION',
  2288.         'TREAT',
  2289.         'TRIGGER',
  2290.         'TRIM',
  2291.         'TRUE',
  2292.         'TRUNCATE',
  2293.         'TSEQUAL',
  2294.         'UID',
  2295.         'UNDER',
  2296.         'UNDO',
  2297.         'UNION',
  2298.         'UNIQUE',
  2299.         'UNKNOWN',
  2300.         'UNLOCK',
  2301.         'UNNEST',
  2302.         'UNSIGNED',
  2303.         'UPDATE',
  2304.         'UPDATETEXT',
  2305.         'UPPER',
  2306.         'USAGE',
  2307.         'USE',
  2308.         'USER',
  2309.         'USER_RESOURCES',
  2310.         'USING',
  2311.         'UTC_DATE',
  2312.         'UTC_TIME',
  2313.         'UTC_TIMESTAMP',
  2314.         'VALIDATE',
  2315.         'VALUE',
  2316.         'VALUES',
  2317.         'VARBINARY',
  2318.         'VARCHAR',
  2319.         'VARCHAR2',
  2320.         'VARCHARACTER',
  2321.         'VARIABLE',
  2322.         'VARYING',
  2323.         'VERBOSE',
  2324.         'VIEW',
  2325.         'WAITFOR',
  2326.         'WHEN',
  2327.         'WHENEVER',
  2328.         'WHERE',
  2329.         'WHILE',
  2330.         'WITH',
  2331.         'WITHOUT',
  2332.         'WORK',
  2333.         'WRITE',
  2334.         'WRITETEXT',
  2335.         'XOR',
  2336.         'YEAR',
  2337.         'YEAR_MONTH',
  2338.         'ZEROFILL',
  2339.         'ZONE',
  2340.     );
  2341. }
  2342.         
  2343. ?>
  2344.