From df52d5c823725023b4a153cd48ee2210057062d0 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Sat, 1 Apr 2023 06:32:31 +1000
Subject: [PATCH] Revert "Issue #1148856 by drunken monkey, stefan.r, bzrudi71,
 xatoo, Ben Coleman, jyotisankar, daffie, mondrake, andypost, Damien Tournoud,
 alexpott: Postgres schema doesn't support keylength on a unique index"

This reverts commit 5074bef03d63d224fe67557a9d536862c7daf79b.
---
 .../lib/Drupal/Core/Database/database.api.php |   3 -
 .../src/Driver/Database/pgsql/Schema.php      |  14 +-
 .../SchemaUniquePrefixedKeysIndexTest.php     | 135 ------------------
 3 files changed, 4 insertions(+), 148 deletions(-)
 delete mode 100644 core/tests/Drupal/KernelTests/Core/Database/SchemaUniquePrefixedKeysIndexTest.php

diff --git a/core/lib/Drupal/Core/Database/database.api.php b/core/lib/Drupal/Core/Database/database.api.php
index e4e5a0b9be0..ab704108873 100644
--- a/core/lib/Drupal/Core/Database/database.api.php
+++ b/core/lib/Drupal/Core/Database/database.api.php
@@ -340,9 +340,6 @@ use Drupal\Core\Database\Query\SelectInterface;
  *
  * A key column specifier is either a string naming a column or an array of two
  * elements, column name and length, specifying a prefix of the named column.
- * Note that some DBMS drivers may opt to ignore the prefix length configuration
- * and still use the whole field value for the key. Code should therefore not
- * rely on this functionality.
  *
  * As an example, this is the schema definition for the 'users_data' table. It
  * shows five fields ('uid', 'module', 'name', 'value', and 'serialized'), the
diff --git a/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php b/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php
index 13f169c1518..b2fc2aa1571 100644
--- a/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php
+++ b/core/modules/pgsql/src/Driver/Database/pgsql/Schema.php
@@ -286,11 +286,7 @@ EOD;
     }
     if (isset($table['unique keys']) && is_array($table['unique keys'])) {
       foreach ($table['unique keys'] as $key_name => $key) {
-        // Use the createPrimaryKeySql(), which already discards any prefix
-        // lengths passed as part of the key column specifiers. (Postgres
-        // doesn't support setting a prefix length for PRIMARY or UNIQUE
-        // indices.)
-        $sql_keys[] = 'CONSTRAINT ' . $this->ensureIdentifiersLength($name, $key_name, 'key') . ' UNIQUE (' . $this->createPrimaryKeySql($key) . ')';
+        $sql_keys[] = 'CONSTRAINT ' . $this->ensureIdentifiersLength($name, $key_name, 'key') . ' UNIQUE (' . implode(', ', $key) . ')';
       }
     }
 
