dana-medical-site/migrations/import/sqlread.py
2026-10-14 13:33:13 +00:00

94 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import io, re
BS = chr(92)
# Как MySQL экранирует спецсимволы в дампе. Всё, чего здесь нет (\' \" \\ и т.п.),
# подставляется как есть — снимается только сам слэш.
ESCAPES = {
'n': '\n',
'r': '\r',
't': '\t',
'0': '\0',
'b': '\b',
'Z': chr(26),
}
def columns(path, table):
cols, inside = [], False
for line in io.open(path, encoding='utf-8', errors='replace'):
if line.startswith('CREATE TABLE `%s`' % table):
inside = True
continue
if inside:
m = re.match(r'\s+`([^`]+)`', line)
if m:
cols.append(m.group(1))
elif line.startswith(')'):
break
return cols
def _scan(s, start=0):
"""Scan one (...) row starting at s[start]=='('. Returns (fields, next_index)."""
assert s[start] == '('
i = start + 1
fields, buf, q = [], [], False
while i < len(s):
c = s[i]
if q:
if c == BS:
# Escape-последовательности MySQL нужно раскодировать, а не просто
# снимать слэш: иначе \r\n превращался в буквы "rn" прямо в тексте.
nxt = s[i + 1] if i + 1 < len(s) else ''
buf.append(ESCAPES.get(nxt, nxt))
i += 2
continue
if c == "'":
q = False
i += 1
continue
buf.append(c)
i += 1
continue
if c == "'":
q = True
i += 1
continue
if c == ',':
fields.append(''.join(buf))
buf = []
i += 1
continue
if c == ')':
fields.append(''.join(buf))
return fields, i + 1
buf.append(c)
i += 1
return None, i
def rows(path, table):
cols = columns(path, table)
text = []
cur = False
for line in io.open(path, encoding='utf-8', errors='replace'):
if re.match(r'INSERT INTO `%s` VALUES' % re.escape(table), line):
cur = True
text.append(line.split('VALUES', 1)[1])
continue
if cur:
text.append(line)
if line.rstrip().endswith(';'):
cur = False
s = ''.join(text)
i = 0
while i < len(s):
if s[i] == '(':
fields, i = _scan(s, i)
if fields is None:
break
yield dict(zip(cols, [f.strip() for f in fields]))
else:
i += 1