diff --git a/includes/database/pgsql/schema.inc b/includes/database/pgsql/schema.inc index f05cc08680b3038b776e6b0b5d309a78a2231d0b..b7a8fe4b41acd0eee5b6cb82c8273b63bb9e1228 100644 --- a/includes/database/pgsql/schema.inc +++ b/includes/database/pgsql/schema.inc @@ -74,6 +74,39 @@ public function queryTableInformation($table) { return $this->tableInformation[$key]; } + /** + * Fetch the list of CHECK constraints used on a field. + * + * We introspect the database to collect the information required by field + * alteration. + * + * @param $table + * The non-prefixed name of the table. + * @param $field + * The name of the field. + * @return + * An array of all the checks for the field. + */ + public function queryFieldInformation($table, $field) { + $prefixInfo = $this->getPrefixInfo($table, TRUE); + + // Split the key into schema and table for querying. + $schema = $prefixInfo['schema']; + $table_name = $prefixInfo['table']; + + $field_information = (object) array( + 'checks' => array(), + ); + $checks = $this->connection->query("SELECT conname FROM pg_class cl INNER JOIN pg_constraint co ON co.conrelid = cl.oid INNER JOIN pg_attribute attr ON attr.attrelid = cl.oid AND attr.attnum = ANY (co.conkey) INNER JOIN pg_namespace ns ON cl.relnamespace = ns.oid WHERE co.contype = 'c' AND ns.nspname = :schema AND cl.relname = :table AND attr.attname = :column", array( + ':schema' => $schema, + ':table' => $table_name, + ':column' => $field, + )); + $field_information = $checks->fetchCol(); + + return $field_information; + } + /** * Generate SQL to create a new table from a Drupal schema definition. * @@ -469,13 +502,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new))); } - $spec += array('size' => 'normal'); - - // Map type definition to the PostgreSQL type. - if (!isset($spec['pgsql_type'])) { - $map = $this->getFieldTypeMap(); - $spec['pgsql_type'] = $map[$spec['type'] . ':' . $spec['size']]; - } + $spec = $this->processField($spec); // We need to typecast the new column to best be able to transfer the data // Schema_pgsql::getFieldTypeMap() will return possibilities that are not @@ -487,6 +514,20 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array $typecast = $spec['pgsql_type']; } + if (in_array($spec['pgsql_type'], array('varchar', 'character', 'text')) && isset($spec['length'])) { + $typecast .= '(' . $spec['length'] . ')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $typecast .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')'; + } + + // Remove old check constraints. + $field_info = $this->queryFieldInformation($table, $field); + + foreach ($field_info as $check) { + $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"'); + } + $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast); if (isset($spec['not null'])) { @@ -516,6 +557,11 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '"'); } + // Add unsigned check if necessary. + if (!empty($spec['unsigned'])) { + $this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)'); + } + // Change description if necessary. if (!empty($spec['description'])) { $this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));