MariaDB aliases json columns to longtext internally. When DataJoint reads the column type back from information_schema, it sees longtext instead of json, so attr.json ends up False. That means json.dumps() is skipped on insert (raw dict hits pymysql → TypeError) and json.loads() is skipped on fetch (you get back a string instead of a dict).
The root cause is in heading.py — _init_from_database() matches the reported type against TYPE_PATTERN["JSON"] (r"jsonb?$"), which matches json but not longtext. So on MariaDB, any column declared as json silently loses its json behavior.
This hits two code paths:
- Insert (
table.py): the elif attr.json: value = json.dumps(value) branch is skipped
- Fetch (
codecs.py): the if attr.json: branch is skipped
Codec columns are partially unaffected on fetch because that path uses final_dtype from get_dtype() rather than attr.json.
Reproduction
import datajoint as dj
schema = dj.Schema("test_json_compat")
@schema
class JsonTest(dj.Manual):
definition = """
id : int
---
metadata : json
"""
JsonTest.insert1({"id": 1, "metadata": {"key": "value"}})
# TypeError: dict can not be used as parameter
Suggested fix
In heading.py, _init_from_database() currently sets attr.json based solely on what the database reports. On MariaDB this is longtext, so the match fails. But the original declared type (json) is available from the table definition. If _init_from_database() cross-referenced the declared type against the reported type, it could detect this aliasing and set attr.json = True even when the DB reports longtext.
MariaDB aliases
jsoncolumns tolongtextinternally. When DataJoint reads the column type back frominformation_schema, it seeslongtextinstead ofjson, soattr.jsonends upFalse. That meansjson.dumps()is skipped on insert (raw dict hits pymysql →TypeError) andjson.loads()is skipped on fetch (you get back a string instead of a dict).The root cause is in
heading.py—_init_from_database()matches the reported type againstTYPE_PATTERN["JSON"](r"jsonb?$"), which matchesjsonbut notlongtext. So on MariaDB, any column declared asjsonsilently loses its json behavior.This hits two code paths:
table.py): theelif attr.json: value = json.dumps(value)branch is skippedcodecs.py): theif attr.json:branch is skippedCodec columns are partially unaffected on fetch because that path uses
final_dtypefromget_dtype()rather thanattr.json.Reproduction
Suggested fix
In
heading.py,_init_from_database()currently setsattr.jsonbased solely on what the database reports. On MariaDB this islongtext, so the match fails. But the original declared type (json) is available from the table definition. If_init_from_database()cross-referenced the declared type against the reported type, it could detect this aliasing and setattr.json = Trueeven when the DB reportslongtext.