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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39d7f662c156d9cd897af698c86f2af772c5918dcfd4126d833d08294da7b840
4
- data.tar.gz: 79c08139a1e9bd7cb90858cba0a28cd0f442770165f6fd54488d9ae8ab49546a
3
+ metadata.gz: b4e2f7c1a407de6ba1787a074b477f15c2d52844db280ab3b46a7ea0ff53307d
4
+ data.tar.gz: eb16c182003ff444a9dcb0c50bdeb01b0d0c64d030e3a604cea97b4391eb9749
5
5
  SHA512:
6
- metadata.gz: 7b3967012a3af6a90252a1c2d480d70aa9b7af6cd8824f73972b3d5efc0f1badf93cc43635c1b155201d1398279ffb40728c937df9f5f1544981e6ddcc6e1086
7
- data.tar.gz: 0a0b8dafc3fb66166e09a208bfae07cc60251ddb8b6a6482ddb9eeb37355c176bfb019d02ebe546da211d33d8e64c77c63c03582c96b343d4408f82003472dc6
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.add_if_not_exists_to_create_table(stdout)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Exwiw
4
- VERSION = "0.9.16"
4
+ VERSION = "0.9.17"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exwiw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.16
4
+ version: 0.9.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia