Пример #1
0
 /**
  * 
  * 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);
     }
 }
Пример #2
0
 /**
  * 
  * Verifies the table based on $this->col and $this->idx.
  * 
  * @access public
  * 
  * @return mixed Boolean true if the verification was successful, and a
  * PEAR_Error if verification failed.
  *
  * @see DB_Table_Manager::verify()
  * 
  */
 function verify()
 {
     return DB_Table_Manager::verify($this->db, $this->table, $this->col, $this->idx);
 }
Пример #3
0
 /**
  * 
  * Creates the table based on $this->col and $this->idx.
  * 
  * @access public
  * 
  * @param mixed $flag Boolean false to abort the create attempt from
  * the start, 'drop' to drop the existing table and
  * re-create it, or 'safe' to only create the table if it
  * does not exist in the database.
  * 
  * @return mixed Boolean false if there was no attempt to create the
  * table, boolean true if the attempt succeeded, or a PEAR_Error if
  * the attempt failed.
  *
  * @see DB_Table_Manager::create()
  * 
  */
 function create($flag)
 {
     // are we OK to create the table?
     $ok = false;
     // check the create-flag
     switch ($flag) {
         case 'drop':
             // forcibly drop an existing table
             $this->db->query("DROP TABLE {$this->table}");
             $ok = true;
             break;
         case 'safe':
             // create only if table does not exist
             $list = $this->db->getListOf('tables');
             // ok to create only if table does not exist
             $ok = !in_array($this->table, $list);
             break;
         default:
             // unknown flag
             return $this->throwError(DB_TABLE_ERR_CREATE_FLAG, "('{$flag}')");
     }
     // are we going to create the table?
     if (!$ok) {
         return false;
     } else {
         include_once 'DB/Table/Manager.php';
         return DB_Table_Manager::create($this->db, $this->table, $this->col, $this->idx, $flag);
     }
 }
