From 59ee5a78c931cf1cdff1093eded50b990ab8c468 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 16 Nov 2016 10:23:09 +0200 Subject: [PATCH] MXS-969: Report user var modifications properly User variable modifications are now reported as QUERY_TYPE_USERVAR_WRITE and not as QUERY_TYPE_GSYSVAR_WRITE as earlier. --- .../qc_mysqlembedded/qc_mysqlembedded.cc | 134 ++++++++++++++++-- query_classifier/qc_sqlite/qc_sqlite.c | 128 ++++++++++------- query_classifier/test/expected.sql | 1 - query_classifier/test/input.sql | 1 - .../test/qc_sqlite_unsupported.test | 9 ++ query_classifier/test/set.test | 87 ++++++++---- server/core/query_classifier.c | 13 +- server/include/query_classifier.h | 3 +- utils/skygw_debug.h | 3 +- 9 files changed, 282 insertions(+), 97 deletions(-) diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index 3fd8573ba..b7383a2b1 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -87,7 +87,7 @@ typedef struct parsing_info_st static THD* get_or_create_thd_for_parsing(MYSQL* mysql, char* query_str); static unsigned long set_client_flags(MYSQL* mysql); static bool create_parse_tree(THD* thd); -static uint32_t resolve_query_type(THD* thd); +static uint32_t resolve_query_type(parsing_info_t*, THD* thd); static bool skygw_stmt_causes_implicit_commit(LEX* lex, int* autocommit_stmt); static int is_autocommit_stmt(LEX* lex); @@ -167,7 +167,7 @@ uint32_t qc_get_type(GWBUF* querybuf) /** Find out the query type */ if (mysql != NULL) { - qtype = resolve_query_type((THD *) mysql->thd); + qtype = resolve_query_type(pi, (THD *) mysql->thd); } } } @@ -435,9 +435,102 @@ return_here: return failp; } +/** + * Sniff whether the statement is + * + * SET ROLE ... + * SET NAMES ... + * SET PASSWORD ... + * SET CHARACTER ... + * + * Depending on what kind of SET statement it is, the parser of the embedded + * library creates instances of set_var_user, set_var, set_var_password, + * set_var_role, etc. that all are derived from set_var_base. However, there + * is no type-information available in set_var_base, which is the type of the + * instances when accessed from the lexer. Consequently, we cannot know what + * kind of statment it is based on that, only whether it is a system variable + * or not. + * + * Consequently, we just look at the string and deduce whether it is a + * set [ROLE|NAMES|PASSWORD|CHARACTER] statement. + */ +bool is_set_specific(const char* s) +{ + bool rv = false; + + // Remove space from the beginning. + while (isspace(*s)) + { + ++s; + } + + const char* token = s; + + // Find next non-space character. + while (!isspace(*s) && (*s != 0)) + { + ++s; + } + + if (s - token == 3) // Might be "set" + { + if (strncasecmp(token, "set", 3) == 0) + { + // YES it was! + while (isspace(*s)) + { + ++s; + } + + token = s; + + while (!isspace(*s) && (*s != 0) && (*s != '=')) + { + ++s; + } + + if (s - token == 4) // Might be "role" + { + if (strncasecmp(token, "role", 4) == 0) + { + // YES it was! + rv = true; + } + } + else if (s - token == 5) // Might be "names" + { + if (strncasecmp(token, "names", 5) == 0) + { + // YES it was! + rv = true; + } + } + else if (s - token == 8) // Might be "password + { + if (strncasecmp(token, "password", 8) == 0) + { + // YES it was! + rv = true; + } + } + else if (s - token == 9) // Might be "character" + { + if (strncasecmp(token, "character", 9) == 0) + { + // YES it was! + rv = true; + } + } + } + } + + return rv; +} + /** * Detect query type by examining parsed representation of it. * + * @param pi The parsing info. * @param thd MariaDB thread context. * * @return Copy of query type value. @@ -449,7 +542,7 @@ return_here: * the resulting type may be different. * */ -static uint32_t resolve_query_type(THD* thd) +static uint32_t resolve_query_type(parsing_info_t *pi, THD* thd) { qc_query_type_t qtype = QUERY_TYPE_UNKNOWN; uint32_t type = QUERY_TYPE_UNKNOWN; @@ -565,7 +658,33 @@ static uint32_t resolve_query_type(THD* thd) else if (lex->sql_command == SQLCOM_SET_OPTION) { /** Either user- or system variable write */ - type |= QUERY_TYPE_GSYSVAR_WRITE; + if (is_set_specific(pi->pi_query_plain_str)) + { + type |= QUERY_TYPE_GSYSVAR_WRITE; + } + else + { + List_iterator ilist(lex->var_list); + size_t n = 0; + + while (set_var_base *var = ilist++) + { + if (var->is_system()) + { + type |= QUERY_TYPE_GSYSVAR_WRITE; + } + else + { + type |= QUERY_TYPE_USERVAR_WRITE; + } + ++n; + } + + if (n == 0) + { + type |= QUERY_TYPE_GSYSVAR_WRITE; + } + } } goto return_qtype; @@ -812,12 +931,7 @@ static uint32_t resolve_query_type(THD* thd) /** User-defined variable modification */ case Item_func::SUSERVAR_FUNC: - /** - * Really it is user variable but we - * don't separate sql variables atm. - * 15.9.14 - */ - func_qtype |= QUERY_TYPE_GSYSVAR_WRITE; + func_qtype |= QUERY_TYPE_USERVAR_WRITE; MXS_DEBUG("%lu [resolve_query_type] " "functype SUSERVAR_FUNC, user " "variable write.", diff --git a/query_classifier/qc_sqlite/qc_sqlite.c b/query_classifier/qc_sqlite/qc_sqlite.c index 33d67de28..f96b4cf57 100644 --- a/query_classifier/qc_sqlite/qc_sqlite.c +++ b/query_classifier/qc_sqlite/qc_sqlite.c @@ -746,8 +746,7 @@ static void update_affected_fields(QC_SQLITE_INFO* info, { if ((prev_token == TK_EQ) && (pos == QC_TOKEN_LEFT)) { - // Yes, QUERY_TYPE_USERVAR_WRITE is currently not available. - info->types |= QUERY_TYPE_GSYSVAR_WRITE; + info->types |= QUERY_TYPE_USERVAR_WRITE; } else { @@ -2036,6 +2035,7 @@ void maxscaleSet(Parse* pParse, int scope, mxs_set_t kind, ExprList* pList) ss_dassert(info); info->status = QC_QUERY_PARSED; + info->types = 0; // Reset what was set in maxscaleKeyword switch (kind) { @@ -2053,10 +2053,6 @@ void maxscaleSet(Parse* pParse, int scope, mxs_set_t kind, ExprList* pList) case MXS_SET_VARIABLES: { - // TODO: qc_mysqlembedded sets this bit on, without checking what - // TODO: kind of variable it is. - info->types = QUERY_TYPE_GSYSVAR_WRITE; - for (int i = 0; i < pList->nExpr; ++i) { const struct ExprList_item* pItem = &pList->a[i]; @@ -2065,19 +2061,48 @@ void maxscaleSet(Parse* pParse, int scope, mxs_set_t kind, ExprList* pList) { case TK_CHARACTER: case TK_NAMES: + info->types |= QUERY_TYPE_GSYSVAR_WRITE; break; case TK_EQ: { const Expr* pEq = pItem->pExpr; - const Expr* pVariable = pEq->pLeft; + const Expr* pVariable; const Expr* pValue = pEq->pRight; - // pVariable is either TK_DOT, TK_VARIABLE or TK_ID. If it's TK_DOT, - // then pVariable->pLeft is either TK_VARIABLE or TK_ID and pVariable->pRight + // pEq->pLeft is either TK_DOT, TK_VARIABLE or TK_ID. If it's TK_DOT, + // then pEq->pLeft->pLeft is either TK_VARIABLE or TK_ID and pEq->pLeft->pRight // is either TK_DOT, TK_VARIABLE or TK_ID. + // Find the left-most part. + pVariable = pEq->pLeft; + while (pVariable->op == TK_DOT) + { + pVariable = pVariable->pLeft; + ss_dassert(pVariable); + } + + // Check what kind of variable it is. + size_t n_at = 0; + const char* zName = pVariable->u.zToken; + + while (*zName == '@') + { + ++n_at; + ++zName; + } + + if (n_at == 1) + { + info->types |= QUERY_TYPE_USERVAR_WRITE; + } + else + { + info->types |= QUERY_TYPE_GSYSVAR_WRITE; + } + // Set pVariable to point to the rightmost part of the name. + pVariable = pEq->pLeft; while (pVariable->op == TK_DOT) { pVariable = pVariable->pRight; @@ -2085,54 +2110,59 @@ void maxscaleSet(Parse* pParse, int scope, mxs_set_t kind, ExprList* pList) ss_dassert((pVariable->op == TK_VARIABLE) || (pVariable->op == TK_ID)); - const char* zName = pVariable->u.zToken; - - while (*zName == '@') + if (n_at != 1) { - ++zName; - } + // If it's not a user-variable we need to check whether it might + // be 'autocommit'. + const char* zName = pVariable->u.zToken; - // As pVariable points to the rightmost part, we'll catch both - // "autocommit" and "@@global.autocommit". - if (strcasecmp(zName, "autocommit") == 0) - { - int enable = -1; - - switch (pValue->op) + while (*zName == '@') { - case TK_INTEGER: - if (pValue->u.iValue == 1) - { - enable = 1; - } - else if (pValue->u.iValue == 0) - { - enable = 0; - } - break; - - case TK_ID: - enable = string_to_truth(pValue->u.zToken); - break; - - default: - break; + ++zName; } - switch (enable) + // As pVariable points to the rightmost part, we'll catch both + // "autocommit" and "@@global.autocommit". + if (strcasecmp(zName, "autocommit") == 0) { - case 0: - info->types |= QUERY_TYPE_BEGIN_TRX; - info->types |= QUERY_TYPE_DISABLE_AUTOCOMMIT; - break; + int enable = -1; - case 1: - info->types |= QUERY_TYPE_ENABLE_AUTOCOMMIT; - info->types |= QUERY_TYPE_COMMIT; - break; + switch (pValue->op) + { + case TK_INTEGER: + if (pValue->u.iValue == 1) + { + enable = 1; + } + else if (pValue->u.iValue == 0) + { + enable = 0; + } + break; - default: - break; + case TK_ID: + enable = string_to_truth(pValue->u.zToken); + break; + + default: + break; + } + + switch (enable) + { + case 0: + info->types |= QUERY_TYPE_BEGIN_TRX; + info->types |= QUERY_TYPE_DISABLE_AUTOCOMMIT; + break; + + case 1: + info->types |= QUERY_TYPE_ENABLE_AUTOCOMMIT; + info->types |= QUERY_TYPE_COMMIT; + break; + + default: + break; + } } } diff --git a/query_classifier/test/expected.sql b/query_classifier/test/expected.sql index e5b7239bc..fd67bcc91 100644 --- a/query_classifier/test/expected.sql +++ b/query_classifier/test/expected.sql @@ -4,7 +4,6 @@ QUERY_TYPE_WRITE QUERY_TYPE_WRITE QUERY_TYPE_WRITE|QUERY_TYPE_COMMIT QUERY_TYPE_WRITE|QUERY_TYPE_CREATE_TMP_TABLE -QUERY_TYPE_GSYSVAR_WRITE QUERY_TYPE_READ|QUERY_TYPE_SYSVAR_READ QUERY_TYPE_READ|QUERY_TYPE_USERVAR_READ QUERY_TYPE_GSYSVAR_WRITE|QUERY_TYPE_ENABLE_AUTOCOMMIT|QUERY_TYPE_COMMIT diff --git a/query_classifier/test/input.sql b/query_classifier/test/input.sql index d9f2473b3..450bf81c8 100644 --- a/query_classifier/test/input.sql +++ b/query_classifier/test/input.sql @@ -4,7 +4,6 @@ insert into tst values ("Jane","Doe"),("Daisy","Duck"),("Marie","Curie"); update tst set fname="Farmer", lname="McDonald" where lname="%Doe" and fname="John"; create table tmp as select * from t1; create temporary table tmp as select * from t1; -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; select @@server_id; select @OLD_SQL_NOTES; SET autocommit=1; diff --git a/query_classifier/test/qc_sqlite_unsupported.test b/query_classifier/test/qc_sqlite_unsupported.test index 49480924a..be724cf7c 100644 --- a/query_classifier/test/qc_sqlite_unsupported.test +++ b/query_classifier/test/qc_sqlite_unsupported.test @@ -20,3 +20,12 @@ SET @x:= (SELECT h FROM t1 WHERE (a,b,c,d,e,f,g)=(1,2,3,4,5,6,7)); # REMOVE: expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);} # REMOVE: expr(A) ::= LP expr(X) COMMA(OP) expr(Y) RP. {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} # ADD : expr(A) ::= LP exprlist RP. { ... } + +SET @`a b`='hello'; +set @`test`=1; +set @"tEST"=3; +set @`TeST`=4; +# warning: qc_sqlite: Statement was classified only based on keywords +# (Sqlite3 error: SQL logic error or missing database, unrecognized token: "@"): "set @=4" +# +# sqlite3GetToken needs to be modified to accept a quoted variable name. \ No newline at end of file diff --git a/query_classifier/test/set.test b/query_classifier/test/set.test index 04b8a68c1..d82597526 100644 --- a/query_classifier/test/set.test +++ b/query_classifier/test/set.test @@ -271,7 +271,8 @@ SET timestamp=UNIX_TIMESTAMP('2014-09-30 08:00:00'); SET ROLE role_1; SET ROLE NONE; SET @sum=0; -SET @old_debug= @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @old_debug= @@session.debug; set debug_dbug='+d,send_kill_after_delete'; set debug_dbug=@old_debug; set local sql_mode=""; @@ -398,7 +399,8 @@ SET collation_connection=gb2312_chinese_ci; set names gb2312; set collation_connection=gb2312_bin; SET NAMES gbk; -SET @`tcontent`:=_binary 0x50434B000900000000000000E9000000 COLLATE `binary`/*!*/; +# MXSTODO qc_sqlite can not parse quoted variables. +# MXSTODO SET @`tcontent`:=_binary 0x50434B000900000000000000E9000000 COLLATE `binary`/*!*/; SET @test_character_set= 'gbk'; SET @test_collation= 'gbk_chinese_ci'; SET NAMES gbk; @@ -1487,7 +1489,8 @@ set global event_scheduler=on; set global event_scheduler=off; set global event_scheduler=original; set global event_scheduler=on; -SET @event_scheduler=@@global.event_scheduler; +# MXS Embedded parser is not aware of the 'global.event_scheduler' variable. +# MXS SET @event_scheduler=@@global.event_scheduler; SET GLOBAL event_scheduler=OFF; SET GLOBAL event_scheduler=OFF; SET GLOBAL event_scheduler=1; @@ -1500,7 +1503,8 @@ SET GLOBAL event_scheduler=2; SET GLOBAL event_scheduler=5; SET GLOBAL event_scheduler=ON; SET GLOBAL event_scheduler=@event_scheduler; -SET @old_event_scheduler=@@event_scheduler; +# MXS Embedded parser is not aware of the 'global.event_scheduler' variable. +# MXS SET @old_event_scheduler=@@event_scheduler; SET GLOBAL event_scheduler=on; SET GLOBAL event_scheduler=off; SET GLOBAL event_scheduler=on; @@ -1574,7 +1578,8 @@ set time_zone= @@global.time_zone; set @a:=0; SET @xml='a1b1c1b2a2'; SET sql_mode=STRICT_TRANS_TABLES; -SET @old_debug= @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @old_debug= @@session.debug; SET session debug_dbug= '+d,alloc_sort_buffer_fail'; SET session debug_dbug= @old_debug; SET DEBUG_SYNC='filesort_start SIGNAL filesort_started WAIT_FOR filesort_killed'; @@ -1587,7 +1592,8 @@ set global expire_logs_days = 0; SET AUTOCOMMIT=0; SET AUTOCOMMIT=1; set sql_mode=""; -SET @old_innodb_file_per_table= @@GLOBAL.innodb_file_per_table; +# MXS Embedded parser is not aware of innodb. +# MXS SET @old_innodb_file_per_table= @@GLOBAL.innodb_file_per_table; SET GLOBAL innodb_file_per_table= 1; SET @export = 10; SET GLOBAL innodb_file_per_table= @old_innodb_file_per_table; @@ -2267,7 +2273,8 @@ set join_cache_level= @tmp_mdev5037; set @@join_cache_level= @save_join_cache_level; set storage_engine=@save_storage_engine; set optimizer_switch=@innodb_mrr_cpk_tmp; -set @old_innodb_lock_wait_timeout=@@global.innodb_lock_wait_timeout; +# MXS Embedded parser is not aware of innodb. +# MXS SET set @old_innodb_lock_wait_timeout=@@global.innodb_lock_wait_timeout; set global innodb_lock_wait_timeout=300; set session innodb_lock_wait_timeout=300; set @@autocommit=0; @@ -2414,8 +2421,10 @@ set @value= "1aa"; set @value= "aa1"; set @value= "1e+1111111111a"; set @value= "-1e+1111111111a"; -set @value= 1e+1111111111; -set @value= -1e+1111111111; +# MXS ERROR 1367 (22007): Illegal double '1e+1111111111' value found during parsing +# MXS set @value= 1e+1111111111; +# MXS ERROR 1367 (22007): Illegal double '1e+1111111111' value found during parsing +# MXS set @value= -1e+1111111111; set @value= 1e+111; set @value= -1e+111; set @value= 1; @@ -3389,7 +3398,8 @@ SET DEBUG_SYNC= 'RESET'; set @default_storage_engine= @@global.storage_engine; set global storage_engine=myisam; set session storage_engine=myisam; -SET @orig_debug=@@debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @orig_debug=@@debug; SET GLOBAL debug_dbug="+d,myisam_pretend_crashed_table_on_open"; SET GLOBAL debug_dbug=@orig_debug; set global storage_engine=@default_storage_engine; @@ -3416,7 +3426,8 @@ SET NAMES latin1; set autocommit=0; set autocommit=1; set @mrr_icp_extra_tmp=@@optimizer_switch; -SET @aux = @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @aux = @@session.debug; set @d=4; set sql_safe_updates=1; set sql_safe_updates=0; @@ -3774,15 +3785,19 @@ SET GLOBAL general_log = 0; SET @@global.general_log = @old_general_log_state; SET @old_default_storage_engine = @@default_storage_engine; SET @@default_storage_engine = 'InnoDB'; -SET @save_innodb_stats_on_metadata=@@global.innodb_stats_on_metadata; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @save_innodb_stats_on_metadata=@@global.innodb_stats_on_metadata; SET @@global.innodb_stats_on_metadata=ON; SET @@global.innodb_stats_on_metadata=@save_innodb_stats_on_metadata; SET @@default_storage_engine = @old_default_storage_engine; set sql_mode=""; set sql_mode=default; -SET @old_innodb_file_format = @@global.innodb_file_format; -SET @old_innodb_file_per_table = @@global.innodb_file_per_table; -SET @old_innodb_strict_mode = @@global.innodb_strict_mode; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @old_innodb_file_format = @@global.innodb_file_format; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @old_innodb_file_per_table = @@global.innodb_file_per_table; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @old_innodb_strict_mode = @@global.innodb_strict_mode; SET @@global.innodb_file_format = Barracuda, @@global.innodb_file_per_table = ON, @@global.innodb_strict_mode = ON; @@ -3817,8 +3832,10 @@ SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; set global default_storage_engine='innodb'; set session default_storage_engine='innodb'; -SET @old_innodb_thread_concurrency := @@innodb_thread_concurrency; -SET @old_innodb_thread_sleep_delay := @@innodb_thread_sleep_delay; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @old_innodb_thread_concurrency := @@innodb_thread_concurrency; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @old_innodb_thread_sleep_delay := @@innodb_thread_sleep_delay; SET GLOBAL innodb_thread_concurrency = 1; SET GLOBAL innodb_thread_concurrency = @old_innodb_thread_concurrency; SET GLOBAL innodb_thread_sleep_delay = @old_innodb_thread_sleep_delay; @@ -4825,7 +4842,8 @@ SET optimizer_switch=@save_optimizer_switch; SET @pass='my_pw'; SET @wrong='incorrect'; set sql_mode=""; -set @save_debug_dbug= @@debug_dbug; +# MXS ERROR 1193 (HY000): Unknown system variable 'debug_dbug' +# MXS set @save_debug_dbug= @@debug_dbug; set @@debug_dbug= @save_debug_dbug; set @@debug_dbug= @save_debug_dbug; set gtid_domain_id = 10; @@ -4943,7 +4961,8 @@ SET NAMES latin1; SET NAMES latin1; SET NAMES utf8; SET NAMES latin1; -SET @old_debug= @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @old_debug= @@session.debug; set debug_sync='RESET'; set debug_dbug='+d,show_explain_probe_delete_exec_start'; set @show_explain_probe_select_id=1; @@ -4954,9 +4973,11 @@ set debug_sync='RESET'; set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_start'; set debug_dbug=''; -SET @old_debug= @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @old_debug= @@session.debug; set debug_sync='RESET'; -SET @old_debug= @@session.debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @old_debug= @@session.debug; set @show_explain_probe_select_id=1; set debug_dbug='+d,show_explain_probe_join_exec_start'; set @show_expl_tmp= @@optimizer_switch; @@ -5169,7 +5190,8 @@ set @@max_sp_recursion_depth= 20; set @@max_sp_recursion_depth= 0; SET sql_mode=ONLY_FULL_GROUP_BY; SET @lock_wait_timeout_saved= @@lock_wait_timeout; -SET @innodb_lock_wait_timeout_saved= @@innodb_lock_wait_timeout; +# MXS Embedded parser is not aware of innodb. +# MXS SET SET @innodb_lock_wait_timeout_saved= @@innodb_lock_wait_timeout; SET @@lock_wait_timeout= 1; SET @@innodb_lock_wait_timeout= 1; SET AUTOCOMMIT= 0; @@ -5815,7 +5837,8 @@ set @@optimizer_switch= default; set optimizer_switch='subquery_cache=on'; SET optimizer_switch=@save_optimizer_switch; set @@optimizer_switch= default; -SET @orig_debug=@@debug; +# MXS Embedded parser is not aware of the 'debug' variable. +# MXS SET @orig_debug=@@debug; SET GLOBAL debug_dbug="d,subselect_exec_fail"; SET GLOBAL debug_dbug=@orig_debug; set @subselect_mat_cost=@@optimizer_switch; @@ -6886,7 +6909,8 @@ set @@autocommit=0; set @@autocommit=1; set @@global.general_log=@save_general_log; SET TIMESTAMP=10000; -SET @`a b`='hello'; +# MXSTODO qc_sqlite can not parse quoted variables. +# MXSTODO SET @`a b`='hello'; set @var1= "';aaa"; SET @var2=char(ascii('a')); set @a := foo; @@ -6899,7 +6923,8 @@ set @a=_latin2'test'; set @a=_latin2'test' collate latin2_general_ci; set @var= NULL ; set @v1=null, @v2=1, @v3=1.1, @v4=now(); -set session @honk=99; +# 'set session @honk = 99' is not legal. +# MXS set session @honk=99; set @first_var= NULL; set @first_var= cast(NULL as signed integer); set @first_var= NULL; @@ -6928,7 +6953,8 @@ SET @aux = NULL; SET @bug12408412=1; SET @var=NULL; set @var= repeat('a',20000); -set @my_slave_net_timeout =@@global.slave_net_timeout; +# MXS Embedded parser is not aware of the 'global.slave_net_timeout' variable. +# MXS SET set @my_slave_net_timeout =@@global.slave_net_timeout; set global slave_net_timeout=100; set global sql_slave_skip_counter=100; set global slave_net_timeout=default; @@ -6987,10 +7013,13 @@ set @my_max_allowed_packet =@@global.max_allowed_packet; set @my_delay_key_write =@@global.delay_key_write; set @my_join_buffer_size =@@global.join_buffer_size; set @my_log_warnings =@@global.log_warnings; -set @`test`=1; +# MXSTODO qc_sqlite can not parse quoted variables. +# MXSTODO set @`test`=1; set @TEST=2; -set @"tEST"=3; -set @`TeST`=4; +# MXSTODO qc_sqlite can not parse quoted variables. +# MXSTODO set @"tEST"=3; +# MXSTODO qc_sqlite can not parse quoted variables. +# MXSTODO set @`TeST`=4; set @select=2,@t5=1.23456; set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL; set @test_int="hello",@test_double="hello",@test_string="hello",@test_string2="hello"; diff --git a/server/core/query_classifier.c b/server/core/query_classifier.c index 91dc1df3d..1d0723cbf 100644 --- a/server/core/query_classifier.c +++ b/server/core/query_classifier.c @@ -381,8 +381,14 @@ struct type_name_info type_to_type_name_info(qc_query_type_t type) } break; - /** Not implemented yet */ - //case QUERY_TYPE_USERVAR_WRITE: + case QUERY_TYPE_USERVAR_WRITE: + { + static const char name[] = "QUERY_TYPE_USERVAR_WRITE"; + info.name = name; + info.name_len = sizeof(name) - 1; + } + break; + case QUERY_TYPE_USERVAR_READ: { static const char name[] = "QUERY_TYPE_USERVAR_READ"; @@ -549,8 +555,7 @@ static const qc_query_type_t QUERY_TYPES[] = QUERY_TYPE_WRITE, QUERY_TYPE_MASTER_READ, QUERY_TYPE_SESSION_WRITE, - /** Not implemented yet */ - //QUERY_TYPE_USERVAR_WRITE, + QUERY_TYPE_USERVAR_WRITE, QUERY_TYPE_USERVAR_READ, QUERY_TYPE_SYSVAR_READ, /** Not implemented yet */ diff --git a/server/include/query_classifier.h b/server/include/query_classifier.h index ee434c295..ce60e798a 100644 --- a/server/include/query_classifier.h +++ b/server/include/query_classifier.h @@ -26,8 +26,7 @@ typedef enum QUERY_TYPE_WRITE = 0x000004, /*< Master data will be modified:master */ QUERY_TYPE_MASTER_READ = 0x000008, /*< Read from the master:master */ QUERY_TYPE_SESSION_WRITE = 0x000010, /*< Session data will be modified:master or all */ - /** Not implemented yet */ - //QUERY_TYPE_USERVAR_WRITE = 0x000020, /*< Write a user variable:master or all */ + QUERY_TYPE_USERVAR_WRITE = 0x000020, /*< Write a user variable:master or all */ QUERY_TYPE_USERVAR_READ = 0x000040, /*< Read a user variable:master or any */ QUERY_TYPE_SYSVAR_READ = 0x000080, /*< Read a system variable:master or any */ /** Not implemented yet */ diff --git a/utils/skygw_debug.h b/utils/skygw_debug.h index 15aa1b352..4fd321475 100644 --- a/utils/skygw_debug.h +++ b/utils/skygw_debug.h @@ -146,6 +146,7 @@ typedef enum skygw_chk_t ((t) == QUERY_TYPE_UNKNOWN ? "QUERY_TYPE_UNKNOWN" : \ ((t) == QUERY_TYPE_LOCAL_READ ? "QUERY_TYPE_LOCAL_READ" : \ ((t) == QUERY_TYPE_MASTER_READ ? "QUERY_TYPE_MASTER_READ" : \ + ((t) == QUERY_TYPE_USERVAR_WRITE ? "QUERY_TYPE_USERVAR_WRITE" : \ ((t) == QUERY_TYPE_USERVAR_READ ? "QUERY_TYPE_USERVAR_READ" : \ ((t) == QUERY_TYPE_SYSVAR_READ ? "QUERY_TYPE_SYSVAR_READ" : \ ((t) == QUERY_TYPE_GSYSVAR_READ ? "QUERY_TYPE_GSYSVAR_READ" : \ @@ -162,7 +163,7 @@ typedef enum skygw_chk_t ((t) == QUERY_TYPE_READ_TMP_TABLE ? "QUERY_TYPE_READ_TMP_TABLE" : \ ((t) == QUERY_TYPE_SHOW_DATABASES ? "QUERY_TYPE_SHOW_DATABASES" : \ ((t) == QUERY_TYPE_SHOW_TABLES ? "QUERY_TYPE_SHOW_TABLES" : \ - "Unknown query type")))))))))))))))))))))) + "Unknown query type"))))))))))))))))))))))) #define STRLOGPRIORITYNAME(n)\ ((n) == LOG_EMERG ? "LOG_EMERG" : \