236 lines
8.9 KiB
Go
236 lines
8.9 KiB
Go
package sa
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
)
|
|
|
|
var (
|
|
checkStringQuoteRE = regexp.MustCompile(`^'[0-9A-Za-z_\-=:]+'$`)
|
|
checkIntRE = regexp.MustCompile(`^\d+$`)
|
|
checkImproperIntRE = regexp.MustCompile(`^'\d+'$`)
|
|
checkNumericRE = regexp.MustCompile(`^\d+(\.\d+)?$`)
|
|
checkBooleanRE = regexp.MustCompile(`^([0-1])|(?i)(true|false)|(?i)(on|off)`)
|
|
)
|
|
|
|
// checkMariaDBSystemVariables validates a MariaDB config passed in via SA
|
|
// setDefault or DSN. This manually curated list of system variables was
|
|
// partially generated by a tool in issue #6687. An overview of the validations
|
|
// performed are:
|
|
//
|
|
// - Correct quoting for strings and string enums prevent future
|
|
// problems such as PR #6683 from occurring.
|
|
//
|
|
// - Regex validation is performed for the various booleans, floats, integers, and strings.
|
|
//
|
|
// Only session scoped variables should be included. A session variable is one
|
|
// that affects the current session only. Passing a session variable that only
|
|
// works in the global scope causes database connection error 1045.
|
|
// https://mariadb.com/kb/en/set/#global-session
|
|
func checkMariaDBSystemVariables(name string, value string) error {
|
|
// System variable names will be indexed into the appropriate hash sets
|
|
// below and can possibly exist in several sets.
|
|
|
|
// Check the list of currently known MariaDB string type system variables
|
|
// and determine if the value is a properly formatted string e.g.
|
|
// sql_mode='STRICT_TABLES'
|
|
mariaDBStringTypes := map[string]struct{}{
|
|
"character_set_client": {},
|
|
"character_set_connection": {},
|
|
"character_set_database": {},
|
|
"character_set_filesystem": {},
|
|
"character_set_results": {},
|
|
"character_set_server": {},
|
|
"collation_connection": {},
|
|
"collation_database": {},
|
|
"collation_server": {},
|
|
"debug/debug_dbug": {},
|
|
"debug_sync": {},
|
|
"enforce_storage_engine": {},
|
|
"external_user": {},
|
|
"lc_messages": {},
|
|
"lc_time_names": {},
|
|
"old_alter_table": {},
|
|
"old_mode": {},
|
|
"optimizer_switch": {},
|
|
"proxy_user": {},
|
|
"session_track_system_variables": {},
|
|
"sql_mode": {},
|
|
"time_zone": {},
|
|
}
|
|
|
|
if _, found := mariaDBStringTypes[name]; found {
|
|
if checkStringQuoteRE.FindString(value) != value {
|
|
return fmt.Errorf("%s=%s string is not properly quoted", name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MariaDB numerics which may either be integers or floats.
|
|
// https://mariadb.com/kb/en/numeric-data-type-overview/
|
|
mariaDBNumericTypes := map[string]struct{}{
|
|
"bulk_insert_buffer_size": {},
|
|
"default_week_format": {},
|
|
"eq_range_index_dive_limit": {},
|
|
"error_count": {},
|
|
"expensive_subquery_limit": {},
|
|
"group_concat_max_len": {},
|
|
"histogram_size": {},
|
|
"idle_readonly_transaction_timeout": {},
|
|
"idle_transaction_timeout": {},
|
|
"idle_write_transaction_timeout": {},
|
|
"in_predicate_conversion_threshold": {},
|
|
"insert_id": {},
|
|
"interactive_timeout": {},
|
|
"join_buffer_size": {},
|
|
"join_buffer_space_limit": {},
|
|
"join_cache_level": {},
|
|
"last_insert_id": {},
|
|
"lock_wait_timeout": {},
|
|
"log_slow_min_examined_row_limit": {},
|
|
"log_slow_query_time": {},
|
|
"log_slow_rate_limit": {},
|
|
"long_query_time": {},
|
|
"max_allowed_packet": {},
|
|
"max_delayed_threads": {},
|
|
"max_digest_length": {},
|
|
"max_error_count": {},
|
|
"max_heap_table_size": {},
|
|
"max_join_size": {},
|
|
"max_length_for_sort_data": {},
|
|
"max_recursive_iterations": {},
|
|
"max_rowid_filter_size": {},
|
|
"max_seeks_for_key": {},
|
|
"max_session_mem_used": {},
|
|
"max_sort_length": {},
|
|
"max_sp_recursion_depth": {},
|
|
"max_statement_time": {},
|
|
"max_user_connections": {},
|
|
"min_examined_row_limit": {},
|
|
"mrr_buffer_size": {},
|
|
"net_buffer_length": {},
|
|
"net_read_timeout": {},
|
|
"net_retry_count": {},
|
|
"net_write_timeout": {},
|
|
"optimizer_extra_pruning_depth": {},
|
|
"optimizer_max_sel_arg_weight": {},
|
|
"optimizer_prune_level": {},
|
|
"optimizer_search_depth": {},
|
|
"optimizer_selectivity_sampling_limit": {},
|
|
"optimizer_trace_max_mem_size": {},
|
|
"optimizer_use_condition_selectivity": {},
|
|
"preload_buffer_size": {},
|
|
"profiling_history_size": {},
|
|
"progress_report_time": {},
|
|
"pseudo_slave_mode": {},
|
|
"pseudo_thread_id": {},
|
|
"query_alloc_block_size": {},
|
|
"query_prealloc_size": {},
|
|
"rand_seed1": {},
|
|
"range_alloc_block_size": {},
|
|
"read_rnd_buffer_size": {},
|
|
"rowid_merge_buff_size": {},
|
|
"sql_select_limit": {},
|
|
"tmp_disk_table_size": {},
|
|
"tmp_table_size": {},
|
|
"transaction_alloc_block_size": {},
|
|
"transaction_prealloc_size": {},
|
|
"wait_timeout": {},
|
|
"warning_count": {},
|
|
}
|
|
|
|
if _, found := mariaDBNumericTypes[name]; found {
|
|
if checkNumericRE.FindString(value) != value {
|
|
return fmt.Errorf("%s=%s requires a numeric value, but is not formatted like a number", name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Certain MariaDB enums can have both string and integer values.
|
|
mariaDBIntEnumTypes := map[string]struct{}{
|
|
"completion_type": {},
|
|
"query_cache_type": {},
|
|
}
|
|
|
|
mariaDBStringEnumTypes := map[string]struct{}{
|
|
"completion_type": {},
|
|
"default_regex_flags": {},
|
|
"default_storage_engine": {},
|
|
"default_tmp_storage_engine": {},
|
|
"histogram_type": {},
|
|
"log_slow_filter": {},
|
|
"log_slow_verbosity": {},
|
|
"optimizer_trace": {},
|
|
"query_cache_type": {},
|
|
"session_track_transaction_info": {},
|
|
"transaction_isolation": {},
|
|
"tx_isolation": {},
|
|
"use_stat_tables": {},
|
|
}
|
|
|
|
// Check the list of currently known MariaDB enumeration type system
|
|
// variables and determine if the value is either:
|
|
// 1) A properly formatted integer e.g. completion_type=1
|
|
if _, found := mariaDBIntEnumTypes[name]; found {
|
|
if checkIntRE.FindString(value) == value {
|
|
return nil
|
|
}
|
|
if checkImproperIntRE.FindString(value) == value {
|
|
return fmt.Errorf("%s=%s integer enum is quoted, but should not be", name, value)
|
|
}
|
|
}
|
|
|
|
// 2) A properly formatted string e.g. completion_type='CHAIN'
|
|
if _, found := mariaDBStringEnumTypes[name]; found {
|
|
if checkStringQuoteRE.FindString(value) != value {
|
|
return fmt.Errorf("%s=%s string enum is not properly quoted", name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MariaDB booleans can be (0, false) or (1, true).
|
|
// https://mariadb.com/kb/en/boolean/
|
|
mariaDBBooleanTypes := map[string]struct{}{
|
|
"autocommit": {},
|
|
"big_tables": {},
|
|
"check_constraint_checks": {},
|
|
"foreign_key_checks": {},
|
|
"in_transaction": {},
|
|
"keep_files_on_create": {},
|
|
"log_slow_query": {},
|
|
"low_priority_updates": {},
|
|
"old": {},
|
|
"old_passwords": {},
|
|
"profiling": {},
|
|
"query_cache_strip_comments": {},
|
|
"query_cache_wlock_invalidate": {},
|
|
"session_track_schema": {},
|
|
"session_track_state_change": {},
|
|
"slow_query_log": {},
|
|
"sql_auto_is_null": {},
|
|
"sql_big_selects": {},
|
|
"sql_buffer_result": {},
|
|
"sql_if_exists": {},
|
|
"sql_log_off": {},
|
|
"sql_notes": {},
|
|
"sql_quote_show_create": {},
|
|
"sql_safe_updates": {},
|
|
"sql_warnings": {},
|
|
"standard_compliant_cte": {},
|
|
"tcp_nodelay": {},
|
|
"transaction_read_only": {},
|
|
"tx_read_only": {},
|
|
"unique_checks": {},
|
|
"updatable_views_with_limit": {},
|
|
}
|
|
|
|
if _, found := mariaDBBooleanTypes[name]; found {
|
|
if checkBooleanRE.FindString(value) != value {
|
|
return fmt.Errorf("%s=%s expected boolean value", name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("%s=%s was unexpected", name, value)
|
|
}
|