qc: Add minimal support for qc_get_prepare_name
If the query is a PREPARE or EXECUTE statement, then qc_get_prepare_name will return the name of the prepared statement.
This commit is contained in:
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
MXS_BEGIN_DECLS
|
MXS_BEGIN_DECLS
|
||||||
|
|
||||||
#define QUERY_CLASSIFIER_VERSION {1, 0, 0}
|
#define QUERY_CLASSIFIER_VERSION {1, 1, 0}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qc_query_type_t defines bits that provide information about a
|
* qc_query_type_t defines bits that provide information about a
|
||||||
@ -115,6 +115,7 @@ typedef struct query_classifier
|
|||||||
bool (*qc_query_has_clause)(GWBUF* stmt);
|
bool (*qc_query_has_clause)(GWBUF* stmt);
|
||||||
char* (*qc_get_affected_fields)(GWBUF* stmt);
|
char* (*qc_get_affected_fields)(GWBUF* stmt);
|
||||||
char** (*qc_get_database_names)(GWBUF* stmt, int* size);
|
char** (*qc_get_database_names)(GWBUF* stmt, int* size);
|
||||||
|
char* (*qc_get_prepare_name)(GWBUF* stmt);
|
||||||
} QUERY_CLASSIFIER;
|
} QUERY_CLASSIFIER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,6 +267,24 @@ char** qc_get_database_names(GWBUF* stmt, int* size);
|
|||||||
*/
|
*/
|
||||||
qc_query_op_t qc_get_operation(GWBUF* stmt);
|
qc_query_op_t qc_get_operation(GWBUF* stmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the prepared statement, if the statement
|
||||||
|
* is a PREPARE or EXECUTE statement.
|
||||||
|
*
|
||||||
|
* @param stmt A buffer containing a COM_QUERY packet.
|
||||||
|
*
|
||||||
|
* @return The name of the prepared statement, if the statement
|
||||||
|
* is a PREPARE or EXECUTE statement; otherwise NULL.
|
||||||
|
*
|
||||||
|
* @note The returned string @b must be freed by the caller.
|
||||||
|
*
|
||||||
|
* @note Even though a COM_STMT_PREPARE can be given to the query
|
||||||
|
* classifier for parsing, this function will in that case
|
||||||
|
* return NULL since the id of the statement is provided by
|
||||||
|
* the server.
|
||||||
|
*/
|
||||||
|
char* qc_get_prepare_name(GWBUF* stmt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tables accessed by the statement.
|
* Returns the tables accessed by the statement.
|
||||||
*
|
*
|
||||||
|
@ -1904,6 +1904,21 @@ qc_query_op_t qc_get_operation(GWBUF* querybuf)
|
|||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* qc_get_prepare_name(GWBUF* stmt)
|
||||||
|
{
|
||||||
|
char* name = NULL;
|
||||||
|
|
||||||
|
if (stmt)
|
||||||
|
{
|
||||||
|
if (ensure_query_is_parsed(stmt))
|
||||||
|
{
|
||||||
|
MXS_WARNING("qc_get_prepare_name not implemented yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -2048,6 +2063,7 @@ static QUERY_CLASSIFIER qc =
|
|||||||
qc_query_has_clause,
|
qc_query_has_clause,
|
||||||
qc_get_affected_fields,
|
qc_get_affected_fields,
|
||||||
qc_get_database_names,
|
qc_get_database_names,
|
||||||
|
qc_get_prepare_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* @see function load_module in load_utils.c for explanation of the following
|
/* @see function load_module in load_utils.c for explanation of the following
|
||||||
|
@ -2834,6 +2834,34 @@ static char** qc_sqlite_get_database_names(GWBUF* query, int* sizep)
|
|||||||
return database_names;
|
return database_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char* qc_sqlite_get_prepare_name(GWBUF* query)
|
||||||
|
{
|
||||||
|
QC_TRACE();
|
||||||
|
ss_dassert(this_unit.initialized);
|
||||||
|
ss_dassert(this_thread.initialized);
|
||||||
|
|
||||||
|
char* name = NULL;
|
||||||
|
QC_SQLITE_INFO* info = get_query_info(query);
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
if (qc_info_is_valid(info->status))
|
||||||
|
{
|
||||||
|
MXS_WARNING("qc_get_prepare_name not implemented yet.");
|
||||||
|
}
|
||||||
|
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
|
||||||
|
{
|
||||||
|
log_invalid_data(query, "cannot report the name of a prepared statement");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("The query could not be parsed. Response not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPORTS
|
* EXPORTS
|
||||||
*/
|
*/
|
||||||
@ -2857,6 +2885,7 @@ static QUERY_CLASSIFIER qc =
|
|||||||
qc_sqlite_query_has_clause,
|
qc_sqlite_query_has_clause,
|
||||||
qc_sqlite_get_affected_fields,
|
qc_sqlite_get_affected_fields,
|
||||||
qc_sqlite_get_database_names,
|
qc_sqlite_get_database_names,
|
||||||
|
qc_sqlite_get_prepare_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -814,6 +814,36 @@ bool compare_get_database_names(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1,
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compare_get_prepare_name(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1,
|
||||||
|
QUERY_CLASSIFIER* pClassifier2, GWBUF* pCopy2)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
const char HEADING[] = "qc_get_prepare_name : ";
|
||||||
|
|
||||||
|
char* rv1 = pClassifier1->qc_get_prepare_name(pCopy1);
|
||||||
|
char* rv2 = pClassifier2->qc_get_prepare_name(pCopy2);
|
||||||
|
|
||||||
|
stringstream ss;
|
||||||
|
ss << HEADING;
|
||||||
|
|
||||||
|
if ((!rv1 && !rv2) || (rv1 && rv2 && (strcmp(rv1, rv2) == 0)))
|
||||||
|
{
|
||||||
|
ss << "Ok : " << (rv1 ? rv1 : "NULL");
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss << "ERR: " << (rv1 ? rv1 : "NULL") << " != " << (rv2 ? rv2 : "NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
report(success, ss.str());
|
||||||
|
|
||||||
|
free(rv1);
|
||||||
|
free(rv2);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, const string& s)
|
bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, const string& s)
|
||||||
{
|
{
|
||||||
GWBUF* pCopy1 = create_gwbuf(s);
|
GWBUF* pCopy1 = create_gwbuf(s);
|
||||||
@ -832,6 +862,7 @@ bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, con
|
|||||||
errors += !compare_query_has_clause(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
errors += !compare_query_has_clause(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
errors += !compare_get_affected_fields(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
errors += !compare_get_affected_fields(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
errors += !compare_get_database_names(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
errors += !compare_get_database_names(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
|
errors += !compare_get_prepare_name(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
|
|
||||||
gwbuf_free(pCopy1);
|
gwbuf_free(pCopy1);
|
||||||
gwbuf_free(pCopy2);
|
gwbuf_free(pCopy2);
|
||||||
|
@ -205,6 +205,14 @@ char** qc_get_database_names(GWBUF* query, int* sizep)
|
|||||||
return classifier->qc_get_database_names(query, sizep);
|
return classifier->qc_get_database_names(query, sizep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* qc_get_prepare_name(GWBUF* query)
|
||||||
|
{
|
||||||
|
QC_TRACE();
|
||||||
|
ss_dassert(classifier);
|
||||||
|
|
||||||
|
return classifier->qc_get_prepare_name(query);
|
||||||
|
}
|
||||||
|
|
||||||
const char* qc_op_to_string(qc_query_op_t op)
|
const char* qc_op_to_string(qc_query_op_t op)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
|
Reference in New Issue
Block a user