* Script execution
* Create view wizard looks buggy
* alter function on < 7.2 needs testing
+* error on viewing reports page
+* highlight things on the info stats page
+* advanced stats functions
+* 7.5 alter column support needs a lot of testing in pre-7.5
+* also, array types are not displayed correcting 7.0
+
field while editing data.
* Show query runtime when executing arbitrary SQL
* Allow renaming functions when backend supports it
+* Allow adding SERIAL and BIGSERIAL columns in 7.5-dev
* Views are now more like tables. They are listed in the browser,
you can view the virtual columns of the view and see column defaults.
Columns in view can also be renamed and have defaults set.
+* Support for 7.5-dev ALTER COLUMN TYPE, adding of SERIAL and BIGSERIAL
+ columns, adding NOT NULL columns and adding columns with defaults.
Bugs
* Fix pg_dump output for PostgreSQL 7.0.x and 7.1.x
* -Fix failure to drop database even tho seemingly no-one is connected to it (chriskl, bryan)
* Add alter database for 7.3+
* -Dump database using pg_dump streaming (chriskl)
+* Comments on databases
Tables
------
* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: BaseDB.php,v 1.44 2004/05/09 09:10:04 chriskl Exp $
+ * $Id: BaseDB.php,v 1.45 2004/05/14 07:56:37 chriskl Exp $
*/
include_once('./classes/database/ADODB_base.php');
function hasStatsCollector() { return false; }
function hasSchemaDump() { return false; }
function hasFunctionRename() { return false; }
+ function hasAlterColumnType() { return false; }
}
* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres.php,v 1.202 2004/05/14 01:16:14 soranzo Exp $
+ * $Id: Postgres.php,v 1.203 2004/05/14 07:56:38 chriskl Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
}
else {
$sql = "SELECT
- a.attname, t.typname as type, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, -1 AS attstattarget, a.attstorage,
+ a.attname, t.typname as type, t.typename as base_type,
+ a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, -1 AS attstattarget, a.attstorage,
(SELECT adsrc FROM pg_attrdef adef WHERE a.attrelid=adef.adrelid AND a.attnum=adef.adnum) AS adsrc,
a.attstorage AS typstorage,
(SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
* @param $oldnotnull (boolean) True if column is already not null, false otherwise
* @param $default The new default for the column
* @param $olddefault The old default for the column
+ * @param $type The new type for the column
+ * @param $array True if array type, false otherwise
+ * @param $length The optional size of the column (ie. 30 for varchar(30))
+ * @param $oldtype The old type for the column
* @param $comment Comment for the column
* @return 0 success
* @return -1 set not null error
* @return -3 rename column error
* @return -4 comment error
*/
- function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault, $comment) {
+ function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault,
+ $type, $length, $array, $oldtype, $comment) {
$this->clean($comment);
$this->beginTransaction();
* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres71.php,v 1.56 2004/05/14 01:16:14 soranzo Exp $
+ * $Id: Postgres71.php,v 1.57 2004/05/14 07:56:38 chriskl Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
}
else {
$sql = "SELECT
- a.attname, t.typname as type, a.attlen, a.atttypmod, a.attnotnull,
+ a.attname, t.typname as type, t.typname as base_type
+ a.attlen, a.atttypmod, a.attnotnull,
a.atthasdef, adef.adsrc, -1 AS attstattarget, a.attstorage, t.typstorage,
(SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
FROM
* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres72.php,v 1.63 2004/05/09 09:10:04 chriskl Exp $
+ * $Id: Postgres72.php,v 1.64 2004/05/14 07:56:38 chriskl Exp $
*/
$sql = "
SELECT
a.attname,
- format_type(a.atttypid, a.atttypmod) as type, a.atttypmod,
+ format_type(a.atttypid, a.atttypmod) as type,
+ format_type(a.atttypid, NULL) as base_type,
+ a.atttypmod,
a.attnotnull, a.atthasdef, adef.adsrc,
-1 AS attstattarget, a.attstorage, t.typstorage,
description as comment
* A class that implements the DB interface for Postgres
* Note: This class uses ADODB and returns RecordSets.
*
- * $Id: Postgres73.php,v 1.103 2004/05/14 01:16:14 soranzo Exp $
+ * $Id: Postgres73.php,v 1.104 2004/05/14 07:56:38 chriskl Exp $
*/
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
$sql = "
SELECT
a.attname,
- pg_catalog.format_type(a.atttypid, a.atttypmod) as type, a.atttypmod,
+ pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
+ a.atttypmod,
a.attnotnull, a.atthasdef, adef.adsrc,
a.attstattarget, a.attstorage, t.typstorage,
(
$sql = "
SELECT
a.attname,
- pg_catalog.format_type(a.atttypid, a.atttypmod) as type, a.atttypmod,
+ pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
+ pg_catalog.format_type(a.atttypid, NULL) as base_type,
+ a.atttypmod,
a.attnotnull, a.atthasdef, adef.adsrc,
a.attstattarget, a.attstorage, t.typstorage,
pg_catalog.col_description(a.attrelid, a.attnum) AS comment
/**
* PostgreSQL 7.5 support
*
- * $Id: Postgres75.php,v 1.3 2003/12/17 09:11:32 chriskl Exp $
+ * $Id: Postgres75.php,v 1.4 2004/05/14 07:56:38 chriskl Exp $
*/
include_once('./classes/database/Postgres74.php');
function Postgres75($conn) {
$this->Postgres74($conn);
}
+
+ /**
+ * Alters a column in a table
+ * @param $table The table in which the column resides
+ * @param $column The column to alter
+ * @param $name The new name for the column
+ * @param $notnull (boolean) True if not null, false otherwise
+ * @param $oldnotnull (boolean) True if column is already not null, false otherwise
+ * @param $default The new default for the column
+ * @param $olddefault The old default for the column
+ * @param $type The new type for the column
+ * @param $array True if array type, false otherwise
+ * @param $length The optional size of the column (ie. 30 for varchar(30))
+ * @param $oldtype The old type for the column
+ * @param $comment Comment for the column
+ * @return 0 success
+ * @return -1 batch alteration failed
+ * @return -3 rename column error
+ * @return -4 comment error
+ * @return -6 transaction error
+ */
+ function alterColumn($table, $column, $name, $notnull, $oldnotnull, $default, $olddefault,
+ $type, $length, $array, $oldtype, $comment) {
+ $this->fieldClean($table);
+ $this->fieldClean($column);
+
+ // Initialise an empty SQL string
+ $sql = '';
+
+ // Create the command for changing nullability
+ if ($notnull != $oldnotnull) {
+ $sql .= "ALTER TABLE \"{$table}\" ALTER COLUMN \"{$column}\" " . (($notnull) ? 'SET' : 'DROP') . " NOT NULL";
+ }
+
+ // Add default, if it has changed
+ if ($default != $olddefault) {
+ if ($default == '') {
+ if ($sql == '') $sql = "ALTER TABLE \"{$table}\" ";
+ else $sql .= ", ";
+ $sql .= "ALTER COLUMN \"{$column}\" DROP DEFAULT";
+ }
+ else {
+ if ($sql == '') $sql = "ALTER TABLE \"{$table}\" ";
+ else $sql .= ", ";
+ $sql .= "ALTER COLUMN \"{$column}\" SET DEFAULT {$default}";
+ }
+ }
+
+ // Add type, if it has changed
+ if ($length == '')
+ $ftype = $type;
+ else {
+ switch ($type) {
+ // Have to account for weird placing of length for with/without
+ // time zone types
+ case 'timestamp with time zone':
+ case 'timestamp without time zone':
+ $qual = substr($type, 9);
+ $ftype = "timestamp({$length}){$qual}";
+ break;
+ case 'time with time zone':
+ case 'time without time zone':
+ $qual = substr($type, 4);
+ $ftype = "time({$length}){$qual}";
+ break;
+ default:
+ $ftype = "{$type}({$length})";
+ }
+ }
+
+ // Add array qualifier, if requested
+ if ($array) $ftype .= '[]';
+
+ if ($ftype != $oldtype) {
+ if ($sql == '') $sql = "ALTER TABLE \"{$table}\" ";
+ else $sql .= ", ";
+ $sql .= "ALTER COLUMN \"{$column}\" TYPE {$ftype}";
+ }
+
+ // Begin transaction
+ $status = $this->beginTransaction();
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return -6;
+ }
+
+ // Attempt to process the batch alteration, if anything has been changed
+ if ($sql != '') {
+ $status = $this->execute($sql);
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return -1;
+ }
+ }
+
+ // Update the comment on the column
+ $status = $this->setComment('COLUMN', $column, $table, $comment);
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return -4;
+ }
+
+ // Rename the column, if it has been changed
+ if ($column != $name) {
+ $status = $this->renameColumn($table, $column, $name);
+ if ($status != 0) {
+ $this->rollbackTransaction();
+ return -3;
+ }
+ }
+
+ return $this->endTransaction();
+ }
+ function hasAlterColumnType() { return true; }
+
}
/**
* List tables in a database
*
- * $Id: tables.php,v 1.50 2004/05/08 14:45:10 chriskl Exp $
+ * $Id: tables.php,v 1.51 2004/05/14 07:56:30 chriskl Exp $
*/
// Include application functions
// Output table header
echo "<table>\n";
- echo "\t<tr><th colspan=\"2\" class=\"data\">{$lang['strfield']}</th><th colspan=\"2\" class=\"data\">{$lang['strtype']}</th><th class=\"data\">{$lang['strlength']}</th><th class=\"data\">{$lang['strnotnull']}</th><th class=\"data\">{$lang['strdefault']}</th><th class=\"data\">{$lang['strcomment']}</th></tr>\n";
+ echo "\t<tr><th colspan=\"2\" class=\"data required\">{$lang['strfield']}</th><th colspan=\"2\" class=\"data required\">{$lang['strtype']}</th>";
+ echo"<th class=\"data\">{$lang['strlength']}</th><th class=\"data\">{$lang['strnotnull']}</th><th class=\"data\">{$lang['strdefault']}</th><th class=\"data\">{$lang['strcomment']}</th></tr>\n";
for ($i = 0; $i < $_REQUEST['fields']; $i++) {
if (!isset($_REQUEST['field'][$i])) $_REQUEST['field'][$i] = '';
/**
* List tables in a database
*
- * $Id: tblproperties.php,v 1.44 2004/05/12 15:30:00 chriskl Exp $
+ * $Id: tblproperties.php,v 1.45 2004/05/14 07:56:37 chriskl Exp $
*/
// Include application functions
if (!isset($_POST['type'])) $_POST['type'] = '';
if (!isset($_POST['array'])) $_POST['array'] = '';
if (!isset($_POST['length'])) $_POST['length'] = '';
+ if (!isset($_POST['default'])) $_POST['default'] = '';
if (!isset($_POST['comment'])) $_POST['comment'] = '';
// Fetch all available types
// Output table header
echo "<table>\n<tr>";
- echo "<tr><th class=\"data required\">{$lang['strfield']}</th><th colspan=\"2\" class=\"data required\">{$lang['strtype']}</th><th class=\"data\">{$lang['strlength']}</th><th class=\"data\">{$lang['strcomment']}</th></tr>";
+ echo "<tr><th class=\"data required\">{$lang['strfield']}</th><th colspan=\"2\" class=\"data required\">{$lang['strtype']}</th>";
+ echo "<th class=\"data\">{$lang['strlength']}</th>";
+ if ($data->hasAlterColumnType()) echo "<th class=\"data\">{$lang['strnotnull']}</th><th class=\"data\">{$lang['strdefault']}</th>";
+ echo "<th class=\"data\">{$lang['strcomment']}</th></tr>";
- echo "<tr><td><input name=\"field\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
+ echo "<tr><td><input name=\"field\" size=\"16\" maxlength=\"{$data->_maxNameLen}\" value=\"",
htmlspecialchars($_POST['field']), "\" /></td>";
- echo "<td><select name=\"type\">\n";
+ echo "<td><select name=\"type\">\n";
+ // Output any "magic" types. This came in with the alter column type so we'll check that
+ if ($data->hasAlterColumnType()) {
+ foreach ($data->extraTypes as $v) {
+ echo "<option value=\"", htmlspecialchars($v), "\"",
+ ($v == $_POST['type']) ? ' selected="selected"' : '', ">",
+ $misc->printVal($v), "</option>\n";
+ }
+ }
while (!$types->EOF) {
$typname = $types->f[$data->typFields['typname']];
echo "<option value=\"", htmlspecialchars($typname), "\"", ($typname == $_POST['type']) ? ' selected="selected"' : '', ">",
echo "<td><input name=\"length\" size=\"8\" value=\"",
htmlspecialchars($_POST['length']), "\" /></td>";
- echo "<td><input name=\"comment\" size=\"60\" value=\"",
+ // Support for adding column with not null and default (7.5+ only)
+ if ($data->hasAlterColumnType()) {
+ echo "<td><input type=\"checkbox\" name=\"notnull\"",
+ (isset($_REQUEST['notnull'])) ? ' checked="checked"' : '', " /></td>\n";
+ echo "<td><input name=\"default\" size=\"20\" value=\"",
+ htmlspecialchars($_POST['default']), "\" /></td>";
+ }
+ echo "<td><input name=\"comment\" size=\"40\" value=\"",
htmlspecialchars($_POST['comment']), "\" /></td></tr>";
echo "</table>\n";
echo "<input type=\"hidden\" name=\"action\" value=\"add_column\" />\n";
// Output table header
echo "<table>\n<tr>";
- echo "<tr><th class=\"data required\">{$lang['strname']}</th><th class=\"data required\">{$lang['strtype']}</th>";
+ echo "<tr><th class=\"data required\">{$lang['strname']}</th>";
+ if ($data->hasAlterColumnType()) {
+ echo "<th class=\"data required\" colspan=\"2\">{$lang['strtype']}</th>";
+ echo "<th class=\"data\">{$lang['strlength']}</th>";
+ }
+ else {
+ echo "<th class=\"data required\">{$lang['strtype']}</th>";
+ }
echo "<th class=\"data\">{$lang['strnotnull']}</th><th class=\"data\">{$lang['strdefault']}</th><th class=\"data\">{$lang['strcomment']}</th></tr>";
$column = &$data->getTableAttributes($_REQUEST['table'], $_REQUEST['column']);
$column->f['attnotnull'] = $data->phpBool($column->f['attnotnull']);
+ // Upon first drawing the screen, load the existing column information
+ // from the database.
if (!isset($_REQUEST['default'])) {
$_REQUEST['field'] = $column->f['attname'];
+ $_REQUEST['type'] = $column->f['base_type'];
+ // Check to see if its' an array type...
+ // XXX: HACKY
+ if (substr($column->f['base_type'], strlen($column->f['base_type']) - 2) == '[]') {
+ $_REQUEST['type'] = substr($column->f['base_type'], 0, strlen($column->f['base_type']) - 2);
+ $_REQUEST['array'] = '[]';
+ }
+ else {
+ $_REQUEST['type'] = $column->f['base_type'];
+ $_REQUEST['array'] = '';
+ }
+ // To figure out the length, look in the brackets :(
+ // XXX: HACKY
+ if ($column->f['type'] != $column->f['base_type'] && ereg('\\(([0-9, ]*)\\)', $column->f['type'], $bits)) {
+ $_REQUEST['length'] = $bits[1];
+ }
+ else
+ $_REQUEST['length'] = '';
$_REQUEST['default'] = $_REQUEST['olddefault'] = $column->f['adsrc'];
if ($column->f['attnotnull']) $_REQUEST['notnull'] = 'YES';
$_REQUEST['comment'] = $column->f['comment'];
}
+ // Column name
echo "<tr><td><input name=\"field\" size=\"32\" value=\"",
htmlspecialchars($_REQUEST['field']), "\" /></td>";
- echo "<td>", $misc->printVal($data->formatType($column->f['type'], $column->f['atttypmod'])), "</td>";
+
+ // Column type. On 7.5+ this can be altered
+ if ($data->hasAlterColumnType()) {
+ // Fetch all available types
+ $types = &$data->getTypes(true);
+
+ echo "<td><select name=\"type\">\n";
+ // Output any "magic" types. This came in with the alter column type so we'll check that
+ if ($data->hasAlterColumnType()) {
+ foreach ($data->extraTypes as $v) {
+ echo "<option value=\"", htmlspecialchars($v), "\"",
+ ($v == $_REQUEST['type']) ? ' selected="selected"' : '', ">",
+ $misc->printVal($v), "</option>\n";
+ }
+ }
+ while (!$types->EOF) {
+ $typname = $types->f[$data->typFields['typname']];
+ echo "<option value=\"", htmlspecialchars($typname), "\"", ($typname == $_REQUEST['type']) ? ' selected="selected"' : '', ">",
+ $misc->printVal($typname), "</option>\n";
+ $types->moveNext();
+ }
+ echo "</select></td>";
+
+ // Output array type selector
+ echo "<td><select name=\"array\">\n";
+ echo "<option value=\"\"", ($_REQUEST['array'] == '') ? ' selected="selected"' : '', "></option>\n";
+ echo "<option value=\"[]\"", ($_REQUEST['array'] == '[]') ? ' selected="selected"' : '', ">[ ]</option>\n";
+ echo "</select></td>\n";
+
+ echo "<td><input name=\"length\" size=\"8\" value=\"",
+ htmlspecialchars($_REQUEST['length']), "\" /></td>";
+ } else {
+ // Otherwise draw the read-only type name
+ echo "<td>", $misc->printVal($data->formatType($column->f['type'], $column->f['atttypmod'])), "</td>";
+ }
+
echo "<td><input type=\"checkbox\" name=\"notnull\"", (isset($_REQUEST['notnull'])) ? ' checked="checked"' : '', " /></td>\n";
echo "<td><input name=\"default\" size=\"20\" value=\"",
htmlspecialchars($_REQUEST['default']), "\" /></td>";
- echo "<td><input name=\"comment\" size=\"60\" value=\"",
+ echo "<td><input name=\"comment\" size=\"20\" value=\"",
htmlspecialchars($_REQUEST['comment']), "\" /></td>";
echo "</table>\n";
echo "<input type=\"hidden\" name=\"column\" value=\"", htmlspecialchars($_REQUEST['column']), "\" />\n";
echo "<input type=\"hidden\" name=\"olddefault\" value=\"", htmlspecialchars($_REQUEST['olddefault']), "\" />\n";
if ($column->f['attnotnull']) echo "<input type=\"hidden\" name=\"oldnotnull\" value=\"on\" />\n";
+ echo "<input type=\"hidden\" name=\"oldtype\" value=\"", htmlspecialchars($data->formatType($column->f['type'], $column->f['atttypmod'])), "\" />\n";
+ // Add hidden variables to suppress error notices if we don't support altering column type
+ if (!$data->hasAlterColumnType()) {
+ echo "<input type=\"hidden\" name=\"type\" value=\"", htmlspecialchars($_REQUEST['type']), "\" />\n";
+ echo "<input type=\"hidden\" name=\"length\" value=\"", htmlspecialchars($_REQUEST['length']), "\" />\n";
+ echo "<input type=\"hidden\" name=\"array\" value=\"", htmlspecialchars($_REQUEST['array']), "\" />\n";
+ }
echo "<input type=\"submit\" value=\"{$lang['stralter']}\" />\n";
echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
echo "</form>\n";
doProperties($lang['strfieldneedsname']);
return;
}
-
+
$status = $data->alterColumn($_REQUEST['table'], $_REQUEST['column'], $_REQUEST['field'],
- isset($_REQUEST['notnull']), isset($_REQUEST['oldnotnull']), $_REQUEST['default'],
- $_REQUEST['olddefault'],$_REQUEST['comment']);
+ isset($_REQUEST['notnull']), isset($_REQUEST['oldnotnull']),
+ $_REQUEST['default'], $_REQUEST['olddefault'],
+ $_REQUEST['type'], $_REQUEST['length'], $_REQUEST['array'], $_REQUEST['oldtype'],
+ $_REQUEST['comment']);
if ($status == 0)
doDefault($lang['strcolumnaltered']);
else {
/**
* List views in a database
*
- * $Id: viewproperties.php,v 1.2 2004/05/12 15:30:00 chriskl Exp $
+ * $Id: viewproperties.php,v 1.3 2004/05/14 07:56:37 chriskl Exp $
*/
// Include application functions
echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strdefinition']}</th>\n";
echo "\t\t<td class=\"data1\"><textarea style=\"width: 100%;\" rows=\"20\" cols=\"50\" name=\"formDefinition\" wrap=\"virtual\">",
htmlspecialchars($_POST['formDefinition']), "</textarea></td>\n\t</tr>\n";
- echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strcomment']}</th>\n";
+ echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n";
echo "\t\t<td class=\"data1\"><input style=\"width: 100%;\" name=\"formComment\" value='",
htmlspecialchars($_POST['formComment']), "' /></td>\n\t</tr>\n";
echo "</table>\n";
global $data, $misc;
global $PHP_SELF, $lang;
+ // Get view
+ $vdata = &$data->getView($_REQUEST['view']);
+
$misc->printViewNav();
echo "<h2>", $misc->printVal($_REQUEST['database']), ": {$lang['strviews']}: ", $misc->printVal($_REQUEST['view']), ": {$lang['strdefinition']}</h2>\n";
- $misc->printMsg($msg);
-
- $viewdata = &$data->getView($_REQUEST['view']);
+ $misc->printMsg($msg);
- if ($viewdata->recordCount() > 0) {
+ if ($vdata->recordCount() > 0) {
+ // Show comment if any
+ if ($vdata->f[$data->vwFields['vwcomment']] != null)
+ echo "<p class=\"comment\">", htmlspecialchars($vdata->f[$data->vwFields['vwcomment']]), "</p>\n";
+
echo "<table width=\"100%\">\n";
echo "<tr><th class=\"data\">{$lang['strdefinition']}</th></tr>\n";
- echo "<tr><td class=\"data1\">", $misc->printVal($viewdata->f[$data->vwFields['vwdef']]), "</td></tr>\n";
+ echo "<tr><td class=\"data1\">", $misc->printVal($vdata->f[$data->vwFields['vwdef']]), "</td></tr>\n";
echo "</table>\n";
}
else echo "<p>{$lang['strnodata']}</p>\n";
$misc->printViewNav();
echo "<h2>", $misc->printVal($_REQUEST['database']), ": {$lang['strviews']}: ", $misc->printVal($_REQUEST['view']), "</h2>\n";
- // Get view (using same method for getting a table)
- $vdata = &$data->getTable($_REQUEST['view']);
+ // Get view
+ $vdata = &$data->getView($_REQUEST['view']);
// Get columns (using same method for getting a view)
$attrs = &$data->getTableAttributes($_REQUEST['view']);
$misc->printMsg($msg);