Skip to content

Commit 86c3dff

Browse files
[12.x] Enhance multi-database support (#54274)
* enhance multi-schema support * formatting * formatting * formatting * formatting * formatting * formatting * Update SchemaBuilderSchemaNameTest.php * formatting * formatting --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 9633ac5 commit 86c3dff

38 files changed

+1061
-747
lines changed

src/Illuminate/Database/Connection.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,17 +1650,19 @@ public function withTablePrefix(Grammar $grammar)
16501650
* Execute the given callback without table prefix.
16511651
*
16521652
* @param \Closure $callback
1653-
* @return void
1653+
* @return mixed
16541654
*/
1655-
public function withoutTablePrefix(Closure $callback): void
1655+
public function withoutTablePrefix(Closure $callback): mixed
16561656
{
16571657
$tablePrefix = $this->getTablePrefix();
16581658

16591659
$this->setTablePrefix('');
16601660

1661-
$callback($this);
1662-
1663-
$this->setTablePrefix($tablePrefix);
1661+
try {
1662+
return $callback($this);
1663+
} finally {
1664+
$this->setTablePrefix($tablePrefix);
1665+
}
16641666
}
16651667

16661668
/**

src/Illuminate/Database/Console/DatabaseInspectionCommand.php

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,4 @@ protected function getConfigFromDatabase($database)
4747

4848
return Arr::except(config('database.connections.'.$database), ['password']);
4949
}
50-
51-
/**
52-
* Remove the table prefix from a table name, if it exists.
53-
*
54-
* @param \Illuminate\Database\ConnectionInterface $connection
55-
* @param string $table
56-
* @return string
57-
*/
58-
protected function withoutTablePrefix(ConnectionInterface $connection, string $table)
59-
{
60-
$prefix = $connection->getTablePrefix();
61-
62-
return str_starts_with($table, $prefix)
63-
? substr($table, strlen($prefix))
64-
: $table;
65-
}
6650
}

src/Illuminate/Database/Console/ShowCommand.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Illuminate\Support\Arr;
99
use Illuminate\Support\Collection;
1010
use Illuminate\Support\Number;
11-
use Illuminate\Support\Stringable;
1211
use Symfony\Component\Console\Attribute\AsCommand;
1312

