exwiw 0.9.16 → 0.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/lib/exwiw/adapter/mysql_adapter.rb +2 -1
- data/lib/exwiw/ddl_postprocessor.rb +38 -0
- data/lib/exwiw/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4e2f7c1a407de6ba1787a074b477f15c2d52844db280ab3b46a7ea0ff53307d
|
|
4
|
+
data.tar.gz: eb16c182003ff444a9dcb0c50bdeb01b0d0c64d030e3a604cea97b4391eb9749
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05b71a92ba8a702f8651812bf38b1eef09c65ff4d39c020e571ad8b9f999ffc6ee003dbd16db933355337fc4e497092f3a0272c885ebc401300b353a83bdf412
|
|
7
|
+
data.tar.gz: 26fcf8c9aa7047ca99a2a89d259be9c894ea3d8a072f0fe2fd5e3387a24e4206a3187f7a4bb921b0482669804997d1138db7239f9a80e10de5f8b1b8116b3cd1
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.17] - 2026-08-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **mysql: `insert-000-schema.sql` no longer carries the source server's `DEFINER=` clauses, so a restore into MySQL 8.2+ / 8.4 succeeds without the `SET_ANY_DEFINER` privilege.** `mysqldump` stamps every view and trigger with the account that owns it on the source (e.g. `/*!50013 DEFINER=user@host SQL SECURITY DEFINER */`). From MySQL 8.2, creating a stored object owned by another account needs `SET_ANY_DEFINER` — a privilege managed MySQL (RDS / Cloud SQL) does not grant — so the restore aborted, and a definer account absent on the target left an orphan object that broke later `CREATE USER` / `DROP USER`. A new `DdlPostprocessor.strip_definer_clauses` pass removes the clause (only from the version-gated comment `mysqldump` wraps it in, so a literal `DEFINER=` inside a trigger body or column `COMMENT` is untouched), so each object is created owned by the restoring account — MySQL's default when the clause is omitted. `SQL SECURITY DEFINER` / `INVOKER` is preserved as written; postgresql/sqlite are unaffected. Output for a database with no views or triggers is byte-identical. Note: a schema containing views or triggers is still not *re*-appliable (`--skip-add-drop-table` suppresses the `DROP` that would make it so) — tracked separately.
|
|
10
|
+
|
|
5
11
|
## [0.9.16] - 2026-07-31
|
|
6
12
|
|
|
7
13
|
### Fixed
|
data/README.md
CHANGED
|
@@ -106,7 +106,7 @@ The output dir is emptied before each export so it never mixes files from a prev
|
|
|
106
106
|
idx means the order of the dump. bigger idx might depend on smaller idx,
|
|
107
107
|
so you should import the dump in order.
|
|
108
108
|
|
|
109
|
-
`insert-000-schema.sql` is generated by shelling out to the database client tools (`mysqldump` for `mysql`, `pg_dump` for `postgresql`, and the sqlite3 driver for `sqlite`), so the corresponding client must be available on PATH when running exwiw. For `mysql`, set `EXWIW_MYSQLDUMP` to point at a specific `mysqldump` binary when the one on PATH is incompatible with the server (e.g. a MySQL 9.x `mysqldump` cannot load `mysql_native_password` against a server still using that auth plugin — `EXWIW_MYSQLDUMP=/path/to/mysql@8.0/bin/mysqldump`). The output is post-processed to make it idempotent: `CREATE TABLE IF NOT EXISTS`, `CREATE INDEX IF NOT EXISTS` (where the engine supports it), and PostgreSQL's `ALTER TABLE ... ADD CONSTRAINT` statements are wrapped in `DO $$ ... EXCEPTION WHEN duplicate_object`.
|
|
109
|
+
`insert-000-schema.sql` is generated by shelling out to the database client tools (`mysqldump` for `mysql`, `pg_dump` for `postgresql`, and the sqlite3 driver for `sqlite`), so the corresponding client must be available on PATH when running exwiw. For `mysql`, set `EXWIW_MYSQLDUMP` to point at a specific `mysqldump` binary when the one on PATH is incompatible with the server (e.g. a MySQL 9.x `mysqldump` cannot load `mysql_native_password` against a server still using that auth plugin — `EXWIW_MYSQLDUMP=/path/to/mysql@8.0/bin/mysqldump`). The output is post-processed to make it idempotent: `CREATE TABLE IF NOT EXISTS`, `CREATE INDEX IF NOT EXISTS` (where the engine supports it), and PostgreSQL's `ALTER TABLE ... ADD CONSTRAINT` statements are wrapped in `DO $$ ... EXCEPTION WHEN duplicate_object`. For `mysql`, the source server's `DEFINER=user@host` stamp on views and triggers is stripped too, so restoring into a managed MySQL instance (which usually can't grant the privilege to recreate someone else's `DEFINER`) does not fail.
|
|
110
110
|
|
|
111
111
|
you need to delete the records before importing the dump,
|
|
112
112
|
`delete-{idx}-{table_name}.sql` will help you to do that.
|
|
@@ -136,7 +136,8 @@ module Exwiw
|
|
|
136
136
|
raise "mysqldump failed (exit #{status.exitstatus}): #{stderr}"
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
-
idempotent = DdlPostprocessor.
|
|
139
|
+
idempotent = DdlPostprocessor.strip_definer_clauses(stdout)
|
|
140
|
+
idempotent = DdlPostprocessor.add_if_not_exists_to_create_table(idempotent)
|
|
140
141
|
|
|
141
142
|
File.open(output_path, 'w') do |file|
|
|
142
143
|
file.puts("-- Auto-generated by exwiw via mysqldump. Idempotent CREATE TABLE statements for mysql.")
|
|
@@ -64,6 +64,44 @@ module Exwiw
|
|
|
64
64
|
sql.gsub(/^[ \t]*CREATE\s+(?:OR\s+REPLACE\s+)?(?:CONSTRAINT\s+)?TRIGGER\b[^;]*;\r?\n?/i, "")
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# A user@host pair as mysqldump writes it. Each side is independently a
|
|
68
|
+
# backtick-quoted identifier (doubled backticks escape), a single- or
|
|
69
|
+
# double-quoted string, or a bare word (`root@localhost`). A definer may
|
|
70
|
+
# also be CURRENT_USER / CURRENT_USER(), which has no @host.
|
|
71
|
+
DEFINER_ACCOUNT_PART =
|
|
72
|
+
/(?:`(?:[^`]|``)*`|'(?:[^']|'')*'|"(?:[^"]|"")*"|[A-Za-z0-9_$.%\-]+)/.freeze
|
|
73
|
+
|
|
74
|
+
DEFINER_CLAUSE =
|
|
75
|
+
/DEFINER[ \t]*=[ \t]*
|
|
76
|
+
(?:CURRENT_USER(?:[ \t]*\([ \t]*\))?
|
|
77
|
+
|#{DEFINER_ACCOUNT_PART}(?:@#{DEFINER_ACCOUNT_PART})?)/xi.freeze
|
|
78
|
+
|
|
79
|
+
# mysqldump wraps every view/trigger/routine/event DEFINER in a versioned
|
|
80
|
+
# comment, e.g. `/*!50013 DEFINER=`u`@`h` SQL SECURITY DEFINER */` or the
|
|
81
|
+
# trigger form `/*!50017 DEFINER=`u`@`h`*/`. From MySQL 8.2, creating a
|
|
82
|
+
# stored object owned by another account needs SET_ANY_DEFINER, which
|
|
83
|
+
# managed MySQL (RDS / Cloud SQL) does not grant, and a nonexistent
|
|
84
|
+
# definer leaves an orphan object that later breaks CREATE USER / DROP
|
|
85
|
+
# USER. Omitting the clause defaults the definer to CURRENT_USER (the
|
|
86
|
+
# restoring account), sidestepping both.
|
|
87
|
+
#
|
|
88
|
+
# Anchoring on the versioned comment, rather than gsubbing DEFINER=
|
|
89
|
+
# anywhere, keeps this from touching a literal "DEFINER=" inside a
|
|
90
|
+
# trigger body string or a column COMMENT. SQL SECURITY DEFINER|INVOKER
|
|
91
|
+
# is preserved — it governs runtime privileges, not who the definer is.
|
|
92
|
+
DEFINER_COMMENT_RE =
|
|
93
|
+
%r{/\*!(?<ver>\d{5})[ \t]+#{DEFINER_CLAUSE}[ \t]*
|
|
94
|
+
(?<rest>(?:(?!\*/).)*?)[ \t]*\*/(?<trail>[ \t]*)}xi.freeze
|
|
95
|
+
|
|
96
|
+
def strip_definer_clauses(sql)
|
|
97
|
+
sql.gsub(DEFINER_COMMENT_RE) do
|
|
98
|
+
m = Regexp.last_match
|
|
99
|
+
# Drop the comment whole if DEFINER was its only content (trigger
|
|
100
|
+
# form); otherwise keep the surviving content (e.g. SQL SECURITY).
|
|
101
|
+
m[:rest].empty? ? "" : "/*!#{m[:ver]} #{m[:rest]} */#{m[:trail]}"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
67
105
|
# A bare `CREATE TYPE ... AS ENUM (...)` (as a full-database pg_dump emits,
|
|
68
106
|
# unlike a `--table` dump, which omits enum types) is not idempotent: a
|
|
69
107
|
# second restore raises `duplicate_object`. Wrap each in a DO block that
|
data/lib/exwiw/version.rb
CHANGED