MXS-884: Implement qc_get_fields_infos.
We now collect more information about a particular field and then, if necessary, copy the data over into affected_fields if someone is interested in that. The comparison program is extended as well, but qc_get_fields_infos() is not tested, because qc_mysqlembedded does not implement this yet.
This commit is contained in:
@ -61,8 +61,6 @@ typedef struct qc_sqlite_info
|
|||||||
uint32_t types; // The types of the query.
|
uint32_t types; // The types of the query.
|
||||||
qc_query_op_t operation; // The operation in question.
|
qc_query_op_t operation; // The operation in question.
|
||||||
char* affected_fields; // The affected fields.
|
char* affected_fields; // The affected fields.
|
||||||
size_t affected_fields_len; // The used length of affected_fields.
|
|
||||||
size_t affected_fields_capacity; // The capacity of affected_fields.
|
|
||||||
bool is_real_query; // SELECT, UPDATE, INSERT, DELETE or a variation.
|
bool is_real_query; // SELECT, UPDATE, INSERT, DELETE or a variation.
|
||||||
bool has_clause; // Has WHERE or HAVING.
|
bool has_clause; // Has WHERE or HAVING.
|
||||||
char** table_names; // Array of table names used in the query.
|
char** table_names; // Array of table names used in the query.
|
||||||
@ -82,6 +80,9 @@ typedef struct qc_sqlite_info
|
|||||||
qc_query_op_t prepare_operation; // The operation of a prepared statement.
|
qc_query_op_t prepare_operation; // The operation of a prepared statement.
|
||||||
char* preparable_stmt; // The preparable statement.
|
char* preparable_stmt; // The preparable statement.
|
||||||
size_t preparable_stmt_length; // The length of the preparable statement.
|
size_t preparable_stmt_length; // The length of the preparable statement.
|
||||||
|
QC_FIELD_INFO *field_infos; // Pointer to array of QC_FIELD_INFOs.
|
||||||
|
size_t field_infos_len; // The used entries in field_infos.
|
||||||
|
size_t field_infos_capacity; // The capacity of the field_infos array.
|
||||||
} QC_SQLITE_INFO;
|
} QC_SQLITE_INFO;
|
||||||
|
|
||||||
typedef enum qc_log_level
|
typedef enum qc_log_level
|
||||||
@ -123,11 +124,11 @@ typedef enum qc_token_position
|
|||||||
QC_TOKEN_RIGHT, // To the right, e.g: "b" in "a = b".
|
QC_TOKEN_RIGHT, // To the right, e.g: "b" in "a = b".
|
||||||
} qc_token_position_t;
|
} qc_token_position_t;
|
||||||
|
|
||||||
static void append_affected_field(QC_SQLITE_INFO* info, const char* s);
|
|
||||||
static void buffer_object_free(void* data);
|
static void buffer_object_free(void* data);
|
||||||
static char** copy_string_array(char** strings, int* pn);
|
static char** copy_string_array(char** strings, int* pn);
|
||||||
static void enlarge_string_array(size_t n, size_t len, char*** ppzStrings, size_t* pCapacity);
|
static void enlarge_string_array(size_t n, size_t len, char*** ppzStrings, size_t* pCapacity);
|
||||||
static bool ensure_query_is_parsed(GWBUF* query);
|
static bool ensure_query_is_parsed(GWBUF* query);
|
||||||
|
static void free_field_infos(QC_FIELD_INFO* infos, size_t n_infos);
|
||||||
static void free_string_array(char** sa);
|
static void free_string_array(char** sa);
|
||||||
static QC_SQLITE_INFO* get_query_info(GWBUF* query);
|
static QC_SQLITE_INFO* get_query_info(GWBUF* query);
|
||||||
static QC_SQLITE_INFO* info_alloc(void);
|
static QC_SQLITE_INFO* info_alloc(void);
|
||||||
@ -140,16 +141,16 @@ static bool parse_query(GWBUF* query);
|
|||||||
static void parse_query_string(const char* query, size_t len);
|
static void parse_query_string(const char* query, size_t len);
|
||||||
static bool query_is_parsed(GWBUF* query);
|
static bool query_is_parsed(GWBUF* query);
|
||||||
static bool should_exclude(const char* zName, const ExprList* pExclude);
|
static bool should_exclude(const char* zName, const ExprList* pExclude);
|
||||||
static void update_affected_fields(QC_SQLITE_INFO* info,
|
static void update_fields_infos(QC_SQLITE_INFO* info,
|
||||||
int prev_token,
|
int prev_token,
|
||||||
const Expr* pExpr,
|
const Expr* pExpr,
|
||||||
qc_token_position_t pos,
|
qc_token_position_t pos,
|
||||||
const ExprList* pExclude);
|
const ExprList* pExclude);
|
||||||
static void update_affected_fields_from_exprlist(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_exprlist(QC_SQLITE_INFO* info,
|
||||||
const ExprList* pEList, const ExprList* pExclude);
|
const ExprList* pEList, const ExprList* pExclude);
|
||||||
static void update_affected_fields_from_idlist(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_idlist(QC_SQLITE_INFO* info,
|
||||||
const IdList* pIds, const ExprList* pExclude);
|
const IdList* pIds, const ExprList* pExclude);
|
||||||
static void update_affected_fields_from_select(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_select(QC_SQLITE_INFO* info,
|
||||||
const Select* pSelect, const ExprList* pExclude);
|
const Select* pSelect, const ExprList* pExclude);
|
||||||
static void update_database_names(QC_SQLITE_INFO* info, const char* name);
|
static void update_database_names(QC_SQLITE_INFO* info, const char* name);
|
||||||
static void update_names(QC_SQLITE_INFO* info, const char* zDatabase, const char* zTable);
|
static void update_names(QC_SQLITE_INFO* info, const char* zDatabase, const char* zTable);
|
||||||
@ -248,7 +249,7 @@ static bool ensure_query_is_parsed(GWBUF* query)
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_field_infos(QC_FIELD_INFO* infos, size_t n_infos)
|
static void free_field_infos(QC_FIELD_INFO* infos, size_t n_infos)
|
||||||
{
|
{
|
||||||
if (infos)
|
if (infos)
|
||||||
{
|
{
|
||||||
@ -311,6 +312,7 @@ static void info_finish(QC_SQLITE_INFO* info)
|
|||||||
free_string_array(info->database_names);
|
free_string_array(info->database_names);
|
||||||
free(info->prepare_name);
|
free(info->prepare_name);
|
||||||
free(info->preparable_stmt);
|
free(info->preparable_stmt);
|
||||||
|
free_field_infos(info->field_infos, info->field_infos_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void info_free(QC_SQLITE_INFO* info)
|
static void info_free(QC_SQLITE_INFO* info)
|
||||||
@ -331,8 +333,6 @@ static QC_SQLITE_INFO* info_init(QC_SQLITE_INFO* info)
|
|||||||
info->types = QUERY_TYPE_UNKNOWN;
|
info->types = QUERY_TYPE_UNKNOWN;
|
||||||
info->operation = QUERY_OP_UNDEFINED;
|
info->operation = QUERY_OP_UNDEFINED;
|
||||||
info->affected_fields = NULL;
|
info->affected_fields = NULL;
|
||||||
info->affected_fields_len = 0;
|
|
||||||
info->affected_fields_capacity = 0;
|
|
||||||
info->is_real_query = false;
|
info->is_real_query = false;
|
||||||
info->has_clause = false;
|
info->has_clause = false;
|
||||||
info->table_names = NULL;
|
info->table_names = NULL;
|
||||||
@ -352,6 +352,9 @@ static QC_SQLITE_INFO* info_init(QC_SQLITE_INFO* info)
|
|||||||
info->prepare_operation = QUERY_OP_UNDEFINED;
|
info->prepare_operation = QUERY_OP_UNDEFINED;
|
||||||
info->preparable_stmt = NULL;
|
info->preparable_stmt = NULL;
|
||||||
info->preparable_stmt_length = 0;
|
info->preparable_stmt_length = 0;
|
||||||
|
info->field_infos = NULL;
|
||||||
|
info->field_infos_len = 0;
|
||||||
|
info->field_infos_capacity = 0;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -643,42 +646,6 @@ static void log_invalid_data(GWBUF* query, const char* message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_affected_field(QC_SQLITE_INFO* info, const char* s)
|
|
||||||
{
|
|
||||||
size_t len = strlen(s);
|
|
||||||
size_t required_len = info->affected_fields_len + len + 1; // 1 for NULL
|
|
||||||
|
|
||||||
if (info->affected_fields_len != 0)
|
|
||||||
{
|
|
||||||
required_len += 1; // " " between fields
|
|
||||||
}
|
|
||||||
|
|
||||||
if (required_len > info->affected_fields_capacity)
|
|
||||||
{
|
|
||||||
if (info->affected_fields_capacity == 0)
|
|
||||||
{
|
|
||||||
info->affected_fields_capacity = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (required_len > info->affected_fields_capacity)
|
|
||||||
{
|
|
||||||
info->affected_fields_capacity *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->affected_fields = MXS_REALLOC(info->affected_fields, info->affected_fields_capacity);
|
|
||||||
MXS_ABORT_IF_NULL(info->affected_fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->affected_fields_len != 0)
|
|
||||||
{
|
|
||||||
strcpy(info->affected_fields + info->affected_fields_len, " ");
|
|
||||||
info->affected_fields_len += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(info->affected_fields + info->affected_fields_len, s);
|
|
||||||
info->affected_fields_len += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool should_exclude(const char* zName, const ExprList* pExclude)
|
static bool should_exclude(const char* zName, const ExprList* pExclude)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -714,7 +681,162 @@ static bool should_exclude(const char* zName, const ExprList* pExclude)
|
|||||||
return i != pExclude->nExpr;
|
return i != pExclude->nExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_affected_fields(QC_SQLITE_INFO* info,
|
static void update_field_infos(QC_SQLITE_INFO* info,
|
||||||
|
const char* database,
|
||||||
|
const char* table,
|
||||||
|
const char* column,
|
||||||
|
const ExprList* pExclude)
|
||||||
|
{
|
||||||
|
ss_dassert(column);
|
||||||
|
|
||||||
|
// If only a column is specified, but not a table or database and we
|
||||||
|
// have a list of expressions that should be excluded, we check if the column
|
||||||
|
// value is present in that list. This is in order to exclude the second "d" in
|
||||||
|
// a statement like "select a as d from x where d = 2".
|
||||||
|
if (column && !table && !database && pExclude && should_exclude(column, pExclude))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QC_FIELD_INFO item = { (char*)database, (char*)table, (char*)column };
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < info->field_infos_len; ++i)
|
||||||
|
{
|
||||||
|
QC_FIELD_INFO* field_info = info->field_infos + i;
|
||||||
|
|
||||||
|
if (strcasecmp(item.column, field_info->column) == 0)
|
||||||
|
{
|
||||||
|
if (!item.table && !field_info->table)
|
||||||
|
{
|
||||||
|
ss_dassert(!item.database && !field_info->database);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (item.table && field_info->table && (strcmp(item.table, field_info->table) == 0))
|
||||||
|
{
|
||||||
|
if (!item.database && !field_info->database)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (item.database &&
|
||||||
|
field_info->database &&
|
||||||
|
(strcmp(item.database, field_info->database) == 0))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QC_FIELD_INFO* field_infos = NULL;
|
||||||
|
|
||||||
|
if (i == info->field_infos_len) // If true, the field was not present already.
|
||||||
|
{
|
||||||
|
if (info->field_infos_len < info->field_infos_capacity)
|
||||||
|
{
|
||||||
|
field_infos = info->field_infos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t capacity = info->field_infos_capacity ? 2 * info->field_infos_capacity : 8;
|
||||||
|
field_infos = MXS_REALLOC(info->field_infos, capacity * sizeof(QC_FIELD_INFO));
|
||||||
|
|
||||||
|
if (field_infos)
|
||||||
|
{
|
||||||
|
info->field_infos = field_infos;
|
||||||
|
info->field_infos_capacity = capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field_infos is NULL, then the field was found and has already been noted.
|
||||||
|
if (field_infos)
|
||||||
|
{
|
||||||
|
item.database = item.database ? MXS_STRDUP(item.database) : NULL;
|
||||||
|
item.table = item.table ? MXS_STRDUP(item.table) : NULL;
|
||||||
|
ss_dassert(item.column);
|
||||||
|
item.column = MXS_STRDUP(item.column);
|
||||||
|
|
||||||
|
// We are happy if we at least could dup the column.
|
||||||
|
|
||||||
|
if (item.column)
|
||||||
|
{
|
||||||
|
field_infos[info->field_infos_len++] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_field_infos_from_expr(QC_SQLITE_INFO* info,
|
||||||
|
const struct Expr* pExpr,
|
||||||
|
const ExprList* pExclude)
|
||||||
|
{
|
||||||
|
QC_FIELD_INFO item = {};
|
||||||
|
|
||||||
|
if (pExpr->op == TK_ASTERISK)
|
||||||
|
{
|
||||||
|
item.column = "*";
|
||||||
|
}
|
||||||
|
else if (pExpr->op == TK_ID)
|
||||||
|
{
|
||||||
|
// select a from...
|
||||||
|
item.column = pExpr->u.zToken;
|
||||||
|
}
|
||||||
|
else if (pExpr->op == TK_DOT)
|
||||||
|
{
|
||||||
|
if (pExpr->pLeft->op == TK_ID &&
|
||||||
|
(pExpr->pRight->op == TK_ID || pExpr->pRight->op == TK_ASTERISK))
|
||||||
|
{
|
||||||
|
// select a.b from...
|
||||||
|
item.table = pExpr->pLeft->u.zToken;
|
||||||
|
if (pExpr->pRight->op == TK_ID)
|
||||||
|
{
|
||||||
|
item.column = pExpr->pRight->u.zToken;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.column = "*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pExpr->pLeft->op == TK_ID &&
|
||||||
|
pExpr->pRight->op == TK_DOT &&
|
||||||
|
pExpr->pRight->pLeft->op == TK_ID &&
|
||||||
|
(pExpr->pRight->pRight->op == TK_ID || pExpr->pRight->pRight->op == TK_ASTERISK))
|
||||||
|
{
|
||||||
|
// select a.b.c from...
|
||||||
|
item.database = pExpr->pLeft->u.zToken;
|
||||||
|
item.table = pExpr->pRight->pLeft->u.zToken;
|
||||||
|
if (pExpr->pRight->pRight->op == TK_ID)
|
||||||
|
{
|
||||||
|
item.column = pExpr->pRight->pRight->u.zToken;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.column = "*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.column)
|
||||||
|
{
|
||||||
|
bool should_update = true;
|
||||||
|
|
||||||
|
if ((pExpr->flags & EP_DblQuoted) == 0)
|
||||||
|
{
|
||||||
|
if ((strcasecmp(item.column, "true") == 0) || (strcasecmp(item.column, "false") == 0))
|
||||||
|
{
|
||||||
|
should_update = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_update)
|
||||||
|
{
|
||||||
|
update_field_infos(info, item.database, item.table, item.column, pExclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void update_fields_infos(QC_SQLITE_INFO* info,
|
||||||
int prev_token,
|
int prev_token,
|
||||||
const Expr* pExpr,
|
const Expr* pExpr,
|
||||||
qc_token_position_t pos,
|
qc_token_position_t pos,
|
||||||
@ -724,26 +846,16 @@ static void update_affected_fields(QC_SQLITE_INFO* info,
|
|||||||
|
|
||||||
switch (pExpr->op)
|
switch (pExpr->op)
|
||||||
{
|
{
|
||||||
case TK_ASTERISK: // "select *"
|
case TK_ASTERISK: // select *
|
||||||
append_affected_field(info, "*");
|
update_field_infos_from_expr(info, pExpr, pExclude);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK_DOT:
|
case TK_DOT: // select a.b ... select a.b.c
|
||||||
// In case of "X.Y" qc_mysqlembedded returns "Y".
|
update_field_infos_from_expr(info, pExpr, pExclude);
|
||||||
update_affected_fields(info, TK_DOT, pExpr->pRight, QC_TOKEN_RIGHT, pExclude);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK_ID:
|
case TK_ID: // select a
|
||||||
if ((pExpr->flags & EP_DblQuoted) == 0)
|
update_field_infos_from_expr(info, pExpr, pExclude);
|
||||||
{
|
|
||||||
if ((strcasecmp(zToken, "true") != 0) && (strcasecmp(zToken, "false") != 0))
|
|
||||||
{
|
|
||||||
if (!pExclude || !should_exclude(zToken, pExclude))
|
|
||||||
{
|
|
||||||
append_affected_field(info, zToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK_VARIABLE:
|
case TK_VARIABLE:
|
||||||
@ -804,12 +916,12 @@ static void update_affected_fields(QC_SQLITE_INFO* info,
|
|||||||
|
|
||||||
if (pExpr->pLeft)
|
if (pExpr->pLeft)
|
||||||
{
|
{
|
||||||
update_affected_fields(info, pExpr->op, pExpr->pLeft, QC_TOKEN_LEFT, pExclude);
|
update_fields_infos(info, pExpr->op, pExpr->pLeft, QC_TOKEN_LEFT, pExclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pExpr->pRight)
|
if (pExpr->pRight)
|
||||||
{
|
{
|
||||||
update_affected_fields(info, pExpr->op, pExpr->pRight, QC_TOKEN_RIGHT, pExclude);
|
update_fields_infos(info, pExpr->op, pExpr->pRight, QC_TOKEN_RIGHT, pExclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pExpr->x.pList)
|
if (pExpr->x.pList)
|
||||||
@ -819,7 +931,7 @@ static void update_affected_fields(QC_SQLITE_INFO* info,
|
|||||||
case TK_BETWEEN:
|
case TK_BETWEEN:
|
||||||
case TK_CASE:
|
case TK_CASE:
|
||||||
case TK_FUNCTION:
|
case TK_FUNCTION:
|
||||||
update_affected_fields_from_exprlist(info, pExpr->x.pList, pExclude);
|
update_fields_infos_from_exprlist(info, pExpr->x.pList, pExclude);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK_EXISTS:
|
case TK_EXISTS:
|
||||||
@ -827,11 +939,11 @@ static void update_affected_fields(QC_SQLITE_INFO* info,
|
|||||||
case TK_SELECT:
|
case TK_SELECT:
|
||||||
if (pExpr->flags & EP_xIsSelect)
|
if (pExpr->flags & EP_xIsSelect)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pExpr->x.pSelect, pExclude);
|
update_fields_infos_from_select(info, pExpr->x.pSelect, pExclude);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
update_affected_fields_from_exprlist(info, pExpr->x.pList, pExclude);
|
update_fields_infos_from_exprlist(info, pExpr->x.pList, pExclude);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -840,7 +952,7 @@ static void update_affected_fields(QC_SQLITE_INFO* info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_affected_fields_from_exprlist(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_exprlist(QC_SQLITE_INFO* info,
|
||||||
const ExprList* pEList,
|
const ExprList* pEList,
|
||||||
const ExprList* pExclude)
|
const ExprList* pExclude)
|
||||||
{
|
{
|
||||||
@ -848,11 +960,11 @@ static void update_affected_fields_from_exprlist(QC_SQLITE_INFO* info,
|
|||||||
{
|
{
|
||||||
struct ExprList_item* pItem = &pEList->a[i];
|
struct ExprList_item* pItem = &pEList->a[i];
|
||||||
|
|
||||||
update_affected_fields(info, 0, pItem->pExpr, QC_TOKEN_MIDDLE, pExclude);
|
update_fields_infos(info, 0, pItem->pExpr, QC_TOKEN_MIDDLE, pExclude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_affected_fields_from_idlist(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_idlist(QC_SQLITE_INFO* info,
|
||||||
const IdList* pIds,
|
const IdList* pIds,
|
||||||
const ExprList* pExclude)
|
const ExprList* pExclude)
|
||||||
{
|
{
|
||||||
@ -860,14 +972,11 @@ static void update_affected_fields_from_idlist(QC_SQLITE_INFO* info,
|
|||||||
{
|
{
|
||||||
struct IdList_item* pItem = &pIds->a[i];
|
struct IdList_item* pItem = &pIds->a[i];
|
||||||
|
|
||||||
if (!pExclude || !should_exclude(pItem->zName, pExclude))
|
update_field_infos(info, NULL, NULL, pItem->zName, pExclude);
|
||||||
{
|
|
||||||
append_affected_field(info, pItem->zName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_affected_fields_from_select(QC_SQLITE_INFO* info,
|
static void update_fields_infos_from_select(QC_SQLITE_INFO* info,
|
||||||
const Select* pSelect,
|
const Select* pSelect,
|
||||||
const ExprList* pExclude)
|
const ExprList* pExclude)
|
||||||
{
|
{
|
||||||
@ -885,7 +994,7 @@ static void update_affected_fields_from_select(QC_SQLITE_INFO* info,
|
|||||||
|
|
||||||
if (pSrc->a[i].pSelect)
|
if (pSrc->a[i].pSelect)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pSrc->a[i].pSelect, pExclude);
|
update_fields_infos_from_select(info, pSrc->a[i].pSelect, pExclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QC_COLLECT_NAMES_FROM_USING
|
#ifdef QC_COLLECT_NAMES_FROM_USING
|
||||||
@ -895,7 +1004,7 @@ static void update_affected_fields_from_select(QC_SQLITE_INFO* info,
|
|||||||
// does not reveal its value, right?
|
// does not reveal its value, right?
|
||||||
if (pSrc->a[i].pUsing)
|
if (pSrc->a[i].pUsing)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_idlist(info, pSrc->a[i].pUsing, pSelect->pEList);
|
update_fields_infos_from_idlist(info, pSrc->a[i].pUsing, pSelect->pEList);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -903,24 +1012,24 @@ static void update_affected_fields_from_select(QC_SQLITE_INFO* info,
|
|||||||
|
|
||||||
if (pSelect->pEList)
|
if (pSelect->pEList)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_exprlist(info, pSelect->pEList, NULL);
|
update_fields_infos_from_exprlist(info, pSelect->pEList, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSelect->pWhere)
|
if (pSelect->pWhere)
|
||||||
{
|
{
|
||||||
info->has_clause = true;
|
info->has_clause = true;
|
||||||
update_affected_fields(info, 0, pSelect->pWhere, QC_TOKEN_MIDDLE, pSelect->pEList);
|
update_fields_infos(info, 0, pSelect->pWhere, QC_TOKEN_MIDDLE, pSelect->pEList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSelect->pGroupBy)
|
if (pSelect->pGroupBy)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_exprlist(info, pSelect->pGroupBy, pSelect->pEList);
|
update_fields_infos_from_exprlist(info, pSelect->pGroupBy, pSelect->pEList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSelect->pHaving)
|
if (pSelect->pHaving)
|
||||||
{
|
{
|
||||||
info->has_clause = true;
|
info->has_clause = true;
|
||||||
update_affected_fields(info, 0, pSelect->pHaving, QC_TOKEN_MIDDLE, pSelect->pEList);
|
update_fields_infos(info, 0, pSelect->pHaving, QC_TOKEN_MIDDLE, pSelect->pEList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,7 +1274,7 @@ void mxs_sqlite3CreateView(Parse *pParse, /* The parsing context */
|
|||||||
|
|
||||||
if (pSelect)
|
if (pSelect)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pSelect, NULL);
|
update_fields_infos_from_select(info, pSelect, NULL);
|
||||||
info->is_real_query = false;
|
info->is_real_query = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1235,7 +1344,7 @@ void mxs_sqlite3DeleteFrom(Parse* pParse, SrcList* pTabList, Expr* pWhere, SrcLi
|
|||||||
|
|
||||||
if (pWhere)
|
if (pWhere)
|
||||||
{
|
{
|
||||||
update_affected_fields(info, 0, pWhere, QC_TOKEN_MIDDLE, 0);
|
update_fields_infos(info, 0, pWhere, QC_TOKEN_MIDDLE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
exposed_sqlite3ExprDelete(pParse->db, pWhere);
|
exposed_sqlite3ExprDelete(pParse->db, pWhere);
|
||||||
@ -1299,7 +1408,7 @@ void mxs_sqlite3EndTable(Parse *pParse, /* Parse context */
|
|||||||
{
|
{
|
||||||
if (pSelect)
|
if (pSelect)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pSelect, NULL);
|
update_fields_infos_from_select(info, pSelect, NULL);
|
||||||
info->is_real_query = false;
|
info->is_real_query = false;
|
||||||
}
|
}
|
||||||
else if (pOldTable)
|
else if (pOldTable)
|
||||||
@ -1345,17 +1454,17 @@ void mxs_sqlite3Insert(Parse* pParse,
|
|||||||
|
|
||||||
if (pColumns)
|
if (pColumns)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_idlist(info, pColumns, NULL);
|
update_fields_infos_from_idlist(info, pColumns, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSelect)
|
if (pSelect)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pSelect, NULL);
|
update_fields_infos_from_select(info, pSelect, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSet)
|
if (pSet)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_exprlist(info, pSet, NULL);
|
update_fields_infos_from_exprlist(info, pSet, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
|
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
|
||||||
@ -1479,18 +1588,13 @@ void mxs_sqlite3Update(Parse* pParse, SrcList* pTabList, ExprList* pChanges, Exp
|
|||||||
{
|
{
|
||||||
struct ExprList_item* pItem = &pChanges->a[i];
|
struct ExprList_item* pItem = &pChanges->a[i];
|
||||||
|
|
||||||
if (pItem->zName)
|
update_fields_infos(info, 0, pItem->pExpr, QC_TOKEN_MIDDLE, NULL);
|
||||||
{
|
|
||||||
append_affected_field(info, pItem->zName);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_affected_fields(info, 0, pItem->pExpr, QC_TOKEN_MIDDLE, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pWhere)
|
if (pWhere)
|
||||||
{
|
{
|
||||||
update_affected_fields(info, 0, pWhere, QC_TOKEN_MIDDLE, NULL);
|
update_fields_infos(info, 0, pWhere, QC_TOKEN_MIDDLE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
|
exposed_sqlite3SrcListDelete(pParse->db, pTabList);
|
||||||
@ -1516,7 +1620,7 @@ void maxscaleCollectInfoFromSelect(Parse* pParse, Select* pSelect)
|
|||||||
info->types = QUERY_TYPE_READ;
|
info->types = QUERY_TYPE_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_affected_fields_from_select(info, pSelect, NULL);
|
update_fields_infos_from_select(info, pSelect, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void maxscaleAlterTable(Parse *pParse, /* Parser context. */
|
void maxscaleAlterTable(Parse *pParse, /* Parser context. */
|
||||||
@ -1668,9 +1772,12 @@ void maxscaleExplain(Parse* pParse, SrcList* pName)
|
|||||||
info->status = QC_QUERY_PARSED;
|
info->status = QC_QUERY_PARSED;
|
||||||
info->types = QUERY_TYPE_READ;
|
info->types = QUERY_TYPE_READ;
|
||||||
update_names(info, "information_schema", "COLUMNS");
|
update_names(info, "information_schema", "COLUMNS");
|
||||||
append_affected_field(info,
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", NULL);
|
||||||
"COLUMN_DEFAULT COLUMN_KEY COLUMN_NAME "
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_KEY", NULL);
|
||||||
"COLUMN_TYPE EXTRA IS_NULLABLE");
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_TYPE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "EXTRA", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "IS_NULLABLE", NULL);
|
||||||
|
|
||||||
exposed_sqlite3SrcListDelete(pParse->db, pName);
|
exposed_sqlite3SrcListDelete(pParse->db, pName);
|
||||||
}
|
}
|
||||||
@ -2190,7 +2297,7 @@ void maxscaleSet(Parse* pParse, int scope, mxs_set_t kind, ExprList* pList)
|
|||||||
|
|
||||||
if (pValue->op == TK_SELECT)
|
if (pValue->op == TK_SELECT)
|
||||||
{
|
{
|
||||||
update_affected_fields_from_select(info, pValue->x.pSelect, NULL);
|
update_fields_infos_from_select(info, pValue->x.pSelect, NULL);
|
||||||
info->is_real_query = false; // TODO: This is what qc_mysqlembedded claims.
|
info->is_real_query = false; // TODO: This is what qc_mysqlembedded claims.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2246,16 +2353,24 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
update_names(info, "information_schema", "COLUMNS");
|
update_names(info, "information_schema", "COLUMNS");
|
||||||
if (pShow->data == MXS_SHOW_COLUMNS_FULL)
|
if (pShow->data == MXS_SHOW_COLUMNS_FULL)
|
||||||
{
|
{
|
||||||
append_affected_field(info,
|
update_field_infos(info, "information_schema", "COLUMNS", "COLLATION_NAME", NULL);
|
||||||
"COLLATION_NAME COLUMN_COMMENT COLUMN_DEFAULT "
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_COMMENT", NULL);
|
||||||
"COLUMN_KEY COLUMN_NAME COLUMN_TYPE EXTRA "
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", NULL);
|
||||||
"IS_NULLABLE PRIVILEGES");
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_KEY", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_TYPE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "EXTRA", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "IS_NULLABLE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "PRIVILEGES", NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
append_affected_field(info,
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_DEFAULT", NULL);
|
||||||
"COLUMN_DEFAULT COLUMN_KEY COLUMN_NAME "
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_KEY", NULL);
|
||||||
"COLUMN_TYPE EXTRA IS_NULLABLE");
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "COLUMN_TYPE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "EXTRA", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "COLUMNS", "IS_NULLABLE", NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2278,7 +2393,7 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
{
|
{
|
||||||
info->types = QUERY_TYPE_SHOW_DATABASES;
|
info->types = QUERY_TYPE_SHOW_DATABASES;
|
||||||
update_names(info, "information_schema", "SCHEMATA");
|
update_names(info, "information_schema", "SCHEMATA");
|
||||||
append_affected_field(info, "SCHEMA_NAME");
|
update_field_infos(info, "information_schema", "SCHEMATA", "SCHEMA_NAME", NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2288,10 +2403,19 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
{
|
{
|
||||||
info->types = QUERY_TYPE_WRITE;
|
info->types = QUERY_TYPE_WRITE;
|
||||||
update_names(info, "information_schema", "STATISTICS");
|
update_names(info, "information_schema", "STATISTICS");
|
||||||
append_affected_field(info,
|
update_field_infos(info, "information_schema", "STATISTICS", "CARDINALITY", NULL);
|
||||||
"CARDINALITY COLLATION COLUMN_NAME COMMENT INDEX_COMMENT "
|
update_field_infos(info, "information_schema", "STATISTICS", "COLLATION", NULL);
|
||||||
"INDEX_NAME INDEX_TYPE NON_UNIQUE NULLABLE PACKED SEQ_IN_INDEX "
|
update_field_infos(info, "information_schema", "STATISTICS", "COLUMN_NAME", NULL);
|
||||||
"SUB_PART TABLE_NAME");
|
update_field_infos(info, "information_schema", "STATISTICS", "COMMENT", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "INDEX_COMMENT", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "INDEX_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "INDEX_TYPE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "NON_UNIQUE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "NULLABLE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "PACKED", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "SEQ_IN_INDEX", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "SUB_PART", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "STATISTICS", "TABLE_NAME", NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2299,12 +2423,24 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
{
|
{
|
||||||
info->types = QUERY_TYPE_WRITE;
|
info->types = QUERY_TYPE_WRITE;
|
||||||
update_names(info, "information_schema", "TABLES");
|
update_names(info, "information_schema", "TABLES");
|
||||||
append_affected_field(info,
|
update_field_infos(info, "information_schema", "TABLES", "AUTO_INCREMENT", NULL);
|
||||||
"AUTO_INCREMENT AVG_ROW_LENGTH CHECKSUM CHECK_TIME "
|
update_field_infos(info, "information_schema", "TABLES", "AVG_ROW_LENGTH", NULL);
|
||||||
"CREATE_OPTIONS CREATE_TIME DATA_FREE DATA_LENGTH "
|
update_field_infos(info, "information_schema", "TABLES", "CHECKSUM", NULL);
|
||||||
"ENGINE INDEX_LENGTH MAX_DATA_LENGTH ROW_FORMAT "
|
update_field_infos(info, "information_schema", "TABLES", "CHECK_TIME", NULL);
|
||||||
"TABLE_COLLATION TABLE_COMMENT TABLE_NAME "
|
update_field_infos(info, "information_schema", "TABLES", "CREATE_OPTIONS", NULL);
|
||||||
"TABLE_ROWS UPDATE_TIME VERSION");
|
update_field_infos(info, "information_schema", "TABLES", "CREATE_TIME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "DATA_FREE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "DATA_LENGTH", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "ENGINE", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "INDEX_LENGTH", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "MAX_DATA_LENGTH", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "ROW_FORMAT", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "TABLE_COLLATION", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "TABLE_COMMENT", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "TABLE_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "TABLE_ROWS", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "UPDATE_TIME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "TABLES", "VERSION", NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2318,7 +2454,8 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
// TODO: qc_mysqlembedded does not set the type bit.
|
// TODO: qc_mysqlembedded does not set the type bit.
|
||||||
info->types = QUERY_TYPE_UNKNOWN;
|
info->types = QUERY_TYPE_UNKNOWN;
|
||||||
update_names(info, "information_schema", "SESSION_STATUS");
|
update_names(info, "information_schema", "SESSION_STATUS");
|
||||||
append_affected_field(info, "VARIABLE_NAME VARIABLE_VALUE");
|
update_field_infos(info, "information_schema", "SESSION_STATUS", "VARIABLE_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "SESSION_STATUS", "VARIABLE_VALUE", NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MXS_SHOW_STATUS_MASTER:
|
case MXS_SHOW_STATUS_MASTER:
|
||||||
@ -2343,7 +2480,7 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
{
|
{
|
||||||
info->types = QUERY_TYPE_SHOW_TABLES;
|
info->types = QUERY_TYPE_SHOW_TABLES;
|
||||||
update_names(info, "information_schema", "TABLE_NAMES");
|
update_names(info, "information_schema", "TABLE_NAMES");
|
||||||
append_affected_field(info, "TABLE_NAME");
|
update_field_infos(info, "information_schema", "TABLE_NAMES", "TABLE_NAME", NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2358,7 +2495,8 @@ extern void maxscaleShow(Parse* pParse, MxsShow* pShow)
|
|||||||
info->types = QUERY_TYPE_SYSVAR_READ;
|
info->types = QUERY_TYPE_SYSVAR_READ;
|
||||||
}
|
}
|
||||||
update_names(info, "information_schema", "SESSION_VARIABLES");
|
update_names(info, "information_schema", "SESSION_VARIABLES");
|
||||||
append_affected_field(info, "VARIABLE_NAME VARIABLE_VALUE");
|
update_field_infos(info, "information_schema", "SESSION_STATUS", "VARIABLE_NAME", NULL);
|
||||||
|
update_field_infos(info, "information_schema", "SESSION_STATUS", "VARIABLE_VALUE", NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2856,7 +2994,39 @@ static char* qc_sqlite_get_affected_fields(GWBUF* query)
|
|||||||
{
|
{
|
||||||
if (qc_info_is_valid(info->status))
|
if (qc_info_is_valid(info->status))
|
||||||
{
|
{
|
||||||
affected_fields = info->affected_fields;
|
if (!info->affected_fields)
|
||||||
|
{
|
||||||
|
if (info->field_infos_len != 0)
|
||||||
|
{
|
||||||
|
// The first time qc_sqlite_get_affected_fields() is called
|
||||||
|
// we copy the column data from info->fields_infos into
|
||||||
|
// info->affected_fields.
|
||||||
|
QC_FIELD_INFO* fis = info->field_infos;
|
||||||
|
size_t fis_len = info->field_infos_len;
|
||||||
|
size_t buflen = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fis_len; ++i)
|
||||||
|
{
|
||||||
|
buflen += strlen(fis[i].column);
|
||||||
|
buflen += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buflen += 1;
|
||||||
|
|
||||||
|
affected_fields = MXS_MALLOC(buflen);
|
||||||
|
MXS_ABORT_IF_NULL(affected_fields);
|
||||||
|
|
||||||
|
affected_fields[0] = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fis_len; ++i)
|
||||||
|
{
|
||||||
|
strcat(affected_fields, fis[i].column);
|
||||||
|
strcat(affected_fields, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
info->affected_fields = affected_fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
|
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
|
||||||
{
|
{
|
||||||
@ -2969,16 +3139,33 @@ static qc_query_op_t qc_sqlite_get_prepare_operation(GWBUF* query)
|
|||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qc_sqlite_get_field_info(GWBUF* stmt, const QC_FIELD_INFO** infos, size_t* n_infos)
|
void qc_sqlite_get_field_info(GWBUF* query, const QC_FIELD_INFO** infos, size_t* n_infos)
|
||||||
{
|
{
|
||||||
QC_TRACE();
|
QC_TRACE();
|
||||||
ss_dassert(this_unit.initialized);
|
ss_dassert(this_unit.initialized);
|
||||||
ss_dassert(this_thread.initialized);
|
ss_dassert(this_thread.initialized);
|
||||||
|
|
||||||
MXS_ERROR("qc_get_field_info not implemented yet.");
|
|
||||||
|
|
||||||
*infos = NULL;
|
*infos = NULL;
|
||||||
*n_infos = 0;
|
*n_infos = 0;
|
||||||
|
|
||||||
|
QC_SQLITE_INFO* info = get_query_info(query);
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
if (qc_info_is_valid(info->status))
|
||||||
|
{
|
||||||
|
*infos = info->field_infos;
|
||||||
|
*n_infos = info->field_infos_len;
|
||||||
|
}
|
||||||
|
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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -871,6 +871,123 @@ bool compare_get_prepare_operation(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator == (const QC_FIELD_INFO& lhs, const QC_FIELD_INFO& rhs)
|
||||||
|
{
|
||||||
|
bool rv = false;
|
||||||
|
if (lhs.column && rhs.column && (strcasecmp(lhs.column, rhs.column) == 0))
|
||||||
|
{
|
||||||
|
if (!lhs.table && !rhs.table)
|
||||||
|
{
|
||||||
|
rv = true;
|
||||||
|
}
|
||||||
|
else if (lhs.table && rhs.table && (strcmp(lhs.table, rhs.table) == 0))
|
||||||
|
{
|
||||||
|
if (!lhs.database && !rhs.database)
|
||||||
|
{
|
||||||
|
rv = true;
|
||||||
|
}
|
||||||
|
else if (lhs.database && rhs.database && (strcmp(lhs.database, rhs.database) == 0))
|
||||||
|
{
|
||||||
|
rv = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream& operator << (ostream& out, const QC_FIELD_INFO& x)
|
||||||
|
{
|
||||||
|
if (x.database)
|
||||||
|
{
|
||||||
|
out << x.database;
|
||||||
|
out << ".";
|
||||||
|
ss_dassert(x.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.table)
|
||||||
|
{
|
||||||
|
out << x.table;
|
||||||
|
out << ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
ss_dassert(x.column);
|
||||||
|
out << x.column;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool are_equal(const QC_FIELD_INFO* fields1, size_t n_fields1,
|
||||||
|
const QC_FIELD_INFO* fields2, size_t n_fields2)
|
||||||
|
{
|
||||||
|
bool rv = (n_fields1 == n_fields2);
|
||||||
|
|
||||||
|
if (rv)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
while (rv && (i < n_fields1))
|
||||||
|
{
|
||||||
|
rv = *fields1 == *fields2;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream& print(ostream& out, const QC_FIELD_INFO* fields, size_t n_fields)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < n_fields)
|
||||||
|
{
|
||||||
|
out << fields[i++];
|
||||||
|
|
||||||
|
if (i != n_fields)
|
||||||
|
{
|
||||||
|
out << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_get_field_info(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1,
|
||||||
|
QUERY_CLASSIFIER* pClassifier2, GWBUF* pCopy2)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
const char HEADING[] = "qc_get_field_info : ";
|
||||||
|
|
||||||
|
const QC_FIELD_INFO* infos1;
|
||||||
|
const QC_FIELD_INFO* infos2;
|
||||||
|
size_t n_infos1;
|
||||||
|
size_t n_infos2;
|
||||||
|
|
||||||
|
pClassifier1->qc_get_field_info(pCopy1, &infos1, &n_infos1);
|
||||||
|
pClassifier2->qc_get_field_info(pCopy2, &infos2, &n_infos2);
|
||||||
|
|
||||||
|
stringstream ss;
|
||||||
|
ss << HEADING;
|
||||||
|
|
||||||
|
if (are_equal(infos1, n_infos1, infos2, n_infos2))
|
||||||
|
{
|
||||||
|
ss << "Ok : ";
|
||||||
|
print(ss, infos1, n_infos1);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss << "ERR: ";
|
||||||
|
print(ss, infos1, n_infos1);
|
||||||
|
ss << " != ";
|
||||||
|
print(ss, infos2, n_infos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
report(success, ss.str());
|
||||||
|
|
||||||
|
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);
|
||||||
@ -891,6 +1008,7 @@ bool compare(QUERY_CLASSIFIER* pClassifier1, QUERY_CLASSIFIER* pClassifier2, con
|
|||||||
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);
|
errors += !compare_get_prepare_name(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
errors += !compare_get_prepare_operation(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
errors += !compare_get_prepare_operation(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
|
//errors += !compare_get_field_info(pClassifier1, pCopy1, pClassifier2, pCopy2);
|
||||||
|
|
||||||
gwbuf_free(pCopy1);
|
gwbuf_free(pCopy1);
|
||||||
gwbuf_free(pCopy2);
|
gwbuf_free(pCopy2);
|
||||||
|
Reference in New Issue
Block a user