diff --git a/changelogs/fragments/227-db-create-special-name.yaml b/changelogs/fragments/227-db-create-special-name.yaml new file mode 100644 index 000000000..b9399d16b --- /dev/null +++ b/changelogs/fragments/227-db-create-special-name.yaml @@ -0,0 +1,2 @@ +bugfixes: + mysql_db - Fix mismatch when database name contains a ``%`` character (https://github.com/ansible-collections/community.mysql/pull/227). diff --git a/plugins/modules/mysql_db.py b/plugins/modules/mysql_db.py index aa9ade061..c2a6fd801 100644 --- a/plugins/modules/mysql_db.py +++ b/plugins/modules/mysql_db.py @@ -330,7 +330,7 @@ def db_exists(cursor, db): res = 0 for each_db in db: - res += cursor.execute("SHOW DATABASES LIKE %s", (each_db.replace("_", r"\_"),)) + res += cursor.execute("SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = %s", (each_db,)) return res == len(db) @@ -519,7 +519,8 @@ def db_create(cursor, db, encoding, collation): query_params = dict(enc=encoding, collate=collation) res = 0 for each_db in db: - query = ['CREATE DATABASE %s' % mysql_quote_identifier(each_db, 'database')] + # Escape '%' since mysql cursor.execute() uses a format string + query = ['CREATE DATABASE %s' % mysql_quote_identifier(each_db, 'database').replace('%', '%%')] if encoding: query.append("CHARACTER SET %(enc)s") if collation: diff --git a/tests/integration/targets/test_mysql_db/tasks/db_create_special.yml b/tests/integration/targets/test_mysql_db/tasks/db_create_special.yml new file mode 100644 index 000000000..7b92c5930 --- /dev/null +++ b/tests/integration/targets/test_mysql_db/tasks/db_create_special.yml @@ -0,0 +1,86 @@ +# test code for mysql_db module with database name containing special chars +# (c) 2021, Nicolas Payart + +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# ============================================================ +- name: "Set db_name to db%" + set_fact: + db_name: "db%" + +- name: remove database if it exists + command: > + "{{ mysql_command }} -sse 'drop database {{ db_name }}'" + ignore_errors: True + +- name: make sure the test database is not there + command: "{{ mysql_command }} {{ db_name }}" + register: mysql_db_check + failed_when: "'1049' not in mysql_db_check.stderr" + +- name: test state=present for a database name (expect changed=true) + mysql_db: + login_user: '{{ mysql_user }}' + login_password: '{{ mysql_password }}' + login_host: 127.0.0.1 + login_port: '{{ mysql_primary_port }}' + name: '{{ db_name }}' + state: present + register: result + +- name: assert output message that database exist + assert: + that: + - result is changed + - result.db == '{{ db_name }}' + - result.executed_commands == ["CREATE DATABASE `{{ db_name }}`"] + +- name: run command to test state=present for a database name (expect db_name in stdout) + command: "{{ mysql_command }} -e \"show databases like '{{ db_name | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\"" + register: result + +- name: assert database exist + assert: + that: + - "'{{ db_name }}' in result.stdout" + +# ============================================================ +- name: test state=absent for a database name (expect changed=true) + mysql_db: + login_user: '{{ mysql_user }}' + login_password: '{{ mysql_password }}' + login_host: 127.0.0.1 + login_port: '{{ mysql_primary_port }}' + name: '{{ db_name }}' + state: absent + register: result + +- name: assert output message that database does not exist + assert: + that: + - result is changed + - result.db == '{{ db_name }}' + - result.executed_commands == ["DROP DATABASE `{{ db_name }}`"] + +- name: run command to test state=absent for a database name (expect db_name not in stdout) + command: "{{ mysql_command }} -e \"show databases like '{{ db_name | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\"" + register: result + +- name: assert database does not exist + assert: + that: + - "'{{ db_name }}' not in result.stdout" + diff --git a/tests/integration/targets/test_mysql_db/tasks/main.yml b/tests/integration/targets/test_mysql_db/tasks/main.yml index 139d5bbc6..c1a99bc38 100644 --- a/tests/integration/targets/test_mysql_db/tasks/main.yml +++ b/tests/integration/targets/test_mysql_db/tasks/main.yml @@ -324,3 +324,6 @@ when: ansible_python.version_info[0] >= 3 - include: issue-28.yml + +- include: db_create_special.yml +