From 7a03011625993a601f0c6eac242caf93aaada2bb Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:22:04 -0700 Subject: [PATCH] fix(sql): expand string escape to handle NUL, CR/LF/tab, Ctrl-Z The previous escape only doubled quotes and backslashes. A quest description containing a literal newline would emit a multi-line INSERT that breaks per-line execution scripts; a NUL byte could prematurely terminate the string in non-length-prefixed clients; Ctrl-Z is the historical MySQL string terminator on Windows. Now full MySQL/MariaDB string-literal escape: NUL drops, CR/LF/tab become \r/\n/\t, Ctrl-Z becomes \Z. --- tools/editor/sql_exporter.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tools/editor/sql_exporter.cpp b/tools/editor/sql_exporter.cpp index d9d254e4..c9e62046 100644 --- a/tools/editor/sql_exporter.cpp +++ b/tools/editor/sql_exporter.cpp @@ -14,9 +14,22 @@ std::string SQLExporter::escape(const std::string& s) { std::string out; out.reserve(s.size()); for (char c : s) { - if (c == '\'') out += "''"; - else if (c == '\\') out += "\\\\"; - else out += c; + // MySQL/MariaDB string-literal escape rules. The backslash sequences + // are the canonical way; doubled single quote works inside single- + // quoted strings either way (matches AzerothCore's import scripts). + // Stripping NUL prevents premature string termination in clients + // that don't fully respect length-prefixed strings; \r/\n keep + // each INSERT on its own line for human-readable export files. + switch (c) { + case '\'': out += "''"; break; + case '\\': out += "\\\\"; break; + case '\0': /* drop NUL */ break; + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + case 26: out += "\\Z"; break; // Ctrl-Z + default: out += c; break; + } } return out; }