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

pyodbc - fetchone() crash - Only 4.0.38 issue (other versions work fine) #1196

Closed
jvdalen opened this issue Apr 12, 2023 · 16 comments
Closed

Comments

@jvdalen
Copy link

jvdalen commented Apr 12, 2023

Environment

  • Python: 3.10
  • pyodbc: 4.0.38
  • OS: Win64 (same issue in Linux when running as Azure Python Function)
  • DB: Azure SQL
  • driver: ?

Issue

Get a none-defined error (python crashes)

Code works in 4.0.35 and before. Stopped working after updating to 4.0.38. Works again after downgrading to 4.0.35.

---Some test code that reproduces it for me:

    connection_string = os.environ["SQL_CONNECTION_STRING"]
    with pyodbc.connect(connection_string) as conn:
        cursor = conn.cursor()
        cursor. Execute("SELECT TOP 1 * FROM table")
        logging.info("Executed query")
        row = cursor.fetchone() 
        #loggin the row data
        logging.info("Fetched row")
        logging.info(f"Row: {row}")

Error: Language Worker Process exited. Pid=1516. / python exited with code -1073741819 (0xC0000005).

If running above without fetchone() no issues.


My first ever "bug report". Apologies if it is not according to the standard. Done my best to make it useful.

@v-chojas
Copy link
Contributor

Could you run in a debugger and show where the crash happens?

@gordthompson
Copy link
Collaborator

gordthompson commented Apr 12, 2023

@jvdalen - Good first effort! Thanks for reporting.

You can get the driver information from the connection, e.g., on my Ubuntu box I get

cnxn = pyodbc.connect("DSN=mssql_199;UID=scott;PWD=tiger^5HHH")
print(cnxn.getinfo(pyodbc.SQL_DRIVER_NAME))  # libmsodbcsql-17.10.so.2.1
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER))  # 17.10.0002

(BTW, this works fine for me)

import pyodbc

print(pyodbc.version)  # 4.0.38

cnxn = pyodbc.connect("DSN=mssql_199;UID=scott;PWD=tiger^5HHH")
print(cnxn.getinfo(pyodbc.SQL_DRIVER_NAME))  # libmsodbcsql-17.10.so.2.1
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER))  # 17.10.0002

crsr = cnxn.cursor()
result = crsr.execute("SELECT 1 AS foo").fetchone()
print(result)  # (1,)

@Jskarie
Copy link

Jskarie commented Apr 12, 2023

I'm also having problems with crashing on 4.0.38. Reverting fixes the issue.
I'm getting an exit code 245. The error doesn't show up until I try to pull the values.
it crashes on the line with the logger. I can't even catch the error...

row = self.execute_sql(*args).fetchone()
logger.info(f"sql: {args} time:{round(time.time() - t0, 2)} out:{row}")
return row

driver:IBM i Access ODBC Driver

@dr-rodriguez
Copy link

My tests running in a docker container started failing when updating pyodbc to 4.0.38. I haven't been able to fully track down what the issue is as it reports it as a Python segmentation fault error. Reverting to 4.0.35 fixed the issue.

Here's what I see when I check the database result a few times:

>>> con = pyodbc.connect(dsn=DSN, database=DB, autocommit=True, trusted_connection='yes', app='pyCAOM_unittest')
>>> print(con.getinfo(pyodbc.SQL_DRIVER_NAME))
libmsodbcsql-17.10.so.2.1
>>> print(con.getinfo(pyodbc.SQL_DRIVER_VER)) 
17.10.0002
>>> 
>>> query = 'select @@servername'
>>> db_result = con.execute(query).fetchall()
>>> print(db_result)
[('TWMASTDB9',)]
>>> print(db_result)
[('[_b',)]
>>> print(db_result)
[''\'\\\'\\S',)]
>>> print(db_result)
Segmentation fault (core dumped)

With pyodbc 4.0.35 my value of db_result doesn't change with each print statement.

@gordthompson
Copy link
Collaborator

gordthompson commented Apr 12, 2023

I am able to reproduce the results reported by @dr-rodriguez . With 4.0.38 the value of db_result changes each time it is printed, but with 4.0.35 it remains consistent.

4.0.35

import pyodbc

print(pyodbc.version)  # 4.0.35

cnxn = pyodbc.connect("DSN=mssql_199;UID=scott;PWD=tiger^5HHH")
print(cnxn.getinfo(pyodbc.SQL_DRIVER_NAME))  # libmsodbcsql-17.10.so.2.1
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER))  # 17.10.0002

crsr = cnxn.cursor()
db_result = crsr.execute("SELECT @@servername").fetchall()
print(db_result)  # [('a3924f40a328', )]
print(db_result)  # [('a3924f40a328', )]
print(db_result)  # [('a3924f40a328', )]
print(db_result)  # [('a3924f40a328', )]

