mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 7587b0ec84
			
		
	
	
	7587b0ec84
	
	
	
		
			
			row_create_index_for_mysql(): Tolerate DB_LOCK_TABLE_FULL better. fts_create_one_common_table(), fts_create_one_index_table(): Do not corrupt the error state of a non-active transaction object. fts_config_set_value(): Only run another statement if there was no error yet.
		
			
				
	
	
		
			428 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			428 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*****************************************************************************
 | |
| 
 | |
| Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
 | |
| Copyright (c) 2017, 2021, 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, "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);
 | |
| 	que_graph_free(graph);
 | |
| 	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, "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);
 | |
| 
 | |
| 	que_graph_free(graph);
 | |
| 
 | |
| 	n_rows_updated = trx->undo_no - undo_no;
 | |
| 
 | |
| 	/* Check if we need to do an insert. */
 | |
| 	if (error == DB_SUCCESS && 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, "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);
 | |
| 
 | |
| 		que_graph_free(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);
 | |
| }
 |