diff --git a/app/config/schema/schema.json b/app/config/schema/schema.json index b1f53456d..9ea2d7a21 100644 --- a/app/config/schema/schema.json +++ b/app/config/schema/schema.json @@ -443,7 +443,7 @@ "identifiers_i2": { "columns": [ "identifier", "type_id", "external_identity_id" ] }, "identifiers_i3": { "columns": [ "type_id" ] }, "identifiers_i4": { "needed": false, "columns": [ "provisioning_target_id" ] }, - "identifiers_i5": { "columns": [ "lower(identifier)", "type_id" ] } + "identifiers_i5": { "columns": [ "lower(identifier::text)", "type_id" ] } }, "mvea": [ "person", "external_identity", "group" ], "sourced": true diff --git a/app/src/Lib/Util/CmgPostgreSQLSchemaManager.php b/app/src/Lib/Util/CmgPostgreSQLSchemaManager.php new file mode 100644 index 000000000..d557def5a --- /dev/null +++ b/app/src/Lib/Util/CmgPostgreSQLSchemaManager.php @@ -0,0 +1,107 @@ + $colName) { + $buffer[] = [ + 'key_name' => $row['relname'], + 'column_name' => trim($colName), + 'non_unique' => ! $row['indisunique'], + 'primary' => $row['indisprimary'], + 'where' => $row['where'], + ]; + } + } + + return AbstractSchemaManager::_getPortableTableIndexesList($buffer, $tableName); + } + + + protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result + { + $sql = 'SELECT'; + + if ($tableName === null) { + $sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,'; + } + + $sql .= <<<'SQL' + quote_ident(ic.relname) AS relname, + i.indisunique, + i.indisprimary, + i.indkey, + i.indexprs, + i.indrelid, + ARRAY( + SELECT pg_get_indexdef(i.indexrelid, k + 1, true) + FROM generate_subscripts(i.indkey, 1) AS k + ORDER BY k + ) AS indkey_names, + pg_get_expr(indpred, indrelid) AS "where" + FROM pg_index i + JOIN pg_class AS tc ON tc.oid = i.indrelid + JOIN pg_namespace tn ON tn.oid = tc.relnamespace + JOIN pg_class AS ic ON ic.oid = i.indexrelid + WHERE ic.oid IN ( + SELECT indexrelid + FROM pg_index i, pg_class c, pg_namespace n +SQL; + + $conditions = array_merge([ + 'c.oid = i.indrelid', + 'c.relnamespace = n.oid', + ], $this->buildQueryConditions($tableName)); + + $sql .= ' WHERE ' . implode(' AND ', $conditions) . ')'; + + return $this->_conn->executeQuery($sql); + } + + /** + * @param string|null $tableName + * + * @return list + */ + private function buildQueryConditions($tableName): array + { + $conditions = []; + + if ($tableName !== null) { + if (strpos($tableName, '.') !== false) { + [$schemaName, $tableName] = explode('.', $tableName); + $conditions[] = 'n.nspname = ' . $this->_platform->quoteStringLiteral($schemaName); + } else { + $conditions[] = 'n.nspname = ANY(current_schemas(false))'; + } + + $identifier = new Identifier($tableName); + $conditions[] = 'c.relname = ' . $this->_platform->quoteStringLiteral($identifier->getName()); + } + + $conditions[] = "n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')"; + + return $conditions; + } +} + diff --git a/app/src/Lib/Util/CmgSchemaManagerFactory.php b/app/src/Lib/Util/CmgSchemaManagerFactory.php new file mode 100644 index 000000000..4d54e7fa3 --- /dev/null +++ b/app/src/Lib/Util/CmgSchemaManagerFactory.php @@ -0,0 +1,34 @@ +defaultFactory = new DefaultSchemaManagerFactory(); + } + + public function createSchemaManager(Connection $connection): AbstractSchemaManager + { + $platform = $connection->getDatabasePlatform(); + if ($platform instanceof PostgreSQL1000Platform + || $platform instanceof PostgreSQLPlatform) { + return new CmgPostgreSQLSchemaManager($connection, $platform); + } + + return $this->defaultFactory->createSchemaManager($connection); + } +} diff --git a/app/src/Lib/Util/SchemaManager.php b/app/src/Lib/Util/SchemaManager.php index ef3686850..ee53ab284 100644 --- a/app/src/Lib/Util/SchemaManager.php +++ b/app/src/Lib/Util/SchemaManager.php @@ -32,6 +32,7 @@ use Cake\Console\ConsoleIo; use Cake\Datasource\ConnectionInterface; use Cake\Datasource\ConnectionManager; +use App\Lib\Util\CmgSchemaManagerFactory; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Schema\Comparator; @@ -79,7 +80,9 @@ public function __construct(?ConsoleIo $io=null, string $connection='default') { $cfg = $db->config(); $config = new \Doctrine\DBAL\Configuration(); - + // Load the COmanage custom CmgSchemaManagerFactory + $config->setSchemaManagerFactory(new CmgSchemaManagerFactory()); + $cfargs = [ 'dbname' => $cfg['database'], 'user' => $cfg['username'], @@ -325,12 +328,12 @@ protected function processSchema( // This is the SQL that represents the desired state of the database $toSql = $schema->toSql($this->conn->getDatabasePlatform()); - + // SchemaManager provides info about the database $sm = $this->conn->createSchemaManager(); // The is the current database representation - $curSchema = $sm->createSchema(); + $curSchema = $sm->introspectSchema(); $fromSql = $curSchema->toSql($this->conn->getDatabasePlatform());