Skip to content

Commit 1ee9520

Browse files
committed
fix: "artisan db:wipe" command does not drop tables in all schemas
Fixes #41483
1 parent 0256484 commit 1ee9520

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
272272
*/
273273
public function compileDropAllTables($tables)
274274
{
275-
return 'drop table "'.implode('","', $tables).'" cascade';
275+
return 'drop table '.implode(',', $this->escapeObjectReferences($tables)).' cascade';
276276
}
277277

278278
/**
@@ -283,7 +283,7 @@ public function compileDropAllTables($tables)
283283
*/
284284
public function compileDropAllViews($views)
285285
{
286-
return 'drop view "'.implode('","', $views).'" cascade';
286+
return 'drop view '.implode(',', $this->escapeObjectReferences($views)).' cascade';
287287
}
288288

289289
/**
@@ -294,7 +294,7 @@ public function compileDropAllViews($views)
294294
*/
295295
public function compileDropAllTypes($types)
296296
{
297-
return 'drop type "'.implode('","', $types).'" cascade';
297+
return 'drop type '.implode(',', $this->escapeObjectReferences($types)).' cascade';
298298
}
299299

300300
/**
@@ -305,7 +305,7 @@ public function compileDropAllTypes($types)
305305
*/
306306
public function compileGetAllTables($searchPath)
307307
{
308-
return "select tablename from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $searchPath)."')";
308+
return "select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $searchPath)."')";
309309
}
310310

311311
/**
@@ -316,7 +316,7 @@ public function compileGetAllTables($searchPath)
316316
*/
317317
public function compileGetAllViews($searchPath)
318318
{
319-
return "select viewname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $searchPath)."')";
319+
return "select viewname, schemaname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $searchPath)."')";
320320
}
321321

322322
/**
@@ -1070,4 +1070,31 @@ protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)
10701070
return " generated always as ({$column->storedAs}) stored";
10711071
}
10721072
}
1073+
1074+
/**
1075+
* Escape database object references consitently, schema-qualified or not.
1076+
*
1077+
* @param array $objects
1078+
* @return array
1079+
*/
1080+
public function escapeObjectReferences(array $objects): array
1081+
{
1082+
$escapedObjects = [];
1083+
1084+
foreach ($objects as $object) {
1085+
$parts = explode('.', $object);
1086+
1087+
$newParts = [];
1088+
1089+
array_walk($parts, function (&$part) use (&$newParts) {
1090+
$part = str_replace(['"', "'"], '', $part);
1091+
1092+
$newParts[] = $part;
1093+
});
1094+
1095+
$escapedObjects[] = '"'.implode('"."', $parts).'"';
1096+
}
1097+
1098+
return $escapedObjects;
1099+
}
10731100
}

src/Illuminate/Database/Schema/PostgresBuilder.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ public function dropAllTables()
6464

6565
$excludedTables = $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys'];
6666

