You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

581 lines
16 KiB

12 years ago
  1. /*****************************************************************************
  2. Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
  3. Copyright (c) 2017, 2019, MariaDB Corporation.
  4. This program is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free Software
  6. Foundation; version 2 of the License.
  7. This program is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License along with
  11. this program; if not, write to the Free Software Foundation, Inc.,
  12. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
  13. *****************************************************************************/
  14. /******************************************************************//**
  15. @file fts/fts0config.cc
  16. Full Text Search configuration table.
  17. Created 2007/5/9 Sunny Bains
  18. ***********************************************************************/
  19. #include "trx0roll.h"
  20. #include "row0sel.h"
  21. #include "fts0priv.h"
  22. #ifndef UNIV_NONINL
  23. #include "fts0types.ic"
  24. #include "fts0vlc.ic"
  25. #endif
  26. /******************************************************************//**
  27. Callback function for fetching the config value.
  28. @return always returns TRUE */
  29. static
  30. ibool
  31. fts_config_fetch_value(
  32. /*===================*/
  33. void* row, /*!< in: sel_node_t* */
  34. void* user_arg) /*!< in: pointer to
  35. ib_vector_t */
  36. {
  37. sel_node_t* node = static_cast<sel_node_t*>(row);
  38. fts_string_t* value = static_cast<fts_string_t*>(user_arg);
  39. dfield_t* dfield = que_node_get_val(node->select_list);
  40. dtype_t* type = dfield_get_type(dfield);
  41. ulint len = dfield_get_len(dfield);
  42. void* data = dfield_get_data(dfield);
  43. ut_a(dtype_get_mtype(type) == DATA_VARCHAR);
  44. if (len != UNIV_SQL_NULL) {
  45. ulint max_len = ut_min(value->f_len - 1, len);
  46. memcpy(value->f_str, data, max_len);
  47. value->f_len = max_len;
  48. value->f_str[value->f_len] = '\0';
  49. }
  50. return(TRUE);
  51. }
  52. /******************************************************************//**
  53. Get value from the config table. The caller must ensure that enough
  54. space is allocated for value to hold the column contents.
  55. @return DB_SUCCESS or error code */
  56. UNIV_INTERN
  57. dberr_t
  58. fts_config_get_value(
  59. /*=================*/
  60. trx_t* trx, /*!< transaction */
  61. fts_table_t* fts_table, /*!< in: the indexed
  62. FTS table */
  63. const char* name, /*!< in: get config value for
  64. this parameter name */
  65. fts_string_t* value) /*!< out: value read from
  66. config table */
  67. {
  68. pars_info_t* info;
  69. que_t* graph;
  70. dberr_t error;
  71. ulint name_len = strlen(name);
  72. char table_name[MAX_FULL_NAME_LEN];
  73. info = pars_info_create();
  74. *value->f_str = '\0';
  75. ut_a(value->f_len > 0);
  76. pars_info_bind_function(info, "my_func", fts_config_fetch_value,
  77. value);
  78. /* The len field of value must be set to the max bytes that
  79. it can hold. On a successful read, the len field will be set
  80. to the actual number of bytes copied to value. */
  81. pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
  82. fts_table->suffix = "CONFIG";
  83. fts_get_table_name(fts_table, table_name);
  84. pars_info_bind_id(info, true, "table_name", table_name);
  85. graph = fts_parse_sql(
  86. fts_table,
  87. info,
  88. "DECLARE FUNCTION my_func;\n"
  89. "DECLARE CURSOR c IS SELECT value FROM $table_name"
  90. " WHERE key = :name;\n"
  91. "BEGIN\n"
  92. ""
  93. "OPEN c;\n"
  94. "WHILE 1 = 1 LOOP\n"
  95. " FETCH c INTO my_func();\n"
  96. " IF c % NOTFOUND THEN\n"
  97. " EXIT;\n"
  98. " END IF;\n"
  99. "END LOOP;\n"
  100. "CLOSE c;");
  101. trx->op_info = "getting FTS config value";
  102. error = fts_eval_sql(trx, graph);
  103. mutex_enter(&dict_sys->mutex);
  104. que_graph_free(graph);
  105. mutex_exit(&dict_sys->mutex);
  106. return(error);
  107. }
  108. /*********************************************************************//**
  109. Create the config table name for retrieving index specific value.
  110. @return index config parameter name */
  111. UNIV_INTERN
  112. char*
  113. fts_config_create_index_param_name(
  114. /*===============================*/
  115. const char* param, /*!< in: base name of param */
  116. const dict_index_t* index) /*!< in: index for config */
  117. {
  118. ulint len;
  119. char* name;
  120. /* The format of the config name is: name_<index_id>. */
  121. len = strlen(param);
  122. /* Caller is responsible for deleting name. */
  123. name = static_cast<char*>(ut_malloc(
  124. len + FTS_AUX_MIN_TABLE_ID_LENGTH + 2));
  125. strcpy(name, param);
  126. name[len] = '_';
  127. fts_write_object_id(index->id, name + len + 1,
  128. DICT_TF2_FLAG_IS_SET(index->table,
  129. DICT_TF2_FTS_AUX_HEX_NAME));
  130. return(name);
  131. }
  132. /******************************************************************//**
  133. Get value specific to an FTS index from the config table. The caller
  134. must ensure that enough space is allocated for value to hold the
  135. column contents.
  136. @return DB_SUCCESS or error code */
  137. UNIV_INTERN
  138. dberr_t
  139. fts_config_get_index_value(
  140. /*=======================*/
  141. trx_t* trx, /*!< transaction */
  142. dict_index_t* index, /*!< in: index */
  143. const char* param, /*!< in: get config value for
  144. this parameter name */
  145. fts_string_t* value) /*!< out: value read from
  146. config table */
  147. {
  148. char* name;
  149. dberr_t error;
  150. fts_table_t fts_table;
  151. FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
  152. index->table);
  153. /* We are responsible for free'ing name. */
  154. name = fts_config_create_index_param_name(param, index);
  155. error = fts_config_get_value(trx, &fts_table, name, value);
  156. ut_free(name);
  157. return(error);
  158. }
  159. /******************************************************************//**
  160. Set the value in the config table for name.
  161. @return DB_SUCCESS or error code */
  162. UNIV_INTERN
  163. dberr_t
  164. fts_config_set_value(
  165. /*=================*/
  166. trx_t* trx, /*!< transaction */
  167. fts_table_t* fts_table, /*!< in: the indexed
  168. FTS table */
  169. const char* name, /*!< in: get config value for
  170. this parameter name */
  171. const fts_string_t*
  172. value) /*!< in: value to update */
  173. {
  174. pars_info_t* info;
  175. que_t* graph;
  176. dberr_t error;
  177. undo_no_t undo_no;
  178. undo_no_t n_rows_updated;
  179. ulint name_len = strlen(name);
  180. char table_name[MAX_FULL_NAME_LEN];
  181. info = pars_info_create();
  182. pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
  183. pars_info_bind_varchar_literal(info, "value",
  184. value->f_str, value->f_len);
  185. const bool dict_locked = fts_table->table->fts->fts_status
  186. & TABLE_DICT_LOCKED;
  187. fts_table->suffix = "CONFIG";
  188. fts_get_table_name(fts_table, table_name, dict_locked);
  189. pars_info_bind_id(info, true, "table_name", table_name);
  190. graph = fts_parse_sql(
  191. fts_table, info,
  192. "BEGIN UPDATE $table_name SET value = :value "
  193. "WHERE key = :name;");
  194. trx->op_info = "setting FTS config value";
  195. undo_no = trx->undo_no;
  196. error = fts_eval_sql(trx, graph);
  197. fts_que_graph_free_check_lock(fts_table, NULL, graph);
  198. n_rows_updated = trx->undo_no - undo_no;
  199. /* Check if we need to do an insert. */
  200. if (n_rows_updated == 0) {
  201. info = pars_info_create();
  202. pars_info_bind_varchar_literal(
  203. info, "name", (byte*) name, name_len);
  204. pars_info_bind_varchar_literal(
  205. info, "value", value->f_str, value->f_len);
  206. fts_get_table_name(fts_table, table_name, dict_locked);
  207. pars_info_bind_id(info, true, "table_name", table_name);
  208. graph = fts_parse_sql(
  209. fts_table, info,
  210. "BEGIN\n"
  211. "INSERT INTO $table_name VALUES(:name, :value);");
  212. trx->op_info = "inserting FTS config value";
  213. error = fts_eval_sql(trx, graph);
  214. fts_que_graph_free_check_lock(fts_table, NULL, graph);
  215. }
  216. return(error);
  217. }
  218. /******************************************************************//**
  219. Set the value specific to an FTS index in the config table.
  220. @return DB_SUCCESS or error code */
  221. UNIV_INTERN
  222. dberr_t
  223. fts_config_set_index_value(
  224. /*=======================*/
  225. trx_t* trx, /*!< transaction */
  226. dict_index_t* index, /*!< in: index */
  227. const char* param, /*!< in: get config value for
  228. this parameter name */
  229. fts_string_t* value) /*!< out: value read from
  230. config table */
  231. {
  232. char* name;
  233. dberr_t error;
  234. fts_table_t fts_table;
  235. FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
  236. index->table);
  237. /* We are responsible for free'ing name. */
  238. name = fts_config_create_index_param_name(param, index);
  239. error = fts_config_set_value(trx, &fts_table, name, value);
  240. ut_free(name);
  241. return(error);
  242. }
  243. /******************************************************************//**
  244. Get an ulint value from the config table.
  245. @return DB_SUCCESS if all OK else error code */
  246. UNIV_INTERN
  247. dberr_t
  248. fts_config_get_index_ulint(
  249. /*=======================*/
  250. trx_t* trx, /*!< in: transaction */
  251. dict_index_t* index, /*!< in: FTS index */
  252. const char* name, /*!< in: param name */
  253. ulint* int_value) /*!< out: value */
  254. {
  255. dberr_t error;
  256. fts_string_t value;
  257. /* We set the length of value to the max bytes it can hold. This
  258. information is used by the callback that reads the value.*/
  259. value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
  260. value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
  261. error = fts_config_get_index_value(trx, index, name, &value);
  262. if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
  263. ut_print_timestamp(stderr);
  264. fprintf(stderr, " InnoDB: Error: (%s) reading `%s'\n",
  265. ut_strerr(error), name);
  266. } else {
  267. *int_value = strtoul((char*) value.f_str, NULL, 10);
  268. }
  269. ut_free(value.f_str);
  270. return(error);
  271. }
  272. /******************************************************************//**
  273. Set an ulint value in the config table.
  274. @return DB_SUCCESS if all OK else error code */
  275. UNIV_INTERN
  276. dberr_t
  277. fts_config_set_index_ulint(
  278. /*=======================*/
  279. trx_t* trx, /*!< in: transaction */
  280. dict_index_t* index, /*!< in: FTS index */
  281. const char* name, /*!< in: param name */
  282. ulint int_value) /*!< in: value */
  283. {
  284. dberr_t error;
  285. fts_string_t value;
  286. /* We set the length of value to the max bytes it can hold. This
  287. information is used by the callback that reads the value.*/
  288. value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
  289. value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
  290. // FIXME: Get rid of snprintf
  291. ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
  292. value.f_len = ut_snprintf(
  293. (char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
  294. error = fts_config_set_index_value(trx, index, name, &value);
  295. if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
  296. ut_print_timestamp(stderr);
  297. fprintf(stderr, " InnoDB: Error: (%s) writing `%s'\n",
  298. ut_strerr(error), name);
  299. }
  300. ut_free(value.f_str);
  301. return(error);
  302. }
  303. /******************************************************************//**
  304. Get an ulint value from the config table.
  305. @return DB_SUCCESS if all OK else error code */
  306. UNIV_INTERN
  307. dberr_t
  308. fts_config_get_ulint(
  309. /*=================*/
  310. trx_t* trx, /*!< in: transaction */
  311. fts_table_t* fts_table, /*!< in: the indexed
  312. FTS table */
  313. const char* name, /*!< in: param name */
  314. ulint* int_value) /*!< out: value */
  315. {
  316. dberr_t error;
  317. fts_string_t value;
  318. /* We set the length of value to the max bytes it can hold. This
  319. information is used by the callback that reads the value.*/
  320. value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
  321. value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
  322. error = fts_config_get_value(trx, fts_table, name, &value);
  323. if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
  324. ut_print_timestamp(stderr);
  325. fprintf(stderr, " InnoDB: Error: (%s) reading `%s'\n",
  326. ut_strerr(error), name);
  327. } else {
  328. *int_value = strtoul((char*) value.f_str, NULL, 10);
  329. }
  330. ut_free(value.f_str);
  331. return(error);
  332. }
  333. /******************************************************************//**
  334. Set an ulint value in the config table.
  335. @return DB_SUCCESS if all OK else error code */
  336. UNIV_INTERN
  337. dberr_t
  338. fts_config_set_ulint(
  339. /*=================*/
  340. trx_t* trx, /*!< in: transaction */
  341. fts_table_t* fts_table, /*!< in: the indexed
  342. FTS table */
  343. const char* name, /*!< in: param name */
  344. ulint int_value) /*!< in: value */
  345. {
  346. dberr_t error;
  347. fts_string_t value;
  348. /* We set the length of value to the max bytes it can hold. This
  349. information is used by the callback that reads the value.*/
  350. value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
  351. value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
  352. // FIXME: Get rid of snprintf
  353. ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
  354. value.f_len = snprintf(
  355. (char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
  356. error = fts_config_set_value(trx, fts_table, name, &value);
  357. if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
  358. ut_print_timestamp(stderr);
  359. fprintf(stderr, " InnoDB: Error: (%s) writing `%s'\n",
  360. ut_strerr(error), name);
  361. }
  362. ut_free(value.f_str);
  363. return(error);
  364. }
  365. /******************************************************************//**
  366. Increment the value in the config table for column name.
  367. @return DB_SUCCESS or error code */
  368. UNIV_INTERN
  369. dberr_t
  370. fts_config_increment_value(
  371. /*=======================*/
  372. trx_t* trx, /*!< transaction */
  373. fts_table_t* fts_table, /*!< in: the indexed
  374. FTS table */
  375. const char* name, /*!< in: increment config value
  376. for this parameter name */
  377. ulint delta) /*!< in: increment by this
  378. much */
  379. {
  380. dberr_t error;
  381. fts_string_t value;
  382. que_t* graph = NULL;
  383. ulint name_len = strlen(name);
  384. pars_info_t* info = pars_info_create();
  385. char table_name[MAX_FULL_NAME_LEN];
  386. /* We set the length of value to the max bytes it can hold. This
  387. information is used by the callback that reads the value.*/
  388. value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
  389. value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
  390. *value.f_str = '\0';
  391. pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
  392. pars_info_bind_function(
  393. info, "my_func", fts_config_fetch_value, &value);
  394. fts_table->suffix = "CONFIG";
  395. fts_get_table_name(fts_table, table_name);
  396. pars_info_bind_id(info, true, "config_table", table_name);
  397. graph = fts_parse_sql(
  398. fts_table, info,
  399. "DECLARE FUNCTION my_func;\n"
  400. "DECLARE CURSOR c IS SELECT value FROM $config_table"
  401. " WHERE key = :name FOR UPDATE;\n"
  402. "BEGIN\n"
  403. ""
  404. "OPEN c;\n"
  405. "WHILE 1 = 1 LOOP\n"
  406. " FETCH c INTO my_func();\n"
  407. " IF c % NOTFOUND THEN\n"
  408. " EXIT;\n"
  409. " END IF;\n"
  410. "END LOOP;\n"
  411. "CLOSE c;");
  412. trx->op_info = "read FTS config value";
  413. error = fts_eval_sql(trx, graph);
  414. fts_que_graph_free_check_lock(fts_table, NULL, graph);
  415. if (UNIV_UNLIKELY(error == DB_SUCCESS)) {
  416. ulint int_value;
  417. int_value = strtoul((char*) value.f_str, NULL, 10);
  418. int_value += delta;
  419. ut_a(FTS_MAX_CONFIG_VALUE_LEN > FTS_MAX_INT_LEN);
  420. // FIXME: Get rid of snprintf
  421. value.f_len = snprintf(
  422. (char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
  423. fts_config_set_value(trx, fts_table, name, &value);
  424. }
  425. if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
  426. ut_print_timestamp(stderr);
  427. fprintf(stderr, " InnoDB: Error: (%s) "
  428. "while incrementing %s.\n", ut_strerr(error), name);
  429. }
  430. ut_free(value.f_str);
  431. return(error);
  432. }
  433. /******************************************************************//**
  434. Increment the per index value in the config table for column name.
  435. @return DB_SUCCESS or error code */
  436. UNIV_INTERN
  437. dberr_t
  438. fts_config_increment_index_value(
  439. /*=============================*/
  440. trx_t* trx, /*!< transaction */
  441. dict_index_t* index, /*!< in: FTS index */
  442. const char* param, /*!< in: increment config value
  443. for this parameter name */
  444. ulint delta) /*!< in: increment by this
  445. much */
  446. {
  447. char* name;
  448. dberr_t error;
  449. fts_table_t fts_table;
  450. FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
  451. index->table);
  452. /* We are responsible for free'ing name. */
  453. name = fts_config_create_index_param_name(param, index);
  454. error = fts_config_increment_value(trx, &fts_table, name, delta);
  455. ut_free(name);
  456. return(error);
  457. }