Skip to content

Commit

Permalink
Fix #237 - commit even after simple query
Browse files Browse the repository at this point in the history
  • Loading branch information
amochin committed Feb 20, 2025
1 parent da5e893 commit e403ef4
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 20 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,10 @@ Library DatabaseLibrary log_query_results_head=0
While creating a database connection, the library doesn't explicitly set the _autocommit_ behavior -
so the default value of the Python DB module is used.
According to Python DB API specification it should be disabled by default -
which means each SQL transaction must contain a dedicated commit statement, if necessary.
which means each SQL transaction (even a simple _SELECT_) must contain a dedicated commit statement, if necessary.

The library manages it for you:
- Keywords like `Execute SQL String` perform automatically a commit after running the query - or a rollback in case of error
- Keywords like `Query` don't perform a commit, but also do a rollback in case of error
The library manages it for you - keywords like `Query` or `Execute SQL String`
perform automatically a commit after running the query (or a rollback in case of error).

You can turn off this automatic commit/rollback behavior using the ``no_transaction`` parameter.
See docs of a particular keyword.
Expand Down
7 changes: 3 additions & 4 deletions src/DatabaseLibrary/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,10 @@ class DatabaseLibrary(ConnectionManager, Query, Assertion):
While creating a database connection, the library doesn't explicitly set the _autocommit_ behavior -
so the default value of the Python DB module is used.
According to Python DB API specification it should be disabled by default -
which means each SQL transaction must contain a dedicated commit statement, if necessary.
which means each SQL transaction (even a simple _SELECT_) must contain a dedicated commit statement, if necessary.
The library manages it for you:
- Keywords like `Execute SQL String` perform automatically a commit after running the query - or a rollback in case of error
- Keywords like `Query` don't perform a commit, but also do a rollback in case of error
The library manages it for you - keywords like `Query` or `Execute SQL String`
perform automatically a commit after running the query (or a rollback in case of error).
You can turn off this automatic commit/rollback behavior using the ``no_transaction`` parameter.
See docs of a particular keyword.
Expand Down
9 changes: 6 additions & 3 deletions src/DatabaseLibrary/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def query(
The type of row values depends on the database module -
usually they are tuples or tuple-like objects.
Set ``no_transaction`` to _True_ to run command without explicit transaction rollback in case of error.
Set ``no_transaction`` to _True_ to run command without explicit transaction commit or rollback in case of error.
See `Commit behavior` for details.
Set ``return_dict`` to _True_ to explicitly convert the return values into list of dictionaries.
Expand Down Expand Up @@ -89,6 +89,7 @@ def query(
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
)
all_rows = cur.fetchall()
self._commit_if_needed(db_connection, no_transaction)
col_names = [c[0] for c in cur.description]
self._log_query_results(col_names, all_rows)
if return_dict:
Expand All @@ -111,7 +112,7 @@ def row_count(
"""
Runs a query with the ``select_statement`` and returns the number of rows in the result.
Set ``no_transaction`` to _True_ to run command without explicit transaction rollback in case of error.
Set ``no_transaction`` to _True_ to run command without explicit transaction commit or rollback in case of error.
See `Commit behavior` for details.
Use ``alias`` to specify what connection should be used if `Handling multiple database connections`.
Expand Down Expand Up @@ -143,6 +144,7 @@ def row_count(
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
)
data = cur.fetchall()
self._commit_if_needed(db_connection, no_transaction)
col_names = [c[0] for c in cur.description]
if db_connection.module_name in ["sqlite3", "ibm_db", "ibm_db_dbi", "pyodbc", "jaydebeapi"]:
current_row_count = len(data)
Expand All @@ -168,7 +170,7 @@ def description(
"""
Runs a query with the ``select_statement`` to determine the table description.
Set ``no_transaction`` to _True_ to run command without explicit transaction rollback in case of error.
Set ``no_transaction`` to _True_ to run command without explicit transaction commit or rollback in case of error.
See `Commit behavior` for details.
Use ``alias`` to specify what connection should be used if `Handling multiple database connections`.
Expand Down Expand Up @@ -199,6 +201,7 @@ def description(
parameters=parameters,
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
)
self._commit_if_needed(db_connection, no_transaction)
description = list(cur.description)
if sys.version_info[0] < 3:
for row in range(0, len(description)):
Expand Down
8 changes: 0 additions & 8 deletions test/tests/common_tests/basic_tests.robot
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,3 @@ Verify Query - Row Count foobar table 0 row
[Setup] Create Foobar Table And Insert Data
Delete All Rows From Table foobar
Row Count Is 0 SELECT * FROM foobar

For Loop
FOR ${i} IN RANGE 10
${results}= Query SELECT LAST_NAME FROM person ORDER BY id
Sleep 3s
IF '${results}[0][0]' == 'Musk' BREAK
END
Should Be Equal As Strings ${results}[0][0] Musk
2 changes: 1 addition & 1 deletion test/tests/common_tests/connection_params.robot
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Test Teardown Disconnect From Database
... invalid custom param=TypeError: connect() got an unexpected keyword argument 'blah'
&{Errors pymysql}
... missing basic params=OperationalError: (1045, "Access denied*
... invalid custom param=TypeError: __init__() got an unexpected keyword argument 'blah'
... invalid custom param=TypeError: Connection.__init__() got an unexpected keyword argument 'blah'
&{Errors pyodbc}
... missing basic params=REGEXP: InterfaceError.*Data source name not found and no default driver specified.*

Expand Down
17 changes: 17 additions & 0 deletions test/tests/custom_db_tests/db_update_in_background_commit.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
*** Settings ***
Documentation Check if the SQL statement returns new results, if DB is being updated in the background -
... this requires a commit after each query.
... See https://github.com/MarketSquare/Robotframework-Database-Library/issues/237
Resource ../../resources/common.resource

Suite Setup Connect To DB
Suite Teardown Disconnect From Database
Test Setup Create Person Table And Insert Data
Test Teardown Drop Tables Person And Foobar


*** Test Cases ***
Use Auto retry
[Documentation] Update the DB manually in the background and check if the query returns the new results
Check Query Result SELECT LAST_NAME FROM person ORDER BY id == Musk retry_timeout=30s

0 comments on commit e403ef4

Please sign in to comment.