Windows installer: payload hash-locking, SBOM, client-IP handling, operator docs
This commit is contained in:
40
shopdb/utils/mysql_charset.py
Normal file
40
shopdb/utils/mysql_charset.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Force every table created on MySQL to utf8mb4 + DYNAMIC row format.
|
||||
|
||||
Importing this module installs a SQLAlchemy compiler hook. It is a side effect on
|
||||
purpose: the hook has to be registered before any CreateTable is compiled, and
|
||||
every place that creates tables needs it.
|
||||
|
||||
WHY. Without it a CREATE TABLE inherits the SERVER's default charset. A MySQL box
|
||||
defaulting to latin1 - common on older installs, and the West Jefferson 5.6
|
||||
server is one - silently builds a latin1 schema that drifts from the utf8mb4
|
||||
production target. Nothing fails at create time; it surfaces later as mangled
|
||||
characters, or as a join between a utf8mb4 and a latin1 column that cannot use an
|
||||
index.
|
||||
|
||||
DYNAMIC row format is the other half: it keeps utf8mb4 indexes under the 767-byte
|
||||
prefix limit on pre-5.7 InnoDB, which is what error 1071 ("key too long") is.
|
||||
|
||||
This lived inline in migrations/env.py, so it covered the CORE chain only. Plugin
|
||||
chains (ADR-008) run through shopdb/plugins/alembic_template.py, which never
|
||||
imported it - so a plugin's baseline tables were created at the server default
|
||||
while core's were utf8mb4, on the same database. Both import this now.
|
||||
|
||||
Scoped to the mysql dialect, so the SQLite test database is untouched.
|
||||
"""
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
from sqlalchemy.schema import CreateTable
|
||||
|
||||
TABLE_SUFFIX = (
|
||||
" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
||||
" COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC"
|
||||
)
|
||||
|
||||
|
||||
@compiles(CreateTable, "mysql")
|
||||
def _mysql_create_table_utf8mb4(element, compiler, **kw):
|
||||
sql = compiler.visit_create_table(element, **kw)
|
||||
# An explicit CHARSET in the model's __table_args__ wins - this is a default,
|
||||
# not an override.
|
||||
if "CHARSET" not in sql.upper():
|
||||
sql = sql.rstrip().rstrip(";") + TABLE_SUFFIX
|
||||
return sql
|
||||
Reference in New Issue
Block a user