diff --git a/changelogs/fragments/53-mysql_query_fix_single_query_with_commas.yml b/changelogs/fragments/53-mysql_query_fix_single_query_with_commas.yml new file mode 100644 index 0000000..8bcd1c5 --- /dev/null +++ b/changelogs/fragments/53-mysql_query_fix_single_query_with_commas.yml @@ -0,0 +1,2 @@ +bugfixes: +- mysql_query - fix failing when single-row query contains commas (https://github.com/ansible-collections/community.mysql/issues/51). diff --git a/plugins/modules/mysql_query.py b/plugins/modules/mysql_query.py index 0101c20..e9664db 100644 --- a/plugins/modules/mysql_query.py +++ b/plugins/modules/mysql_query.py @@ -20,8 +20,8 @@ options: query: description: - SQL query to run. Multiple queries can be passed using YAML list syntax. - type: list - elements: str + - Must be a string or YAML list containing strings. + type: raw required: yes positional_args: description: @@ -42,8 +42,6 @@ options: - Where passed queries run in a single transaction (C(yes)) or commit them one-by-one (C(no)). type: bool default: no -notes: -- To pass a query containing commas, use YAML list notation with hyphen (see EXAMPLES block). author: - Andrew Klychkov (@Andersson007) extends_documentation_fragment: @@ -123,7 +121,7 @@ DDL_QUERY_KEYWORDS = ('CREATE', 'DROP', 'ALTER', 'RENAME', 'TRUNCATE') def main(): argument_spec = mysql_common_argument_spec() argument_spec.update( - query=dict(type='list', elements='str', required=True), + query=dict(type='raw', required=True), login_db=dict(type='str'), positional_args=dict(type='list'), named_args=dict(type='dict'), @@ -147,6 +145,17 @@ def main(): check_hostname = module.params['check_hostname'] config_file = module.params['config_file'] query = module.params["query"] + + if not isinstance(query, str) and not isinstance(query, list): + module.fail_json(msg="the query option value must be a string or list, passed %s" % type(query)) + + if isinstance(query, str): + query = [query] + + for elem in query: + if not isinstance(elem, str): + module.fail_json(msg="the elements in query list must be strings, passed '%s' %s" % (elem, type(elem))) + if module.params["single_transaction"]: autocommit = False else: @@ -183,6 +192,7 @@ def main(): query_result = [] executed_queries = [] rowcount = [] + for q in query: try: cursor.execute(q, arguments) diff --git a/tests/integration/targets/test_mysql_query/defaults/main.yml b/tests/integration/targets/test_mysql_query/defaults/main.yml index 5b92aae..51a3bd7 100644 --- a/tests/integration/targets/test_mysql_query/defaults/main.yml +++ b/tests/integration/targets/test_mysql_query/defaults/main.yml @@ -6,6 +6,7 @@ db_name: data test_db: testdb test_table1: test1 test_table2: test2 +test_table3: test3 test_script_path: /tmp/test.sql user_name_1: 'db_user1' 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 f9efdc6..b01de55 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 @@ -238,6 +238,57 @@ that: - result.rowcount == [0] + - name: Create {{ test_table3 }} + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: 'CREATE TABLE {{ test_table3 }} (id int, story text)' + + - name: Add data to {{ test_table3 }} + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: "INSERT INTO {{ test_table3 }} (id, story) VALUES (1, 'first'), (2, 'second')" + + - name: Select from {{ test_table3 }} + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: 'SELECT id, story FROM {{ test_table3 }}' + register: result + + - assert: + that: + - result.rowcount == [2] + + - name: Pass wrong query type + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: {'this type is': 'wrong'} + register: result + ignore_errors: yes + + - assert: + that: + - result is failed + - result.msg is search('the query option value must be a string or list') + + - name: Pass wrong query element + mysql_query: + <<: *mysql_params + login_db: '{{ test_db }}' + query: + - 'SELECT now()' + - {'this type is': 'wrong'} + register: result + ignore_errors: yes + + - assert: + that: + - result is failed + - result.msg is search('the elements in query list must be strings') + - name: Drop db {{ test_db }} mysql_query: <<: *mysql_params