67+
$excludedTables = $this->grammar->escapeObjectReferences($excludedTables);
68+
6769
foreach ($this->getAllTables() as $row) {
6870
$row = (array) $row;
6971

70-
$table = reset($row);
72+
$table = '"'.$row['schemaname'].'"."'.$row['tablename'].'"';
7173

72-
if (! in_array($table, $excludedTables)) {
74+
if (! in_array('"'.$row['tablename'].'"', $excludedTables) && ! in_array($table, $excludedTables)) {
7375
$tables[] = $table;
7476
}
7577
}
@@ -95,7 +97,7 @@ public function dropAllViews()
9597
foreach ($this->getAllViews() as $row) {
9698
$row = (array) $row;
9799

98-
$views[] = reset($row);
100+
$views[] = '"'.$row['schemaname'].'"."'.$row['viewname'].'"';
99101
}
100102

101103
if (empty($views)) {

tests/Database/DatabasePostgresBuilderTest.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,11 @@ public function testDropAllTablesWhenSearchPathIsString()
238238
$connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']);
239239
$grammar = m::mock(PostgresGrammar::class);
240240
$connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar);
241-
$grammar->shouldReceive('compileGetAllTables')->with(['public'])->andReturn("select tablename from pg_catalog.pg_tables where schemaname in ('public')");
242-
$connection->shouldReceive('select')->with("select tablename from pg_catalog.pg_tables where schemaname in ('public')")->andReturn(['users']);
243-
$grammar->shouldReceive('compileDropAllTables')->with(['users'])->andReturn('drop table "'.implode('","', ['users']).'" cascade');
244-
$connection->shouldReceive('statement')->with('drop table "'.implode('","', ['users']).'" cascade');
241+
$grammar->shouldReceive('compileGetAllTables')->with(['public'])->andReturn("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('public')");
242+
$connection->shouldReceive('select')->with("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('public')")->andReturn([['schemaname' => 'public', 'tablename' => 'users']]);
243+
$grammar->shouldReceive('escapeObjectReferences')->with(['foo'])->andReturn(['"foo"']);
244+
$grammar->shouldReceive('compileDropAllTables')->with(['"public"."users"'])->andReturn('drop table "public"."users" cascade');
245+
$connection->shouldReceive('statement')->with('drop table "public"."users" cascade');
245246
$builder = $this->getBuilder($connection);
246247

247248
$builder->dropAllTables();
@@ -255,10 +256,11 @@ public function testDropAllTablesWhenSearchPathIsStringOfMany()
255256
$connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']);
256257
$grammar = m::mock(PostgresGrammar::class);
257258
$connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar);
258-
$grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'public', 'foo_bar-Baz.Áüõß'])->andReturn("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')");
259-
$connection->shouldReceive('select')->with("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')")->andReturn(['users', 'users']);
260-
$grammar->shouldReceive('compileDropAllTables')->with(['users', 'users'])->andReturn('drop table "'.implode('","', ['users', 'users']).'" cascade');
261-
$connection->shouldReceive('statement')->with('drop table "'.implode('","', ['users', 'users']).'" cascade');
259+
$grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'public', 'foo_bar-Baz.Áüõß'])->andReturn("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')");
260+
$connection->shouldReceive('select')->with("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')")->andReturn([['schemaname' => 'users', 'tablename' => 'users']]);
261+
$grammar->shouldReceive('escapeObjectReferences')->with(['foo'])->andReturn(['"foo"']);
262+
$grammar->shouldReceive('compileDropAllTables')->with(['"users"."users"'])->andReturn('drop table "users"."users" cascade');
263+
$connection->shouldReceive('statement')->with('drop table "users"."users" cascade');
262264
$builder = $this->getBuilder($connection);
263265

264266
$builder->dropAllTables();
@@ -277,10 +279,11 @@ public function testDropAllTablesWhenSearchPathIsArrayOfMany()
277279
$connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']);
278280
$grammar = m::mock(PostgresGrammar::class);
279281
$connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar);
280-
$grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'dev', 'test', 'spaced schema'])->andReturn("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')");
281-
$connection->shouldReceive('select')->with("select tablename from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')")->andReturn(['users', 'users']);
282-
$grammar->shouldReceive('compileDropAllTables')->with(['users', 'users'])->andReturn('drop table "'.implode('","', ['users', 'users']).'" cascade');
283-
$connection->shouldReceive('statement')->with('drop table "'.implode('","', ['users', 'users']).'" cascade');
282+
$grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'dev', 'test', 'spaced schema'])->andReturn("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')");
283+
$connection->shouldReceive('select')->with("select tablename, schemaname from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')")->andReturn([['schemaname' => 'users', 'tablename' => 'users']]);
284+
$grammar->shouldReceive('escapeObjectReferences')->with(['foo'])->andReturn(['"foo"']);
285+
$grammar->shouldReceive('compileDropAllTables')->with(['"users"."users"'])->andReturn('drop table "users"."users" cascade');
286+
$connection->shouldReceive('statement')->with('drop table "users"."users" cascade');
284287
$builder = $this->getBuilder($connection);
285288

286289
$builder->dropAllTables();

0 commit comments

Comments
 (0)