Add qc_get_preparable_stmt

This function will return the preparable statement of a PREPARE
statement as a COM_QUERY GWBUF. That is, once obtained, the normal
query classifier functions can be used for obtaining information
about the preparable statement itself.
This commit is contained in:
Johan Wikman 2017-01-16 15:28:31 +02:00
parent 7fee90a399
commit e349319400
5 changed files with 97 additions and 2 deletions

View File

@ -342,6 +342,23 @@ typedef struct query_classifier
* exhaustion or equivalent.
*/
int32_t (*qc_get_function_info)(GWBUF* stmt, const QC_FUNCTION_INFO** infos, uint32_t* n_infos);
/**
* Return the preparable statement of a PREPARE statement.
*
* @param stmt A statement.
* @param preparable_stmt On return, the preparable statement (provided @c stmt is a
* PREPARE statement), if @c QC_RESULT_OK is returned. Otherwise
* NULL.
*
* @attention The returned GWBUF is the property of @c stmt and will be deleted when
* @c stmt is. If the preparable statement need to be retained beyond the
* lifetime of @c stmt, it must be cloned.
*
* @return QC_RESULT_OK, if the parsing was not aborted due to resource
* exhaustion or equivalent.
*/
int32_t (*qc_get_preparable_stmt)(GWBUF* stmt, GWBUF** preparable_stmt);
} QUERY_CLASSIFIER;
/**
@ -578,6 +595,22 @@ char* qc_get_prepare_name(GWBUF* stmt);
*/
qc_query_op_t qc_get_prepare_operation(GWBUF* stmt);
/**
* Returns the preparable statement of a PREPARE statment. Other query classifier
* functions can then be used on the returned statement to find out information
* about the preparable statement. The returned @c GWBUF should not be used for
* anything else but for obtaining information about the preparable statement.
*
* @param stmt A buffer containing a COM_QUERY packet.
*
* @return The preparable statement, if @stmt was a PREPARE statement, or
* NULL.
*
* @attention The returned @c GWBUF is the property of @c stmt and will be
* deleted along with it.
*/
GWBUF* qc_get_preparable_stmt(GWBUF* stmt);
/**
* Returns the tables accessed by the statement.
*

View File

@ -96,7 +96,7 @@ int32_t qc_dummy_setup(const char* args)
return QC_RESULT_OK;
}
int qc_dummy_process_init(void)
int32_t qc_dummy_process_init(void)
{
return QC_RESULT_OK;
}
@ -105,7 +105,7 @@ void qc_dummy_process_end(void)
{
}
int qc_dummy_thread_init(void)
int32_t qc_dummy_thread_init(void)
{
return QC_RESULT_OK;
}
@ -114,6 +114,12 @@ void qc_dummy_thread_end(void)
{
}
int32_t qc_dummy_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
{
*preparable_stmt = NULL;
return QC_RESULT_OK;
}
extern "C"
{
MXS_MODULE* MXS_CREATE_MODULE()
@ -138,6 +144,7 @@ extern "C"
qc_dummy_get_prepare_operation,
qc_dummy_get_field_info,
qc_dummy_get_function_info,
qc_dummy_get_preparable_stmt,
};
static MXS_MODULE info =

View File

@ -1851,6 +1851,15 @@ int32_t qc_mysql_get_prepare_operation(GWBUF* stmt, int32_t* operation)
return QC_RESULT_OK;
}
int32_t qc_mysql_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
{
*preparable_stmt = NULL;
// TODO: Extract preparable stmt.
ss_dassert(!true);
return QC_RESULT_OK;
}
static bool should_exclude(const char* name, List<Item>* excludep)
{
bool exclude = false;

View File

@ -2796,6 +2796,7 @@ static int32_t qc_sqlite_get_table_names(GWBUF* query, int32_t fullnames, char**
static int32_t qc_sqlite_get_canonical(GWBUF* query, char** canonical);
static int32_t qc_sqlite_query_has_clause(GWBUF* query, int32_t* has_clause);
static int32_t qc_sqlite_get_database_names(GWBUF* query, char*** names, int* sizep);
static int32_t qc_sqlite_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt);
static bool get_key_and_value(char* arg, const char** pkey, const char** pvalue)
{
@ -3411,6 +3412,38 @@ int32_t qc_sqlite_get_function_info(GWBUF* query, const QC_FUNCTION_INFO** infos
return rv;
}
int32_t qc_sqlite_get_preparable_stmt(GWBUF* stmt, GWBUF** preparable_stmt)
{
QC_TRACE();
int32_t rv = QC_RESULT_ERROR;
ss_dassert(this_unit.initialized);
ss_dassert(this_thread.initialized);
*preparable_stmt = NULL;
QC_SQLITE_INFO* info = get_query_info(stmt);
if (info)
{
if (qc_info_is_valid(info->status))
{
// TODO: Extract the preparable stmt.
ss_dassert(!true);
rv = QC_RESULT_OK;
}
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
{
log_invalid_data(stmt, "cannot report field info");
}
}
else
{
MXS_ERROR("The query could not be parsed. Response not valid.");
}
return rv;
}
/**
* EXPORTS
*/
@ -3437,6 +3470,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
qc_sqlite_get_prepare_operation,
qc_sqlite_get_field_info,
qc_sqlite_get_function_info,
qc_sqlite_get_preparable_stmt,
};
static MXS_MODULE info =

View File

@ -283,6 +283,18 @@ char* qc_get_prepare_name(GWBUF* query)
return name;
}
GWBUF* qc_get_preparable_stmt(GWBUF* stmt)
{
QC_TRACE();
ss_dassert(classifier);
GWBUF* preparable_stmt = NULL;
classifier->qc_get_preparable_stmt(stmt, &preparable_stmt);
return preparable_stmt;
}
struct type_name_info field_usage_to_type_name_info(qc_field_usage_t usage)
{
struct type_name_info info;