From 811aa2611ede8e425f981a8c3a722dcbdb934bf3 Mon Sep 17 00:00:00 2001 From: Maykel Moya Date: Fri, 18 Oct 2013 12:35:40 +0200 Subject: [PATCH] Add support for string values The SET GLOBAL statement requires properly quoting of values. For example, the following correct queries will fail if quotes are toggled: mysql> SET GLOBAL innodb_lru_scan_depth = 2000; mysql> SET GLOBAL master_info_repository = "TABLE"; `mysql_variable` module doesn't quote the value argument, therefore string values will fail. # this task will pass, 2000 is passed without quotes - name: set a numeric value mysql_variable: variable=innodb_lru_scan_depth value=2000 # this task will fail, TABLE is passed without quotes - name: set a string value mysql_variable: variable=master_info_repository value=TABLE With this patch prepared statements are used. Proper quoting will be done automatically based on the type of the variables thus an attempt to convert to int, then to float is done in first place. Booleans values, ie: ON, OFF, are not specially handled because they can be quoted. For example, the following queries are correct and equivalent, they all set _innodb_file_per_table_ to logical _True_: mysql> SET GLOBAL innodb_file_per_table = "ON"; mysql> SET GLOBAL innodb_file_per_table = ON; mysql> SET GLOBAL innodb_file_per_table = 1; Tested in mysql 5.5 and 5.6. --- library/database/mysql_variables | 45 +++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/library/database/mysql_variables b/library/database/mysql_variables index 720478cc00..595e0bbb55 100644 --- a/library/database/mysql_variables +++ b/library/database/mysql_variables @@ -76,14 +76,48 @@ else: mysqldb_found = True +def typedvalue(value): + """ + Convert value to number whenever possible, return same value + otherwise. + + >>> typedvalue('3') + 3 + >>> typedvalue('3.0') + 3.0 + >>> typedvalue('foobar') + 'foobar' + + """ + try: + return int(value) + except ValueError: + pass + + try: + return float(value) + except ValueError: + pass + + return value + + def getvariable(cursor, mysqlvar): cursor.execute("SHOW VARIABLES LIKE '" + mysqlvar + "'") mysqlvar_val = cursor.fetchall() return mysqlvar_val + def setvariable(cursor, mysqlvar, value): + """ Set a global mysql variable to a given value + + The DB driver will handle quoting of the given value based on its + type, thus numeric strings like '3.0' or '8' are illegal, they + should be passed as numeric literals. + + """ try: - cursor.execute("SET GLOBAL " + mysqlvar + "=" + value) + cursor.execute("SET GLOBAL " + mysqlvar + " = %s", (value,)) cursor.fetchall() result = True except Exception, e: @@ -203,11 +237,14 @@ def main(): else: if len(mysqlvar_val) < 1: module.fail_json(msg="Variable not available", changed=False) - if value == mysqlvar_val[0][1]: + # Type values before using them + value_wanted = typedvalue(value) + value_actual = typedvalue(mysqlvar_val[0][1]) + if value_wanted == value_actual: module.exit_json(msg="Variable already set to requested value", changed=False) - result = setvariable(cursor, mysqlvar, value) + result = setvariable(cursor, mysqlvar, value_wanted) if result is True: - module.exit_json(msg="Variable change succeeded", changed=True) + module.exit_json(msg="Variable change succeeded prev_value=%s" % value_actual, changed=True) else: module.fail_json(msg=result, changed=False)