-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[12.x] Enhance multi-database support #54274
[12.x] Enhance multi-database support #54274
Conversation
Thanks for submitting a PR! Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface. Pull requests that are abandoned in draft may be closed due to inactivity. |
Will this result in something different than setting the connection property/method? |
@NickSdot I hope the updated PR description makes things clearer. |
@hafezdivandari Thanks! Can you send a PR to laravel/docs master branch to document the breaking changes and any other updates we need to make? |
@taylorotwell sure. |
@hafezdivandari thanks for this! How will it affect applications using mulitple databases via seperate and/or dynamic/ephemaral connections, such as multitenant database setups which switch databases at runtime? Also, would this support extending with a closure to set |
@inmanturbo Good question. The main difference lies in how you set up your DB connections, the database driver you're using, and what you aim to achieve. This PR focuses on utilizing multi-schema with a single connection! As I mentioned in the PR description, "database" and "schema" are essentially the same in MySQL and SQLite, but they differ in PostgreSQL and SQL Server.
Are you referring to Eloquent models? In that case, you can override the class Post extends Model
{
// ...
public function getTable()
{
$schema = $this->schema ?? 'my_schema'; // Determine the schema dynamically!
return "$schema.posts";
}
} |
@hafezdivandari Thank you for the helpful reply! Your example for models is helpful in demostrating the utility afforded by this PR |
This PR improves support for multi-database aka schemas (using a single connection) setups. Laravel's Eloquent, Query Builder, and most Schema Builder functions already support references in the
schema_name.table_name
format. Since all supported databases allow multi-schema functionality, this PR ensures consistent usage across all databases and adds full support for it in all Schema Builder methods.Improvements
$schema
argument toSchema::getTables()
,Schema::getViews()
,Schema::getTypes()
, andSchema::getTableListing()
methods.$schema = null
, returning all tables / views / types of all schemas.$schema
asstring
orarray
will return the result for the given schemas only.Schema::hasTable()
,Schema::hasView()
,Schema::getColumns()
,Schema::getIndexes()
,Schema::getForeignKeys()
,Schema::hasColumn()
,Schema::getColumnListing()
, andSchema::hasIndex()
methods utilizing MySQL, MariaDB, and SQLite, fallback to the current schema if not specified explicitly on the table name.schema_qualified_name
property to the returned results ofSchema::getTables()
,Schema::getViews()
,Schema::getTypes()
methods.$schemaQualified
argument toSchema::getTableListing()
method:$schemaQualified = true
, returning the table names asschema_name.table_name
format.schemaQualified = false
value results in not schema-qualified table names.Schema::getSchemas()
method for all DB drivers to get schemas for the connection with these properties:name
(string
): Name of the schema.path
(?string
): Schema file path (SQLite only)default
(bool
): The schema is the default one.Schema::getCurrentSchemaName()
method. This method has been used by the framework internally to determine the name of the current schema for the connection:search_path
config property (same asselect current_schema()
).select schema()
).'main'
.select schema_name()
query.Schema::getCurrentSchemaListing()
method that returns names of schemas currently in-use for the connection. This method has been used by the framework internally, e.g. when dropping / truncating all tables are needed:search_path
config property (same asselect current_schemas()
).['main']
null
, means all schemas.schema
property on returned result ofSchema::getTables()
andSchema::getViews()
on MySQL, MariaDB and SQLite (was alwaysnull
previously).foreign_schema
property on returned result ofSchema::getForeignKeys()
on SQLite (was alwaysnull
previously).DB::withoutTablePrefix()
method to return the result of the given callback.DB::table('schema_name.table_name')->truncate()
db:show
,db:table
commands,Schema\Builder
andSchema\Grammar
classes, removing redundant codes (without any BC change).Behavioral Changes
DB::withoutTablePrefix($callback)
method now returns the result of the given callback instead ofvoid
.Schema::getTables()
,Schema::getViews()
andSchema::getTableListing()
methods:$schema
argument to filter the result as desired.Schema::getTableListing()
method now returns schema-qualified table names by default. Acceptingbool $schemaQualified
argument to change the behavior as desired.db:table
anddb:show
command now outputs results of all schemas on MySQL, MariaDB and SQLite, just like PostgreSQL and SQL Server. Consistent usage across all DB drivers.Context
Being able to categorize your database tables is useful, and this is already possible with all databases supported by Laravel. This means you can manage multiple databases with a single MySQL connection! For example, let’s assume you have this connection:
This
mysql
connection usesprimary_db
as the default "schema," which you already know how to use. But what if you want to interact with multiple MySQL databases? Laravel has you covered:The same example works in MariaDB, PostgreSQL, SQL Server, and even SQLite (with a small change when creating the schema). You can use
schema_name.table_name
references almost everywhere, regardless of the database driver. However, each database driver handles "schemas" differently, so it's important to abstract these differences to ensure consistent usage at the application layer.Let's compare databases:
MariaDB
"def"
(Engine has 1 Catalog)
(Catalog has many databases)
CREATE DATABASE sch_name
or
CREATE SCHEMA sch_name
(Schema has many tables)
CREATE sch_name.tbl_name
(Many database files attached as Schemas)
ATTACH db_file AS sch_name
(Schema has many tables)
CREATE sch_name.tbl_name
(Engine has many databases)
CREATE DATABASE db_name
(Catalog has many Schemas)
CREATE SCHEMA sch_name
(Schema has many tables)
CREATE sch_name.tbl_name
(Engine has many databases)
CREATE DATABASE db_name
(Catalog has many Schemas)
CREATE SCHEMA sch_name
(Schema has many tables)
CREATE db_name.sch_name.tbl_name
This means:
schema_name.table_name
reference.SCHEMA
as a synonym forDATABASE
(ref). MySQL connects with adatabase
config property as the default schema / database and can switches between schemas / databases viaUSE schema_name
):memory:
) as schemas (ref). SQLite connects to a database file as the default schema named"main"
.USE db_name
). It connects to adatabase
config property as the default database and first schema name on thesearch_path
config property as the default schema.database
config propertyas the default database, and "dbo" as the default schema. Unlike PostgreSQL, it's possible to switch between databases via
USE db_name
and change the default schema (refer to [11.x] Use Default Schema Name on SQL Server #50855 for more). That's why sqlsrv has three-part referencesdb_name.schema_name.table_name
, but Laravel doesn't fully / officially supports three-part references for tables.Let's compare "Current Schema" for each DB driver connection:
MariaDB
'laravel'
SELECT schema()
SELECT database()
'main'
'public'
search_path
SELECT current_schema()
'dbo'
ALTER USER
SELECT schema_name()