Understanding the Type Mismatch in GridDB Python Client

When working with GridDB in Python, you might encounter a puzzling behavior: retrieving a row using container.get() returns the correct Python types (like int), but querying the same row using query().fetch() converts those same integer values into Python float types. This article explains why this happens and how to resolve it.

The Symptom

Consider a container defined with an INTEGER key and a FLOAT value. When you fetch the row directly, the types are preserved:

row = container.get(1)
print(type(row[0]), type(row[1]))
# Output: <class 'int'> <class 'float'>

However, when executing a TQL query and fetching the results, the integer is unexpectedly promoted to a float:

query = container.query("SELECT *")
rs = query.fetch()
for row in rs:
    print(type(row[0]), type(row[1]))
# Output: <class 'float'> <class 'float'>

Why Does This Happen?

This inconsistency stems from how the griddb_python C-wrapper handles data deserialization across two different execution paths:

  • The Direct Path (container.get): This method uses the container's strict, predefined schema. The client knows exactly what type each column is supposed to be beforehand, mapping GridDB's Type.INTEGER directly to a Python int.
  • The Query Path (query().fetch()): When you run a query, GridDB returns a dynamic RowSet. The Python client's underlying C/C++ binding layer materializes these rows dynamically. In certain versions of the Python SDK, the dynamic type mapper defaults generic numeric values returned by the query engine to double-precision floats to prevent precision loss, resulting in Python float types. This is especially true when fetch(False) is used, which retrieves raw query projections rather than mapping back to the container's strict row schema.

How to Fix and Work Around This Issue

1. Use query.fetch() without disabling row-mapping

If you pass False to fetch(), it tells GridDB not to bind the results to the container's row type. Try calling fetch() without arguments (or passing True, depending on your SDK version) to force the client to use the container's schema definition during deserialization:

rs = query.fetch(True) # Or simply query.fetch()

2. Explicit Type Casting in Python

If you are executing complex queries or projections where schema binding isn't possible, the safest workaround is to explicitly cast the values to your expected types in Python:

for row in rs:
    row_id = int(row[0])
    reading = float(row[1])
    # Process your data with correct types

3. Upgrade the griddb_python Client

Type coercion issues in dynamic row sets are frequently addressed in newer releases of the GridDB Python client. Ensure you are using the latest version of the C client and Python binding:

pip install --upgrade griddb_python

Conclusion

The type discrepancy between get() and query().fetch() is a side-effect of dynamic row-set materialization in the GridDB Python C-bindings. By ensuring your queries bind back to the container schema or by performing explicit type casting, you can maintain type safety across your GridDB applications.