diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
index b1aa8f7..8114f04 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
@@ -94,7 +94,7 @@ protected function ensureIdentifiersLength($identifier) {
   public function queryTableInformation($table) {
     // Generate a key to reference this table's information on.
     $key = $this->connection->prefixTables('{' . $table . '}');
-    if (!strpos($key, '.')) {
+    if (strpos($key, '.') === FALSE) {
       $key = 'public.' . $key;
     }
 
@@ -110,8 +110,8 @@ public function queryTableInformation($table) {
 
       try {
         $result = $this->connection->query("SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table AND (data_type = 'bytea' OR (numeric_precision IS NOT NULL AND column_default LIKE :default))", array(
-          ':schema' => $schema,
-          ':table' => $table_name,
+          ':schema' => db_escape_table($schema),
+          ':table' => db_escape_table($table_name),
           ':default' => '%nextval%',
         ));
       }
@@ -139,6 +139,20 @@ public function queryTableInformation($table) {
   }
 
   /**
+   * Resets information about table blobs, sequences and serial fields.
+   *
+   * @param $table
+   *   The non-prefixed name of the table.
+   */
+  protected function resetTableInformation($table) {
+    $key = $this->connection->prefixTables('{' . $table . '}');
+    if (strpos($key, '.') === FALSE) {
+      $key = 'public.' . $key;
+    }
+    unset($this->tableInformation[$key]);
+  }
+
+  /**
    * Fetch the list of CHECK constraints used on a field.
    *
    * We introspect the database to collect the information required by field
@@ -162,8 +176,8 @@ public function queryFieldInformation($table, $field) {
 
     try {
       $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,
+        ':schema' => db_escape_table($schema),
+        ':table' => db_escape_table($table_name),
         ':column' => $field,
       ));
     }
@@ -197,15 +211,15 @@ protected function createTableSql($name, $table) {
 
     $sql_keys = array();
     if (isset($table['primary key']) && is_array($table['primary key'])) {
-      $sql_keys[] = 'PRIMARY KEY (' . $this->createPrimaryKeySql($table['primary key']) . ')';
+      $sql_keys[] = 'CONSTRAINT "' . $this->ensureIdentifiersLength($name, '', 'pkey') . '" PRIMARY KEY (' . $this->createPrimaryKeySql($table['primary key']) . ')';
     }
     if (isset($table['unique keys']) && is_array($table['unique keys'])) {
       foreach ($table['unique keys'] as $key_name => $key) {
-        $sql_keys[] = 'CONSTRAINT ' . $this->ensureIdentifiersLength($name, $key_name, 'key') . ' UNIQUE (' . implode(', ', $key) . ')';
+        $sql_keys[] = 'CONSTRAINT "' . $this->ensureIdentifiersLength($name, $key_name, 'key') . '" UNIQUE (' . implode(', ', $key) . ')';
       }
     }
 
-    $sql = "CREATE TABLE {" . $name . "} (\n\t";
+    $sql = "CREATE TABLE {" . db_escape_table($name) . "} (\n\t";
     $sql .= implode(",\n\t", $sql_fields);
     if (count($sql_keys) > 0) {
       $sql .= ",\n\t";
@@ -222,7 +236,7 @@ protected function createTableSql($name, $table) {
 
     // Add table comment.
     if (!empty($table['description'])) {
-      $statements[] = 'COMMENT ON TABLE {' . $name . '} IS ' . $this->prepareComment($table['description']);
+      $statements[] = 'COMMENT ON TABLE {' . db_escape_table($name) . '} IS ' . $this->prepareComment($table['description']);
     }
 
     // Add column comments.
@@ -414,23 +428,49 @@ function renameTable($table, $new_name) {
     }
 
     // Get the schema and tablename for the old table.
-    $old_full_name = $this->connection->prefixTables('{' . $table . '}');
+    $old_full_name = $this->connection->prefixTables('{' . db_escape_table($table) . '}');
     list($old_schema, $old_table_name) = strpos($old_full_name, '.') ? explode('.', $old_full_name) : array('public', $old_full_name);
 
     // Index names and constraint names are global in PostgreSQL, so we need to
     // rename them when renaming the table.
-    $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', array(':schema' => $old_schema, ':table' => $old_table_name));
+    $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', array(':schema' => db_escape_table($old_schema), ':table' => db_escape_table($old_table_name)));
+
     foreach ($indexes as $index) {
-      if (preg_match('/^' . preg_quote($old_full_name) . '_(.*)$/', $index->indexname, $matches)) {
+      // Get the index type by suffix, e.g. idx/key/pkey
+      $index_type = substr($index->indexname, strrpos($index->indexname, '_') + 1);
+
+      // If the index is already rewritten by ensureIdentifiersLength() to not
+      // exceed the 63 chars limit of PostgreSQL, we need to take care of that.
+      // Example (drupal_Gk7Su_T1jcBHVuvSPeP22_I3Ni4GrVEgTYlIYnBJkro_idx).
+      if (strpos($index->indexname, 'drupal_') !== FALSE) {
+        preg_match('/^drupal_(.*)_' . preg_quote($index_type) . '/', $index->indexname, $matches);
         $index_name = $matches[1];
-        $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO ' . $this->ensureIdentifiersLength($new_name, $index_name, 'idx'));
       }
+      else {
+        // Make sure to remove the suffix from index names, because
+        // $this->ensureIdentifiersLength() will add the suffix again and thus
+        // would result in a wrong index name.
+        preg_match('/^' . preg_quote($old_full_name) . '__(.*)__' . preg_quote($index_type) . '/', $index->indexname, $matches);
+        $index_name = $matches[1];
+      }
+      $this->connection->query('ALTER INDEX "' . $index->indexname . '" RENAME TO "' . $this->ensureIdentifiersLength($new_name, $index_name, $index_type) . '"');
     }
 
-    // Now rename the table.
     // Ensure the new table name does not include schema syntax.
     $prefixInfo = $this->getPrefixInfo($new_name);
-    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $prefixInfo['table']);
+
+    // Rename sequences if there's a serial fields.
+    $info = $this->queryTableInformation($table);
+    if (!empty($info->serial_fields)) {
+      foreach ($info->serial_fields as $field) {
+        $old_sequence = $this->prefixNonTable($table, $field, 'seq');
+        $new_sequence = $this->prefixNonTable($new_name, $field, 'seq');
+        $this->connection->query('ALTER SEQUENCE ' . $old_sequence . ' RENAME TO ' . $new_sequence);
+      }
+    }
+    // Now rename the table.
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} RENAME TO ' . db_escape_table($prefixInfo['table']));
+    $this->resetTableInformation($table);
   }
 
   public function dropTable($table) {
@@ -438,7 +478,8 @@ public function dropTable($table) {
       return FALSE;
     }
 
-    $this->connection->query('DROP TABLE {' . $table . '}');
+    $this->connection->query('DROP TABLE {' . db_escape_table($table) . '}');
+    $this->resetTableInformation($table);
     return TRUE;
   }
 
@@ -455,7 +496,7 @@ public function addField($table, $field, $spec, $new_keys = array()) {
       $fixnull = TRUE;
       $spec['not null'] = FALSE;
     }
-    $query = 'ALTER TABLE {' . $table . '} ADD COLUMN ';
+    $query = 'ALTER TABLE {' . db_escape_table($table) . '} ADD COLUMN ';
     $query .= $this->createFieldSql($field, $this->processField($spec));
     $this->connection->query($query);
     if (isset($spec['initial'])) {
@@ -464,15 +505,16 @@ public function addField($table, $field, $spec, $new_keys = array()) {
         ->execute();
     }
     if ($fixnull) {
-      $this->connection->query("ALTER TABLE {" . $table . "} ALTER $field SET NOT NULL");
+      $this->connection->query("ALTER TABLE {" . db_escape_table($table) . "} ALTER $field SET NOT NULL");
     }
     if (isset($new_keys)) {
       $this->_createKeys($table, $new_keys);
     }
     // Add column comment.
     if (!empty($spec['description'])) {
-      $this->connection->query('COMMENT ON COLUMN {' . $table . '}.' . $field . ' IS ' . $this->prepareComment($spec['description']));
+      $this->connection->query('COMMENT ON COLUMN {' . db_escape_table($table) . '}.' . $field . ' IS ' . $this->prepareComment($spec['description']));
     }
+    $this->resetTableInformation($table);
   }
 
   public function dropField($table, $field) {
@@ -480,7 +522,8 @@ public function dropField($table, $field) {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP COLUMN "' . $field . '"');
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} DROP COLUMN "' . $field . '"');
+    $this->resetTableInformation($table);
     return TRUE;
   }
 
@@ -491,7 +534,7 @@ public function fieldSetDefault($table, $field, $default) {
 
     $default = $this->escapeDefaultValue($default);
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" SET DEFAULT ' . $default);
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER COLUMN "' . $field . '" SET DEFAULT ' . $default);
   }
 
   public function fieldSetNoDefault($table, $field) {
@@ -499,13 +542,13 @@ public function fieldSetNoDefault($table, $field) {
       throw new SchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
   }
 
   public function indexExists($table, $name) {
     // Details http://www.postgresql.org/docs/8.3/interactive/view-pg-indexes.html
     $index_name = $this->ensureIdentifiersLength($table, $name, 'idx');
-    return (bool) $this->connection->query("SELECT 1 FROM pg_indexes WHERE indexname = '$index_name'")->fetchField();
+    return (bool) $this->connection->query("SELECT 1 FROM pg_indexes WHERE indexname = :index_name",array(':index_name'=> $index_name))->fetchField();
   }
 
   /**
@@ -516,9 +559,9 @@ public function indexExists($table, $name) {
    * @param $name
    *   The name of the constraint (typically 'pkey' or '[constraint]_key').
    */
-  protected function constraintExists($table, $name) {
+  public function constraintExists($table, $name) {
     $constraint_name = $this->ensureIdentifiersLength($table, $name);
-    return (bool) $this->connection->query("SELECT 1 FROM pg_constraint WHERE conname = '$constraint_name'")->fetchField();
+    return (bool) $this->connection->query("SELECT 1 FROM pg_constraint WHERE conname = :connname",array(':connname'=>$constraint_name))->fetchField();
   }
 
   public function addPrimaryKey($table, $fields) {
@@ -529,7 +572,8 @@ public function addPrimaryKey($table, $fields) {
       throw new SchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createPrimaryKeySql($fields) . ')');
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ADD CONSTRAINT "' . $this->ensureIdentifiersLength($table, '', 'pkey') . '" PRIMARY KEY (' . $this->createPrimaryKeySql($fields) . ')');
+    $this->resetTableInformation($table);
   }
 
   public function dropPrimaryKey($table) {
@@ -537,7 +581,8 @@ public function dropPrimaryKey($table) {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $this->ensureIdentifiersLength($table, 'pkey'));
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} DROP CONSTRAINT "' . $this->ensureIdentifiersLength($table, '', 'pkey') . '"');
+    $this->resetTableInformation($table);
     return TRUE;
   }
 
@@ -545,19 +590,21 @@ function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
       throw new SchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
     }
-    if ($this->constraintExists($table, $name . '_key')) {
+    if ($this->constraintExists($table, $name . '__key')) {
       throw new SchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ADD CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
+    $this->resetTableInformation($table);
   }
 
   public function dropUniqueKey($table, $name) {
-    if (!$this->constraintExists($table, $name . '_key')) {
+    if (!$this->constraintExists($table, $name . '__key')) {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '"');
+    $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} DROP CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '"');
+    $this->resetTableInformation($table);
     return TRUE;
   }
 
@@ -570,6 +617,7 @@ public function addIndex($table, $name, $fields) {
     }
 
     $this->connection->query($this->_createIndexSql($table, $name, $fields));
+    $this->resetTableInformation($table);
   }
 
   public function dropIndex($table, $name) {
@@ -578,6 +626,7 @@ public function dropIndex($table, $name) {
     }
 
     $this->connection->query('DROP INDEX ' . $this->ensureIdentifiersLength($table, $name, 'idx'));
+    $this->resetTableInformation($table);
     return TRUE;
   }
 
@@ -623,7 +672,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
     // the typecast does not work for conversions to bytea.
     // @see http://www.postgresql.org/docs/current/static/datatype-binary.html
     if ($spec['pgsql_type'] != 'bytea') {
-      $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast);
+      $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast);
     }
     else {
       // Do not attempt to convert a field that is bytea already.
@@ -632,7 +681,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
         // Convert to a bytea type by using the SQL replace() function to
         // convert any single backslashes in the field content to double
         // backslashes ('\' to '\\').
-        $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING decode(replace("' . $field . '"' . ", '\\', '\\\\'), 'escape');");
+        $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING decode(replace("' . $field . '"' . ", '\\', '\\\\'), 'escape');");
       }
     }
 
@@ -643,7 +692,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
       else {
         $nullaction = 'DROP NOT NULL';
       }
-      $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" ' . $nullaction);
+      $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER "' . $field . '" ' . $nullaction);
     }
 
     if (in_array($spec['pgsql_type'], array('serial', 'bigserial'))) {
@@ -655,17 +704,17 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
       // Set sequence to maximal field value to not conflict with existing
       // entries.
       $this->connection->query("SELECT setval('" . $seq . "', MAX(\"" . $field . '")) FROM {' . $table . "}");
-      $this->connection->query('ALTER TABLE {' . $table . '} ALTER ' . $field . ' SET DEFAULT nextval(' . $this->connection->quote($seq) . ')');
+      $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ALTER ' . $field . ' SET DEFAULT nextval(' . $this->connection->quote($seq) . ')');
     }
 
     // Rename the column if necessary.
     if ($field != $field_new) {
-      $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '"');
+      $this->connection->query('ALTER TABLE {' . db_escape_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)');
+      $this->connection->query('ALTER TABLE {' . db_escape_table($table) . '} ADD CHECK ("' . $field_new . '" >= 0)');
     }
 
     // Add default if necessary.
@@ -675,16 +724,17 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
 
     // Change description if necessary.
     if (!empty($spec['description'])) {
-      $this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));
+      $this->connection->query('COMMENT ON COLUMN {' . db_escape_table($table) . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));
     }
 
     if (isset($new_keys)) {
       $this->_createKeys($table, $new_keys);
     }
