diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php index 4688cdebdc5220714fae3b1c74386e3a1a532b7c..80497962cb2469a97377c6d8cac11381581fe5ed 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php @@ -210,13 +210,8 @@ public function escapeField($field) { // need to be escaped. $escaped = $this->escapeTable($table) . '.' . $this->escapeAlias($column); } - elseif (preg_match('/[A-Z]/', $escaped)) { - // Quote the field name for case-sensitivity. - $escaped = '"' . $escaped . '"'; - } - elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) { - // Quote the field name for PostgreSQL reserved key words. - $escaped = '"' . $escaped . '"'; + else { + $escaped = $this->doEscape($escaped); } return $escaped; @@ -227,16 +222,7 @@ public function escapeField($field) { */ public function escapeAlias($field) { $escaped = preg_replace('/[^A-Za-z0-9_]+/', '', $field); - - // Escape the alias in quotes for case-sensitivity. - if (preg_match('/[A-Z]/', $escaped)) { - $escaped = '"' . $escaped . '"'; - } - elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) { - // Quote the alias name for PostgreSQL reserved key words. - $escaped = '"' . $escaped . '"'; - } - + $escaped = $this->doEscape($escaped); return $escaped; } @@ -246,16 +232,33 @@ public function escapeAlias($field) { public function escapeTable($table) { $escaped = parent::escapeTable($table); + // Ensure that each part (database, schema and table) of the table name is + // properly and independently escaped. + $parts = explode('.', $escaped); + $parts = array_map([$this, 'doEscape'], $parts); + $escaped = implode('.', $parts); + + return $escaped; + } + + /** + * Escape a string if needed. + * + * @param $string + * The string to escape. + * @return string + * The escaped string. + */ + protected function doEscape($string) { // Quote identifier to make it case-sensitive. - if (preg_match('/[A-Z]/', $escaped)) { - $escaped = '"' . $escaped . '"'; + if (preg_match('/[A-Z]/', $string)) { + $string = '"' . $string . '"'; } - elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) { - // Quote the table name for PostgreSQL reserved key words. - $escaped = '"' . $escaped . '"'; + elseif (in_array(strtolower($string), $this->postgresqlReservedKeyWords)) { + // Quote the string for PostgreSQL reserved key words. + $string = '"' . $string . '"'; } - - return $escaped; + return $string; } public function driver() { diff --git a/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlConnectionTest.php b/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlConnectionTest.php index 2bf263962d9de300e9ff87a2d14d7ea072a5b24e..883f851d950a1b4d4e9c58a83c1ffac7699618cb 100644 --- a/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlConnectionTest.php +++ b/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlConnectionTest.php @@ -40,6 +40,11 @@ public function providerEscapeTables() { array('"camelCase"', 'camelCase'), array('"camelCase"', '"camelCase"'), array('"camelCase"', 'camel/Case'), + // Sometimes, table names are following the pattern database.schema.table. + array('"camelCase".nocase.nocase', 'camelCase.nocase.nocase'), + array('nocase."camelCase".nocase', 'nocase.camelCase.nocase'), + array('nocase.nocase."camelCase"', 'nocase.nocase.camelCase'), + array('"camelCase"."camelCase"."camelCase"', 'camelCase.camelCase.camelCase'), ); }