MXS-1275: Function name mappings need to follow sql_mode
This commit is contained in:
@ -74,30 +74,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define MYSQL_COM_QUERY_HEADER_SIZE 5 /*< 3 bytes size, 1 sequence, 1 command */
|
|
||||||
#define MAX_QUERYBUF_SIZE 2048
|
|
||||||
typedef struct parsing_info_st
|
|
||||||
{
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
skygw_chk_t pi_chk_top;
|
|
||||||
#endif
|
|
||||||
void* pi_handle; /*< parsing info object pointer */
|
|
||||||
char* pi_query_plain_str; /*< query as plain string */
|
|
||||||
void (*pi_done_fp)(void *); /*< clean-up function for parsing info */
|
|
||||||
QC_FIELD_INFO* field_infos;
|
|
||||||
size_t field_infos_len;
|
|
||||||
size_t field_infos_capacity;
|
|
||||||
QC_FUNCTION_INFO* function_infos;
|
|
||||||
size_t function_infos_len;
|
|
||||||
size_t function_infos_capacity;
|
|
||||||
GWBUF* preparable_stmt;
|
|
||||||
qc_parse_result_t result;
|
|
||||||
int32_t type_mask;
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
skygw_chk_t pi_chk_tail;
|
|
||||||
#endif
|
|
||||||
} parsing_info_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines what a particular name should be mapped to.
|
* Defines what a particular name should be mapped to.
|
||||||
*/
|
*/
|
||||||
@ -119,9 +95,7 @@ static NAME_MAPPING function_name_mappings_oracle[] =
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static NAME_MAPPING* function_name_mappings = function_name_mappings_default;
|
static const char* map_function_name(NAME_MAPPING* function_name_mappings, const char* from)
|
||||||
|
|
||||||
static const char* map_function_name(const char* from)
|
|
||||||
{
|
{
|
||||||
NAME_MAPPING* map = function_name_mappings;
|
NAME_MAPPING* map = function_name_mappings;
|
||||||
const char* to = NULL;
|
const char* to = NULL;
|
||||||
@ -141,6 +115,31 @@ static const char* map_function_name(const char* from)
|
|||||||
return to ? to : from;
|
return to ? to : from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MYSQL_COM_QUERY_HEADER_SIZE 5 /*< 3 bytes size, 1 sequence, 1 command */
|
||||||
|
#define MAX_QUERYBUF_SIZE 2048
|
||||||
|
typedef struct parsing_info_st
|
||||||
|
{
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t pi_chk_top;
|
||||||
|
#endif
|
||||||
|
void* pi_handle; /*< parsing info object pointer */
|
||||||
|
char* pi_query_plain_str; /*< query as plain string */
|
||||||
|
void (*pi_done_fp)(void *); /*< clean-up function for parsing info */
|
||||||
|
QC_FIELD_INFO* field_infos;
|
||||||
|
size_t field_infos_len;
|
||||||
|
size_t field_infos_capacity;
|
||||||
|
QC_FUNCTION_INFO* function_infos;
|
||||||
|
size_t function_infos_len;
|
||||||
|
size_t function_infos_capacity;
|
||||||
|
GWBUF* preparable_stmt;
|
||||||
|
qc_parse_result_t result;
|
||||||
|
int32_t type_mask;
|
||||||
|
NAME_MAPPING* function_name_mappings;
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t pi_chk_tail;
|
||||||
|
#endif
|
||||||
|
} parsing_info_t;
|
||||||
|
|
||||||
#define QTYPE_LESS_RESTRICTIVE_THAN_WRITE(t) (t<QUERY_TYPE_WRITE ? true : false)
|
#define QTYPE_LESS_RESTRICTIVE_THAN_WRITE(t) (t<QUERY_TYPE_WRITE ? true : false)
|
||||||
|
|
||||||
static THD* get_or_create_thd_for_parsing(MYSQL* mysql, char* query_str);
|
static THD* get_or_create_thd_for_parsing(MYSQL* mysql, char* query_str);
|
||||||
@ -175,9 +174,27 @@ inline void get_string_and_length(const char* cs, const char** s, size_t* length
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static qc_sql_mode_t default_qc_sql_mode = QC_SQL_MODE_DEFAULT;
|
static struct
|
||||||
static thread_local qc_sql_mode_t thread_qc_sql_mode = QC_SQL_MODE_DEFAULT;
|
{
|
||||||
static pthread_mutex_t sql_mode_mutex = PTHREAD_MUTEX_INITIALIZER;
|
qc_sql_mode_t sql_mode;
|
||||||
|
pthread_mutex_t sql_mode_mutex;
|
||||||
|
NAME_MAPPING* function_name_mappings;
|
||||||
|
} this_unit =
|
||||||
|
{
|
||||||
|
QC_SQL_MODE_DEFAULT,
|
||||||
|
PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
function_name_mappings_default
|
||||||
|
};
|
||||||
|
|
||||||
|
static thread_local struct
|
||||||
|
{
|
||||||
|
qc_sql_mode_t sql_mode;
|
||||||
|
NAME_MAPPING* function_name_mappings;
|
||||||
|
} this_thread =
|
||||||
|
{
|
||||||
|
QC_SQL_MODE_DEFAULT,
|
||||||
|
function_name_mappings_default
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the query is parsed. If it is not already parsed, it
|
* Ensures that the query is parsed. If it is not already parsed, it
|
||||||
@ -206,10 +223,10 @@ bool ensure_query_is_parsed(GWBUF* query)
|
|||||||
|
|
||||||
ss_debug(int rv);
|
ss_debug(int rv);
|
||||||
|
|
||||||
ss_debug(rv = )pthread_mutex_lock(&sql_mode_mutex);
|
ss_debug(rv = )pthread_mutex_lock(&this_unit.sql_mode_mutex);
|
||||||
ss_dassert(rv == 0);
|
ss_dassert(rv == 0);
|
||||||
|
|
||||||
if (thread_qc_sql_mode == QC_SQL_MODE_ORACLE)
|
if (this_thread.sql_mode == QC_SQL_MODE_ORACLE)
|
||||||
{
|
{
|
||||||
global_system_variables.sql_mode |= MODE_ORACLE;
|
global_system_variables.sql_mode |= MODE_ORACLE;
|
||||||
}
|
}
|
||||||
@ -220,7 +237,7 @@ bool ensure_query_is_parsed(GWBUF* query)
|
|||||||
|
|
||||||
parsed = parse_query(query);
|
parsed = parse_query(query);
|
||||||
|
|
||||||
ss_debug(rv = )pthread_mutex_unlock(&sql_mode_mutex);
|
ss_debug(rv = )pthread_mutex_unlock(&this_unit.sql_mode_mutex);
|
||||||
ss_dassert(rv == 0);
|
ss_dassert(rv == 0);
|
||||||
|
|
||||||
if (!parsed)
|
if (!parsed)
|
||||||
@ -1675,6 +1692,8 @@ static parsing_info_t* parsing_info_init(void (*donefun)(void *))
|
|||||||
pi->pi_handle = mysql;
|
pi->pi_handle = mysql;
|
||||||
pi->pi_done_fp = donefun;
|
pi->pi_done_fp = donefun;
|
||||||
pi->result = QC_QUERY_INVALID;
|
pi->result = QC_QUERY_INVALID;
|
||||||
|
ss_dassert(this_thread.function_name_mappings);
|
||||||
|
pi->function_name_mappings = this_thread.function_name_mappings;
|
||||||
|
|
||||||
retblock:
|
retblock:
|
||||||
return pi;
|
return pi;
|
||||||
@ -2207,7 +2226,7 @@ static void add_function_info(parsing_info_t* info,
|
|||||||
{
|
{
|
||||||
ss_dassert(name);
|
ss_dassert(name);
|
||||||
|
|
||||||
name = map_function_name(name);
|
name = map_function_name(info->function_name_mappings, name);
|
||||||
|
|
||||||
QC_FUNCTION_INFO item = { (char*)name, usage };
|
QC_FUNCTION_INFO item = { (char*)name, usage };
|
||||||
|
|
||||||
@ -2972,8 +2991,8 @@ int32_t qc_mysql_setup(const char* zArgs)
|
|||||||
|
|
||||||
if (strcmp(value, "MODE_ORACLE") == 0)
|
if (strcmp(value, "MODE_ORACLE") == 0)
|
||||||
{
|
{
|
||||||
default_qc_sql_mode = QC_SQL_MODE_ORACLE;
|
this_unit.sql_mode = QC_SQL_MODE_ORACLE;
|
||||||
function_name_mappings = function_name_mappings_oracle;
|
this_unit.function_name_mappings = function_name_mappings_oracle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3016,6 +3035,10 @@ int32_t qc_mysql_process_init(void)
|
|||||||
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
|
this_thread.sql_mode = this_unit.sql_mode;
|
||||||
|
ss_dassert(this_unit.function_name_mappings);
|
||||||
|
this_thread.function_name_mappings = this_unit.function_name_mappings;
|
||||||
|
|
||||||
MXS_ERROR("mysql_library_init() failed. Error code: %d", rc);
|
MXS_ERROR("mysql_library_init() failed. Error code: %d", rc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3038,7 +3061,9 @@ void qc_mysql_process_end(void)
|
|||||||
|
|
||||||
int32_t qc_mysql_thread_init(void)
|
int32_t qc_mysql_thread_init(void)
|
||||||
{
|
{
|
||||||
thread_qc_sql_mode = default_qc_sql_mode;
|
this_thread.sql_mode = this_unit.sql_mode;
|
||||||
|
ss_dassert(this_unit.function_name_mappings);
|
||||||
|
this_thread.function_name_mappings = this_unit.function_name_mappings;
|
||||||
|
|
||||||
bool inited = (mysql_thread_init() == 0);
|
bool inited = (mysql_thread_init() == 0);
|
||||||
|
|
||||||
@ -3057,7 +3082,7 @@ void qc_mysql_thread_end(void)
|
|||||||
|
|
||||||
int32_t qc_mysql_get_sql_mode(qc_sql_mode_t* sql_mode)
|
int32_t qc_mysql_get_sql_mode(qc_sql_mode_t* sql_mode)
|
||||||
{
|
{
|
||||||
*sql_mode = thread_qc_sql_mode;
|
*sql_mode = this_thread.sql_mode;
|
||||||
return QC_RESULT_OK;
|
return QC_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3065,12 +3090,19 @@ int32_t qc_mysql_set_sql_mode(qc_sql_mode_t sql_mode)
|
|||||||
{
|
{
|
||||||
int32_t rv = QC_RESULT_OK;
|
int32_t rv = QC_RESULT_OK;
|
||||||
|
|
||||||
if ((sql_mode == QC_SQL_MODE_DEFAULT) || (sql_mode == QC_SQL_MODE_ORACLE))
|
switch (sql_mode)
|
||||||
{
|
|
||||||
thread_qc_sql_mode = sql_mode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
case QC_SQL_MODE_DEFAULT:
|
||||||
|
this_thread.sql_mode = sql_mode;
|
||||||
|
this_thread.function_name_mappings = function_name_mappings_default;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QC_SQL_MODE_ORACLE:
|
||||||
|
this_thread.sql_mode = sql_mode;
|
||||||
|
this_thread.function_name_mappings = function_name_mappings_oracle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
rv = QC_RESULT_ERROR;
|
rv = QC_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,45 +63,6 @@ typedef enum qc_parse_as
|
|||||||
QC_PARSE_AS_103 // Parse as embedded lib does in 10.3
|
QC_PARSE_AS_103 // Parse as embedded lib does in 10.3
|
||||||
} qc_parse_as_t;
|
} qc_parse_as_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains information about a particular query.
|
|
||||||
*/
|
|
||||||
typedef struct qc_sqlite_info
|
|
||||||
{
|
|
||||||
qc_parse_result_t status; // The validity of the information in this structure.
|
|
||||||
uint32_t collect; // What information should be collected.
|
|
||||||
uint32_t collected; // What information has been collected.
|
|
||||||
const char* query; // The query passed to sqlite.
|
|
||||||
size_t query_len; // The length of the query.
|
|
||||||
|
|
||||||
uint32_t type_mask; // The type mask of the query.
|
|
||||||
qc_query_op_t operation; // The operation in question.
|
|
||||||
bool has_clause; // Has WHERE or HAVING.
|
|
||||||
char** table_names; // Array of table names used in the query.
|
|
||||||
size_t table_names_len; // The used entries in table_names.
|
|
||||||
size_t table_names_capacity; // The capacity of table_names.
|
|
||||||
char** table_fullnames; // Array of full (i.e. qualified) table names used in the query.
|
|
||||||
size_t table_fullnames_len; // The used entries in table_fullnames.
|
|
||||||
size_t table_fullnames_capacity; // The capacity of table_fullnames.
|
|
||||||
char* created_table_name; // The name of a created table.
|
|
||||||
bool is_drop_table; // Is the query a DROP TABLE.
|
|
||||||
char** database_names; // Array of database names used in the query.
|
|
||||||
size_t database_names_len; // The used entries in database_names.
|
|
||||||
size_t database_names_capacity; // The capacity of database_names.
|
|
||||||
int keyword_1; // The first encountered keyword.
|
|
||||||
int keyword_2; // The second encountered keyword.
|
|
||||||
char* prepare_name; // The name of a prepared statement.
|
|
||||||
GWBUF* preparable_stmt; // The preparable statement.
|
|
||||||
QC_FIELD_INFO *field_infos; // Pointer to array of QC_FIELD_INFOs.
|
|
||||||
size_t field_infos_len; // The used entries in field_infos.
|
|
||||||
size_t field_infos_capacity; // The capacity of the field_infos array.
|
|
||||||
QC_FUNCTION_INFO *function_infos;// Pointer to array of QC_FUNCTION_INFOs.
|
|
||||||
size_t function_infos_len; // The used entries in function_infos.
|
|
||||||
size_t function_infos_capacity; // The capacity of the function_infos array.
|
|
||||||
bool initializing; // Whether we are initializing sqlite3.
|
|
||||||
qc_sql_mode_t sql_mode; // The current sql_mode.
|
|
||||||
} QC_SQLITE_INFO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines what a particular name should be mapped to.
|
* Defines what a particular name should be mapped to.
|
||||||
*/
|
*/
|
||||||
@ -130,6 +91,46 @@ static QC_NAME_MAPPING function_name_mappings_oracle[] =
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information about a particular query.
|
||||||
|
*/
|
||||||
|
typedef struct qc_sqlite_info
|
||||||
|
{
|
||||||
|
qc_parse_result_t status; // The validity of the information in this structure.
|
||||||
|
uint32_t collect; // What information should be collected.
|
||||||
|
uint32_t collected; // What information has been collected.
|
||||||
|
const char* query; // The query passed to sqlite.
|
||||||
|
size_t query_len; // The length of the query.
|
||||||
|
|
||||||
|
uint32_t type_mask; // The type mask of the query.
|
||||||
|
qc_query_op_t operation; // The operation in question.
|
||||||
|
bool has_clause; // Has WHERE or HAVING.
|
||||||
|
char** table_names; // Array of table names used in the query.
|
||||||
|
size_t table_names_len; // The used entries in table_names.
|
||||||
|
size_t table_names_capacity; // The capacity of table_names.
|
||||||
|
char** table_fullnames; // Array of full (i.e. qualified) table names used in the query.
|
||||||
|
size_t table_fullnames_len; // The used entries in table_fullnames.
|
||||||
|
size_t table_fullnames_capacity; // The capacity of table_fullnames.
|
||||||
|
char* created_table_name; // The name of a created table.
|
||||||
|
bool is_drop_table; // Is the query a DROP TABLE.
|
||||||
|
char** database_names; // Array of database names used in the query.
|
||||||
|
size_t database_names_len; // The used entries in database_names.
|
||||||
|
size_t database_names_capacity; // The capacity of database_names.
|
||||||
|
int keyword_1; // The first encountered keyword.
|
||||||
|
int keyword_2; // The second encountered keyword.
|
||||||
|
char* prepare_name; // The name of a prepared statement.
|
||||||
|
GWBUF* preparable_stmt; // The preparable statement.
|
||||||
|
QC_FIELD_INFO *field_infos; // Pointer to array of QC_FIELD_INFOs.
|
||||||
|
size_t field_infos_len; // The used entries in field_infos.
|
||||||
|
size_t field_infos_capacity; // The capacity of the field_infos array.
|
||||||
|
QC_FUNCTION_INFO *function_infos; // Pointer to array of QC_FUNCTION_INFOs.
|
||||||
|
size_t function_infos_len; // The used entries in function_infos.
|
||||||
|
size_t function_infos_capacity; // The capacity of the function_infos array.
|
||||||
|
bool initializing; // Whether we are initializing sqlite3.
|
||||||
|
qc_sql_mode_t sql_mode; // The current sql_mode.
|
||||||
|
QC_NAME_MAPPING* function_name_mappings; // How function names should be mapped.
|
||||||
|
} QC_SQLITE_INFO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of qc_sqlite.
|
* The state of qc_sqlite.
|
||||||
*/
|
*/
|
||||||
@ -148,10 +149,11 @@ static struct
|
|||||||
*/
|
*/
|
||||||
static thread_local struct
|
static thread_local struct
|
||||||
{
|
{
|
||||||
bool initialized; // Whether the thread specific data has been initialized.
|
bool initialized; // Whether the thread specific data has been initialized.
|
||||||
sqlite3* db; // Thread specific database handle.
|
sqlite3* db; // Thread specific database handle.
|
||||||
qc_sql_mode_t sql_mode; // What sql_mode is used.
|
qc_sql_mode_t sql_mode; // What sql_mode is used.
|
||||||
QC_SQLITE_INFO* info; // The information for the current statement being classified.
|
QC_SQLITE_INFO* info; // The information for the current statement being classified.
|
||||||
|
QC_NAME_MAPPING* function_name_mappings; // How function names should be mapped.
|
||||||
} this_thread;
|
} this_thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -182,7 +184,7 @@ static bool is_sequence_related_field(QC_SQLITE_INFO* info,
|
|||||||
const char* column);
|
const char* column);
|
||||||
static bool is_sequence_related_function(QC_SQLITE_INFO* info, const char* func_name);
|
static bool is_sequence_related_function(QC_SQLITE_INFO* info, const char* func_name);
|
||||||
static void log_invalid_data(GWBUF* query, const char* message);
|
static void log_invalid_data(GWBUF* query, const char* message);
|
||||||
static const char* map_function_name(const char* name);
|
static const char* map_function_name(QC_NAME_MAPPING* function_name_mappings, const char* name);
|
||||||
static bool parse_query(GWBUF* query, uint32_t collect);
|
static bool parse_query(GWBUF* query, uint32_t collect);
|
||||||
static void parse_query_string(const char* query, size_t len);
|
static void parse_query_string(const char* query, size_t len);
|
||||||
static bool query_is_parsed(GWBUF* query, uint32_t collect);
|
static bool query_is_parsed(GWBUF* query, uint32_t collect);
|
||||||
@ -439,6 +441,7 @@ static QC_SQLITE_INFO* info_init(QC_SQLITE_INFO* info, uint32_t collect)
|
|||||||
info->function_infos_capacity = 0;
|
info->function_infos_capacity = 0;
|
||||||
info->initializing = false;
|
info->initializing = false;
|
||||||
info->sql_mode = this_thread.sql_mode;
|
info->sql_mode = this_thread.sql_mode;
|
||||||
|
info->function_name_mappings = this_thread.function_name_mappings;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -747,9 +750,17 @@ static void log_invalid_data(GWBUF* query, const char* message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* map_function_name(const char* from)
|
/**
|
||||||
|
* Map a function name to another.
|
||||||
|
*
|
||||||
|
* @param function_name_mappings The name mapping to use.
|
||||||
|
* @param from The function name to map.
|
||||||
|
*
|
||||||
|
* @param The mapped name, or @c from if the name is not mapped.
|
||||||
|
*/
|
||||||
|
static const char* map_function_name(QC_NAME_MAPPING* function_name_mappings, const char* from)
|
||||||
{
|
{
|
||||||
QC_NAME_MAPPING* map = this_unit.function_name_mappings;
|
QC_NAME_MAPPING* map = function_name_mappings;
|
||||||
const char* to = NULL;
|
const char* to = NULL;
|
||||||
|
|
||||||
while (!to && map->from)
|
while (!to && map->from)
|
||||||
@ -926,7 +937,7 @@ static void update_function_info(QC_SQLITE_INFO* info,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = map_function_name(name);
|
name = map_function_name(info->function_name_mappings, name);
|
||||||
|
|
||||||
QC_FUNCTION_INFO item = { (char*)name, usage };
|
QC_FUNCTION_INFO item = { (char*)name, usage };
|
||||||
|
|
||||||
@ -3499,6 +3510,7 @@ static int32_t qc_sqlite_thread_init(void)
|
|||||||
if (rc == SQLITE_OK)
|
if (rc == SQLITE_OK)
|
||||||
{
|
{
|
||||||
this_thread.sql_mode = this_unit.sql_mode;
|
this_thread.sql_mode = this_unit.sql_mode;
|
||||||
|
this_thread.function_name_mappings = this_unit.function_name_mappings;
|
||||||
this_thread.initialized = true;
|
this_thread.initialized = true;
|
||||||
|
|
||||||
MXS_INFO("In-memory sqlite database successfully opened for thread %lu.",
|
MXS_INFO("In-memory sqlite database successfully opened for thread %lu.",
|
||||||
@ -3979,12 +3991,26 @@ int32_t qc_sqlite_set_sql_mode(qc_sql_mode_t sql_mode)
|
|||||||
{
|
{
|
||||||
int32_t rv = QC_RESULT_OK;
|
int32_t rv = QC_RESULT_OK;
|
||||||
|
|
||||||
if ((sql_mode == QC_SQL_MODE_DEFAULT) || (sql_mode == QC_SQL_MODE_ORACLE))
|
switch (sql_mode)
|
||||||
{
|
{
|
||||||
|
case QC_SQL_MODE_DEFAULT:
|
||||||
this_thread.sql_mode = sql_mode;
|
this_thread.sql_mode = sql_mode;
|
||||||
}
|
if (this_unit.parse_as == QC_PARSE_AS_103)
|
||||||
else
|
{
|
||||||
{
|
this_thread.function_name_mappings = function_name_mappings_103;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this_thread.function_name_mappings = function_name_mappings_default;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QC_SQL_MODE_ORACLE:
|
||||||
|
this_thread.sql_mode = sql_mode;
|
||||||
|
this_thread.function_name_mappings = function_name_mappings_oracle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
rv = QC_RESULT_ERROR;
|
rv = QC_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user