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")