From 63d6e6dfc35e6d82c4a64f37c408794c163becd4 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Wed, 28 Sep 2011 15:16:41 -0400 Subject: [PATCH] Bump versions to 0.6 stable --- program/lib/MDB2/Driver/Manager/pgsql.php | 826 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 602 insertions(+), 224 deletions(-) diff --git a/program/lib/MDB2/Driver/Manager/pgsql.php b/program/lib/MDB2/Driver/Manager/pgsql.php old mode 100755 new mode 100644 index 5db3e5c..7d35627 --- a/program/lib/MDB2/Driver/Manager/pgsql.php +++ b/program/lib/MDB2/Driver/Manager/pgsql.php @@ -2,7 +2,7 @@ // +----------------------------------------------------------------------+ // | PHP versions 4 and 5 | // +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | +// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox, | // | Stig. S. Bakken, Lukas Smith | // | All rights reserved. | // +----------------------------------------------------------------------+ @@ -42,7 +42,7 @@ // | Author: Paul Cooper <pgc@ucecom.com> | // +----------------------------------------------------------------------+ // -// $Id$ +// $Id: pgsql.php 295587 2010-02-28 17:16:38Z quipo $ require_once 'MDB2/Driver/Manager/Common.php'; @@ -60,18 +60,54 @@ /** * create a new database * - * @param string $name name of the database that should be created + * @param string $name name of the database that should be created + * @param array $options array with charset info + * * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public - **/ - function createDatabase($name) + */ + function createDatabase($name, $options = array()) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - return $db->standaloneQuery("CREATE DATABASE $name"); + $name = $db->quoteIdentifier($name, true); + $query = 'CREATE DATABASE ' . $name; + if (!empty($options['charset'])) { + $query .= ' WITH ENCODING ' . $db->quote($options['charset'], 'text'); + } + return $db->standaloneQuery($query, null, true); + } + + // }}} + // {{{ alterDatabase() + + /** + * alter an existing database + * + * @param string $name name of the database that is intended to be changed + * @param array $options array with name, owner info + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function alterDatabase($name, $options = array()) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true); + if (!empty($options['name'])) { + $query .= ' RENAME TO ' . $options['name']; + } + if (!empty($options['owner'])) { + $query .= ' OWNER TO ' . $options['owner']; + } + return $db->standaloneQuery($query, null, true); } // }}} @@ -83,15 +119,116 @@ * @param string $name name of the database that should be dropped * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public - **/ + */ function dropDatabase($name) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - return $db->standaloneQuery("DROP DATABASE $name"); + $name = $db->quoteIdentifier($name, true); + $query = "DROP DATABASE $name"; + return $db->standaloneQuery($query, null, true); + } + + // }}} + // {{{ _getAdvancedFKOptions() + + /** + * Return the FOREIGN KEY query section dealing with non-standard options + * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... + * + * @param array $definition + * @return string + * @access protected + */ + function _getAdvancedFKOptions($definition) + { + $query = ''; + if (!empty($definition['match'])) { + $query .= ' MATCH '.$definition['match']; + } + if (!empty($definition['onupdate'])) { + $query .= ' ON UPDATE '.$definition['onupdate']; + } + if (!empty($definition['ondelete'])) { + $query .= ' ON DELETE '.$definition['ondelete']; + } + if (!empty($definition['deferrable'])) { + $query .= ' DEFERRABLE'; + } else { + $query .= ' NOT DEFERRABLE'; + } + if (!empty($definition['initiallydeferred'])) { + $query .= ' INITIALLY DEFERRED'; + } else { + $query .= ' INITIALLY IMMEDIATE'; + } + return $query; + } + + // }}} + // {{{ truncateTable() + + /** + * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, + * it falls back to a DELETE FROM TABLE query) + * + * @param string $name name of the table that should be truncated + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function truncateTable($name) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($name, true); + return $db->exec("TRUNCATE TABLE $name"); + } + + // }}} + // {{{ vacuum() + + /** + * Optimize (vacuum) all the tables in the db (or only the specified table) + * and optionally run ANALYZE. + * + * @param string $table table name (all the tables if empty) + * @param array $options an array with driver-specific options: + * - timeout [int] (in seconds) [mssql-only] + * - analyze [boolean] [pgsql and mysql] + * - full [boolean] [pgsql-only] + * - freeze [boolean] [pgsql-only] + * + * @return mixed MDB2_OK success, a MDB2 error on failure + * @access public + */ + function vacuum($table = null, $options = array()) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $query = 'VACUUM'; + + if (!empty($options['full'])) { + $query .= ' FULL'; + } + if (!empty($options['freeze'])) { + $query .= ' FREEZE'; + } + if (!empty($options['analyze'])) { + $query .= ' ANALYZE'; + } + + if (!empty($table)) { + $query .= ' '.$db->quoteIdentifier($table, true); + } + return $db->exec($query); } // }}} @@ -100,85 +237,96 @@ /** * alter an existing table * - * @param string $name name of the table that is intended to be changed. - * @param array $changes associative array that contains the details of each type - * of change that is intended to be performed. The types of - * changes that are currently supported are defined as follows: + * @param string $name name of the table that is intended to be changed. + * @param array $changes associative array that contains the details of each type + * of change that is intended to be performed. The types of + * changes that are currently supported are defined as follows: * - * name + * name * - * New name for the table. + * New name for the table. * - * add + * add * - * Associative array with the names of fields to be added as - * indexes of the array. The value of each entry of the array - * should be set to another associative array with the properties - * of the fields to be added. The properties of the fields should - * be the same as defined by the Metabase parser. + * Associative array with the names of fields to be added as + * indexes of the array. The value of each entry of the array + * should be set to another associative array with the properties + * of the fields to be added. The properties of the fields should + * be the same as defined by the MDB2 parser. * * - * remove + * remove * - * Associative array with the names of fields to be removed as indexes - * of the array. Currently the values assigned to each entry are ignored. - * An empty array should be used for future compatibility. + * Associative array with the names of fields to be removed as indexes + * of the array. Currently the values assigned to each entry are ignored. + * An empty array should be used for future compatibility. * - * rename + * rename * - * Associative array with the names of fields to be renamed as indexes - * of the array. The value of each entry of the array should be set to - * another associative array with the entry named name with the new - * field name and the entry named Declaration that is expected to contain - * the portion of the field declaration already in DBMS specific SQL code - * as it is used in the CREATE TABLE statement. + * Associative array with the names of fields to be renamed as indexes + * of the array. The value of each entry of the array should be set to + * another associative array with the entry named name with the new + * field name and the entry named Declaration that is expected to contain + * the portion of the field declaration already in DBMS specific SQL code + * as it is used in the CREATE TABLE statement. * - * change + * change * - * Associative array with the names of the fields to be changed as indexes - * of the array. Keep in mind that if it is intended to change either the - * name of a field and any other properties, the change array entries - * should have the new names of the fields as array indexes. + * Associative array with the names of the fields to be changed as indexes + * of the array. Keep in mind that if it is intended to change either the + * name of a field and any other properties, the change array entries + * should have the new names of the fields as array indexes. * - * The value of each entry of the array should be set to another associative - * array with the properties of the fields to that are meant to be changed as - * array entries. These entries should be assigned to the new values of the - * respective properties. The properties of the fields should be the same - * as defined by the Metabase parser. + * The value of each entry of the array should be set to another associative + * array with the properties of the fields to that are meant to be changed as + * array entries. These entries should be assigned to the new values of the + * respective properties. The properties of the fields should be the same + * as defined by the MDB2 parser. * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'gender' => array( - * 'default' => 'M', - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * ) - * ) - * ) - * @param boolean $check indicates whether the function should just check if the DBMS driver - * can perform the requested table alterations if the value is true or - * actually perform them otherwise. - * @return mixed MDB2_OK on success, a MDB2 error on failure + * Example + * array( + * 'name' => 'userlist', + * 'add' => array( + * 'quota' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * ) + * ), + * 'remove' => array( + * 'file_limit' => array(), + * 'time_limit' => array() + * ), + * 'change' => array( + * 'name' => array( + * 'length' => '20', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 20, + * ), + * ) + * ), + * 'rename' => array( + * 'sex' => array( + * 'name' => 'gender', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 1, + * 'default' => 'M', + * ), + * ) + * ) + * ) + * + * @param boolean $check indicates whether the function should just check if the DBMS driver + * can perform the requested table alterations if the value is true or + * actually perform them otherwise. * @access public - **/ + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + */ function alterTable($name, $changes, $check) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } @@ -189,11 +337,11 @@ case 'remove': case 'change': case 'name': - break; case 'rename': + break; default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'alterTable: change type "'.$change_name.'\" not yet supported'); + return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, + 'change type "'.$change_name.'\" not yet supported', __FUNCTION__); } } @@ -201,46 +349,85 @@ return MDB2_OK; } - $query = (array_key_exists('name', $changes) ? 'RENAME TO '.$changes['name'] : ''); + $name = $db->quoteIdentifier($name, true); - if (array_key_exists('add', $changes)) { - foreach ($changes['add'] as $field_name => $field) { - $type_declaration = $db->getDeclaration($field['type'], $field_name, $field); - if (PEAR::isError($type_declaration)) { - return $err; - } - if ($query) { - $query.= ', '; - } - $query.= 'ADD ' . $type_declaration; - } - } - - if (array_key_exists('remove', $changes)) { + if (!empty($changes['remove']) && is_array($changes['remove'])) { foreach ($changes['remove'] as $field_name => $field) { - if ($query) { - $query.= ', '; + $field_name = $db->quoteIdentifier($field_name, true); + $query = 'DROP ' . $field_name; + $result = $db->exec("ALTER TABLE $name $query"); + if (PEAR::isError($result)) { + return $result; } - $query.= 'DROP ' . $field_name; } } - if (array_key_exists('change', $changes)) { - // missing support to change DEFAULT and NULLability + if (!empty($changes['rename']) && is_array($changes['rename'])) { + foreach ($changes['rename'] as $field_name => $field) { + $field_name = $db->quoteIdentifier($field_name, true); + $result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true)); + if (PEAR::isError($result)) { + return $result; + } + } + } + + if (!empty($changes['add']) && is_array($changes['add'])) { + foreach ($changes['add'] as $field_name => $field) { + $query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field); + $result = $db->exec("ALTER TABLE $name $query"); + if (PEAR::isError($result)) { + return $result; + } + } + } + + if (!empty($changes['change']) && is_array($changes['change'])) { foreach ($changes['change'] as $field_name => $field) { - if ($query) { - $query.= ', '; + $field_name = $db->quoteIdentifier($field_name, true); + if (!empty($field['definition']['type'])) { + $server_info = $db->getServerVersion(); + if (PEAR::isError($server_info)) { + return $server_info; + } + if (is_array($server_info) && $server_info['major'] < 8) { + return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null, + 'changing column type for "'.$change_name.'\" requires PostgreSQL 8.0 or above', __FUNCTION__); + } + $db->loadModule('Datatype', null, true); + $type = $db->datatype->getTypeDeclaration($field['definition']); + $query = "ALTER $field_name TYPE $type USING CAST($field_name AS $type)"; + $result = $db->exec("ALTER TABLE $name $query"); + if (PEAR::isError($result)) { + return $result; + } } - $db->loadModule('Datatype'); - $query.= "ALTER $field_name TYPE ".$db->datatype->getTypeDeclaration($field); + if (array_key_exists('default', $field['definition'])) { + $query = "ALTER $field_name SET DEFAULT ".$db->quote($field['definition']['default'], $field['definition']['type']); + $result = $db->exec("ALTER TABLE $name $query"); + if (PEAR::isError($result)) { + return $result; + } + } + if (array_key_exists('notnull', $field['definition'])) { + $query = "ALTER $field_name ".($field['definition']['notnull'] ? 'SET' : 'DROP').' NOT NULL'; + $result = $db->exec("ALTER TABLE $name $query"); + if (PEAR::isError($result)) { + return $result; + } + } } } - if (!$query) { - return MDB2_OK; + if (!empty($changes['name'])) { + $change_name = $db->quoteIdentifier($changes['name'], true); + $result = $db->exec("ALTER TABLE $name RENAME TO ".$change_name); + if (PEAR::isError($result)) { + return $result; + } } - return $db->query("ALTER TABLE $name $query"); + return MDB2_OK; } // }}} @@ -249,24 +436,31 @@ /** * list all databases * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of database names on success, a MDB2 error on failure * @access public - **/ + */ function listDatabases() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $result = $db->standaloneQuery('SELECT datname FROM pg_database'); - if (!MDB2::isResultCommon($result)) { - return $result; + $query = 'SELECT datname FROM pg_database'; + $result2 = $db->standaloneQuery($query, array('text'), false); + if (!MDB2::isResultCommon($result2)) { + return $result2; } - $col = $result->fetchCol(); - $result->free(); - return $col; + $result = $result2->fetchCol(); + $result2->free(); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} @@ -275,44 +469,84 @@ /** * list all users * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of user names on success, a MDB2 error on failure * @access public - **/ + */ function listUsers() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $result = $db->standaloneQuery('SELECT usename FROM pg_user'); - if (!MDB2::isResultCommon($result)) { - return $result; + $query = 'SELECT usename FROM pg_user'; + $result2 = $db->standaloneQuery($query, array('text'), false); + if (!MDB2::isResultCommon($result2)) { + return $result2; } - $col = $result->fetchCol(); - $result->free(); - return $col; + $result = $result2->fetchCol(); + $result2->free(); + return $result; } // }}} // {{{ listViews() /** - * list the views in the database + * list all views in the current database * - * @return mixed MDB2_OK on success, a MDB2 error on failure + * @return mixed array of view names on success, a MDB2 error on failure * @access public - **/ + */ function listViews() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $query = 'SELECT viewname FROM pg_views'; - return $db->queryCol($query); + $query = "SELECT viewname + FROM pg_views + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') + AND viewname !~ '^pg_'"; + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listTableViews() + + /** + * list the views in the database that reference a given table + * + * @param string table for which all referenced views should be found + * @return mixed array of view names on success, a MDB2 error on failure + * @access public + */ + function listTableViews($table) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT viewname FROM pg_views NATURAL JOIN pg_tables'; + $query.= ' WHERE tablename ='.$db->quote($table, 'text'); + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} @@ -321,12 +555,12 @@ /** * list all functions in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of function names on success, a MDB2 error on failure * @access public */ function listFunctions() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } @@ -343,7 +577,49 @@ AND tp.typname <> 'trigger' AND pr.pronamespace IN (SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')"; - return $db->queryCol($query); + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; + } + + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure + * @access public + */ + function listTableTriggers($table = null) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $query = 'SELECT trg.tgname AS trigger_name + FROM pg_trigger trg, + pg_class tbl + WHERE trg.tgrelid = tbl.oid'; + if (null !== $table) { + $table = $db->quote(strtoupper($table), 'text'); + $query .= " AND UPPER(tbl.relname) = $table"; + } + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} @@ -352,12 +628,12 @@ /** * list all tables in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of table names on success, a MDB2 error on failure * @access public - **/ + */ function listTables() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } @@ -382,93 +658,50 @@ . ' (SELECT 1 FROM pg_user' . ' WHERE usesysid = c.relowner)' . " AND c.relname !~ '^pg_'"; - return $db->queryCol($query); + $result = $db->queryCol($query); + if (PEAR::isError($result)) { + return $result; + } + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } // }}} // {{{ listTableFields() /** - * list all fields in a tables in the current database + * list all fields in a table in the current database * * @param string $table name of table that should be used in method - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of field names on success, a MDB2 error on failure * @access public */ function listTableFields($table) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $result = $db->query("SELECT * FROM $table"); + list($schema, $table) = $this->splitTableSchema($table); + + $table = $db->quoteIdentifier($table, true); + if (!empty($schema)) { + $table = $db->quoteIdentifier($schema, true) . '.' .$table; + } + $db->setLimit(1); + $result2 = $db->query("SELECT * FROM $table"); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $result2->getColumnNames(); + $result2->free(); if (PEAR::isError($result)) { return $result; } - $columns = $result->getColumnNames(); - $result->free(); - if (PEAR::isError($columns)) { - return $columns; - } - return array_flip($columns); - } - - // }}} - // {{{ createIndex() - - /** - * get the stucture of a field into an array - * - * @param string $table name of the table on which the index is to be created - * @param string $name name of the index to be created - * @param array $definition associative array that defines properties of the index to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the index fields as array - * indexes. Each entry of this array is set to another type of associative - * array that specifies properties of the index that are specific to - * each field. - * - * Currently, only the sorting property is supported. It should be used - * to define the sorting direction of the index. It may be set to either - * ascending or descending. - * - * Not all DBMS support index sorting direction configuration. The DBMS - * drivers of those that do not support it ignore this property. Use the - * function supports() to determine whether the DBMS driver can manage indexes. - * - * Example - * array( - * 'fields' => array( - * 'user_name' => array( - * 'sorting' => 'ascending' - * ), - * 'last_login' => array() - * ) - * ) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createIndex($table, $name, $definition) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (array_key_exists('primary', $definition) && $definition['primary']) { - $query = "ALTER TABLE $table ADD CONSTRAINT $name PRIMARY KEY ("; - } else { - $query = 'CREATE'; - if (array_key_exists('unique', $definition) && $definition['unique']) { - $query.= ' UNIQUE'; - } - $query.= " INDEX $name ON $table ("; - } - $query.= implode(', ', array_keys($definition['fields'])); - $query.= ')'; - - return $db->query($query); + return array_flip($result); } // }}} @@ -477,20 +710,163 @@ /** * list all indexes in a table * - * @param string $table name of table that should be used in method - * @return mixed data array on success, a MDB2 error on failure + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure * @access public */ function listTableIndexes($table) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $subquery = "SELECT indexrelid FROM pg_index, pg_class"; - $subquery.= " WHERE (pg_class.relname='$table') AND (pg_class.oid=pg_index.indrelid)"; - return $db->queryCol("SELECT relname FROM pg_class WHERE oid IN ($subquery)"); + list($schema, $table) = $this->splitTableSchema($table); + + $table = $db->quote($table, 'text'); + $subquery = "SELECT indexrelid + FROM pg_index + LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid + LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid + WHERE pg_class.relname = $table + AND indisunique != 't' + AND indisprimary != 't'"; + if (!empty($schema)) { + $subquery .= ' AND pg_namespace.nspname = '.$db->quote($schema, 'text'); + } + $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)"; + $indexes = $db->queryCol($query, 'text'); + if (PEAR::isError($indexes)) { + return $indexes; + } + + $result = array(); + foreach ($indexes as $index) { + $index = $this->_fixIndexName($index); + if (!empty($index)) { + $result[$index] = true; + } + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_change_key_case($result, $db->options['field_case']); + } + return array_keys($result); + } + + // }}} + // {{{ dropConstraint() + + /** + * drop existing constraint + * + * @param string $table name of table that should be used in method + * @param string $name name of the constraint to be dropped + * @param string $primary hint if the constraint is primary + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropConstraint($table, $name, $primary = false) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + // is it an UNIQUE index? + $query = 'SELECT relname + FROM pg_class + WHERE oid IN ( + SELECT indexrelid + FROM pg_index, pg_class + WHERE pg_class.relname = '.$db->quote($table, 'text').' + AND pg_class.oid = pg_index.indrelid + AND indisunique = \'t\') + EXCEPT + SELECT conname + FROM pg_constraint, pg_class + WHERE pg_constraint.conrelid = pg_class.oid + AND relname = '. $db->quote($table, 'text'); + $unique = $db->queryCol($query, 'text'); + if (PEAR::isError($unique) || empty($unique)) { + // not an UNIQUE index, maybe a CONSTRAINT + return parent::dropConstraint($table, $name, $primary); + } + + if (in_array($name, $unique)) { + return $db->exec('DROP INDEX '.$db->quoteIdentifier($name, true)); + } + $idxname = $db->getIndexName($name); + if (in_array($idxname, $unique)) { + return $db->exec('DROP INDEX '.$db->quoteIdentifier($idxname, true)); + } + return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + $name . ' is not an existing constraint for table ' . $table, __FUNCTION__); + } + + // }}} + // {{{ listTableConstraints() + + /** + * list all constraints in a table + * + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure + * @access public + */ + function listTableConstraints($table) + { + $db = $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + list($schema, $table) = $this->splitTableSchema($table); + + $table = $db->quote($table, 'text'); + $query = 'SELECT conname + FROM pg_constraint + LEFT JOIN pg_class ON pg_constraint.conrelid = pg_class.oid + LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid + WHERE relname = ' .$table; + if (!empty($schema)) { + $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text'); + } + $query .= ' + UNION DISTINCT + SELECT relname + FROM pg_class + WHERE oid IN ( + SELECT indexrelid + FROM pg_index + LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid + LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid + WHERE pg_class.relname = '.$table.' + AND indisunique = \'t\''; + if (!empty($schema)) { + $query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text'); + } + $query .= ')'; + $constraints = $db->queryCol($query); + if (PEAR::isError($constraints)) { + return $constraints; + } + + $result = array(); + foreach ($constraints as $constraint) { + $constraint = $this->_fixIndexName($constraint); + if (!empty($constraint)) { + $result[$constraint] = true; + } + } + + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE + && $db->options['field_case'] == CASE_LOWER + ) { + $result = array_change_key_case($result, $db->options['field_case']); + } + return array_keys($result); } // }}} @@ -503,16 +879,16 @@ * @param string $start start value of the sequence; default is 1 * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public - **/ + */ function createSequence($seq_name, $start = 1) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $sequence_name = $db->getSequenceName($seq_name); - return $db->query("CREATE SEQUENCE $sequence_name INCREMENT 1". + $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); + return $db->exec("CREATE SEQUENCE $sequence_name INCREMENT 1". ($start < 1 ? " MINVALUE $start" : '')." START $start"); } @@ -525,16 +901,16 @@ * @param string $seq_name name of the sequence to be dropped * @return mixed MDB2_OK on success, a MDB2 error on failure * @access public - **/ + */ function dropSequence($seq_name) { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } - $sequence_name = $db->getSequenceName($seq_name); - return $db->query("DROP SEQUENCE $sequence_name"); + $sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true); + return $db->exec("DROP SEQUENCE $sequence_name"); } // }}} @@ -543,12 +919,12 @@ /** * list all sequences in the current database * - * @return mixed data array on success, a MDB2 error on failure + * @return mixed array of sequence names on success, a MDB2 error on failure * @access public - **/ + */ function listSequences() { - $db =& $this->getDBInstance(); + $db = $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } @@ -559,12 +935,14 @@ if (PEAR::isError($table_names)) { return $table_names; } - $sequences = array(); - for ($i = 0, $j = count($table_names); $i < $j; ++$i) { - if ($sqn = $this->_isSequenceName($table_names[$i])) - $sequences[] = $sqn; + $result = array(); + foreach ($table_names as $table_name) { + $result[] = $this->_fixSequenceName($table_name); } - return $sequences; + if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + $result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result); + } + return $result; } } -?> +?> \ No newline at end of file -- Gitblit v1.9.1