Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql_mode can be set in session, therefore we should look for ANSI_QUOTES in session variable instead of global variable #677

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/module_utils/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class InvalidPrivsError(Exception):


def get_mode(cursor):
cursor.execute('SELECT @@GLOBAL.sql_mode')
cursor.execute('SELECT @@sql_mode')
result = cursor.fetchone()
mode_str = result[0]
if 'ANSI' in mode_str:
Expand Down
112 changes: 112 additions & 0 deletions tests/integration/targets/test_mysql_user/tasks/issue-671.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
# Due to https://bugs.mysql.com/bug.php?id=115953, in Mysql 8, if ANSI_QUOTES is enabled,
# backticks will be used instead of double quotes to quote functions or procedures name.
# As a consequence, mysql_user and mysql_roles will always report "changed" for functions
# and procedures no matter the privileges are granted or not.
# Workaround for the mysql bug 116953 is removing ANSI_QUOTES from the module's session
# sql_mode. But because issue 671, ANSI_QUOTES is always got from GLOBAL sql_mode, thus
# this workaround can't work. Even without the Mysql bug, because sql_mode in session
# precedes GLOBAL sql_mode. we should check for sql_mode in session variable instead of
# the GLOBAL one.
- vars:
mysql_parameters: &mysql_params
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'

block:
- name: Issue-671| test setup | drop database
mysql_db:
<<: *mysql_params
name: "{{ item }}"
state: absent
loop:
- foo
- bar

- name: Issue-671| test setup | create database
mysql_db:
<<: *mysql_params
name: "{{ item }}"
state: present
loop:
- foo
- bar

- name: Issue-671| test setup | get value of GLOBAL.sql_mode
mysql_query:
<<: *mysql_params
query: 'select @@GLOBAL.sql_mode AS sql_mode'
register: sql_mode_orig
Copy link
Collaborator

@Andersson007 Andersson007 Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
register: sql_mode_orig
register: sql_mode_orig

would you like to assert: this one too? I see you assert the second one called result

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, let me check and add the assert. by the way, due to some reasons, I will need to close this PR and open another via other account.


- name: Issue-671| enable sql_mode ANSI_QUOTES
mysql_variables:
<<: *mysql_params
variable: sql_mode
value: '{{ sql_mode_orig.query_result[0][0].sql_mode }},ANSI_QUOTES'
mode: "{% if db_engine == 'mariadb' %}global{% else %}persist{% endif %}"

- name: Issue-671| test setup | get value of GLOBAL.sql_mode
mysql_query:
<<: *mysql_params
query: 'select @@GLOBAL.sql_mode'

- name: Issue-671| Copy SQL scripts to remote
copy:
src: "{{ item }}"
dest: "{{ remote_tmp_dir }}/{{ item | basename }}"
with_items:
- create-function.sql
- create-procedure.sql

- name: Issue-671| Create function for test
shell: "{{ mysql_command }} < {{ remote_tmp_dir }}/create-function.sql"

- name: Issue-671| Create procedure for test
shell: "{{ mysql_command }} < {{ remote_tmp_dir }}/create-procedure.sql"

- name: Issue-671| Create user with FUNCTION and PROCEDURE privileges
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
password: '{{ user_password_2 }}'
state: present
priv: 'FUNCTION foo.function:EXECUTE/foo.*:SELECT/PROCEDURE bar.procedure:EXECUTE'

- name: Issue-671| Grant the privileges again, remove ANSI_QUOTES from the session variable
mysql_user:
<<: *mysql_params
session_vars:
sql_mode: ""
name: '{{ user_name_2 }}'
password: '{{ user_password_2 }}'
state: present
priv: 'FUNCTION foo.function:EXECUTE/foo.*:SELECT/PROCEDURE bar.procedure:EXECUTE'
register: result

- name: Issue-671| Assert Create user with FUNCTION and PROCEDURE privileges
assert:
that:
- result is success
- result is not changed

- name: Issue-671| Test teardown | cleanup databases
mysql_db:
<<: *mysql_params
name: "{{ item }}"
state: absent
loop:
- foo
- bar

- name: Issue-671| set sql_mode back to original value
mysql_variables:
<<: *mysql_params
variable: sql_mode
value: '{{ sql_mode_orig.query_result[0][0].sql_mode }}'
mode: "{% if db_engine == 'mariadb' %}global{% else %}persist{% endif %}"

- include_tasks: utils/remove_user.yml
vars:
user_name: "{{ user_name_2 }}"
4 changes: 4 additions & 0 deletions tests/integration/targets/test_mysql_user/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@
- import_tasks: issue-64560.yaml
tags:
- issue-64560

- import_tasks: issue-671.yaml
tags:
- issue-671

# Test that mysql_user still works with force_context enabled (database set to "mysql")
# (https://github.com/ansible-collections/community.mysql/issues/265)
Expand Down