ha_innobase.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:67k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & Innobase Oy
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* This file defines the Innobase handler: the interface between MySQL and
  14. Innobase */
  15. /* TODO list for the Innobase handler:
  16.   - Ask Monty if strings of different languages can exist in the same
  17.     database. Answer: in near future yes, but not yet.
  18. */
  19. #ifdef __GNUC__
  20. #pragma implementation // gcc: Class implementation
  21. #endif
  22. #include "mysql_priv.h"
  23. #ifdef HAVE_INNOBASE_DB
  24. #include <m_ctype.h>
  25. #include <assert.h>
  26. #include <hash.h>
  27. #include <myisampack.h>
  28. #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
  29. #include "ha_innobase.h"
  30. /* Store MySQL definition of 'byte': in Linux it is char while Innobase
  31. uses unsigned char */
  32. typedef byte mysql_byte;
  33. #define INSIDE_HA_INNOBASE_CC
  34. /* Include necessary Innobase headers */
  35. extern "C" {
  36. #include "../innobase/include/univ.i"
  37. #include "../innobase/include/srv0start.h"
  38. #include "../innobase/include/srv0srv.h"
  39. #include "../innobase/include/trx0roll.h"
  40. #include "../innobase/include/trx0trx.h"
  41. #include "../innobase/include/row0ins.h"
  42. #include "../innobase/include/row0mysql.h"
  43. #include "../innobase/include/row0sel.h"
  44. #include "../innobase/include/row0upd.h"
  45. #include "../innobase/include/log0log.h"
  46. #include "../innobase/include/lock0lock.h"
  47. #include "../innobase/include/dict0crea.h"
  48. #include "../innobase/include/btr0cur.h"
  49. #include "../innobase/include/btr0btr.h"
  50. #include "../innobase/include/fsp0fsp.h"
  51. }
  52. #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
  53. #define HA_INNOBASE_RANGE_COUNT   100
  54. bool  innobase_skip  = 0;
  55. uint  innobase_init_flags  = 0;
  56. ulong  innobase_cache_size  = 0;
  57. long innobase_mirrored_log_groups, innobase_log_files_in_group,
  58.      innobase_log_file_size, innobase_log_buffer_size,
  59.      innobase_buffer_pool_size, innobase_additional_mem_pool_size,
  60.      innobase_file_io_threads, innobase_lock_wait_timeout;
  61. char *innobase_data_home_dir, *innobase_data_file_path;
  62. char *innobase_log_group_home_dir, *innobase_log_arch_dir;
  63. bool innobase_flush_log_at_trx_commit, innobase_log_archive,
  64. innobase_use_native_aio;
  65. /* innobase_data_file_path=ibdata:15,idata2:1,... */
  66. /* The following counter is used to convey information to Innobase
  67. about server activity: in selects it is not sensible to call
  68. srv_active_wake_master_thread after each fetch or search, we only do
  69. it every INNOBASE_WAKE_INTERVAL'th step. */
  70. #define INNOBASE_WAKE_INTERVAL 32
  71. ulong innobase_active_counter = 0;
  72. char* innobase_home  = NULL;
  73. pthread_mutex_t innobase_mutex;
  74. static HASH  innobase_open_tables;
  75. static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
  76.       my_bool not_used __attribute__((unused)));
  77. static INNOBASE_SHARE *get_share(const char *table_name);
  78. static void free_share(INNOBASE_SHARE *share);
  79. static void innobase_print_error(const char* db_errpfx, char* buffer);
  80. /* General functions */
  81. /************************************************************************
  82. Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
  83. time calls srv_active_wake_master_thread. This function should be used
  84. when a single database operation may introduce a small need for
  85. server utility activity, like checkpointing. */
  86. inline
  87. void
  88. innobase_active_small(void)
  89. /*=======================*/
  90. {
  91. innobase_active_counter++;
  92. if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
  93. srv_active_wake_master_thread();
  94. }
  95. }
  96. /************************************************************************
  97. Converts an Innobase error code to a MySQL error code. */
  98. static
  99. int
  100. convert_error_code_to_mysql(
  101. /*========================*/
  102. /* out: MySQL error code */
  103. int error) /* in: Innobase error code */
  104. {
  105. if (error == DB_SUCCESS) {
  106. return(0);
  107.    } else if (error == (int) DB_DUPLICATE_KEY) {
  108.      return(HA_ERR_FOUND_DUPP_KEY);
  109.   } else if (error == (int) DB_RECORD_NOT_FOUND) {
  110.      return(HA_ERR_NO_ACTIVE_RECORD);
  111.   } else if (error == (int) DB_ERROR) {
  112.      return(HA_ERR_NO_ACTIVE_RECORD);
  113.   } else if (error == (int) DB_DEADLOCK) {
  114.      return(1000000);
  115.   } else if (error == (int) DB_OUT_OF_FILE_SPACE) {
  116.      return(HA_ERR_RECORD_FILE_FULL);
  117.   } else if (error == (int) DB_TABLE_IS_BEING_USED) {
  118.      return(HA_ERR_WRONG_COMMAND);
  119.   } else if (error == (int) DB_TABLE_NOT_FOUND) {
  120.      return(HA_ERR_KEY_NOT_FOUND);
  121.    } else if (error == (int) DB_TOO_BIG_RECORD) {
  122.      return(HA_ERR_TO_BIG_ROW);
  123.      } else {
  124.      dbug_assert(0);
  125.      return(-1); // Unknown error
  126.      }
  127. }
  128. /*************************************************************************
  129. Gets the Innobase transaction handle for a MySQL handler object, creates
  130. an Innobase transaction struct if the corresponding MySQL thread struct still
  131. lacks one. */
  132. static
  133. trx_t*
  134. check_trx_exists(
  135. /*=============*/
  136. /* out: Innobase transaction handle */
  137. THD* thd) /* in: user thread handle */
  138. {
  139. trx_t* trx;
  140. trx = (trx_t*) thd->transaction.all.innobase_tid;
  141. if (trx == NULL) {
  142.         dbug_assert(thd != NULL);
  143. trx = trx_allocate_for_mysql();
  144. thd->transaction.all.innobase_tid = trx;
  145. /* The execution of a single SQL statement is denoted by
  146. a 'transaction' handle which is a NULL pointer: Innobase
  147. remembers internally where the latest SQL statement
  148. started, and if error handling requires rolling back the
  149. latest statement, Innobase does a rollback to a savepoint. */
  150. thd->transaction.stmt.innobase_tid = NULL;
  151. }
  152. return(trx);
  153. }
  154. /*************************************************************************
  155. Updates the user_thd field in a handle and also allocates a new Innobase
  156. transaction handle if needed, and updates the transaction fields in the
  157. prebuilt struct. */
  158. inline
  159. int
  160. ha_innobase::update_thd(
  161. /*====================*/
  162. /* out: 0 or error code */
  163. THD* thd) /* in: thd to use the handle */
  164. {
  165. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  166. trx_t* trx;
  167. trx = check_trx_exists(thd);
  168. if (prebuilt->trx != trx) {
  169. row_update_prebuilt_trx(prebuilt, trx);
  170. }
  171. user_thd = thd;
  172. return(0);
  173. }
  174. /*************************************************************************
  175. Reads the data files and their sizes from a character string given in
  176. the .cnf file. */
  177. static
  178. bool
  179. innobase_parse_data_file_paths_and_sizes(void)
  180. /*==========================================*/
  181. /* out: TRUE if ok, FALSE if parsing
  182. error */
  183. {
  184. char* str;
  185. char* endp;
  186. char* path;
  187. ulint size;
  188. ulint i = 0;
  189. str = innobase_data_file_path;
  190. /* First calculate the number of data files and check syntax:
  191. path:size[M];path:size[M]... */
  192. while (*str != '') {
  193. path = str;
  194. while (*str != ':' && *str != '') {
  195. str++;
  196. }
  197. if (*str == '') {
  198. return(FALSE);
  199. }
  200. str++;
  201. size = strtoul(str, &endp, 10);
  202. str = endp;
  203. if (*str != 'M') {
  204. size = size / (1024 * 1024);
  205. } else {
  206. str++;
  207. }
  208. if (size == 0) {
  209. return(FALSE);
  210. }
  211. i++;
  212. if (*str == ';') {
  213. str++;
  214. } else if (*str != '') {
  215. return(FALSE);
  216. }
  217. }
  218. srv_data_file_names = (char**) ut_malloc(i * sizeof(void*));
  219. srv_data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint));
  220. srv_n_data_files = i;
  221. /* Then store the actual values to our arrays */
  222. str = innobase_data_file_path;
  223. i = 0;
  224. while (*str != '') {
  225. path = str;
  226. while (*str != ':' && *str != '') {
  227. str++;
  228. }
  229. if (*str == ':') {
  230. /* Make path a null-terminated string */
  231. *str = '';
  232. str++;
  233. }
  234. size = strtoul(str, &endp, 10);
  235. str = endp;
  236. if (*str != 'M') {
  237. size = size / (1024 * 1024);
  238. } else {
  239. str++;
  240. }
  241. srv_data_file_names[i] = path;
  242. srv_data_file_sizes[i] = size;
  243. i++;
  244. if (*str == ';') {
  245. str++;
  246. }
  247. }
  248. return(TRUE);
  249. }
  250. /*************************************************************************
  251. Reads log group home directories from a character string given in
  252. the .cnf file. */
  253. static
  254. bool
  255. innobase_parse_log_group_home_dirs(void)
  256. /*====================================*/
  257. /* out: TRUE if ok, FALSE if parsing
  258. error */
  259. {
  260. char* str;
  261. char* path;
  262. ulint i = 0;
  263. str = innobase_log_group_home_dir;
  264. /* First calculate the number of directories and check syntax:
  265. path;path;... */
  266. while (*str != '') {
  267. path = str;
  268. while (*str != ';' && *str != '') {
  269. str++;
  270. }
  271. i++;
  272. if (*str == ';') {
  273. str++;
  274. } else if (*str != '') {
  275. return(FALSE);
  276. }
  277. }
  278. if (i != (ulint) innobase_mirrored_log_groups) {
  279. return(FALSE);
  280. }
  281. srv_log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*));
  282. /* Then store the actual values to our array */
  283. str = innobase_log_group_home_dir;
  284. i = 0;
  285. while (*str != '') {
  286. path = str;
  287. while (*str != ';' && *str != '') {
  288. str++;
  289. }
  290. if (*str == ';') {
  291. *str = '';
  292. str++;
  293. }
  294. srv_log_group_home_dirs[i] = path;
  295. i++;
  296. }
  297. return(TRUE);
  298. }
  299. /*************************************************************************
  300. Opens an Innobase database. */
  301. bool
  302. innobase_init(void)
  303. /*===============*/
  304. /* out: TRUE if error */
  305. {
  306. static char  current_dir[3];
  307. int err;
  308. bool ret;
  309.    DBUG_ENTER("innobase_init");
  310. /* Use current_dir if no paths are set */
  311. current_dir[0]=FN_CURLIB;
  312. current_dir[1]=FN_LIBCHAR;
  313. current_dir[2]=0;
  314. /* Set Innobase initialization parameters according to the values
  315. read from MySQL .cnf file */
  316. if (!innobase_data_file_path)
  317. {
  318.   fprintf(stderr,
  319.        "Can't initialize Innobase as 'innobase_data_file_path' is not setn");
  320.   innobase_skip=1;
  321.   DBUG_RETURN(FALSE); // Continue without innobase
  322. }
  323. srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
  324.  current_dir);
  325. srv_logs_home = (char*) "";
  326. srv_arch_dir =  (innobase_log_arch_dir ? innobase_log_arch_dir :
  327.  current_dir);
  328. ret = innobase_parse_data_file_paths_and_sizes();
  329. if (ret == FALSE) {
  330.   DBUG_RETURN(TRUE);
  331. }
  332. if (!innobase_log_group_home_dir)
  333.   innobase_log_group_home_dir= current_dir;
  334. ret = innobase_parse_log_group_home_dirs();
  335. if (ret == FALSE) {
  336.   DBUG_RETURN(TRUE);
  337. }
  338. srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
  339. srv_n_log_files = (ulint) innobase_log_files_in_group;
  340. srv_log_file_size = (ulint) innobase_log_file_size;
  341. srv_log_archive_on = (ulint) innobase_log_archive;
  342. srv_log_buffer_size = (ulint) innobase_log_buffer_size;
  343. srv_flush_log_at_trx_commit = (ulint) innobase_flush_log_at_trx_commit;
  344. srv_use_native_aio = 0;
  345. srv_pool_size = (ulint) innobase_buffer_pool_size;
  346. srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
  347. srv_n_file_io_threads = (ulint) innobase_file_io_threads;
  348. srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout;
  349. err = innobase_start_or_create_for_mysql();
  350. if (err != DB_SUCCESS) {
  351.   DBUG_RETURN(1);
  352. }
  353. (void) hash_init(&innobase_open_tables,32,0,0,
  354.  (hash_get_key) innobase_get_key,0,0);
  355. pthread_mutex_init(&innobase_mutex,NULL);
  356.    DBUG_RETURN(0);
  357. }
  358. /***********************************************************************
  359. Closes an Innobase database. */
  360. bool
  361. innobase_end(void)
  362. /*==============*/
  363. /* out: TRUE if error */
  364. {
  365. int err;
  366. DBUG_ENTER("innobase_end");
  367. err = innobase_shutdown_for_mysql();
  368. hash_free(&innobase_open_tables);
  369. if (err != DB_SUCCESS) {
  370.   DBUG_RETURN(1);
  371. }
  372.    DBUG_RETURN(0);
  373. }
  374. /********************************************************************
  375. Flushes Innobase logs to disk and makes a checkpoint. Really, a commit
  376. flushes logs, and the name of this function should be innobase_checkpoint. */
  377. bool
  378. innobase_flush_logs(void)
  379. /*=====================*/
  380. /* out: TRUE if error */
  381. {
  382.    bool  result = 0;
  383.    DBUG_ENTER("innobase_flush_logs");
  384. log_make_checkpoint_at(ut_dulint_max, TRUE);
  385.    DBUG_RETURN(result);
  386. }
  387. /*************************************************************************
  388. Gets the free space in an Innobase database: returned in units of kB. */
  389. uint
  390. innobase_get_free_space(void)
  391. /*=========================*/
  392. /* out: free space in kB */
  393. {
  394. return((uint) fsp_get_available_space_in_free_extents(0));
  395. }
  396. /*********************************************************************
  397. Commits a transaction in an Innobase database. */
  398. int
  399. innobase_commit(
  400. /*============*/
  401. /* out: 0 or error number */
  402. THD* thd, /* in: MySQL thread handle of the user for whom
  403. the transaction should be committed */
  404. void* trx_handle)/* in: Innobase trx handle or NULL: NULL means
  405. that the current SQL statement ended, and we should
  406. mark the start of a new statement with a savepoint */
  407. {
  408. int error = 0;
  409. trx_t* trx;
  410.    DBUG_ENTER("innobase_commit");
  411.    DBUG_PRINT("trans", ("ending transaction"));
  412. trx = check_trx_exists(thd);
  413. if (trx_handle) {
  414. trx_commit_for_mysql(trx);
  415. } else {
  416. trx_mark_sql_stat_end(trx);
  417. }
  418. #ifndef DBUG_OFF
  419. if (error) {
  420.      DBUG_PRINT("error", ("error: %d", error));
  421.      }
  422. #endif
  423. /* Tell Innobase server that there might be work for
  424. utility threads: */
  425. srv_active_wake_master_thread();
  426. DBUG_RETURN(error);
  427. }
  428. /*********************************************************************
  429. Rolls back a transaction in an Innobase database. */
  430. int
  431. innobase_rollback(
  432. /*==============*/
  433. /* out: 0 or error number */
  434. THD* thd, /* in: handle to the MySQL thread of the user
  435. whose transaction should be rolled back */
  436. void* trx_handle)/* in: Innobase trx handle or NULL: NULL means
  437. that the current SQL statement should be rolled
  438. back */
  439. {
  440. int error = 0;
  441. trx_t* trx;
  442. DBUG_ENTER("innobase_rollback");
  443. DBUG_PRINT("trans", ("aborting transaction"));
  444. trx = check_trx_exists(thd);
  445. if (trx_handle) {
  446. error = trx_rollback_for_mysql(trx);
  447. } else {
  448. error = trx_rollback_last_sql_stat_for_mysql(trx);
  449. }
  450. DBUG_RETURN(convert_error_code_to_mysql(error));
  451. }
  452. /*********************************************************************
  453. Frees a possible Innobase trx object associated with the current
  454. THD. */
  455. int
  456. innobase_close_connection(
  457. /*======================*/
  458. /* out: 0 or error number */
  459. THD* thd) /* in: handle to the MySQL thread of the user
  460. whose transaction should be rolled back */
  461. {
  462. if (NULL != thd->transaction.all.innobase_tid) {
  463. trx_free_for_mysql((trx_t*)
  464. (thd->transaction.all.innobase_tid));
  465. }
  466. return(0);
  467. }
  468. /**********************************************************************
  469. Prints an error message. */
  470. static
  471. void
  472. innobase_print_error(
  473. /*=================*/
  474. const char* db_errpfx, /* in: error prefix text */
  475. char* buffer) /* in: error text */
  476. {
  477.    sql_print_error("%s:  %s", db_errpfx, buffer);
  478. }
  479. /*****************************************************************************
  480. ** Innobase database tables
  481. *****************************************************************************/
  482. /********************************************************************
  483. This function is not relevant since we store the tables and indexes
  484. into our own tablespace, not as files, whose extension this function would
  485. give. */
  486. const char**
  487. ha_innobase::bas_ext() const
  488. /*========================*/
  489. /* out: file extension strings, currently not
  490. used */
  491. {
  492. static const char* ext[] = {".not_used", NullS};
  493. return(ext);
  494. }
  495. /*********************************************************************
  496. Normalizes a table name string. A normalized name consists of the
  497. database name catenated to '/' and table name. An example:
  498. test/mytable. */
  499. static
  500. void
  501. normalize_table_name(
  502. /*=================*/
  503. char* norm_name, /* out: normalized name as a
  504. null-terminated string */
  505. const char* name) /* in: table name string */
  506. {
  507. char* name_ptr;
  508. char* db_ptr;
  509. char* ptr;
  510. /* Scan name from the end */
  511. ptr = strend(name)-1;
  512. while (ptr >= name && *ptr != '\' && *ptr != '/') {
  513. ptr--;
  514. }
  515. name_ptr = ptr + 1;
  516. dbug_assert(ptr > name);
  517. ptr--;
  518. while (ptr >= name && *ptr != '\' && *ptr != '/') {
  519. ptr--;
  520. }
  521. db_ptr = ptr + 1;
  522. memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
  523. norm_name[name_ptr - db_ptr - 1] = '/';
  524. }
  525. /*********************************************************************
  526. Creates and opens a handle to a table which already exists in an Innnobase
  527. database. */
  528. int
  529. ha_innobase::open(
  530. /*==============*/
  531. /* out: 1 if error, 0 if success */
  532. const char* name, /* in: table name */
  533. int  mode, /* in: not used */
  534. uint  test_if_locked) /* in: not used */
  535. {
  536. dict_table_t* ib_table;
  537.    int  error = 0;
  538.    uint buff_len;
  539.    char norm_name[1000];
  540. DBUG_ENTER("ha_innobase::open");
  541. UT_NOT_USED(mode);
  542. UT_NOT_USED(test_if_locked);
  543. normalize_table_name(norm_name, name);
  544. user_thd = NULL;
  545. if (!(share=get_share(name)))
  546.   DBUG_RETURN(1);
  547. /* Create buffers for packing the fields of a record. Why
  548. table->reclength did not work here? Obviously, because char
  549. fields when packed actually became 1 byte longer, when we also
  550. stored the string length as the first byte. */
  551. buff_len = table->reclength + table->max_key_length
  552. + MAX_REF_PARTS * 3;
  553. if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME),
  554.      &upd_buff, buff_len,
  555.      &key_val_buff, buff_len,
  556.      NullS)) {
  557.    free_share(share);
  558.    DBUG_RETURN(1);
  559.    }
  560.    /* MySQL allocates the buffer for ref */
  561.    ref_length = buff_len;
  562. /* Get pointer to a table object in Innobase dictionary cache */
  563.   if (NULL == (ib_table = dict_table_get(norm_name, NULL))) {
  564.         free_share(share);
  565.      my_free((char*) upd_buff, MYF(0));
  566.      my_errno = ENOENT;
  567.      DBUG_RETURN(1);
  568.    }
  569. innobase_prebuilt = row_create_prebuilt(ib_table);
  570. ((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len = table->reclength;
  571.    primary_key = MAX_KEY;
  572.    if (!row_table_got_default_clust_index(ib_table)) {
  573. /* If we automatically created the clustered index,
  574. then MySQL does not know about it and it must not be aware
  575. of the index used on scan, to avoid checking if we update
  576. the column of the index. The column is the row id in
  577. the automatical case, and it will not be updated. */
  578. ((row_prebuilt_t*)innobase_prebuilt)
  579. ->clust_index_was_generated = FALSE;
  580. primary_key = 0;
  581. key_used_on_scan = 0;
  582. } else {
  583. ((row_prebuilt_t*)innobase_prebuilt)
  584. ->clust_index_was_generated = TRUE;
  585. dbug_assert(key_used_on_scan == MAX_KEY);
  586. }
  587.   /* Init table lock structure */
  588. thr_lock_data_init(&share->lock,&lock,(void*) 0);
  589.    info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
  590.    DBUG_RETURN(0);
  591. }
  592. /*********************************************************************
  593. Does nothing. */
  594. void
  595. ha_innobase::initialize(void)
  596. /*=========================*/
  597. {
  598. }
  599. /**********************************************************************
  600. Closes a handle to an Innobase table. */
  601. int
  602. ha_innobase::close(void)
  603. /*====================*/
  604. /* out: error number */
  605. {
  606.    DBUG_ENTER("ha_innobase::close");
  607. row_prebuilt_free((row_prebuilt_t*) innobase_prebuilt);
  608.      my_free((char*) upd_buff, MYF(0));
  609.         free_share(share);
  610. /* Tell Innobase server that there might be work for
  611. utility threads: */
  612. srv_active_wake_master_thread();
  613.    DBUG_RETURN(0);
  614. }
  615. /* The following accessor functions should really be inside MySQL code! */
  616. /******************************************************************
  617. Gets field offset for a field in a table. */
  618. inline
  619. uint
  620. get_field_offset(
  621. /*=============*/
  622. /* out: offset */
  623. TABLE* table, /* in: MySQL table object */
  624. Field* field) /* in: MySQL field object */
  625. {
  626. return((uint) (field->ptr - (char*) table->record[0]));
  627. }
  628. /******************************************************************
  629. Checks if a field in a record is SQL NULL. Uses the record format
  630. information in table to track the null bit in record. */
  631. inline
  632. uint
  633. field_in_record_is_null(
  634. /*====================*/
  635. /* out: 1 if NULL, 0 otherwise */
  636. TABLE* table, /* in: MySQL table object */
  637. Field* field, /* in: MySQL field object */
  638. char* record) /* in: a row in MySQL format */
  639. {
  640. int null_offset;
  641. if (!field->null_ptr) {
  642. return(0);
  643. }
  644. null_offset = (uint) ((char*) field->null_ptr
  645. - (char*) table->record[0]);
  646. if (record[null_offset] & field->null_bit) {
  647. return(1);
  648. }
  649. return(0);
  650. }
  651. /******************************************************************
  652. Sets a field in a record to SQL NULL. Uses the record format
  653. information in table to track the null bit in record. */
  654. inline
  655. void
  656. set_field_in_record_to_null(
  657. /*========================*/
  658. TABLE* table, /* in: MySQL table object */
  659. Field* field, /* in: MySQL field object */
  660. char* record) /* in: a row in MySQL format */
  661. {
  662. int null_offset;
  663. null_offset = (uint) ((char*) field->null_ptr
  664. - (char*) table->record[0]);
  665. record[null_offset] = record[null_offset] | field->null_bit;
  666. }
  667. /******************************************************************
  668. Resets SQL NULL bits in a record to zero. */
  669. inline
  670. void
  671. reset_null_bits(
  672. /*============*/
  673. TABLE* table, /* in: MySQL table object */
  674. char* record) /* in: a row in MySQL format */
  675. {
  676. bzero(record, table->null_bytes);
  677. }
  678. extern "C" {
  679. /*****************************************************************
  680. Innobase uses this function is to compare two data fields for which the
  681. data type is such that we must use MySQL code to compare them. NOTE that the
  682. prototype of this function is in rem0cmp.c in Innobase source code!
  683. If you change this function, remember to update the prototype there! */
  684. int
  685. innobase_mysql_cmp(
  686. /*===============*/
  687. /* out: 1, 0, -1, if a is greater,
  688. equal, less than b, respectively */
  689. int mysql_type, /* in: MySQL type */
  690. unsigned char* a, /* in: data field */
  691. unsigned int a_length, /* in: data field length,
  692. not UNIV_SQL_NULL */
  693. unsigned char* b, /* in: data field */
  694. unsigned int b_length) /* in: data field length,
  695. not UNIV_SQL_NULL */
  696. {
  697. enum_field_types mysql_tp;
  698. dbug_assert(a_length != UNIV_SQL_NULL);
  699. dbug_assert(b_length != UNIV_SQL_NULL);
  700. mysql_tp = (enum_field_types) mysql_type;
  701. switch (mysql_tp) {
  702. case FIELD_TYPE_STRING:
  703. case FIELD_TYPE_VAR_STRING:
  704.    return(my_sortncmp((const char*) a, a_length,
  705. (const char*) b, b_length));
  706. default:
  707. assert(0);
  708. }
  709. return(0);
  710. }
  711. }
  712. /******************************************************************
  713. Converts a MySQL type to an Innobase type. */
  714. inline
  715. ulint
  716. get_innobase_type_from_mysql_type(
  717. /*==============================*/
  718. /* out: DATA_BINARY, DATA_VARCHAR, ... */
  719. Field* field) /* in: MySQL field */
  720. {
  721. /* The following asserts check that MySQL type code fits in
  722. 8 bits: this is used in ibuf and also when DATA_NOT_NULL is
  723. ORed to the type */
  724. dbug_assert((ulint)FIELD_TYPE_STRING < 256);
  725. dbug_assert((ulint)FIELD_TYPE_VAR_STRING < 256);
  726. dbug_assert((ulint)FIELD_TYPE_DOUBLE < 256);
  727. dbug_assert((ulint)FIELD_TYPE_FLOAT < 256);
  728. dbug_assert((ulint)FIELD_TYPE_DECIMAL < 256);
  729. switch (field->type()) {
  730. case FIELD_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) {
  731. return(DATA_BINARY);
  732. } else if (strcmp(
  733.    default_charset_info->name,
  734. "latin1") == 0) {
  735. return(DATA_VARCHAR);
  736. } else {
  737. return(DATA_VARMYSQL);
  738. }
  739. case FIELD_TYPE_STRING: if (field->flags & BINARY_FLAG) {
  740. return(DATA_FIXBINARY);
  741. } else if (strcmp(
  742.    default_charset_info->name,
  743. "latin1") == 0) {
  744. return(DATA_CHAR);
  745. } else {
  746. return(DATA_MYSQL);
  747. }
  748. case FIELD_TYPE_LONG:
  749. case FIELD_TYPE_LONGLONG:
  750. case FIELD_TYPE_TINY:
  751. case FIELD_TYPE_SHORT:
  752. case FIELD_TYPE_INT24:
  753. case FIELD_TYPE_DATE:
  754. case FIELD_TYPE_DATETIME:
  755. case FIELD_TYPE_YEAR:
  756. case FIELD_TYPE_NEWDATE:
  757. case FIELD_TYPE_ENUM:
  758. case FIELD_TYPE_SET:
  759. case FIELD_TYPE_TIME:
  760. case FIELD_TYPE_TIMESTAMP:
  761. return(DATA_INT);
  762. case FIELD_TYPE_FLOAT:
  763. return(DATA_FLOAT);
  764. case FIELD_TYPE_DOUBLE:
  765. return(DATA_DOUBLE);
  766. case FIELD_TYPE_DECIMAL:
  767. return(DATA_DECIMAL);
  768. case FIELD_TYPE_TINY_BLOB:
  769. case FIELD_TYPE_MEDIUM_BLOB:
  770. case FIELD_TYPE_BLOB:
  771. case FIELD_TYPE_LONG_BLOB:
  772. return(DATA_BLOB);
  773. default:
  774. assert(0);
  775. }
  776. return(0);
  777. }
  778. /***********************************************************************
  779. Stores a key value for a row to a buffer. */
  780. uint
  781. ha_innobase::store_key_val_for_row(
  782. /*===============================*/
  783. /* out: key value length as stored in buff */
  784. uint  keynr, /* in: key number */
  785. char* buff, /* in/out: buffer for the key value (in MySQL
  786. format) */
  787. const mysql_byte* record)/* in: row in MySQL format */
  788. {
  789. KEY* key_info  = table->key_info + keynr;
  790.    KEY_PART_INFO* key_part = key_info->key_part;
  791.    KEY_PART_INFO* end = key_part + key_info->key_parts;
  792. char* buff_start = buff;
  793.    DBUG_ENTER("store_key_val_for_row");
  794.    for (; key_part != end; key_part++) {
  795.      if (key_part->null_bit) {
  796.        /* Store 0 if the key part is a NULL part */
  797.        if (record[key_part->null_offset]
  798. & key_part->null_bit) {
  799. *buff++ = 1;
  800. continue;
  801.        }
  802.        *buff++ = 0;
  803.      }
  804. memcpy(buff, record + key_part->offset, key_part->length);
  805. buff += key_part->length;
  806.    }
  807. DBUG_RETURN(buff - buff_start);
  808. }
  809. /******************************************************************
  810. Builds a template to the prebuilt struct. */
  811. static
  812. void
  813. build_template(
  814. /*===========*/
  815. row_prebuilt_t* prebuilt, /* in: prebuilt struct */
  816. THD* thd, /* in: current user thread, used
  817. only if templ_type is
  818. ROW_MYSQL_REC_FIELDS */
  819. TABLE* table, /* in: MySQL table */
  820. ulint templ_type) /* in: ROW_MYSQL_WHOLE_ROW or
  821. ROW_MYSQL_REC_FIELDS */
  822. {
  823. dict_index_t* index;
  824. dict_index_t* clust_index;
  825. mysql_row_templ_t* templ;
  826. Field* field;
  827. ulint n_fields;
  828. ulint n_requested_fields = 0;
  829. ulint i;
  830. clust_index = dict_table_get_first_index_noninline(prebuilt->table);
  831. if (!prebuilt->in_update_remember_pos) {
  832. /* We are building a temporary table: fetch all columns */
  833. templ_type = ROW_MYSQL_WHOLE_ROW;
  834. }
  835. if (prebuilt->select_lock_type == LOCK_X) {
  836.   /* TODO: should fix the code in sql_update so that we could do
  837.      with fetching only the needed columns */
  838.         templ_type = ROW_MYSQL_WHOLE_ROW;
  839. }
  840. if (templ_type == ROW_MYSQL_REC_FIELDS) {
  841. if (prebuilt->select_lock_type != LOCK_NONE) {
  842. /* Let index be the clustered index */
  843. index = clust_index;
  844. } else {
  845. index = prebuilt->index;
  846. }
  847. } else {
  848. index = clust_index;
  849. }
  850. if (index == clust_index) {
  851. prebuilt->need_to_access_clustered = TRUE;
  852. } else {
  853. prebuilt->need_to_access_clustered = FALSE;
  854. /* Below we check column by column if we need to access
  855. the clustered index */
  856. }
  857. n_fields = (ulint)table->fields;
  858. if (!prebuilt->mysql_template) {
  859. prebuilt->mysql_template = (mysql_row_templ_t*)
  860. mem_alloc_noninline(
  861. n_fields * sizeof(mysql_row_templ_t));
  862. }
  863. prebuilt->template_type = templ_type;
  864. prebuilt->null_bitmap_len = table->null_bytes;
  865. prebuilt->templ_contains_blob = FALSE;
  866. for (i = 0; i < n_fields; i++) {
  867. templ = prebuilt->mysql_template + n_requested_fields;
  868. field = table->field[i];
  869. if (templ_type == ROW_MYSQL_REC_FIELDS
  870. && thd->query_id != field->query_id
  871. && thd->query_id != (field->query_id ^ MAX_ULONG_BIT)
  872. && thd->query_id !=
  873. (field->query_id ^ (MAX_ULONG_BIT >> 1))) {
  874. /* This field is not needed in the query, skip it */
  875. goto skip_field;
  876. }
  877. n_requested_fields++;
  878. templ->col_no = i;
  879. if (index == clust_index) {
  880. templ->rec_field_no = (index->table->cols + i)
  881. ->clust_pos;
  882. } else {
  883. templ->rec_field_no = dict_index_get_nth_col_pos(
  884. index, i);
  885. }
  886. if (templ->rec_field_no == ULINT_UNDEFINED) {
  887. prebuilt->need_to_access_clustered = TRUE;
  888. }
  889. if (field->null_ptr) {
  890. templ->mysql_null_byte_offset =
  891. (ulint) ((char*) field->null_ptr
  892. - (char*) table->record[0]);
  893. templ->mysql_null_bit_mask = (ulint) field->null_bit;
  894. } else {
  895. templ->mysql_null_bit_mask = 0;
  896. }
  897. templ->mysql_col_offset = (ulint)
  898. get_field_offset(table, field);
  899. templ->mysql_col_len = (ulint) field->pack_length();
  900. templ->type = get_innobase_type_from_mysql_type(field);
  901. templ->is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG);
  902. if (templ->type == DATA_BLOB) {
  903. prebuilt->templ_contains_blob = TRUE;
  904. }
  905. skip_field:
  906. ;
  907. }
  908. prebuilt->n_template = n_requested_fields;
  909. if (prebuilt->need_to_access_clustered) {
  910. /* Change rec_field_no's to correspond to the clustered index
  911. record */
  912. for (i = 0; i < n_requested_fields; i++) {
  913. templ = prebuilt->mysql_template + i;
  914. templ->rec_field_no =
  915.     (index->table->cols + templ->col_no)->clust_pos;
  916. }
  917. }
  918. if (templ_type == ROW_MYSQL_REC_FIELDS
  919. && prebuilt->select_lock_type != LOCK_NONE) {
  920. prebuilt->need_to_access_clustered = TRUE;
  921. }
  922. }
  923. /************************************************************************
  924. Stores a row in an Innobase database, to the table specified in this
  925. handle. */
  926. int
  927. ha_innobase::write_row(
  928. /*===================*/
  929. /* out: error code */
  930. mysql_byte*  record) /* in: a row in MySQL format */
  931. {
  932. row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
  933.    int  error;
  934.    DBUG_ENTER("ha_innobase::write_row");
  935.    statistic_increment(ha_write_count, &LOCK_status);
  936.    if (table->time_stamp) {
  937.      update_timestamp(record + table->time_stamp - 1);
  938.      }
  939.    if (table->next_number_field && record == table->record[0]) {
  940.         /* Set the 'in_update_remember_pos' flag to FALSE to
  941.         make sure all columns are fetched in the select done by
  942.         update_auto_increment */
  943.         prebuilt->in_update_remember_pos = FALSE;
  944.      update_auto_increment();
  945. /* We have to set sql_stat_start to TRUE because
  946. update_auto_increment has called a select, and
  947. has reset that flag; row_insert_for_mysql has to
  948. know to set the IX intention lock on the table, something
  949. it only does at the start of each statement */
  950. prebuilt->sql_stat_start = TRUE;
  951.      }
  952. if (prebuilt->mysql_template == NULL
  953. || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
  954. /* Build the template used in converting quickly between
  955. the two database formats */
  956. build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
  957. }
  958. error = row_insert_for_mysql((byte*) record, prebuilt);
  959. error = convert_error_code_to_mysql(error);
  960. /* Tell Innobase server that there might be work for
  961. utility threads: */
  962. innobase_active_small();
  963.    DBUG_RETURN(error);
  964. }
  965. /******************************************************************
  966. Converts field data for storage in an Innobase update vector. */
  967. inline
  968. mysql_byte*
  969. innobase_convert_and_store_changed_col(
  970. /*===================================*/
  971. /* out: pointer to the end of the converted
  972. data in the buffer */
  973. upd_field_t* ufield, /* in/out: field in the update vector */
  974. mysql_byte* buf, /* in: buffer we can use in conversion */
  975. mysql_byte* data, /* in: column data to store */
  976. ulint len, /* in: data len */
  977. ulint col_type,/* in: data type in Innobase type numbers */
  978. ulint is_unsigned)/* in: != 0 if an unsigned integer type */
  979. {
  980. uint i;
  981. if (len == UNIV_SQL_NULL) {
  982. data = NULL;
  983. } else if (col_type == DATA_VARCHAR || col_type == DATA_BINARY
  984.    || col_type == DATA_VARMYSQL) {
  985.         /* Remove trailing spaces */
  986.          while (len > 0 && data[len - 1] == ' ') {
  987.                 len--;
  988.         }
  989. } else if (col_type == DATA_INT) {
  990. /* Store integer data in Innobase in a big-endian
  991. format, sign bit negated, if signed */
  992. for (i = 0; i < len; i++) {
  993. buf[len - 1 - i] = data[i];
  994. }
  995. if (!is_unsigned) {
  996. buf[0] = buf[0] ^ 128;
  997. }
  998. data = buf;
  999. buf += len;
  1000. }
  1001. ufield->new_val.data = data;
  1002. ufield->new_val.len = len;
  1003. return(buf);
  1004. }
  1005. /**************************************************************************
  1006. Checks which fields have changed in a row and stores information
  1007. of them to an update vector. */
  1008. static
  1009. int
  1010. calc_row_difference(
  1011. /*================*/
  1012. /* out: error number or 0 */
  1013. upd_t* uvect, /* in/out: update vector */
  1014. mysql_byte*  old_row, /* in: old row in MySQL format */
  1015. mysql_byte*  new_row, /* in: new row in MySQL format */
  1016. struct st_table* table, /* in: table in MySQL data dictionary */
  1017. mysql_byte* upd_buff, /* in: buffer to use */
  1018. row_prebuilt_t* prebuilt, /* in: Innobase prebuilt struct */
  1019. THD* thd) /* in: user thread */
  1020. {
  1021. Field* field;
  1022. uint n_fields;
  1023. ulint o_len;
  1024. ulint n_len;
  1025. byte*         o_ptr;
  1026.         byte*         n_ptr;
  1027.         byte*         buf;
  1028. upd_field_t* ufield;
  1029. ulint col_type;
  1030. ulint is_unsigned;
  1031. ulint n_changed = 0;
  1032. uint i;
  1033. n_fields = table->fields;
  1034. /* We use upd_buff to convert changed fields */
  1035. buf = (byte*) upd_buff;
  1036. for (i = 0; i < n_fields; i++) {
  1037. field = table->field[i];
  1038. /* if (thd->query_id != field->query_id) { */
  1039. /* TODO: check that these fields cannot have
  1040. changed! */
  1041. /* goto skip_field;
  1042. }*/
  1043. o_ptr = (byte*) old_row + get_field_offset(table, field);
  1044. n_ptr = (byte*) new_row + get_field_offset(table, field);
  1045. o_len = field->pack_length();
  1046. n_len = field->pack_length();
  1047. col_type = get_innobase_type_from_mysql_type(field);
  1048. is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG);
  1049. switch (col_type) {
  1050. case DATA_BLOB:
  1051. o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
  1052. n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
  1053. break;
  1054. case DATA_VARCHAR:
  1055. case DATA_BINARY:
  1056. case DATA_VARMYSQL:
  1057. o_ptr = row_mysql_read_var_ref_noninline(&o_len, o_ptr);
  1058. n_ptr = row_mysql_read_var_ref_noninline(&n_len, n_ptr);
  1059. default:
  1060. ;
  1061. }
  1062. if (field->null_ptr) {
  1063. if (field_in_record_is_null(table, field,
  1064. (char*) old_row)) {
  1065. o_len = UNIV_SQL_NULL;
  1066. }
  1067. if (field_in_record_is_null(table, field,
  1068. (char*) new_row)) {
  1069. n_len = UNIV_SQL_NULL;
  1070. }
  1071. }
  1072. if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
  1073. 0 != memcmp(o_ptr, n_ptr, o_len))) {
  1074. /* The field has changed */
  1075. ufield = uvect->fields + n_changed;
  1076. buf = (byte*)
  1077.                           innobase_convert_and_store_changed_col(ufield,
  1078.   (mysql_byte*)buf,
  1079.   (mysql_byte*)n_ptr, n_len, col_type,
  1080. is_unsigned);
  1081. ufield->exp = NULL;
  1082. ufield->field_no =
  1083. (prebuilt->table->cols + i)->clust_pos;
  1084. n_changed++;
  1085. }
  1086. ;
  1087. }
  1088. uvect->n_fields = n_changed;
  1089. uvect->info_bits = 0;
  1090. return(0);
  1091. }
  1092. /**************************************************************************
  1093. Updates a row given as a parameter to a new value. Note that we are given
  1094. whole rows, not just the fields which are updated: this incurs some
  1095. overhead for CPU when we check which fields are actually updated.
  1096. TODO: currently Innobase does not prevent the 'Halloween problem':
  1097. in a searched update a single row can get updated several times
  1098. if its index columns are updated! */
  1099. int
  1100. ha_innobase::update_row(
  1101. /*====================*/
  1102. /* out: error number or 0 */
  1103. const mysql_byte*  old_row,/* in: old row in MySQL format */
  1104. mysql_byte*  new_row)/* in: new row in MySQL format */
  1105. {
  1106. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1107. upd_t* uvect;
  1108. int error = 0;
  1109. DBUG_ENTER("ha_innobase::update_row");
  1110. if (prebuilt->upd_node) {
  1111. uvect = prebuilt->upd_node->update;
  1112. } else {
  1113. uvect = row_get_prebuilt_update_vector(prebuilt);
  1114. }
  1115. /* Build an update vector from the modified fields in the rows
  1116. (uses upd_buff of the handle) */
  1117. calc_row_difference(uvect, (mysql_byte*) old_row, new_row, table,
  1118. upd_buff, prebuilt, user_thd);
  1119. /* This is not a delete */
  1120. prebuilt->upd_node->is_delete = FALSE;
  1121. if (!prebuilt->in_update_remember_pos) {
  1122. assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
  1123. }
  1124. error = row_update_for_mysql((byte*) old_row, prebuilt);
  1125. error = convert_error_code_to_mysql(error);
  1126. /* Tell Innobase server that there might be work for
  1127. utility threads: */
  1128. innobase_active_small();
  1129. DBUG_RETURN(error);
  1130. }
  1131. /**************************************************************************
  1132. Deletes a row given as the parameter. */
  1133. int
  1134. ha_innobase::delete_row(
  1135. /*====================*/
  1136. /* out: error number or 0 */
  1137. const mysql_byte* record) /* in: a row in MySQL format */
  1138. {
  1139. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1140. int error = 0;
  1141. DBUG_ENTER("ha_innobase::delete_row");
  1142. if (!prebuilt->upd_node) {
  1143. row_get_prebuilt_update_vector(prebuilt);
  1144. }
  1145. /* This is a delete */
  1146. prebuilt->upd_node->is_delete = TRUE;
  1147. prebuilt->in_update_remember_pos = TRUE;
  1148. error = row_update_for_mysql((byte*) record, prebuilt);
  1149. error = convert_error_code_to_mysql(error);
  1150. /* Tell the Innobase server that there might be work for
  1151. utility threads: */
  1152. innobase_active_small();
  1153. DBUG_RETURN(error);
  1154. }
  1155. /**********************************************************************
  1156. Initializes a handle to use an index. */
  1157. int
  1158. ha_innobase::index_init(
  1159. /*====================*/
  1160. /* out: 0 or error number */
  1161. uint  keynr) /* in: key (index) number */
  1162. {
  1163. int  error = 0;
  1164.    DBUG_ENTER("index_init");
  1165. change_active_index(keynr);
  1166.    DBUG_RETURN(error);
  1167. }
  1168. /**********************************************************************
  1169. ?????????????????????????????????? */
  1170. int
  1171. ha_innobase::index_end(void)
  1172. /*========================*/
  1173. {
  1174. int  error = 0;
  1175.    DBUG_ENTER("index_end");
  1176.    DBUG_RETURN(error);
  1177. }
  1178. /*************************************************************************
  1179. Converts a search mode flag understood by MySQL to a flag understood
  1180. by Innobase. */
  1181. inline
  1182. ulint
  1183. convert_search_mode_to_innobase(
  1184. /*============================*/
  1185. enum ha_rkey_function find_flag)
  1186. {
  1187. switch (find_flag) {
  1188.    case HA_READ_KEY_EXACT: return(PAGE_CUR_GE);
  1189.    /* the above does not require the index to be UNIQUE */
  1190.    case HA_READ_KEY_OR_NEXT: return(PAGE_CUR_GE);
  1191. case HA_READ_KEY_OR_PREV: return(PAGE_CUR_LE);
  1192. case HA_READ_AFTER_KEY: return(PAGE_CUR_G);
  1193. case HA_READ_BEFORE_KEY: return(PAGE_CUR_L);
  1194. case HA_READ_PREFIX: return(PAGE_CUR_GE);
  1195. case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE);
  1196. /* the above PREFIX flags mean that the last
  1197. field in the key value may just be a prefix
  1198. of the complete fixed length field */
  1199. default: assert(0);
  1200. }
  1201. return(0);
  1202. }
  1203. /**************************************************************************
  1204. Positions an index cursor to the index specified in the handle. Fetches the
  1205. row if any. */
  1206. int
  1207. ha_innobase::index_read(
  1208. /*====================*/
  1209. /* out: 0, HA_ERR_KEY_NOT_FOUND,
  1210. or error number */
  1211. mysql_byte* buf, /* in/out: buffer for the returned
  1212. row */
  1213. const mysql_byte*  key_ptr,/* in: key value; if this is NULL
  1214. we position the cursor at the
  1215. start or end of index */
  1216. uint key_len,/* in: key value length */
  1217. enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
  1218. {
  1219. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1220. ulint mode;
  1221. dict_index_t* index;
  1222. ulint match_mode  = 0;
  1223. int  error;
  1224. ulint ret;
  1225.    DBUG_ENTER("index_read");
  1226.    statistic_increment(ha_read_key_count, &LOCK_status);
  1227. index = prebuilt->index;
  1228. /* Note that if the select is used for an update, we always
  1229. fetch the clustered index record: therefore the index for which the
  1230. template is built is not necessarily prebuilt->index, but can also
  1231. be the clustered index */
  1232. if (prebuilt->sql_stat_start) {
  1233. build_template(prebuilt, user_thd, table,
  1234. ROW_MYSQL_REC_FIELDS);
  1235. }
  1236. if (key_ptr) {
  1237. row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple,
  1238. (byte*) key_val_buff,
  1239. index,
  1240. (byte*) key_ptr,
  1241. (ulint) key_len);
  1242. } else {
  1243. /* We position the cursor to the last or the first entry
  1244. in the index */
  1245.   dtuple_set_n_fields(prebuilt->search_tuple, 0);
  1246. }
  1247. mode = convert_search_mode_to_innobase(find_flag);
  1248. match_mode = 0;
  1249. if (find_flag == HA_READ_KEY_EXACT) {
  1250. match_mode = ROW_SEL_EXACT;
  1251. } else if (find_flag == HA_READ_PREFIX
  1252. || find_flag == HA_READ_PREFIX_LAST) {
  1253. match_mode = ROW_SEL_EXACT_PREFIX;
  1254. }
  1255. last_match_mode = match_mode;
  1256. ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0);
  1257. if (ret == DB_SUCCESS) {
  1258. error = 0;
  1259. table->status = 0;
  1260. } else if (ret == DB_RECORD_NOT_FOUND) {
  1261. error = HA_ERR_KEY_NOT_FOUND;
  1262. table->status = STATUS_NOT_FOUND;
  1263. } else if (ret == DB_END_OF_INDEX) {
  1264. error = HA_ERR_KEY_NOT_FOUND;
  1265. table->status = STATUS_NOT_FOUND;
  1266. } else {
  1267. error = convert_error_code_to_mysql(ret);
  1268. table->status = STATUS_NOT_FOUND;
  1269. }
  1270. DBUG_RETURN(error);
  1271. }
  1272. /************************************************************************
  1273. Changes the active index of a handle. */
  1274. int
  1275. ha_innobase::change_active_index(
  1276. /*=============================*/
  1277. /* out: 0 or error code */
  1278. uint  keynr) /* in: use this index; MAX_KEY means always clustered
  1279. index, even if it was internally generated by
  1280. Innobase */
  1281. {
  1282. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1283. KEY* key;
  1284.    statistic_increment(ha_read_key_count, &LOCK_status);
  1285.    DBUG_ENTER("index_read_idx");
  1286. active_index = keynr;
  1287. if (keynr != MAX_KEY && table->keys > 0) {
  1288. key = table->key_info + active_index;
  1289. prebuilt->index = dict_table_get_index_noninline(
  1290. prebuilt->table, key->name);
  1291. } else {
  1292. prebuilt->index = dict_table_get_first_index_noninline(
  1293. prebuilt->table);
  1294. }
  1295. dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
  1296.   dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
  1297. prebuilt->index->n_fields);
  1298. assert(prebuilt->index);
  1299. /* Maybe MySQL changes the active index for a handle also
  1300. during some queries, we do not know: then it is safest to build
  1301. the template such that all columns will be fetched */
  1302. build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW);
  1303. return(0);
  1304. }
  1305. /**************************************************************************
  1306. Positions an index cursor to the index specified in keynr. Fetches the
  1307. row if any. */
  1308. /* ??? This is only used to read whole keys ??? */
  1309. int
  1310. ha_innobase::index_read_idx(
  1311. /*========================*/
  1312. /* out: error number or 0 */
  1313. mysql_byte* buf, /* in/out: buffer for the returned
  1314. row */
  1315. uint  keynr, /* in: use this index */
  1316. const mysql_byte* key, /* in: key value; if this is NULL
  1317. we position the cursor at the
  1318. start or end of index */
  1319. uint key_len, /* in: key value length */
  1320. enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
  1321. {
  1322. change_active_index(keynr);
  1323. return(index_read(buf, key, key_len, find_flag));
  1324. }
  1325. /***************************************************************************
  1326. Reads the next or previous row from a cursor, which must have previously been
  1327. positioned using index_read. */
  1328. int
  1329. ha_innobase::general_fetch(
  1330. /*=======================*/
  1331. /* out: 0, HA_ERR_END_OF_FILE, or error
  1332. number */
  1333. mysql_byte*  buf, /* in/out: buffer for next row in MySQL
  1334. format */
  1335. uint  direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */
  1336. uint match_mode) /* in: 0, ROW_SEL_EXACT, or
  1337. ROW_SEL_EXACT_PREFIX */
  1338. {
  1339. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1340. ulint ret;
  1341. int error = 0;
  1342. DBUG_ENTER("general_fetch");
  1343. ret = row_search_for_mysql((byte*)buf, 0, prebuilt,
  1344.                        match_mode, direction);
  1345. if (ret == DB_SUCCESS) {
  1346. error = 0;
  1347. table->status = 0;
  1348. } else if (ret == DB_RECORD_NOT_FOUND) {
  1349. error = HA_ERR_END_OF_FILE;
  1350. table->status = STATUS_NOT_FOUND;
  1351. } else if (ret == DB_END_OF_INDEX) {
  1352. error = HA_ERR_END_OF_FILE;
  1353. table->status = STATUS_NOT_FOUND;
  1354. } else {
  1355. error = convert_error_code_to_mysql(ret);
  1356. table->status = STATUS_NOT_FOUND;
  1357. }
  1358. DBUG_RETURN(error);
  1359. }
  1360. /***************************************************************************
  1361. Reads the next row from a cursor, which must have previously been
  1362. positioned using index_read. */
  1363. int
  1364. ha_innobase::index_next(
  1365. /*====================*/
  1366. /* out: 0, HA_ERR_END_OF_FILE, or error
  1367. number */
  1368. mysql_byte*  buf) /* in/out: buffer for next row in MySQL
  1369. format */
  1370. {
  1371.    statistic_increment(ha_read_next_count, &LOCK_status);
  1372. return(general_fetch(buf, ROW_SEL_NEXT, 0));
  1373. }
  1374. /***********************************************************************
  1375. Reads the next row matching to the key value given as the parameter. */
  1376. int
  1377. ha_innobase::index_next_same(
  1378. /*=========================*/
  1379. /* out: 0, HA_ERR_END_OF_FILE, or error
  1380. number */
  1381. mysql_byte*  buf, /* in/out: buffer for the row */
  1382. const mysql_byte* key, /* in: key value */
  1383. uint  keylen) /* in: key value length */
  1384. {
  1385.    statistic_increment(ha_read_next_count, &LOCK_status);
  1386. return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
  1387. }
  1388. /***************************************************************************
  1389. Reads the previous row from a cursor, which must have previously been
  1390. positioned using index_read. */
  1391. int
  1392. ha_innobase::index_prev(
  1393. /*====================*/
  1394. /* out: 0, HA_ERR_END_OF_FILE, or error
  1395. number */
  1396. mysql_byte*  buf) /* in/out: buffer for previous row in MySQL
  1397. format */
  1398. {
  1399. return(general_fetch(buf, ROW_SEL_PREV, 0));
  1400. }
  1401. /************************************************************************
  1402. Positions a cursor on the first record in an index and reads the
  1403. corresponding row to buf. */
  1404. int
  1405. ha_innobase::index_first(
  1406. /*=====================*/
  1407. /* out: 0, HA_ERR_KEY_NOT_FOUND,
  1408. or error code */
  1409. mysql_byte* buf) /* in/out: buffer for the row */
  1410. {
  1411. int error;
  1412.    DBUG_ENTER("index_first");
  1413.    statistic_increment(ha_read_first_count, &LOCK_status);
  1414.    error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
  1415.    DBUG_RETURN(error);
  1416. }
  1417. /************************************************************************
  1418. Positions a cursor on the last record in an index and reads the
  1419. corresponding row to buf. */
  1420. int
  1421. ha_innobase::index_last(
  1422. /*====================*/
  1423. /* out: 0, HA_ERR_END_OF_FILE, or error code */
  1424. mysql_byte* buf) /* in/out: buffer for the row */
  1425. {
  1426. int error;
  1427.    DBUG_ENTER("index_first");
  1428.    statistic_increment(ha_read_last_count, &LOCK_status);
  1429.    error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
  1430.    /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
  1431.    if (error == HA_ERR_KEY_NOT_FOUND) {
  1432.    error = HA_ERR_END_OF_FILE;
  1433.    }
  1434.    DBUG_RETURN(error);
  1435. }
  1436. /********************************************************************
  1437. Initialize a table scan. */
  1438. int
  1439. ha_innobase::rnd_init(
  1440. /*==================*/
  1441. /* out: 0 or error number */
  1442. bool scan) /* in: ???????? */
  1443. {
  1444. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1445. if (prebuilt->clust_index_was_generated) {
  1446. change_active_index(MAX_KEY);
  1447. } else {
  1448. change_active_index(primary_key);
  1449. }
  1450.    start_of_scan = 1;
  1451.   return(0);
  1452. }
  1453. /*********************************************************************
  1454. Ends a table scan ???????????????? */
  1455. int
  1456. ha_innobase::rnd_end(void)
  1457. /*======================*/
  1458. /* out: 0 or error number */
  1459. {
  1460.    return(index_end());
  1461. }
  1462. /*********************************************************************
  1463. Reads the next row in a table scan (also used to read the FIRST row
  1464. in a table scan). */
  1465. int
  1466. ha_innobase::rnd_next(
  1467. /*==================*/
  1468. /* out: 0, HA_ERR_END_OF_FILE, or error number */
  1469. mysql_byte* buf)/* in/out: returns the row in this buffer,
  1470. in MySQL format */
  1471. {
  1472. int error;
  1473.    DBUG_ENTER("rnd_next");
  1474.    statistic_increment(ha_read_rnd_next_count, &LOCK_status);
  1475.    if (start_of_scan) {
  1476. error = index_first(buf);
  1477. if (error == HA_ERR_KEY_NOT_FOUND) {
  1478. error = HA_ERR_END_OF_FILE;
  1479. }
  1480. start_of_scan = 0;
  1481. } else {
  1482. error = general_fetch(buf, ROW_SEL_NEXT, 0);
  1483. }
  1484.    DBUG_RETURN(error);
  1485. }
  1486. /**************************************************************************
  1487. Fetches a row from the table based on a reference. TODO: currently we use
  1488. 'ref_stored_len' of the handle as the key length. This may change. */
  1489. int
  1490. ha_innobase::rnd_pos(
  1491. /*=================*/
  1492. /* out: 0, HA_ERR_KEY_NOT_FOUND,
  1493. or error code */
  1494. mysql_byte*  buf, /* in/out: buffer for the row */
  1495. mysql_byte* pos) /* in: primary key value in MySQL format */
  1496. {
  1497. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1498. int error;
  1499. uint keynr = active_index;
  1500. DBUG_ENTER("rnd_pos");
  1501. statistic_increment(ha_read_rnd_count, &LOCK_status);
  1502. if (prebuilt->clust_index_was_generated) {
  1503. /* No primary key was defined for the table and we
  1504. generated the clustered index from the row id: the
  1505. row reference is the row id, not any key value
  1506. that MySQL knows */
  1507. change_active_index(MAX_KEY);
  1508. } else {
  1509. change_active_index(primary_key);
  1510. }
  1511. error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT);
  1512. change_active_index(keynr);
  1513.    DBUG_RETURN(error);
  1514. }
  1515. /*************************************************************************
  1516. Stores a reference to the current row to 'ref' field of the handle. Note
  1517. that the function parameter is illogical: we must assume that 'record'
  1518. is the current 'position' of the handle, because if row ref is actually
  1519. the row id internally generated in Innobase, then 'record' does not contain
  1520. it. We just guess that the row id must be for the record where the handle
  1521. was positioned the last time. */
  1522. void
  1523. ha_innobase::position(
  1524. /*==================*/
  1525. const mysql_byte* record) /* in: row in MySQL format */
  1526. {
  1527. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1528. uint len;
  1529. if (prebuilt->clust_index_was_generated) {
  1530. /* No primary key was defined for the table and we
  1531. generated the clustered index from row id: the
  1532. row reference will be the row id, not any key value
  1533. that MySQL knows */
  1534. len = DATA_ROW_ID_LEN;
  1535. memcpy(ref, prebuilt->row_id, len);
  1536. } else {
  1537. len = store_key_val_for_row(primary_key, (char*) ref, record);
  1538. }
  1539. dbug_assert(len <= ref_length);
  1540. ref_stored_len = len;
  1541. }
  1542. /***********************************************************************
  1543. Tells something additional to the handler about how to do things. */
  1544. int
  1545. ha_innobase::extra(
  1546. /*===============*/
  1547.    /* out: 0 or error number */
  1548. enum ha_extra_function operation)
  1549.                            /* in: HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE */
  1550. {
  1551. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1552. switch (operation) {
  1553.         case HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE:
  1554. prebuilt->in_update_remember_pos = FALSE;
  1555. break;
  1556. default: /* Do nothing */
  1557. ;
  1558. }
  1559. return(0);
  1560. }
  1561. int ha_innobase::reset(void)
  1562. {
  1563.    return(0);
  1564. }
  1565. /**********************************************************************
  1566. As MySQL will execute an external lock for every new table it uses when it
  1567. starts to process an SQL statement, we can use this function to store the
  1568. pointer to the THD in the handle. We will also use this function to communicate
  1569. to Innobase that a new SQL statement has started and that we must store a
  1570. savepoint to our transaction handle, so that we are able to roll back
  1571. the SQL statement in case of an error. */
  1572. int
  1573. ha_innobase::external_lock(
  1574. /*=======================*/
  1575. THD* thd, /* in: handle to the user thread */
  1576. int  lock_type) /* in: lock type */
  1577. {
  1578. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1579. int  error = 0;
  1580. trx_t* trx;
  1581.    DBUG_ENTER("ha_innobase::external_lock");
  1582. update_thd(thd);
  1583. trx = prebuilt->trx;
  1584. prebuilt->sql_stat_start = TRUE;
  1585. prebuilt->in_update_remember_pos = TRUE;
  1586. if (lock_type == F_WRLCK) {
  1587. /* If this is a SELECT, then it is in UPDATE TABLE ...
  1588. or SELECT ... FOR UPDATE */
  1589. prebuilt->select_lock_type = LOCK_X;
  1590. }
  1591. if (lock_type != F_UNLCK) {
  1592. if (trx->n_mysql_tables_in_use == 0) {
  1593. trx_mark_sql_stat_end(trx);
  1594. }
  1595. trx->n_mysql_tables_in_use++;
  1596. } else {
  1597. trx->n_mysql_tables_in_use--;
  1598. if (trx->n_mysql_tables_in_use == 0 &&
  1599.     !(thd->options
  1600.       & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
  1601.   innobase_commit(thd, trx);
  1602. }
  1603. }
  1604. DBUG_RETURN(error);
  1605. }
  1606. /*********************************************************************
  1607. Creates a table definition to an Innobase database. */
  1608. static
  1609. int
  1610. create_table_def(
  1611. /*=============*/
  1612. trx_t* trx, /* in: Innobase transaction handle */
  1613. TABLE* form, /* in: information on table
  1614. columns and indexes */
  1615. const char* table_name) /* in: table name */
  1616. {
  1617. Field* field;
  1618. dict_table_t* table;
  1619. ulint n_cols;
  1620.    int  error;
  1621.    ulint col_type;
  1622.    ulint nulls_allowed;
  1623. ulint unsigned_type;
  1624.    ulint i;
  1625.    DBUG_ENTER("create_table_def");
  1626.    DBUG_PRINT("enter", ("table_name: %s", table_name));
  1627. n_cols = form->fields;
  1628. /* The '0' below specifies that everything is currently
  1629. created in tablespace 0 */
  1630. table = dict_mem_table_create((char*) table_name, 0, n_cols);
  1631. for (i = 0; i < n_cols; i++) {
  1632. field = form->field[i];
  1633. col_type = get_innobase_type_from_mysql_type(field);
  1634. if (field->null_ptr) {
  1635. nulls_allowed = 0;
  1636. } else {
  1637. nulls_allowed = DATA_NOT_NULL;
  1638. }
  1639. if (field->flags & UNSIGNED_FLAG) {
  1640. unsigned_type = DATA_UNSIGNED;
  1641. } else {
  1642. unsigned_type = 0;
  1643. }
  1644. dict_mem_table_add_col(table, (char*) field->field_name,
  1645. col_type, (ulint)field->type()
  1646. | nulls_allowed | unsigned_type,
  1647. field->pack_length(), 0);
  1648. }
  1649. error = row_create_table_for_mysql(table, trx);
  1650. error = convert_error_code_to_mysql(error);
  1651. DBUG_RETURN(error);
  1652. }
  1653. /*********************************************************************
  1654. Creates an index in an Innobase database. */
  1655. static
  1656. int
  1657. create_index(
  1658. /*=========*/
  1659. trx_t* trx, /* in: Innobase transaction handle */
  1660. TABLE* form, /* in: information on table
  1661. columns and indexes */
  1662. const char* table_name, /* in: table name */
  1663. uint key_num) /* in: index number */
  1664. {
  1665. dict_index_t* index;
  1666.    int  error;
  1667. ulint n_fields;
  1668. KEY* key;
  1669. KEY_PART_INFO* key_part;
  1670. ulint ind_type;
  1671.    ulint i;
  1672.    DBUG_ENTER("create_index");
  1673. key = form->key_info + key_num;
  1674.      n_fields = key->key_parts;
  1675.      ind_type = 0;
  1676.      if (strcmp(key->name, "PRIMARY") == 0) {
  1677. ind_type = ind_type | DICT_CLUSTERED;
  1678. }
  1679. if (key->flags & HA_NOSAME ) {
  1680. ind_type = ind_type | DICT_UNIQUE;
  1681. }
  1682. /* The '0' below specifies that everything in Innobase is currently
  1683. created in tablespace 0 */
  1684. index = dict_mem_index_create((char*) table_name, key->name, 0,
  1685. ind_type, n_fields);
  1686. for (i = 0; i < n_fields; i++) {
  1687. key_part = key->key_part + i;
  1688. /* We assume all fields should be sorted in ascending
  1689. order, hence the '0': */
  1690. dict_mem_index_add_field(index,
  1691. (char*) key_part->field->field_name, 0);
  1692. }
  1693. error = row_create_index_for_mysql(index, trx);
  1694. error = convert_error_code_to_mysql(error);
  1695. DBUG_RETURN(error);
  1696. }
  1697. /*********************************************************************
  1698. Creates an index to an Innobase table when the user has defined no
  1699. primary index. */
  1700. static
  1701. int
  1702. create_clustered_index_when_no_primary(
  1703. /*===================================*/
  1704. trx_t* trx, /* in: Innobase transaction handle */
  1705. const char* table_name) /* in: table name */
  1706. {
  1707. dict_index_t* index;
  1708.    int  error;
  1709. /* The first '0' below specifies that everything in Innobase is
  1710. currently created in file space 0 */
  1711. index = dict_mem_index_create((char*) table_name,
  1712.       (char*) "GEN_CLUST_INDEX",
  1713.       0, DICT_CLUSTERED, 0);
  1714. error = row_create_index_for_mysql(index, trx);
  1715. error = convert_error_code_to_mysql(error);
  1716. return(error);
  1717. }
  1718. /*********************************************************************
  1719. Creates a new table to an Innobase database. */
  1720. int
  1721. ha_innobase::create(
  1722. /*================*/
  1723. /* out: error number */
  1724. const char* name, /* in: table name */
  1725. TABLE* form, /* in: information on table
  1726. columns and indexes */
  1727. HA_CREATE_INFO* create_info) /* in: ??????? */
  1728. {
  1729. int error;
  1730. dict_table_t* innobase_table;
  1731. trx_t* trx;
  1732. int primary_key_no = -1;
  1733. KEY* key;
  1734. uint i;
  1735. char name2[FN_REFLEN];
  1736. char norm_name[FN_REFLEN];
  1737.    DBUG_ENTER("ha_innobase::create");
  1738. trx = trx_allocate_for_mysql();
  1739. fn_format(name2, name, "", "",2); // Remove the .frm extension
  1740. normalize_table_name(norm_name, name2);
  1741.    /* Create the table definition in Innobase */
  1742.    if (error = create_table_def(trx, form, norm_name)) {
  1743. trx_commit_for_mysql(trx);
  1744.    trx_free_for_mysql(trx);
  1745.   DBUG_RETURN(error);
  1746.   }
  1747. /* Look for a primary key */
  1748. for (i = 0; i < form->keys; i++) {
  1749. key = form->key_info + i;
  1750.      if (strcmp(key->name, "PRIMARY") == 0) {
  1751.      primary_key_no = (int) i;
  1752.      }
  1753. }
  1754. /* Our function row_get_mysql_key_number_for_index assumes
  1755. the primary key is always number 0, if it exists */
  1756. assert(primary_key_no == -1 || primary_key_no == 0);
  1757. /* Create the keys */
  1758. if (form->keys == 0 || primary_key_no == -1) {
  1759. /* Create an index which is used as the clustered index;
  1760. order the rows by their row id which is internally generated
  1761. by Innobase */
  1762. error = create_clustered_index_when_no_primary(trx,
  1763. norm_name);
  1764.    if (error) {
  1765. trx_commit_for_mysql(trx);
  1766. trx_free_for_mysql(trx);
  1767. DBUG_RETURN(error);
  1768.        }
  1769. }
  1770. if (primary_key_no != -1) {
  1771. /* In Innobase the clustered index must always be created
  1772. first */
  1773.      if ((error = create_index(trx, form, norm_name,
  1774.   (uint) primary_key_no))) {
  1775. trx_commit_for_mysql(trx);
  1776.    trx_free_for_mysql(trx);
  1777. DBUG_RETURN(error);
  1778.        }
  1779.        }
  1780. for (i = 0; i < form->keys; i++) {
  1781. if (i != (uint) primary_key_no) {
  1782.      if ((error = create_index(trx, form, norm_name, i))) {
  1783. trx_commit_for_mysql(trx);
  1784.    trx_free_for_mysql(trx);
  1785. DBUG_RETURN(error);
  1786.        }
  1787.        }
  1788.    }
  1789.    trx_commit_for_mysql(trx);
  1790. innobase_table = dict_table_get(norm_name, NULL);
  1791. assert(innobase_table);
  1792. /* Tell the Innobase server that there might be work for
  1793. utility threads: */
  1794. srv_active_wake_master_thread();
  1795.    trx_free_for_mysql(trx);
  1796. DBUG_RETURN(0);
  1797. }
  1798. /*********************************************************************
  1799. Drops a table from an Innobase database. Before calling this function,
  1800. MySQL calls innobase_commit to commit the transaction of the current user.
  1801. Then the current user cannot have locks set on the table. Drop table
  1802. operation inside Innobase will wait sleeping in a loop until no other
  1803. user has locks on the table. */
  1804. int
  1805. ha_innobase::delete_table(
  1806. /*======================*/
  1807. /* out: error number */
  1808. const char* name) /* in: table name */
  1809. {
  1810. ulint name_len;
  1811. int error;
  1812. trx_t* trx;
  1813. char norm_name[1000];
  1814.    DBUG_ENTER("ha_innobase::delete_table");
  1815. trx = trx_allocate_for_mysql();
  1816. name_len = strlen(name);
  1817. assert(name_len < 1000);
  1818. /* Strangely, MySQL passes the table name without the '.frm'
  1819. extension, in contrast to ::create */
  1820. normalize_table_name(norm_name, name);
  1821.    /* Drop the table in Innobase */
  1822.    error = row_drop_table_for_mysql(norm_name, trx, FALSE);
  1823. /* Tell the Innobase server that there might be work for
  1824. utility threads: */
  1825. srv_active_wake_master_thread();
  1826.    trx_free_for_mysql(trx);
  1827. error = convert_error_code_to_mysql(error);
  1828. DBUG_RETURN(error);
  1829. }
  1830. /*************************************************************************
  1831. Renames an Innobase table. */
  1832. int
  1833. ha_innobase::rename_table(
  1834. /*======================*/
  1835. /* out: 0 or error code */
  1836. const char* from, /* in: old name of the table */
  1837. const char* to) /* in: new name of the table */
  1838. {
  1839. ulint name_len1;
  1840. ulint name_len2;
  1841. int error;
  1842. trx_t* trx;
  1843. char norm_from[1000];
  1844. char norm_to[1000];
  1845.    DBUG_ENTER("ha_innobase::rename_table");
  1846. trx = trx_allocate_for_mysql();
  1847. name_len1 = strlen(from);
  1848. name_len2 = strlen(to);
  1849. assert(name_len1 < 1000);
  1850. assert(name_len2 < 1000);
  1851. normalize_table_name(norm_from, from);
  1852. normalize_table_name(norm_to, to);
  1853.    /* Rename the table in Innobase */
  1854.    error = row_rename_table_for_mysql(norm_from, norm_to, trx);
  1855. /* Tell the Innobase server that there might be work for
  1856. utility threads: */
  1857. srv_active_wake_master_thread();
  1858.    trx_free_for_mysql(trx);
  1859. error = convert_error_code_to_mysql(error);
  1860. DBUG_RETURN(error);
  1861. }
  1862. /*************************************************************************
  1863. Estimates the number of index records in a range. */
  1864. ha_rows
  1865. ha_innobase::records_in_range(
  1866. /*==========================*/
  1867. /* out: estimated number of rows,
  1868. currently 32-bit int or uint */
  1869. int  keynr, /* in: index number */
  1870. const mysql_byte* start_key, /* in: start key value of the
  1871. range, may also be empty */
  1872. uint  start_key_len, /* in: start key val len, may
  1873. also be 0 */
  1874. enum ha_rkey_function  start_search_flag,/* in: start search condition
  1875. e.g., 'greater than' */
  1876. const mysql_byte* end_key, /* in: range end key val, may
  1877. also be empty */
  1878. uint  end_key_len, /* in: range end key val len,
  1879. may also be 0 */
  1880. enum ha_rkey_function  end_search_flag)/* in: range end search cond */
  1881. {
  1882. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1883. KEY* key;
  1884. dict_index_t* index;
  1885. mysql_byte* key_val_buff2  = (mysql_byte*) my_malloc(
  1886. table->reclength,
  1887. MYF(MY_WME));
  1888. dtuple_t* range_start;
  1889. dtuple_t* range_end;
  1890. ulint n_rows;
  1891. ulint mode1;
  1892. ulint mode2;
  1893. void*           heap1;
  1894. void*           heap2;
  1895.     DBUG_ENTER("records_in_range");
  1896. active_index = keynr;
  1897. key = table->key_info + active_index;
  1898. index = dict_table_get_index_noninline(prebuilt->table, key->name);
  1899. range_start = dtuple_create_for_mysql(&heap1, key->key_parts);
  1900.   dict_index_copy_types(range_start, index, index->n_fields);
  1901. range_end = dtuple_create_for_mysql(&heap2, key->key_parts);
  1902.   dict_index_copy_types(range_end, index, index->n_fields);
  1903. row_sel_convert_mysql_key_to_innobase(
  1904. range_start, (byte*) key_val_buff, index,
  1905. (byte*) start_key,
  1906. (ulint) start_key_len);
  1907. row_sel_convert_mysql_key_to_innobase(
  1908. range_end, (byte*) key_val_buff2, index,
  1909. (byte*) end_key,
  1910. (ulint) end_key_len);
  1911. mode1 = convert_search_mode_to_innobase(start_search_flag);
  1912. mode2 = convert_search_mode_to_innobase(end_search_flag);
  1913. n_rows = btr_estimate_n_rows_in_range(index, range_start,
  1914. mode1, range_end, mode2);
  1915. dtuple_free_for_mysql(heap1);
  1916. dtuple_free_for_mysql(heap2);
  1917.      my_free((char*) key_val_buff2, MYF(0));
  1918. DBUG_RETURN((ha_rows) n_rows);
  1919. }
  1920. /*************************************************************************
  1921. How many seeks it will take to read through the table. This is to be
  1922. comparable to the number returned by records_in_range so that we can
  1923. decide if we should scan the table or use keys. */
  1924. double
  1925. ha_innobase::scan_time()
  1926. /*====================*/
  1927. /* out: estimated time measured in disk seeks */
  1928. {
  1929. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1930. /* In the following formula we assume that scanning 5 pages
  1931. takes the same time as a disk seek: */
  1932. return((double) (1 + prebuilt->table->stat_clustered_index_size / 5));
  1933. }
  1934. /*************************************************************************
  1935. Returns statistics information of the table to the MySQL interpreter,
  1936. in various fields of the handle object. */
  1937. void
  1938. ha_innobase::info(
  1939. /*==============*/
  1940. uint flag) /* in: what information MySQL requests */
  1941. {
  1942. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1943. dict_table_t* ib_table;
  1944. dict_index_t* index;
  1945. uint rec_per_key;
  1946. uint i;
  1947.   DBUG_ENTER("info");
  1948.   ib_table = prebuilt->table;
  1949.   if (flag & HA_STATUS_TIME) {
  1950.   /* In sql_show we call with this flag: update then statistics
  1951.   so that they are up-to-date */
  1952.   dict_update_statistics(ib_table);
  1953.   }
  1954. if (flag & HA_STATUS_VARIABLE) {
  1955.      records = ib_table->stat_n_rows;
  1956.      deleted = 0;
  1957.      data_file_length = ((ulonglong)
  1958. ib_table->stat_clustered_index_size)
  1959.      * UNIV_PAGE_SIZE;
  1960.      index_file_length = ((ulonglong)
  1961. ib_table->stat_sum_of_other_index_sizes)
  1962.      * UNIV_PAGE_SIZE;
  1963.      delete_length = 0;
  1964.      check_time = 0;
  1965.      if (records == 0) {
  1966.      mean_rec_length = 0;
  1967.      } else {
  1968.      mean_rec_length = (ulong) data_file_length / records;
  1969.      }
  1970.      }
  1971. if (flag & HA_STATUS_CONST) {
  1972. index = dict_table_get_first_index_noninline(ib_table);
  1973. if (prebuilt->clust_index_was_generated) {
  1974. index = dict_table_get_next_index_noninline(index);
  1975. }
  1976. for (i = 0; i < table->keys; i++) {
  1977. if (index->stat_n_diff_key_vals == 0) {
  1978. rec_per_key = records;
  1979. } else {
  1980. rec_per_key = records /
  1981. index->stat_n_diff_key_vals;
  1982. }
  1983. table->key_info[i].rec_per_key[
  1984. table->key_info[i].key_parts - 1]
  1985. = rec_per_key;
  1986. index = dict_table_get_next_index_noninline(index);
  1987. }
  1988. }
  1989.    if (flag & HA_STATUS_ERRKEY) {
  1990. errkey = (unsigned int) row_get_mysql_key_number_for_index(
  1991. (dict_index_t*)
  1992. prebuilt->trx->error_info);
  1993.    }
  1994.    DBUG_VOID_RETURN;
  1995. }
  1996. /*****************************************************************
  1997. Adds information about free space in the Innobase tablespace to a
  1998. table comment which is printed out when a user calls SHOW TABLE STATUS. */
  1999. char*
  2000. ha_innobase::update_table_comment(
  2001. /*==============================*/
  2002.         const char* comment)
  2003. {
  2004.   uint length=strlen(comment);
  2005.   char *str=my_malloc(length + 100,MYF(0));
  2006.   if (!str)
  2007.     return (char*)comment;
  2008.   sprintf(str,
  2009.     "%s; Innobase free: %lu kB",
  2010.   comment, (ulong) innobase_get_free_space());
  2011.   return(str);
  2012. }
  2013. /****************************************************************************
  2014.  Handling the shared INNOBASE_SHARE structure that is needed to provide table
  2015.  locking.
  2016. ****************************************************************************/
  2017. static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
  2018.       my_bool not_used __attribute__((unused)))
  2019. {
  2020.   *length=share->table_name_length;
  2021.   return (mysql_byte*) share->table_name;
  2022. }
  2023. static INNOBASE_SHARE *get_share(const char *table_name)
  2024. {
  2025.   INNOBASE_SHARE *share;
  2026.   pthread_mutex_lock(&innobase_mutex);
  2027.   uint length=(uint) strlen(table_name);
  2028.   if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables,
  2029. (mysql_byte*) table_name,
  2030.     length)))
  2031.   {
  2032.     if ((share=(INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
  2033.        MYF(MY_WME | MY_ZEROFILL))))
  2034.     {
  2035.       share->table_name_length=length;
  2036.       share->table_name=(char*) (share+1);
  2037.       strmov(share->table_name,table_name);
  2038.       if (hash_insert(&innobase_open_tables, (mysql_byte*) share))
  2039.       {
  2040. pthread_mutex_unlock(&innobase_mutex);
  2041. my_free((gptr) share,0);
  2042. return 0;
  2043.       }
  2044.       thr_lock_init(&share->lock);
  2045.       pthread_mutex_init(&share->mutex,NULL);
  2046.     }
  2047.   }
  2048.   share->use_count++;
  2049.   pthread_mutex_unlock(&innobase_mutex);
  2050.   return share;
  2051. }
  2052. static void free_share(INNOBASE_SHARE *share)
  2053. {
  2054.   pthread_mutex_lock(&innobase_mutex);
  2055.   if (!--share->use_count)
  2056.   {
  2057.     hash_delete(&innobase_open_tables, (mysql_byte*) share);
  2058.     thr_lock_delete(&share->lock);
  2059.     pthread_mutex_destroy(&share->mutex);
  2060.     my_free((gptr) share, MYF(0));
  2061.   }
  2062.   pthread_mutex_unlock(&innobase_mutex);
  2063. }
  2064. /*********************************************************************
  2065. Stores a MySQL lock into a 'lock' field in a handle. */
  2066. THR_LOCK_DATA**
  2067. ha_innobase::store_lock(
  2068. /*====================*/
  2069. /* out: pointer to the next
  2070. element in the 'to' array */
  2071. THD* thd, /* in: user thread handle */
  2072. THR_LOCK_DATA** to, /* in: pointer to an array
  2073. of pointers to lock structs;
  2074. pointer to the 'lock' field
  2075. of current handle is stored
  2076. next to this array */
  2077. enum thr_lock_type  lock_type) /* in: lock type to store in
  2078. 'lock' */
  2079. {
  2080. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  2081. if (lock_type == TL_READ_WITH_SHARED_LOCKS) {
  2082. /* This is a SELECT ... IN SHARE MODE */
  2083. prebuilt->select_lock_type = LOCK_S;
  2084. } else {
  2085. /* We set possible LOCK_X value in external_lock, not yet
  2086. here even if this would be SELECT ... FOR UPDATE */
  2087. prebuilt->select_lock_type = LOCK_NONE;
  2088. }
  2089. if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
  2090.      /* If we are not doing a LOCK TABLE, then allow multiple
  2091. writers */
  2092.      if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
  2093.       lock_type <= TL_WRITE) && !thd->in_lock_tables) {
  2094.        lock_type = TL_WRITE_ALLOW_WRITE;
  2095.        }
  2096.   lock.type=lock_type;
  2097.    }
  2098.    *to++= &lock;
  2099. return(to);
  2100. }
  2101. #endif /* HAVE_INNOBASE_DB */