-
Notifications
You must be signed in to change notification settings - Fork 11.4k
[9.x] Fix "artisan db:wipe" command does not drop tables in all schemas #41541
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
Conversation
@cbj4074 remember that draft PR's aren't reviewed. |
I'm not entirely certain whether the same types of changes that I made to framework/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php Lines 327 to 330 in 82f3ccf
Types in PostgreSQL can definitely be qualified at the schema level, but I'm not sure if this method needs to be modified to behave in its intended way. @richards-square , would you mind taking a peek at this, if you're available (since you wrote it)? Much appreciated! |
@@ -67,7 +67,7 @@ public function dropAllTables() | |||
foreach ($this->getAllTables() as $row) { | |||
$row = (array) $row; | |||
|
|||
$table = reset($row); | |||
$table = '"'.$row['schemaname'].'"."'.$row['tablename'].'"'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a 9.x breaking change for the $excludedTables
check on line 72. Existing apps with values in config('database.pgsql.dont_drop')
won't be schema-qualified with wrapping quotes. Even the hardcoded $excludedTables = ['spatial_ref_sys']
default value used by 99.9% of Laravel/Postgres apps will fail to be skipped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! Thank you! This is exactly why I said the following in the related Issue:
As is the case with all things search_path-related, the fix is likely to be nuanced and will have to be vetted carefully so as not to break anything else, as not all of the affected code has test coverage (particularly the older code).
I'll work on a solution to this. Thanks again!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whenever it's convenient, please take a look at the new commit that I pushed. My hope is that it resolves the concern that you raise here.
Now, tables are excluded in a backwards-compatible way, so that all of the following table notations would be excluded:
'dont_drop' => [
'users',
'"password_resets"',
'public.failed_jobs',
'"public"."personal_access_tokens"',
'spatial_ref_sys'
],
This configuration produces the following DROP
query in a stock Laravel installation in which php artisan migrate
has been run (and migrations
is the only table we didn't exclude):
"drop table "public"."migrations" cascade"
So, in essence, the user can schema-qualify those dont_drop
references if desired, and if not, the unqualified references will be treated just as they have been prior to this PR. That is to say, when a reference is unqualified, the table will not be dropped from any schema in which it exists.
As a related aside, the the current logic around the spatial_ref_sys
table that exists when the postgis
extension is enabled seems a little odd to me.
In essence, the logic is, "If the user has not specified tables to be excluded, then exclude spatial_ref_sys
, else, exclude the specified tables (in which case spatial_ref_sys
will be dropped)."
Is that necessarily the desired behavior? It seems all too easy to drop spatial_ref_sys
without even realizing it's happening, merely by specifying some other, completely unrelated table(s) to be excluded. I suppose once the user realizes what's happening, they'll add spatial_ref_sys
to the dont_drop
array, too.
The same is true of the dropAllViews()
method. It'll drop the two views that are created for postgis
(geography_columns
and geometry_columns
):
laravel=# CREATE EXTENSION postgis;
CREATE EXTENSION
laravel=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------------+-------+----------
public | geography_columns | view | postgres
public | geometry_columns | view | postgres
public | spatial_ref_sys | table | postgres
(3 rows)
I don't know if any of this is of concern to anybody, I just figured I'd mention it while on the subject.
Regarding my earlier comment, I do in fact believe that this query is currently broken/problematic, too, because it returns rows for user-created types that exist in all schemas to which the effective user has access, even schemas that are not within the effective CREATE TYPE "foobar"."foo" AS ENUM ('bar', 'bat', 'baz'); and then running
Upon cursory analysis, the fix for this might simply be to modify the laravel=# select distinct pg_type.typname, nspname from pg_type inner join pg_enum on pg_enum.enumtypid = pg_type.oid inner join pg_namespace on pg_type.typnamespace = pg_namespace.oid;
typname | nspname
------------+---------
foo | foobar
(1 row) Now, we can qualify the types fully in the This change alone doesn't address the fact that the where nspname in ('".implode("','", (array) $searchPath)."') to framework/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php Lines 327 to 330 in 89e43ae
I'm open to any thoughts on any of this, of course. |
@driesvints This can be closed now that #41701 has been merged. @cbj4074: The |
Thanks all! |
@derekmd Thanks for taking the torch and running with it here. I haven't had much time to dedicate to this over the past week, so I appreciate your help. As you noted above, we should still try to "close the loop" on a handful of remaining issues, which, in my estimation, are as follows:
I'll try to work-up some tests that prove these various issues, and, ideally, submit another PR that seeks to address them, provided you (and anybody else who has input) don't see any holes in my logic. Thanks again! |
#41483 describes a flaw that manifests in the Artisan
db:wipe
command, whereby the tables are not deleted from all schemas.The problem is not so much with the
db:wipe
command itself, but rather, how the underlying library acquires the names of the tables to be deleted.This PR seeks to fix the underlying problem in a backwards-compatible way, and adds a
escapeObjectReferences()
method that offloads the table escaping (quoting) that is applied to schema-qualified and non-schema-qualified table object references to a dedicated method (instead of repeating the sameimplode()
code all over the place).