4.0.38

import pyodbc

print(pyodbc.version)  # 4.0.38

cnxn = pyodbc.connect("DSN=mssql_199;UID=scott;PWD=tiger^5HHH")
print(cnxn.getinfo(pyodbc.SQL_DRIVER_NAME))  # libmsodbcsql-17.10.so.2.1
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER))  # 17.10.0002

crsr = cnxn.cursor()
db_result = crsr.execute("SELECT @@servername").fetchall()
print(db_result)  # [('a3924f40a328', )]
print(db_result)  # [('(392',)]
print(db_result)  # [("('(3",)]
print(db_result)  # [('("(\'',)]

@gordthompson
Copy link
Collaborator

Additional info: This seems to only affect string values

db_result = crsr.execute("SELECT N'hello world' AS foo").fetchall()
print(db_result)  # [('hello world',)]
print(db_result)  # [('(ell',)]
print(db_result)  # [("('(e",)]
print(db_result)  # [('("(\'',)]
db_result = crsr.execute("SELECT 'hello world' AS foo").fetchall()
print(db_result)  # [('hello world',)]
print(db_result)  # [('(ell',)]
print(db_result)  # [("('(e",)]
print(db_result)  # [('("(\'',)]

but not other types

db_result = crsr.execute("SELECT 1 AS foo").fetchall()
print(db_result)  # [(1,)]
print(db_result)  # [(1,)]
print(db_result)  # [(1,)]
db_result = crsr.execute("SELECT 3.14 AS foo").fetchall()
print(db_result)  # [(Decimal('3.14'),)]
print(db_result)  # [(Decimal('3.14'),)]
print(db_result)  # [(Decimal('3.14'),)]
db_result = crsr.execute("SELECT CAST('2023-04-12 13:14:15' AS datetime2) AS foo").fetchall()
print(db_result)  # [(datetime.datetime(2023, 4, 12, 13, 14, 15),)]
print(db_result)  # [(datetime.datetime(2023, 4, 12, 13, 14, 15),)]
print(db_result)  # [(datetime.datetime(2023, 4, 12, 13, 14, 15),)]

@v-chojas
Copy link
Contributor

I suspect the change that caused it is 615ebdd

@jvdalen
Copy link
Author

jvdalen commented Apr 13, 2023

print(cnxn.getinfo(pyodbc.SQL_DRIVER_NAME))  # libmsodbcsql-17.10.so.2.1
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER))  # 17.10.0002

@gordthompson Thanks!

Driver version: 17.10.0003
Driver: msodbcsql17.dll

@v-chojas, let me know if you still need additional debug info (VSCode doesn't seem to give me more info than what provided). With the above comments from others, if still more info is required, please let me know and I will see if I can get more debugger ifno.

@Jskarie
Copy link

Jskarie commented Apr 13, 2023

I suspect the change that caused it is 615ebdd

That is likely correct. I can run 4829107, without issues where as 615ebdd fails.

@jvdalen you can test this via
commit prior to the issue for me
pip install pyodbc@git+https://github.com/mkleehammer/pyodbc@4829107
commit with the issue
pip install pyodbc@git+https://github.com/mkleehammer/pyodbc@615ebdd

Thank you!

@jvdalen
Copy link
Author

jvdalen commented Apr 14, 2023

@Jskarie,

I have just tested as per the above. That is indeed correct. The second one reproduces the error, the first doesn't.

615ebdd seems to be the culprit.

@mkleehammer
Copy link
Owner

I forgot to include the issue number in the commit: 4c385cf

There is a clear reference count bug in the new code. I've just fixed it and will make a new release. This is an embarrasing bug. I'm very surprised none of the unit tests caught this.

mkleehammer added a commit that referenced this issue Apr 14, 2023
Original unit tests for Row.__repr__ only retrieved ints, but mismanaging int refcounts doesn't
seem to cause immediate crashes.  (The values were 1-4, so perhaps those are "immortal".)
Changing one of the values selected to a string reproduces the old error.
@mkleehammer
Copy link
Owner

FYI: I have yanked 4.0.38 from PyPI. 4.0.39 will be uploaded soon. The AppVeyor tests take a while. Once the current set completes I'll bump the version, push, wait for those tests to complete (as they'll have the version tag), then release.

Thanks to everyone for reporting this.

@mkleehammer
Copy link
Owner

Uploading 4.0.39 now...

@dr-rodriguez
Copy link

Thanks for this quick fix! My own tests are now passing with 4.0.39

@Jskarie
Copy link

Jskarie commented Apr 14, 2023

Thank you! I appreciate the work you put into maintaining this project.

@jvdalen
Copy link
Author

jvdalen commented Apr 15, 2023

Awesome and thanks for resolving this!

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

6 participants