From 7b001994b4fafd4e14d41215420325dd36c3327d Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 31 Oct 2018 13:47:21 +0200 Subject: [PATCH] MXS-1978 Change qc_sqlite behaviour and update test A statement like SELECT ... INTO OUTFILE|DUMPFILE ... is now classified as a QUERY_TYPE_WRITE, instead of as QUERY_TYPE_GSYSVAR_WRITE so that it will be sent only to the master. --- query_classifier/qc_sqlite/qc_sqlite.cc | 23 ++++++++++++++++--- .../qc_sqlite/sqlite-src-3110100/src/parse.y | 16 +++++++++++-- query_classifier/test/expected.sql | 6 ++--- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/query_classifier/qc_sqlite/qc_sqlite.cc b/query_classifier/qc_sqlite/qc_sqlite.cc index 3e576ccde..57d26af4d 100644 --- a/query_classifier/qc_sqlite/qc_sqlite.cc +++ b/query_classifier/qc_sqlite/qc_sqlite.cc @@ -2004,9 +2004,26 @@ public: if (pSelect->pInto) { - // If there's a single variable, then it's a write. - // mysql embedded considers it a system var write. - m_type_mask = QUERY_TYPE_GSYSVAR_WRITE; + const ExprList* pInto = pSelect->pInto; + mxb_assert(pInto->nExpr >= 1); + + if ((pInto->nExpr == 1) + && (pInto->a[0].zName) + && ((strcmp(pInto->a[0].zName, ":DUMPFILE:") == 0) + || (strcmp(pInto->a[0].zName, ":OUTFILE:") == 0))) + { + // If there is exactly one expression that has a name that is either + // ":DUMPFILE:" or ":OUTFILE:" then it's a SELECT ... INTO OUTFILE|DUMPFILE + // and the statement needs to go to master. + // See in parse.y, the rule for select_into. + m_type_mask = QUERY_TYPE_WRITE; + } + else + { + // If there's a single variable, then it's a write. + // mysql embedded considers it a system var write. + m_type_mask = QUERY_TYPE_GSYSVAR_WRITE; + } // Also INTO {OUTFILE|DUMPFILE} will be typed as QUERY_TYPE_GSYSVAR_WRITE. } diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y index 9310d4d38..78117c2b7 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y @@ -1177,8 +1177,20 @@ select_into_opt(A) ::= select_into(X). {A = X;} %type select_into {ExprList*} %destructor select_into {sqlite3ExprListDelete(pParse->db, $$);} select_into(A) ::= INTO variables(X). {A = X;} -select_into(A) ::= INTO DUMPFILE STRING. {A = sqlite3ExprListAppend(pParse, 0, 0);} -select_into(A) ::= INTO OUTFILE STRING. {A = sqlite3ExprListAppend(pParse, 0, 0);} +// In order to allow us to distinguish between "INTO @var" and +// "INTO OUTFILE" or "INTO DUMPFILE", we give the expression list +// a name that cannot be a variable and look for that in +// maxscaleCollectInfoFromSelect(). +select_into(A) ::= INTO DUMPFILE STRING. { + static Token dumpfile = { ":DUMPFILE:", 10 }; + A = sqlite3ExprListAppend(pParse, 0, 0); + sqlite3ExprListSetName(pParse, A, &dumpfile, 1); +} +select_into(A) ::= INTO OUTFILE STRING. { + static Token outfile = { ":OUTFILE:", 9 }; + A = sqlite3ExprListAppend(pParse, 0, 0); + sqlite3ExprListSetName(pParse, A, &outfile, 1); +} %type select_options {int} select_options(A) ::= . {A = 0;} diff --git a/query_classifier/test/expected.sql b/query_classifier/test/expected.sql index 702017af5..55a350bd2 100644 --- a/query_classifier/test/expected.sql +++ b/query_classifier/test/expected.sql @@ -25,8 +25,6 @@ QUERY_TYPE_READ|QUERY_TYPE_WRITE QUERY_TYPE_READ|QUERY_TYPE_WRITE QUERY_TYPE_DEALLOC_PREPARE QUERY_TYPE_WRITE +QUERY_TYPE_WRITE +QUERY_TYPE_WRITE QUERY_TYPE_GSYSVAR_WRITE -QUERY_TYPE_GSYSVAR_WRITE -QUERY_TYPE_GSYSVAR_WRITE - -