Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection.copy_records_to_table does not seem to like nullable rows #153

Closed
Rapptz opened this issue Jun 11, 2017 · 3 comments
Closed

Connection.copy_records_to_table does not seem to like nullable rows #153

Rapptz opened this issue Jun 11, 2017 · 3 comments

Comments

@Rapptz
Copy link

Rapptz commented Jun 11, 2017

  • asyncpg version: 0.11
  • PostgreSQL version: 9.6
  • Python version: 3.6
  • Platform: Windows
  • Do you use pgbouncer?: No
  • Did you install asyncpg with pip?: Yes
  • If you built asyncpg locally, which version of Cython did you use?: N/A
  • Can the issue be reproduced under both asyncio and
    uvloop?
    : Yes

I have no clue if this is a limitation of the COPY protocol, if so sorry for the issue.

My problem comes from attempting to insert elements using None to denote NULL. For example, given the following table:

CREATE TABLE test (id SERIAL PRIMARY KEY, entity_id INTEGER);

Attempts to create a connection and insert NULL entity_id entries results in a TypeError:

async with pool.acquire() as con:
  await con.copy_records_to_table('test', records=[(1, 1), (2, None)], 
                                          columns=('id', 'entity_id'))

Would result in:

Traceback (most recent call last):
  File "asyncpg\connection.py", line 619, in copy_records_to_table
    copy_stmt, records, intro_ps._state, timeout)
  File "asyncpg\connection.py", line 741, in _copy_in_records
    copy_stmt, None, None, records, intro_stmt, timeout)
  File "asyncpg\protocol\protocol.pyx", line 441, in copy_in (asyncpg/protocol/protocol.c:66206)
  File "asyncpg\protocol\protocol.pyx", line 389, in asyncpg.protocol.protocol.BaseProtocol.copy_in (asyncpg/protocol/protocol.c:64677)
  File "asyncpg\protocol\codecs\base.pyx", line 150, in asyncpg.protocol.protocol.Codec.encode (asyncpg/protocol/protocol.c:14433)
  File "asyncpg\protocol\codecs\base.pyx", line 95, in asyncpg.protocol.protocol.Codec.encode_scalar (asyncpg/protocol/protocol.c:13818)
  File "asyncpg\protocol\codecs\int.pyx", line 47, in asyncpg.protocol.protocol.int8_encode (asyncpg/protocol/protocol.c:29584)
TypeError: an integer is required (got type NoneType)

The documentation for the COPY protocol seems to suggest that encoding into NULL is possible:

Each tuple begins with a 16-bit integer count of the number of fields in the tuple. (Presently, all tuples in a table will have the same count, but that might not always be true.) Then, repeated for each field in the tuple, there is a 32-bit length word followed by that many bytes of field data. (The length word does not include itself, and can be zero.) As a special case, -1 indicates a NULL field value. No value bytes follow in the NULL case.

Emphasis mine, from the documentation.

However I don't know if I'm misreading it.

Thanks for your time.

@elprans
Copy link
Member

elprans commented Jun 26, 2017

Fixed. Thanks for catching this!

@midlewis
Copy link

I am having this issue with a value - nan of type: float are you sure it's closed out? the only way i was able to use copy records to table was to convert the entire column to a string.

@elprans
Copy link
Member

elprans commented Nov 14, 2017

This issue was about the handling of NULLs. NaN is a different case, please open a new issue with some example code. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants