MXS-1278: Sql mode must be specified explicitly
The default sql mode must now be provided explicitly when the query classifier is setup. This is in preparation for "sql_mode" becoming a global configuration parameter of MaxScale.
This commit is contained in:
@ -185,12 +185,13 @@ typedef struct query_classifier
|
|||||||
/**
|
/**
|
||||||
* Called once to setup the query classifier
|
* Called once to setup the query classifier
|
||||||
*
|
*
|
||||||
* @param args The value of `query_classifier_args` in the configuration file.
|
* @param sql_mode The default sql mode.
|
||||||
|
* @param args The value of `query_classifier_args` in the configuration file.
|
||||||
*
|
*
|
||||||
* @return QC_RESULT_OK, if the query classifier could be setup, otherwise
|
* @return QC_RESULT_OK, if the query classifier could be setup, otherwise
|
||||||
* some specific error code.
|
* some specific error code.
|
||||||
*/
|
*/
|
||||||
int32_t (*qc_setup)(const char* args);
|
int32_t (*qc_setup)(qc_sql_mode_t sql_mode, const char* args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called once at process startup, after @c qc_setup has successfully
|
* Called once at process startup, after @c qc_setup has successfully
|
||||||
@ -417,6 +418,7 @@ typedef struct query_classifier
|
|||||||
*
|
*
|
||||||
* @param plugin_name The name of the plugin from which the query classifier
|
* @param plugin_name The name of the plugin from which the query classifier
|
||||||
* should be loaded.
|
* should be loaded.
|
||||||
|
* @param sql_mode The default sql mode.
|
||||||
* @param plugin_args The arguments to be provided to the query classifier.
|
* @param plugin_args The arguments to be provided to the query classifier.
|
||||||
*
|
*
|
||||||
* @return True if the query classifier could be loaded and initialized,
|
* @return True if the query classifier could be loaded and initialized,
|
||||||
@ -424,7 +426,7 @@ typedef struct query_classifier
|
|||||||
*
|
*
|
||||||
* @see qc_end qc_thread_init
|
* @see qc_end qc_thread_init
|
||||||
*/
|
*/
|
||||||
bool qc_setup(const char* plugin_name, const char* plugin_args);
|
bool qc_setup(const char* plugin_name, qc_sql_mode_t sql_mode, const char* plugin_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intializes the query classifier.
|
* Intializes the query classifier.
|
||||||
|
@ -86,7 +86,7 @@ int32_t qc_dummy_get_function_info(GWBUF* query, const QC_FUNCTION_INFO** ppInfo
|
|||||||
return QC_RESULT_OK;
|
return QC_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t qc_dummy_setup(const char* args)
|
int32_t qc_dummy_setup(qc_sql_mode_t sql_mode, const char* args)
|
||||||
{
|
{
|
||||||
return QC_RESULT_OK;
|
return QC_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
@ -2969,47 +2969,19 @@ void configure_options(const char* datadir, const char* langdir)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t qc_mysql_setup(const char* zArgs)
|
int32_t qc_mysql_setup(qc_sql_mode_t sql_mode, const char* zArgs)
|
||||||
{
|
{
|
||||||
|
this_unit.sql_mode = sql_mode;
|
||||||
|
|
||||||
|
if (sql_mode == QC_SQL_MODE_ORACLE)
|
||||||
|
{
|
||||||
|
this_unit.function_name_mappings = function_name_mappings_oracle;
|
||||||
|
}
|
||||||
|
|
||||||
if (zArgs)
|
if (zArgs)
|
||||||
{
|
{
|
||||||
#if MYSQL_VERSION_MINOR >= 3
|
|
||||||
char args[strlen(zArgs) + 1];
|
|
||||||
strcpy(args, zArgs);
|
|
||||||
|
|
||||||
char *p1;
|
|
||||||
char *token = strtok_r(args, ",", &p1);
|
|
||||||
|
|
||||||
while (token)
|
|
||||||
{
|
|
||||||
char *p2;
|
|
||||||
char* key = trim(strtok_r(token, "=", &p2));
|
|
||||||
|
|
||||||
if (strcmp(key, "sql_mode") == 0)
|
|
||||||
{
|
|
||||||
char* value = trim(p2);
|
|
||||||
|
|
||||||
if (strcmp(value, "MODE_ORACLE") == 0)
|
|
||||||
{
|
|
||||||
this_unit.sql_mode = QC_SQL_MODE_ORACLE;
|
|
||||||
this_unit.function_name_mappings = function_name_mappings_oracle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_WARNING("Unknown value \"%s\" for key \"%s\"", value, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_WARNING("Unknown argument \"%s\".", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
token = strtok_r(NULL, ",", &p1);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
MXS_WARNING("'%s' provided as arguments, "
|
MXS_WARNING("'%s' provided as arguments, "
|
||||||
"even though no arguments are supported.", zArgs);
|
"even though no arguments are supported.", zArgs);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QC_RESULT_OK;
|
return QC_RESULT_OK;
|
||||||
|
@ -3294,7 +3294,7 @@ void maxscaleUse(Parse* pParse, Token* pToken)
|
|||||||
/**
|
/**
|
||||||
* API
|
* API
|
||||||
*/
|
*/
|
||||||
static int32_t qc_sqlite_setup(const char* args);
|
static int32_t qc_sqlite_setup(qc_sql_mode_t sql_mode, const char* args);
|
||||||
static int32_t qc_sqlite_process_init(void);
|
static int32_t qc_sqlite_process_init(void);
|
||||||
static void qc_sqlite_process_end(void);
|
static void qc_sqlite_process_end(void);
|
||||||
static int32_t qc_sqlite_thread_init(void);
|
static int32_t qc_sqlite_thread_init(void);
|
||||||
@ -3329,16 +3329,14 @@ static bool get_key_and_value(char* arg, const char** pkey, const char** pvalue)
|
|||||||
|
|
||||||
static const char ARG_LOG_UNRECOGNIZED_STATEMENTS[] = "log_unrecognized_statements";
|
static const char ARG_LOG_UNRECOGNIZED_STATEMENTS[] = "log_unrecognized_statements";
|
||||||
static const char ARG_PARSE_AS[] = "parse_as";
|
static const char ARG_PARSE_AS[] = "parse_as";
|
||||||
static const char ARG_SQL_MODE[] = "sql_mode";
|
|
||||||
|
|
||||||
static int32_t qc_sqlite_setup(const char* cargs)
|
static int32_t qc_sqlite_setup(qc_sql_mode_t sql_mode, const char* cargs)
|
||||||
{
|
{
|
||||||
QC_TRACE();
|
QC_TRACE();
|
||||||
assert(!this_unit.setup);
|
assert(!this_unit.setup);
|
||||||
|
|
||||||
qc_log_level_t log_level = QC_LOG_NOTHING;
|
qc_log_level_t log_level = QC_LOG_NOTHING;
|
||||||
qc_sql_mode_t sql_mode = QC_SQL_MODE_DEFAULT;
|
qc_parse_as_t parse_as = (sql_mode == QC_SQL_MODE_ORACLE) ? QC_PARSE_AS_103 : QC_PARSE_AS_DEFAULT;
|
||||||
qc_parse_as_t parse_as = QC_PARSE_AS_DEFAULT;
|
|
||||||
QC_NAME_MAPPING* function_name_mappings = function_name_mappings_default;
|
QC_NAME_MAPPING* function_name_mappings = function_name_mappings_default;
|
||||||
|
|
||||||
if (cargs)
|
if (cargs)
|
||||||
@ -3385,21 +3383,6 @@ static int32_t qc_sqlite_setup(const char* cargs)
|
|||||||
"Parsing as pre-10.3.", value, key);
|
"Parsing as pre-10.3.", value, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(key, ARG_SQL_MODE) == 0)
|
|
||||||
{
|
|
||||||
if (strcmp(value, "MODE_ORACLE") == 0)
|
|
||||||
{
|
|
||||||
sql_mode = QC_SQL_MODE_ORACLE;
|
|
||||||
MXS_NOTICE("Expecting Oracle SQL.");
|
|
||||||
|
|
||||||
parse_as = QC_PARSE_AS_103;
|
|
||||||
MXS_NOTICE("Parsing as 10.3.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_WARNING("Unknown value \"%s\" for key \"%s\"", value, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MXS_WARNING("'%s' is not a recognized argument.", key);
|
MXS_WARNING("'%s' is not a recognized argument.", key);
|
||||||
|
@ -46,7 +46,7 @@ int main(int argc, char** argv)
|
|||||||
set_langdir(strdup("."));
|
set_langdir(strdup("."));
|
||||||
set_process_datadir(strdup("/tmp"));
|
set_process_datadir(strdup("/tmp"));
|
||||||
|
|
||||||
qc_setup("qc_sqlite", NULL);
|
qc_setup("qc_sqlite", QC_SQL_MODE_DEFAULT, NULL);
|
||||||
qc_process_init(QC_INIT_BOTH);
|
qc_process_init(QC_INIT_BOTH);
|
||||||
|
|
||||||
infile = fopen(argv[1], "rb");
|
infile = fopen(argv[1], "rb");
|
||||||
|
@ -313,7 +313,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||||
{
|
{
|
||||||
if (qc_setup(lib, NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup(lib, QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
rc = run(input_name, expected_name);
|
rc = run(input_name, expected_name);
|
||||||
qc_process_end(QC_INIT_BOTH);
|
qc_process_end(QC_INIT_BOTH);
|
||||||
|
@ -53,14 +53,15 @@ namespace
|
|||||||
|
|
||||||
char USAGE[] =
|
char USAGE[] =
|
||||||
"usage: compare [-r count] [-d] [-1 classfier1] [-2 classifier2] "
|
"usage: compare [-r count] [-d] [-1 classfier1] [-2 classifier2] "
|
||||||
"[-A args] [-B args] [-v [0..2]] [-s statement]|[file]]\n\n"
|
"[-A args] [-B args] [-C args] [-m [default|oracle]] [-v [0..2]] [-s statement]|[file]]\n\n"
|
||||||
"-r redo the test the specified number of times; 0 means forever, default is 1\n"
|
"-r redo the test the specified number of times; 0 means forever, default is 1\n"
|
||||||
"-d don't stop after first failed query\n"
|
"-d don't stop after first failed query\n"
|
||||||
"-1 the first classifier, default qc_mysqlembedded\n"
|
"-1 the first classifier, default 'qc_mysqlembedded'\n"
|
||||||
"-2 the second classifier, default qc_sqlite\n"
|
"-2 the second classifier, default 'qc_sqlite'\n"
|
||||||
"-A arguments for the first classifier\n"
|
"-A arguments for the first classifier\n"
|
||||||
"-B arguments for the second classifier\n"
|
"-B arguments for the second classifier\n"
|
||||||
"-C arguments for both classifiers\n"
|
"-C arguments for both classifiers\n"
|
||||||
|
"-m initial sql mode, 'default' or 'oracle', default is 'default'\n"
|
||||||
"-s compare single statement\n"
|
"-s compare single statement\n"
|
||||||
"-S strict, also require that the parse result is identical\n"
|
"-S strict, also require that the parse result is identical\n"
|
||||||
"-R strict reporting, report if parse result is different\n"
|
"-R strict reporting, report if parse result is different\n"
|
||||||
@ -173,13 +174,13 @@ QUERY_CLASSIFIER* load_classifier(const char* name)
|
|||||||
return pClassifier;
|
return pClassifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUERY_CLASSIFIER* get_classifier(const char* zName, const char* zArgs)
|
QUERY_CLASSIFIER* get_classifier(const char* zName, qc_sql_mode_t sql_mode, const char* zArgs)
|
||||||
{
|
{
|
||||||
QUERY_CLASSIFIER* pClassifier = load_classifier(zName);
|
QUERY_CLASSIFIER* pClassifier = load_classifier(zName);
|
||||||
|
|
||||||
if (pClassifier)
|
if (pClassifier)
|
||||||
{
|
{
|
||||||
if ((pClassifier->qc_setup(zArgs) != QC_RESULT_OK) ||
|
if ((pClassifier->qc_setup(sql_mode, zArgs) != QC_RESULT_OK) ||
|
||||||
((pClassifier->qc_process_init() != QC_RESULT_OK)))
|
((pClassifier->qc_process_init() != QC_RESULT_OK)))
|
||||||
{
|
{
|
||||||
cerr << "error: Could not setup or init classifier " << zName << "." << endl;
|
cerr << "error: Could not setup or init classifier " << zName << "." << endl;
|
||||||
@ -200,16 +201,17 @@ void put_classifier(QUERY_CLASSIFIER* pClassifier)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_classifiers(const char* zName1, const char* zArgs1, QUERY_CLASSIFIER** ppClassifier1,
|
bool get_classifiers(qc_sql_mode_t sql_mode,
|
||||||
|
const char* zName1, const char* zArgs1, QUERY_CLASSIFIER** ppClassifier1,
|
||||||
const char* zName2, const char* zArgs2, QUERY_CLASSIFIER** ppClassifier2)
|
const char* zName2, const char* zArgs2, QUERY_CLASSIFIER** ppClassifier2)
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
|
|
||||||
QUERY_CLASSIFIER* pClassifier1 = get_classifier(zName1, zArgs1);
|
QUERY_CLASSIFIER* pClassifier1 = get_classifier(zName1, sql_mode, zArgs1);
|
||||||
|
|
||||||
if (pClassifier1)
|
if (pClassifier1)
|
||||||
{
|
{
|
||||||
QUERY_CLASSIFIER* pClassifier2 = get_classifier(zName2, zArgs2);
|
QUERY_CLASSIFIER* pClassifier2 = get_classifier(zName2, sql_mode, zArgs2);
|
||||||
|
|
||||||
if (pClassifier2)
|
if (pClassifier2)
|
||||||
{
|
{
|
||||||
@ -1369,11 +1371,12 @@ int main(int argc, char* argv[])
|
|||||||
string classifier2Args("log_unrecognized_statements=1");
|
string classifier2Args("log_unrecognized_statements=1");
|
||||||
#endif
|
#endif
|
||||||
const char* zStatement = NULL;
|
const char* zStatement = NULL;
|
||||||
|
qc_sql_mode_t sql_mode = QC_SQL_MODE_DEFAULT;
|
||||||
|
|
||||||
size_t rounds = 1;
|
size_t rounds = 1;
|
||||||
int v = VERBOSITY_NORMAL;
|
int v = VERBOSITY_NORMAL;
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt(argc, argv, "r:d1:2:v:A:B:C:s:SR")) != -1)
|
while ((c = getopt(argc, argv, "r:d1:2:v:A:B:C:m:s:SR")) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -1414,6 +1417,22 @@ int main(int argc, char* argv[])
|
|||||||
zStatement = optarg;
|
zStatement = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
if (strcasecmp(optarg, "default") == 0)
|
||||||
|
{
|
||||||
|
sql_mode = QC_SQL_MODE_DEFAULT;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(optarg, "oracle") == 0)
|
||||||
|
{
|
||||||
|
sql_mode = QC_SQL_MODE_ORACLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = EXIT_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
global.strict = true;
|
global.strict = true;
|
||||||
break;
|
break;
|
||||||
@ -1449,7 +1468,8 @@ int main(int argc, char* argv[])
|
|||||||
QUERY_CLASSIFIER* pClassifier1;
|
QUERY_CLASSIFIER* pClassifier1;
|
||||||
QUERY_CLASSIFIER* pClassifier2;
|
QUERY_CLASSIFIER* pClassifier2;
|
||||||
|
|
||||||
if (get_classifiers(zClassifier1, zClassifier1Args, &pClassifier1,
|
if (get_classifiers(sql_mode,
|
||||||
|
zClassifier1, zClassifier1Args, &pClassifier1,
|
||||||
zClassifier2, zClassifier2Args, &pClassifier2))
|
zClassifier2, zClassifier2Args, &pClassifier2))
|
||||||
{
|
{
|
||||||
size_t round = 0;
|
size_t round = 0;
|
||||||
|
@ -41,7 +41,7 @@ int main()
|
|||||||
|
|
||||||
set_libdir(strdup("../qc_sqlite"));
|
set_libdir(strdup("../qc_sqlite"));
|
||||||
|
|
||||||
if (qc_setup("qc_sqlite", NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup("qc_sqlite", QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
const char s[] = "SELECT @@global.max_allowed_packet";
|
const char s[] = "SELECT @@global.max_allowed_packet";
|
||||||
|
|
||||||
|
@ -1897,7 +1897,7 @@ int main(int argc, char **argv)
|
|||||||
cnf = config_get_global_options();
|
cnf = config_get_global_options();
|
||||||
ss_dassert(cnf);
|
ss_dassert(cnf);
|
||||||
|
|
||||||
if (!qc_setup(cnf->qc_name, cnf->qc_args))
|
if (!qc_setup(cnf->qc_name, QC_SQL_MODE_DEFAULT, cnf->qc_args))
|
||||||
{
|
{
|
||||||
const char* logerr = "Failed to initialise query classifier library.";
|
const char* logerr = "Failed to initialise query classifier library.";
|
||||||
print_log_n_stderr(true, true, logerr, logerr, eno);
|
print_log_n_stderr(true, true, logerr, logerr, eno);
|
||||||
|
@ -45,7 +45,7 @@ static QUERY_CLASSIFIER* classifier;
|
|||||||
static qc_trx_parse_using_t qc_trx_parse_using = QC_TRX_PARSE_USING_PARSER;
|
static qc_trx_parse_using_t qc_trx_parse_using = QC_TRX_PARSE_USING_PARSER;
|
||||||
|
|
||||||
|
|
||||||
bool qc_setup(const char* plugin_name, const char* plugin_args)
|
bool qc_setup(const char* plugin_name, qc_sql_mode_t sql_mode, const char* plugin_args)
|
||||||
{
|
{
|
||||||
QC_TRACE();
|
QC_TRACE();
|
||||||
ss_dassert(!classifier);
|
ss_dassert(!classifier);
|
||||||
@ -61,7 +61,7 @@ bool qc_setup(const char* plugin_name, const char* plugin_args)
|
|||||||
|
|
||||||
if (classifier)
|
if (classifier)
|
||||||
{
|
{
|
||||||
rv = classifier->qc_setup(plugin_args);
|
rv = classifier->qc_setup(sql_mode, plugin_args);
|
||||||
|
|
||||||
if (rv != QC_RESULT_OK)
|
if (rv != QC_RESULT_OK)
|
||||||
{
|
{
|
||||||
|
@ -184,7 +184,7 @@ int main(int argc, char* argv[])
|
|||||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||||
{
|
{
|
||||||
// We have to setup something in order for the regexes to be compiled.
|
// We have to setup something in order for the regexes to be compiled.
|
||||||
if (qc_setup("qc_sqlite", NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup("qc_sqlite", QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
Tester tester(verbosity);
|
Tester tester(verbosity);
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ int main(int argc, char* argv[])
|
|||||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||||
{
|
{
|
||||||
// We have to setup something in order for the regexes to be compiled.
|
// We have to setup something in order for the regexes to be compiled.
|
||||||
if (qc_setup("qc_sqlite", NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup("qc_sqlite", QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
rc = EXIT_SUCCESS;
|
rc = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||||
{
|
{
|
||||||
if (qc_setup(NULL, NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup(NULL, QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
const char* zModule = argv[1];
|
const char* zModule = argv[1];
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ int main()
|
|||||||
pConfig->n_threads = 1;
|
pConfig->n_threads = 1;
|
||||||
|
|
||||||
set_libdir(MXS_STRDUP_A("../../../../../query_classifier/qc_sqlite/"));
|
set_libdir(MXS_STRDUP_A("../../../../../query_classifier/qc_sqlite/"));
|
||||||
if (qc_setup("qc_sqlite", "") && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup("qc_sqlite", QC_SQL_MODE_DEFAULT, "") && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
set_libdir(MXS_STRDUP_A("../"));
|
set_libdir(MXS_STRDUP_A("../"));
|
||||||
rc = test();
|
rc = test();
|
||||||
|
@ -50,7 +50,7 @@ int TestStorage::run(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||||
{
|
{
|
||||||
if (qc_setup(NULL, NULL) && qc_process_init(QC_INIT_BOTH))
|
if (qc_setup(NULL, QC_SQL_MODE_DEFAULT, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||||
{
|
{
|
||||||
const char* zModule = NULL;
|
const char* zModule = NULL;
|
||||||
size_t threads = m_threads;
|
size_t threads = m_threads;
|
||||||
|
Reference in New Issue
Block a user