From 001179838250d86ac5df7f97eb70847a02a921f0 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Wed, 25 May 2022 19:58:15 +0200 Subject: [PATCH] mysql_query: fix false change reports when IF NOT EXISTS clause is used (#322) (#374) * mysql_query: fix false change reports when IF NOT EXISTS clause is used * Fix * Fix doc, add fragment * Improve doc (cherry picked from commit 647461010db5af4fb68164eeacbfda3dce6a41c8) Co-authored-by: Andrew Klychkov --- ...22-mysql_query_fix_false_change_report.yml | 2 ++ plugins/modules/mysql_query.py | 32 +++++++++++++++--- .../tasks/mysql_query_initial.yml | 33 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/322-mysql_query_fix_false_change_report.yml diff --git a/changelogs/fragments/322-mysql_query_fix_false_change_report.yml b/changelogs/fragments/322-mysql_query_fix_false_change_report.yml new file mode 100644 index 00000000..db539225 --- /dev/null +++ b/changelogs/fragments/322-mysql_query_fix_false_change_report.yml @@ -0,0 +1,2 @@ +bugfixes: +- mysql_query - fix false change reports when ``IF EXISTS/IF NOT EXISTS`` clause is used (https://github.com/ansible-collections/community.mysql/issues/268). diff --git a/plugins/modules/mysql_query.py b/plugins/modules/mysql_query.py index fc789c5c..a91335b3 100644 --- a/plugins/modules/mysql_query.py +++ b/plugins/modules/mysql_query.py @@ -22,6 +22,10 @@ description: - SQL query to run. Multiple queries can be passed using YAML list syntax. - Must be a string or YAML list containing strings. + - Note that if you use the C(IF EXISTS/IF NOT EXISTS) clauses in your query + and C(mysqlclient) connector, the module will report that + the state has been changed even if it has not. If it is important in your + workflow, use the C(PyMySQL) connector instead. type: raw required: yes positional_args: @@ -103,6 +107,8 @@ sample: [5, 1] ''' +import warnings + from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.mysql.plugins.module_utils.mysql import ( mysql_connect, @@ -196,9 +202,22 @@ def main(): executed_queries = [] rowcount = [] + already_exists = False for q in query: try: - cursor.execute(q, arguments) + with warnings.catch_warnings(): + warnings.filterwarnings(action='error', + message='.*already exists*', + category=mysql_driver.Warning) + + try: + cursor.execute(q, arguments) + except mysql_driver.Warning: + # When something is run with IF NOT EXISTS + # and there's "already exists" MySQL warning, + # set the flag as True. + # PyMySQL throws the warning, mysqlclinet does NOT. + already_exists = True except Exception as e: if not autocommit: @@ -208,7 +227,8 @@ def main(): module.fail_json(msg="Cannot execute SQL '%s' args [%s]: %s" % (q, arguments, to_native(e))) try: - query_result.append([dict(row) for row in cursor.fetchall()]) + if not already_exists: + query_result.append([dict(row) for row in cursor.fetchall()]) except Exception as e: if not autocommit: @@ -224,8 +244,12 @@ def main(): for keyword in DDL_QUERY_KEYWORDS: if keyword in q: - changed = True - + if already_exists: + # Indicates the entity already exists + changed = False + already_exists = False # Reset flag + else: + changed = True try: executed_queries.append(cursor._last_executed) except AttributeError: diff --git a/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml b/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml index 30182fe6..2d971ab5 100644 --- a/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml +++ b/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml @@ -321,6 +321,39 @@ - result is changed - result.rowcount == [2] + # Issue https://github.com/ansible-collections/community.mysql/issues/268 + - name: Create table + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: "CREATE TABLE issue268 (id int)" + single_transaction: yes + + # Issue https://github.com/ansible-collections/community.mysql/issues/268 + - name: Create table with IF NOT EXISTS + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: "CREATE TABLE IF NOT EXISTS issue268 (id int)" + single_transaction: yes + register: result + + # Issue https://github.com/ansible-collections/community.mysql/issues/268 + - assert: + that: + # PyMySQL driver throws a warning, so the following is correct + - result is not changed + when: connector.name.0 is search('pymysql') + + # Issue https://github.com/ansible-collections/community.mysql/issues/268 + - assert: + that: + # mysqlclient driver throws nothing, so it's impossible to figure out + # if the state was changed or not. + # We assume that it was for DDL queryes by default in the code + - result is changed + when: connector.name.0 is search('mysqlclient') + - name: Drop db {{ test_db }} mysql_query: <<: *mysql_params