1413
#[AsCommand(name: 'db:show')]
@@ -80,9 +79,10 @@ protected function tables(ConnectionInterface $connection, Builder $schema)
8079
return (new Collection($schema->getTables()))->map(fn ($table) => [
8180
'table' => $table['name'],
8281
'schema' => $table['schema'],
82+
'schema_qualified_name' => $table['schema_qualified_name'],
8383
'size' => $table['size'],
8484
'rows' => $this->option('counts')
85-
? ($connection->table($table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name'])->count())
85+
? $connection->withoutTablePrefix(fn ($connection) => $connection->table($table['schema_qualified_name'])->count())
8686
: null,
8787
'engine' => $table['engine'],
8888
'collation' => $table['collation'],
@@ -100,11 +100,10 @@ protected function tables(ConnectionInterface $connection, Builder $schema)
100100
protected function views(ConnectionInterface $connection, Builder $schema)
101101
{
102102
return (new Collection($schema->getViews()))
103-
->reject(fn ($view) => (new Stringable($view['name']))->startsWith(['pg_catalog', 'information_schema', 'spt_']))
104103
->map(fn ($view) => [
105104
'view' => $view['name'],
106105
'schema' => $view['schema'],
107-
'rows' => $connection->table($view['schema'] ? $view['schema'].'.'.$view['name'] : $view['name'])->count(),
106+
'rows' => $connection->withoutTablePrefix(fn ($connection) => $connection->table($view['schema_qualified_name'])->count()),
108107
]);
109108
}
110109

src/Illuminate/Database/Console/TableCommand.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ class TableCommand extends DatabaseInspectionCommand
3939
public function handle(ConnectionResolverInterface $connections)
4040
{
4141
$connection = $connections->connection($this->input->getOption('database'));
42-
$schema = $connection->getSchemaBuilder();
43-
$tables = (new Collection($schema->getTables()))
44-
->keyBy(fn ($table) => $table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name'])
45-
->all();
42+
$tables = (new Collection($connection->getSchemaBuilder()->getTables()))
43+
->keyBy('schema_qualified_name')->all();
4644

4745
$tableName = $this->argument('table') ?: select(
4846
'Which table would you like to inspect?',
@@ -57,16 +55,22 @@ public function handle(ConnectionResolverInterface $connections)
5755
return 1;
5856
}
5957

60-
$tableName = ($table['schema'] ? $table['schema'].'.' : '').$this->withoutTablePrefix($connection, $table['name']);
58+
[$columns, $indexes, $foreignKeys] = $connection->withoutTablePrefix(function ($connection) use ($table) {
59+
$schema = $connection->getSchemaBuilder();
60+
$tableName = $table['schema_qualified_name'];
6161

62-
$columns = $this->columns($schema, $tableName);
63-
$indexes = $this->indexes($schema, $tableName);
64-
$foreignKeys = $this->foreignKeys($schema, $tableName);
62+
return [
63+
$this->columns($schema, $tableName),
64+
$this->indexes($schema, $tableName),
65+
$this->foreignKeys($schema, $tableName),
66+
];
67+
});
6568

6669
$data = [
6770
'table' => [
6871
'schema' => $table['schema'],
6972
'name' => $table['name'],
73+
'schema_qualified_name' => $table['schema_qualified_name'],
7074
'columns' => count($columns),
7175
'size' => $table['size'],
7276
'comment' => $table['comment'],
@@ -205,7 +209,7 @@ protected function displayForCli(array $data)
205209

206210
$this->newLine();
207211

208-
$this->components->twoColumnDetail('<fg=green;options=bold>'.($table['schema'] ? $table['schema'].'.'.$table['name'] : $table['name']).'</>', $table['comment'] ? '<fg=gray>'.$table['comment'].'</>' : null);
212+
$this->components->twoColumnDetail('<fg=green;options=bold>'.$table['schema_qualified_name'].'</>', $table['comment'] ? '<fg=gray>'.$table['comment'].'</>' : null);
209213
$this->components->twoColumnDetail('Columns', $table['columns']);
210214

211215
if (! is_null($table['size'])) {

src/Illuminate/Database/Grammar.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ public function wrapArray(array $values)
4040
* Wrap a table in keyword identifiers.
4141
*
4242
* @param \Illuminate\Contracts\Database\Query\Expression|string $table
43+
* @param string|null $prefix
4344
* @return string
4445
*/
45-
public function wrapTable($table)
46+
public function wrapTable($table, $prefix = null)
4647
{
4748
if ($this->isExpression($table)) {
4849
return $this->getValue($table);
@@ -55,18 +56,20 @@ public function wrapTable($table)
5556
return $this->wrapAliasedTable($table);
5657
}
5758

59+
$prefix ??= $this->tablePrefix;
60+
5861
// If the table being wrapped has a custom schema name specified, we need to
5962
// prefix the last segment as the table name then wrap each segment alone
6063
// and eventually join them both back together using the dot connector.
6164
if (str_contains($table, '.')) {
62-
$table = substr_replace($table, '.'.$this->tablePrefix, strrpos($table, '.'), 1);
65+
$table = substr_replace($table, '.'.$prefix, strrpos($table, '.'), 1);
6366

6467
return (new Collection(explode('.', $table)))
6568
->map($this->wrapValue(...))
6669
->implode('.');
6770
}
6871

69-
return $this->wrapValue($this->tablePrefix.$table);
72+
return $this->wrapValue($prefix.$table);
7073
}
7174

7275
/**

src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,12 @@ protected function compileDeleteWithJoinsOrLimit(Builder $query)
439439
*/
440440
public function compileTruncate(Builder $query)
441441
{
442+
[$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($query->from);
443+
444+
$schema = $schema ? $this->wrapValue($schema).'.' : '';
445+
442446
return [
443-
'delete from sqlite_sequence where name = ?' => [$this->getTablePrefix().$query->from],
447+
'delete from '.$schema.'sqlite_sequence where name = ?' => [$this->getTablePrefix().$table],
444448
'delete from '.$this->wrapTable($query->from) => [],
445449
];
446450
}

src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,13 @@ protected function wrapJsonBooleanValue($value)
557557
* Wrap a table in keyword identifiers.
558558
*
559559
* @param \Illuminate\Contracts\Database\Query\Expression|string $table
560+
* @param string|null $prefix
560561
* @return string
561562
*/
562-
public function wrapTable($table)
563+
public function wrapTable($table, $prefix = null)
563564
{
564565
if (! $this->isExpression($table)) {
565-
return $this->wrapTableValuedFunction(parent::wrapTable($table));
566+
return $this->wrapTableValuedFunction(parent::wrapTable($table, $prefix));
566567
}
567568

568569
return $this->getValue($table);

src/Illuminate/Database/Query/Processors/PostgresProcessor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function processTypes($results)
4444
return [
4545
'name' => $result->name,
4646
'schema' => $result->schema,
47+
'schema_qualified_name' => $result->schema.'.'.$result->name,
4748
'implicit' => (bool) $result->implicit,
4849
'type' => match (strtolower($result->type)) {
4950
'b' => 'base',

src/Illuminate/Database/Query/Processors/Processor.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu
3636
return is_numeric($id) ? (int) $id : $id;
3737
}
3838

39+
/**
40+
* Process the results of a schemas query.
41+
*
42+
* @param array $results
43+
* @return array
44+
*/
45+
public function processSchemas($results)
46+
{
47+
return array_map(function ($result) {
48+
$result = (object) $result;
49+
50+
return [
51+
'name' => $result->name,
52+
'path' => $result->path ?? null, // SQLite Only...
53+
'default' => (bool) $result->default,
54+
];
55+
}, $results);
56+
}
57+
3958
/**
4059
* Process the results of a tables query.
4160
*
@@ -49,7 +68,8 @@ public function processTables($results)
4968

5069
return [
5170
'name' => $result->name,
52-
'schema' => $result->schema ?? null, // PostgreSQL and SQL Server
71+
'schema' => $result->schema ?? null,
72+
'schema_qualified_name' => isset($result->schema) ? $result->schema.'.'.$result->name : $result->name,
5373
'size' => isset($result->size) ? (int) $result->size : null,
5474
'comment' => $result->comment ?? null, // MySQL and PostgreSQL
5575
'collation' => $result->collation ?? null, // MySQL only
@@ -71,7 +91,8 @@ public function processViews($results)
7191

7292
return [
7393
'name' => $result->name,
74-
'schema' => $result->schema ?? null, // PostgreSQL and SQL Server
94+
'schema' => $result->schema ?? null,
95+
'schema_qualified_name' => isset($result->schema) ? $result->schema.'.'.$result->name : $result->name,
7596
'definition' => $result->definition,
7697
];
7798
}, $results);

src/Illuminate/Database/Query/Processors/SQLiteProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public function processForeignKeys($results)
104104
return [
105105
'name' => null,
106106
'columns' => explode(',', $result->columns),
107-
'foreign_schema' => null,
107+
'foreign_schema' => $result->foreign_schema,
108108
'foreign_table' => $result->foreign_table,
109109
'foreign_columns' => explode(',', $result->foreign_columns),
110110
'on_update' => strtolower($result->on_update),

0 commit comments

Comments
 (0)