Search code examples
pythonsqlignite

Trying to use a DATE column with pyignite


When I query my date column I get an error:

Traceback (most recent call last): File "...\Python\Python38\site-packages\pyignite\datatypes\internal.py", line 390, in __data_class_parse return tc_map(type_code) File "...\Python\Python38\site-packages\pyignite\datatypes\internal.py", line 117, in tc_map return _tc_map[key] KeyError: b'\xfe'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "min_repo.py", line 24, in with client.sql('SELECT * FROM DATETEST') as cursor: File "...\Python\Python38\site-packages\pyignite\client.py", line 774, in sql return SqlFieldsCursor(self, c_info, query_str, page_size, query_args, schema, statement_type, File "...\Python\Python38\site-packages\pyignite\cursors.py", line 305, in init self._finalize_init(sql_fields(self.connection, self.cache_info, *args, **kwargs)) File "...\Python\Python38\site-packages\pyignite\api\sql.py", line 309, in sql_fields
return __sql_fields(conn, cache_info, query_str, page_size, query_args, schema, statement_type, distributed_joins,
File "...\Python\Python38\site-packages\pyignite\api\sql.py", line 360, in __sql_fields
return query_perform( File "...\Python\Python38\site-packages\pyignite\queries\query.py", line 49, in query_perform return _internal() File "...\Python\Python38\site-packages\pyignite\queries\query.py", line 42, in _internal
result = query_struct.perform(conn, **kwargs) File "...\Python\Python38\site-packages\pyignite\queries\query.py", line 177, in perform
raise e File "...\Python\Python38\site-packages\pyignite\queries\query.py", line 167, in perform
response_ctype = response_struct.parse(stream) File "...\Python\Python38\site-packages\pyignite\queries\response.py", line 110, in parse
self._parse_success(stream, fields) File "...\Python\Python38\site-packages\pyignite\queries\response.py", line 178, in _parse_success field_class = AnyDataObject.parse(stream) File "...\Python\Python38\site-packages\pyignite\datatypes\internal.py", line 378, in parse data_class = cls.__data_class_parse(stream) File "...\Python\Python38\site-packages\pyignite\datatypes\internal.py", line 392, in __data_class_parse raise ParseError('Unknown type code: {}'.format(type_code)) pyignite.exceptions.ParseError: Unknown type code: b'\xfe'

My understanding of this is that it tried to decode the type code to match it to its type. It should map to a DateObject with the type code of x\0b. My int and timestamp columns work without issue.

Here is my code:

from pyignite import Client
import datetime

client = Client()

with client.connect("localhost", 10800):
    client.sql("DROP TABLE DATETEST IF EXISTS")
    client.sql('''CREATE TABLE DATETEST (
        ID INT PRIMARY KEY, 
        Date DATE, 
        Timestamp TIMESTAMP
    )''')

    insert = '''INSERT INTO DATETEST (
        ID, Date, Timestamp
    ) VALUES (?, ?, ?)'''
    client.sql(insert, query_args=[
        1,
        datetime.datetime.fromisoformat("2022-01-02"),
        datetime.datetime.fromisoformat("2022-01-02")
    ])

    with client.sql('SELECT * FROM DATETEST') as cursor:
        for row in cursor:
            print(row)

Solution

  • the problem is data types. The datetime.fromisoformat method returns a datetime.datetime object, which fit Ignit's Timestamp type, but not suitable for it's Date type, which requires datetime.date:

    #You can import the mapping for date with:
    from pyignite.datatypes import DateObject
    #...
        client.sql(insert, query_args=[
            1,
            datetime.date.fromisoformat("2022-01-02"),
            datetime.datetime.fromisoformat("2022-01-02")
        ])
    

    Nevertheless, the type DATE seems poorly supported by Ignite, and Ignite recommend to use TIMESTAMP instead:

    "Use the TIMESTAMP type instead of DATE whenever possible. The DATE type is serialized/deserialized very inefficiently resulting in performance degradation."

    https://ignite.apache.org/docs/latest/sql-reference/data-types#date

    ...so that it could be better to store your date as TIMESTAMP in Ignite, and parse it to datetime.date in your python code for computation or display purposes:

        client.sql('''CREATE TABLE DATETEST (
            ID INT PRIMARY KEY, 
            Date TIMESTAMP, 
            Timestamp TIMESTAMP
        )''')
    
        insert = '''INSERT INTO DATETEST (
            ID, Date, Timestamp
        ) VALUES (?, ?, ?)'''
        client.sql(insert, query_args=[
            1,
            datetime.datetime.fromisoformat("2022-01-02"),
            datetime.datetime.fromisoformat("2022-01-02")
        ])