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

TypeError when trying to unpickle results with equal column names #649

Open
tweakimp opened this issue Nov 21, 2019 · 8 comments
Open

TypeError when trying to unpickle results with equal column names #649

tweakimp opened this issue Nov 21, 2019 · 8 comments

Comments

@tweakimp
Copy link

tweakimp commented Nov 21, 2019

Environment

  • Python: 3.7.4
  • pyodbc: 4.0.27
  • OS: win10 64bit
  • DB: SQLITE and MSSQL
  • driver: sqliteodbc_w64.exe from here

Issue

When trying to unpickle a result from a query with some equal column names, a TypeError is raised: TypeError: cannot create 'pyodbc.Row' instances

Code to reproduce

I noticed that at work where we have a MS SQL Server, but it is possible to reproduce the error with sqlite.

import sqlite3
import pickle
import pyodbc

# create a database
conn = sqlite3.connect("db.db")
c = conn.cursor()
# create table and fill it
c.execute("""CREATE TABLE IF NOT EXISTS test (value1 int, value2 int,value3 int)""")
c.execute("INSERT INTO test VALUES (1,1,1),(2,2,2),(3,3,3)")
conn.commit()
conn.close()

# create pyodbc connection
cnxn = pyodbc.connect("Driver=SQLite3 ODBC Driver;Database=db.db")

cursor = cnxn.cursor()

# select unique column names
cursor.execute("SELECT value1, value2, value3 from test")
result = cursor.fetchall()

# we get the actual values
print(f"actual result1 {result}")

# pickle the results
with open("result_ok.pkl", "wb") as file:
    pickle.dump(result, file, protocol=pickle.HIGHEST_PROTOCOL)

# unpickle them
with open("result_ok.pkl", "rb") as file:
    unpickled = pickle.load(file)

# we can load the pickled values
print(f"unpickled result1 {unpickled}")

# same thing again, but select a column twice
cursor = cnxn.cursor()
cursor.execute("SELECT value1, value2, value3, value1 from test")
result = cursor.fetchall()

# we get the actual values again, everything seems fine
print(f"actual result2 {result}")
# pickle the results
with open("result_error.pkl", "wb") as file:
    pickle.dump(result, file, protocol=pickle.HIGHEST_PROTOCOL)

# unpickle them
with open("result_error.pkl", "rb") as file:
    unpickled = pickle.load(file)  # code breaks here

print(f"unpickled result2 {unpickled}")
@v-makouz
Copy link
Contributor

I will try to reproduce this, just to confirm, this happens on SQL Server as well, with "ODBC Driver 17 for SQL Server"?

@tweakimp
Copy link
Author

Yes.

@v-chojas
Copy link
Contributor

Possibly related: #446

@v-makouz
Copy link
Contributor

@tweakimp I am able to repro the issue, and I will into it over the next few days

@tweakimp
Copy link
Author

Great, thank you for your time

@v-makouz
Copy link
Contributor

I've located the code that throws that error, but I still don't quite understand the logic behind it,
in the file row.cpp around line 110, there's this:

    if (PyDict_Size(map) != cols || PyTuple_GET_SIZE(args) - 2 != cols)
        return 0;

Which will cause the early return if you select different number of columns, because then PyDict_Size(map) != cols will be true. I tried running the repro with that check removed and I got correct looking results back after unpickling (with 4 columns), but that check was put there for a reason, I'm just not sure what it is @mkleehammer?

@piskvorky
Copy link

piskvorky commented Nov 13, 2020

Also bitten by this on SQL Server 2014 + msodbcsql17; @v-makouz did you manage to find a work around?

@v-makouz
Copy link
Contributor

@piskvorky I'm afraid I don't really know anything new, other then if the above code is changed to

    if (PyTuple_GET_SIZE(args) - 2 != cols)
        return 0;

The above repro will work correctly, but I'm not sure if that'll cause issues for anything else. I'm just not sure why that check is there.

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

4 participants