diff --git a/apps/federatedfilesharing/lib/Migration/Version1011Date20201120125158.php b/apps/federatedfilesharing/lib/Migration/Version1011Date20201120125158.php
index 43e84ed1795f5..aa1edd576f6aa 100644
--- a/apps/federatedfilesharing/lib/Migration/Version1011Date20201120125158.php
+++ b/apps/federatedfilesharing/lib/Migration/Version1011Date20201120125158.php
@@ -10,7 +10,6 @@
namespace OCA\FederatedFileSharing\Migration;
use Closure;
-use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\IDBConnection;
@@ -32,10 +31,10 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
if ($schema->hasTable('federated_reshares')) {
$table = $schema->getTable('federated_reshares');
$remoteIdColumn = $table->getColumn('remote_id');
- if ($remoteIdColumn && Type::lookupName($remoteIdColumn->getType()) !== Types::STRING) {
+ if ($remoteIdColumn->getType()->getName() !== Types::STRING) {
$remoteIdColumn->setNotnull(false);
- $remoteIdColumn->setType(Type::getType(Types::STRING));
- $remoteIdColumn->setOptions(['length' => 255]);
+ $remoteIdColumn->setType(Types::STRING);
+ $remoteIdColumn->setLength(255);
$remoteIdColumn->setDefault('');
return $schema;
}
diff --git a/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php b/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php
index 78035d9ccda9c..4800e98eca549 100644
--- a/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php
+++ b/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php
@@ -10,7 +10,6 @@
namespace OCA\Files_Sharing\Migration;
use Closure;
-use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\IDBConnection;
@@ -91,10 +90,10 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
} else {
$table = $schema->getTable('share_external');
$remoteIdColumn = $table->getColumn('remote_id');
- if ($remoteIdColumn && Type::lookupName($remoteIdColumn->getType()) !== Types::STRING) {
+ if ($remoteIdColumn->getType()->getName() !== Types::STRING) {
$remoteIdColumn->setNotnull(false);
- $remoteIdColumn->setType(Type::getType(Types::STRING));
- $remoteIdColumn->setOptions(['length' => 255]);
+ $remoteIdColumn->setType(Types::STRING);
+ $remoteIdColumn->setLength(255);
$remoteIdColumn->setDefault('');
}
if (!$table->hasColumn('parent')) {
diff --git a/apps/settings/lib/SetupChecks/DatabasePendingBigIntConversions.php b/apps/settings/lib/SetupChecks/DatabasePendingBigIntConversions.php
index dc73f2fd3932c..554c6915b2138 100644
--- a/apps/settings/lib/SetupChecks/DatabasePendingBigIntConversions.php
+++ b/apps/settings/lib/SetupChecks/DatabasePendingBigIntConversions.php
@@ -9,10 +9,10 @@
namespace OCA\Settings\SetupChecks;
-use Doctrine\DBAL\Types\BigIntType;
use OC\Core\Command\Db\ConvertFilecacheBigInt;
use OC\DB\Connection;
use OC\DB\SchemaWrapper;
+use OCP\DB\Types;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\IL10N;
@@ -57,7 +57,7 @@ protected function getBigIntConversionPendingColumns(): array {
$column = $table->getColumn($columnName);
$isAutoIncrement = $column->getAutoincrement();
$isAutoIncrementOnSqlite = $isSqlite && $isAutoIncrement;
- if (!($column->getType() instanceof BigIntType) && !$isAutoIncrementOnSqlite) {
+ if ($column->getType()->getName() !== Types::BIGINT && !$isAutoIncrementOnSqlite) {
$pendingColumns[] = $tableName . '.' . $columnName;
}
}
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
index c96263360f6df..a36397625fb06 100644
--- a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
@@ -9,9 +9,8 @@
namespace OCA\TwoFactorBackupCodes\Migration;
-use Doctrine\DBAL\Types\Type;
-use Doctrine\DBAL\Types\Types;
use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
@@ -35,8 +34,8 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op
$column = $table->getColumn('used');
if ($column->getType()->getName() !== Types::SMALLINT) {
- $column->setType(Type::getType(Types::SMALLINT));
- $column->setOptions(['length' => 6]);
+ $column->setType(Types::SMALLINT);
+ $column->setLength(6);
}
return $schema;
diff --git a/apps/workflowengine/lib/Migration/Version2000Date20190808074233.php b/apps/workflowengine/lib/Migration/Version2000Date20190808074233.php
index 1d6c0ae85687b..bf037aa67e682 100644
--- a/apps/workflowengine/lib/Migration/Version2000Date20190808074233.php
+++ b/apps/workflowengine/lib/Migration/Version2000Date20190808074233.php
@@ -10,9 +10,9 @@
namespace OCA\WorkflowEngine\Migration;
use Closure;
-use Doctrine\DBAL\Schema\Table;
use OCA\WorkflowEngine\Entity\File;
use OCP\DB\ISchemaWrapper;
+use OCP\DB\Schema\ITable;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
@@ -118,7 +118,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
return $schema;
}
- protected function ensureEntityColumns(Table $table) {
+ protected function ensureEntityColumns(ITable $table): void {
if (!$table->hasColumn('entity')) {
$table->addColumn('entity', Types::STRING, [
'notnull' => true,
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 8fbfd584765b4..0aac69f0d8ad1 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -2669,11 +2669,6 @@
-
-
-
-
-
diff --git a/core/Command/Db/ConvertFilecacheBigInt.php b/core/Command/Db/ConvertFilecacheBigInt.php
index 5d55cdb314ea8..2547a9f64e0e2 100644
--- a/core/Command/Db/ConvertFilecacheBigInt.php
+++ b/core/Command/Db/ConvertFilecacheBigInt.php
@@ -7,7 +7,6 @@
namespace OC\Core\Command\Db;
-use Doctrine\DBAL\Types\Type;
use OC\DB\Connection;
use OC\DB\SchemaWrapper;
use OCP\DB\Types;
@@ -73,9 +72,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$column = $table->getColumn($columnName);
$isAutoIncrement = $column->getAutoincrement();
$isAutoIncrementOnSqlite = $isSqlite && $isAutoIncrement;
- if (Type::lookupName($column->getType()) !== Types::BIGINT && !$isAutoIncrementOnSqlite) {
- $column->setType(Type::getType(Types::BIGINT));
- $column->setOptions(['length' => 20]);
+ if ($column->getType()->getName() !== Types::BIGINT && !$isAutoIncrementOnSqlite) {
+ $column->setType(Types::BIGINT);
+ $column->setLength(20);
$updates[] = '* ' . $tableName . '.' . $columnName;
}
diff --git a/core/Migrations/Version34000Date20260318095645.php b/core/Migrations/Version34000Date20260318095645.php
index 8be6dfc912277..103cb68eed072 100644
--- a/core/Migrations/Version34000Date20260318095645.php
+++ b/core/Migrations/Version34000Date20260318095645.php
@@ -10,7 +10,6 @@
namespace OC\Core\Migrations;
use Closure;
-use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\Attributes\ColumnType;
@@ -30,8 +29,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
$table = $schema->getTable('jobs');
$argumentColumn = $table->getColumn('argument');
- if ($argumentColumn->getType() !== Type::getType(Types::TEXT)) {
- $argumentColumn->setType(Type::getType(Types::TEXT));
+ if ($argumentColumn->getType()->getName() !== Types::TEXT) {
+ $argumentColumn->setType(Types::TEXT);
return $schema;
}
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 6472ccd5e2050..9ee0b66bdc418 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -369,6 +369,11 @@
'OCP\\DB\\QueryBuilder\\IQueryFunction' => $baseDir . '/lib/public/DB/QueryBuilder/IQueryFunction.php',
'OCP\\DB\\QueryBuilder\\ITypedQueryBuilder' => $baseDir . '/lib/public/DB/QueryBuilder/ITypedQueryBuilder.php',
'OCP\\DB\\QueryBuilder\\Sharded\\IShardMapper' => $baseDir . '/lib/public/DB/QueryBuilder/Sharded/IShardMapper.php',
+ 'OCP\\DB\\Schema\\IColumn' => $baseDir . '/lib/public/DB/Schema/IColumn.php',
+ 'OCP\\DB\\Schema\\IIndex' => $baseDir . '/lib/public/DB/Schema/IIndex.php',
+ 'OCP\\DB\\Schema\\ITable' => $baseDir . '/lib/public/DB/Schema/ITable.php',
+ 'OCP\\DB\\Schema\\IType' => $baseDir . '/lib/public/DB/Schema/IType.php',
+ 'OCP\\DB\\Schema\\SchemaException' => $baseDir . '/lib/public/DB/Schema/SchemaException.php',
'OCP\\DB\\Types' => $baseDir . '/lib/public/DB/Types.php',
'OCP\\Dashboard\\IAPIWidget' => $baseDir . '/lib/public/Dashboard/IAPIWidget.php',
'OCP\\Dashboard\\IAPIWidgetV2' => $baseDir . '/lib/public/Dashboard/IAPIWidgetV2.php',
@@ -1774,6 +1779,10 @@
'OC\\DB\\SQLiteMigrator' => $baseDir . '/lib/private/DB/SQLiteMigrator.php',
'OC\\DB\\SQLiteSessionInit' => $baseDir . '/lib/private/DB/SQLiteSessionInit.php',
'OC\\DB\\SchemaWrapper' => $baseDir . '/lib/private/DB/SchemaWrapper.php',
+ 'OC\\DB\\Schema\\Column' => $baseDir . '/lib/private/DB/Schema/Column.php',
+ 'OC\\DB\\Schema\\Index' => $baseDir . '/lib/private/DB/Schema/Index.php',
+ 'OC\\DB\\Schema\\Table' => $baseDir . '/lib/private/DB/Schema/Table.php',
+ 'OC\\DB\\Schema\\Type' => $baseDir . '/lib/private/DB/Schema/Type.php',
'OC\\DB\\SetTransactionIsolationLevel' => $baseDir . '/lib/private/DB/SetTransactionIsolationLevel.php',
'OC\\Dashboard\\Manager' => $baseDir . '/lib/private/Dashboard/Manager.php',
'OC\\DatabaseException' => $baseDir . '/lib/private/DatabaseException.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index eb51034b2dff1..1b0d9f24271fa 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -410,6 +410,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\DB\\QueryBuilder\\IQueryFunction' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IQueryFunction.php',
'OCP\\DB\\QueryBuilder\\ITypedQueryBuilder' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ITypedQueryBuilder.php',
'OCP\\DB\\QueryBuilder\\Sharded\\IShardMapper' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/Sharded/IShardMapper.php',
+ 'OCP\\DB\\Schema\\IColumn' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IColumn.php',
+ 'OCP\\DB\\Schema\\IIndex' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IIndex.php',
+ 'OCP\\DB\\Schema\\ITable' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/ITable.php',
+ 'OCP\\DB\\Schema\\IType' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IType.php',
+ 'OCP\\DB\\Schema\\SchemaException' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/SchemaException.php',
'OCP\\DB\\Types' => __DIR__ . '/../../..' . '/lib/public/DB/Types.php',
'OCP\\Dashboard\\IAPIWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IAPIWidget.php',
'OCP\\Dashboard\\IAPIWidgetV2' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IAPIWidgetV2.php',
@@ -1815,6 +1820,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\DB\\SQLiteMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/SQLiteMigrator.php',
'OC\\DB\\SQLiteSessionInit' => __DIR__ . '/../../..' . '/lib/private/DB/SQLiteSessionInit.php',
'OC\\DB\\SchemaWrapper' => __DIR__ . '/../../..' . '/lib/private/DB/SchemaWrapper.php',
+ 'OC\\DB\\Schema\\Column' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Column.php',
+ 'OC\\DB\\Schema\\Index' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Index.php',
+ 'OC\\DB\\Schema\\Table' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Table.php',
+ 'OC\\DB\\Schema\\Type' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Type.php',
'OC\\DB\\SetTransactionIsolationLevel' => __DIR__ . '/../../..' . '/lib/private/DB/SetTransactionIsolationLevel.php',
'OC\\Dashboard\\Manager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/Manager.php',
'OC\\DatabaseException' => __DIR__ . '/../../..' . '/lib/private/DatabaseException.php',
diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php
index 12bc7d975ef0d..761fa5398b69e 100644
--- a/lib/private/DB/MigrationService.php
+++ b/lib/private/DB/MigrationService.php
@@ -10,7 +10,6 @@
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Schema;
-use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Sequence;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\Type;
@@ -18,6 +17,7 @@
use OC\Migration\SimpleOutput;
use OCP\App\IAppManager;
use OCP\DB\ISchemaWrapper;
+use OCP\DB\Schema\SchemaException;
use OCP\DB\Types;
use OCP\IConfig;
use OCP\IDBConnection;
@@ -130,7 +130,7 @@ private function createMigrationTable(): bool {
$column = $table->getColumn('version');
$schemaMismatch = $column->getLength() !== 255;
}
- } catch (SchemaException $e) {
+ } catch (SchemaException|\Doctrine\DBAL\Schema\SchemaException) {
// One of the columns is missing
$schemaMismatch = true;
}
@@ -147,7 +147,7 @@ private function createMigrationTable(): bool {
// Recreate the schema wrapper after dropping the table.
$schema = new SchemaWrapper($this->connection);
- } catch (SchemaException $e) {
+ } catch (SchemaException|\Doctrine\DBAL\Schema\SchemaException) {
// The table does not exist; it will be created below.
}
@@ -550,7 +550,7 @@ public function ensureNamingConstraints(Schema $sourceSchema, Schema $targetSche
foreach ($targetSchema->getTables() as $table) {
try {
$sourceTable = $sourceSchema->getTable($table->getName());
- } catch (SchemaException $e) {
+ } catch (\Doctrine\DBAL\Schema\SchemaException $e) {
// we only validate new tables
if (\strlen($table->getName()) + $prefixLength > $MAX_NAME_LENGTH) {
throw new \InvalidArgumentException('Table name "' . $table->getName() . '" exceeds the maximum length of ' . $MAX_NAME_LENGTH);
@@ -643,7 +643,7 @@ public function ensureOracleConstraints(Schema $sourceSchema, Schema $targetSche
foreach ($targetSchema->getTables() as $table) {
try {
$sourceTable = $sourceSchema->getTable($table->getName());
- } catch (SchemaException $e) {
+ } catch (\Doctrine\DBAL\Schema\SchemaException|SchemaException) {
$sourceTable = null;
}
diff --git a/lib/private/DB/Schema/Column.php b/lib/private/DB/Schema/Column.php
new file mode 100644
index 0000000000000..1d9a126240615
--- /dev/null
+++ b/lib/private/DB/Schema/Column.php
@@ -0,0 +1,152 @@
+column;
+ }
+
+ #[\Override]
+ public function setType(string|IType|DBALType $type): self {
+ if ($type instanceof IType) {
+ $type = $type->getName();
+ }
+
+ $this->column->setType($type instanceof DBALType ? $type : DBALType::getType($type));
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setLength(?int $length): self {
+ $this->column->setLength($length);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setPrecision(int $precision): self {
+ $this->column->setPrecision($precision);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setScale(int $scale): self {
+ $this->column->setScale($scale);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setUnsigned(bool $unsigned): self {
+ $this->column->setUnsigned($unsigned);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setFixed(bool $fixed): self {
+ $this->column->setFixed($fixed);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setNotnull(bool $notnull): self {
+ $this->column->setNotnull($notnull);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function setDefault(mixed $default): self {
+ $this->column->setDefault($default);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function getType(): IType {
+ return new Type($this->column->getType());
+ }
+
+ #[\Override]
+ public function getLength(): ?int {
+ return $this->column->getLength();
+ }
+
+ #[\Override]
+ public function getPrecision(): int {
+ return $this->column->getPrecision();
+ }
+
+ #[\Override]
+ public function getScale(): int {
+ return $this->column->getScale();
+ }
+
+ #[\Override]
+ public function getUnsigned(): bool {
+ return $this->column->getUnsigned();
+ }
+
+ #[\Override]
+ public function getFixed(): bool {
+ return $this->column->getFixed();
+ }
+
+ #[\Override]
+ public function getNotnull(): bool {
+ return $this->column->getNotnull();
+ }
+
+ #[\Override]
+ public function getDefault(): mixed {
+ return $this->column->getDefault();
+ }
+
+ #[\Override]
+ public function getAutoincrement(): bool {
+ return $this->column->getAutoincrement();
+ }
+
+ /**
+ * Forwards any method not declared on IColumn to the wrapped Doctrine
+ * DBAL column, e.g. read-only accessors like `getName()` or
+ * `getAutoincrement()` that are not part of the public API.
+ */
+ public function __call(string $name, array $arguments): mixed {
+ try {
+ return $this->column->$name(...$arguments);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+}
diff --git a/lib/private/DB/Schema/Index.php b/lib/private/DB/Schema/Index.php
new file mode 100644
index 0000000000000..dc3ea40328ede
--- /dev/null
+++ b/lib/private/DB/Schema/Index.php
@@ -0,0 +1,64 @@
+index;
+ }
+
+ #[\Override]
+ public function getName(): string {
+ return $this->index->getName();
+ }
+
+ #[\Override]
+ public function getColumns(): array {
+ return array_values($this->index->getColumns());
+ }
+
+ #[\Override]
+ public function isUnique(): bool {
+ return $this->index->isUnique();
+ }
+
+ #[\Override]
+ public function isPrimary(): bool {
+ return $this->index->isPrimary();
+ }
+
+ #[\Override]
+ public function isSimpleIndex(): bool {
+ return $this->index->isSimpleIndex();
+ }
+
+ /**
+ * Forwards any method not declared on IIndex to the wrapped Doctrine
+ * DBAL index, e.g. mutators like `addFlag()` or `removeFlag()` that are
+ * not part of the public API.
+ */
+ public function __call(string $name, array $arguments): mixed {
+ return $this->index->$name(...$arguments);
+ }
+}
diff --git a/lib/private/DB/Schema/Table.php b/lib/private/DB/Schema/Table.php
new file mode 100644
index 0000000000000..25c3c7f6413c7
--- /dev/null
+++ b/lib/private/DB/Schema/Table.php
@@ -0,0 +1,241 @@
+table;
+ }
+
+ #[\Override]
+ public function getName(): string {
+ return $this->table->getName();
+ }
+
+ #[\Override]
+ public function setPrimaryKey(array $columnNames, string|false $indexName = false): self {
+ try {
+ $this->table->setPrimaryKey($columnNames, $indexName);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function addIndex(array $columnNames, ?string $indexName = null, array $flags = [], array $options = []): self {
+ try {
+ $this->table->addIndex($columnNames, $indexName, $flags, $options);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function addUniqueConstraint(
+ array $columnNames,
+ ?string $indexName = null,
+ array $flags = [],
+ array $options = [],
+ ): self {
+ try {
+ $this->table->addUniqueConstraint($columnNames, $indexName, $flags, $options);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function dropPrimaryKey(): self {
+ try {
+ $this->table->dropPrimaryKey();
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function getPrimaryKey(): ?IIndex {
+ $primaryKey = $this->table->getPrimaryKey();
+
+ return $primaryKey !== null ? new Index($primaryKey) : null;
+ }
+
+ #[\Override]
+ public function dropIndex(string $name): self {
+ try {
+ $this->table->dropIndex($name);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function hasIndex(string $name): bool {
+ return $this->table->hasIndex($name);
+ }
+
+ #[\Override]
+ public function addUniqueIndex(array $columnNames, ?string $indexName = null, array $options = []): self {
+ try {
+ $this->table->addUniqueIndex($columnNames, $indexName, $options);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function renameIndex(string $oldName, ?string $newName = null): self {
+ try {
+ $this->table->renameIndex($oldName, $newName);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function addColumn(string $name, string $typeName, array $options = []): IColumn {
+ try {
+ return new Column($this->table->addColumn($name, $typeName, $options));
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ #[\Override]
+ public function modifyColumn(string $name, array $options): self {
+ try {
+ $this->table->modifyColumn($name, $options);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function dropColumn(string $name): self {
+ $this->table->dropColumn($name);
+
+ return $this;
+ }
+
+ #[\Override]
+ public function addForeignKeyConstraint(
+ ITable|string $foreignTable,
+ array $localColumnNames,
+ array $foreignColumnNames,
+ array $options = [],
+ ?string $name = null,
+ ): self {
+ try {
+ $this->table->addForeignKeyConstraint(
+ $foreignTable instanceof self ? $foreignTable->getWrappedTable() : $foreignTable,
+ $localColumnNames,
+ $foreignColumnNames,
+ $options,
+ $name,
+ );
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ #[\Override]
+ public function hasForeignKey(string $name): bool {
+ return $this->table->hasForeignKey($name);
+ }
+
+ #[\Override]
+ public function removeForeignKey(string $name): void {
+ try {
+ $this->table->removeForeignKey($name);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * Forwards any method not declared on ITable to the wrapped Doctrine
+ * DBAL table, e.g. read-only accessors that are not part of the public API.
+ */
+ public function __call(string $name, array $arguments): mixed {
+ try {
+ return $this->table->$name(...$arguments);
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ #[\Override]
+ public function hasColumn(string $string): bool {
+ return $this->table->hasColumn($string);
+ }
+
+ #[\Override]
+ public function getColumn(string $name): IColumn {
+ try {
+ return new Column($this->table->getColumn($name));
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ #[\Override]
+ public function getColumns(): array {
+ return array_values(array_map(
+ static fn (DBALColumn $column): IColumn => new Column($column),
+ $this->table->getColumns(),
+ ));
+ }
+
+ #[\Override]
+ public function getIndexes(): array {
+ return array_values(array_map(
+ static fn (DBALIndex $index): IIndex => new Index($index),
+ $this->table->getIndexes(),
+ ));
+ }
+}
diff --git a/lib/private/DB/Schema/Type.php b/lib/private/DB/Schema/Type.php
new file mode 100644
index 0000000000000..670f9d2ff92e0
--- /dev/null
+++ b/lib/private/DB/Schema/Type.php
@@ -0,0 +1,39 @@
+getType()->getName()` (the Doctrine DBAL API) working, without
+ * committing to the rest of Doctrine's Type API as public API.
+ */
+class Type implements IType {
+ public function __construct(
+ private DBALType $type,
+ ) {
+ }
+
+ /**
+ * Returns the wrapped Doctrine DBAL type.
+ */
+ public function getWrappedType(): DBALType {
+ return $this->type;
+ }
+
+ #[\Override]
+ public function getName(): string {
+ return $this->type->getName();
+ }
+}
diff --git a/lib/private/DB/SchemaWrapper.php b/lib/private/DB/SchemaWrapper.php
index 103bcb25cccaf..429d3e5775ade 100644
--- a/lib/private/DB/SchemaWrapper.php
+++ b/lib/private/DB/SchemaWrapper.php
@@ -1,5 +1,7 @@
schema;
}
@@ -46,14 +53,9 @@ public function performDropTableCalls(): void {
}
}
- /**
- * Gets all table names
- *
- * @return array
- */
#[\Override]
- public function getTableNamesWithoutPrefix() {
- $tableNames = $this->schema->getTableNames();
+ public function getTableNamesWithoutPrefix(): array {
+ $tableNames = $this->getTableNames();
return array_map(function ($tableName) {
if (str_starts_with($tableName, $this->connection->getPrefix())) {
return substr($tableName, strlen($this->connection->getPrefix()));
@@ -65,80 +67,52 @@ public function getTableNamesWithoutPrefix() {
// Overwritten methods
- /**
- * @return array
- */
#[\Override]
- public function getTableNames() {
- return $this->schema->getTableNames();
+ public function getTableNames(): array {
+ return array_values(array_map(fn (DBALTable $table): string => $table->getName(), $this->schema->getTables()));
}
- /**
- * @param string $tableName
- *
- * @return \Doctrine\DBAL\Schema\Table
- * @throws \Doctrine\DBAL\Schema\SchemaException
- */
#[\Override]
- public function getTable($tableName) {
- return $this->schema->getTable($this->connection->getPrefix() . $tableName);
+ public function getTable(string $tableName): ITable {
+ try {
+ return new Table($this->schema->getTable($this->connection->getPrefix() . $tableName));
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
}
/**
* Does this schema have a table with the given name?
- *
- * @param string $tableName
- *
- * @return boolean
*/
#[\Override]
- public function hasTable($tableName) {
+ public function hasTable(string $tableName): bool {
return $this->schema->hasTable($this->connection->getPrefix() . $tableName);
}
- /**
- * Creates a new table.
- *
- * @param string $tableName
- * @return \Doctrine\DBAL\Schema\Table
- */
#[\Override]
- public function createTable($tableName) {
+ public function createTable(string $tableName): ITable {
unset($this->tablesToDelete[$tableName]);
- return $this->schema->createTable($this->connection->getPrefix() . $tableName);
+ try {
+ return new Table($this->schema->createTable($this->connection->getPrefix() . $tableName));
+ } catch (DBALSchemaException $e) {
+ throw new SchemaException($e->getMessage(), $e->getCode(), $e);
+ }
}
- /**
- * Drops a table from the schema.
- *
- * @param string $tableName
- * @return \Doctrine\DBAL\Schema\Schema
- */
#[\Override]
- public function dropTable($tableName) {
+ public function dropTable(string $tableName): self {
$this->tablesToDelete[$tableName] = true;
- return $this->schema->dropTable($this->connection->getPrefix() . $tableName);
+ $this->schema->dropTable($this->connection->getPrefix() . $tableName);
+ return $this;
}
- /**
- * Gets all tables of this schema.
- *
- * @return \Doctrine\DBAL\Schema\Table[]
- */
#[\Override]
- public function getTables() {
- return $this->schema->getTables();
+ public function getTables(): array {
+ return array_values(array_map(fn (DBALTable $table): ITable => new Table($table), $this->schema->getTables()));
}
- /**
- * Gets the DatabasePlatform for the database.
- *
- * @return AbstractPlatform
- *
- * @throws Exception
- */
#[\Override]
- public function getDatabasePlatform() {
+ public function getDatabasePlatform(): AbstractPlatform {
return $this->connection->getDatabasePlatform();
}
diff --git a/lib/private/Repair/Owncloud/MigratePropertiesTable.php b/lib/private/Repair/Owncloud/MigratePropertiesTable.php
index 09fe5fddb8905..c172db9c7ac5a 100644
--- a/lib/private/Repair/Owncloud/MigratePropertiesTable.php
+++ b/lib/private/Repair/Owncloud/MigratePropertiesTable.php
@@ -9,10 +9,9 @@
namespace OC\Repair\Owncloud;
-use Doctrine\DBAL\Types\StringType;
-use Doctrine\DBAL\Types\Type;
use OC\DB\Connection;
use OC\DB\SchemaWrapper;
+use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
@@ -39,8 +38,8 @@ public function run(IOutput $output): void {
$output->info('Update the oc_properties table schema.');
$table = $schema->getTable('oc_properties');
$column = $table->getColumn('propertyvalue');
- if ($column->getType() instanceof StringType) {
- $column->setType(Type::getType('text'));
+ if ($column->getType()->getName() === Types::STRING) {
+ $column->setType(Types::TEXT);
$column->setLength(null);
}
diff --git a/lib/public/DB/ISchemaWrapper.php b/lib/public/DB/ISchemaWrapper.php
index faefa988e4d68..cc94f1035b34d 100644
--- a/lib/public/DB/ISchemaWrapper.php
+++ b/lib/public/DB/ISchemaWrapper.php
@@ -9,6 +9,8 @@
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\AbstractPlatform;
+use OCP\AppFramework\Attribute\Consumable;
+use OCP\DB\Schema\ITable;
/**
* This interface allows to get information about the database schema.
@@ -20,67 +22,62 @@
*
* @since 13.0.0
*/
+#[Consumable(since: '13.0.0')]
interface ISchemaWrapper {
/**
- * @param string $tableName
- *
- * @return \Doctrine\DBAL\Schema\Table
- * @throws \Doctrine\DBAL\Schema\SchemaException
+ * @throws Schema\SchemaException
* @since 13.0.0
*/
- public function getTable($tableName);
+ public function getTable(string $tableName): ITable;
/**
* Does this schema have a table with the given name?
*
* @param string $tableName Prefix is automatically prepended
*
- * @return boolean
* @since 13.0.0
*/
- public function hasTable($tableName);
+ public function hasTable(string $tableName): bool;
/**
* Creates a new table.
*
* @param string $tableName Prefix is automatically prepended
- * @return \Doctrine\DBAL\Schema\Table
* @since 13.0.0
*/
- public function createTable($tableName);
+ public function createTable(string $tableName): ITable;
/**
* Drops a table from the schema.
*
* @param string $tableName Prefix is automatically prepended
- * @return \Doctrine\DBAL\Schema\Schema
* @since 13.0.0
*/
- public function dropTable($tableName);
+ public function dropTable(string $tableName): self;
/**
* Gets all tables of this schema.
*
- * @return \Doctrine\DBAL\Schema\Table[]
+ * @return list
* @since 13.0.0
*/
- public function getTables();
+ public function getTables(): array;
/**
* Gets all table names, prefixed with table prefix
*
- * @return array
+ * @return list
* @since 13.0.0
*/
- public function getTableNames();
+ public function getTableNames(): array;
/**
* Gets all table names
*
- * @return array
+ * @return list
* @since 13.0.0
*/
- public function getTableNamesWithoutPrefix();
+ public function getTableNamesWithoutPrefix(): array;
/**
* Gets the DatabasePlatform for the database.
@@ -90,7 +87,7 @@ public function getTableNamesWithoutPrefix();
* @throws Exception
* @since 23.0.0
*/
- public function getDatabasePlatform();
+ public function getDatabasePlatform(): AbstractPlatform;
/**
* Drop autoincrement from an existing table of the database.
diff --git a/lib/public/DB/Schema/IColumn.php b/lib/public/DB/Schema/IColumn.php
new file mode 100644
index 0000000000000..b9d284fd0c59a
--- /dev/null
+++ b/lib/public/DB/Schema/IColumn.php
@@ -0,0 +1,119 @@
+
+ * @since 35.0.0
+ */
+ public function getColumns(): array;
+
+ /**
+ * Returns whether this index is a unique index.
+ *
+ * @since 35.0.0
+ */
+ public function isUnique(): bool;
+
+ /**
+ * Returns whether this index is the primary key.
+ *
+ * @since 35.0.0
+ */
+ public function isPrimary(): bool;
+
+ /**
+ * Returns whether this index is neither unique nor the primary key.
+ *
+ * @since 35.0.0
+ */
+ public function isSimpleIndex(): bool;
+}
diff --git a/lib/public/DB/Schema/ITable.php b/lib/public/DB/Schema/ITable.php
new file mode 100644
index 0000000000000..d388129058644
--- /dev/null
+++ b/lib/public/DB/Schema/ITable.php
@@ -0,0 +1,229 @@
+ $columnNames
+ * @param string|false $indexName
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function setPrimaryKey(array $columnNames, string|false $indexName = false): self;
+
+ /**
+ * @param list $columnNames
+ * @param list $flags
+ * @param array $options
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function addIndex(array $columnNames, ?string $indexName = null, array $flags = [], array $options = []): self;
+
+ /**
+ * @param list $columnNames
+ * @param list $flags
+ * @param array $options
+ * @since 35.0.0
+ */
+ public function addUniqueConstraint(
+ array $columnNames,
+ ?string $indexName = null,
+ array $flags = [],
+ array $options = [],
+ ): self;
+
+ /**
+ * Drops the primary key from this table.
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function dropPrimaryKey(): self;
+
+ /**
+ * Returns the primary key, or null if this table has no primary key.
+ *
+ * @since 35.0.0
+ */
+ public function getPrimaryKey(): ?IIndex;
+
+ /**
+ * Drops an index from this table.
+ *
+ * @param string $name The index name.
+ *
+ * @throws SchemaException If the index does not exist.
+ * @since 35.0.0
+ */
+ public function dropIndex(string $name): self;
+
+ /**
+ * Returns whether this table has an index with the given name.
+ *
+ * @param string $name The index name.
+ * @since 35.0.0
+ */
+ public function hasIndex(string $name): bool;
+
+ /**
+ * @param list $columnNames
+ * @param string|null $indexName
+ * @param array $options
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function addUniqueIndex(array $columnNames, ?string $indexName = null, array $options = []): self;
+
+ /**
+ * Renames an index.
+ *
+ * @param string $oldName The name of the index to rename from.
+ * @param string|null $newName The name of the index to rename to.
+ * If null is given, the index name will be auto-generated.
+ *
+ * @return self This table instance.
+ *
+ * @throws SchemaException If no index exists for the given current name
+ * or if an index with the given new name already exists on this table.
+ * @since 35.0.0
+ */
+ public function renameIndex(string $oldName, ?string $newName = null): self;
+
+ /**
+ * @param string $name
+ * @param string $typeName
+ * @param array{
+ * notnull?: bool,
+ * length?: ?int,
+ * default?: ?scalar,
+ * unsigned?: bool,
+ * autoincrement?: bool,
+ * fixed?: bool,
+ * } $options
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function addColumn(string $name, string $typeName, array $options = []): IColumn;
+
+ /**
+ * @param string $name
+ * @param array{
+ * notnull?: bool,
+ * length?: ?int,
+ * default?: ?scalar,
+ * unsigned?: bool,
+ * autoincrement?: bool,
+ * fixed?: bool,
+ * } $options
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function modifyColumn(string $name, array $options): self;
+
+ /**
+ * Drops a Column from the Table.
+ * @since 35.0.0
+ */
+ public function dropColumn(string $name): self;
+
+ /**
+ * Returns whether this table has a Column with the given name.
+ *
+ * @param string $name The column name.
+ * @since 35.0.0
+ */
+ public function hasColumn(string $string): bool;
+
+ /**
+ * Returns the Column with the given name.
+ *
+ * @param string $name The column name.
+ *
+ * @throws SchemaException If the column does not exist.
+ * @since 35.0.0
+ */
+ public function getColumn(string $name): IColumn;
+
+ /**
+ * Returns all columns of this table.
+ *
+ * @return list
+ * @since 35.0.0
+ */
+ public function getColumns(): array;
+
+ /**
+ * Returns all indexes of this table.
+ *
+ * @return list
+ * @since 35.0.0
+ */
+ public function getIndexes(): array;
+
+ /**
+ * Adds a foreign key constraint.
+ *
+ * Name is inferred from the local columns.
+ *
+ * @param ITable|string $foreignTable Table schema instance or table name
+ * @param list $localColumnNames
+ * @param list $foreignColumnNames
+ * @param array $options
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function addForeignKeyConstraint(
+ ITable|string $foreignTable,
+ array $localColumnNames,
+ array $foreignColumnNames,
+ array $options = [],
+ ?string $name = null,
+ ): self;
+
+ /**
+ * Returns whether this table has a foreign key constraint with the given name.
+ * @since 35.0.0
+ */
+ public function hasForeignKey(string $name): bool;
+
+ /**
+ * Removes the foreign key constraint with the given name.
+ *
+ * @param string $name The constraint name.
+ *
+ * @throws SchemaException
+ * @since 35.0.0
+ */
+ public function removeForeignKey(string $name): void;
+}
diff --git a/lib/public/DB/Schema/IType.php b/lib/public/DB/Schema/IType.php
new file mode 100644
index 0000000000000..241ee9c4465e6
--- /dev/null
+++ b/lib/public/DB/Schema/IType.php
@@ -0,0 +1,24 @@
+getColumn($columnName);
- if (Type::lookupName($column->getType()) !== Types::BIGINT) {
- $column->setType(Type::getType(Types::BIGINT));
- $column->setOptions(['length' => 20]);
+ if ($column->getType()->getName() !== Types::BIGINT) {
+ $column->setType(Types::BIGINT);
+ $column->setLength(20);
}
}
}