Handle WITH CONSISTENT SNAPSHOT as well

TrsBoundaryParser now capable of parsing WITH CONSISTENT
SNAPSHOT transaction statements as well.
This commit is contained in:
Johan Wikman
2017-03-11 16:46:49 +02:00
parent 35132f3afe
commit d5fc54a9de
2 changed files with 102 additions and 17 deletions

View File

@ -38,7 +38,9 @@ public:
{ {
TK_AUTOCOMMIT, TK_AUTOCOMMIT,
TK_BEGIN, TK_BEGIN,
TK_COMMA,
TK_COMMIT, TK_COMMIT,
TK_CONSISTENT,
TK_EQ, TK_EQ,
TK_FALSE, TK_FALSE,
TK_ONE, TK_ONE,
@ -46,9 +48,11 @@ public:
TK_READ, TK_READ,
TK_ROLLBACK, TK_ROLLBACK,
TK_SET, TK_SET,
TK_SNAPSHOT,
TK_START, TK_START,
TK_TRANSACTION, TK_TRANSACTION,
TK_TRUE, TK_TRUE,
TK_WITH,
TK_WORK, TK_WORK,
TK_WRITE, TK_WRITE,
TK_ZERO, TK_ZERO,
@ -105,12 +109,25 @@ public:
} }
private: private:
enum token_required_t
{
TOKEN_REQUIRED,
TOKEN_NOT_REQUIRED,
};
void log_unexpected() void log_unexpected()
{ {
MXS_ERROR("In statement '%.*s', unexpected token at '%.*s'.", MXS_ERROR("In statement '%.*s', unexpected token at '%.*s'.",
(int)m_len, m_pSql, (int)(m_pEnd - m_pI), m_pI); (int)m_len, m_pSql, (int)(m_pEnd - m_pI), m_pI);
} }
void log_exhausted()
{
#ifndef NDEBUG
MXS_WARNING("More tokens expected in statement '%.*s'.", (int)m_len, m_pSql);
#endif
}
uint32_t parse() uint32_t parse()
{ {
uint32_t type_mask = 0; uint32_t type_mask = 0;
@ -200,6 +217,10 @@ private:
switch (token) switch (token)
{ {
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
break; break;
@ -213,7 +234,7 @@ private:
uint32_t parse_read(uint32_t type_mask) uint32_t parse_read(uint32_t type_mask)
{ {
token_t token = next_token(); token_t token = next_token(TOKEN_REQUIRED);
switch (token) switch (token)
{ {
@ -227,7 +248,6 @@ private:
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
type_mask = 0; type_mask = 0;
MXS_WARNING("Expected more.");
break; break;
default: default:
@ -263,7 +283,7 @@ private:
uint32_t parse_set(uint32_t type_mask) uint32_t parse_set(uint32_t type_mask)
{ {
token_t token = next_token(); token_t token = next_token(TOKEN_REQUIRED);
switch (token) switch (token)
{ {
@ -295,7 +315,6 @@ private:
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
type_mask = 0; type_mask = 0;
MXS_WARNING("Expected more.");
break; break;
default: default:
@ -308,7 +327,7 @@ private:
uint32_t parse_start(uint32_t type_mask) uint32_t parse_start(uint32_t type_mask)
{ {
token_t token = next_token(); token_t token = next_token(TOKEN_REQUIRED);
switch (token) switch (token)
{ {
@ -318,7 +337,6 @@ private:
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
type_mask = 0; type_mask = 0;
MXS_WARNING("Expected more.");
break; break;
default: default:
@ -341,19 +359,52 @@ private:
type_mask = parse_read(type_mask); type_mask = parse_read(type_mask);
break; break;
case TK_WITH:
type_mask = parse_with_consistent_snapshot(type_mask);
break;
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
break; break;
default: default:
MXS_WARNING("START TRANSACTION followed by '%.*s', assuming it's ok.", type_mask = 0;
(int)(m_pEnd - m_pI), m_pI);
//type_mask = 0;
log_unexpected(); log_unexpected();
} }
return type_mask; return type_mask;
} }
uint32_t parse_with_consistent_snapshot(uint32_t type_mask)
{
token_t token = next_token(TOKEN_REQUIRED);
if (token == TK_CONSISTENT)
{
token = next_token(TOKEN_REQUIRED);
if (token == TK_SNAPSHOT)
{
token = next_token();
switch (token)
{
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED:
break;
default:
type_mask = 0;
log_unexpected();
}
}
}
return type_mask;
}
uint32_t parse_work(uint32_t type_mask) uint32_t parse_work(uint32_t type_mask)
{ {
token_t token = next_token(); token_t token = next_token();
@ -379,6 +430,10 @@ private:
switch (token) switch (token)
{ {
case TK_COMMA:
type_mask = parse_transaction(type_mask);
break;
case PARSER_EXHAUSTED: case PARSER_EXHAUSTED:
break; break;
@ -435,7 +490,7 @@ private:
return token; return token;
} }
token_t next_token() token_t next_token(token_required_t required = TOKEN_NOT_REQUIRED)
{ {
token_t token = PARSER_UNKNOWN_TOKEN; token_t token = PARSER_UNKNOWN_TOKEN;
@ -479,17 +534,29 @@ private:
token = expect_token(TBP_EXPECT_TOKEN("begin"), TK_BEGIN); token = expect_token(TBP_EXPECT_TOKEN("begin"), TK_BEGIN);
break; break;
case ',':
++m_pI;
token = TK_COMMA;
break;
case 'c': case 'c':
case 'C': case 'C':
token = expect_token(TBP_EXPECT_TOKEN("commit"), TK_COMMIT); if (is_next_char('o') || is_next_char('O'))
{
if (is_next_char('m', 2) || is_next_char('M', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("commit"), TK_COMMIT);
}
else if (is_next_char('n', 2) || is_next_char('N', 2))
{
token = expect_token(TBP_EXPECT_TOKEN("consistent"), TK_CONSISTENT);
}
}
break; break;
case '=': case '=':
if (!is_next_char('=')) ++m_pI;
{ token = TK_EQ;
++m_pI;
token = TK_EQ;
}
break; break;
case 'f': case 'f':
@ -531,6 +598,10 @@ private:
{ {
token = expect_token(TBP_EXPECT_TOKEN("set"), TK_SET); token = expect_token(TBP_EXPECT_TOKEN("set"), TK_SET);
} }
else if (is_next_char('n') || is_next_char('N'))
{
token = expect_token(TBP_EXPECT_TOKEN("snapshot"), TK_SNAPSHOT);
}
else if (is_next_char('t') || is_next_char('T')) else if (is_next_char('t') || is_next_char('T'))
{ {
token = expect_token(TBP_EXPECT_TOKEN("start"), TK_START); token = expect_token(TBP_EXPECT_TOKEN("start"), TK_START);
@ -554,7 +625,11 @@ private:
case 'w': case 'w':
case 'W': case 'W':
if (is_next_char('o') || is_next_char('O')) if (is_next_char('i') || is_next_char('I'))
{
token = expect_token(TBP_EXPECT_TOKEN("with"), TK_WITH);
}
else if (is_next_char('o') || is_next_char('O'))
{ {
token = expect_token(TBP_EXPECT_TOKEN("work"), TK_WORK); token = expect_token(TBP_EXPECT_TOKEN("work"), TK_WORK);
} }
@ -580,6 +655,11 @@ private:
} }
} }
if ((token == PARSER_EXHAUSTED) && (required == TOKEN_REQUIRED))
{
log_exhausted();
}
return token; return token;
} }

View File

@ -98,6 +98,11 @@ struct test_case
{ "START TRANSACTION WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX }, { "START TRANSACTION WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX },
{ "START TRANSACTION WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX }, { "START TRANSACTION WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX },
{ "START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY", QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_READ },
{ "START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_READ },
{ "START TRANSACTION WITH CONSISTENT SNAPSHOT, READ WRITE", QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_WRITE },
{ "START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT", QUERY_TYPE_BEGIN_TRX | QUERY_TYPE_WRITE },
{ "SET AUTOCOMMIT=true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT }, { "SET AUTOCOMMIT=true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT },
{ "SET AUTOCOMMIT=true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT }, { "SET AUTOCOMMIT=true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT },
{ "SET AUTOCOMMIT =true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT }, { "SET AUTOCOMMIT =true", QUERY_TYPE_COMMIT|QUERY_TYPE_ENABLE_AUTOCOMMIT },