Skip to content

json columns on MariaDB: insert fails with TypeError, fetch returns raw strings #1438

@esutlie

Description

@esutlie

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.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions