diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 9f5dbaa5f0e0..472f8ab33171 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -144,8 +144,7 @@ public function hasTable($table) { $table = $this->connection->getTablePrefix().$table; - /** @phpstan-ignore arguments.count (SQLite accepts a withSize argument) */ - foreach ($this->getTables(false) as $value) { + foreach ($this->getTables() as $value) { if (strtolower($table) === strtolower($value['name'])) { return true; } diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 70812633a749..667a06ebe9f4 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -76,6 +76,23 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine if the given table exists. + * + * @param string $database + * @param string $table + * @return string + */ + public function compileTableExists($database, $table) + { + return sprintf( + 'select exists (select 1 from information_schema.tables where ' + ."table_schema = %s and table_name = %s and table_type in ('BASE TABLE', 'SYSTEM VERSIONED')) as `exists`", + $this->quoteString($database), + $this->quoteString($table) + ); + } + /** * Compile the query to determine the tables. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index a3ff8e8fc27a..85b57df62f50 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -68,6 +68,23 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine if the given table exists. + * + * @param string $schema + * @param string $table + * @return string + */ + public function compileTableExists($schema, $table) + { + return sprintf( + 'select exists (select 1 from pg_class c, pg_namespace n where ' + ."n.nspname = %s and c.relname = %s and c.relkind in ('r', 'p') and n.oid = c.relnamespace)", + $this->quoteString($schema), + $this->quoteString($table) + ); + } + /** * Compile the query to determine the tables. * diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 19689ab6526e..8bd92e0c6ede 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -68,6 +68,20 @@ public function compileDbstatExists() return "select exists (select 1 from pragma_compile_options where compile_options = 'ENABLE_DBSTAT_VTAB') as enabled"; } + /** + * Compile the query to determine if the given table exists. + * + * @param string $table + * @return string + */ + public function compileTableExists($table) + { + return sprintf( + 'select exists (select 1 from sqlite_master where name = %s and type = \'table\') as "exists"', + $this->quoteString(str_replace('.', '__', $table)) + ); + } + /** * Compile the query to determine the tables. * diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index fe8121b4f4fc..81258f2e1036 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -76,6 +76,21 @@ public function compileDropDatabaseIfExists($name) ); } + /** + * Compile the query to determine if the given table exists. + * + * @param string|null $schema + * @param string $table + * @return string + */ + public function compileTableExists($schema, $table) + { + return sprintf( + 'select (case when object_id(%s, \'U\') is null then 0 else 1 end) as [exists]', + $this->quoteString($schema ? $schema.'.'.$table : $table) + ); + } + /** * Compile the query to determine the tables. * diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index 943ae9f4fadf..842130503595 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -30,6 +30,23 @@ public function dropDatabaseIfExists($name) ); } + /** + * Determine if the given table exists. + * + * @param string $table + * @return bool + */ + public function hasTable($table) + { + $table = $this->connection->getTablePrefix().$table; + + $database = $this->connection->getDatabaseName(); + + return (bool) $this->connection->scalar( + $this->grammar->compileTableExists($database, $table) + ); + } + /** * Get the tables for the database. * diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index c8d7cd4c8b4e..7bb13a687a90 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -49,14 +49,9 @@ public function hasTable($table) $table = $this->connection->getTablePrefix().$table; - foreach ($this->getTables() as $value) { - if (strtolower($table) === strtolower($value['name']) - && strtolower($schema) === strtolower($value['schema'])) { - return true; - } - } - - return false; + return (bool) $this->connection->scalar( + $this->grammar->compileTableExists($schema, $table) + ); } /** diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 5295584ea12f..fb352bf0dd04 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -31,6 +31,21 @@ public function dropDatabaseIfExists($name) : true; } + /** + * Determine if the given table exists. + * + * @param string $table + * @return bool + */ + public function hasTable($table) + { + $table = $this->connection->getTablePrefix().$table; + + return (bool) $this->connection->scalar( + $this->grammar->compileTableExists($table) + ); + } + /** * Get the tables for the database. * diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index 2833b5098aba..9b59ccc0ebd3 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -42,17 +42,11 @@ public function hasTable($table) { [$schema, $table] = $this->parseSchemaAndTable($table); - $schema ??= $this->getDefaultSchema(); $table = $this->connection->getTablePrefix().$table; - foreach ($this->getTables() as $value) { - if (strtolower($table) === strtolower($value['name']) - && strtolower($schema) === strtolower($value['schema'])) { - return true; - } - } - - return false; + return (bool) $this->connection->scalar( + $this->grammar->compileTableExists($schema, $table) + ); } /** diff --git a/tests/Database/DatabaseMariaDbSchemaBuilderTest.php b/tests/Database/DatabaseMariaDbSchemaBuilderTest.php index a49345a6c14b..d8d7a64c17cc 100755 --- a/tests/Database/DatabaseMariaDbSchemaBuilderTest.php +++ b/tests/Database/DatabaseMariaDbSchemaBuilderTest.php @@ -20,15 +20,12 @@ public function testHasTable() { $connection = m::mock(Connection::class); $grammar = m::mock(MariaDbGrammar::class); - $processor = m::mock(MariaDbProcessor::class); $connection->shouldReceive('getDatabaseName')->andReturn('db'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); $builder = new MariaDbBuilder($connection); - $grammar->shouldReceive('compileTables')->once()->andReturn('sql'); - $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'prefix_table']]); + $grammar->shouldReceive('compileTableExists')->once()->andReturn('sql'); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); - $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql')->andReturn([['name' => 'prefix_table']]); + $connection->shouldReceive('scalar')->once()->with('sql')->andReturn(1); $this->assertTrue($builder->hasTable('table')); } diff --git a/tests/Database/DatabaseMySQLSchemaBuilderTest.php b/tests/Database/DatabaseMySQLSchemaBuilderTest.php index 53869e6d5604..c5fa3ea273f2 100755 --- a/tests/Database/DatabaseMySQLSchemaBuilderTest.php +++ b/tests/Database/DatabaseMySQLSchemaBuilderTest.php @@ -20,15 +20,12 @@ public function testHasTable() { $connection = m::mock(Connection::class); $grammar = m::mock(MySqlGrammar::class); - $processor = m::mock(MySqlProcessor::class); $connection->shouldReceive('getDatabaseName')->andReturn('db'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); $builder = new MySqlBuilder($connection); - $grammar->shouldReceive('compileTables')->once()->andReturn('sql'); - $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'prefix_table']]); + $grammar->shouldReceive('compileTableExists')->once()->andReturn('sql'); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); - $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql')->andReturn([['name' => 'prefix_table']]); + $connection->shouldReceive('scalar')->once()->with('sql')->andReturn(1); $this->assertTrue($builder->hasTable('table')); } diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index d3a280239d3a..a7c60e6c7267 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -52,14 +52,11 @@ public function testHasTableWhenSchemaUnqualifiedAndSearchPathMissing() $connection->shouldReceive('getConfig')->with('search_path')->andReturn(null); $connection->shouldReceive('getConfig')->with('schema')->andReturn(null); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['schema' => 'public', 'name' => 'foo']]); + $grammar->shouldReceive('compileTableExists')->andReturn('sql'); + $connection->shouldReceive('scalar')->with('sql')->andReturn(1); $connection->shouldReceive('getTablePrefix'); $builder = $this->getBuilder($connection); - $processor->shouldReceive('processTables')->andReturn([['schema' => 'public', 'name' => 'foo']]); $this->assertTrue($builder->hasTable('foo')); $this->assertTrue($builder->hasTable('public.foo')); @@ -70,14 +67,11 @@ public function testHasTableWhenSchemaUnqualifiedAndSearchPathFilled() $connection = $this->getConnection(); $connection->shouldReceive('getConfig')->with('search_path')->andReturn('myapp,public'); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); + $grammar->shouldReceive('compileTableExists')->andReturn('sql'); + $connection->shouldReceive('scalar')->with('sql')->andReturn(1); $connection->shouldReceive('getTablePrefix'); $builder = $this->getBuilder($connection); - $processor->shouldReceive('processTables')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); $this->assertTrue($builder->hasTable('foo')); $this->assertTrue($builder->hasTable('myapp.foo')); @@ -89,14 +83,11 @@ public function testHasTableWhenSchemaUnqualifiedAndSearchPathFallbackFilled() $connection->shouldReceive('getConfig')->with('search_path')->andReturn(null); $connection->shouldReceive('getConfig')->with('schema')->andReturn(['myapp', 'public']); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); + $grammar->shouldReceive('compileTableExists')->andReturn('sql'); + $connection->shouldReceive('scalar')->with('sql')->andReturn(1); $connection->shouldReceive('getTablePrefix'); $builder = $this->getBuilder($connection); - $processor->shouldReceive('processTables')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); $this->assertTrue($builder->hasTable('foo')); $this->assertTrue($builder->hasTable('myapp.foo')); @@ -108,14 +99,11 @@ public function testHasTableWhenSchemaUnqualifiedAndSearchPathIsUserVariable() $connection->shouldReceive('getConfig')->with('username')->andReturn('foouser'); $connection->shouldReceive('getConfig')->with('search_path')->andReturn('$user'); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['schema' => 'foouser', 'name' => 'foo']]); + $grammar->shouldReceive('compileTableExists')->andReturn('sql'); + $connection->shouldReceive('scalar')->with('sql')->andReturn(1); $connection->shouldReceive('getTablePrefix'); $builder = $this->getBuilder($connection); - $processor->shouldReceive('processTables')->andReturn([['schema' => 'foouser', 'name' => 'foo']]); $this->assertTrue($builder->hasTable('foo')); $this->assertTrue($builder->hasTable('foouser.foo')); @@ -126,14 +114,11 @@ public function testHasTableWhenSchemaQualifiedAndSearchPathMismatches() $connection = $this->getConnection(); $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); - $grammar->shouldReceive('compileTables')->andReturn('sql'); - $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); + $grammar->shouldReceive('compileTableExists')->andReturn('sql'); + $connection->shouldReceive('scalar')->with('sql')->andReturn(1); $connection->shouldReceive('getTablePrefix'); $builder = $this->getBuilder($connection); - $processor->shouldReceive('processTables')->andReturn([['schema' => 'myapp', 'name' => 'foo']]); $this->assertTrue($builder->hasTable('myapp.foo')); } diff --git a/tests/Database/DatabasePostgresSchemaBuilderTest.php b/tests/Database/DatabasePostgresSchemaBuilderTest.php index 5794ce44aeea..c38c7d183614 100755 --- a/tests/Database/DatabasePostgresSchemaBuilderTest.php +++ b/tests/Database/DatabasePostgresSchemaBuilderTest.php @@ -20,16 +20,13 @@ public function testHasTable() { $connection = m::mock(Connection::class); $grammar = m::mock(PostgresGrammar::class); - $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); - $connection->shouldReceive('getPostProcessor')->andReturn($processor); $connection->shouldReceive('getConfig')->with('schema')->andReturn('schema'); $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); $builder = new PostgresBuilder($connection); - $grammar->shouldReceive('compileTables')->twice()->andReturn('sql'); - $processor->shouldReceive('processTables')->twice()->andReturn([['schema' => 'public', 'name' => 'prefix_table']]); + $grammar->shouldReceive('compileTableExists')->twice()->andReturn('sql'); $connection->shouldReceive('getTablePrefix')->twice()->andReturn('prefix_'); - $connection->shouldReceive('selectFromWriteConnection')->twice()->with('sql')->andReturn([['schema' => 'public', 'name' => 'prefix_table']]); + $connection->shouldReceive('scalar')->twice()->with('sql')->andReturn(1); $this->assertTrue($builder->hasTable('table')); $this->assertTrue($builder->hasTable('public.table'));