qc: Reveal function usage

MXS-1070

Just interface changes. Implementation follow in separate changes.
This commit is contained in:
Johan Wikman
2017-01-02 17:44:15 +02:00
parent 2d849e0ab2
commit d078f56dc5
5 changed files with 205 additions and 0 deletions

View File

@ -118,6 +118,15 @@ typedef struct qc_field_info
uint32_t usage; /** Bitfield denoting where the column appears. */
} QC_FIELD_INFO;
/**
* QC_FUNCTION_INFO contains information about a function used in a statement.
*/
typedef struct qc_function_info
{
char* name; /** Name of function. */
uint32_t usage; /** Bitfield denoting where the column appears. */
} QC_FUNCTION_INFO;
/**
* QUERY_CLASSIFIER defines the object a query classifier plugin must
* implement and return.
@ -150,6 +159,7 @@ typedef struct query_classifier
char* (*qc_get_prepare_name)(GWBUF* stmt);
qc_query_op_t (*qc_get_prepare_operation)(GWBUF* stmt);
void (*qc_get_field_info)(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos);
void (*qc_get_function_info)(GWBUF* stmt, const QC_FUNCTION_INFO** infos, size_t* n_infos);
} QUERY_CLASSIFIER;
/**
@ -297,6 +307,21 @@ char* qc_field_usage_mask_to_string(uint32_t usage_mask);
*/
void qc_get_field_info(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos);
/**
* Returns information about function usage.
*
* @param stmt A buffer containing a COM_QUERY packet.
* @param infos Pointer to pointer that after the call will point to an
* array of QC_FUNCTION_INFO:s.
* @param n_infos Pointer to size_t variable where the number of items
* in @c infos will be returned.
*
* @note The returned array belongs to the GWBUF and remains valid for as
* long as the GWBUF is valid. If the data is needed for longer than
* that, it must be copied.
*/
void qc_get_function_info(GWBUF* stmt, const QC_FUNCTION_INFO** infos, size_t* n_infos);
/**
* Returns the statement, with literals replaced with question marks.
*

View File

@ -2432,6 +2432,19 @@ void qc_get_field_info(GWBUF* buf, const QC_FIELD_INFO** infos, size_t* n_infos)
*n_infos = pi->field_infos_len;
}
void qc_get_function_info(GWBUF* buf, const QC_FUNCTION_INFO** infos, size_t* n_infos)
{
*infos = NULL;
*n_infos = 0;
if (!ensure_query_is_parsed(buf))
{
return;
}
// TODO: Implement functionality.
}
namespace
{
@ -2584,6 +2597,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
qc_get_prepare_name,
qc_get_prepare_operation,
qc_get_field_info,
qc_get_function_info
};
static MXS_MODULE info =

View File

@ -3181,6 +3181,36 @@ void qc_sqlite_get_field_info(GWBUF* query, const QC_FIELD_INFO** infos, size_t*
}
}
void qc_sqlite_get_function_info(GWBUF* query, const QC_FUNCTION_INFO** infos, size_t* n_infos)
{
QC_TRACE();
ss_dassert(this_unit.initialized);
ss_dassert(this_thread.initialized);
*infos = NULL;
*n_infos = 0;
QC_SQLITE_INFO* info = get_query_info(query);
if (info)
{
if (qc_info_is_valid(info->status))
{
// TODO: Implement functionality.
*infos = NULL;
*n_infos = 0;
}
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
{
log_invalid_data(query, "cannot report field info");
}
}
else
{
MXS_ERROR("The query could not be parsed. Response not valid.");
}
}
/**
* EXPORTS
*/
@ -3207,6 +3237,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
qc_sqlite_get_prepare_name,
qc_sqlite_get_prepare_operation,
qc_sqlite_get_field_info,
qc_sqlite_get_function_info,
};
static MXS_MODULE info =

View File

@ -1060,6 +1060,132 @@ bool compare_get_field_info(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1,
}
class QcFunctionInfo
{
public:
QcFunctionInfo(const QC_FUNCTION_INFO& info)
: m_name(info.name)
, m_usage(info.usage)
{}
bool eq(const QcFunctionInfo& rhs) const
{
return
m_name == rhs.m_name &&
m_usage == rhs.m_usage;
}
bool lt(const QcFunctionInfo& rhs) const
{
bool rv = false;
if (m_name < rhs.m_name)
{
rv = true;
}
else if (m_name > rhs.m_name)
{
rv = false;
}
else
{
rv = (m_usage < rhs.m_usage);
}
return rv;
}
void print(ostream& out) const
{
out << m_name;
out << "(";
char* s = qc_field_usage_mask_to_string(m_usage);
out << s;
free(s);
out << ")";
}
private:
std::string m_name;
uint32_t m_usage;
};
ostream& operator << (ostream& out, const QcFunctionInfo& x)
{
x.print(out);
return out;
}
ostream& operator << (ostream& out, std::set<QcFunctionInfo>& x)
{
std::set<QcFunctionInfo>::iterator i = x.begin();
std::set<QcFunctionInfo>::iterator end = x.end();
while (i != end)
{
out << *i++;
if (i != end)
{
out << " ";
}
}
return out;
}
bool operator < (const QcFunctionInfo& lhs, const QcFunctionInfo& rhs)
{
return lhs.lt(rhs);
}
bool operator == (const QcFunctionInfo& lhs, const QcFunctionInfo& rhs)
{
return lhs.eq(rhs);
}
bool compare_get_function_info(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1,
QUERY_CLASSIFIER* pClassifier2, GWBUF* pCopy2)
{
bool success = false;
const char HEADING[] = "qc_get_function_info : ";
const QC_FUNCTION_INFO* infos1;
const QC_FUNCTION_INFO* infos2;
size_t n_infos1;
size_t n_infos2;
pClassifier1->qc_get_function_info(pCopy1, &infos1, &n_infos1);
pClassifier2->qc_get_function_info(pCopy2, &infos2, &n_infos2);
stringstream ss;
ss << HEADING;
int i;
std::set<QcFunctionInfo> f1;
f1.insert(infos1, infos1 + n_infos1);
std::set<QcFunctionInfo> f2;
f2.insert(infos2, infos2 + n_infos2);
if (f1 == f2)
{
ss << "Ok : ";
ss << f1;
success = true;
}
else
{
ss << "ERR: " << f1 << " != " << f2;
}
report(success, ss.str());
return success;
}
bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, const string& s)
{
GWBUF* pCopy1 = create_gwbuf(s);
@ -1080,6 +1206,7 @@ bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, con
errors += !compare_get_prepare_name(pClassifier1, pCopy1, pClassifier2, pCopy2);
errors += !compare_get_prepare_operation(pClassifier1, pCopy1, pClassifier2, pCopy2);
errors += !compare_get_field_info(pClassifier1, pCopy1, pClassifier2, pCopy2);
errors += !compare_get_function_info(pClassifier1, pCopy1, pClassifier2, pCopy2);
gwbuf_free(pCopy1);
gwbuf_free(pCopy2);

View File

@ -217,6 +217,14 @@ void qc_get_field_info(GWBUF* query, const QC_FIELD_INFO** infos, size_t* n_info
classifier->qc_get_field_info(query, infos, n_infos);
}
void qc_get_function_info(GWBUF* query, const QC_FUNCTION_INFO** infos, size_t* n_infos)
{
QC_TRACE();
ss_dassert(classifier);
classifier->qc_get_function_info(query, infos, n_infos);
}
char** qc_get_database_names(GWBUF* query, int* sizep)
{
QC_TRACE();