MXS-1196: Do not parse EXPLAIN statements

EXPLAIN statements are no longer parsed completely as doing so makes
it hard to modify the grammar for the needs or Oracle SQL.

Consequently, for an EXPLAIN statement you now bascially only get the
type and the operation (the newly added QUERY_OP_EXPLAIN and QUERY_OP_SHOW).
The other information is not interesting and is related to
information_schema and similar tables.
This commit is contained in:
Johan Wikman 2017-05-15 13:28:29 +03:00
parent 951c96383c
commit 43ab0f036e
5 changed files with 377 additions and 358 deletions

View File

@ -89,11 +89,13 @@ typedef enum qc_query_op
QUERY_OP_CREATE,
QUERY_OP_DELETE,
QUERY_OP_DROP,
QUERY_OP_EXPLAIN,
QUERY_OP_GRANT,
QUERY_OP_INSERT,
QUERY_OP_LOAD,
QUERY_OP_REVOKE,
QUERY_OP_SELECT,
QUERY_OP_SHOW,
QUERY_OP_TRUNCATE,
QUERY_OP_UPDATE,
} qc_query_op_t;

View File

@ -593,6 +593,12 @@ static uint32_t resolve_query_type(parsing_info_t *pi, THD* thd)
goto return_qtype;
}
if (lex->describe)
{
type = QUERY_TYPE_READ;
goto return_qtype;
}
if (skygw_stmt_causes_implicit_commit(lex, &set_autocommit_stmt))
{
if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
@ -708,6 +714,10 @@ static uint32_t resolve_query_type(parsing_info_t *pi, THD* thd)
}
}
}
else
{
type |= QUERY_TYPE_READ;
}
goto return_qtype;
}
@ -798,6 +808,11 @@ static uint32_t resolve_query_type(parsing_info_t *pi, THD* thd)
goto return_qtype;
break;
case SQLCOM_SHOW_CREATE:
type |= QUERY_TYPE_READ;
goto return_qtype;
break;
case SQLCOM_SHOW_DATABASES:
type |= QUERY_TYPE_SHOW_DATABASES;
goto return_qtype;
@ -805,6 +820,12 @@ static uint32_t resolve_query_type(parsing_info_t *pi, THD* thd)
case SQLCOM_SHOW_FIELDS:
type |= QUERY_TYPE_READ;
goto return_qtype;
break;
case SQLCOM_SHOW_STATUS:
type |= QUERY_TYPE_READ;
goto return_qtype;
break;
case SQLCOM_SHOW_TABLES:
@ -1265,6 +1286,33 @@ static TABLE_LIST* skygw_get_affected_tables(void* lexptr)
return tbl;
}
static bool is_show_command(int sql_command)
{
bool rv = false;
switch (sql_command)
{
case SQLCOM_SHOW_CREATE:
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_KEYS:
case SQLCOM_SHOW_MASTER_STAT:
case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SHOW_STATUS:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_WARNS:
rv = true;
break;
default:
break;
}
return rv;
}
int32_t qc_mysql_get_table_names(GWBUF* querybuf, int32_t fullnames, char*** tablesp, int32_t* tblsize)
{
LEX* lex;
@ -1287,6 +1335,11 @@ int32_t qc_mysql_get_table_names(GWBUF* querybuf, int32_t fullnames, char*** tab
goto retblock;
}
if (lex->describe || is_show_command(lex->sql_command))
{
goto retblock;
}
lex->current_select = lex->all_selects_list;
while (lex->current_select)
@ -1420,16 +1473,19 @@ int32_t qc_mysql_query_has_clause(GWBUF* buf, int32_t* has_clause)
if (lex)
{
SELECT_LEX* current = lex->all_selects_list;
while (current && !*has_clause)
if (!lex->describe && !is_show_command(lex->sql_command))
{
if (current->where || current->having)
{
*has_clause = true;
}
SELECT_LEX* current = lex->all_selects_list;
current = current->next_select_in_list();
while (current && !*has_clause)
{
if (current->where || current->having)
{
*has_clause = true;
}
current = current->next_select_in_list();
}
}
}
}
@ -1592,6 +1648,11 @@ int32_t qc_mysql_get_database_names(GWBUF* querybuf, char*** databasesp, int* si
goto retblock;
}
if (lex->describe || is_show_command(lex->sql_command))
{
goto retblock;
}
lex->current_select = lex->all_selects_list;
while (lex->current_select)
@ -1655,90 +1716,111 @@ int32_t qc_mysql_get_operation(GWBUF* querybuf, int32_t* operation)
if (lex)
{
switch (lex->sql_command)
if (lex->describe)
{
case SQLCOM_SELECT:
*operation = QUERY_OP_SELECT;
break;
*operation = QUERY_OP_EXPLAIN;
}
else
{
switch (lex->sql_command)
{
case SQLCOM_SELECT:
*operation = QUERY_OP_SELECT;
break;
case SQLCOM_CREATE_DB:
case SQLCOM_CREATE_EVENT:
case SQLCOM_CREATE_FUNCTION:
case SQLCOM_CREATE_INDEX:
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SERVER:
case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_TRIGGER:
case SQLCOM_CREATE_USER:
case SQLCOM_CREATE_VIEW:
*operation = QUERY_OP_CREATE;
break;
case SQLCOM_CREATE_DB:
case SQLCOM_CREATE_EVENT:
case SQLCOM_CREATE_FUNCTION:
case SQLCOM_CREATE_INDEX:
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SERVER:
case SQLCOM_CREATE_SPFUNCTION:
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_TRIGGER:
case SQLCOM_CREATE_USER:
case SQLCOM_CREATE_VIEW:
*operation = QUERY_OP_CREATE;
break;
case SQLCOM_ALTER_DB:
case SQLCOM_ALTER_DB_UPGRADE:
case SQLCOM_ALTER_EVENT:
case SQLCOM_ALTER_FUNCTION:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_SERVER:
case SQLCOM_ALTER_TABLE:
case SQLCOM_ALTER_TABLESPACE:
*operation = QUERY_OP_ALTER;
break;
case SQLCOM_ALTER_DB:
case SQLCOM_ALTER_DB_UPGRADE:
case SQLCOM_ALTER_EVENT:
case SQLCOM_ALTER_FUNCTION:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_SERVER:
case SQLCOM_ALTER_TABLE:
case SQLCOM_ALTER_TABLESPACE:
*operation = QUERY_OP_ALTER;
break;
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
*operation = QUERY_OP_UPDATE;
break;
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
*operation = QUERY_OP_UPDATE;
break;
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
*operation = QUERY_OP_INSERT;
break;
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
*operation = QUERY_OP_INSERT;
break;
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
*operation = QUERY_OP_DELETE;
break;
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
*operation = QUERY_OP_DELETE;
break;
case SQLCOM_TRUNCATE:
*operation = QUERY_OP_TRUNCATE;
break;
case SQLCOM_TRUNCATE:
*operation = QUERY_OP_TRUNCATE;
break;
case SQLCOM_DROP_DB:
case SQLCOM_DROP_EVENT:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_INDEX:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_SERVER:
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_TRIGGER:
case SQLCOM_DROP_USER:
case SQLCOM_DROP_VIEW:
*operation = QUERY_OP_DROP;
break;
case SQLCOM_DROP_DB:
case SQLCOM_DROP_EVENT:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_INDEX:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_SERVER:
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_TRIGGER:
case SQLCOM_DROP_USER:
case SQLCOM_DROP_VIEW:
*operation = QUERY_OP_DROP;
break;
case SQLCOM_CHANGE_DB:
*operation = QUERY_OP_CHANGE_DB;
break;
case SQLCOM_CHANGE_DB:
*operation = QUERY_OP_CHANGE_DB;
break;
case SQLCOM_LOAD:
*operation = QUERY_OP_LOAD;
break;
case SQLCOM_LOAD:
*operation = QUERY_OP_LOAD;
break;
case SQLCOM_GRANT:
*operation = QUERY_OP_GRANT;
break;
case SQLCOM_GRANT:
*operation = QUERY_OP_GRANT;
break;
case SQLCOM_REVOKE:
case SQLCOM_REVOKE_ALL:
*operation = QUERY_OP_REVOKE;
break;
case SQLCOM_REVOKE:
case SQLCOM_REVOKE_ALL:
*operation = QUERY_OP_REVOKE;
break;
default:
*operation = QUERY_OP_UNDEFINED;
case SQLCOM_SHOW_CREATE:
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_KEYS:
case SQLCOM_SHOW_MASTER_STAT:
case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SHOW_STATUS:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_WARNS:
*operation = QUERY_OP_SHOW;
break;
default:
*operation = QUERY_OP_UNDEFINED;
}
}
}
}
@ -1757,15 +1839,18 @@ int32_t qc_mysql_get_prepare_name(GWBUF* stmt, char** namep)
{
LEX* lex = get_lex(stmt);
if ((lex->sql_command == SQLCOM_PREPARE) ||
(lex->sql_command == SQLCOM_EXECUTE) ||
(lex->sql_command == SQLCOM_DEALLOCATE_PREPARE))
if (!lex->describe)
{
name = (char*)malloc(lex->prepared_stmt_name.length + 1);
if (name)
if ((lex->sql_command == SQLCOM_PREPARE) ||
(lex->sql_command == SQLCOM_EXECUTE) ||
(lex->sql_command == SQLCOM_DEALLOCATE_PREPARE))
{
memcpy(name, lex->prepared_stmt_name.str, lex->prepared_stmt_name.length);
name[lex->prepared_stmt_name.length] = 0;
name = (char*)malloc(lex->prepared_stmt_name.length + 1);
if (name)
{
memcpy(name, lex->prepared_stmt_name.str, lex->prepared_stmt_name.length);
name[lex->prepared_stmt_name.length] = 0;
}
}
}
}
@ -1784,7 +1869,7 @@ int32_t qc_mysql_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
{
LEX* lex = get_lex(stmt);
if (lex->sql_command == SQLCOM_PREPARE)
if ((lex->sql_command == SQLCOM_PREPARE) && !lex->describe)
{
parsing_info_t* pi = get_pinfo(stmt);
@ -2483,6 +2568,13 @@ int32_t qc_mysql_get_field_info(GWBUF* buf, const QC_FIELD_INFO** infos, uint32_
return QC_RESULT_ERROR;
}
if (lex->describe || is_show_command(lex->sql_command))
{
*infos = NULL;
*n_infos = 0;
return QC_RESULT_OK;
}
uint32_t usage = 0;
switch (lex->sql_command)

View File

@ -411,6 +411,11 @@ static void parse_query_string(const char* query, size_t len)
const char* suffix = (len > max_len ? "..." : "");
const char* format;
if (this_thread.info->operation == QUERY_OP_EXPLAIN)
{
this_thread.info->status = QC_QUERY_PARSED;
}
if (rc != SQLITE_OK)
{
if (qc_info_was_tokenized(this_thread.info->status))
@ -1524,60 +1529,64 @@ void mxs_sqlite3DeleteFrom(Parse* pParse, SrcList* pTabList, Expr* pWhere, SrcLi
ss_dassert(info);
info->status = QC_QUERY_PARSED;
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_DELETE;
info->has_clause = pWhere ? true : false;
if (pUsing)
if (info->operation != QUERY_OP_EXPLAIN)
{
// Walk through the using declaration and update
// table and database names.
for (int i = 0; i < pUsing->nSrc; ++i)
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_DELETE;
info->has_clause = pWhere ? true : false;
if (pUsing)
{
struct SrcList_item* pItem = &pUsing->a[i];
update_names(info, pItem->zDatabase, pItem->zName);
}
// Walk through the tablenames while excluding alias
// names from the using declaration.
for (int i = 0; i < pTabList->nSrc; ++i)
{
const struct SrcList_item* pTable = &pTabList->a[i];
ss_dassert(pTable->zName);
int j = 0;
bool isSame = false;
do
// Walk through the using declaration and update
// table and database names.
for (int i = 0; i < pUsing->nSrc; ++i)
{
struct SrcList_item* pItem = &pUsing->a[j++];
struct SrcList_item* pItem = &pUsing->a[i];
if (strcasecmp(pTable->zName, pItem->zName) == 0)
update_names(info, pItem->zDatabase, pItem->zName);
}
// Walk through the tablenames while excluding alias
// names from the using declaration.
for (int i = 0; i < pTabList->nSrc; ++i)
{
const struct SrcList_item* pTable = &pTabList->a[i];
ss_dassert(pTable->zName);
int j = 0;
bool isSame = false;
do
{
isSame = true;
struct SrcList_item* pItem = &pUsing->a[j++];
if (strcasecmp(pTable->zName, pItem->zName) == 0)
{
isSame = true;
}
else if (pItem->zAlias && (strcasecmp(pTable->zName, pItem->zAlias) == 0))
{
isSame = true;
}
}
else if (pItem->zAlias && (strcasecmp(pTable->zName, pItem->zAlias) == 0))
while (!isSame && (j < pUsing->nSrc));
if (!isSame)
{
isSame = true;
// No alias name, update the table name.
update_names(info, pTable->zDatabase, pTable->zName);
}
}
while (!isSame && (j < pUsing->nSrc));
if (!isSame)
{
// No alias name, update the table name.
update_names(info, pTable->zDatabase, pTable->zName);
}
}
}
else
{
update_names_from_srclist(info, pTabList);
}
else
{
update_names_from_srclist(info, pTabList);
}
if (pWhere)
{
update_field_infos(info, 0, pWhere, QC_USED_IN_WHERE, QC_TOKEN_MIDDLE, 0);
if (pWhere)
{
update_field_infos(info, 0, pWhere, QC_USED_IN_WHERE, QC_TOKEN_MIDDLE, 0);
}
}
exposed_sqlite3ExprDelete(pParse->db, pWhere);
@ -1677,36 +1686,40 @@ void mxs_sqlite3Insert(Parse* pParse,
ss_dassert(info);
info->status = QC_QUERY_PARSED;
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_INSERT;
ss_dassert(pTabList);
ss_dassert(pTabList->nSrc >= 1);
update_names_from_srclist(info, pTabList);
if (pColumns)
if (info->operation != QUERY_OP_EXPLAIN)
{
update_field_infos_from_idlist(info, pColumns, 0, NULL);
}
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_INSERT;
ss_dassert(pTabList);
ss_dassert(pTabList->nSrc >= 1);
update_names_from_srclist(info, pTabList);
if (pSelect)
{
uint32_t usage;
if (pSelect->selFlags & SF_Values) // Synthesized from VALUES clause
if (pColumns)
{
usage = 0;
}
else
{
usage = QC_USED_IN_SELECT;
update_field_infos_from_idlist(info, pColumns, 0, NULL);
}
update_field_infos_from_select(info, pSelect, usage, NULL);
}
if (pSelect)
{
uint32_t usage;
if (pSet)
{
update_field_infos_from_exprlist(info, pSet, 0, NULL);
if (pSelect->selFlags & SF_Values) // Synthesized from VALUES clause
{
usage = 0;
}
else
{
usage = QC_USED_IN_SELECT;
}
update_field_infos_from_select(info, pSelect, usage, NULL);
}
if (pSet)
{
update_field_infos_from_exprlist(info, pSet, 0, NULL);
}
}
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
@ -1737,9 +1750,13 @@ int mxs_sqlite3Select(Parse* pParse, Select* p, SelectDest* pDest)
if (!info->initializing)
{
info->status = QC_QUERY_PARSED;
info->operation = QUERY_OP_SELECT;
maxscaleCollectInfoFromSelect(pParse, p, 0);
if (info->operation != QUERY_OP_EXPLAIN)
{
info->operation = QUERY_OP_SELECT;
maxscaleCollectInfoFromSelect(pParse, p, 0);
}
// NOTE: By convention, the select is deleted in parse.y.
}
else
@ -1828,24 +1845,28 @@ void mxs_sqlite3Update(Parse* pParse, SrcList* pTabList, ExprList* pChanges, Exp
ss_dassert(info);
info->status = QC_QUERY_PARSED;
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_UPDATE;
update_names_from_srclist(info, pTabList);
info->has_clause = (pWhere ? true : false);
if (pChanges)
if (info->operation != QUERY_OP_EXPLAIN)
{
for (int i = 0; i < pChanges->nExpr; ++i)
info->type_mask = QUERY_TYPE_WRITE;
info->operation = QUERY_OP_UPDATE;
update_names_from_srclist(info, pTabList);
info->has_clause = (pWhere ? true : false);
if (pChanges)
{
struct ExprList_item* pItem = &pChanges->a[i];
for (int i = 0; i < pChanges->nExpr; ++i)
{
struct ExprList_item* pItem = &pChanges->a[i];
update_field_infos(info, 0, pItem->pExpr, QC_USED_IN_SET, QC_TOKEN_MIDDLE, NULL);
update_field_infos(info, 0, pItem->pExpr, QC_USED_IN_SET, QC_TOKEN_MIDDLE, NULL);
}
}
}
if (pWhere)
{
update_field_infos(info, 0, pWhere, QC_USED_IN_WHERE, QC_TOKEN_MIDDLE, pChanges);
if (pWhere)
{
update_field_infos(info, 0, pWhere, QC_USED_IN_WHERE, QC_TOKEN_MIDDLE, pChanges);
}
}
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
@ -2045,7 +2066,7 @@ void maxscaleExecute(Parse* pParse, Token* pName)
}
}
void maxscaleExplain(Parse* pParse, SrcList* pName)
void maxscaleExplain(Parse* pParse, Token* pNext)
{
QC_TRACE();
@ -2054,16 +2075,28 @@ void maxscaleExplain(Parse* pParse, SrcList* pName)
info->status = QC_QUERY_PARSED;
info->type_mask = QUERY_TYPE_READ;
update_names(info, pName->a[0].zDatabase, pName->a[0].zName);
uint32_t u = QC_USED_IN_SELECT;
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_KEY", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_NAME", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_TYPE", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "EXTRA", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "IS_NULLABLE", u, NULL);
info->operation = QUERY_OP_SHOW;
exposed_sqlite3SrcListDelete(pParse->db, pName);
if (pNext)
{
if (pNext->z)
{
const char EXTENDED[] = "EXTENDED";
const char PARTITIONS[] = "PARTITIONS";
const char FORMAT[] = "FORMAT";
const char FOR[] = "FOR";
#define MATCHES_KEYWORD(t, k) ((t->n == sizeof(k) - 1) && (strncasecmp(t->z, k, t->n) == 0))
if (MATCHES_KEYWORD(pNext, EXTENDED) ||
MATCHES_KEYWORD(pNext, PARTITIONS) ||
MATCHES_KEYWORD(pNext, FORMAT) ||
MATCHES_KEYWORD(pNext, FOR))
{
info->operation = QUERY_OP_EXPLAIN;
}
}
}
}
void maxscaleFlush(Parse* pParse, Token* pWhat)
@ -2203,6 +2236,7 @@ void maxscaleKeyword(int token)
case TK_DESC:
info->status = QC_QUERY_TOKENIZED;
info->type_mask = QUERY_TYPE_READ;
info->operation = QUERY_OP_EXPLAIN;
break;
case TK_DROP:
@ -2219,6 +2253,7 @@ void maxscaleKeyword(int token)
case TK_EXPLAIN:
info->status = QC_QUERY_TOKENIZED;
info->type_mask = QUERY_TYPE_READ;
info->operation = QUERY_OP_EXPLAIN;
break;
case TK_GRANT:
@ -2656,188 +2691,83 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
ss_dassert(info);
info->status = QC_QUERY_PARSED;
char* zDatabase = NULL;
char* zName = NULL;
char database[pShow->pDatabase ? pShow->pDatabase->n + 1 : 0];
if (pShow->pDatabase)
{
strncpy(database, pShow->pDatabase->z, pShow->pDatabase->n);
database[pShow->pDatabase->n] = 0;
zDatabase = database;
}
char name[pShow->pName ? pShow->pName->n + 1 : 0];
if (pShow->pName)
{
strncpy(name, pShow->pName->z, pShow->pName->n);
name[pShow->pName->n] = 0;
zName = name;
}
info->operation = QUERY_OP_SHOW;
uint32_t u = QC_USED_IN_SELECT;
switch (pShow->what)
{
case MXS_SHOW_COLUMNS:
{
info->type_mask = QUERY_TYPE_READ;
update_names(info, zDatabase, zName);
if (pShow->data == MXS_SHOW_COLUMNS_FULL)
{
update_field_info(info, "information_schema", "COLUMNS", "COLLATION_NAME", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_COMMENT", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_KEY", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_NAME", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_TYPE", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "EXTRA", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "IS_NULLABLE", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "PRIVILEGES", u, NULL);
}
else
{
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_KEY", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_NAME", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "COLUMN_TYPE", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "EXTRA", u, NULL);
update_field_info(info, "information_schema", "COLUMNS", "IS_NULLABLE", u, NULL);
}
}
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_CREATE_VIEW:
{
info->type_mask = QUERY_TYPE_WRITE;
update_names(info, zDatabase, zName);
}
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_CREATE_TABLE:
{
info->type_mask = QUERY_TYPE_WRITE;
update_names(info, zDatabase, zName);
}
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_DATABASES:
{
info->type_mask = QUERY_TYPE_SHOW_DATABASES;
update_names(info, "information_schema", "SCHEMATA");
update_field_info(info, "information_schema", "SCHEMATA", "SCHEMA_NAME", u, NULL);
}
info->type_mask = QUERY_TYPE_SHOW_DATABASES;
break;
case MXS_SHOW_INDEX:
case MXS_SHOW_INDEXES:
case MXS_SHOW_KEYS:
{
info->type_mask = QUERY_TYPE_WRITE;
update_names(info, "information_schema", "STATISTICS");
update_field_info(info, "information_schema", "STATISTICS", "CARDINALITY", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "COLLATION", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "COLUMN_NAME", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "COMMENT", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "INDEX_COMMENT", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "INDEX_NAME", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "INDEX_TYPE", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "NON_UNIQUE", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "NULLABLE", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "PACKED", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "SEQ_IN_INDEX", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "SUB_PART", u, NULL);
update_field_info(info, "information_schema", "STATISTICS", "TABLE_NAME", u, NULL);
}
info->type_mask = QUERY_TYPE_WRITE;
break;
case MXS_SHOW_TABLE_STATUS:
{
info->type_mask = QUERY_TYPE_WRITE;
update_names(info, "information_schema", "TABLES");
update_field_info(info, "information_schema", "TABLES", "AUTO_INCREMENT", u, NULL);
update_field_info(info, "information_schema", "TABLES", "AVG_ROW_LENGTH", u, NULL);
update_field_info(info, "information_schema", "TABLES", "CHECKSUM", u, NULL);
update_field_info(info, "information_schema", "TABLES", "CHECK_TIME", u, NULL);
update_field_info(info, "information_schema", "TABLES", "CREATE_OPTIONS", u, NULL);
update_field_info(info, "information_schema", "TABLES", "CREATE_TIME", u, NULL);
update_field_info(info, "information_schema", "TABLES", "DATA_FREE", u, NULL);
update_field_info(info, "information_schema", "TABLES", "DATA_LENGTH", u, NULL);
update_field_info(info, "information_schema", "TABLES", "ENGINE", u, NULL);
update_field_info(info, "information_schema", "TABLES", "INDEX_LENGTH", u, NULL);
update_field_info(info, "information_schema", "TABLES", "MAX_DATA_LENGTH", u, NULL);
update_field_info(info, "information_schema", "TABLES", "ROW_FORMAT", u, NULL);
update_field_info(info, "information_schema", "TABLES", "TABLE_COLLATION", u, NULL);
update_field_info(info, "information_schema", "TABLES", "TABLE_COMMENT", u, NULL);
update_field_info(info, "information_schema", "TABLES", "TABLE_NAME", u, NULL);
update_field_info(info, "information_schema", "TABLES", "TABLE_ROWS", u, NULL);
update_field_info(info, "information_schema", "TABLES", "UPDATE_TIME", u, NULL);
update_field_info(info, "information_schema", "TABLES", "VERSION", u, NULL);
}
info->type_mask = QUERY_TYPE_WRITE;
break;
case MXS_SHOW_STATUS:
switch (pShow->data)
{
switch (pShow->data)
{
case MXS_SHOW_VARIABLES_GLOBAL:
case MXS_SHOW_VARIABLES_SESSION:
case MXS_SHOW_VARIABLES_UNSPECIFIED:
// TODO: qc_mysqlembedded does not set the type bit.
info->type_mask = QUERY_TYPE_UNKNOWN;
update_names(info, "information_schema", "SESSION_STATUS");
update_field_info(info, "information_schema", "SESSION_STATUS", "VARIABLE_NAME", u, NULL);
update_field_info(info, "information_schema", "SESSION_STATUS", "VARIABLE_VALUE", u, NULL);
break;
case MXS_SHOW_VARIABLES_GLOBAL:
case MXS_SHOW_VARIABLES_SESSION:
case MXS_SHOW_VARIABLES_UNSPECIFIED:
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_STATUS_MASTER:
info->type_mask = QUERY_TYPE_WRITE;
break;
case MXS_SHOW_STATUS_MASTER:
info->type_mask = QUERY_TYPE_WRITE;
break;
case MXS_SHOW_STATUS_SLAVE:
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_STATUS_SLAVE:
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_STATUS_ALL_SLAVES:
info->type_mask = QUERY_TYPE_READ;
break;
case MXS_SHOW_STATUS_ALL_SLAVES:
info->type_mask = QUERY_TYPE_READ;
break;
default:
break;
}
default:
info->type_mask = QUERY_TYPE_READ;
break;
}
break;
case MXS_SHOW_TABLES:
{
info->type_mask = QUERY_TYPE_SHOW_TABLES;
update_names(info, "information_schema", "TABLE_NAMES");
update_field_info(info, "information_schema", "TABLE_NAMES", "TABLE_NAME", u, NULL);
}
info->type_mask = QUERY_TYPE_SHOW_TABLES;
break;
case MXS_SHOW_VARIABLES:
if (pShow->data == MXS_SHOW_VARIABLES_GLOBAL)
{
if (pShow->data == MXS_SHOW_VARIABLES_GLOBAL)
{
info->type_mask = QUERY_TYPE_GSYSVAR_READ;
}
else
{
info->type_mask = QUERY_TYPE_SYSVAR_READ;
}
update_names(info, "information_schema", "SESSION_VARIABLES");
update_field_info(info, "information_schema", "SESSION_STATUS", "VARIABLE_NAME", u, NULL);
update_field_info(info, "information_schema", "SESSION_STATUS", "VARIABLE_VALUE", u, NULL);
info->type_mask = QUERY_TYPE_GSYSVAR_READ;
}
else
{
info->type_mask = QUERY_TYPE_SYSVAR_READ;
}
break;
case MXS_SHOW_WARNINGS:
{
// qc_mysqliembedded claims this.
info->type_mask = QUERY_TYPE_WRITE;
}
// qc_mysqliembedded claims this.
info->type_mask = QUERY_TYPE_WRITE;
break;
default:

View File

@ -113,7 +113,7 @@ extern void maxscaleDeallocate(Parse*, Token* pName);
extern void maxscaleDo(Parse*, ExprList* pEList);
extern void maxscaleDrop(Parse*, MxsDrop* pDrop);
extern void maxscaleExecute(Parse*, Token* pName);
extern void maxscaleExplain(Parse*, SrcList* pName);
extern void maxscaleExplain(Parse*, Token* pNext);
extern void maxscaleFlush(Parse*, Token* pWhat);
extern void maxscaleHandler(Parse*, mxs_handler_t, SrcList* pFullName, Token* pName);
extern void maxscaleLoadData(Parse*, SrcList* pFullName);
@ -276,33 +276,22 @@ input ::= cmdlist.
cmdlist ::= cmdlist ecmd.
cmdlist ::= ecmd.
ecmd ::= SEMI.
ecmd ::= explain cmdx SEMI.
ecmd ::= explain SEMI.
ecmd ::= cmdx SEMI.
%ifdef MAXSCALE
explain_kw ::= EXPLAIN. // Also covers DESCRIBE
explain_kw ::= DESC.
ecmd ::= explain_kw fullname(X) SEMI. {
pParse->explain = 1;
maxscaleExplain(pParse, X);
}
explain ::= explain_kw. { pParse->explain = 1; }
// deferred_id is defined later, after the id token_class has been defined.
ecmd ::= explain FOR deferred_id INTEGER SEMI. { // FOR CONNECTION connection_id
explain ::= explain_kw deferred_id(A). { maxscaleExplain(pParse, &A); }
explain ::= explain_kw deferred_id(A) DOT deferred_id. { maxscaleExplain(pParse, &A); }
ecmd ::= explain FOR(A) deferred_id INTEGER SEMI. { // FOR CONNECTION connection_id
pParse->explain = 1;
maxscaleExplain(pParse, 0);
maxscaleExplain(pParse, &A);
}
%endif
explain ::= .
%ifndef SQLITE_OMIT_EXPLAIN
%ifdef MAXSCALE
explain_type_opt ::= .
explain_type_opt ::= deferred_id. // EXTENDED | PARTITIONS
explain_type_opt ::= deferred_id eq deferred_id. // FORMAT = {TRADITIONAL|JSON}
explain ::= explain_kw explain_type_opt. { pParse->explain = 1; }
%endif
%ifndef MAXSCALE
explain ::= EXPLAIN. { pParse->explain = 1; }
%endif
%ifndef MAXSCALE
explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; }
%endif
@ -2675,7 +2664,7 @@ type_options(A) ::= type_options CHARACTER SET ids. {A|=8;}
type_options(A) ::= type_options CHARSET ids. {A|=8;}
// deferred_id is used instead of id before the token_class id has been defined.
deferred_id ::= id.
deferred_id(A) ::= id(X). {A=X;}
as_opt ::= .
as_opt ::= AS.

View File

@ -494,42 +494,48 @@ const char* qc_op_to_string(qc_query_op_t op)
case QUERY_OP_UNDEFINED:
return "QUERY_OP_UNDEFINED";
case QUERY_OP_SELECT:
return "QUERY_OP_SELECT";
case QUERY_OP_UPDATE:
return "QUERY_OP_UPDATE";
case QUERY_OP_INSERT:
return "QUERY_OP_INSERT";
case QUERY_OP_DELETE:
return "QUERY_OP_DELETE";
case QUERY_OP_TRUNCATE:
return "QUERY_OP_TRUNCATE";
case QUERY_OP_ALTER:
return "QUERY_OP_ALTER";
case QUERY_OP_CREATE:
return "QUERY_OP_CREATE";
case QUERY_OP_DROP:
return "QUERY_OP_DROP";
case QUERY_OP_CHANGE_DB:
return "QUERY_OP_CHANGE_DB";
case QUERY_OP_LOAD:
return "QUERY_OP_LOAD";
case QUERY_OP_CREATE:
return "QUERY_OP_CREATE";
case QUERY_OP_DELETE:
return "QUERY_OP_DELETE";
case QUERY_OP_DROP:
return "QUERY_OP_DROP";
case QUERY_OP_EXPLAIN:
return "QUERY_OP_EXPLAIN";
case QUERY_OP_GRANT:
return "QUERY_OP_GRANT";
case QUERY_OP_INSERT:
return "QUERY_OP_INSERT";
case QUERY_OP_LOAD:
return "QUERY_OP_LOAD";
case QUERY_OP_REVOKE:
return "QUERY_OP_REVOKE";
case QUERY_OP_SELECT:
return "QUERY_OP_SELECT";
case QUERY_OP_SHOW:
return "QUERY_OP_SHOW";
case QUERY_OP_TRUNCATE:
return "QUERY_OP_TRUNCATE";
case QUERY_OP_UPDATE:
return "QUERY_OP_UPDATE";
default:
return "UNKNOWN_QUERY_OP";
}