From c2e286b7d469107de6f99594bef0b9dc2b665662 Mon Sep 17 00:00:00 2001 From: Siting Ren Date: Tue, 24 Aug 2021 11:06:21 -0400 Subject: [PATCH 1/4] Add cancel() test --- .../tests/integration_tests/test_cancel.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/vertica_python/tests/integration_tests/test_cancel.py b/vertica_python/tests/integration_tests/test_cancel.py index 47ef3193..6eec92f4 100644 --- a/vertica_python/tests/integration_tests/test_cancel.py +++ b/vertica_python/tests/integration_tests/test_cancel.py @@ -55,5 +55,39 @@ def cancel_query(conn, delay=5): cur.execute(long_running_query) p1.join() + def test_connection_cancel_returned_query(self): + with self._connect() as conn: + cur = conn.cursor() + cur.execute("DROP TABLE IF EXISTS vptest") + try: + # Creating and loading table + cur.execute("CREATE TABLE vptest(id INTEGER, time TIMESTAMP)") + cur.execute("INSERT INTO vptest" + " SELECT row_number() OVER(), slice_time" + " FROM(" + " SELECT slice_time FROM(" + " SELECT '2021-01-01'::timestamp s UNION ALL SELECT '2022-01-01'::timestamp s" + " ) sq TIMESERIES slice_time AS '1 second' OVER(ORDER BY s)" + " ) sq2") + + # This query returns over 30,000,000 rows. We cancel the command after + # reading 100 of them, and then continue reading results. This quickly + # results in an exception being thrown due to the cancel having taken effect. + cur.execute("SELECT id, time FROM vptest") + + nCount = 0 + with self.assertRaises(errors.QueryCanceled): + while cur.fetchone(): + nCount += 1 + if nCount == 100: + conn.cancel() + + # The number of rows read after the cancel message is sent to the server can vary. + # 100,000 seems to leave a safe margin while still falling well short of + # the 30,000,000+ rows we'd have read if the cancel didn't work. + self.assertTrue(100 <= nCount < 100000) + finally: + cur.execute("DROP TABLE IF EXISTS vptest") + exec(CancelTestCase.createPrepStmtClass()) From 340f6f5c38343271c63eb0182b38d08feee2e75f Mon Sep 17 00:00:00 2001 From: Siting Ren Date: Tue, 24 Aug 2021 23:19:40 +0800 Subject: [PATCH 2/4] Update README.md --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index e4a217f4..1baa4b43 100644 --- a/README.md +++ b/README.md @@ -549,6 +549,7 @@ def cancel_query(connection, timeout=5): time.sleep(timeout) connection.cancel() +# Example 1: Cancel the query before Cursor.execute() return with vertica_python.connect(**conn_info) as conn: cur = conn.cursor() @@ -562,9 +563,25 @@ with vertica_python.connect(**conn_info) as conn: pass p1.join() + +# Example 2: Cancel the query after Cursor.execute() return. +# Less number of rows read after the cancel message is sent. +with vertica_python.connect(**conn_info) as conn: + cur = conn.cursor() + cur.execute("SELECT id, time FROM large_table") + nCount = 0 + try: + while cur.fetchone(): + nCount += 1 + if nCount == 100: + conn.cancel() + except vertica_python.errors.QueryCanceled as e: + pass + ``` + ## Rowcount oddities vertica_python behaves a bit differently than dbapi when returning rowcounts. From 8a8148144856cab16ebf633c4ce7816b492f6540 Mon Sep 17 00:00:00 2001 From: Siting Ren Date: Tue, 24 Aug 2021 11:41:19 -0400 Subject: [PATCH 3/4] fix --- vertica_python/tests/integration_tests/test_cancel.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/vertica_python/tests/integration_tests/test_cancel.py b/vertica_python/tests/integration_tests/test_cancel.py index 6eec92f4..a07420fd 100644 --- a/vertica_python/tests/integration_tests/test_cancel.py +++ b/vertica_python/tests/integration_tests/test_cancel.py @@ -55,6 +55,11 @@ def cancel_query(conn, delay=5): cur.execute(long_running_query) p1.join() + # Must be able to successfully run next query + cur.execute("SELECT 1") + res = cur.fetchall() + self.assertListOfListsEqual(res, [[1]]) + def test_connection_cancel_returned_query(self): with self._connect() as conn: cur = conn.cursor() @@ -86,6 +91,11 @@ def test_connection_cancel_returned_query(self): # 100,000 seems to leave a safe margin while still falling well short of # the 30,000,000+ rows we'd have read if the cancel didn't work. self.assertTrue(100 <= nCount < 100000) + + # Must be able to successfully run next query + cur.execute("SELECT 1") + res = cur.fetchall() + self.assertListOfListsEqual(res, [[1]]) finally: cur.execute("DROP TABLE IF EXISTS vptest") From 7c8c7f39b146611a2a1843534ed00300765d9779 Mon Sep 17 00:00:00 2001 From: Siting Ren Date: Tue, 24 Aug 2021 23:49:49 +0800 Subject: [PATCH 4/4] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1baa4b43..09820653 100644 --- a/README.md +++ b/README.md @@ -549,7 +549,8 @@ def cancel_query(connection, timeout=5): time.sleep(timeout) connection.cancel() -# Example 1: Cancel the query before Cursor.execute() return +# Example 1: Cancel the query before Cursor.execute() return. +# The query stops executing in a shorter time after the cancel message is sent. with vertica_python.connect(**conn_info) as conn: cur = conn.cursor() @@ -577,6 +578,7 @@ with vertica_python.connect(**conn_info) as conn: conn.cancel() except vertica_python.errors.QueryCanceled as e: pass + # nCount is less than the number of rows in large_table ```