-
Notifications
You must be signed in to change notification settings - Fork 46
FIX: ODBC Catalog method fetchone() issue #520
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -15961,3 +15961,148 @@ def reader(reader_id): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| finally: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stop_event.set() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mssql_python.native_uuid = original | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_catalog_fetchone_iteration_setup(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Create test objects for catalog fetchone/iteration testing""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.execute( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'pytest_cat_fetch') " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "EXEC('CREATE SCHEMA pytest_cat_fetch')" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.execute("DROP TABLE IF EXISTS pytest_cat_fetch.fetch_test_child") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.execute("DROP TABLE IF EXISTS pytest_cat_fetch.fetch_test") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.execute(""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE TABLE pytest_cat_fetch.fetch_test ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id INT PRIMARY KEY, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name VARCHAR(100) NOT NULL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value DECIMAL(10,2), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ts DATETIME DEFAULT GETDATE() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.execute(""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE TABLE pytest_cat_fetch.fetch_test_child ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| child_id INT PRIMARY KEY, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parent_id INT NOT NULL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CONSTRAINT fk_parent FOREIGN KEY (parent_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REFERENCES pytest_cat_fetch.fetch_test(id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| db_connection.commit() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest.fail(f"Catalog fetchone/iteration setup failed: {e}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15966
to
+15995
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_tables_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on tables() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.tables(table="fetch_test", schema="pytest_cat_fetch") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.table_name.lower() == "fetch_test" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.table_schem.lower() == "pytest_cat_fetch" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert cursor.fetchone() is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_tables_iteration(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that 'for row in cursor.tables()' works (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows = list(cursor.tables(table="fetch_test", schema="pytest_cat_fetch")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert len(rows) == 1, "Iteration should yield 1 row" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert rows[0].table_name.lower() == "fetch_test" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_columns_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on columns() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.columns(table="fetch_test", schema="pytest_cat_fetch") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row from columns()" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert hasattr(row, "column_name") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.table_name.lower() == "fetch_test" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_primarykeys_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on primaryKeys() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.primaryKeys(table="fetch_test", schema="pytest_cat_fetch") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row from primaryKeys()" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.column_name.lower() == "id" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert cursor.fetchone() is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_foreignkeys_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on foreignKeys() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.foreignKeys( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| table="fetch_test_child", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schema="pytest_cat_fetch", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row from foreignKeys()" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.pkcolumn_name.lower() == "id" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.fkcolumn_name.lower() == "parent_id" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert cursor.fetchone() is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_statistics_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on statistics() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.statistics(table="fetch_test", schema="pytest_cat_fetch") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row from statistics()" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row.table_name.lower() == "fetch_test" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_procedures_fetchone(cursor, db_connection): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Test that fetchone() works on procedures() result set (GH-505)""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.procedures() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = cursor.fetchone() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert row is not None, "fetchone() should return a row from procedures()" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert hasattr(row, "procedure_name") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+16055
to
+16060
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cursor.procedures() | |
| row = cursor.fetchone() | |
| assert row is not None, "fetchone() should return a row from procedures()" | |
| assert hasattr(row, "procedure_name") | |
| proc_name = f"fetch_proc_{uuid.uuid4().hex[:8]}" | |
| qualified_proc_name = f"pytest_cat_fetch.{proc_name}" | |
| try: | |
| cursor.execute( | |
| f""" | |
| CREATE PROCEDURE {qualified_proc_name} | |
| AS | |
| BEGIN | |
| SELECT 1 AS value | |
| END | |
| """ | |
| ) | |
| db_connection.commit() | |
| cursor.procedures(procedure=proc_name, schema="pytest_cat_fetch") | |
| row = cursor.fetchone() | |
| assert row is not None, "fetchone() should return a row from procedures()" | |
| assert hasattr(row, "procedure_name") | |
| assert row.procedure_name.lower() == proc_name.lower() | |
| assert cursor.fetchone() is None | |
| finally: | |
| cursor.execute(f"DROP PROCEDURE IF EXISTS {qualified_proc_name}") | |
| db_connection.commit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_prepare_metadata_result_set()resets internal rownumber state, but it does not resetself.rowcount. Since_reset_cursor()doesn’t touchrowcount, catalog methods can temporarily expose a stalerowcountvalue from a prior statement until the first fetch updates it. Consider settingself.rowcount = -1(consistent withexecute()for result-set-producing statements) when preparing metadata result sets.