From c652f1330a4626a73fa96434110c37c612befedd Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 1 Nov 2016 16:34:28 +0200 Subject: [PATCH] qc: Add qc_get_field_info This function returns more detailed information about the fields of a statement. Supersedes qc_get_affected_fields() that will be deprecated and removed. Note that this function now introduced new kind of behaviour; the returned data belongs to the GWBUF and remains valid for as long as the GWBUF is alive. That means that unnecessary copying need not be done. --- include/maxscale/query_classifier.h | 28 +++++++++++++++++++ .../qc_mysqlembedded/qc_mysqlembedded.cc | 9 ++++++ query_classifier/qc_sqlite/qc_sqlite.c | 28 +++++++++++++++++++ server/core/query_classifier.c | 8 ++++++ 4 files changed, 73 insertions(+) diff --git a/include/maxscale/query_classifier.h b/include/maxscale/query_classifier.h index 438613eac..02db99d5d 100644 --- a/include/maxscale/query_classifier.h +++ b/include/maxscale/query_classifier.h @@ -87,6 +87,18 @@ typedef enum qc_parse_result } qc_parse_result_t; +/** + * QC_FIELD_INFO contains information about a field used in a statement. + */ +typedef struct qc_field_info +{ + char* database; /** Present if the field is of the form "a.b.c", NULL otherwise. */ + char* table; /** Present if the field is of the form "a.b", NULL otherwise. */ + char* column; /** Always present. */ + // TODO: Possibly add bits telling where the field is used; e.g. in the select + // TODO: part or the where part, or both. +} QC_FIELD_INFO; + /** * QUERY_CLASSIFIER defines the object a query classifier plugin must * implement and return. @@ -117,6 +129,7 @@ typedef struct query_classifier char** (*qc_get_database_names)(GWBUF* stmt, int* size); 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); } QUERY_CLASSIFIER; /** @@ -223,6 +236,21 @@ qc_parse_result_t qc_parse(GWBUF* stmt); */ char* qc_get_affected_fields(GWBUF* stmt); +/** + * Returns information about affected fields. + * + * @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_FIELD_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_field_info(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos); + /** * Returns the statement, with literals replaced with question marks. * diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index 48330808e..1041b6d44 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -2010,6 +2010,14 @@ qc_query_op_t qc_get_prepare_operation(GWBUF* stmt) return operation; } +void qc_get_field_info(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos) +{ + MXS_ERROR("qc_get_field_info not implemented yet."); + + *infos = NULL; + *n_infos = 0; +} + namespace { @@ -2156,6 +2164,7 @@ static QUERY_CLASSIFIER qc = qc_get_database_names, qc_get_prepare_name, qc_get_prepare_operation, + qc_get_field_info, }; /* @see function load_module in load_utils.c for explanation of the following diff --git a/query_classifier/qc_sqlite/qc_sqlite.c b/query_classifier/qc_sqlite/qc_sqlite.c index ccec8c165..d73d06bea 100644 --- a/query_classifier/qc_sqlite/qc_sqlite.c +++ b/query_classifier/qc_sqlite/qc_sqlite.c @@ -248,6 +248,21 @@ static bool ensure_query_is_parsed(GWBUF* query) return parsed; } +void free_field_infos(QC_FIELD_INFO* infos, size_t n_infos) +{ + if (infos) + { + for (int i = 0; i < n_infos; ++i) + { + MXS_FREE(infos[i].database); + MXS_FREE(infos[i].table); + MXS_FREE(infos[i].column); + } + + MXS_FREE(infos); + } +} + static void free_string_array(char** sa) { if (sa) @@ -2954,6 +2969,18 @@ static qc_query_op_t qc_sqlite_get_prepare_operation(GWBUF* query) return op; } +void qc_sqlite_get_field_info(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos) +{ + QC_TRACE(); + ss_dassert(this_unit.initialized); + ss_dassert(this_thread.initialized); + + MXS_ERROR("qc_get_field_info not implemented yet."); + + *infos = NULL; + *n_infos = 0; +} + /** * EXPORTS */ @@ -2979,6 +3006,7 @@ static QUERY_CLASSIFIER qc = qc_sqlite_get_database_names, qc_sqlite_get_prepare_name, qc_sqlite_get_prepare_operation, + qc_sqlite_get_field_info, }; diff --git a/server/core/query_classifier.c b/server/core/query_classifier.c index 5800f38e1..70d7f3cfe 100644 --- a/server/core/query_classifier.c +++ b/server/core/query_classifier.c @@ -197,6 +197,14 @@ char* qc_get_affected_fields(GWBUF* query) return classifier->qc_get_affected_fields(query); } +void qc_get_field_info(GWBUF* query, const QC_FIELD_INFO** infos, size_t* n_infos) +{ + QC_TRACE(); + ss_dassert(classifier); + + classifier->qc_get_field_info(query, infos, n_infos); +} + char** qc_get_database_names(GWBUF* query, int* sizep) { QC_TRACE();