From c9462d0c1e2493a7399b1dbd21e23b215e97f808 Mon Sep 17 00:00:00 2001 From: svncommit Date: Thu, 27 Oct 2005 13:40:37 +0000 Subject: added all mdb2 drivers --- program/lib/MDB2/Driver/Reverse/fbsql.php | 157 ++++++++++++ program/lib/MDB2/Driver/Reverse/ibase.php | 238 +++++++++++++++++++ program/lib/MDB2/Driver/Reverse/mssql.php | 269 +++++++++++++++++++++ program/lib/MDB2/Driver/Reverse/mysqli.php | 368 +++++++++++++++++++++++++++++ program/lib/MDB2/Driver/Reverse/oci8.php | 178 ++++++++++++++ program/lib/MDB2/Driver/Reverse/pgsql.php | 356 ++++++++++++++++++++++++++++ program/lib/MDB2/Driver/Reverse/sqlite.php | 308 ++++++++++++++++++++++++ 7 files changed, 1874 insertions(+) create mode 100755 program/lib/MDB2/Driver/Reverse/fbsql.php create mode 100755 program/lib/MDB2/Driver/Reverse/ibase.php create mode 100755 program/lib/MDB2/Driver/Reverse/mssql.php create mode 100755 program/lib/MDB2/Driver/Reverse/mysqli.php create mode 100755 program/lib/MDB2/Driver/Reverse/oci8.php create mode 100755 program/lib/MDB2/Driver/Reverse/pgsql.php create mode 100755 program/lib/MDB2/Driver/Reverse/sqlite.php (limited to 'program/lib/MDB2/Driver/Reverse') diff --git a/program/lib/MDB2/Driver/Reverse/fbsql.php b/program/lib/MDB2/Driver/Reverse/fbsql.php new file mode 100755 index 000000000..d20d1957a --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/fbsql.php @@ -0,0 +1,157 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 FrontBase driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_fbsql extends MDB2_Driver_Reverse_Common +{ + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + + $connected = $db->connect(); + if (PEAR::isError($connected)) { + return $connected; + } + $id = @fbsql_list_fields($db->database_name, $result, $db->connection); + $got_string = true; + } elseif (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->getResource(); + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $count = @fbsql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $case_func(@fbsql_field_table($id, $i)), + 'name' => $case_func(@fbsql_field_name($id, $i)), + 'type' => @fbsql_field_type($id, $i), + 'len' => @fbsql_field_len($id, $i), + 'flags' => @fbsql_field_flags($id, $i), + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @fbsql_free_result($id); + } + return $res; + } +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Driver/Reverse/ibase.php b/program/lib/MDB2/Driver/Reverse/ibase.php new file mode 100755 index 000000000..8895744fc --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/ibase.php @@ -0,0 +1,238 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 InterbaseBase driver for the reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_ibase extends MDB2_Driver_Reverse_Common +{ + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = $db->_doQuery("SELECT * FROM $result WHERE 1=0"); + if (PEAR::isError($id)) { + return $id; + } + $got_string = true; + } elseif (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->getResource(); + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $count = @ibase_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $info = @ibase_field_info($id, $i); + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func($info['name']), + 'type' => $info['type'], + 'len' => $info['length'], + 'flags' => ($got_string) + ? $this->_ibaseFieldFlags($info['name'], $result) : '', + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @ibase_free_result($id); + } + return $res; + } + + // }}} + // {{{ _ibaseFieldFlags() + + /** + * Get the column's flags + * + * Supports "primary_key", "unique_key", "not_null", "default", + * "computed" and "blob". + * + * @param string $field_name the name of the field + * @param string $table_name the name of the table + * + * @return string the flags + * + * @access protected + */ + function _ibaseFieldFlags($field_name, $table_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE' + .' FROM RDB$INDEX_SEGMENTS I' + .' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME' + .' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\'' + .' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''; + + $result = $db->_doQuery($query); + if (PEAR::isError($result)) { + return $result; + } + + $flags = ''; + if ($obj = @ibase_fetch_object($result)) { + @ibase_free_result($result); + if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') { + $flags.= 'primary_key '; + } + if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') { + $flags.= 'unique_key '; + } + } + + $query = 'SELECT R.RDB$NULL_FLAG AS NFLAG,' + .' R.RDB$DEFAULT_SOURCE AS DSOURCE,' + .' F.RDB$FIELD_TYPE AS FTYPE,' + .' F.RDB$COMPUTED_SOURCE AS CSOURCE' + .' FROM RDB$RELATION_FIELDS R ' + .' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME' + .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'' + .' AND R.RDB$FIELD_NAME=\'' . $field_name . '\''; + + $result = $db->_doQuery($query); + if (PEAR::isError($result)) { + return $result; + } + + if ($obj = @ibase_fetch_object($result)) { + @ibase_free_result($result); + if (isset($obj->NFLAG)) { + $flags.= 'not_null '; + } + if (isset($obj->DSOURCE)) { + $flags.= 'default '; + } + if (isset($obj->CSOURCE)) { + $flags.= 'computed '; + } + if (isset($obj->FTYPE) && $obj->FTYPE == 261) { + $flags.= 'blob '; + } + } + + return trim($flags); + } +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Driver/Reverse/mssql.php b/program/lib/MDB2/Driver/Reverse/mssql.php new file mode 100755 index 000000000..658b7df60 --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/mssql.php @@ -0,0 +1,269 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 MSSQL driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common +{ + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = $db->_doQuery("SELECT TOP 0 * FROM [$result]"); + if (PEAR::isError($id)) { + return $id; + } + + $got_string = true; + } elseif (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->getResource(); + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $count = @mssql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@mssql_field_name($id, $i)), + 'type' => @mssql_field_type($id, $i), + 'len' => @mssql_field_length($id, $i), + // We only support flags for table + 'flags' => $got_string + ? $this->_mssql_field_flags($result, @mssql_field_name($id, $i)) : '', + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mssql_free_result($id); + } + return $res; + } + + // }}} + // {{{ _mssql_field_flags() + + /** + * Get a column's flags + * + * Supports "not_null", "primary_key", + * "auto_increment" (mssql identity), "timestamp" (mssql timestamp), + * "unique_key" (mssql unique index, unique check or primary_key) and + * "multiple_key" (multikey index) + * + * mssql timestamp is NOT similar to the mysql timestamp so this is maybe + * not useful at all - is the behaviour of mysql_field_flags that primary + * keys are alway unique? is the interpretation of multiple_key correct? + * + * @param string $table the table name + * @param string $column the field name + * + * @return string the flags + * + * @access protected + * @author Joern Barthel + */ + function _mssql_field_flags($table, $column) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + static $tableName = null; + static $flags = array(); + + if ($table != $tableName) { + + $flags = array(); + $tableName = $table; + + // get unique and primary keys + $res = $db->queryAll("EXEC SP_HELPINDEX[$table]", null, MDB2_FETCHMODE_ASSOC); + + foreach ($res as $val) { + $keys = explode(', ', $val['index_keys']); + + if (sizeof($keys) > 1) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'multiple_key'); + } + } + + if (strpos($val['index_description'], 'primary key')) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'primary_key'); + } + } elseif (strpos($val['index_description'], 'unique')) { + foreach ($keys as $key) { + $this->_add_flag($flags[$key], 'unique_key'); + } + } + } + + // get auto_increment, not_null and timestamp + $res = $db->queryAll("EXEC SP_COLUMNS[$table]", null, MDB2_FETCHMODE_ASSOC); + + foreach ($res as $val) { + $val = array_change_key_case($val, $db->options['field_case']); + if ($val['nullable'] == '0') { + $this->_add_flag($flags[$val['column_name']], 'not_null'); + } + if (strpos($val['type_name'], 'identity')) { + $this->_add_flag($flags[$val['column_name']], 'auto_increment'); + } + if (strpos($val['type_name'], 'timestamp')) { + $this->_add_flag($flags[$val['column_name']], 'timestamp'); + } + } + } + + if (array_key_exists($column, $flags)) { + return(implode(' ', $flags[$column])); + } + return ''; + } + + // }}} + // {{{ _add_flag() + + /** + * Adds a string to the flags array if the flag is not yet in there + * - if there is no flag present the array is created + * + * @param array &$array the reference to the flag-array + * @param string $value the flag value + * + * @return void + * + * @access protected + * @author Joern Barthel + */ + function _add_flag(&$array, $value) + { + if (!is_array($array)) { + $array = array($value); + } elseif (!in_array($value, $array)) { + array_push($array, $value); + } + } +} +?> diff --git a/program/lib/MDB2/Driver/Reverse/mysqli.php b/program/lib/MDB2/Driver/Reverse/mysqli.php new file mode 100755 index 000000000..f452c0d53 --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/mysqli.php @@ -0,0 +1,368 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 MySQL driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common +{ + /** + * Array for converting MYSQLI_*_FLAG constants to text values + * @var array + * @access public + * @since Property available since Release 1.6.5 + */ + var $flags = array( + MYSQLI_NOT_NULL_FLAG => 'not_null', + MYSQLI_PRI_KEY_FLAG => 'primary_key', + MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', + MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', + MYSQLI_BLOB_FLAG => 'blob', + MYSQLI_UNSIGNED_FLAG => 'unsigned', + MYSQLI_ZEROFILL_FLAG => 'zerofill', + MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', + MYSQLI_TIMESTAMP_FLAG => 'timestamp', + MYSQLI_SET_FLAG => 'set', + // MYSQLI_NUM_FLAG => 'numeric', // unnecessary + // MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie + MYSQLI_GROUP_FLAG => 'group_by' + ); + + /** + * Array for converting MYSQLI_TYPE_* constants to text values + * @var array + * @access public + * @since Property available since Release 1.6.5 + */ + var $types = array( + MYSQLI_TYPE_DECIMAL => 'decimal', + MYSQLI_TYPE_TINY => 'tinyint', + MYSQLI_TYPE_SHORT => 'int', + MYSQLI_TYPE_LONG => 'int', + MYSQLI_TYPE_FLOAT => 'float', + MYSQLI_TYPE_DOUBLE => 'double', + // MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it + MYSQLI_TYPE_TIMESTAMP => 'timestamp', + MYSQLI_TYPE_LONGLONG => 'bigint', + MYSQLI_TYPE_INT24 => 'mediumint', + MYSQLI_TYPE_DATE => 'date', + MYSQLI_TYPE_TIME => 'time', + MYSQLI_TYPE_DATETIME => 'datetime', + MYSQLI_TYPE_YEAR => 'year', + MYSQLI_TYPE_NEWDATE => 'date', + MYSQLI_TYPE_ENUM => 'enum', + MYSQLI_TYPE_SET => 'set', + MYSQLI_TYPE_TINY_BLOB => 'tinyblob', + MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', + MYSQLI_TYPE_LONG_BLOB => 'longblob', + MYSQLI_TYPE_BLOB => 'blob', + MYSQLI_TYPE_VAR_STRING => 'varchar', + MYSQLI_TYPE_STRING => 'char', + MYSQLI_TYPE_GEOMETRY => 'geometry', + ); + + // {{{ getTableFieldDefinition() + + /** + * get the stucture of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $field_name name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableFieldDefinition($table, $field_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->loadModule('Datatype'); + if (PEAR::isError($result)) { + return $result; + } + $columns = $db->queryAll("SHOW COLUMNS FROM $table", null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($columns)) { + return $columns; + } + foreach ($columns as $column) { + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $column['field'] = strtolower($column['field']); + } else { + $column['field'] = strtoupper($column['field']); + } + } else { + $column = array_change_key_case($column, $db->options['field_case']); + } + if ($field_name == $column['field']) { + list($types, $length) = $db->datatype->mapNativeDatatype($column); + $notnull = false; + if (array_key_exists('null', $column) && $column['null'] != 'YES') { + $notnull = true; + } + $default = false; + if (array_key_exists('default', $column)) { + $default = $column['default']; + if (is_null($default) && $notnull) { + $default = ''; + } + } + $autoincrement = false; + if (array_key_exists('extra', $column) && $column['extra'] == 'auto_increment') { + $autoincrement = true; + } + $definition = array(); + foreach ($types as $key => $type) { + $definition[$key] = array( + 'type' => $type, + 'notnull' => $notnull, + ); + if ($length > 0) { + $definition[$key]['length'] = $length; + } + if ($default !== false) { + $definition[$key]['default'] = $default; + } + if ($autoincrement !== false) { + $definition[$key]['autoincrement'] = $autoincrement; + } + } + return $definition; + } + } + + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableFieldDefinition: it was not specified an existing table column'); + } + + // }}} + // {{{ getTableIndexDefinition() + + /** + * get the stucture of an index into an array + * + * @param string $table name of table that should be used in method + * @param string $index_name name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableIndexDefinition($table, $index_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->query("SHOW INDEX FROM $table"); + if (PEAR::isError($result)) { + return $result; + } + $definition = array(); + while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) { + if (!($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) + || $db->options['field_case'] != CASE_LOWER + ) { + $row = array_change_key_case($row, CASE_LOWER); + } + $key_name = $row['key_name']; + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $key_name = strtolower($key_name); + } else { + $key_name = strtoupper($key_name); + } + } + if ($index_name == $key_name) { + if ($row['key_name'] == 'PRIMARY') { + $definition['primary'] = true; + } elseif (!$row['non_unique']) { + $definition['unique'] = true; + } + $column_name = $row['column_name']; + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $column_name = strtolower($column_name); + } else { + $column_name = strtoupper($column_name); + } + } + $definition['fields'][$column_name] = array(); + if (array_key_exists('collation', $row)) { + $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A' + ? 'ascending' : 'descending'); + } + } + } + $result->free(); + if (!array_key_exists('fields', $definition)) { + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableIndexDefinition: it was not specified an existing table index'); + } + return $definition; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::setOption() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = $db->_doQuery("SELECT * FROM $result LIMIT 0"); + if (PEAR::isError($id)) { + return $id; + } + $got_string = true; + } elseif (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->getResource(); + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_a($id, 'mysqli_result')) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $count = @mysqli_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $tmp = @mysqli_fetch_field($id); + + $flags = ''; + foreach ($this->flags as $const => $means) { + if ($tmp->flags & $const) { + $flags.= $means . ' '; + } + } + if ($tmp->def) { + $flags.= 'default_' . rawurlencode($tmp->def); + } + $flags = trim($flags); + + $res[$i] = array( + 'table' => $case_func($tmp->table), + 'name' => $case_func($tmp->name), + 'type' => isset($this->types[$tmp->type]) + ? $this->types[$tmp->type] + : 'unknown', + 'len' => $tmp->max_length, + 'flags' => $flags, + ); + + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mysqli_free_result($id); + } + return $res; + } +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Driver/Reverse/oci8.php b/program/lib/MDB2/Driver/Reverse/oci8.php new file mode 100755 index 000000000..7447fb008 --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/oci8.php @@ -0,0 +1,178 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 Oracle driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_oci8 extends MDB2_Driver_Reverse_Common +{ + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * NOTE: flags won't contain index information. + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $res = array(); + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $result = strtoupper($result); + $query = 'SELECT column_name, data_type, data_length, ' + . 'nullable ' + . 'FROM user_tab_columns ' + . "WHERE table_name='$result' ORDER BY column_id"; + + $stmt = $db->_doQuery($query); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $i = 0; + while (@OCIFetch($stmt)) { + $res[$i] = array( + 'table' => $case_func($result), + 'name' => $case_func(@OCIResult($stmt, 1)), + 'type' => @OCIResult($stmt, 2), + 'len' => @OCIResult($stmt, 3), + 'flags' => (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '', + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + $i++; + } + + if ($mode) { + $res['num_fields'] = $i; + } + @OCIFreeStatement($stmt); + + } else { + if (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $result = $result->getResource(); + } + + $res = array(); + + if ($result === $db->last_stmt) { + $count = @OCINumCols($result); + if ($mode) { + $res['num_fields'] = $count; + } + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => '', + 'name' => $case_func(@OCIColumnName($result, $i+1)), + 'type' => @OCIColumnType($result, $i+1), + 'len' => @OCIColumnSize($result, $i+1), + 'flags' => '', + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + } else { + return $db->raiseError(MDB2_ERROR_NOT_CAPABLE); + } + } + return $res; + } +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Driver/Reverse/pgsql.php b/program/lib/MDB2/Driver/Reverse/pgsql.php new file mode 100755 index 000000000..28629eed0 --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/pgsql.php @@ -0,0 +1,356 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 PostGreSQL driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Paul Cooper + */ +class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common +{ + // {{{ getTableFieldDefinition() + + /** + * get the stucture of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $field_name name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableFieldDefinition($table, $field_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->loadModule('Datatype'); + if (PEAR::isError($result)) { + return $result; + } + + $column = $db->queryRow("SELECT + attnum,attname,typname,attlen,attnotnull, + atttypmod,usename,usesysid,pg_class.oid,relpages, + reltuples,relhaspkey,relhasrules,relacl,adsrc + FROM pg_class,pg_user,pg_type, + pg_attribute left outer join pg_attrdef on + pg_attribute.attrelid=pg_attrdef.adrelid + WHERE (pg_class.relname='$table') + and (pg_class.oid=pg_attribute.attrelid) + and (pg_class.relowner=pg_user.usesysid) + and (pg_attribute.atttypid=pg_type.oid) + and attnum > 0 + and attname = '$field_name' + ORDER BY attnum + ", null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($column)) { + return $column; + } + + list($types, $length) = $db->datatype->mapNativeDatatype($column); + $notnull = false; + if (array_key_exists('attnotnull', $column) && $column['attnotnull'] == 't') { + $notnull = true; + } + $default = false; + // todo .. check how default look like + if (!preg_match("/nextval\('([^']+)'/", $column['adsrc']) + && strlen($column['adsrc']) > 2 + ) { + $default = substr($column['adsrc'], 1, -1); + if (is_null($default) && $notnull) { + $default = ''; + } + } + $autoincrement = false; + if (preg_match("/nextval\('([^']+)'/", $column['adsrc'], $nextvals)) { + $autoincrement = true; + } + $definition = array(); + foreach ($types as $key => $type) { + $definition[$key] = array( + 'type' => $type, + 'notnull' => $notnull, + ); + if ($length > 0) { + $definition[$key]['length'] = $length; + } + if ($default !== false) { + $definition[$key]['default'] = $default; + } + if ($autoincrement !== false) { + $definition[$key]['autoincrement'] = $autoincrement; + } + } + return $definition; + } + + + // }}} + // {{{ getTableIndexDefinition() + /** + * get the stucture of an index into an array + * + * @param string $table name of table that should be used in method + * @param string $index_name name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableIndexDefinition($table, $index_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = "SELECT * FROM pg_index, pg_class + WHERE (pg_class.relname='$index_name') AND (pg_class.oid=pg_index.indexrelid)"; + $row = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($row)) { + return $row; + } + if ($row['relname'] != $index_name) { + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableIndexDefinition: it was not specified an existing table index'); + } + + $db->loadModule('Manager'); + $columns = $db->manager->listTableFields($table); + + $definition = array(); + if ($row['indisunique'] == 't') { + $definition['unique'] = true; + } + + $index_column_numbers = explode(' ', $row['indkey']); + + foreach ($index_column_numbers as $number) { + $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending'); + } + return $definition; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if $result + * is a table name. + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = $db->_doQuery("SELECT * FROM $result LIMIT 0"); + if (PEAR::isError($id)) { + return $id; + } + $got_string = true; + } elseif (MDB2::isResultCommon($result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->getResource(); + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($db->options['field_case'] == CASE_LOWER) { + $case_func = 'strtolower'; + } else { + $case_func = 'strtoupper'; + } + } else { + $case_func = 'strval'; + } + + $count = @pg_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@pg_field_name($id, $i)), + 'type' => @pg_field_type($id, $i), + 'len' => @pg_field_size($id, $i), + 'flags' => $got_string + ? $this->_pgFieldFlags($id, $i, $result) + : '', + ); + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @pg_free_result($id); + } + return $res; + } + + // }}} + // {{{ _pgFieldFlags() + + /** + * Get a column's flags + * + * Supports "not_null", "default_value", "primary_key", "unique_key" + * and "multiple_key". The default value is passed through + * rawurlencode() in case there are spaces in it. + * + * @param int $resource the PostgreSQL result identifier + * @param int $num_field the field number + * + * @return string the flags + * + * @access protected + */ + function _pgFieldFlags($resource, $num_field, $table_name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $field_name = @pg_field_name($resource, $num_field); + + $result = @pg_query($db->connection, "SELECT f.attnotnull, f.atthasdef + FROM pg_attribute f, pg_class tab, pg_type typ + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + if (@pg_num_rows($result) > 0) { + $row = @pg_fetch_row($result, 0); + $flags = ($row[0] == 't') ? 'not_null ' : ''; + + if ($row[1] == 't') { + $result = @pg_query($db->connection, "SELECT a.adsrc + FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a + WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid + AND f.attrelid = a.adrelid AND f.attname = '$field_name' + AND tab.relname = '$table_name' AND f.attnum = a.adnum"); + $row = @pg_fetch_row($result, 0); + $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); + $flags.= 'default_' . rawurlencode($num) . ' '; + } + } else { + $flags = ''; + } + $result = @pg_query($db->connection, "SELECT i.indisunique, i.indisprimary, i.indkey + FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attrelid = i.indrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + $count = @pg_num_rows($result); + + for ($i = 0; $i < $count ; $i++) { + $row = @pg_fetch_row($result, $i); + $keys = explode(' ', $row[2]); + + if (in_array($num_field + 1, $keys)) { + $flags.= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; + $flags.= ($row[1] == 't') ? 'primary_key ' : ''; + if (count($keys) > 1) + $flags.= 'multiple_key '; + } + } + + return trim($flags); + } +} +?> \ No newline at end of file diff --git a/program/lib/MDB2/Driver/Reverse/sqlite.php b/program/lib/MDB2/Driver/Reverse/sqlite.php new file mode 100755 index 000000000..dd56853cc --- /dev/null +++ b/program/lib/MDB2/Driver/Reverse/sqlite.php @@ -0,0 +1,308 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +require_once 'MDB2/Driver/Reverse/Common.php'; + +/** + * MDB2 SQlite driver for the schema reverse engineering module + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common +{ + + function _getTableColumns($query) + { + $start_pos = strpos($query, '('); + $end_pos = strrpos($query, ')'); + $column_def = substr($query, $start_pos+1, $end_pos-$start_pos-1); + $column_sql = split(',', $column_def); + $columns = array(); + $count = count($column_sql); + if ($count == 0) { + return $db->raiseError('unexpected empty table column definition list'); + } + $regexp = '/^([^ ]+) (CHAR|VARCHAR|VARCHAR2|TEXT|INT|INTEGER|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( PRIMARY)?( \(([1-9][0-9]*)(,([1-9][0-9]*))?\))?( DEFAULT (\'[^\']*\'|[^ ]+))?( NOT NULL)?$/i'; + for ($i=0, $j=0; $i<$count; ++$i) { + if (!preg_match($regexp, $column_sql[$i], $matches)) { + return $db->raiseError('unexpected table column SQL definition'); + } + $columns[$j]['name'] = $matches[1]; + $columns[$j]['type'] = strtolower($matches[2]); + if (isset($matches[5]) && strlen($matches[5])) { + $columns[$j]['length'] = $matches[5]; + } + if (isset($matches[7]) && strlen($matches[7])) { + $columns[$j]['decimal'] = $matches[7]; + } + if (isset($matches[9]) && strlen($matches[9])) { + $default = $matches[9]; + if (strlen($default) && $default[0]=="'") { + $default = str_replace("''", "'", substr($default, 1, strlen($default)-2)); + } + $columns[$j]['default'] = $default; + } + if (isset($matches[10]) && strlen($matches[10])) { + $columns[$j]['notnull'] = true; + } + ++$j; + } + return $columns; + } + + // {{{ getTableFieldDefinition() + + /** + * get the stucture of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $field_name name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableFieldDefinition($table, $field_name) + { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $result = $db->loadModule('Datatype'); + if (PEAR::isError($result)) { + return $result; + } + $query = "SELECT sql FROM sqlite_master WHERE type='table' AND name='$table'"; + $query = $db->queryOne($query); + if (PEAR::isError($query)) { + return $query; + } + if (PEAR::isError($columns = $this->_getTableColumns($query))) { + return $columns; + } + foreach ($columns as $column) { + if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) { + $column['name'] = strtolower($column['name']); + } else { + $column = array_change_key_case($column, CASE_LOWER); + } + if ($field_name == $column['name']) { + list($types, $length) = $db->datatype->mapNativeDatatype($column); + unset($notnull); + if (isset($column['null']) && $column['null'] != 'YES') { + $notnull = true; + } + unset($default); + if (isset($column['default'])) { + $default = $column['default']; + } + $definition = array(); + foreach ($types as $key => $type) { + $definition[0][$key] = array('type' => $type); + if (isset($notnull)) { + $definition[0][$key]['notnull'] = true; + } + if (isset($default)) { + $definition[0][$key]['default'] = $default; + } + if (isset($length)) { + $definition[0][$key]['length'] = $length; + } + } + // todo .. handle auto_inrement and primary keys + return $definition; + } + } + + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableFieldDefinition: it was not specified an existing table column'); + } + + // }}} + // {{{ getTableIndexDefinition() + + /** + * get the stucture of an index into an array + * + * @param string $table name of table that should be used in method + * @param string $index_name name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableIndexDefinition($table, $index_name) + { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + if ($index_name == 'PRIMARY') { + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableIndexDefinition: PRIMARY is an hidden index'); + } + $query = "SELECT sql FROM sqlite_master WHERE type='index' AND name='$index_name' AND tbl_name='$table' AND sql NOT NULL ORDER BY name"; + $result = $db->query($query); + if (PEAR::isError($result)) { + return $result; + } + $columns = $result->getColumnNames(); + $column = 'sql'; + if (!isset($columns[$column])) { + $result->free(); + return $db->raiseError('getTableIndexDefinition: show index does not return the table creation sql'); + } + + $query = strtolower($result->fetchOne()); + $unique = strstr($query, ' unique '); + $key_name = $index_name; + $start_pos = strpos($query, '('); + $end_pos = strrpos($query, ')'); + $column_names = substr($query, $start_pos+1, $end_pos-$start_pos-1); + $column_names = split(',', $column_names); + + $definition = array(); + if ($unique) { + $definition['unique'] = true; + } + $count = count($column_names); + for ($i=0; $i<$count; ++$i) { + $column_name = strtok($column_names[$i]," "); + $collation = strtok(" "); + $definition['fields'][$column_name] = array(); + if (!empty($collation)) { + $definition['fields'][$column_name]['sorting'] = ($collation=='ASC' ? 'ascending' : 'descending'); + } + } + + $result->free(); + if (!isset($definition['fields'])) { + return $db->raiseError(MDB2_ERROR, null, null, + 'getTableIndexDefinition: it was not specified an existing table index'); + } + return $definition; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table + * + * @param string $result a string containing the name of a table + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_common::tableInfo() + * @since Method available since Release 1.7.0 + */ + function tableInfo($result, $mode = null) + { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = $db->queryAll("PRAGMA table_info('$result');", null, MDB2_FETCHMODE_ASSOC); + $got_string = true; + } else { + return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null, + 'This DBMS can not obtain tableInfo' . + ' from result sets'); + } + + if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = count($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + if (strpos($id[$i]['type'], '(') !== false) { + $bits = explode('(', $id[$i]['type']); + $type = $bits[0]; + $len = rtrim($bits[1],')'); + } else { + $type = $id[$i]['type']; + $len = 0; + } + + $flags = ''; + if ($id[$i]['pk']) { + $flags .= 'primary_key '; + } + if ($id[$i]['notnull']) { + $flags .= 'not_null '; + } + if ($id[$i]['dflt_value'] !== null) { + $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); + } + $flags = trim($flags); + + $res[$i] = array( + 'table' => $case_func($result), + 'name' => $case_func($id[$i]['name']), + 'type' => $type, + 'len' => $len, + 'flags' => $flags, + ); + + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + return $res; + } +} + +?> \ No newline at end of file -- cgit v1.2.3