2350 lines
68 KiB
PHP
2350 lines
68 KiB
PHP
|
<?php
|
||
|
|
||
|
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||
|
|
||
|
/**
|
||
|
* Creates, checks or alters tables from DB_Table definitions.
|
||
|
*
|
||
|
* DB_Table_Manager provides database automated table creation
|
||
|
* facilities.
|
||
|
*
|
||
|
* PHP versions 4 and 5
|
||
|
*
|
||
|
* LICENSE:
|
||
|
*
|
||
|
* Copyright (c) 1997-2007, Paul M. Jones <pmjones@php.net>
|
||
|
* David C. Morse <morse@php.net>
|
||
|
* Mark Wiesemann <wiesemann@php.net>
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
* * The names of the authors may not be used to endorse or promote products
|
||
|
* derived from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
* @category Database
|
||
|
* @package DB_Table
|
||
|
* @author Paul M. Jones <pmjones@php.net>
|
||
|
* @author David C. Morse <morse@php.net>
|
||
|
* @author Mark Wiesemann <wiesemann@php.net>
|
||
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||
|
* @version CVS: $Id: Manager.php,v 1.40 2008/12/25 19:56:35 wiesemann Exp $
|
||
|
* @link http://pear.php.net/package/DB_Table
|
||
|
*/
|
||
|
|
||
|
require_once 'DB/Table.php';
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Valid types for the different data types in the different DBMS.
|
||
|
*/
|
||
|
$GLOBALS['_DB_TABLE']['valid_type'] = array(
|
||
|
'fbsql' => array( // currently not supported
|
||
|
'boolean' => '',
|
||
|
'char' => '',
|
||
|
'varchar' => '',
|
||
|
'smallint' => '',
|
||
|
'integer' => '',
|
||
|
'bigint' => '',
|
||
|
'decimal' => '',
|
||
|
'single' => '',
|
||
|
'double' => '',
|
||
|
'clob' => '',
|
||
|
'date' => '',
|
||
|
'time' => '',
|
||
|
'timestamp' => ''
|
||
|
),
|
||
|
'ibase' => array(
|
||
|
'boolean' => array('char', 'integer', 'real', 'smallint'),
|
||
|
'char' => array('char', 'varchar'),
|
||
|
'varchar' => 'varchar',
|
||
|
'smallint' => array('integer', 'smallint'),
|
||
|
'integer' => 'integer',
|
||
|
'bigint' => array('bigint', 'integer'),
|
||
|
'decimal' => 'numeric',
|
||
|
'single' => array('double precision', 'float'),
|
||
|
'double' => 'double precision',
|
||
|
'clob' => 'blob',
|
||
|
'date' => 'date',
|
||
|
'time' => 'time',
|
||
|
'timestamp' => 'timestamp'
|
||
|
),
|
||
|
'mssql' => array( // currently not supported
|
||
|
'boolean' => '',
|
||
|
'char' => '',
|
||
|
'varchar' => '',
|
||
|
'smallint' => '',
|
||
|
'integer' => '',
|
||
|
'bigint' => '',
|
||
|
'decimal' => '',
|
||
|
'single' => '',
|
||
|
'double' => '',
|
||
|
'clob' => '',
|
||
|
'date' => '',
|
||
|
'time' => '',
|
||
|
'timestamp' => ''
|
||
|
),
|
||
|
'mysql' => array(
|
||
|
'boolean' => array('char', 'decimal', 'int', 'real', 'tinyint'),
|
||
|
'char' => array('char', 'string', 'varchar'),
|
||
|
'varchar' => array('char', 'string', 'varchar'),
|
||
|
'smallint' => array('smallint', 'int'),
|
||
|
'integer' => 'int',
|
||
|
'bigint' => array('int', 'bigint'),
|
||
|
'decimal' => array('decimal', 'real'),
|
||
|
'single' => array('double', 'real'),
|
||
|
'double' => array('double', 'real'),
|
||
|
'clob' => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
|
||
|
'date' => array('char', 'date', 'string'),
|
||
|
'time' => array('char', 'string', 'time'),
|
||
|
'timestamp' => array('char', 'datetime', 'string')
|
||
|
),
|
||
|
'mysqli' => array(
|
||
|
'boolean' => array('char', 'decimal', 'tinyint'),
|
||
|
'char' => array('char', 'varchar'),
|
||
|
'varchar' => array('char', 'varchar'),
|
||
|
'smallint' => array('smallint', 'int'),
|
||
|
'integer' => 'int',
|
||
|
'bigint' => array('int', 'bigint'),
|
||
|
'decimal' => 'decimal',
|
||
|
'single' => array('double', 'float'),
|
||
|
'double' => 'double',
|
||
|
'clob' => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
|
||
|
'date' => array('char', 'date', 'varchar'),
|
||
|
'time' => array('char', 'time', 'varchar'),
|
||
|
'timestamp' => array('char', 'datetime', 'varchar')
|
||
|
),
|
||
|
'oci8' => array(
|
||
|
'boolean' => 'number',
|
||
|
'char' => array('char', 'varchar2'),
|
||
|
'varchar' => 'varchar2',
|
||
|
'smallint' => 'number',
|
||
|
'integer' => 'number',
|
||
|
'bigint' => 'number',
|
||
|
'decimal' => 'number',
|
||
|
'single' => array('float', 'number'),
|
||
|
'double' => array('float', 'number'),
|
||
|
'clob' => 'clob',
|
||
|
'date' => array('char', 'date'),
|
||
|
'time' => array('char', 'date'),
|
||
|
'timestamp' => array('char', 'date')
|
||
|
),
|
||
|
'pgsql' => array(
|
||
|
'boolean' => array('bool', 'numeric'),
|
||
|
'char' => array('bpchar', 'varchar'),
|
||
|
'varchar' => 'varchar',
|
||
|
'smallint' => array('int2', 'int4'),
|
||
|
'integer' => 'int4',
|
||
|
'bigint' => array('int4', 'int8'),
|
||
|
'decimal' => 'numeric',
|
||
|
'single' => array('float4', 'float8'),
|
||
|
'double' => 'float8',
|
||
|
'clob' => array('oid', 'text'),
|
||
|
'date' => array('bpchar', 'date'),
|
||
|
'time' => array('bpchar', 'time'),
|
||
|
'timestamp' => array('bpchar', 'timestamp')
|
||
|
),
|
||
|
'sqlite' => array(
|
||
|
'boolean' => 'boolean',
|
||
|
'char' => 'char',
|
||
|
'varchar' => array('char', 'varchar'),
|
||
|
'smallint' => array('int', 'smallint'),
|
||
|
'integer' => array('int', 'integer'),
|
||
|
'bigint' => array('int', 'bigint'),
|
||
|
'decimal' => array('decimal', 'numeric'),
|
||
|
'single' => array('double', 'float'),
|
||
|
'double' => 'double',
|
||
|
'clob' => array('clob', 'longtext'),
|
||
|
'date' => 'date',
|
||
|
'time' => 'time',
|
||
|
'timestamp' => array('datetime', 'timestamp')
|
||
|
),
|
||
|
);
|
||
|
|
||
|
/**
|
||
|
* Mapping between DB_Table and MDB2 data types.
|
||
|
*/
|
||
|
$GLOBALS['_DB_TABLE']['mdb2_type'] = array(
|
||
|
'boolean' => 'boolean',
|
||
|
'char' => 'text',
|
||
|
'varchar' => 'text',
|
||
|
'smallint' => 'integer',
|
||
|
'integer' => 'integer',
|
||
|
'bigint' => 'integer',
|
||
|
'decimal' => 'decimal',
|
||
|
'single' => 'float',
|
||
|
'double' => 'float',
|
||
|
'clob' => 'clob',
|
||
|
'date' => 'date',
|
||
|
'time' => 'time',
|
||
|
'timestamp' => 'timestamp'
|
||
|
);
|
||
|
|
||
|
/**
|
||
|
* Creates, checks or alters tables from DB_Table definitions.
|
||
|
*
|
||
|
* DB_Table_Manager provides database automated table creation
|
||
|
* facilities.
|
||
|
*
|
||
|
* @category Database
|
||
|
* @package DB_Table
|
||
|
* @author Paul M. Jones <pmjones@php.net>
|
||
|
* @author David C. Morse <morse@php.net>
|
||
|
* @author Mark Wiesemann <wiesemann@php.net>
|
||
|
* @version Release: 1.5.6
|
||
|
* @link http://pear.php.net/package/DB_Table
|
||
|
*/
|
||
|
class DB_Table_Manager {
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Create the table based on DB_Table column and index arrays.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $table The table name to connect to in the database.
|
||
|
*
|
||
|
* @param mixed $column_set A DB_Table $this->col array.
|
||
|
*
|
||
|
* @param mixed $index_set A DB_Table $this->idx array.
|
||
|
*
|
||
|
* @return mixed Boolean false if there was no attempt to create the
|
||
|
* table, boolean true if the attempt succeeded, and a PEAR_Error if
|
||
|
* the attempt failed.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function create(&$db, $table, $column_set, $index_set)
|
||
|
{
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$backend = 'db';
|
||
|
} elseif (is_subclass_of($db, 'mdb2_driver_common')) {
|
||
|
$backend = 'mdb2';
|
||
|
$db->loadModule('Manager');
|
||
|
}
|
||
|
$phptype = $db->phptype;
|
||
|
|
||
|
// columns to be created
|
||
|
$column = array();
|
||
|
|
||
|
// max. value for scope (only used with MDB2 as backend)
|
||
|
$max_scope = 0;
|
||
|
|
||
|
// indexes to be created
|
||
|
$indexes = array();
|
||
|
|
||
|
// check the table name
|
||
|
$name_check = DB_Table_Manager::_validateTableName($table);
|
||
|
if (PEAR::isError($name_check)) {
|
||
|
return $name_check;
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
//
|
||
|
// validate each column mapping and build the individual
|
||
|
// definitions, and note column indexes as we go.
|
||
|
//
|
||
|
|
||
|
if (is_null($column_set)) {
|
||
|
$column_set = array();
|
||
|
}
|
||
|
|
||
|
foreach ($column_set as $colname => $val) {
|
||
|
|
||
|
$colname = trim($colname);
|
||
|
|
||
|
// check the column name
|
||
|
$name_check = DB_Table_Manager::_validateColumnName($colname);
|
||
|
if (PEAR::isError($name_check)) {
|
||
|
return $name_check;
|
||
|
}
|
||
|
|
||
|
|
||
|
// prepare variables
|
||
|
$type = (isset($val['type'])) ? $val['type'] : null;
|
||
|
$size = (isset($val['size'])) ? $val['size'] : null;
|
||
|
$scope = (isset($val['scope'])) ? $val['scope'] : null;
|
||
|
$require = (isset($val['require'])) ? $val['require'] : null;
|
||
|
$default = (isset($val['default'])) ? $val['default'] : null;
|
||
|
|
||
|
if ($backend == 'mdb2') {
|
||
|
|
||
|
// get the declaration string
|
||
|
$result = DB_Table_Manager::getDeclareMDB2($type,
|
||
|
$size, $scope, $require, $default, $max_scope);
|
||
|
|
||
|
// did it work?
|
||
|
if (PEAR::isError($result)) {
|
||
|
$result->userinfo .= " ('$colname')";
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
// add the declaration to the array of all columns
|
||
|
$column[$colname] = $result;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// get the declaration string
|
||
|
$result = DB_Table_Manager::getDeclare($phptype, $type,
|
||
|
$size, $scope, $require, $default);
|
||
|
|
||
|
// did it work?
|
||
|
if (PEAR::isError($result)) {
|
||
|
$result->userinfo .= " ('$colname')";
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
// add the declaration to the array of all columns
|
||
|
$column[] = "$colname $result";
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
//
|
||
|
// validate the indexes.
|
||
|
//
|
||
|
|
||
|
if (is_null($index_set)) {
|
||
|
$index_set = array();
|
||
|
}
|
||
|
|
||
|
$count_primary_keys = 0;
|
||
|
|
||
|
foreach ($index_set as $idxname => $val) {
|
||
|
|
||
|
list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
|
||
|
|
||
|
$newIdxName = '';
|
||
|
|
||
|
// check the index definition
|
||
|
$index_check = DB_Table_Manager::_validateIndexName($idxname,
|
||
|
$table, $phptype, $type, $cols, $column_set, $newIdxName);
|
||
|
if (PEAR::isError($index_check)) {
|
||
|
return $index_check;
|
||
|
}
|
||
|
|
||
|
// check number of primary keys (only one is allowed)
|
||
|
if ($type == 'primary') {
|
||
|
// SQLite does not support primary keys
|
||
|
if ($phptype == 'sqlite') {
|
||
|
return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIM_SQLITE);
|
||
|
}
|
||
|
$count_primary_keys++;
|
||
|
}
|
||
|
if ($count_primary_keys > 1) {
|
||
|
return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIMARY);
|
||
|
}
|
||
|
|
||
|
// create index entry
|
||
|
if ($backend == 'mdb2') {
|
||
|
|
||
|
// array with column names as keys
|
||
|
$idx_cols = array();
|
||
|
foreach ($cols as $col) {
|
||
|
$idx_cols[$col] = array();
|
||
|
}
|
||
|
|
||
|
switch ($type) {
|
||
|
case 'primary':
|
||
|
$indexes['primary'][$newIdxName] =
|
||
|
array('fields' => $idx_cols,
|
||
|
'primary' => true);
|
||
|
break;
|
||
|
case 'unique':
|
||
|
$indexes['unique'][$newIdxName] =
|
||
|
array('fields' => $idx_cols,
|
||
|
'unique' => true);
|
||
|
break;
|
||
|
case 'normal':
|
||
|
$indexes['normal'][$newIdxName] =
|
||
|
array('fields' => $idx_cols);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
$indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
|
||
|
$type, $newIdxName, $table, $cols);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
//
|
||
|
// now for the real action: create the table and indexes!
|
||
|
//
|
||
|
if ($backend == 'mdb2') {
|
||
|
|
||
|
// save user defined 'decimal_places' option
|
||
|
$decimal_places = $db->getOption('decimal_places');
|
||
|
$db->setOption('decimal_places', $max_scope);
|
||
|
|
||
|
// attempt to create the table
|
||
|
$result = $db->manager->createTable($table, $column);
|
||
|
// restore user defined 'decimal_places' option
|
||
|
$db->setOption('decimal_places', $decimal_places);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// build the CREATE TABLE command
|
||
|
$cmd = "CREATE TABLE $table (\n\t";
|
||
|
$cmd .= implode(",\n\t", $column);
|
||
|
$cmd .= "\n)";
|
||
|
|
||
|
// attempt to create the table
|
||
|
$result = $db->query($cmd);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
$result = DB_Table_Manager::_createIndexesAndContraints($db, $backend,
|
||
|
$table, $indexes);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
// we're done!
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Verify whether the table and columns exist, whether the columns
|
||
|
* have the right type and whether the indexes exist.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $table The table name to connect to in the database.
|
||
|
*
|
||
|
* @param mixed $column_set A DB_Table $this->col array.
|
||
|
*
|
||
|
* @param mixed $index_set A DB_Table $this->idx array.
|
||
|
*
|
||
|
* @return mixed Boolean true if the verification was successful, and a
|
||
|
* PEAR_Error if verification failed.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function verify(&$db, $table, $column_set, $index_set)
|
||
|
{
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$backend = 'db';
|
||
|
$reverse =& $db;
|
||
|
$table_info_mode = DB_TABLEINFO_FULL;
|
||
|
$table_info_error = DB_ERROR_NEED_MORE_DATA;
|
||
|
} elseif (is_subclass_of($db, 'mdb2_driver_common')) {
|
||
|
$backend = 'mdb2';
|
||
|
$reverse =& $this->db->loadModule('Reverse');
|
||
|
$table_info_mode = MDB2_TABLEINFO_FULL;
|
||
|
$table_info_error = MDB2_ERROR_NEED_MORE_DATA;
|
||
|
}
|
||
|
$phptype = $db->phptype;
|
||
|
|
||
|
// check #1: does the table exist?
|
||
|
|
||
|
// check the table name
|
||
|
$name_check = DB_Table_Manager::_validateTableName($table);
|
||
|
if (PEAR::isError($name_check)) {
|
||
|
return $name_check;
|
||
|
}
|
||
|
|
||
|
// get table info
|
||
|
$tableInfo = $reverse->tableInfo($table, $table_info_mode);
|
||
|
if (PEAR::isError($tableInfo)) {
|
||
|
if ($tableInfo->getCode() == $table_info_error) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_VER_TABLE_MISSING,
|
||
|
"(table='$table')"
|
||
|
);
|
||
|
}
|
||
|
return $tableInfo;
|
||
|
}
|
||
|
$tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
|
||
|
|
||
|
if (is_null($column_set)) {
|
||
|
$column_set = array();
|
||
|
}
|
||
|
|
||
|
foreach ($column_set as $colname => $val) {
|
||
|
$colname = strtolower(trim($colname));
|
||
|
|
||
|
// check the column name
|
||
|
$name_check = DB_Table_Manager::_validateColumnName($colname);
|
||
|
if (PEAR::isError($name_check)) {
|
||
|
return $name_check;
|
||
|
}
|
||
|
|
||
|
// check #2: do all columns exist?
|
||
|
$column_exists = DB_Table_Manager::_columnExists($colname,
|
||
|
$tableInfoOrder, 'verify');
|
||
|
if (PEAR::isError($column_exists)) {
|
||
|
return $column_exists;
|
||
|
}
|
||
|
|
||
|
// check #3: do all columns have the right type?
|
||
|
|
||
|
// check whether the column type is a known type
|
||
|
$type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
|
||
|
if (PEAR::isError($type_check)) {
|
||
|
return $type_check;
|
||
|
}
|
||
|
|
||
|
// check whether the column has the right type
|
||
|
$type_check = DB_Table_Manager::_checkColumnType($phptype,
|
||
|
$colname, $val['type'], $tableInfoOrder, $tableInfo, 'verify');
|
||
|
if (PEAR::isError($type_check)) {
|
||
|
return $type_check;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// check #4: do all indexes exist?
|
||
|
$table_indexes = DB_Table_Manager::getIndexes($db, $table);
|
||
|
if (PEAR::isError($table_indexes)) {
|
||
|
return $table_indexes;
|
||
|
}
|
||
|
|
||
|
if (is_null($index_set)) {
|
||
|
$index_set = array();
|
||
|
}
|
||
|
|
||
|
foreach ($index_set as $idxname => $val) {
|
||
|
|
||
|
list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
|
||
|
|
||
|
$newIdxName = '';
|
||
|
|
||
|
// check the index definition
|
||
|
$index_check = DB_Table_Manager::_validateIndexName($idxname,
|
||
|
$table, $phptype, $type, $cols, $column_set, $newIdxName);
|
||
|
if (PEAR::isError($index_check)) {
|
||
|
return $index_check;
|
||
|
}
|
||
|
|
||
|
// check whether the index has the right type and has all
|
||
|
// specified columns
|
||
|
$index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
|
||
|
$type, $cols, $table_indexes, 'verify');
|
||
|
if (PEAR::isError($index_check)) {
|
||
|
return $index_check;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Alter columns and indexes of a table based on DB_Table column and index
|
||
|
* arrays.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $table The table name to connect to in the database.
|
||
|
*
|
||
|
* @param mixed $column_set A DB_Table $this->col array.
|
||
|
*
|
||
|
* @param mixed $index_set A DB_Table $this->idx array.
|
||
|
*
|
||
|
* @return bool|object True if altering was successful or a PEAR_Error on
|
||
|
* failure.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function alter(&$db, $table, $column_set, $index_set)
|
||
|
{
|
||
|
$phptype = $db->phptype;
|
||
|
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$backend = 'db';
|
||
|
$reverse =& $db;
|
||
|
// workaround for missing index and constraint information methods
|
||
|
// in PEAR::DB ==> use adopted code from MDB2's driver classes
|
||
|
require_once 'DB/Table/Manager/' . $phptype . '.php';
|
||
|
$classname = 'DB_Table_Manager_' . $phptype;
|
||
|
$dbtm = new $classname();
|
||
|
$dbtm->_db =& $db; // pass database instance to the 'workaround' class
|
||
|
$manager =& $dbtm;
|
||
|
$table_info_mode = DB_TABLEINFO_FULL;
|
||
|
$ok_const = DB_OK;
|
||
|
} elseif (is_subclass_of($db, 'mdb2_driver_common')) {
|
||
|
$backend = 'mdb2';
|
||
|
$db->loadModule('Reverse');
|
||
|
$manager =& $db->manager;
|
||
|
$reverse =& $db->reverse;
|
||
|
$table_info_mode = MDB2_TABLEINFO_FULL;
|
||
|
$ok_const = MDB2_OK;
|
||
|
}
|
||
|
|
||
|
// get table info
|
||
|
$tableInfo = $reverse->tableInfo($table, $table_info_mode);
|
||
|
if (PEAR::isError($tableInfo)) {
|
||
|
return $tableInfo;
|
||
|
}
|
||
|
$tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
|
||
|
|
||
|
// emulate MDB2 Reverse extension for PEAR::DB as backend
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$reverse =& $dbtm;
|
||
|
}
|
||
|
|
||
|
// check (and alter) columns
|
||
|
if (is_null($column_set)) {
|
||
|
$column_set = array();
|
||
|
}
|
||
|
|
||
|
foreach ($column_set as $colname => $val) {
|
||
|
$colname = strtolower(trim($colname));
|
||
|
|
||
|
// check the column name
|
||
|
$name_check = DB_Table_Manager::_validateColumnName($colname);
|
||
|
if (PEAR::isError($name_check)) {
|
||
|
return $name_check;
|
||
|
}
|
||
|
|
||
|
// check the column's existence
|
||
|
$column_exists = DB_Table_Manager::_columnExists($colname,
|
||
|
$tableInfoOrder, 'alter');
|
||
|
if (PEAR::isError($column_exists)) {
|
||
|
return $column_exists;
|
||
|
}
|
||
|
if ($column_exists === false) { // add the column
|
||
|
$definition = DB_Table_Manager::_getColumnDefinition($backend,
|
||
|
$phptype, $val);
|
||
|
if (PEAR::isError($definition)) {
|
||
|
return $definition;
|
||
|
}
|
||
|
$changes = array('add' => array($colname => $definition));
|
||
|
if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
|
||
|
echo "(alter) New table field will be added ($colname):\n";
|
||
|
var_dump($changes);
|
||
|
echo "\n";
|
||
|
}
|
||
|
$result = $manager->alterTable($table, $changes, false);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// check whether the column type is a known type
|
||
|
$type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
|
||
|
if (PEAR::isError($type_check)) {
|
||
|
return $type_check;
|
||
|
}
|
||
|
|
||
|
// check whether the column has the right type
|
||
|
$type_check = DB_Table_Manager::_checkColumnType($phptype,
|
||
|
$colname, $val['type'], $tableInfoOrder, $tableInfo, 'alter');
|
||
|
if (PEAR::isError($type_check)) {
|
||
|
return $type_check;
|
||
|
}
|
||
|
if ($type_check === false) { // change the column type
|
||
|
$definition = DB_Table_Manager::_getColumnDefinition($backend,
|
||
|
$phptype, $val);
|
||
|
if (PEAR::isError($definition)) {
|
||
|
return $definition;
|
||
|
}
|
||
|
$changes = array('change' =>
|
||
|
array($colname => array('type' => null,
|
||
|
'definition' => $definition)));
|
||
|
if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
|
||
|
echo "(alter) Table field's type will be changed ($colname):\n";
|
||
|
var_dump($changes);
|
||
|
echo "\n";
|
||
|
}
|
||
|
$result = $manager->alterTable($table, $changes, false);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// get information about indexes / constraints
|
||
|
$table_indexes = DB_Table_Manager::getIndexes($db, $table);
|
||
|
if (PEAR::isError($table_indexes)) {
|
||
|
return $table_indexes;
|
||
|
}
|
||
|
|
||
|
// check (and alter) indexes / constraints
|
||
|
if (is_null($index_set)) {
|
||
|
$index_set = array();
|
||
|
}
|
||
|
|
||
|
foreach ($index_set as $idxname => $val) {
|
||
|
|
||
|
list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
|
||
|
|
||
|
$newIdxName = '';
|
||
|
|
||
|
// check the index definition
|
||
|
$index_check = DB_Table_Manager::_validateIndexName($idxname,
|
||
|
$table, $phptype, $type, $cols, $column_set, $newIdxName);
|
||
|
if (PEAR::isError($index_check)) {
|
||
|
return $index_check;
|
||
|
}
|
||
|
|
||
|
// check whether the index has the right type and has all
|
||
|
// specified columns
|
||
|
$index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
|
||
|
$type, $cols, $table_indexes, 'alter');
|
||
|
if (PEAR::isError($index_check)) {
|
||
|
return $index_check;
|
||
|
}
|
||
|
if ($index_check === false) { // (1) drop wrong index/constraint
|
||
|
// (2) add right index/constraint
|
||
|
if ($backend == 'mdb2') {
|
||
|
// save user defined 'idxname_format' option
|
||
|
$idxname_format = $db->getOption('idxname_format');
|
||
|
$db->setOption('idxname_format', '%s');
|
||
|
}
|
||
|
// drop index/constraint only if it exists
|
||
|
foreach (array('normal', 'unique', 'primary') as $idx_type) {
|
||
|
if (array_key_exists(strtolower($newIdxName),
|
||
|
$table_indexes[$idx_type])) {
|
||
|
if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
|
||
|
echo "(alter) Index/constraint will be deleted (name: '$newIdxName', type: '$idx_type').\n";
|
||
|
}
|
||
|
if ($idx_type == 'normal') {
|
||
|
$result = $manager->dropIndex($table, $newIdxName);
|
||
|
} else {
|
||
|
$result = $manager->dropConstraint($table, $newIdxName);
|
||
|
}
|
||
|
if (PEAR::isError($result)) {
|
||
|
if ($backend == 'mdb2') {
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// prepare index/constraint definition
|
||
|
$indexes = array();
|
||
|
if ($backend == 'mdb2') {
|
||
|
|
||
|
// array with column names as keys
|
||
|
$idx_cols = array();
|
||
|
foreach ($cols as $col) {
|
||
|
$idx_cols[$col] = array();
|
||
|
}
|
||
|
|
||
|
switch ($type) {
|
||
|
case 'primary':
|
||
|
$indexes['primary'][$newIdxName] =
|
||
|
array('fields' => $idx_cols,
|
||
|
'primary' => true);
|
||
|
break;
|
||
|
case 'unique':
|
||
|
$indexes['unique'][$newIdxName] =
|
||
|
array('fields' => $idx_cols,
|
||
|
'unique' => true);
|
||
|
break;
|
||
|
case 'normal':
|
||
|
$indexes['normal'][$newIdxName] =
|
||
|
array('fields' => $idx_cols);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
$indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
|
||
|
$type, $newIdxName, $table, $cols);
|
||
|
|
||
|
}
|
||
|
|
||
|
// create index/constraint
|
||
|
if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
|
||
|
echo "(alter) New index/constraint will be created (name: '$newIdxName', type: '$type'):\n";
|
||
|
var_dump($indexes);
|
||
|
echo "\n";
|
||
|
}
|
||
|
$result = DB_Table_Manager::_createIndexesAndContraints(
|
||
|
$db, $backend, $table, $indexes);
|
||
|
if ($backend == 'mdb2') {
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check whether a table exists.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $table The table name that should be checked.
|
||
|
*
|
||
|
* @return bool|object True if the table exists, false if not, or a
|
||
|
* PEAR_Error on failure.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function tableExists(&$db, $table)
|
||
|
{
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$list = $db->getListOf('tables');
|
||
|
} elseif (is_subclass_of($db, 'mdb2_driver_common')) {
|
||
|
$db->loadModule('Manager');
|
||
|
$list = $db->manager->listTables();
|
||
|
}
|
||
|
if (PEAR::isError($list)) {
|
||
|
return $list;
|
||
|
}
|
||
|
array_walk($list, create_function('&$value,$key',
|
||
|
'$value = trim(strtolower($value));'));
|
||
|
return in_array(strtolower($table), $list);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Get the column declaration string for a DB_Table column.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $phptype The DB/MDB2 phptype key.
|
||
|
*
|
||
|
* @param string $coltype The DB_Table column type.
|
||
|
*
|
||
|
* @param int $size The size for the column (needed for string and
|
||
|
* decimal).
|
||
|
*
|
||
|
* @param int $scope The scope for the column (needed for decimal).
|
||
|
*
|
||
|
* @param bool $require True if the column should be NOT NULL, false
|
||
|
* allowed to be NULL.
|
||
|
*
|
||
|
* @param string $default The SQL calculation for a default value.
|
||
|
*
|
||
|
* @return string|object A declaration string on success, or a
|
||
|
* PEAR_Error on failure.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function getDeclare($phptype, $coltype, $size = null, $scope = null,
|
||
|
$require = null, $default = null)
|
||
|
{
|
||
|
// validate char/varchar/decimal type declaration
|
||
|
$validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
|
||
|
$scope);
|
||
|
if (PEAR::isError($validation)) {
|
||
|
return $validation;
|
||
|
}
|
||
|
|
||
|
// map of column types and declarations for this RDBMS
|
||
|
$map = $GLOBALS['_DB_TABLE']['type'][$phptype];
|
||
|
|
||
|
// is it a recognized column type?
|
||
|
$types = array_keys($map);
|
||
|
if (! in_array($coltype, $types)) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_TYPE,
|
||
|
"('$coltype')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// basic declaration
|
||
|
switch ($coltype) {
|
||
|
|
||
|
case 'char':
|
||
|
case 'varchar':
|
||
|
$declare = $map[$coltype] . "($size)";
|
||
|
break;
|
||
|
|
||
|
case 'decimal':
|
||
|
$declare = $map[$coltype] . "($size,$scope)";
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$declare = $map[$coltype];
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// set the "NULL"/"NOT NULL" portion
|
||
|
$null = ' NULL';
|
||
|
if ($phptype == 'ibase') { // Firebird does not like 'NULL'
|
||
|
$null = ''; // in CREATE TABLE
|
||
|
}
|
||
|
if ($phptype == 'pgsql') { // PostgreSQL does not like 'NULL'
|
||
|
$null = ''; // in ALTER TABLE
|
||
|
}
|
||
|
$declare .= ($require) ? ' NOT NULL' : $null;
|
||
|
|
||
|
// set the "DEFAULT" portion
|
||
|
if ($default) {
|
||
|
switch ($coltype) {
|
||
|
case 'char':
|
||
|
case 'varchar':
|
||
|
case 'clob':
|
||
|
$declare .= " DEFAULT '$default'";
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
$declare .= " DEFAULT $default";
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return $declare;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Get the column declaration string for a DB_Table column.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $coltype The DB_Table column type.
|
||
|
*
|
||
|
* @param int $size The size for the column (needed for string and
|
||
|
* decimal).
|
||
|
*
|
||
|
* @param int $scope The scope for the column (needed for decimal).
|
||
|
*
|
||
|
* @param bool $require True if the column should be NOT NULL, false
|
||
|
* allowed to be NULL.
|
||
|
*
|
||
|
* @param string $default The SQL calculation for a default value.
|
||
|
*
|
||
|
* @param int $max_scope The maximal scope for all table column
|
||
|
* (pass-by-reference).
|
||
|
*
|
||
|
* @return string|object A MDB2 column definition array on success, or a
|
||
|
* PEAR_Error on failure.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function getDeclareMDB2($coltype, $size = null, $scope = null,
|
||
|
$require = null, $default = null, &$max_scope)
|
||
|
{
|
||
|
// validate char/varchar/decimal type declaration
|
||
|
$validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
|
||
|
$scope);
|
||
|
if (PEAR::isError($validation)) {
|
||
|
return $validation;
|
||
|
}
|
||
|
|
||
|
// map of MDB2 column types
|
||
|
$map = $GLOBALS['_DB_TABLE']['mdb2_type'];
|
||
|
|
||
|
// is it a recognized column type?
|
||
|
$types = array_keys($map);
|
||
|
if (! in_array($coltype, $types)) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_TYPE,
|
||
|
"('$coltype')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// build declaration array
|
||
|
$new_column = array(
|
||
|
'type' => $map[$coltype],
|
||
|
'notnull' => $require
|
||
|
);
|
||
|
|
||
|
if ($size) {
|
||
|
$new_column['length'] = $size;
|
||
|
}
|
||
|
|
||
|
// determine integer length to be used in MDB2
|
||
|
if (in_array($coltype, array('smallint', 'integer', 'bigint'))) {
|
||
|
switch ($coltype) {
|
||
|
case 'smallint':
|
||
|
$new_column['length'] = 2;
|
||
|
break;
|
||
|
case 'integer':
|
||
|
$new_column['length'] = 4;
|
||
|
break;
|
||
|
case 'bigint':
|
||
|
$new_column['length'] = 5;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($scope) {
|
||
|
$max_scope = max($max_scope, $scope);
|
||
|
}
|
||
|
|
||
|
if ($default) {
|
||
|
$new_column['default'] = $default;
|
||
|
}
|
||
|
|
||
|
return $new_column;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Get the index declaration string for a DB_Table index.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $phptype The DB phptype key.
|
||
|
*
|
||
|
* @param string $type The index type.
|
||
|
*
|
||
|
* @param string $idxname The index name.
|
||
|
*
|
||
|
* @param string $table The table name.
|
||
|
*
|
||
|
* @param mixed $cols Array with the column names for the index.
|
||
|
*
|
||
|
* @return string A declaration string.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function getDeclareForIndex($phptype, $type, $idxname, $table, $cols)
|
||
|
{
|
||
|
// string of column names
|
||
|
$colstring = implode(', ', $cols);
|
||
|
|
||
|
switch ($type) {
|
||
|
|
||
|
case 'primary':
|
||
|
switch ($phptype) {
|
||
|
case 'ibase':
|
||
|
case 'oci8':
|
||
|
case 'pgsql':
|
||
|
$declare = "ALTER TABLE $table ADD";
|
||
|
$declare .= " CONSTRAINT $idxname";
|
||
|
$declare .= " PRIMARY KEY ($colstring)";
|
||
|
break;
|
||
|
case 'mysql':
|
||
|
case 'mysqli':
|
||
|
$declare = "ALTER TABLE $table ADD PRIMARY KEY";
|
||
|
$declare .= " ($colstring)";
|
||
|
break;
|
||
|
case 'sqlite':
|
||
|
// currently not possible
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'unique':
|
||
|
$declare = "CREATE UNIQUE INDEX $idxname ON $table ($colstring)";
|
||
|
break;
|
||
|
|
||
|
case 'normal':
|
||
|
$declare = "CREATE INDEX $idxname ON $table ($colstring)";
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
return $declare;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Return the definition array for a column.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $backend The name of the backend ('db' or 'mdb2').
|
||
|
*
|
||
|
* @param string $phptype The DB/MDB2 phptype key.
|
||
|
*
|
||
|
* @param mixed $column A single DB_Table column definition array.
|
||
|
*
|
||
|
* @return mixed|object Declaration string (DB), declaration array (MDB2) or a
|
||
|
* PEAR_Error with a description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _getColumnDefinition($backend, $phptype, $column)
|
||
|
{
|
||
|
static $max_scope;
|
||
|
|
||
|
// prepare variables
|
||
|
$type = (isset($column['type'])) ? $column['type'] : null;
|
||
|
$size = (isset($column['size'])) ? $column['size'] : null;
|
||
|
$scope = (isset($column['scope'])) ? $column['scope'] : null;
|
||
|
$require = (isset($column['require'])) ? $column['require'] : null;
|
||
|
$default = (isset($column['default'])) ? $column['default'] : null;
|
||
|
|
||
|
if ($backend == 'db') {
|
||
|
return DB_Table_Manager::getDeclare($phptype, $type,
|
||
|
$size, $scope, $require, $default);
|
||
|
} else {
|
||
|
return DB_Table_Manager::getDeclareMDB2($type,
|
||
|
$size, $scope, $require, $default, $max_scope);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check char/varchar/decimal type declarations for validity.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $coltype The DB_Table column type.
|
||
|
*
|
||
|
* @param int $size The size for the column (needed for string and
|
||
|
* decimal).
|
||
|
*
|
||
|
* @param int $scope The scope for the column (needed for decimal).
|
||
|
*
|
||
|
* @return bool|object Boolean true if the type declaration is valid or a
|
||
|
* PEAR_Error with a description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _validateTypeDeclaration($coltype, $size, $scope)
|
||
|
{
|
||
|
// validate char and varchar: does it have a size?
|
||
|
if (($coltype == 'char' || $coltype == 'varchar') &&
|
||
|
($size < 1 || $size > 255) ) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_STRING,
|
||
|
"(size='$size')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// validate decimal: does it have a size and scope?
|
||
|
if ($coltype == 'decimal' &&
|
||
|
($size < 1 || $size > 255 || $scope < 0 || $scope > $size)) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_DECIMAL,
|
||
|
"(size='$size' scope='$scope')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check a table name for validity.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $tablename The table name.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the table name is valid or a
|
||
|
* PEAR_Error with a description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _validateTableName($tablename)
|
||
|
{
|
||
|
// is the table name too long?
|
||
|
if ( $GLOBALS['_DB_TABLE']['disable_length_check'] === false
|
||
|
&& strlen($tablename) > 30
|
||
|
) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_TABLE_STRLEN,
|
||
|
" ('$tablename')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check a column name for validity.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $colname The column name.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the column name is valid or a
|
||
|
* PEAR_Error with a description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _validateColumnName($colname)
|
||
|
{
|
||
|
// column name cannot be a reserved keyword
|
||
|
$reserved = in_array(
|
||
|
strtoupper($colname),
|
||
|
$GLOBALS['_DB_TABLE']['reserved']
|
||
|
);
|
||
|
|
||
|
if ($reserved) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_COLNAME,
|
||
|
" ('$colname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// column name must be no longer than 30 chars
|
||
|
if ( $GLOBALS['_DB_TABLE']['disable_length_check'] === false
|
||
|
&& strlen($colname) > 30
|
||
|
) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_STRLEN,
|
||
|
"('$colname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check whether a column exists.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $colname The column name.
|
||
|
*
|
||
|
* @param mixed $tableInfoOrder Array with columns in the table (result
|
||
|
* from tableInfo(), shortened to key 'order').
|
||
|
*
|
||
|
* @param string $mode The name of the calling function, this can be either
|
||
|
* 'verify' or 'alter'.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the column exists.
|
||
|
* Otherwise, either boolean false (case 'alter') or a PEAR_Error
|
||
|
* (case 'verify').
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _columnExists($colname, $tableInfoOrder, $mode)
|
||
|
{
|
||
|
if (array_key_exists($colname, $tableInfoOrder)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
switch ($mode) {
|
||
|
|
||
|
case 'alter':
|
||
|
return false;
|
||
|
|
||
|
case 'verify':
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_VER_COLUMN_MISSING,
|
||
|
"(column='$colname')"
|
||
|
);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check whether a column type is a known type.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $phptype The DB/MDB2 phptype key.
|
||
|
*
|
||
|
* @param string $type The column type.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the column type is a known type
|
||
|
* or a PEAR_Error, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _validateColumnType($phptype, $type)
|
||
|
{
|
||
|
// map of valid types for the current RDBMS
|
||
|
$map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
|
||
|
|
||
|
// is it a recognized column type?
|
||
|
$types = array_keys($map);
|
||
|
if (!in_array($type, $types)) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_TYPE,
|
||
|
"('" . $type . "')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check whether a column has the right type.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $phptype The DB/MDB2 phptype key.
|
||
|
*
|
||
|
* @param string $colname The column name.
|
||
|
*
|
||
|
* @param string $coltype The column type.
|
||
|
*
|
||
|
* @param mixed $tableInfoOrder Array with columns in the table (result
|
||
|
* from tableInfo(), shortened to key 'order').
|
||
|
*
|
||
|
* @param mixed $tableInfo Array with information about the table (result
|
||
|
* from tableInfo()).
|
||
|
*
|
||
|
* @param string $mode The name of the calling function, this can be either
|
||
|
* 'verify' or 'alter'.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the column has the right type.
|
||
|
* Otherwise, either boolean false (case 'alter') or a PEAR_Error
|
||
|
* (case 'verify').
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _checkColumnType($phptype, $colname, $coltype, $tableInfoOrder,
|
||
|
$tableInfo, $mode)
|
||
|
{
|
||
|
// map of valid types for the current RDBMS
|
||
|
$map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
|
||
|
|
||
|
// get the column type from tableInfo()
|
||
|
$colindex = $tableInfoOrder[$colname];
|
||
|
$type = strtolower($tableInfo[$colindex]['type']);
|
||
|
|
||
|
// workaround for possibly wrong detected column type (taken from MDB2)
|
||
|
if ($type == 'unknown' && ($phptype == 'mysql' || $phptype == 'mysqli')) {
|
||
|
$type = 'decimal';
|
||
|
}
|
||
|
|
||
|
// strip size information (e.g. NUMERIC(9,2) => NUMERIC) if given
|
||
|
if (($pos = strpos($type, '(')) !== false) {
|
||
|
$type = substr($type, 0, $pos);
|
||
|
}
|
||
|
|
||
|
// is the type valid for the given DB_Table column type?
|
||
|
if (in_array($type, (array)$map[$coltype])) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
switch ($mode) {
|
||
|
|
||
|
case 'alter':
|
||
|
return false;
|
||
|
|
||
|
case 'verify':
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_VER_COLUMN_TYPE,
|
||
|
"(column='$colname', type='$type')"
|
||
|
);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Return the index type and the columns belonging to this index.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param mixed $idx_def The index definition.
|
||
|
*
|
||
|
* @return mixed Array with the index type and the columns belonging to
|
||
|
* this index.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _getIndexTypeAndColumns($idx_def, $idxname)
|
||
|
{
|
||
|
$type = '';
|
||
|
$cols = '';
|
||
|
if (is_string($idx_def)) {
|
||
|
// shorthand for index names: colname => index_type
|
||
|
$type = trim($idx_def);
|
||
|
$cols = trim($idxname);
|
||
|
} elseif (is_array($idx_def)) {
|
||
|
// normal: index_name => array('type' => ..., 'cols' => ...)
|
||
|
$type = (isset($idx_def['type'])) ? $idx_def['type'] : 'normal';
|
||
|
$cols = (isset($idx_def['cols'])) ? $idx_def['cols'] : null;
|
||
|
}
|
||
|
|
||
|
return array($type, $cols);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check an index name for validity.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $idxname The index name.
|
||
|
*
|
||
|
* @param string $table The table name.
|
||
|
*
|
||
|
* @param string $phptype The DB/MDB2 phptype key.
|
||
|
*
|
||
|
* @param string $type The index type.
|
||
|
*
|
||
|
* @param mixed $cols The column names for the index. Will become an array
|
||
|
* if it is not an array.
|
||
|
*
|
||
|
* @param mixed $column_set A DB_Table $this->col array.
|
||
|
*
|
||
|
* @param string $newIdxName The new index name (prefixed with the table
|
||
|
* name, suffixed with '_idx').
|
||
|
*
|
||
|
* @return bool|object Boolean true if the index name is valid or a
|
||
|
* PEAR_Error with a description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _validateIndexName($idxname, $table, $phptype, $type, &$cols,
|
||
|
$column_set, &$newIdxName)
|
||
|
{
|
||
|
// index name cannot be a reserved keyword
|
||
|
$reserved = in_array(
|
||
|
strtoupper($idxname),
|
||
|
$GLOBALS['_DB_TABLE']['reserved']
|
||
|
);
|
||
|
|
||
|
if ($reserved && !($type == 'primary' && $idxname == 'PRIMARY')) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_DECLARE_IDXNAME,
|
||
|
"('$idxname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// are there any columns for the index?
|
||
|
if (! $cols) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_IDX_NO_COLS,
|
||
|
"('$idxname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// are there any CLOB columns, or any columns that are not
|
||
|
// in the schema?
|
||
|
settype($cols, 'array');
|
||
|
$valid_cols = array_keys($column_set);
|
||
|
foreach ($cols as $colname) {
|
||
|
|
||
|
if (! in_array($colname, $valid_cols)) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_IDX_COL_UNDEF,
|
||
|
"'$idxname' ('$colname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if ($column_set[$colname]['type'] == 'clob') {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_IDX_COL_CLOB,
|
||
|
"'$idxname' ('$colname')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// we prefix all index names with the table name,
|
||
|
// and suffix all index names with '_idx'. this
|
||
|
// is to soothe PostgreSQL, which demands that index
|
||
|
// names not collide, even when they indexes are on
|
||
|
// different tables.
|
||
|
$newIdxName = $table . '_' . $idxname . '_idx';
|
||
|
|
||
|
// MySQL requires the primary key to be named 'primary', therefore let's
|
||
|
// ignore the user defined name
|
||
|
if (($phptype == 'mysql' || $phptype == 'mysqli') && $type == 'primary') {
|
||
|
$newIdxName = 'primary';
|
||
|
}
|
||
|
|
||
|
// now check the length; must be under 30 chars to
|
||
|
// soothe Oracle.
|
||
|
if ( $GLOBALS['_DB_TABLE']['disable_length_check'] === false
|
||
|
&& strlen($newIdxName) > 30
|
||
|
) {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_IDX_STRLEN,
|
||
|
"'$idxname' ('$newIdxName')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// check index type
|
||
|
if ($type != 'primary' && $type != 'unique' && $type != 'normal') {
|
||
|
return DB_Table::throwError(
|
||
|
DB_TABLE_ERR_IDX_TYPE,
|
||
|
"'$idxname' ('$type')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Return all indexes for a table.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $table The table name.
|
||
|
*
|
||
|
* @return mixed Array with all indexes or a PEAR_Error when an error
|
||
|
* occured.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function getIndexes(&$db, $table)
|
||
|
{
|
||
|
if (is_subclass_of($db, 'db_common')) {
|
||
|
$backend = 'db';
|
||
|
// workaround for missing index and constraint information methods
|
||
|
// in PEAR::DB ==> use adopted code from MDB2's driver classes
|
||
|
require_once 'DB/Table/Manager/' . $db->phptype . '.php';
|
||
|
$classname = 'DB_Table_Manager_' . $db->phptype;
|
||
|
$dbtm = new $classname();
|
||
|
$dbtm->_db =& $db; // pass database instance to the 'workaround' class
|
||
|
$manager =& $dbtm;
|
||
|
$reverse =& $dbtm;
|
||
|
} elseif (is_subclass_of($db, 'mdb2_driver_common')) {
|
||
|
$backend = 'mdb2';
|
||
|
$manager =& $db->manager;
|
||
|
$reverse =& $db->reverse;
|
||
|
}
|
||
|
|
||
|
$indexes = array('normal' => array(),
|
||
|
'primary' => array(),
|
||
|
'unique' => array()
|
||
|
);
|
||
|
|
||
|
// save user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$idxname_format = $db->getOption('idxname_format');
|
||
|
$db->setOption('idxname_format', '%s');
|
||
|
}
|
||
|
|
||
|
// get table constraints
|
||
|
$table_indexes_tmp = $manager->listTableConstraints($table);
|
||
|
if (PEAR::isError($table_indexes_tmp)) {
|
||
|
// restore user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
return $table_indexes_tmp;
|
||
|
}
|
||
|
|
||
|
// get fields of table constraints
|
||
|
foreach ($table_indexes_tmp as $table_idx_tmp) {
|
||
|
$index_fields = $reverse->getTableConstraintDefinition($table,
|
||
|
$table_idx_tmp);
|
||
|
if (PEAR::isError($index_fields)) {
|
||
|
// restore user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
return $index_fields;
|
||
|
}
|
||
|
// get the first key of $index_fields that has boolean true value
|
||
|
foreach ($index_fields as $index_type => $value) {
|
||
|
if ($value === true) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
$indexes[$index_type][$table_idx_tmp] = array_keys($index_fields['fields']);
|
||
|
}
|
||
|
|
||
|
// get table indexes
|
||
|
$table_indexes_tmp = $manager->listTableIndexes($table);
|
||
|
if (PEAR::isError($table_indexes_tmp)) {
|
||
|
// restore user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
return $table_indexes_tmp;
|
||
|
}
|
||
|
|
||
|
// get fields of table indexes
|
||
|
foreach ($table_indexes_tmp as $table_idx_tmp) {
|
||
|
$index_fields = $reverse->getTableIndexDefinition($table,
|
||
|
$table_idx_tmp);
|
||
|
if (PEAR::isError($index_fields)) {
|
||
|
// restore user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
return $index_fields;
|
||
|
}
|
||
|
$indexes['normal'][$table_idx_tmp] = array_keys($index_fields['fields']);
|
||
|
}
|
||
|
|
||
|
// restore user defined 'idxname_format' option (MDB2 only)
|
||
|
if ($backend == 'mdb2') {
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
}
|
||
|
|
||
|
return $indexes;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Check whether an index has the right type and has all specified columns.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $idxname The index name.
|
||
|
*
|
||
|
* @param string $newIdxName The prefixed and suffixed index name.
|
||
|
*
|
||
|
* @param string $type The index type.
|
||
|
*
|
||
|
* @param mixed $cols The column names for the index.
|
||
|
*
|
||
|
* @param mixed $table_indexes Array with all indexes of the table.
|
||
|
*
|
||
|
* @param string $mode The name of the calling function, this can be either
|
||
|
* 'verify' or 'alter'.
|
||
|
*
|
||
|
* @return bool|object Boolean true if the index has the right type and all
|
||
|
* specified columns. Otherwise, either boolean false (case 'alter') or a
|
||
|
* PEAR_Error (case 'verify').
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _checkIndex($idxname, $newIdxName, $type, $cols, &$table_indexes, $mode)
|
||
|
{
|
||
|
$index_found = false;
|
||
|
|
||
|
foreach ($table_indexes[$type] as $index_name => $index_fields) {
|
||
|
if (strtolower($index_name) == strtolower($newIdxName)) {
|
||
|
$index_found = true;
|
||
|
array_walk($cols, create_function('&$value,$key',
|
||
|
'$value = trim(strtolower($value));'));
|
||
|
array_walk($index_fields, create_function('&$value,$key',
|
||
|
'$value = trim(strtolower($value));'));
|
||
|
foreach ($index_fields as $index_field) {
|
||
|
if (($key = array_search($index_field, $cols)) !== false) {
|
||
|
unset($cols[$key]);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!$index_found) {
|
||
|
return ($mode == 'alter') ? false : DB_Table::throwError(
|
||
|
DB_TABLE_ERR_VER_IDX_MISSING,
|
||
|
"'$idxname' ('$newIdxName')"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (count($cols) > 0) {
|
||
|
// string of column names
|
||
|
$colstring = implode(', ', $cols);
|
||
|
return ($mode == 'alter') ? false : DB_Table::throwError(
|
||
|
DB_TABLE_ERR_VER_IDX_COL_MISSING,
|
||
|
"'$idxname' ($colstring)"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Create indexes and contraints.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param object &$db A PEAR DB/MDB2 object.
|
||
|
*
|
||
|
* @param string $backend The name of the backend ('db' or 'mdb2').
|
||
|
*
|
||
|
* @param string $table The table name.
|
||
|
*
|
||
|
* @param mixed $indexes An array with index and constraint definitions.
|
||
|
*
|
||
|
* @return bool|object Boolean true on success or a PEAR_Error with a
|
||
|
* description about the invalidity, otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
function _createIndexesAndContraints($db, $backend, $table, $indexes)
|
||
|
{
|
||
|
if ($backend == 'mdb2') {
|
||
|
|
||
|
// save user defined 'idxname_format' option
|
||
|
$idxname_format = $db->getOption('idxname_format');
|
||
|
$db->setOption('idxname_format', '%s');
|
||
|
|
||
|
// attempt to create the primary key
|
||
|
if (!array_key_exists('primary', $indexes)) {
|
||
|
$indexes['primary'] = array();
|
||
|
}
|
||
|
foreach ($indexes['primary'] as $name => $definition) {
|
||
|
$result = $db->manager->createConstraint($table, $name, $definition);
|
||
|
if (PEAR::isError($result)) {
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
return $result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// attempt to create the unique indexes / constraints
|
||
|
if (!array_key_exists('unique', $indexes)) {
|
||
|
$indexes['unique'] = array();
|
||
|
}
|
||
|
foreach ($indexes['unique'] as $name => $definition) {
|
||
|
$result = $db->manager->createConstraint($table, $name, $definition);
|
||
|
if (PEAR::isError($result)) {
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
return $result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// attempt to create the normal indexes
|
||
|
if (!array_key_exists('normal', $indexes)) {
|
||
|
$indexes['normal'] = array();
|
||
|
}
|
||
|
foreach ($indexes['normal'] as $name => $definition) {
|
||
|
$result = $db->manager->createIndex($table, $name, $definition);
|
||
|
if (PEAR::isError($result)) {
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
return $result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// restore user defined 'idxname_format' option
|
||
|
$db->setOption('idxname_format', $idxname_format);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// attempt to create the indexes
|
||
|
foreach ($indexes as $cmd) {
|
||
|
$result = $db->query($cmd);
|
||
|
if (PEAR::isError($result)) {
|
||
|
return $result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* List of all reserved words for all supported databases. Yes, this is a
|
||
|
* monster of a list.
|
||
|
*/
|
||
|
if (! isset($GLOBALS['_DB_TABLE']['reserved'])) {
|
||
|
$GLOBALS['_DB_TABLE']['reserved'] = array(
|
||
|
'_ROWID_',
|
||
|
'ABSOLUTE',
|
||
|
'ACCESS',
|
||
|
'ACTION',
|
||
|
'ADD',
|
||
|
'ADMIN',
|
||
|
'AFTER',
|
||
|
'AGGREGATE',
|
||
|
'ALIAS',
|
||
|
'ALL',
|
||
|
'ALLOCATE',
|
||
|
'ALTER',
|
||
|
'ANALYSE',
|
||
|
'ANALYZE',
|
||
|
'AND',
|
||
|
'ANY',
|
||
|
'ARE',
|
||
|
'ARRAY',
|
||
|
'AS',
|
||
|
'ASC',
|
||
|
'ASENSITIVE',
|
||
|
'ASSERTION',
|
||
|
'AT',
|
||
|
'AUDIT',
|
||
|
'AUTHORIZATION',
|
||
|
'AUTO_INCREMENT',
|
||
|
'AVG',
|
||
|
'BACKUP',
|
||
|
'BDB',
|
||
|
'BEFORE',
|
||
|
'BEGIN',
|
||
|
'BERKELEYDB',
|
||
|
'BETWEEN',
|
||
|
'BIGINT',
|
||
|
'BINARY',
|
||
|
'BIT',
|
||
|
'BIT_LENGTH',
|
||
|
'BLOB',
|
||
|
'BOOLEAN',
|
||
|
'BOTH',
|
||
|
'BREADTH',
|
||
|
'BREAK',
|
||
|
'BROWSE',
|
||
|
'BULK',
|
||
|
'BY',
|
||
|
'CALL',
|
||
|
'CASCADE',
|
||
|
'CASCADED',
|
||
|
'CASE',
|
||
|
'CAST',
|
||
|
'CATALOG',
|
||
|
'CHANGE',
|
||
|
'CHAR',
|
||
|
'CHAR_LENGTH',
|
||
|
'CHARACTER',
|
||
|
'CHARACTER_LENGTH',
|
||
|
'CHECK',
|
||
|
'CHECKPOINT',
|
||
|
'CLASS',
|
||
|
'CLOB',
|
||
|
'CLOSE',
|
||
|
'CLUSTER',
|
||
|
'CLUSTERED',
|
||
|
'COALESCE',
|
||
|
'COLLATE',
|
||
|
'COLLATION',
|
||
|
'COLUMN',
|
||
|
'COLUMNS',
|
||
|
'COMMENT',
|
||
|
'COMMIT',
|
||
|
'COMPLETION',
|
||
|
'COMPRESS',
|
||
|
'COMPUTE',
|
||
|
'CONDITION',
|
||
|
'CONNECT',
|
||
|
'CONNECTION',
|
||
|
'CONSTRAINT',
|
||
|
'CONSTRAINTS',
|
||
|
'CONSTRUCTOR',
|
||
|
'CONTAINS',
|
||
|
'CONTAINSTABLE',
|
||
|
'CONTINUE',
|
||
|
'CONVERT',
|
||
|
'CORRESPONDING',
|
||
|
'COUNT',
|
||
|
'CREATE',
|
||
|
'CROSS',
|
||
|
'CUBE',
|
||
|
'CURRENT',
|
||
|
'CURRENT_DATE',
|
||
|
'CURRENT_PATH',
|
||
|
'CURRENT_ROLE',
|
||
|
'CURRENT_TIME',
|
||
|
'CURRENT_TIMESTAMP',
|
||
|
'CURRENT_USER',
|
||
|
'CURSOR',
|
||
|
'CYCLE',
|
||
|
'DATA',
|
||
|
'DATABASE',
|
||
|
'DATABASES',
|
||
|
'DATE',
|
||
|
'DAY',
|
||
|
'DAY_HOUR',
|
||
|
'DAY_MICROSECOND',
|
||
|
'DAY_MINUTE',
|
||
|
'DAY_SECOND',
|
||
|
'DBCC',
|
||
|
'DEALLOCATE',
|
||
|
'DEC',
|
||
|
'DECIMAL',
|
||
|
'DECLARE',
|
||
|
'DEFAULT',
|
||
|
'DEFERRABLE',
|
||
|
'DEFERRED',
|
||
|
'DELAYED',
|
||
|
'DELETE',
|
||
|
'DENY',
|
||
|
'DEPTH',
|
||
|
'DEREF',
|
||
|
'DESC',
|
||
|
'DESCRIBE',
|
||
|
'DESCRIPTOR',
|
||
|
'DESTROY',
|
||
|
'DESTRUCTOR',
|
||
|
'DETERMINISTIC',
|
||
|
'DIAGNOSTICS',
|
||
|
'DICTIONARY',
|
||
|
'DISCONNECT',
|
||
|
'DISK',
|
||
|
'DISTINCT',
|
||
|
'DISTINCTROW',
|
||
|
'DISTRIBUTED',
|
||
|
'DIV',
|
||
|
'DO',
|
||
|
'DOMAIN',
|
||
|
'DOUBLE',
|
||
|
'DROP',
|
||
|
'DUMMY',
|
||
|
'DUMP',
|
||
|
'DYNAMIC',
|
||
|
'EACH',
|
||
|
'ELSE',
|
||
|
'ELSEIF',
|
||
|
'ENCLOSED',
|
||
|
'END',
|
||
|
'END-EXEC',
|
||
|
'EQUALS',
|
||
|
'ERRLVL',
|
||
|
'ESCAPE',
|
||
|
'ESCAPED',
|
||
|
'EVERY',
|
||
|
'EXCEPT',
|
||
|
'EXCEPTION',
|
||
|
'EXCLUSIVE',
|
||
|
'EXEC',
|
||
|
'EXECUTE',
|
||
|
'EXISTS',
|
||
|
'EXIT',
|
||
|
'EXPLAIN',
|
||
|
'EXTERNAL',
|
||
|
'EXTRACT',
|
||
|
'FALSE',
|
||
|
'FETCH',
|
||
|
'FIELDS',
|
||
|
'FILE',
|
||
|
'FILLFACTOR',
|
||
|
'FIRST',
|
||
|
'FLOAT',
|
||
|
'FOR',
|
||
|
'FORCE',
|
||
|
'FOREIGN',
|
||
|
'FOUND',
|
||
|
'FRAC_SECOND',
|
||
|
'FREE',
|
||
|
'FREETEXT',
|
||
|
'FREETEXTTABLE',
|
||
|
'FREEZE',
|
||
|
'FROM',
|
||
|
'FULL',
|
||
|
'FULLTEXT',
|
||
|
'FUNCTION',
|
||
|
'GENERAL',
|
||
|
'GET',
|
||
|
'GLOB',
|
||
|
'GLOBAL',
|
||
|
'GO',
|
||
|
'GOTO',
|
||
|
'GRANT',
|
||
|
'GROUP',
|
||
|
'GROUPING',
|
||
|
'HAVING',
|
||
|
'HIGH_PRIORITY',
|
||
|
'HOLDLOCK',
|
||
|
'HOST',
|
||
|
'HOUR',
|
||
|
'HOUR_MICROSECOND',
|
||
|
'HOUR_MINUTE',
|
||
|
'HOUR_SECOND',
|
||
|
'IDENTIFIED',
|
||
|
'IDENTITY',
|
||
|
'IDENTITY_INSERT',
|
||
|
'IDENTITYCOL',
|
||
|
'IF',
|
||
|
'IGNORE',
|
||
|
'ILIKE',
|
||
|
'IMMEDIATE',
|
||
|
'IN',
|
||
|
'INCREMENT',
|
||
|
'INDEX',
|
||
|
'INDICATOR',
|
||
|
'INFILE',
|
||
|
'INITIAL',
|
||
|
'INITIALIZE',
|
||
|
'INITIALLY',
|
||
|
'INNER',
|
||
|
'INNODB',
|
||
|
'INOUT',
|
||
|
'INPUT',
|
||
|
'INSENSITIVE',
|
||
|
'INSERT',
|
||
|
'INT',
|
||
|
'INTEGER',
|
||
|
'INTERSECT',
|
||
|
'INTERVAL',
|
||
|
'INTO',
|
||
|
'IO_THREAD',
|
||
|
'IS',
|
||
|
'ISNULL',
|
||
|
'ISOLATION',
|
||
|
'ITERATE',
|
||
|
'JOIN',
|
||
|
'KEY',
|
||
|
'KEYS',
|
||
|
'KILL',
|
||
|
'LANGUAGE',
|
||
|
'LARGE',
|
||
|
'LAST',
|
||
|
'LATERAL',
|
||
|
'LEADING',
|
||
|
'LEAVE',
|
||
|
'LEFT',
|
||
|
'LESS',
|
||
|
'LEVEL',
|
||
|
'LIKE',
|
||
|
'LIMIT',
|
||
|
'LINENO',
|
||
|
'LINES',
|
||
|
'LOAD',
|
||
|
'LOCAL',
|
||
|
'LOCALTIME',
|
||
|
'LOCALTIMESTAMP',
|
||
|
'LOCATOR',
|
||
|
'LOCK',
|
||
|
'LONG',
|
||
|
'LONGBLOB',
|
||
|
'LONGTEXT',
|
||
|
'LOOP',
|
||
|
'LOW_PRIORITY',
|
||
|
'LOWER',
|
||
|
'MAIN',
|
||
|
'MAP',
|
||
|
'MASTER_SERVER_ID',
|
||
|
'MATCH',
|
||
|
'MAX',
|
||
|
'MAXEXTENTS',
|
||
|
'MEDIUMBLOB',
|
||
|
'MEDIUMINT',
|
||
|
'MEDIUMTEXT',
|
||
|
'MIDDLEINT',
|
||
|
'MIN',
|
||
|
'MINUS',
|
||
|
'MINUTE',
|
||
|
'MINUTE_MICROSECOND',
|
||
|
'MINUTE_SECOND',
|
||
|
'MLSLABEL',
|
||
|
'MOD',
|
||
|
'MODE',
|
||
|
'MODIFIES',
|
||
|
'MODIFY',
|
||
|
'MODULE',
|
||
|
'MONTH',
|
||
|
'NAMES',
|
||
|
'NATIONAL',
|
||
|
'NATURAL',
|
||
|
'NCHAR',
|
||
|
'NCLOB',
|
||
|
'NEW',
|
||
|
'NEXT',
|
||
|
'NO',
|
||
|
'NO_WRITE_TO_BINLOG',
|
||
|
'NOAUDIT',
|
||
|
'NOCHECK',
|
||
|
'NOCOMPRESS',
|
||
|
'NONCLUSTERED',
|
||
|
'NONE',
|
||
|
'NOT',
|
||
|
'NOTNULL',
|
||
|
'NOWAIT',
|
||
|
'NULL',
|
||
|
'NULLIF',
|
||
|
'NUMBER',
|
||
|
'NUMERIC',
|
||
|
'OBJECT',
|
||
|
'OCTET_LENGTH',
|
||
|
'OF',
|
||
|
'OFF',
|
||
|
'OFFLINE',
|
||
|
'OFFSET',
|
||
|
'OFFSETS',
|
||
|
'OID',
|
||
|
'OLD',
|
||
|
'ON',
|
||
|
'ONLINE',
|
||
|
'ONLY',
|
||
|
'OPEN',
|
||
|
'OPENDATASOURCE',
|
||
|
'OPENQUERY',
|
||
|
'OPENROWSET',
|
||
|
'OPENXML',
|
||
|
'OPERATION',
|
||
|
'OPTIMIZE',
|
||
|
'OPTION',
|
||
|
'OPTIONALLY',
|
||
|
'OR',
|
||
|
'ORDER',
|
||
|
'ORDINALITY',
|
||
|
'OUT',
|
||
|
'OUTER',
|
||
|
'OUTFILE',
|
||
|
'OUTPUT',
|
||
|
'OVER',
|
||
|
'OVERLAPS',
|
||
|
'PAD',
|
||
|
'PARAMETER',
|
||
|
'PARAMETERS',
|
||
|
'PARTIAL',
|
||
|
'PATH',
|
||
|
'PCTFREE',
|
||
|
'PERCENT',
|
||
|
'PLACING',
|
||
|
'PLAN',
|
||
|
'POSITION',
|
||
|
'POSTFIX',
|
||
|
'PRECISION',
|
||
|
'PREFIX',
|
||
|
'PREORDER',
|
||
|
'PREPARE',
|
||
|
'PRESERVE',
|
||
|
'PRIMARY',
|
||
|
'PRINT',
|
||
|
'PRIOR',
|
||
|
'PRIVILEGES',
|
||
|
'PROC',
|
||
|
'PROCEDURE',
|
||
|
'PUBLIC',
|
||
|
'PURGE',
|
||
|
'RAISERROR',
|
||
|
'RAW',
|
||
|
'READ',
|
||
|
'READS',
|
||
|
'READTEXT',
|
||
|
'REAL',
|
||
|
'RECONFIGURE',
|
||
|
'RECURSIVE',
|
||
|
'REF',
|
||
|
'REFERENCES',
|
||
|
'REFERENCING',
|
||
|
'REGEXP',
|
||
|
'RELATIVE',
|
||
|
'RENAME',
|
||
|
'REPEAT',
|
||
|
'REPLACE',
|
||
|
'REPLICATION',
|
||
|
'REQUIRE',
|
||
|
'RESOURCE',
|
||
|
'RESTORE',
|
||
|
'RESTRICT',
|
||
|
'RESULT',
|
||
|
'RETURN',
|
||
|
'RETURNS',
|
||
|
'REVOKE',
|
||
|
'RIGHT',
|
||
|
'RLIKE',
|
||
|
'ROLE',
|
||
|
'ROLLBACK',
|
||
|
'ROLLUP',
|
||
|
'ROUTINE',
|
||
|
'ROW',
|
||
|
'ROWCOUNT',
|
||
|
'ROWGUIDCOL',
|
||
|
'ROWID',
|
||
|
'ROWNUM',
|
||
|
'ROWS',
|
||
|
'RULE',
|
||
|
'SAVE',
|
||
|
'SAVEPOINT',
|
||
|
'SCHEMA',
|
||
|
'SCOPE',
|
||
|
'SCROLL',
|
||
|
'SEARCH',
|
||
|
'SECOND',
|
||
|
'SECOND_MICROSECOND',
|
||
|
'SECTION',
|
||
|
'SELECT',
|
||
|
'SENSITIVE',
|
||
|
'SEPARATOR',
|
||
|
'SEQUENCE',
|
||
|
'SESSION',
|
||
|
'SESSION_USER',
|
||
|
'SET',
|
||
|
'SETS',
|
||
|
'SETUSER',
|
||
|
'SHARE',
|
||
|
'SHOW',
|
||
|
'SHUTDOWN',
|
||
|
'SIMILAR',
|
||
|
'SIZE',
|
||
|
'SMALLINT',
|
||
|
'SOME',
|
||
|
'SONAME',
|
||
|
'SPACE',
|
||
|
'SPATIAL',
|
||
|
'SPECIFIC',
|
||
|
'SPECIFICTYPE',
|
||
|
'SQL',
|
||
|
'SQL_BIG_RESULT',
|
||
|
'SQL_CALC_FOUND_ROWS',
|
||
|
'SQL_SMALL_RESULT',
|
||
|
'SQL_TSI_DAY',
|
||
|
'SQL_TSI_FRAC_SECOND',
|
||
|
'SQL_TSI_HOUR',
|
||
|
'SQL_TSI_MINUTE',
|
||
|
'SQL_TSI_MONTH',
|
||
|
'SQL_TSI_QUARTER',
|
||
|
'SQL_TSI_SECOND',
|
||
|
'SQL_TSI_WEEK',
|
||
|
'SQL_TSI_YEAR',
|
||
|
'SQLCODE',
|
||
|
'SQLERROR',
|
||
|
'SQLEXCEPTION',
|
||
|
'SQLITE_MASTER',
|
||
|
'SQLITE_TEMP_MASTER',
|
||
|
'SQLSTATE',
|
||
|
'SQLWARNING',
|
||
|
'SSL',
|
||
|
'START',
|
||
|
'STARTING',
|
||
|
'STATE',
|
||
|
'STATEMENT',
|
||
|
'STATIC',
|
||
|
'STATISTICS',
|
||
|
'STRAIGHT_JOIN',
|
||
|
'STRIPED',
|
||
|
'STRUCTURE',
|
||
|
'SUBSTRING',
|
||
|
'SUCCESSFUL',
|
||
|
'SUM',
|
||
|
'SYNONYM',
|
||
|
'SYSDATE',
|
||
|
'SYSTEM_USER',
|
||
|
'TABLE',
|
||
|
'TABLES',
|
||
|
'TEMPORARY',
|
||
|
'TERMINATE',
|
||
|
'TERMINATED',
|
||
|
'TEXTSIZE',
|
||
|
'THAN',
|
||
|
'THEN',
|
||
|
'TIME',
|
||
|
'TIMESTAMP',
|
||
|
'TIMESTAMPADD',
|
||
|
'TIMESTAMPDIFF',
|
||
|
'TIMEZONE_HOUR',
|
||
|
'TIMEZONE_MINUTE',
|
||
|
'TINYBLOB',
|
||
|
'TINYINT',
|
||
|
'TINYTEXT',
|
||
|
'TO',
|
||
|
'TOP',
|
||
|
'TRAILING',
|
||
|
'TRAN',
|
||
|
'TRANSACTION',
|
||
|
'TRANSLATE',
|
||
|
'TRANSLATION',
|
||
|
'TREAT',
|
||
|
'TRIGGER',
|
||
|
'TRIM',
|
||
|
'TRUE',
|
||
|
'TRUNCATE',
|
||
|
'TSEQUAL',
|
||
|
'UID',
|
||
|
'UNDER',
|
||
|
'UNDO',
|
||
|
'UNION',
|
||
|
'UNIQUE',
|
||
|
'UNKNOWN',
|
||
|
'UNLOCK',
|
||
|
'UNNEST',
|
||
|
'UNSIGNED',
|
||
|
'UPDATE',
|
||
|
'UPDATETEXT',
|
||
|
'UPPER',
|
||
|
'USAGE',
|
||
|
'USE',
|
||
|
'USER',
|
||
|
'USER_RESOURCES',
|
||
|
'USING',
|
||
|
'UTC_DATE',
|
||
|
'UTC_TIME',
|
||
|
'UTC_TIMESTAMP',
|
||
|
'VALIDATE',
|
||
|
'VALUE',
|
||
|
'VALUES',
|
||
|
'VARBINARY',
|
||
|
'VARCHAR',
|
||
|
'VARCHAR2',
|
||
|
'VARCHARACTER',
|
||
|
'VARIABLE',
|
||
|
'VARYING',
|
||
|
'VERBOSE',
|
||
|
'VIEW',
|
||
|
'WAITFOR',
|
||
|
'WHEN',
|
||
|
'WHENEVER',
|
||
|
'WHERE',
|
||
|
'WHILE',
|
||
|
'WITH',
|
||
|
'WITHOUT',
|
||
|
'WORK',
|
||
|
'WRITE',
|
||
|
'WRITETEXT',
|
||
|
'XOR',
|
||
|
'YEAR',
|
||
|
'YEAR_MONTH',
|
||
|
'ZEROFILL',
|
||
|
'ZONE',
|
||
|
);
|
||
|
}
|
||
|
|
||
|
?>
|