Skip to main content

Pack/unpack Python dicts into/out of MariaDB's Dynamic Columns format.

Project description

https://img.shields.io/github/workflow/status/adamchainz/mariadb-dyncol/CI/main?style=for-the-badge https://img.shields.io/pypi/v/mariadb-dyncol.svg?style=for-the-badge https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge pre-commit

Unmaintained (2022-12-07)

I stopped maintaining this package as it has never been popular. Since MariaDB added JSON support, it’s better to use that for portability, rather than the custom dynamic columns format. If you’d like to take over maintenance of this package please email me.


Pack/unpack Python dicts into/out of MariaDB’s Dynamic Columns format.

A quick example:

>>> mariadb_dyncol.pack({"key": "value"})
b'\x04\x01\x00\x03\x00\x00\x00\x03\x00key!value'
>>> mariadb_dyncol.unpack(mariadb_dyncol.pack({"key": "value"}))
{'key': 'value'}

Installation

Use pip:

python -m pip install mariadb-dyncol

Python 3.7 to 3.11 supported.


Working on a Django project? Check out my book Boost Your Django DX which covers many ways to improve your development experience.


Features

  • Sensible type mapping from Python to SQL

  • Tested against examples from MariaDB, including property/fuzz testing with hypothesis (which is amazing and found many bugs)

Why?

The normal way for adding data into dynamic columns fields is with the COLUMN_CREATE function, and its relatives. This allows you to do things like:

INSERT INTO mytable (attrs) VALUES (COLUMN_CREATE('key', 'value'))

Unfortunately the Django ORM is restricted and cannot use database functions like this in every instance, at least not until Django 1.9. It was this limitation I hit whilst implementing a dynamic columns field for my project django-mysql that spurred the creation of this library.

By pre-packing the dynamic columns, the above query can just insert the blob of data directly:

INSERT INTO mytable (attrs) VALUES (X'0401000300000003006B65792176616C7565')

Asides from being more easily implemented with the Django ORM, this approach of packing/unpacking dynamic columns in Python also has some advantages:

  • All data types are properly preserved in Python. The only way MariaDB provides of pulling back all values for a dynamic columns field is to call COLUMN_JSON, but JSON only supports strings and integers. Also COLUMN_JSON has a depth limit of 10, but the format has no actual limit.

  • The CPU overhead of packing/unpacking the dynamic columns is moved from you database server to your (presumably more scalable) clients.

API

All functions and names are accessible as attributes of the mariadb_dyncol module, which you can import with import mariadb_dyncol.

pack(mapping)

Packs the given mapping (a dict) into the MariaDB Dynamic Columns format for named columns and returns it as a byte string (Python 3’s bytes, Python 2’s str). This is suitable for then inserting into a table as part of a normal query.

The dict's keys must all be unicode strings, and the values must all be one of the supported data types:

  • int between -(2 ** 32) + 1 and (2 ** 64) - 1 (Python 2: long is supported too)

  • str up to 4GB encoded in UTF-8 (Python 2: unicode)

  • float - anything except NaN or +/- inf

  • datetime.datetime - full range supported

  • datetime.date - full range supported

  • datetime.time - full range supported

  • Any dict that is valid by these rules, allowing nested keys. There is no nesting limit except from for MariaDB’s COLUMN_JSON function which restricts the depth to 10

Note that this does not support the DECIMAL type that MariaDB does (and would naturally map to Python’s Decimal) - it is a little more fiddly to pack/unpack, though certainly possible, and pull requests are welcomed. If you try and pack a Decimal, a DynColNotSupported exception will be raised.

There are other restrictions on the UTF-8 encoded column names as documented in MariaDB:

  • The maximum length of a column name is 16383 bytes

  • The maximum length of all column names (at one level in nested hierarchies) is 65535 bytes

All other unsupported types will raise a DynColTypeError. Out of range values will raise a DynColValueError.

Examples:

>>> mariadb_dyncol.pack({"a": 1})
b'\x04\x01\x00\x01\x00\x00\x00\x00\x00a\x02'
>>> mariadb_dyncol.pack({"a": "💩"})
b'\x04\x01\x00\x01\x00\x00\x00\x03\x00a!\xf0\x9f\x92\xa9'

unpack(bytestring)

Unpacks MariaDB dynamic columns data encoded byte string into a dict; the types you can expect back are those listed above. This is suitable for fetching the data direct from MariaDB and decoding in Python as opposed to with MariaDB’s COLUMN_JSON function, preserving the types that JSON discards.

As noted above, DECIMAL values are not supported, and unpacking this will raise DynColNotSupported. Also strings will only be decoded with the MySQL charsets utf8 or utf8mb4; strings with other charsets will raise DynColNotSupported as well.

Unsupported column formats, for example the old MariaDB numbered dynamic columns format, or corrupt data, will raise DynColValueError.

Examples:

>>> mariadb_dyncol.unpack(b"\x04\x01\x00\x01\x00\x00\x00\x03\x00a!\xf0\x9f\x92\xa9")
{"a": "💩"}
>>> mariadb_dyncol.unpack(b"\x04\x01\x00\x01\x00\x00\x00\x00\x00a\x02")
{"a": 1}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mariadb-dyncol-3.6.1.tar.gz (12.6 kB view details)

Uploaded Source

Built Distribution

mariadb_dyncol-3.6.1-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file mariadb-dyncol-3.6.1.tar.gz.

File metadata

  • Download URL: mariadb-dyncol-3.6.1.tar.gz
  • Upload date:
  • Size: 12.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.0

File hashes

Hashes for mariadb-dyncol-3.6.1.tar.gz
Algorithm Hash digest
SHA256 cc63fe28fa5dad4d843f665fad0ae091db3756f0a51d1fded5b2861304359724
MD5 b0de0fe57c3b5b5ee0e39350603f92cb
BLAKE2b-256 50ba5df33fdf9a961dbc3a062648540e21f3a7223936b376f5bddb2d32affa57

See more details on using hashes here.

File details

Details for the file mariadb_dyncol-3.6.1-py3-none-any.whl.

File metadata

File hashes

Hashes for mariadb_dyncol-3.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 843cc1cd56e6e696e75331f644cfc30ff9f20a40741267ed3cf86a2093994804
MD5 3f46bcf67daa49da4ac606f54a0cc8b9
BLAKE2b-256 1c0e60d6183ac16b01fa61cba920f282a8df0e26302dde2e47c456851b9d1b21

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page