+    $this->resetTableInformation($table);
   }
 
   protected function _createIndexSql($table, $name, $fields) {
-    $query = 'CREATE INDEX "' . $this->ensureIdentifiersLength($table, $name, 'idx') . '" ON {' . $table . '} (';
+    $query = 'CREATE INDEX "' . $this->ensureIdentifiersLength($table, $name, 'idx') . '" ON {' . db_escape_table($table) . '} (';
     $query .= $this->_createKeySql($fields) . ')';
     return $query;
   }
diff --git a/core/modules/system/src/Tests/Database/SchemaTest.php b/core/modules/system/src/Tests/Database/SchemaTest.php
index da8623d..7b2bf2e 100644
--- a/core/modules/system/src/Tests/Database/SchemaTest.php
+++ b/core/modules/system/src/Tests/Database/SchemaTest.php
@@ -127,6 +127,67 @@ function testSchema() {
     $count = db_query('SELECT COUNT(*) FROM {test_table}')->fetchField();
     $this->assertEqual($count, 2, 'There were two rows.');
 
+    // Test renaming of keys and constraints.
+    db_drop_table('test_table');
+    $table_specification = array(
+      'fields' => array(
+        'id'  => array(
+          'type' => 'serial',
+          'not null' => TRUE,
+        ),
+        'test_field'  => array(
+          'type' => 'int',
+          'default' => 0,
+        ),
+      ),
+      'primary key' => array('id'),
+      'unique keys' => array(
+        'test_field' => array('test_field'),
+      ),
+    );
+    db_create_table('test_table', $table_specification);
+
+    // Tests for indexes are Database specific.
+    $db_type = Database::getConnection()->databaseType();
+
+    // Test for existing primary and unique keys.
+    switch ($db_type) {
+      case 'pgsql':
+        $primary_key_exists = Database::getConnection()->schema()->constraintExists('test_table', '__pkey');
+        $unique_key_exists = Database::getConnection()->schema()->constraintExists('test_table', 'test_field' . '__key');
+        break;
+      default:
+        $primary_key_exists = Database::getConnection()->schema()->indexExists('test_table', 'PRIMARY');
+        $unique_key_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field');
+        break;
+    }
+    $this->assertIdentical($primary_key_exists, TRUE, 'Primary key created.');
+    $this->assertIdentical($unique_key_exists, TRUE, 'Unique key created.');
+
+    db_rename_table('test_table', 'test_table2');
+
+    // Test for renamed primary and unique keys.
+    switch ($db_type) {
+      case 'pgsql':
+        $renamed_primary_key_exists = Database::getConnection()->schema()->constraintExists('test_table2', '__pkey');
+        $renamed_unique_key_exists = Database::getConnection()->schema()->constraintExists('test_table2', 'test_field' . '__key');
+        break;
+      default:
+        $renamed_primary_key_exists = Database::getConnection()->schema()->indexExists('test_table2', 'PRIMARY');
+        $renamed_unique_key_exists = Database::getConnection()->schema()->indexExists('test_table2', 'test_field');
+        break;
+    }
+    $this->assertIdentical($renamed_primary_key_exists, TRUE, 'Primary key was renamed.');
+    $this->assertIdentical($renamed_unique_key_exists, TRUE, 'Unique key was renamed.');
+
+    // For PostgreSQL check in addition that sequence was renamed.
+    if ($db_type == 'pgsql') {
+      // Get information about new table.
+      $info = Database::getConnection()->schema()->queryTableInformation('test_table2');
+      $sequence_name = Database::getConnection()->schema()->prefixNonTable('test_table2', 'id', 'seq');
+      $this->assertEqual($sequence_name, current($info->sequences), 'Sequence was renamed.');
+    }
+
     // Use database specific data type and ensure that table is created.
     $table_specification = array(
       'description' => 'Schema table description.',
