/** Track node allocations, in case there is an error during parsing. */ static void
fts_ast_state_add_node(
fts_ast_state_t*state, /*!< in: ast instance */
fts_ast_node_t* node) /*!< in: node to add to ast */
{ if (!state->list.head) {
ut_a(!state->list.tail);
/******************************************************************//** This function takes ownership of the ptr and is responsible for free'ing it
@returnnew node or a node list with tokenized words */
fts_ast_node_t*
fts_ast_create_node_term( /*=====================*/ void* arg, /*!< in: ast state instance */ const fts_ast_string_t* ptr) /*!< in: ast term string */
{
fts_ast_state_t* state = static_cast<fts_ast_state_t*>(arg);
ulint len = ptr->len;
ulint cur_pos = 0;
fts_ast_node_t* node = NULL;
fts_ast_node_t* node_list = NULL;
fts_ast_node_t* first_node = NULL;
/* Scan the incoming string and filter out any "non-word" characters */ while (cur_pos < len) {
fts_string_t str;
ulint cur_len;
if (str.f_n_char > 0) { /* If the subsequent term (after the first one)'s size islessthanfts_min_token_sizeorthetermisgreater thanfts_max_token_size,weshallignorethat.Thisis
to make consistent with MyISAM behavior */ if ((first_node && (str.f_n_char < fts_min_token_size))
|| str.f_n_char > fts_max_token_size) { continue;
}
if (first_node) { /* There is more than one word, create
a list to organize them */ if (!node_list) {
node_list = fts_ast_create_node_list( static_cast<fts_ast_state_t*>(
arg),
first_node);
}
/******************************************************************//**
Create an AST term node, makes a copy of ptr for plugin parser
@return node */
fts_ast_node_t*
fts_ast_create_node_term_for_parser( /*================================*/ void* arg, /*!< in: ast state */ constchar* ptr, /*!< in: term string */ const ulint len) /*!< in: term string length */
{
fts_ast_node_t* node = NULL;
/* '%' as first char is forbidden for LIKE in internal SQL parser;
'%' as last char is reserved for wildcard search;*/ if (len == 0 || len > FTS_MAX_WORD_LEN
|| ptr[0] == '%' || ptr[len - 1] == '%') { return(NULL);
}
/******************************************************************//** This function takes ownership of the ptr and is responsible for free'ing it.
@returnnew node */
fts_ast_node_t*
fts_ast_create_node_text( /*=====================*/ void* arg, /*!< in: ast state instance */ const fts_ast_string_t* ptr) /*!< in: ast text string */
{
ulint len = ptr->len;
fts_ast_node_t* node = NULL;
/* Once we come here, the string must have at least 2 quotes "" aroundthequerystring,whichcouldbeempty.Alsothequery
string may contain 0x00 in it, we don't treat it as null-terminated. */
ut_ad(len >= 2);
ut_ad(ptr->str[0] == '\"' && ptr->str[len - 1] == '\"');
if (len == 2) { /* If the query string contains nothing except quotes,
it's obviously an invalid query. */ return(NULL);
}
/******************************************************************//** This function takes ownership of the expr and is responsible for free'ing it.
@returnnew node */
fts_ast_node_t*
fts_ast_create_node_list( /*=====================*/ void* arg, /*!< in: ast state instance */
fts_ast_node_t* expr) /*!< in: ast expr instance */
{
fts_ast_node_t* node = fts_ast_node_create();
/******************************************************************//**
Create a sub-expression list node. This function takes ownership of
expr and is responsible for deleting it.
@returnnew node */
fts_ast_node_t*
fts_ast_create_node_subexp_list( /*============================*/ void* arg, /*!< in: ast state instance */
fts_ast_node_t* expr) /*!< in: ast expr instance */
{
fts_ast_node_t* node = fts_ast_node_create();
/********************************************************************//**
Free a fts_ast_node_t instance.
@return next node to free */
fts_ast_node_t*
fts_ast_free_node( /*==============*/
fts_ast_node_t* node) /*!< in: the node to free */
{
fts_ast_node_t* next_node;
switch (node->type) { case FTS_AST_TEXT: if (node->text.ptr) {
fts_ast_string_free(node->text.ptr);
node->text.ptr = NULL;
} break;
case FTS_AST_TERM: if (node->term.ptr) {
fts_ast_string_free(node->term.ptr);
node->term.ptr = NULL;
} break;
case FTS_AST_LIST: case FTS_AST_SUBEXP_LIST: case FTS_AST_PARSER_PHRASE_LIST:
fts_ast_free_list(node);
node->list.head = node->list.tail = NULL; break;
case FTS_AST_OPER: break;
default:
ut_error;
}
/*!< Get next node before freeing the node itself */
next_node = node->next;
ut_free(node);
return(next_node);
}
/******************************************************************//** This AST takes ownership of the expr and is responsible for free'ing it.
@return in param "list" */
fts_ast_node_t*
fts_ast_add_node( /*=============*/
fts_ast_node_t* node, /*!< in: list instance */
fts_ast_node_t* elem) /*!< in: node to add to list */
{ if (!elem) { return(NULL);
}
/******************************************************************//**
Set the wildcard attribute of a term. */ void
fts_ast_term_set_wildcard( /*======================*/
fts_ast_node_t* node) /*!< in/out: set attribute of
a term node */
{ if (!node) { return;
}
/* If it's a node list, the wildcard should be set to the tail node*/ if (node->type == FTS_AST_LIST) {
ut_ad(node->list.tail != NULL);
node = node->list.tail;
}
/******************************************************************//**
Set the proximity attribute of a text node. */ void
fts_ast_text_set_distance( /*======================*/
fts_ast_node_t* node, /*!< in/out: text node */
ulint distance) /*!< in: the text proximity
distance */
{ if (node == NULL) { return;
}
/** Check only union operation involved in the node @param[in]nodeastnodetocheck
@return true if the node contains only union else false. */ bool
fts_ast_node_check_union(
fts_ast_node_t* node)
{ if (node->type == FTS_AST_LIST
|| node->type == FTS_AST_SUBEXP_LIST) {
for (node = node->list.head; node; node = node->next) { if (!fts_ast_node_check_union(node)) { return(false);
}
}
/******************************************************************//**
Traverse the AST - in-order traversal, except for the FTX_EXIST and FTS_IGNORE
nodes, which will be ignored in the first pass of each level, and visited in a
second and third pass after all other nodes in the same level are visited.
@return DB_SUCCESS if all went well */
dberr_t
fts_ast_visit( /*==========*/
fts_ast_oper_t oper, /*!< in: current operator */
fts_ast_node_t* node, /*!< in: current root node */
fts_ast_callback visitor, /*!< in: callback function */ void* arg, /*!< in: arg for callback */ bool* has_ignore) /*!< out: true, if the operator wasignoredduringprocessing, currentlyweignoreFTS_EXIST
and FTS_IGNORE operators */
{
dberr_t error = DB_SUCCESS;
fts_ast_node_t* oper_node = NULL;
fts_ast_node_t* start_node; bool revisit = false; bool will_be_ignored = false;
fts_ast_visit_pass_t visit_pass = FTS_PASS_FIRST; const trx_t* trx = node->trx;
/* In the first pass of the tree, at the leaf level of the tree,FTS_EXISTandFTS_IGNOREoperationwillbeignored. Itwillberepeatedatthelevelabovetheleaflevel.
Theordershouldberestrictlyfollowed,orwewillgetwrongresults. Forexample,wehaveaquery'a+b-cd+e-f'. firstpass:process'a'and'd'byunion; existpass:process'+b'and'+e'byintersection;
ignore pass: process '-c' and '-f' by difference. */
/* If will_be_ignored is set to true, then weencounteredandignoredaFTS_EXISTorFTS_IGNORE
operator. */ if (will_be_ignored) {
revisit = true; /* Remember oper for list in case '-abc&def',
ignored oper is from previous node of list.*/
node->oper = oper;
}
break;
case FTS_AST_OPER:
oper = node->oper;
oper_node = node;
/* Change the operator for revisit */ if (oper == FTS_EXIST) {
oper_node->oper = FTS_EXIST_SKIP;
} elseif (oper == FTS_IGNORE) {
oper_node->oper = FTS_IGNORE_SKIP;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.