Пример #4
0
 /**
  * Gets column and index definitions by querying database
  *
  * Upon return, column definitions are stored in $this->col[$table],
  * and index definitions in $this->idx[$table].
  *
  * Calls DB/MDB2::tableInfo() for column definitions, and uses
  * the DB_Table_Manager class to obtain index definitions.
  *
  * @param string $table name of table
  *
  * @return mixed true on success, PEAR Error on failure
  * @access public
  */
 function getTableDefinition($table)
 {
     /*
     // postgres strip the schema bit from the
     if (!empty($options['generator_strip_schema'])) {
         $bits = explode('.', $table,2);
         $table = $bits[0];
         if (count($bits) > 1) {
             $table = $bits[1];
         }
     }
     */
     if ($this->backend == 'db') {
         $defs = $this->db->tableInfo($table);
         if (PEAR::isError($defs)) {
             return $defs;
         }
         $this->columns[$table] = $defs;
     } else {
         // Temporarily change 'portability' MDB2 option
         $portability = $this->db->getOption('portability');
         $this->db->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
         $this->db->loadModule('Manager');
         $this->db->loadModule('Reverse');
         // Columns
         $defs = $this->db->reverse->tableInfo($table);
         if (PEAR::isError($defs)) {
             return $defs;
         }
         // rename the 'length' key, so it matches db's return.
         foreach ($defs as $k => $v) {
             if (isset($defs[$k]['length'])) {
                 $defs[$k]['len'] = $defs[$k]['length'];
             }
         }
         $this->columns[$table] = $defs;
         // Temporarily set 'idxname_format' MDB2 option to $this->idx_format
         $idxname_format = $this->db->getOption('idxname_format');
         $this->db->setOption('idxname_format', $this->idxname_format);
     }
     // Default - no auto increment column
     $this->auto_inc_col[$table] = null;
     // Loop over columns to create $this->col[$table]
     $this->col[$table] = array();
     foreach ($defs as $t) {
         $name = $t['name'];
         $col = array();
         switch (strtoupper($t['type'])) {
             case 'INT2':
                 // postgres
             // postgres
             case 'TINYINT':
             case 'TINY':
                 //mysql
             //mysql
             case 'SMALLINT':
                 $col['type'] = 'smallint';
                 break;
             case 'INT4':
                 // postgres
             // postgres
             case 'SERIAL4':
                 // postgres
             // postgres
             case 'INT':
             case 'SHORT':
                 // mysql
             // mysql
             case 'INTEGER':
             case 'MEDIUMINT':
             case 'YEAR':
                 $col['type'] = 'integer';
                 break;
             case 'BIGINT':
             case 'LONG':
                 // mysql
             // mysql
             case 'INT8':
                 // postgres
             // postgres
             case 'SERIAL8':
                 // postgres
                 $col['type'] = 'bigint';
                 break;
             case 'REAL':
             case 'NUMERIC':
             case 'NUMBER':
                 // oci8
             // oci8
             case 'FLOAT':
                 // mysql
             // mysql
             case 'FLOAT4':
                 // real (postgres)
                 $col['type'] = 'single';
                 break;
             case 'DOUBLE':
             case 'DOUBLE PRECISION':
                 // double precision (firebird)
             // double precision (firebird)
             case 'FLOAT8':
                 // double precision (postgres)
                 $col['type'] = 'double';
                 break;
             case 'DECIMAL':
             case 'MONEY':
                 // mssql and maybe others
                 $col['type'] = 'decimal';
                 break;
             case 'BIT':
             case 'BOOL':
             case 'BOOLEAN':
                 $col['type'] = 'boolean';
                 break;
             case 'STRING':
             case 'CHAR':
                 $col['type'] = 'char';
                 break;
             case 'VARCHAR':
             case 'VARCHAR2':
             case 'TINYTEXT':
                 $col['type'] = 'varchar';
                 break;
             case 'TEXT':
             case 'MEDIUMTEXT':
             case 'LONGTEXT':
                 $col['type'] = 'clob';
                 break;
             case 'DATE':
                 $col['type'] = 'date';
                 break;
             case 'TIME':
                 $col['type'] = 'time';
                 break;
             case 'DATETIME':
                 // mysql
             // mysql
             case 'TIMESTAMP':
                 $col['type'] = 'timestamp';
                 break;
             case 'ENUM':
             case 'SET':
                 // not really but oh well
             // not really but oh well
             case 'TIMESTAMPTZ':
                 // postgres
             // postgres
             case 'BPCHAR':
                 // postgres
             // postgres
             case 'INTERVAL':
                 // postgres (eg. '12 days')
             // postgres (eg. '12 days')
             case 'CIDR':
                 // postgres IP net spec
             // postgres IP net spec
             case 'INET':
                 // postgres IP
             // postgres IP
             case 'MACADDR':
                 // postgress network Mac address.
             // postgress network Mac address.
             case 'INTEGER[]':
                 // postgres type
             // postgres type
             case 'BOOLEAN[]':
                 // postgres type
                 $col['type'] = 'varchar';
                 break;
             default:
                 $col['type'] = $t['type'] . ' (Unknown type)';
                 break;
         }
         // Set length and scope if required
         if (in_array($col['type'], array('char', 'varchar', 'decimal'))) {
             if (isset($t['len'])) {
                 $col['size'] = (int) $t['len'];
             } elseif ($col['type'] == 'varchar') {
                 $col['size'] = 255;
                 // default length
             } elseif ($col['type'] == 'char') {
                 $col['size'] = 128;
                 // default length
             } elseif ($col['type'] == 'decimal') {
                 $col['size'] = 15;
                 // default length
             }
             if ($col['type'] == 'decimal') {
                 $col['scope'] = 2;
             }
         }
         if (isset($t['notnull'])) {
             if ($t['notnull']) {
                 $col['require'] = true;
             }
         }
         if (isset($t['autoincrement'])) {
             $this->auto_inc_col[$table] = $name;
         }
         if (isset($t['flags'])) {
             $flags = $t['flags'];
             if (preg_match('/not[ _]null/i', $flags)) {
                 $col['require'] = true;
             }
             if (preg_match("/(auto_increment|nextval\\()/i", $flags)) {
                 $this->auto_inc_col[$table] = $name;
             }
         }
         $require = isset($col['require']) ? $col['require'] : false;
         if ($require) {
             if (isset($t['default'])) {
                 $default = $t['default'];
                 $type = $col['type'];
                 if (in_array($type, array('smallint', 'integer', 'bigint'))) {
                     $default = (int) $default;
                 } elseif (in_array($type, array('single', 'double'))) {
                     $default = (double) $default;
                 } elseif ($type == 'boolean') {
                     $default = (int) $default ? 1 : 0;
                 }
                 $col['default'] = $default;
             }
         }
         $this->col[$table][$name] = $col;
     }
     // Make array with lower case column array names as keys
     $col_lc = array();
     foreach ($this->col[$table] as $name => $def) {
         $name_lc = strtolower($name);
         $col_lc[$name_lc] = $name;
     }
     // Constraints/Indexes
     $DB_indexes = DB_Table_Manager::getIndexes($this->db, $table);
     if (PEAR::isError($DB_indexes)) {
         return $DB_indexes;
     }
     // Check that index columns correspond to valid column names.
     // Try to correct problems with capitalization, if necessary.
     foreach ($DB_indexes as $type => $indexes) {
         foreach ($indexes as $name => $fields) {
             foreach ($fields as $key => $field) {
                 // If index column is not a valid column name
                 if (!array_key_exists($field, $this->col[$table])) {
                     // Try a case-insensitive match
                     $field_lc = strtolower($field);
                     if (isset($col_lc[$field_lc])) {
                         $correct = $col_lc[$field_lc];
                         $DB_indexes[$type][$name][$key] = $correct;
                     } else {
                         $code = DB_TABLE_GENERATOR_ERR_INDEX_COL;
                         $return =& DB_Table_Generator::throwError($code, $field);
                     }
                 }
             }
         }
     }
     // Generate index definitions, if any, as php code
     $n_idx = 0;
     $u = array();
     $this->idx[$table] = array();
     $this->primary_key[$table] = null;
     foreach ($DB_indexes as $type => $indexes) {
         if (count($indexes) > 0) {
             foreach ($indexes as $name => $fields) {
                 $this->idx[$table][$name] = array();
                 $this->idx[$table][$name]['type'] = $type;
                 if (count($fields) == 1) {
                     $key = $fields[0];
                 } else {
                     $key = array();
                     foreach ($fields as $value) {
                         $key[] = $value;
                     }
                 }
                 $this->idx[$table][$name]['cols'] = $key;
                 if ($type == 'primary') {
                     $this->primary_key[$table] = $key;
                 }
             }
         }
     }
     if ($this->backend == 'mdb2') {
         // Restore original MDB2 'idxname_format' and 'portability'
         $this->db->setOption('idxname_format', $idxname_format);
         $this->db->setOption('portability', $portability);
     }
     return true;
 }
