Reimplemented the handling of comments in 'USE' statements #3493

This commits partially revert 0dde4adb21

It also improve the TAP test reg_test_3493-USE_with_comment-t.cpp with a
variety of combinations, that helped find a bug in the tokenizer
mysql_query_digest_and_first_comment()
pull/3610/head
René Cannaò 5 years ago
parent 5f971aefc7
commit b485623d6f

@ -90,7 +90,7 @@ class MySQL_Session
* But since it was change for handling 'USE' statements which are preceded by
* comments, it's called after 'QueryProcessor' has processed the query.
*/
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(PtrSize_t *pkt, const char* query_digest);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(PtrSize_t *pkt);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PING(PtrSize_t *);
void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_CHANGE_USER(PtrSize_t *, bool *);

@ -3538,8 +3538,18 @@ __get_pkts_from_client:
// For more context check issue: #3493.
// ===================================================
if (session_type != PROXYSQL_SESSION_CLICKHOUSE) {
if (strncasecmp((char *)"USE ",CurrentQuery.get_digest_text(),4)==0) {
handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(&pkt, CurrentQuery.get_digest_text());
fprintf(stderr,"%s\n", CurrentQuery.get_digest_text());
const char *qd = CurrentQuery.get_digest_text();
if (
(strncasecmp((char *)"USE",qd,3)==0)
&&
(
(strncasecmp((char *)"USE ",qd,4)==0)
||
(strncasecmp((char *)"USE`",qd,4)==0)
)
) {
handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(&pkt);
if (mirror == false) {
break;
@ -5186,18 +5196,25 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
// this function was introduced due to isseu #718
// some application (like the one written in Perl) do not use COM_INIT_DB , but COM_QUERY with USE dbname
void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(PtrSize_t *pkt, const char* query_digest) {
void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_USE_DB(PtrSize_t *pkt) {
gtid_hid=-1;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Got COM_QUERY with USE dbname\n");
if (session_type == PROXYSQL_SESSION_MYSQL) {
__sync_fetch_and_add(&MyHGM->status.frontend_use_db, 1);
char *schemaname=strndup(query_digest+4,strlen(query_digest)-4);
string nq=string((char *)pkt->ptr+sizeof(mysql_hdr)+1,pkt->size-sizeof(mysql_hdr)-1);
RE2::GlobalReplace(&nq,(char *)"(?U)/\\*.*\\*/",(char *)" ");
char *sn_tmp = (char *)nq.c_str();
while (sn_tmp < ( nq.c_str() + nq.length() - 4 ) && *sn_tmp == ' ')
sn_tmp++;
//char *schemaname=strdup(nq.c_str()+4);
char *schemaname=strdup(sn_tmp+3);
char *schemanameptr=trim_spaces_and_quotes_in_place(schemaname);
// handle cases like "USE `schemaname`
if(schemanameptr[0]=='`' && schemanameptr[strlen(schemanameptr)-1]=='`') {
schemanameptr[strlen(schemanameptr)-1]='\0';
schemanameptr++;
}
proxy_info("%s\n", schemanameptr);
client_myds->myconn->userinfo->set_schemaname(schemanameptr,strlen(schemanameptr));
free(schemaname);
if (mirror==false) {

@ -484,6 +484,11 @@ char *mysql_query_digest_and_first_comment(char *s, int _len, char **first_comme
}
cmd=0;
}
if (flag == 1 && prev_char == '*' && *s == '/') {
if (r != p_r && *p_r != ' ') { // not at the beginning, and previous char is not ' '
*p_r++ = ' ';
}
}
prev_char = ' ';
flag = 0;
s++;

@ -16,6 +16,7 @@
#include <cstring>
#include <vector>
#include <utility>
#include <string>
#include <stdio.h>
@ -37,6 +38,8 @@ void parse_result_json_column(MYSQL_RES *result, json& j) {
}
}
std::vector<std::pair<std::string,std::string>> db_query;
int main(int argc, char** argv) {
CommandLine cl;
@ -47,6 +50,24 @@ int main(int argc, char** argv) {
MYSQL* proxysql_mysql = mysql_init(NULL);
db_query.push_back(std::make_pair("reg_test_3493_use_comment", "/*+ placeholder_comment */ USE reg_test_3493_use_comment"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-a1`", "USE /*+ placeholder_comment */ `reg_test_3493_use_comment-a1`"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_1", " USE /*+ placeholder_comment */ `reg_test_3493_use_comment_1`"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_2", "USE/*+ placeholder_comment */ `reg_test_3493_use_comment_2`"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_3", "USE /*+ placeholder_comment */`reg_test_3493_use_comment_3`"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_4", " USE /*+ placeholder_comment */ reg_test_3493_use_comment_4"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_5", "USE/*+ placeholder_comment */ reg_test_3493_use_comment_5"));
db_query.push_back(std::make_pair("reg_test_3493_use_comment_6", "USE /*+ placeholder_comment */reg_test_3493_use_comment_6"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-1`", " USE /*+ placeholder_comment */ `reg_test_3493_use_comment-1`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-2`", "USE/*+ placeholder_comment */ `reg_test_3493_use_comment-2`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-3`", "USE /*+ placeholder_comment */`reg_test_3493_use_comment-3`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-4`", "/*+ placeholder_comment */USE `reg_test_3493_use_comment-4`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-5`", "USE/*+ placeholder_comment */`reg_test_3493_use_comment-5`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-6`", "/* comment */USE`reg_test_3493_use_comment-6`"));
db_query.push_back(std::make_pair("`reg_test_3493_use_comment-7`", "USE`reg_test_3493_use_comment-7`"));
plan(db_query.size());
if (
!mysql_real_connect(
proxysql_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0
@ -60,46 +81,81 @@ int main(int argc, char** argv) {
}
// Prepare the DB for the test
MYSQL_QUERY(proxysql_mysql, "DROP DATABASE IF EXISTS reg_test_3493_use_comment");
MYSQL_QUERY(proxysql_mysql, "CREATE DATABASE reg_test_3493_use_comment");
int err = mysql_query(proxysql_mysql, "/*+ placeholder_comment */ USE reg_test_3493_use_comment");
if (err) {
diag(
"'USE' command failed with error code '%d' and error '%s'",
err, mysql_error(proxysql_mysql)
);
return EXIT_FAILURE;
}
// Perform the 'SELECT DATABASE()' query in a new backend connection, to
// verify that ProxySQL is properly tracking the previously performed 'USE'
// statement.
MYSQL_QUERY(proxysql_mysql, "/*+ ;create_new_connection=1 */ SELECT DATABASE()");
MYSQL_RES* result = mysql_store_result(proxysql_mysql);
if (result == nullptr) {
diag("Invalid 'MYSQL_RES' returned from 'SELECT DATABASE()'");
return EXIT_FAILURE;
for (std::vector<std::pair<std::string,std::string>>::iterator it = db_query.begin(); it != db_query.end() ; it++) {
// MYSQL_QUERY(proxysql_mysql, "DROP DATABASE IF EXISTS reg_test_3493_use_comment");
// MYSQL_QUERY(proxysql_mysql, "CREATE DATABASE reg_test_3493_use_comment");
std::string s = "";
s = "DROP DATABASE IF EXISTS " + it->first;
MYSQL_QUERY(proxysql_mysql, s.c_str());
s = "CREATE DATABASE " + it->first;
MYSQL_QUERY(proxysql_mysql, s.c_str());
}
MYSQL_ROW row = mysql_fetch_row(result);
if (row == nullptr) {
diag("Invalid 'MYSQL_ROW' returned from 'SELECT DATABASE()'");
return EXIT_FAILURE;
for (std::vector<std::pair<std::string,std::string>>::iterator it = db_query.begin(); it != db_query.end() ; it++) {
int i = 0;
int err = mysql_query(proxysql_mysql, it->second.c_str());
if (err) {
diag(
"'USE' command failed with error code '%d' and error '%s' for query: %s",
err, mysql_error(proxysql_mysql), it->second.c_str()
);
return EXIT_FAILURE;
}
// Perform the 'SELECT DATABASE()' query in a new backend connection, to
// verify that ProxySQL is properly tracking the previously performed 'USE'
// statement.
switch (i%5) {
case 0:
MYSQL_QUERY(proxysql_mysql, "/*+ ;create_new_connection=1 */ SELECT DATABASE()");
break;
case 1:
MYSQL_QUERY(proxysql_mysql, "/*+ ;create_new_connection=1 */SELECT DATABASE()");
break;
case 2:
MYSQL_QUERY(proxysql_mysql, "SELECT /*+ ;create_new_connection=1 */ DATABASE()");
break;
case 3:
MYSQL_QUERY(proxysql_mysql, "SELECT/*+ ;create_new_connection=1 */ DATABASE()");
break;
case 4:
MYSQL_QUERY(proxysql_mysql, "SELECT /*+ ;create_new_connection=1 */DATABASE()");
break;
default:
assert(0);
}
i++;
MYSQL_RES* result = mysql_store_result(proxysql_mysql);
if (result == nullptr) {
diag("Invalid 'MYSQL_RES' returned from 'SELECT DATABASE()'");
return EXIT_FAILURE;
}
MYSQL_ROW row = mysql_fetch_row(result);
if (row == nullptr) {
diag("Invalid 'MYSQL_ROW' returned from 'SELECT DATABASE()'");
return EXIT_FAILURE;
}
std::string database_name { row[0] };
if (it->first[0] == '`') {
database_name = "`" + database_name + "`";
}
ok(
database_name == it->first,
"Selected DB name should be equal to actual DB name: (Exp: '%s') == (Act: '%s')",
it->first.c_str(),
database_name.c_str()
);
}
std::string database_name { row[0] };
ok(
database_name == "reg_test_3493_use_comment",
"Selected DB name should be equal to actual DB name: (Exp: '%s') == (Act: '%s')",
"reg_test_3493_use_comment",
database_name.c_str()
);
// Drop created database
MYSQL_QUERY(proxysql_mysql, "DROP DATABASE IF EXISTS reg_test_3493_use_comment");
for (std::vector<std::pair<std::string,std::string>>::iterator it = db_query.begin(); it != db_query.end() ; it++) {
std::string s = "";
s = "DROP DATABASE IF EXISTS " + it->first;
MYSQL_QUERY(proxysql_mysql, s.c_str());
}
mysql_close(proxysql_mysql);
return exit_status();

Loading…
Cancel
Save