MXS-2043 Classify SELECT ... FOR UPDATE as QUERY_TYPE_WRITE

SELECT...FOR UPDATE locks the rows for update, but only if
autocommit==0 or a transaction is active, so in principle even if
it were classified as READ it'd still be sent to master when it
actually matters.

However, even if autocommit==1 and/or no transaction is active, a
slave in read only mode will reject the statement if the user is
subject to the read only restriction (a user with super privileges
is not), which might be considered a server bug. By classifying the
statement as a write, it'll be sent to master and always succeed.
This commit is contained in:
Johan Wikman
2018-09-25 18:26:45 +03:00
parent 743daa5755
commit 2aca6226d9
2 changed files with 43 additions and 1 deletions

View File

@ -1987,7 +1987,14 @@ public:
}
else
{
m_type_mask = QUERY_TYPE_READ;
// Only if the type has explicitly been set to QUERY_TYPE_WRITE
// we don't force it to QUERY_TYPE_READ but with other bits we do.
// This is something of kludge to ensure continued compatibility
// with qc_mysqlembedded.
if (m_type_mask != QUERY_TYPE_WRITE)
{
m_type_mask = QUERY_TYPE_READ;
}
}
QcAliases aliases;
@ -3000,6 +3007,12 @@ public:
m_operation = QUERY_OP_CHANGE_DB;
}
void set_type_mask(uint32_t type_mask)
{
ss_dassert(this_thread.initialized);
m_type_mask = type_mask;
}
private:
QcSqliteInfo(uint32_t cllct)
: m_status(QC_QUERY_INVALID)
@ -3266,6 +3279,8 @@ extern void maxscaleTruncate(Parse*, Token* pDatabase, Token* pName);
extern void maxscaleUse(Parse*, Token*);
extern void maxscale_update_function_info(const char* name, const Expr* pExpr);
// 'unsigned int' and not 'uint32_t' because 'uint32_t' is unknown in sqlite3 context.
extern void maxscale_set_type_mask(unsigned int type_mask);
extern void maxscaleComment();
extern int maxscaleKeyword(int token);
@ -3649,6 +3664,14 @@ extern void maxscale_update_function_info(const char* name, const Expr* pExpr)
pInfo->update_function_info(NULL, name, pExpr, NULL);
}
extern void maxscale_set_type_mask(unsigned int type_mask)
{
QcSqliteInfo* pInfo = this_thread.pInfo;
ss_dassert(pInfo);
pInfo->set_type_mask(type_mask);
}
static const char* get_token_symbol(int token)
{
switch (token)