Skip to content

Commit

Permalink
Fixes for v4.6.4 (#1665)
Browse files Browse the repository at this point in the history
* avoid error during php artisan optimize
* add transaction on change
* fixes migration problem on pgsql
  • Loading branch information
ildyria authored Dec 26, 2022
1 parent 6a61bc6 commit 2dcc23e
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 7 deletions.
28 changes: 25 additions & 3 deletions app/Actions/Diagnostics/Pipes/Checks/ForeignKeyListInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function handle(array &$data, \Closure $next): array
match (DB::getDriverName()) {
'sqlite' => $this->sqlite($data),
'mysql' => $this->mysql($data),
'pgsql' => '',
'pgsql' => $this->pgsql($data),
default => ''
};

Expand All @@ -35,8 +35,7 @@ private function sqlite(array &$data): void

private function mysql(array &$data): void
{
$fks = DB::select('select
*
$fks = DB::select('select *
from information_schema.referential_constraints fks
join information_schema.key_column_usage kcu on fks.constraint_schema = kcu.table_schema
and fks.table_name = kcu.table_name
Expand All @@ -52,5 +51,28 @@ private function mysql(array &$data): void
$fk->UPDATE_RULE);
}
}

private function pgsql(array &$data): void
{
$fks = DB::select('SELECT tc.table_schema, tc.constraint_name, tc.table_name, kcu.column_name,
ccu.table_schema AS foreign_table_schema,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = \'FOREIGN KEY\';');

foreach ($fks as $fk) {
$data[] = sprintf('Foreign key: %-30s → %-20s',
$fk->table_name . '.' . $fk->column_name,
$fk->foreign_table_name . '.' . $fk->foreign_column_name);
}
}
}

21 changes: 20 additions & 1 deletion app/Actions/Diagnostics/Pipes/Infos/CountForeignKeyInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function handle(array &$data, \Closure $next): array
match (DB::getDriverName()) {
'sqlite' => $this->sqlite($data),
'mysql' => $this->mysql($data),
'pgsql' => '',
'pgsql' => $this->pgsql($data),
default => ''
};

Expand All @@ -39,5 +39,24 @@ private function mysql(array &$data): void

$data[] = Diagnostics::line('Number of foreign key:', sprintf('%d found.', count($fks)));
}

private function pgsql(array &$data): void
{
$fks = DB::select('SELECT tc.table_schema, tc.constraint_name, tc.table_name, kcu.column_name,
ccu.table_schema AS foreign_table_schema,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = \'FOREIGN KEY\';');

$data[] = Diagnostics::line('Number of foreign key:', sprintf('%d found.', count($fks)));
}
}

34 changes: 33 additions & 1 deletion database/migrations/2022_12_10_183251_increment_user_i_ds.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
public function up(): void
{
Schema::disableForeignKeyConstraints();
DB::beginTransaction();

// In the case of pgsql we mark the following foreign keys to be defered after the commit transaction
// rather than after every requests
if (DB::getDriverName() === 'pgsql') {
$this->defer('base_albums', 'base_albums_owner_id_foreign');
$this->defer('user_base_album', 'user_base_album_user_id_foreign');
$this->defer('photos', 'photos_owner_id_foreign');
}

/** @var App\Models\User|null $admin */
$admin = DB::table('users')->find(0);
if ($admin !== null && ($admin->username === '' || $admin->password === '')) {
Expand All @@ -22,6 +32,7 @@ public function up(): void
// MigrateAdminUser migration and the user has never logged in.
DB::table('users')->where('id', '=', 0)->delete();
}

/** @var App\Models\User $user */
foreach (DB::table('users')->orderByDesc('id')->get() as $user) {
$oldID = $user->id;
Expand All @@ -34,13 +45,15 @@ public function up(): void
DB::table('webauthn_credentials')->where('authenticatable_id', '=', $oldID)->update(['authenticatable_id' => $newID]);
DB::table('users')->delete($oldID);
}
if (Schema::connection(null)->getConnection()->getDriverName() === 'pgsql' && DB::table('users')->count() > 0) {

if (DB::getDriverName() === 'pgsql' && DB::table('users')->count() > 0) {
// when using PostgreSQL, the new IDs are not updated after incrementing. Thus, we need to reset the index to the greatest ID + 1
// the sequence is called `users_id_seq1`
/** @var App\Models\User $lastUser */
$lastUser = DB::table('users')->orderByDesc('id')->first();
DB::statement('ALTER SEQUENCE users_id_seq1 RESTART WITH ' . strval($lastUser->id + 1));
}
DB::commit();
Schema::enableForeignKeyConstraints();
}

Expand All @@ -52,6 +65,16 @@ public function up(): void
public function down(): void
{
Schema::disableForeignKeyConstraints();
DB::beginTransaction();

// In the case of pgsql we mark the following foreign keys to be defered after the commit transaction
// rather than after every requests
if (DB::getDriverName() === 'pgsql') {
$this->defer('base_albums', 'base_albums_owner_id_foreign');
$this->defer('user_base_album', 'user_base_album_user_id_foreign');
$this->defer('photos', 'photos_owner_id_foreign');
}

/** @var App\Models\User $user */
foreach (User::query()->orderBy('id')->get() as $user) {
$oldID = $user->id;
Expand All @@ -66,6 +89,15 @@ public function down(): void
DB::table('webauthn_credentials')->where('authenticatable_id', '=', $oldID)->update(['authenticatable_id' => $newID]);
DB::table('users')->delete($oldID);
}
DB::commit();
Schema::enableForeignKeyConstraints();
}

/**
* Defer a foreign key evalation to the end of a transaction in pgsql.
*/
private function defer(string $tableName, string $fkName): void
{
DB::select('ALTER TABLE ' . $tableName . ' ALTER CONSTRAINT ' . $fkName . ' DEFERRABLE INITIALLY DEFERRED;');
}
};
3 changes: 1 addition & 2 deletions routes/web-install.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,4 @@
->name('install-admin');
Route::get('install/admin', [SetUpAdminController::class, 'init'])
->withoutMiddleware(['installation:incomplete'])
->middleware(['admin_user:unset', 'installation:complete'])
->name('install-admin');
->middleware(['admin_user:unset', 'installation:complete']);

0 comments on commit 2dcc23e

Please sign in to comment.