@@ -475,7 +471,7 @@ EOD;
   }
 
   /**
-   * Create the SQL expression for primary and unique keys.
+   * Create the SQL expression for primary keys.
    *
    * Postgresql does not support key length. It does support fillfactor, but
    * that requires a separate database lookup for each column in the key. The
@@ -798,10 +794,8 @@ EOD;
       throw new SchemaObjectExistsException("Cannot add unique key '$name' to table '$table': unique key already exists.");
     }
 
-    // Use the createPrimaryKeySql(), which already discards any prefix lengths
-    // passed as part of the key column specifiers. (Postgres doesn't support
-    // setting a prefix length for PRIMARY or UNIQUE indices.)
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' . $this->ensureIdentifiersLength($table, $name, 'key') . ' UNIQUE (' . $this->createPrimaryKeySql($fields) . ')');
+    $fields = array_map([$this->connection, 'escapeField'], $fields);
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' . $this->ensureIdentifiersLength($table, $name, 'key') . ' UNIQUE (' . implode(',', $fields) . ')');
     $this->resetTableInformation($table);
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/Database/SchemaUniquePrefixedKeysIndexTest.php b/core/tests/Drupal/KernelTests/Core/Database/SchemaUniquePrefixedKeysIndexTest.php
deleted file mode 100644
index b21543c13cd..00000000000
--- a/core/tests/Drupal/KernelTests/Core/Database/SchemaUniquePrefixedKeysIndexTest.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-namespace Drupal\KernelTests\Core\Database;
-
-use Drupal\Core\Database\DatabaseException;
-
-/**
- * Tests adding UNIQUE keys to tables.
- *
- * @coversDefaultClass \Drupal\Core\Database\Schema
- *
- * @group Database
- */
-class SchemaUniquePrefixedKeysIndexTest extends DatabaseTestBase {
-
-  /**
-   * Tests UNIQUE keys put directly on the table definition.
-   *
-   * @covers ::createTable
-   */
-  public function testCreateTable(): void {
-    $this->connection->schema()->createTable('test_unique', [
-      'fields' => [
-        'field' => [
-          'type' => 'varchar',
-          'length' => 50,
-        ],
-      ],
-      'unique keys' => [
-        'field' => [['field', 10]],
-      ],
-    ]);
-
-    $this->checkUniqueConstraintException('test_unique', 'field');
-  }
-
-  /**
-   * Tests adding a UNIQUE key to an existing table.
-   *
-   * @covers ::addUniqueKey
-   */
-  public function testAddUniqueKey(): void {
-    $this->connection->schema()
-      ->addUniqueKey('test_people', 'job', [['job', 10]]);
-
-    $this->checkUniqueConstraintException('test_people', 'job');
-  }
-
-  /**
-   * Tests adding a new field with UNIQUE key.
-   *
-   * @covers ::addField
-   */
-  public function testAddField(): void {
-    $field_spec = [
-      'type' => 'varchar',
-      'length' => 50,
-    ];
-    $keys_spec = [
-      'unique keys' => [
-        'field' => [['field', 10]],
-      ],
-    ];
-    $this->connection->schema()
-      ->addField('test', 'field', $field_spec, $keys_spec);
-
-    $this->checkUniqueConstraintException('test', 'field');
-  }
-
-  /**
-   * Tests changing a field to add a UNIQUE key.
-   *
-   * @covers ::changeField
-   */
-  public function testChangeField(): void {
-    $field_spec = [
-      'description' => "The person's job",
-      'type' => 'varchar_ascii',
-      'length' => 50,
-      'not null' => TRUE,
-      'default' => '',
-    ];
-    $keys_spec = [
-      'unique keys' => [
-        'job' => [['job', 10]],
-      ],
-    ];
-    $this->connection->schema()
-      ->changeField('test_people', 'job', 'job', $field_spec, $keys_spec);
-
-    $this->checkUniqueConstraintException('test_people', 'job');
-  }
-
-  /**
-   * Verifies that inserting the same value/prefix twice causes an exception.
-   *
-   * @param string $table
-   *   The table to insert into.
-   * @param string $column
-   *   The column on that table that has a UNIQUE index. If prefix lengths are
-   *   accepted for UNIQUE keys on the current database, the prefix length for
-   *   the field is expected to be set to 10 characters.
-   */
-  protected function checkUniqueConstraintException(string $table, string $column): void {
-    $this->connection->insert($table)
-      ->fields([
-        $column => '1234567890 foo',
-      ])
-      ->execute();
-
-    $this->expectException(DatabaseException::class);
-    $value = '1234567890 ' . ($this->supportsPrefixLength() ? 'bar' : 'foo');
-    $this->connection->insert($table)
-      ->fields([
-        $column => $value,
-      ])
-      ->execute();
-  }
-
-  /**
-   * Determines whether the current database supports prefix lengths for keys.
-   *
-   * The basic syntax of passing an array (field, prefix length) as a key column
-   * specifier must always be accepted by the driver. However, due to technical
-   * limitations, some drivers may choose to ignore them.
-   *
-   * @return bool
-   *   TRUE if the current database (driver) will conform to the prefix length
-   *   specified as part of a key column specifier, FALSE if it will be ignored.
-   */
-  protected function supportsPrefixLength(): bool {
-    return $this->connection->driver() === 'mysql';
-  }
-
-}