From c2add97e307bc1259a2f1800813ff3a81f21ebba Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 14 Mar 2017 17:13:46 +0200 Subject: [PATCH] Recognise various autocommit syntaxes set autocommit=1 set global autocommit=1 set session autocommit=1 set @@global.autocommit=1 set @@session.autocommit=1 --- server/core/maxscale/trxboundaryparser.hh | 146 +++++++++++++++++++--- server/core/test/testtrxtracking.cc | 5 + 2 files changed, 136 insertions(+), 15 deletions(-) diff --git a/server/core/maxscale/trxboundaryparser.hh b/server/core/maxscale/trxboundaryparser.hh index c83e0ec31..767fcb4d7 100644 --- a/server/core/maxscale/trxboundaryparser.hh +++ b/server/core/maxscale/trxboundaryparser.hh @@ -41,12 +41,17 @@ public: TK_COMMA, TK_COMMIT, TK_CONSISTENT, + TK_DOT, TK_EQ, TK_FALSE, + TK_GLOBAL, + TK_GLOBAL_VAR, TK_ONE, TK_ONLY, TK_READ, TK_ROLLBACK, + TK_SESSION, + TK_SESSION_VAR, TK_SET, TK_SNAPSHOT, TK_START, @@ -119,14 +124,16 @@ private: void log_unexpected() { - MXS_ERROR("In statement '%.*s', unexpected token at '%.*s'.", - (int)m_len, m_pSql, (int)(m_pEnd - m_pI), m_pI); +#ifdef SS_DEBUG + MXS_NOTICE("Transaction tracking: In statement '%.*s', unexpected token at '%.*s'.", + (int)m_len, m_pSql, (int)(m_pEnd - m_pI), m_pI); +#endif } void log_exhausted() { #ifdef SS_DEBUG - MXS_WARNING("More tokens expected in statement '%.*s'.", (int)m_len, m_pSql); + MXS_NOTICE("Transaction tracking: More tokens expected in statement '%.*s'.", (int)m_len, m_pSql); #endif } @@ -283,6 +290,45 @@ private: return type_mask; } + uint32_t parse_set_autocommit(uint32_t type_mask) + { + token_t token = next_token(TOKEN_REQUIRED); + + switch (token) + { + case TK_EQ: + token = next_token(TOKEN_REQUIRED); + if (token == TK_ONE || token == TK_TRUE) + { + type_mask |= (QUERY_TYPE_COMMIT | QUERY_TYPE_ENABLE_AUTOCOMMIT); + } + else if (token == TK_ZERO || token == TK_FALSE) + { + type_mask = (QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_DISABLE_AUTOCOMMIT); + } + else + { + type_mask = 0; + + if (token != PARSER_EXHAUSTED) + { + log_unexpected(); + } + } + break; + + case PARSER_EXHAUSTED: + type_mask = 0; + break; + + default: + type_mask = 0; + log_unexpected(); + } + + return type_mask; + } + uint32_t parse_set(uint32_t type_mask) { token_t token = next_token(TOKEN_REQUIRED); @@ -290,28 +336,52 @@ private: switch (token) { case TK_AUTOCOMMIT: - token = next_token(); - if (token == TK_EQ) + type_mask = parse_set_autocommit(type_mask); + break; + + case TK_GLOBAL: + case TK_SESSION: + token = next_token(TOKEN_REQUIRED); + if (token == TK_AUTOCOMMIT) { - token = next_token(); - if (token == TK_ONE || token == TK_TRUE) + type_mask = parse_set_autocommit(type_mask); + } + else + { + type_mask = 0; + if (token != PARSER_EXHAUSTED) { - type_mask |= (QUERY_TYPE_COMMIT | QUERY_TYPE_ENABLE_AUTOCOMMIT); + log_unexpected(); } - else if (token == TK_ZERO || token == TK_FALSE) + } + break; + + case TK_GLOBAL_VAR: + case TK_SESSION_VAR: + token = next_token(TOKEN_REQUIRED); + if (token == TK_DOT) + { + token = next_token(TOKEN_REQUIRED); + if (token == TK_AUTOCOMMIT) { - type_mask = (QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_DISABLE_AUTOCOMMIT); + type_mask = parse_set_autocommit(type_mask); } else { type_mask = 0; - log_unexpected(); + if (token != PARSER_EXHAUSTED) + { + log_unexpected(); + } } } else { type_mask = 0; - MXS_WARNING("Expected more."); + if (token != PARSER_EXHAUSTED) + { + log_unexpected(); + } } break; @@ -468,7 +538,7 @@ private: { const char* pNext = m_pI; - while ((pNext < m_pEnd) && isalpha(*pNext)) + while ((pNext < m_pEnd) && (isalpha(*pNext) || (*pNext == '@'))) { ++pNext; } @@ -627,6 +697,21 @@ private: { switch (*m_pI) { + case '@': + if (is_next_char('a', 2) || is_next_char('A', 2)) + { + token = expect_token(TBP_EXPECT_TOKEN("@@autocommit"), TK_AUTOCOMMIT); + } + if (is_next_char('s', 2) || is_next_char('S', 2)) + { + token = expect_token(TBP_EXPECT_TOKEN("@@session"), TK_SESSION_VAR); + } + else if (is_next_char('g', 2) || is_next_char('G', 2)) + { + token = expect_token(TBP_EXPECT_TOKEN("@@global"), TK_GLOBAL_VAR); + } + break; + case 'a': case 'A': token = expect_token(TBP_EXPECT_TOKEN("autocommit"), TK_AUTOCOMMIT); @@ -657,6 +742,11 @@ private: } break; + case '.': + ++m_pI; + token = TK_DOT; + break; + case '=': ++m_pI; token = TK_EQ; @@ -667,6 +757,11 @@ private: token = expect_token(TBP_EXPECT_TOKEN("false"), TK_FALSE); break; + case 'g': + case 'G': + token = expect_token(TBP_EXPECT_TOKEN("global"), TK_GLOBAL); + break; + case '1': { char c; @@ -680,7 +775,21 @@ private: case 'o': case 'O': - token = expect_token(TBP_EXPECT_TOKEN("only"), TK_ONLY); + if (is_next_char('f') || is_next_char('F')) + { + token = expect_token(TBP_EXPECT_TOKEN("off"), TK_ZERO); + } + else if (is_next_char('n') || is_next_char('N')) + { + if (is_next_char('l') || is_next_char('L')) + { + token = expect_token(TBP_EXPECT_TOKEN("on"), TK_ONE); + } + else + { + token = expect_token(TBP_EXPECT_TOKEN("only"), TK_ONLY); + } + } break; case 'r': @@ -699,7 +808,14 @@ private: case 'S': if (is_next_char('e') || is_next_char('E')) { - token = expect_token(TBP_EXPECT_TOKEN("set"), TK_SET); + if (is_next_char('s', 2) || is_next_char('S', 2)) + { + token = expect_token(TBP_EXPECT_TOKEN("session"), TK_SESSION); + } + else + { + token = expect_token(TBP_EXPECT_TOKEN("set"), TK_SET); + } } else if (is_next_char('n') || is_next_char('N')) { diff --git a/server/core/test/testtrxtracking.cc b/server/core/test/testtrxtracking.cc index cf1db4e32..1655e0993 100644 --- a/server/core/test/testtrxtracking.cc +++ b/server/core/test/testtrxtracking.cc @@ -100,6 +100,11 @@ struct test_case { "SET AUTOCOMMIT=false", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, { "SET AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, + { "SET @@AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, + { "SET GLOBAL AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, + { "SET SESSION AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, + { "SET @@SESSION . AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, + { "SET @@GLOBAL . AUTOCOMMIT=0", QUERY_TYPE_BEGIN_TRX|QUERY_TYPE_DISABLE_AUTOCOMMIT }, }; const size_t N_TEST_CASES = sizeof(test_cases)/sizeof(test_cases[0]);