Пример #5
0
 /**
  * 
  * Create the table based on DB_Table column and index arrays.
  * 
  * @static
  * 
  * @access public
  * 
  * @param object &$db A PEAR DB 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)
 {
     // columns to be created
     $column = array();
     // indexes to be created
     $index = array();
     // is the table name too long?
     if (strlen($table) > 30) {
         return DB_Table::throwError(DB_TABLE_ERR_TABLE_STRLEN, " ('{$table}')");
     }
     // -------------------------------------------------------------
     //
     // validate each column mapping and build the individual
     // definitions, and note column indexes as we go.
     //
     foreach ($column_set as $colname => $val) {
         $colname = trim($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 must be no longer than 30 chars
         if (strlen($colname) > 30) {
             return DB_Table::throwError(DB_TABLE_ERR_DECLARE_STRLEN, "('{$colname}')");
         }
         // 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;
         // get the declaration string
         $result = DB_Table_Manager::getDeclare($db->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.
     //
     foreach ($index_set as $idxname => $val) {
         if (is_string($val)) {
             // shorthand for index names: colname => index_type
             $type = trim($val);
             $cols = trim($idxname);
         } elseif (is_array($val)) {
             // normal: index_name => array('type' => ..., 'cols' => ...)
             $type = isset($val['type']) ? $val['type'] : 'normal';
             $cols = isset($val['cols']) ? $val['cols'] : null;
         }
         // index name cannot be a reserved keyword
         $reserved = in_array(strtoupper($idxname), $GLOBALS['_DB_TABLE']['reserved']);
         if ($reserved) {
             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}')");
             }
         }
         // string of column names
         $colstring = implode(', ', $cols);
         // 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';
         // now check the length; must be under 30 chars to
         // soothe Oracle.
         if (strlen($newIdxName) > 30) {
             return DB_Table::throwError(DB_TABLE_ERR_IDX_STRLEN, "'{$idxname}' ('{$newIdxName}')");
         }
         // create index entry
         if ($type == 'unique') {
             $index[] = "CREATE UNIQUE INDEX {$newIdxName} ON {$table} ({$colstring})";
         } elseif ($type == 'normal') {
             $index[] = "CREATE INDEX {$newIdxName} ON {$table} ({$colstring})";
         } else {
             return DB_Table::throwError(DB_TABLE_ERR_IDX_TYPE, "'{$idxname}' ('{$type}')");
         }
     }
     // -------------------------------------------------------------
     //
     // now for the real action: create the table and indexes!
     //
     // 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;
     }
     // attempt to create the indexes
     foreach ($index as $cmd) {
         $result = $db->query($cmd);
         if (PEAR::isError($result)) {
             return $result;
         }
     }
     // we're done!
     return true;
 }