summaryrefslogtreecommitdiffstats
path: root/storage/innobase/fts/fts0config.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/fts/fts0config.cc')
-rw-r--r--storage/innobase/fts/fts0config.cc432
1 files changed, 432 insertions, 0 deletions
diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc
new file mode 100644
index 00000000..9e2b4091
--- /dev/null
+++ b/storage/innobase/fts/fts0config.cc
@@ -0,0 +1,432 @@
+/*****************************************************************************
+
+Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 2020, MariaDB Corporation.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file fts/fts0config.cc
+Full Text Search configuration table.
+
+Created 2007/5/9 Sunny Bains
+***********************************************************************/
+
+#include "trx0roll.h"
+#include "row0sel.h"
+
+#include "fts0priv.h"
+
+/******************************************************************//**
+Callback function for fetching the config value.
+@return always returns TRUE */
+static
+ibool
+fts_config_fetch_value(
+/*===================*/
+ void* row, /*!< in: sel_node_t* */
+ void* user_arg) /*!< in: pointer to
+ ib_vector_t */
+{
+ sel_node_t* node = static_cast<sel_node_t*>(row);
+ fts_string_t* value = static_cast<fts_string_t*>(user_arg);
+
+ dfield_t* dfield = que_node_get_val(node->select_list);
+ dtype_t* type = dfield_get_type(dfield);
+ ulint len = dfield_get_len(dfield);
+ void* data = dfield_get_data(dfield);
+
+ ut_a(dtype_get_mtype(type) == DATA_VARCHAR);
+
+ if (len != UNIV_SQL_NULL) {
+ ulint max_len = ut_min(value->f_len - 1, len);
+
+ memcpy(value->f_str, data, max_len);
+ value->f_len = max_len;
+ value->f_str[value->f_len] = '\0';
+ }
+
+ return(TRUE);
+}
+
+/******************************************************************//**
+Get value from the config table. The caller must ensure that enough
+space is allocated for value to hold the column contents.
+@return DB_SUCCESS or error code */
+dberr_t
+fts_config_get_value(
+/*=================*/
+ trx_t* trx, /*!< transaction */
+ fts_table_t* fts_table, /*!< in: the indexed
+ FTS table */
+ const char* name, /*!< in: get config value for
+ this parameter name */
+ fts_string_t* value) /*!< out: value read from
+ config table */
+{
+ pars_info_t* info;
+ que_t* graph;
+ dberr_t error;
+ ulint name_len = strlen(name);
+ char table_name[MAX_FULL_NAME_LEN];
+
+ info = pars_info_create();
+
+ *value->f_str = '\0';
+ ut_a(value->f_len > 0);
+
+ pars_info_bind_function(info, "my_func", fts_config_fetch_value,
+ value);
+
+ /* The len field of value must be set to the max bytes that
+ it can hold. On a successful read, the len field will be set
+ to the actual number of bytes copied to value. */
+ pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
+
+ fts_table->suffix = "CONFIG";
+ fts_get_table_name(fts_table, table_name);
+ pars_info_bind_id(info, true, "table_name", table_name);
+
+ graph = fts_parse_sql(
+ fts_table,
+ info,
+ "DECLARE FUNCTION my_func;\n"
+ "DECLARE CURSOR c IS SELECT value FROM $table_name"
+ " WHERE key = :name;\n"
+ "BEGIN\n"
+ ""
+ "OPEN c;\n"
+ "WHILE 1 = 1 LOOP\n"
+ " FETCH c INTO my_func();\n"
+ " IF c % NOTFOUND THEN\n"
+ " EXIT;\n"
+ " END IF;\n"
+ "END LOOP;\n"
+ "CLOSE c;");
+
+ trx->op_info = "getting FTS config value";
+
+ error = fts_eval_sql(trx, graph);
+
+ mutex_enter(&dict_sys.mutex);
+ que_graph_free(graph);
+ mutex_exit(&dict_sys.mutex);
+
+ return(error);
+}
+
+/*********************************************************************//**
+Create the config table name for retrieving index specific value.
+@return index config parameter name */
+char*
+fts_config_create_index_param_name(
+/*===============================*/
+ const char* param, /*!< in: base name of param */
+ const dict_index_t* index) /*!< in: index for config */
+{
+ ulint len;
+ char* name;
+
+ /* The format of the config name is: name_<index_id>. */
+ len = strlen(param);
+
+ /* Caller is responsible for deleting name. */
+ name = static_cast<char*>(ut_malloc_nokey(
+ len + FTS_AUX_MIN_TABLE_ID_LENGTH + 2));
+ ::strcpy(name, param);
+ name[len] = '_';
+
+ fts_write_object_id(index->id, name + len + 1);
+
+ return(name);
+}
+
+/******************************************************************//**
+Get value specific to an FTS index from the config table. The caller
+must ensure that enough space is allocated for value to hold the
+column contents.
+@return DB_SUCCESS or error code */
+dberr_t
+fts_config_get_index_value(
+/*=======================*/
+ trx_t* trx, /*!< transaction */
+ dict_index_t* index, /*!< in: index */
+ const char* param, /*!< in: get config value for
+ this parameter name */
+ fts_string_t* value) /*!< out: value read from
+ config table */
+{
+ char* name;
+ dberr_t error;
+ fts_table_t fts_table;
+
+ FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
+ index->table);
+
+ /* We are responsible for free'ing name. */
+ name = fts_config_create_index_param_name(param, index);
+
+ error = fts_config_get_value(trx, &fts_table, name, value);
+
+ ut_free(name);
+
+ return(error);
+}
+
+/******************************************************************//**
+Set the value in the config table for name.
+@return DB_SUCCESS or error code */
+dberr_t
+fts_config_set_value(
+/*=================*/
+ trx_t* trx, /*!< transaction */
+ fts_table_t* fts_table, /*!< in: the indexed
+ FTS table */
+ const char* name, /*!< in: get config value for
+ this parameter name */
+ const fts_string_t*
+ value) /*!< in: value to update */
+{
+ pars_info_t* info;
+ que_t* graph;
+ dberr_t error;
+ undo_no_t undo_no;
+ undo_no_t n_rows_updated;
+ ulint name_len = strlen(name);
+ char table_name[MAX_FULL_NAME_LEN];
+
+ info = pars_info_create();
+
+ pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
+ pars_info_bind_varchar_literal(info, "value",
+ value->f_str, value->f_len);
+
+ const bool dict_locked = fts_table->table->fts->dict_locked;
+
+ fts_table->suffix = "CONFIG";
+ fts_get_table_name(fts_table, table_name, dict_locked);
+ pars_info_bind_id(info, true, "table_name", table_name);
+
+ graph = fts_parse_sql(
+ fts_table, info,
+ "BEGIN UPDATE $table_name SET value = :value"
+ " WHERE key = :name;");
+
+ trx->op_info = "setting FTS config value";
+
+ undo_no = trx->undo_no;
+
+ error = fts_eval_sql(trx, graph);
+
+ fts_que_graph_free_check_lock(fts_table, NULL, graph);
+
+ n_rows_updated = trx->undo_no - undo_no;
+
+ /* Check if we need to do an insert. */
+ if (n_rows_updated == 0) {
+ info = pars_info_create();
+
+ pars_info_bind_varchar_literal(
+ info, "name", (byte*) name, name_len);
+
+ pars_info_bind_varchar_literal(
+ info, "value", value->f_str, value->f_len);
+
+ fts_get_table_name(fts_table, table_name, dict_locked);
+ pars_info_bind_id(info, true, "table_name", table_name);
+
+ graph = fts_parse_sql(
+ fts_table, info,
+ "BEGIN\n"
+ "INSERT INTO $table_name VALUES(:name, :value);");
+
+ trx->op_info = "inserting FTS config value";
+
+ error = fts_eval_sql(trx, graph);
+
+ fts_que_graph_free_check_lock(fts_table, NULL, graph);
+ }
+
+ return(error);
+}
+
+/******************************************************************//**
+Set the value specific to an FTS index in the config table.
+@return DB_SUCCESS or error code */
+dberr_t
+fts_config_set_index_value(
+/*=======================*/
+ trx_t* trx, /*!< transaction */
+ dict_index_t* index, /*!< in: index */
+ const char* param, /*!< in: get config value for
+ this parameter name */
+ fts_string_t* value) /*!< out: value read from
+ config table */
+{
+ char* name;
+ dberr_t error;
+ fts_table_t fts_table;
+
+ FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
+ index->table);
+
+ /* We are responsible for free'ing name. */
+ name = fts_config_create_index_param_name(param, index);
+
+ error = fts_config_set_value(trx, &fts_table, name, value);
+
+ ut_free(name);
+
+ return(error);
+}
+
+#ifdef FTS_OPTIMIZE_DEBUG
+/******************************************************************//**
+Get an ulint value from the config table.
+@return DB_SUCCESS if all OK else error code */
+dberr_t
+fts_config_get_index_ulint(
+/*=======================*/
+ trx_t* trx, /*!< in: transaction */
+ dict_index_t* index, /*!< in: FTS index */
+ const char* name, /*!< in: param name */
+ ulint* int_value) /*!< out: value */
+{
+ dberr_t error;
+ fts_string_t value;
+
+ /* We set the length of value to the max bytes it can hold. This
+ information is used by the callback that reads the value.*/
+ value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
+ value.f_str = static_cast<byte*>(ut_malloc_nokey(value.f_len + 1));
+
+ error = fts_config_get_index_value(trx, index, name, &value);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+ ib::error() << "(" << error << ") reading `" << name << "'";
+ } else {
+ *int_value = strtoul((char*) value.f_str, NULL, 10);
+ }
+
+ ut_free(value.f_str);
+
+ return(error);
+}
+
+/******************************************************************//**
+Set an ulint value in the config table.
+@return DB_SUCCESS if all OK else error code */
+dberr_t
+fts_config_set_index_ulint(
+/*=======================*/
+ trx_t* trx, /*!< in: transaction */
+ dict_index_t* index, /*!< in: FTS index */
+ const char* name, /*!< in: param name */
+ ulint int_value) /*!< in: value */
+{
+ dberr_t error;
+ fts_string_t value;
+
+ /* We set the length of value to the max bytes it can hold. This
+ information is used by the callback that reads the value.*/
+ value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
+ value.f_str = static_cast<byte*>(ut_malloc_nokey(value.f_len + 1));
+
+ // FIXME: Get rid of snprintf
+ ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
+
+ value.f_len = snprintf(
+ (char*) value.f_str, FTS_MAX_INT_LEN, ULINTPF, int_value);
+
+ error = fts_config_set_index_value(trx, index, name, &value);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+ ib::error() << "(" << error << ") writing `" << name << "'";
+ }
+
+ ut_free(value.f_str);
+
+ return(error);
+}
+#endif /* FTS_OPTIMIZE_DEBUG */
+
+/******************************************************************//**
+Get an ulint value from the config table.
+@return DB_SUCCESS if all OK else error code */
+dberr_t
+fts_config_get_ulint(
+/*=================*/
+ trx_t* trx, /*!< in: transaction */
+ fts_table_t* fts_table, /*!< in: the indexed
+ FTS table */
+ const char* name, /*!< in: param name */
+ ulint* int_value) /*!< out: value */
+{
+ dberr_t error;
+ fts_string_t value;
+
+ /* We set the length of value to the max bytes it can hold. This
+ information is used by the callback that reads the value.*/
+ value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
+ value.f_str = static_cast<byte*>(ut_malloc_nokey(value.f_len + 1));
+
+ error = fts_config_get_value(trx, fts_table, name, &value);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+ ib::error() << "(" << error << ") reading `" << name << "'";
+ } else {
+ *int_value = strtoul((char*) value.f_str, NULL, 10);
+ }
+
+ ut_free(value.f_str);
+
+ return(error);
+}
+
+/******************************************************************//**
+Set an ulint value in the config table.
+@return DB_SUCCESS if all OK else error code */
+dberr_t
+fts_config_set_ulint(
+/*=================*/
+ trx_t* trx, /*!< in: transaction */
+ fts_table_t* fts_table, /*!< in: the indexed
+ FTS table */
+ const char* name, /*!< in: param name */
+ ulint int_value) /*!< in: value */
+{
+ dberr_t error;
+ fts_string_t value;
+
+ /* We set the length of value to the max bytes it can hold. This
+ information is used by the callback that reads the value.*/
+ value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
+ value.f_str = static_cast<byte*>(ut_malloc_nokey(value.f_len + 1));
+
+ ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
+
+ value.f_len = (ulint) snprintf(
+ (char*) value.f_str, FTS_MAX_INT_LEN, ULINTPF, int_value);
+
+ error = fts_config_set_value(trx, fts_table, name, &value);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+ ib::error() << "(" << error << ") writing `" << name << "'";
+ }
+
+ ut_free(value.f_str);
+
+ return(error);
+}