fix getConstraints method for pg 7.3
authorioguix <ioguix>
Fri, 28 Dec 2007 15:28:57 +0000 (15:28 +0000)
committerioguix <ioguix>
Fri, 28 Dec 2007 15:28:57 +0000 (15:28 +0000)
classes/database/Postgres73.php
constraints.php
tblproperties.php

index 21d14ad97fb45d3bfe30f16696cb3052259e98a4..b777f5d1240197766596117a814b3210b2194a31 100644 (file)
@@ -4,7 +4,7 @@
  * A class that implements the DB interface for Postgres
  * Note: This class uses ADODB and returns RecordSets.
  *
- * $Id: Postgres73.php,v 1.182 2007/12/12 10:45:35 ioguix Exp $
+ * $Id: Postgres73.php,v 1.183 2007/12/28 15:28:57 ioguix Exp $
  */
 
 // @@@ THOUGHT: What about inherits? ie. use of ONLY???
@@ -63,7 +63,7 @@ class Postgres73 extends Postgres72 {
        }
 
        /**
-        * Returns the current schema to prepend on object names 
+        * Returns the current schema to prepend on object names
         */
        function schema() {
                return "\"{$this->_schema}\".";
@@ -356,9 +356,9 @@ class Postgres73 extends Postgres72 {
                $this->fieldClean($owner);
                $this->clean($comment);
                /* $schema, $owner, $tablespace not supported in pg70 */
-               
+
                $table = $tblrs->fields['relname'];
-               
+
                // Comment
                $status = $this->setComment('TABLE', '', $table, $comment);
                if ($status != 0) return -4;
@@ -371,7 +371,7 @@ class Postgres73 extends Postgres72 {
                                return -3;
                        $table = $name;
                }
-                               
+
                // Owner
                if (!empty($owner) && ($tblrs->fields['relowner'] != $owner)) {
                        // If owner has been changed, then do the alteration.  We are
@@ -385,7 +385,7 @@ class Postgres73 extends Postgres72 {
 
                return 0;
        }
-       
+
        /**
         * Removes a table from the database
         * @param $table The table to drop
@@ -642,7 +642,7 @@ class Postgres73 extends Postgres72 {
        function dropColumn($table, $column, $cascade) {
                $this->fieldClean($table);
                $this->fieldClean($column);
-               
+
                $sql = "ALTER TABLE \"{$this->_schema}\".\"{$table}\" DROP COLUMN \"{$column}\"";
                if ($cascade) $sql .= " CASCADE";
 
@@ -691,12 +691,12 @@ class Postgres73 extends Postgres72 {
         */
        function emptyTable($table) {
                $this->fieldClean($table);
-               
+
                $sql = "DELETE FROM \"{$this->_schema}\".\"{$table}\"";
 
                return $this->execute($sql);
        }
-       
+
        /**
         * Adds a check constraint to a table
         * @param $table The table to which to add the check
@@ -891,7 +891,7 @@ class Postgres73 extends Postgres72 {
                        $status = $this->execute($sql);
                        if ($status != 0) return -5;
                }
-               
+
                // Rename (only if name has changed)
                $this->fieldClean($name);
                if ($name != $view) {
@@ -944,7 +944,7 @@ class Postgres73 extends Postgres72 {
        function setView($viewname, $definition,$comment) {
                return $this->createView($viewname, $definition, true, $comment);
        }
-       
+
        /**
         * Rename a view
         * @param $view The current view's name
@@ -1763,36 +1763,92 @@ class Postgres73 extends Postgres72 {
 
                $rs = $this->selectSet($sql);
 
-           if ($rs->EOF) $max_col = 0;
-               else $max_col = $rs->fields['nb'];
+           if ($rs->EOF) $max_col_cstr = 0;
+               else $max_col_cstr = $rs->fields['nb'];
 
-       $sql = '
-                       SELECT
-                               c.contype, c.conname, pg_catalog.pg_get_constraintdef(c.oid) AS consrc,
-                               ns1.nspname as p_schema, r1.relname as p_table, ns2.nspname as f_schema,
-                               r2.relname as f_table, f1.attname as p_field, f2.attname as f_field,
-                               pg_catalog.obj_description(c.oid, \'pg_constraint\') AS constcomment
-                       FROM
-                               pg_catalog.pg_constraint AS c
-                               JOIN pg_catalog.pg_class AS r1 ON (c.conrelid=r1.oid)
-                               JOIN pg_catalog.pg_attribute AS f1 ON (f1.attrelid=r1.oid AND (f1.attnum=c.conkey[1]';
-               for ($i = 2; $i <= $rs->fields['nb']; $i++) {
+               // get the max number of col used in a constraint for the table
+       $sql = "SELECT i.indkey
+               FROM
+                 pg_catalog.pg_index AS i
+                 JOIN pg_catalog.pg_class AS r ON (i.indrelid = r.oid)
+                 JOIN pg_catalog.pg_namespace AS ns ON r.relnamespace=ns.oid
+       WHERE
+               r.relname = '$table' AND ns.nspname='". $this->_schema ."'";
+
+               /* parse our output to find the highest dimension of index keys since
+                * i.indkey is stored in an int2vector */
+               $max_col_ind = 0;
+               $rs = $this->selectSet($sql);
+               while (!$rs->EOF) {
+                       $tmp = count(explode(' ', $rs->fields['indkey']));
+                       $max_col_ind = $tmp > $max_col_ind ? $tmp : $max_col_ind;
+                       $rs->MoveNext();
+               }
+
+               $sql = "
+               SELECT contype, conname, consrc, ns1.nspname as p_schema, sub.relname as p_table,
+               f_schema, f_table, p_field, f_field, indkey
+               FROM (
+                 SELECT
+                       contype, conname,
+                       CASE WHEN contype='f' THEN
+                         pg_catalog.pg_get_constraintdef(c.oid)
+                       ELSE
+                         'CHECK (' || consrc || ')'
+                       END AS consrc, r1.relname,
+                       f1.attname as p_field, ns2.nspname as f_schema, r2.relname as f_table,
+                       conrelid, r1.relnamespace, f2.attname as f_field, NULL AS indkey
+                 FROM
+                       pg_catalog.pg_constraint AS c
+                       JOIN pg_catalog.pg_class AS r1 ON (c.conrelid=r1.oid)
+                       JOIN pg_catalog.pg_attribute AS f1 ON ((f1.attrelid=c.conrelid) AND (f1.attnum=c.conkey[1]";
+               for ($i = 2; $i <= $max_col_cstr; $i++) {
                        $sql.= " OR f1.attnum=c.conkey[$i]";
                }
-               $sql.= '))
-                               JOIN pg_catalog.pg_namespace AS ns1 ON r1.relnamespace=ns1.oid
-                               LEFT JOIN (
-                                       pg_catalog.pg_class AS r2 JOIN pg_catalog.pg_namespace AS ns2 ON (r2.relnamespace=ns2.oid)
-                               ) ON (c.confrelid=r2.oid)
-                               LEFT JOIN pg_catalog.pg_attribute AS f2 ON
-                                       (f2.attrelid=r2.oid AND ((c.confkey[1]=f2.attnum AND c.conkey[1]=f1.attnum)';
-               for ($i = 2; $i <= $rs->fields['nb']; $i++)
+               $sql .= "))
+                       LEFT JOIN (
+                         pg_catalog.pg_class AS r2 JOIN pg_catalog.pg_namespace AS ns2 ON (r2.relnamespace=ns2.oid)
+                       ) ON (c.confrelid=r2.oid)
+                       LEFT JOIN pg_catalog.pg_attribute AS f2 ON
+                         ((f2.attrelid=r2.oid) AND ((c.confkey[1]=f2.attnum AND c.conkey[1]=f1.attnum)";
+               for ($i = 2; $i <= $max_col_cstr; $i++)
                        $sql.= "OR (c.confkey[$i]=f2.attnum AND c.conkey[$i]=f1.attnum)";
-
-               $sql .= sprintf("))
-                       WHERE
-                               r1.relname = '%s' AND ns1.nspname='%s'
-                       ORDER BY 1", $table, $this->_schema);
+               $sql .= "))
+                 WHERE
+                       contype IN ('f', 'c')
+                 UNION ALL
+                 SELECT
+                       CASE WHEN indisprimary THEN
+                         'p'
+                       ELSE
+                         'u'
+                       END as contype,
+                       pc.relname as conname, NULL as consrc, r2.relname, f1.attname as p_field,
+                       NULL as f_schema, NULL as f_table, indrelid as conrelid, pc.relnamespace,
+                       NULL as f_field, indkey
+                 FROM
+                       pg_catalog.pg_class pc, pg_catalog.pg_index pi
+                       -- JOIN pg_catalog.pg_attribute AS f1 ON ((f1.attrelid=pi.indrelid) AND (f1.attnum=pi.indkey[0]))
+                       JOIN pg_catalog.pg_attribute AS f1 ON ((f1.attrelid=pi.indrelid) AND (f1.attnum=pi.indkey[0]";
+                       for ($i = 1; $i <= $max_col_ind; $i++) {
+                               $sql.= " OR f1.attnum=pi.indkey[$i]";
+                       }
+                       $sql .= "))
+                       JOIN pg_catalog.pg_class r2 ON (pi.indrelid=r2.oid)
+                 WHERE
+                       pc.oid=pi.indexrelid
+                       AND EXISTS (
+                         SELECT 1 FROM pg_catalog.pg_depend AS d JOIN pg_catalog.pg_constraint AS c
+                               ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
+                         WHERE d.classid = pc.tableoid AND d.objid = pc.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
+                       )
+               ) AS sub
+                 JOIN pg_catalog.pg_namespace AS ns1 ON sub.relnamespace=ns1.oid
+               WHERE conrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
+                 AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace
+                       WHERE nspname='{$this->_schema}'))
+               ORDER BY 1
+               ";
 
                return $this->selectSet($sql);
        }
@@ -2476,7 +2532,7 @@ class Postgres73 extends Postgres72 {
 
                return $this->execute($sql);
        }
-       
+
        // Query functions
 
        /**
index d70e62ee83cf21450e97f1901a5eeba9c560abc2..137f8a6b5ea86a121bb6b16e2fb24b493e22084f 100644 (file)
@@ -3,7 +3,7 @@
        /**
         * List constraints on a table
         *
-        * $Id: constraints.php,v 1.54 2007/09/29 09:09:45 ioguix Exp $
+        * $Id: constraints.php,v 1.55 2007/12/28 15:28:57 ioguix Exp $
         */
 
        // Include application functions
@@ -31,7 +31,7 @@
                                        // Copy the IndexColumnList variable from stage 1
                                        if (isset($_REQUEST['IndexColumnList']) && !isset($_REQUEST['SourceColumnList']))
                                                $_REQUEST['SourceColumnList'] = serialize($_REQUEST['IndexColumnList']);
-                                       
+
                                        // Initialise variables
                                        if (!isset($_POST['upd_action'])) $_POST['upd_action'] = null;
                                        if (!isset($_POST['del_action'])) $_POST['del_action'] = null;
@@ -39,7 +39,7 @@
                                        if (!isset($_POST['deferrable'])) $_POST['deferrable'] = null;
                                        if (!isset($_POST['initially'])) $_POST['initially'] = null;
                                        $_REQUEST['target'] = unserialize($_REQUEST['target']);
-                                       
+
                                        $misc->printTrail('table');
                                        $misc->printTitle($lang['straddfk'],'pg.constraint.foreign_key');
                                        $misc->printMsg($msg);
@@ -73,7 +73,7 @@
                                        $buttonRemove->set_attribute('onclick', 'buttonPressed(this);');
                                        $buttonRemove->set_attribute('type', 'button');
 
-                                       echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";      
+                                       echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";
 
                                        echo "<table>\n";
                                        echo "<tr><th class=\"data\" colspan=\"3\">{$lang['strfktarget']}</th></tr>";
@@ -83,7 +83,7 @@
                                        echo "<td class=\"data1\">" . $selIndex->fetch() . "</td></tr>\n";
                                        echo "<tr><th class=\"data\" colspan=\"3\">{$lang['stractions']}</th></tr>";
                                        echo "<tr>";
-                                       echo "<td class=\"data1\" colspan=\"3\">\n";                            
+                                       echo "<td class=\"data1\" colspan=\"3\">\n";
                                        // ON SELECT actions
                                        echo "{$lang['stronupdate']} <select name=\"upd_action\">";
                                        foreach ($data->fkactions as $v)
                                // Check that they've given at least one column
                                if (isset($_POST['SourceColumnList'])) $temp = unserialize($_POST['SourceColumnList']);
                                if (!isset($_POST['IndexColumnList']) || !is_array($_POST['IndexColumnList'])
-                                               || sizeof($_POST['IndexColumnList']) == 0 || !isset($temp) 
+                                               || sizeof($_POST['IndexColumnList']) == 0 || !isset($temp)
                                                || !is_array($temp) || sizeof($temp) == 0) addForeignKey(2, $lang['strfkneedscols']);
                                else {
-                                       $status = $data->addForeignKey($_POST['table'], $_POST['target']['schemaname'], $_POST['target']['tablename'], 
-                                               unserialize($_POST['SourceColumnList']), $_POST['IndexColumnList'], $_POST['upd_action'], $_POST['del_action'], 
+                                       $status = $data->addForeignKey($_POST['table'], $_POST['target']['schemaname'], $_POST['target']['tablename'],
+                                               unserialize($_POST['SourceColumnList']), $_POST['IndexColumnList'], $_POST['upd_action'], $_POST['del_action'],
                                                $_POST['match'], $_POST['deferrable'], $_POST['initially'], $_POST['name']);
                                        if ($status == 0)
                                                doDefault($lang['strfkadded']);
                                $buttonRemove->set_attribute('onclick', 'buttonPressed(this);');
                                $buttonRemove->set_attribute('type', 'button');
 
-                               echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";      
+                               echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";
 
                                echo "<table>\n";
                                echo "<tr><th class=\"data\" colspan=\"3\">{$lang['strname']}</th></tr>\n";
                                                        echo htmlspecialchars($tables->fields['nspname']), '.';
                                        }
                                        echo htmlspecialchars($tables->fields['relname']), "</option>\n";
-                                       $tables->moveNext();    
+                                       $tables->moveNext();
                                }
                                echo "</select>\n";
                                echo "</td></tr>";
                if ($confirm) {
                        if (!isset($_POST['name'])) $_POST['name'] = '';
                        if (!isset($_POST['tablespace'])) $_POST['tablespace'] = '';
-                       
+
                        $misc->printTrail('table');
-                       
+
                        switch ($type) {
                                case 'primary':
                                        $misc->printTitle($lang['straddpk'],'pg.constraint.primary_key');
                                        doDefault($lang['strinvalidparam']);
                                        return;
                        }
-                       
+
                        $misc->printMsg($msg);
-                       
+
                        $attrs = $data->getTableAttributes($_REQUEST['table']);
                        // Fetch all tablespaces from the database
                        if ($data->hasTablespaces()) $tablespaces = $data->getTablespaces();
 
-                       
+
                        $selColumns = new XHTML_select('TableColumnList', true, 10);
                        $selColumns->set_style('width: 10em;');
-       
+
                        if ($attrs->recordCount() > 0) {
                                while (!$attrs->EOF) {
                                        $selColumns->add(new XHTML_Option($attrs->fields['attname']));
                                        $attrs->moveNext();
-                               } 
+                               }
                        }
-       
+
                        $selIndex = new XHTML_select('IndexColumnList[]', true, 10);
                        $selIndex->set_style('width: 10em;');
                        $selIndex->set_attribute('id', 'IndexColumnList');
                        $buttonAdd = new XHTML_Button('add', '>>');
                        $buttonAdd->set_attribute('onclick', 'buttonPressed(this);');
                        $buttonAdd->set_attribute('type', 'button');
-       
+
                        $buttonRemove = new XHTML_Button('remove', '<<');
                        $buttonRemove->set_attribute('onclick', 'buttonPressed(this);');
                        $buttonRemove->set_attribute('type', 'button');
-       
-                       echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";      
-       
+
+                       echo "<form onsubmit=\"doSelectAll();\" name=\"formIndex\" action=\"constraints.php\" method=\"post\">\n";
+
                        echo "<table>\n";
                        echo "<tr><th class=\"data\" colspan=\"3\">{$lang['strname']}</th></tr>";
                        echo "<tr>";
-                       echo "<td class=\"data1\" colspan=\"3\"><input type=\"text\" name=\"name\" value=\"", htmlspecialchars($_POST['name']), 
+                       echo "<td class=\"data1\" colspan=\"3\"><input type=\"text\" name=\"name\" value=\"", htmlspecialchars($_POST['name']),
                                "\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" /></td></tr>";
                        echo "<tr><th class=\"data\">{$lang['strtablecolumnlist']}</th><th class=\"data\">&nbsp;</th><th class=\"data required\">{$lang['strindexcolumnlist']}</th></tr>\n";
                        echo "<tr><td class=\"data1\">" . $selColumns->fetch() . "</td>\n";
                        }
 
                        echo "</table>\n";
-       
+
                        echo "<p><input type=\"hidden\" name=\"action\" value=\"save_add_primary_key\" />\n";
                        echo $misc->form;
                        echo "<input type=\"hidden\" name=\"table\" value=\"", htmlspecialchars($_REQUEST['table']), "\" />\n";
                else {
                        // Default tablespace to empty if it isn't set
                        if (!isset($_POST['tablespace'])) $_POST['tablespace'] = '';
-               
+
                        if ($_POST['type'] == 'primary') {
                                // Check that they've given at least one column
                                if (!isset($_POST['IndexColumnList']) || !is_array($_POST['IndexColumnList'])
         * List all the constraints on the table
         */
        function doDefault($msg = '') {
-               global $data, $misc;
-               global $lang;
+               global $data, $misc, $lang;
 
                function cnPre(&$rowdata) {
-                       global $data, $lang;
+                       global $data;
                        if (is_null($rowdata->fields['consrc'])) {
                                $atts = $data->getAttributeNames($_REQUEST['table'], explode(' ', $rowdata->fields['indkey']));
                                $rowdata->fields['+definition'] = ($rowdata->fields['contype'] == 'u' ? "UNIQUE (" : "PRIMARY KEY (") . join(',', $atts) . ')';
                                $rowdata->fields['+definition'] = $rowdata->fields['consrc'];
                        }
                }
-               
+
                $misc->printTrail('table');
                $misc->printTabs('table','constraints');
                $misc->printMsg($msg);
                );
 
                if (!$data->hasConstraintsInfo()) unset($columns['comment']);
-               
+
                $actions = array(
                        'drop' => array(
                                'title' => $lang['strdrop'],
                                'vars'  => array('constraint' => 'conname', 'type' => 'contype'),
                        ),
                );
-               
+
                if (!$data->hasIsClustered()) unset($columns['clustered']);
-               
+
                $misc->printTable($constraints, $columns, $actions, $lang['strnoconstraints'], 'cnPre');
-               
+
                echo "<ul class=\"navlink\">\n\t<li><a href=\"constraints.php?action=add_check&amp;{$misc->href}&amp;table=", urlencode($_REQUEST['table']),
                        "\">{$lang['straddcheck']}</a></li>\n";
                echo "\t<li><a href=\"constraints.php?action=add_unique_key&amp;{$misc->href}&amp;table=", urlencode($_REQUEST['table']),
                global $misc, $data;
 
                $constraints = $data->getConstraints($_REQUEST['table']);
-               
+
                $reqvars = $misc->getRequestVars('schema');
 
                function getIcon($f) {
                                        return 'ForeignKey';
                                case 'p':
                                        return 'PrimaryKey';
-                               
+
                        }
                }
-       
+
                $attrs = array(
                        'text'   => field('conname'),
                        'icon'   => callback('getIcon'),
                        doDefault();
                        break;
        }
-       
+
        $misc->printFooter();
 
 ?>
index 850c46e9378659ee5636783039a9b126a54c7828..20ecc813adfcf35f6f51bd4c5a876bcad61c9723 100644 (file)
@@ -3,7 +3,7 @@
        /**
         * List tables in a database
         *
-        * $Id: tblproperties.php,v 1.89 2007/11/21 15:45:31 ioguix Exp $
+        * $Id: tblproperties.php,v 1.90 2007/12/28 15:28:57 ioguix Exp $
         */
 
        // Include application functions
@@ -11,7 +11,7 @@
 
        $action = (isset($_REQUEST['action'])) ? $_REQUEST['action'] : '';
 
-       /** 
+       /**
         * Function to save after altering a table
         */
        function doSaveAlter() {
@@ -22,7 +22,7 @@
                // Default tablespace to null if it isn't set
                if (!isset($_POST['tablespace'])) $_POST['tablespace'] = null;
                if (!isset($_POST['newschema'])) $_POST['newschema'] = null;
-               
+
                $status = $data->alterTable($_POST['table'], $_POST['name'], $_POST['owner'], $_POST['newschema'], $_POST['comment'], $_POST['tablespace']);
                if ($status == 0) {
                        // If table has been renamed, need to change to the new name and
        function doAlter($msg = '') {
                global $data, $misc;
                global $lang;
-               
+
                $misc->printTrail('table');
                $misc->printTitle($lang['stralter'], 'pg.table.alter');
                $misc->printMsg($msg);
 
-               // Fetch table info             
+               // Fetch table info
                $table = $data->getTable($_REQUEST['table']);
                // Fetch all users
                $users = $data->getUsers();
                // Fetch all tablespaces from the database
                if ($data->hasTablespaces()) $tablespaces = $data->getTablespaces(true);
-               
+
                if ($table->recordCount() > 0) {
-                       
+
                        if (!isset($_POST['name'])) $_POST['name'] = $table->fields['relname'];
                        if (!isset($_POST['owner'])) $_POST['owner'] = $table->fields['relowner'];
                        if (!isset($_POST['newschema'])) $_POST['newschema'] = $table->fields['nspname'];
                        if (!isset($_POST['comment'])) $_POST['comment'] = $table->fields['relcomment'];
                        if ($data->hasTablespaces() && !isset($_POST['tablespace'])) $_POST['tablespace'] = $table->fields['tablespace'];
-                       
+
                        echo "<form action=\"tblproperties.php\" method=\"post\">\n";
                        echo "<table>\n";
                        echo "<tr><th class=\"data left required\">{$lang['strname']}</th>\n";
                        echo "<td class=\"data1\">";
-                       echo "<input name=\"name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", 
+                       echo "<input name=\"name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
                                htmlspecialchars($_POST['name']), "\" /></td></tr>\n";
-                       
+
                        $server_info = $misc->getServerInfo();
                        if ($data->hasAlterTableOwner() && $data->isSuperUser($server_info['username'])) {
                                echo "<tr><th class=\"data left required\">{$lang['strowner']}</th>\n";
@@ -88,9 +88,9 @@
                                                ($uname == $_POST['owner']) ? ' selected="selected"' : '', ">", htmlspecialchars($uname), "</option>\n";
                                        $users->moveNext();
                                }
-                               echo "</select></td></tr>\n";                           
+                               echo "</select></td></tr>\n";
                        }
-                       
+
                        if ($data->hasAlterTableSchema()) {
                                $schemas = $data->getSchemas();
                                echo "<tr><th class=\"data left required\">{$lang['strschema']}</th>\n";
                                }
                            echo "</select></td></tr>\n";
                        }
-                       
+
                        // Tablespace (if there are any)
                        if ($data->hasTablespaces() && $tablespaces->recordCount() > 0) {
                                echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strtablespace']}</th>\n";
                                }
                                echo "\t\t\t</select>\n\t\t</td>\n\t</tr>\n";
                        }
-                       
+
                        echo "<tr><th class=\"data left\">{$lang['strcomment']}</th>\n";
                        echo "<td class=\"data1\">";
                        echo "<textarea rows=\"3\" cols=\"32\" name=\"comment\">",
                }
                else echo "<p>{$lang['strnodata']}</p>\n";
        }
-       
+
        function doExport($msg = '') {
                global $data, $misc;
                global $lang;
 
                // Determine whether or not the table has an object ID
                $hasID = $data->hasObjectID($_REQUEST['table']);
-               
+
                $misc->printTrail('table');
                $misc->printTabs('table','export');
                $misc->printMsg($msg);
                        echo "<tr><td><label for=\"sd_oids\">{$lang['stroids']}</label></td><td><input type=\"checkbox\" id=\"sd_oids\" name=\"sd_oids\" /></td>\n</tr>\n";
                }
                echo "</table>\n";
-               
+
                echo "<h3>{$lang['stroptions']}</h3>\n";
                echo "<p><input type=\"radio\" id=\"output1\" name=\"output\" value=\"show\" checked=\"checked\" /><label for=\"output1\">{$lang['strshow']}</label>\n";
                echo "<br/><input type=\"radio\" id=\"output2\" name=\"output\" value=\"download\" /><label for=\"output2\">{$lang['strdownload']}</label></p>\n";
                echo "<input type=\"submit\" value=\"{$lang['strexport']}\" /></p>\n";
                echo "</form>\n";
        }
-       
+
        function doImport($msg = '') {
                global $data, $misc;
                global $lang;
                                echo "</form>\n";
                        }
                }
-               else echo "<p>{$lang['strnouploads']}</p>\n";           
-       }       
+               else echo "<p>{$lang['strnouploads']}</p>\n";
+       }
 
        /**
         * Displays a screen where they can add a column
 
                                echo "<tr><td><input name=\"field\" size=\"16\" maxlength=\"{$data->_maxNameLen}\" value=\"",
                                        htmlspecialchars($_POST['field']), "\" /></td>\n";
-                               echo "<td><select name=\"type\" id=\"type\" onchange=\"checkLengths(document.getElementById('type').value,'');\">\n";                           
+                               echo "<td><select name=\"type\" id=\"type\" onchange=\"checkLengths(document.getElementById('type').value,'');\">\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) {
                                        $types->moveNext();
                                }
                                echo "</select></td>\n";
-                               
+
                                // Output array type selector
                                echo "<td><select name=\"array\">\n";
                                echo "\t<option value=\"\"", ($_POST['array'] == '') ? ' selected="selected"' : '', "></option>\n";
                                echo "<td><input name=\"length\" id=\"lengths\" size=\"8\" value=\"",
                                        htmlspecialchars($_POST['length']), "\" /></td>\n";
                                // Support for adding column with not null and default
-                               if ($data->hasAlterColumnType()) {                                      
-                                       echo "<td><input type=\"checkbox\" name=\"notnull\"", 
+                               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>\n";
                                echo $misc->form;
                                echo "<input type=\"hidden\" name=\"table\" value=\"", htmlspecialchars($_REQUEST['table']), "\">\n";
                                if (!$data->hasAlterColumnType()) {
-                                       echo "<input type=\"hidden\" name=\"default\" value=\"\" />\n"; 
+                                       echo "<input type=\"hidden\" name=\"default\" value=\"\" />\n";
                                }
                                echo "<input type=\"submit\" value=\"{$lang['stradd']}\" />\n";
                                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
 
             echo "<p>", sprintf($lang['strconfdropcolumn'], $misc->printVal($_REQUEST['column']),
                     $misc->printVal($_REQUEST['table'])), "</p>\n";
-                                                               
+
 
                        echo "<form action=\"tblproperties.php\" method=\"post\">\n";
                        echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n";
                        else
                                doDefault($lang['strcolumndroppedbad']);
                }
-               
+
        }
 
        function doTree() {
                                                                        'table'         => $_REQUEST['table'],
                                                                        'column'        => field('attname'),
                                                                        'query'         => replace(
-                                                                                                               'SELECT "%column%", count(*) AS "count" FROM "%table%" GROUP BY "%column%" ORDER BY "%column%"', 
+                                                                                                               'SELECT "%column%", count(*) AS "count" FROM "%table%" GROUP BY "%column%" ORDER BY "%column%"',
                                                                                                                array (
                                                                                                                        '%column%' => field('attname'),
                                                                                                                        '%table%' => $_REQUEST['table']
                }
                else {
                        function cstrRender($s, $p) {
-                               global $misc;
+                               global $misc, $data;
 
                                $str ='';
-                               foreach ($p['keys'] as $c)
+                               foreach ($p['keys'] as $k => $c) {
+
+                                       if (is_null($p['keys'][$k]['consrc'])) {
+                                               $atts = $data->getAttributeNames($_REQUEST['table'], explode(' ', $p['keys'][$k]['indkey']));
+                                               $c['consrc'] = ($c['contype'] == 'u' ? "UNIQUE (" : "PRIMARY KEY (") . join(',', $atts) . ')';
+                                       }
+
                                        if ($c['p_field'] == $s)
                                                switch ($c['contype']) {
                                                        case 'p':
                                                                $str .= '<a href="constraints.php?'. $misc->href ."&amp;table={$c['p_table']}&amp;schema={$c['p_schema']}\"><img src=\"".
                                                                        $misc->icon('CheckConstraint') .'" alt="[check]" title="'. htmlentities($c['consrc']) .'" /></a>';
                                                }
+                               }
 
                                return $str;
                        }
                }
-               
+
                $return_url = urlencode("tblproperties.php?{$misc->href}&amp;table={$_REQUEST['table']}");
 
                $actions = array(
                                'vars'  => array('column' => 'attname'),
                        ),
                );
-               
+
                if (!$data->hasDropColumn()) unset($actions['drop']);
-               
+
                $misc->printTable($attrs, $columns, $actions, null, 'attPre');
 
                echo "<ul class=\"navlink\">\n";
                        doDefault();
                        break;
        }
-       
+
        $misc->printFooter();
 
 ?>