Spaces:
Running
Running
File size: 3,391 Bytes
dd5eed8 96beb10 dd5eed8 96beb10 55b6916 96beb10 55b6916 dd5eed8 70b7769 96beb10 dd5eed8 96beb10 55b6916 96beb10 55b6916 dd5eed8 9b36278 dd5eed8 9b36278 dd5eed8 9b36278 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | """Patch setup_db.py to import SQL via Python instead of mariadb CLI.
The `mariadb` CLI restore fails with some external MySQL hosts. This patch
replaces the CLI-based restore with direct `frappe.db.sql_ddl()` calls,
reading and executing the SQL file through the existing Python connection.
"""
import os, re
SETUP_DB = "apps/frappe/frappe/database/mariadb/setup_db.py"
if not os.path.exists(SETUP_DB):
print(f"ERROR: {SETUP_DB} not found")
exit(1)
with open(SETUP_DB) as f:
content = f.read()
OLD_CALL = '''\tDbManager(frappe.local.db).restore_database(
\t\tverbose, db_name, source_sql, db_name, frappe.conf.db_password
\t)'''
NEW_CALL = '''\t# PATCHED: Import SQL via Python connection (avoids mariadb CLI issues)
\tprint(f" [patch] Reading SQL from {source_sql}")
\twith open(source_sql, "r", encoding="utf-8") as _f:
\t\t_raw = _f.read()
\t# Split on ";\\n" to isolate individual SQL statements.
\t# Each fragment may contain leading comment lines ("-- ...") — strip them
\t# so that CREATE / DROP / INSERT statements are not silently skipped.
\t_clean_statements = []
\tfor _frag in _raw.replace("\\r\\n", "\\n").split(";\\n"):
\t\t_lines = []
\t\tfor _line in _frag.split("\\n"):
\t\t\t_stripped = _line.strip()
\t\t\tif _stripped.startswith("--") or _stripped == "":
\t\t\t\tcontinue
\t\t\t_lines.append(_line)
\t\t_cleaned = "\\n".join(_lines).strip()
\t\tif _cleaned and _cleaned != ";":
\t\t\t_clean_statements.append(_cleaned)
\tprint(f" [patch] Found {len(_clean_statements)} SQL statements, importing via db.sql_ddl...")
\t_ok = _fail = 0
\tfor _idx, _stmt in enumerate(_clean_statements):
\t\ttry:
\t\t\tfrappe.db.sql_ddl(_stmt)
\t\t\t_ok += 1
\t\texcept Exception as _e:
\t\t\t_fail += 1
\t\t\tprint(f" [patch] STMT {_idx} FAIL: {_stmt[:160]}... ({_e})")
\t\t\tpass
\tprint(f" [patch] SQL import complete: {_ok} OK, {_fail} failed")
\tprint(f" [patch] Tables after import: {frappe.db.get_tables(cached=False)}")'''
PATCHES = 0
if OLD_CALL in content:
content = content.replace(OLD_CALL, NEW_CALL)
PATCHES += 1
print(f"SUCCESS: Patched restore_database call -> Python SQL import")
else:
print(f"WARNING: Could not find restore_database call in {SETUP_DB}")
if 'import_db_from_sql' in content:
idx = content.index('import_db_from_sql')
print("--- Around import_db_from_sql ---")
print(content[idx:idx+600])
# Also patch the tabDefaultValue table check to be case-insensitive
# External MySQL may have lower_case_table_names=1, returning lowercase table names
OLD_CHECK = '''\tif "tabDefaultValue" not in frappe.db.get_tables(cached=False):'''
NEW_CHECK = '''\t_tables_lower = [t.lower() for t in frappe.db.get_tables(cached=False)]
\tif "tabdefaultvalue" not in _tables_lower:'''
if OLD_CHECK in content:
content = content.replace(OLD_CHECK, NEW_CHECK)
PATCHES += 1
print(f"SUCCESS: Patched tabDefaultValue check -> case-insensitive")
else:
print(f"WARNING: Could not find tabDefaultValue check in {SETUP_DB}")
if 'tabDefaultValue' in content:
idx = content.index('tabDefaultValue')
print(f"--- Around tabDefaultValue (offset {idx}) ---")
print(content[max(0,idx-60):idx+200])
if PATCHES:
with open(SETUP_DB, 'w') as f:
f.write(content)
print(f"DONE: Applied {PATCHES} patch(es) to {SETUP_DB}")
else:
print(f"FAILED: No patches applied")
|