ha_innodb.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:165k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. uint  keynr) /* in: key (index) number */
  2. {
  3. int  error = 0;
  4.    DBUG_ENTER("index_init");
  5. error = change_active_index(keynr);
  6.    DBUG_RETURN(error);
  7. }
  8. /**********************************************************************
  9. Currently does nothing. */
  10. int
  11. ha_innobase::index_end(void)
  12. /*========================*/
  13. {
  14. int  error = 0;
  15.    DBUG_ENTER("index_end");
  16.         active_index=MAX_KEY;
  17.    DBUG_RETURN(error);
  18. }
  19. /*************************************************************************
  20. Converts a search mode flag understood by MySQL to a flag understood
  21. by InnoDB. */
  22. inline
  23. ulint
  24. convert_search_mode_to_innobase(
  25. /*============================*/
  26. enum ha_rkey_function find_flag)
  27. {
  28. switch (find_flag) {
  29.    case HA_READ_KEY_EXACT: return(PAGE_CUR_GE);
  30.    /* the above does not require the index to be UNIQUE */
  31.    case HA_READ_KEY_OR_NEXT: return(PAGE_CUR_GE);
  32. case HA_READ_KEY_OR_PREV: return(PAGE_CUR_LE);
  33. case HA_READ_AFTER_KEY: return(PAGE_CUR_G);
  34. case HA_READ_BEFORE_KEY: return(PAGE_CUR_L);
  35. case HA_READ_PREFIX: return(PAGE_CUR_GE);
  36.         case HA_READ_PREFIX_LAST:       return(PAGE_CUR_LE);
  37.                 case HA_READ_PREFIX_LAST_OR_PREV:return(PAGE_CUR_LE);
  38.   /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
  39.   pass a complete-field prefix of a key value as the search
  40.   tuple. I.e., it is not allowed that the last field would
  41.   just contain n first bytes of the full field value.
  42.   MySQL uses a 'padding' trick to convert LIKE 'abc%'
  43.   type queries so that it can use as a search tuple
  44.   a complete-field-prefix of a key value. Thus, the InnoDB
  45.   search mode PAGE_CUR_LE_OR_EXTENDS is never used.
  46.   TODO: when/if MySQL starts to use also partial-field
  47.   prefixes, we have to deal with stripping of spaces
  48.   and comparison of non-latin1 char type fields in
  49.   innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
  50.   work correctly. */
  51. default: assert(0);
  52. }
  53. return(0);
  54. }
  55. /*
  56.    BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
  57.    ---------------------------------------------------
  58. The following does not cover all the details, but explains how we determine
  59. the start of a new SQL statement, and what is associated with it.
  60. For each table in the database the MySQL interpreter may have several
  61. table handle instances in use, also in a single SQL query. For each table
  62. handle instance there is an InnoDB  'prebuilt' struct which contains most
  63. of the InnoDB data associated with this table handle instance.
  64.   A) if the user has not explicitly set any MySQL table level locks:
  65.   1) MySQL calls ::external_lock to set an 'intention' table level lock on
  66. the table of the handle instance. There we set
  67. prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
  68. true if we are taking this table handle instance to use in a new SQL
  69. statement issued by the user. We also increment trx->n_mysql_tables_in_use.
  70.   2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
  71. instructions to prebuilt->template of the table handle instance in
  72. ::index_read. The template is used to save CPU time in large joins.
  73.   3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
  74. allocate a new consistent read view for the trx if it does not yet have one,
  75. or in the case of a locking read, set an InnoDB 'intention' table level
  76. lock on the table.
  77.   4) We do the SELECT. MySQL may repeatedly call ::index_read for the
  78. same table handle instance, if it is a join.
  79.   5) When the SELECT ends, MySQL removes its intention table level locks
  80. in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
  81.  (a) we execute a COMMIT there if the autocommit is on,
  82.  (b) we also release possible 'SQL statement level resources' InnoDB may
  83. have for this SQL statement. The MySQL interpreter does NOT execute
  84. autocommit for pure read transactions, though it should. That is why the
  85. table handler in that case has to execute the COMMIT in ::external_lock.
  86.   B) If the user has explicitly set MySQL table level locks, then MySQL
  87. does NOT call ::external_lock at the start of the statement. To determine
  88. when we are at the start of a new SQL statement we at the start of
  89. ::index_read also compare the query id to the latest query id where the
  90. table handle instance was used. If it has changed, we know we are at the
  91. start of a new SQL statement. Since the query id can theoretically
  92. overwrap, we use this test only as a secondary way of determining the
  93. start of a new SQL statement. */
  94. /**************************************************************************
  95. Positions an index cursor to the index specified in the handle. Fetches the
  96. row if any. */
  97. int
  98. ha_innobase::index_read(
  99. /*====================*/
  100. /* out: 0, HA_ERR_KEY_NOT_FOUND,
  101. or error number */
  102. mysql_byte* buf, /* in/out: buffer for the returned
  103. row */
  104. const mysql_byte*  key_ptr,/* in: key value; if this is NULL
  105. we position the cursor at the
  106. start or end of index; this can
  107. also contain an InnoDB row id, in
  108. which case key_len is the InnoDB
  109. row id length; the key value can
  110. also be a prefix of a full key value,
  111. and the last column can be a prefix
  112. of a full column */
  113. uint key_len,/* in: key value length */
  114. enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
  115. {
  116. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  117. ulint mode;
  118. dict_index_t* index;
  119. ulint match_mode  = 0;
  120. int  error;
  121. ulint ret;
  122.    DBUG_ENTER("index_read");
  123. ut_ad(prebuilt->trx ==
  124. (trx_t*) current_thd->transaction.all.innobase_tid);
  125.    statistic_increment(ha_read_key_count, &LOCK_status);
  126. if (last_query_id != user_thd->query_id) {
  127.         prebuilt->sql_stat_start = TRUE;
  128.                 last_query_id = user_thd->query_id;
  129. innobase_release_stat_resources(prebuilt->trx);
  130. }
  131. index = prebuilt->index;
  132. /* Note that if the index for which the search template is built is not
  133.         necessarily prebuilt->index, but can also be the clustered index */
  134. if (prebuilt->sql_stat_start) {
  135. build_template(prebuilt, user_thd, table,
  136. ROW_MYSQL_REC_FIELDS);
  137. }
  138. if (key_ptr) {
  139.         /* Convert the search key value to InnoDB format into
  140. prebuilt->search_tuple */
  141. row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple,
  142. (byte*) key_val_buff,
  143. (ulint)upd_and_key_val_buff_len,
  144. index,
  145. (byte*) key_ptr,
  146. (ulint) key_len, prebuilt->trx);
  147. } else {
  148. /* We position the cursor to the last or the first entry
  149. in the index */
  150.   dtuple_set_n_fields(prebuilt->search_tuple, 0);
  151. }
  152. mode = convert_search_mode_to_innobase(find_flag);
  153. match_mode = 0;
  154. if (find_flag == HA_READ_KEY_EXACT) {
  155. match_mode = ROW_SEL_EXACT;
  156. } else if (find_flag == HA_READ_PREFIX
  157. || find_flag == HA_READ_PREFIX_LAST) {
  158. match_mode = ROW_SEL_EXACT_PREFIX;
  159. }
  160. last_match_mode = match_mode;
  161. innodb_srv_conc_enter_innodb(prebuilt->trx);
  162. ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0);
  163. innodb_srv_conc_exit_innodb(prebuilt->trx);
  164. if (ret == DB_SUCCESS) {
  165. error = 0;
  166. table->status = 0;
  167. } else if (ret == DB_RECORD_NOT_FOUND) {
  168. error = HA_ERR_KEY_NOT_FOUND;
  169. table->status = STATUS_NOT_FOUND;
  170. } else if (ret == DB_END_OF_INDEX) {
  171. error = HA_ERR_KEY_NOT_FOUND;
  172. table->status = STATUS_NOT_FOUND;
  173. } else {
  174. error = convert_error_code_to_mysql(ret, user_thd);
  175. table->status = STATUS_NOT_FOUND;
  176. }
  177. DBUG_RETURN(error);
  178. }
  179. /***********************************************************************
  180. The following functions works like index_read, but it find the last
  181. row with the current key value or prefix. */
  182. int
  183. ha_innobase::index_read_last(
  184. /*=========================*/
  185.            /* out: 0, HA_ERR_KEY_NOT_FOUND, or an
  186.    error code */
  187.         mysql_byte*       buf,     /* out: fetched row */
  188.         const mysql_byte* key_ptr, /* in: key value, or a prefix of a full
  189.    key value */
  190. uint              key_len) /* in: length of the key val or prefix
  191.    in bytes */
  192. {
  193.         return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
  194. }
  195. /************************************************************************
  196. Changes the active index of a handle. */
  197. int
  198. ha_innobase::change_active_index(
  199. /*=============================*/
  200. /* out: 0 or error code */
  201. uint  keynr) /* in: use this index; MAX_KEY means always clustered
  202. index, even if it was internally generated by
  203. InnoDB */
  204. {
  205. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  206. KEY* key=0;
  207. statistic_increment(ha_read_key_count, &LOCK_status);
  208. DBUG_ENTER("change_active_index");
  209. ut_ad(user_thd == current_thd);
  210. ut_ad(prebuilt->trx ==
  211.      (trx_t*) current_thd->transaction.all.innobase_tid);
  212. active_index = keynr;
  213. if (keynr != MAX_KEY && table->keys > 0) {
  214. key = table->key_info + active_index;
  215. prebuilt->index = dict_table_get_index_noninline(
  216.      prebuilt->table,
  217.      key->name);
  218.         } else {
  219. prebuilt->index = dict_table_get_first_index_noninline(
  220.    prebuilt->table);
  221. }
  222. if (!prebuilt->index) {
  223.        sql_print_error(
  224. "Innodb could not find key n:o %u with name %s from dict cache for table %s",
  225.       keynr, key ? key->name : "NULL", prebuilt->table->name);
  226.       DBUG_RETURN(1);
  227. }
  228. assert(prebuilt->search_tuple != 0);
  229. dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
  230. dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
  231. prebuilt->index->n_fields);
  232. /* MySQL changes the active index for a handle also during some
  233. queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
  234. and then calculates the sum. Previously we played safe and used
  235. the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
  236. copying. Starting from MySQL-4.1 we use a more efficient flag here. */
  237. build_template(prebuilt, user_thd, table, ROW_MYSQL_REC_FIELDS);
  238. DBUG_RETURN(0);
  239. }
  240. /**************************************************************************
  241. Positions an index cursor to the index specified in keynr. Fetches the
  242. row if any. */
  243. /* ??? This is only used to read whole keys ??? */
  244. int
  245. ha_innobase::index_read_idx(
  246. /*========================*/
  247. /* out: error number or 0 */
  248. mysql_byte* buf, /* in/out: buffer for the returned
  249. row */
  250. uint  keynr, /* in: use this index */
  251. const mysql_byte* key, /* in: key value; if this is NULL
  252. we position the cursor at the
  253. start or end of index */
  254. uint key_len, /* in: key value length */
  255. enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
  256. {
  257. if (change_active_index(keynr)) {
  258. return(1);
  259. }
  260. return(index_read(buf, key, key_len, find_flag));
  261. }
  262. /***************************************************************************
  263. Reads the next or previous row from a cursor, which must have previously been
  264. positioned using index_read. */
  265. int
  266. ha_innobase::general_fetch(
  267. /*=======================*/
  268. /* out: 0, HA_ERR_END_OF_FILE, or error
  269. number */
  270. mysql_byte*  buf, /* in/out: buffer for next row in MySQL
  271. format */
  272. uint  direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */
  273. uint match_mode) /* in: 0, ROW_SEL_EXACT, or
  274. ROW_SEL_EXACT_PREFIX */
  275. {
  276. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  277. ulint ret;
  278. int error = 0;
  279. DBUG_ENTER("general_fetch");
  280. ut_ad(prebuilt->trx ==
  281.      (trx_t*) current_thd->transaction.all.innobase_tid);
  282. innodb_srv_conc_enter_innodb(prebuilt->trx);
  283. ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
  284. direction);
  285. innodb_srv_conc_exit_innodb(prebuilt->trx);
  286. if (ret == DB_SUCCESS) {
  287. error = 0;
  288. table->status = 0;
  289. } else if (ret == DB_RECORD_NOT_FOUND) {
  290. error = HA_ERR_END_OF_FILE;
  291. table->status = STATUS_NOT_FOUND;
  292. } else if (ret == DB_END_OF_INDEX) {
  293. error = HA_ERR_END_OF_FILE;
  294. table->status = STATUS_NOT_FOUND;
  295. } else {
  296. error = convert_error_code_to_mysql(ret, user_thd);
  297. table->status = STATUS_NOT_FOUND;
  298. }
  299. DBUG_RETURN(error);
  300. }
  301. /***************************************************************************
  302. Reads the next row from a cursor, which must have previously been
  303. positioned using index_read. */
  304. int
  305. ha_innobase::index_next(
  306. /*====================*/
  307. /* out: 0, HA_ERR_END_OF_FILE, or error
  308. number */
  309. mysql_byte*  buf) /* in/out: buffer for next row in MySQL
  310. format */
  311. {
  312.    statistic_increment(ha_read_next_count, &LOCK_status);
  313. return(general_fetch(buf, ROW_SEL_NEXT, 0));
  314. }
  315. /***********************************************************************
  316. Reads the next row matching to the key value given as the parameter. */
  317. int
  318. ha_innobase::index_next_same(
  319. /*=========================*/
  320. /* out: 0, HA_ERR_END_OF_FILE, or error
  321. number */
  322. mysql_byte*  buf, /* in/out: buffer for the row */
  323. const mysql_byte* key, /* in: key value */
  324. uint  keylen) /* in: key value length */
  325. {
  326.    statistic_increment(ha_read_next_count, &LOCK_status);
  327. return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
  328. }
  329. /***************************************************************************
  330. Reads the previous row from a cursor, which must have previously been
  331. positioned using index_read. */
  332. int
  333. ha_innobase::index_prev(
  334. /*====================*/
  335. /* out: 0, HA_ERR_END_OF_FILE, or error
  336. number */
  337. mysql_byte*  buf) /* in/out: buffer for previous row in MySQL
  338. format */
  339. {
  340. return(general_fetch(buf, ROW_SEL_PREV, 0));
  341. }
  342. /************************************************************************
  343. Positions a cursor on the first record in an index and reads the
  344. corresponding row to buf. */
  345. int
  346. ha_innobase::index_first(
  347. /*=====================*/
  348. /* out: 0, HA_ERR_END_OF_FILE,
  349. or error code */
  350. mysql_byte* buf) /* in/out: buffer for the row */
  351. {
  352. int error;
  353.    DBUG_ENTER("index_first");
  354.    statistic_increment(ha_read_first_count, &LOCK_status);
  355.    error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
  356.         /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
  357.    if (error == HA_ERR_KEY_NOT_FOUND) {
  358.    error = HA_ERR_END_OF_FILE;
  359.    }
  360.    DBUG_RETURN(error);
  361. }
  362. /************************************************************************
  363. Positions a cursor on the last record in an index and reads the
  364. corresponding row to buf. */
  365. int
  366. ha_innobase::index_last(
  367. /*====================*/
  368. /* out: 0, HA_ERR_END_OF_FILE, or error code */
  369. mysql_byte* buf) /* in/out: buffer for the row */
  370. {
  371. int error;
  372.    DBUG_ENTER("index_last");
  373.    statistic_increment(ha_read_last_count, &LOCK_status);
  374.    error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
  375.         /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
  376.    if (error == HA_ERR_KEY_NOT_FOUND) {
  377.    error = HA_ERR_END_OF_FILE;
  378.    }
  379.    DBUG_RETURN(error);
  380. }
  381. /********************************************************************
  382. Initialize a table scan. */
  383. int
  384. ha_innobase::rnd_init(
  385. /*==================*/
  386. /* out: 0 or error number */
  387. bool scan) /* in: ???????? */
  388. {
  389. int err;
  390. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  391. /* Store the active index value so that we can restore the original
  392. value after a scan */
  393. if (prebuilt->clust_index_was_generated) {
  394. err = change_active_index(MAX_KEY);
  395. } else {
  396. err = change_active_index(primary_key);
  397. }
  398.    start_of_scan = 1;
  399.   return(err);
  400. }
  401. /*********************************************************************
  402. Ends a table scan. */
  403. int
  404. ha_innobase::rnd_end(void)
  405. /*======================*/
  406. /* out: 0 or error number */
  407. {
  408. return(index_end());
  409. }
  410. /*********************************************************************
  411. Reads the next row in a table scan (also used to read the FIRST row
  412. in a table scan). */
  413. int
  414. ha_innobase::rnd_next(
  415. /*==================*/
  416. /* out: 0, HA_ERR_END_OF_FILE, or error number */
  417. mysql_byte* buf)/* in/out: returns the row in this buffer,
  418. in MySQL format */
  419. {
  420. int error;
  421.    DBUG_ENTER("rnd_next");
  422.    statistic_increment(ha_read_rnd_next_count, &LOCK_status);
  423.    if (start_of_scan) {
  424. error = index_first(buf);
  425. if (error == HA_ERR_KEY_NOT_FOUND) {
  426. error = HA_ERR_END_OF_FILE;
  427. }
  428. start_of_scan = 0;
  429. } else {
  430. error = general_fetch(buf, ROW_SEL_NEXT, 0);
  431. }
  432.    DBUG_RETURN(error);
  433. }
  434. /**************************************************************************
  435. Fetches a row from the table based on a row reference. */
  436. int
  437. ha_innobase::rnd_pos(
  438. /*=================*/
  439. /* out: 0, HA_ERR_KEY_NOT_FOUND,
  440. or error code */
  441. mysql_byte*  buf, /* in/out: buffer for the row */
  442. mysql_byte* pos) /* in: primary key value of the row in the
  443. MySQL format, or the row id if the clustered
  444. index was internally generated by InnoDB;
  445. the length of data in pos has to be
  446. ref_length */
  447. {
  448. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  449. int error;
  450. uint keynr = active_index;
  451. DBUG_ENTER("rnd_pos");
  452. DBUG_DUMP("key", (char*) pos, ref_length);
  453. statistic_increment(ha_read_rnd_count, &LOCK_status);
  454. ut_ad(prebuilt->trx ==
  455. (trx_t*) current_thd->transaction.all.innobase_tid);
  456. if (prebuilt->clust_index_was_generated) {
  457. /* No primary key was defined for the table and we
  458. generated the clustered index from the row id: the
  459. row reference is the row id, not any key value
  460. that MySQL knows of */
  461. error = change_active_index(MAX_KEY);
  462. } else {
  463. error = change_active_index(primary_key);
  464. }
  465. if (error) {
  466.         DBUG_PRINT("error",("Got error: %ld",error));
  467. DBUG_RETURN(error);
  468. }
  469. /* Note that we assume the length of the row reference is fixed
  470.         for the table, and it is == ref_length */
  471. error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
  472. if (error)
  473. {
  474.   DBUG_PRINT("error",("Got error: %ld",error));
  475. }
  476. change_active_index(keynr);
  477.    DBUG_RETURN(error);
  478. }
  479. /*************************************************************************
  480. Stores a reference to the current row to 'ref' field of the handle. Note
  481. that in the case where we have generated the clustered index for the
  482. table, the function parameter is illogical: we MUST ASSUME that 'record'
  483. is the current 'position' of the handle, because if row ref is actually
  484. the row id internally generated in InnoDB, then 'record' does not contain
  485. it. We just guess that the row id must be for the record where the handle
  486. was positioned the last time. */
  487. void
  488. ha_innobase::position(
  489. /*==================*/
  490. const mysql_byte* record) /* in: row in MySQL format */
  491. {
  492. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  493. uint len;
  494. ut_ad(prebuilt->trx ==
  495. (trx_t*) current_thd->transaction.all.innobase_tid);
  496. if (prebuilt->clust_index_was_generated) {
  497. /* No primary key was defined for the table and we
  498. generated the clustered index from row id: the
  499. row reference will be the row id, not any key value
  500. that MySQL knows of */
  501. len = DATA_ROW_ID_LEN;
  502. memcpy(ref, prebuilt->row_id, len);
  503. } else {
  504. len = store_key_val_for_row(primary_key, (char*)ref,
  505.  ref_length, record);
  506. }
  507. /* Since we do not store len to the buffer 'ref', we must assume
  508. that len is always fixed for this table. The following assertion
  509. checks this. */
  510.   
  511. if (len != ref_length) {
  512.         fprintf(stderr,
  513.  "InnoDB: Error: stored ref len is %lu, but table ref len is %lun",
  514.   (ulong)len, (ulong)ref_length);
  515. }
  516. }
  517. /*********************************************************************
  518. Creates a table definition to an InnoDB database. */
  519. static
  520. int
  521. create_table_def(
  522. /*=============*/
  523. trx_t* trx, /* in: InnoDB transaction handle */
  524. TABLE* form, /* in: information on table
  525. columns and indexes */
  526. const char* table_name, /* in: table name */
  527. const char* path_of_temp_table)/* in: if this is a table explicitly
  528. created by the user with the
  529. TEMPORARY keyword, then this
  530. parameter is the dir path where the
  531. table should be placed if we create
  532. an .ibd file for it (no .ibd extension
  533. in the path, though); otherwise this
  534. is NULL */
  535. {
  536. Field* field;
  537. dict_table_t* table;
  538. ulint n_cols;
  539.    int  error;
  540.    ulint col_type;
  541.    ulint nulls_allowed;
  542. ulint unsigned_type;
  543. ulint binary_type;
  544. ulint charset_no;
  545.    ulint i;
  546.    DBUG_ENTER("create_table_def");
  547.    DBUG_PRINT("enter", ("table_name: %s", table_name));
  548. n_cols = form->fields;
  549. /* We pass 0 as the space id, and determine at a lower level the space
  550. id where to store the table */
  551. table = dict_mem_table_create((char*) table_name, 0, n_cols);
  552. if (path_of_temp_table) {
  553. table->dir_path_of_temp_table =
  554. mem_heap_strdup(table->heap, path_of_temp_table);
  555. }
  556. for (i = 0; i < n_cols; i++) {
  557. field = form->field[i];
  558. col_type = get_innobase_type_from_mysql_type(&unsigned_type,
  559. field);
  560. if (field->null_ptr) {
  561. nulls_allowed = 0;
  562. } else {
  563. nulls_allowed = DATA_NOT_NULL;
  564. }
  565. if (field->binary()) {
  566. binary_type = DATA_BINARY_TYPE;
  567. } else {
  568. binary_type = 0;
  569. }
  570. charset_no = 0;
  571. if (dtype_is_string_type(col_type)) {
  572. charset_no = (ulint)field->charset()->number;
  573. ut_a(charset_no < 256); /* in ut0type.h we assume that
  574. the number fits in one byte */
  575. }
  576. dict_mem_table_add_col(table, (char*) field->field_name,
  577. col_type, dtype_form_prtype( 
  578. (ulint)field->type()
  579. | nulls_allowed | unsigned_type
  580. | binary_type,
  581. + charset_no),
  582. field->pack_length(), 0);
  583. }
  584. error = row_create_table_for_mysql(table, trx);
  585. error = convert_error_code_to_mysql(error, NULL);
  586. DBUG_RETURN(error);
  587. }
  588. /*********************************************************************
  589. Creates an index in an InnoDB database. */
  590. static
  591. int
  592. create_index(
  593. /*=========*/
  594. trx_t* trx, /* in: InnoDB transaction handle */
  595. TABLE* form, /* in: information on table
  596. columns and indexes */
  597. const char* table_name, /* in: table name */
  598. uint key_num) /* in: index number */
  599. {
  600. Field* field;
  601. dict_index_t* index;
  602.    int  error;
  603. ulint n_fields;
  604. KEY* key;
  605. KEY_PART_INFO* key_part;
  606. ulint ind_type;
  607. ulint col_type;
  608. ulint prefix_len;
  609. ulint is_unsigned;
  610.    ulint i;
  611.    ulint j;
  612.    DBUG_ENTER("create_index");
  613. key = form->key_info + key_num;
  614.      n_fields = key->key_parts;
  615.      ind_type = 0;
  616.      if (key_num == form->primary_key) {
  617. ind_type = ind_type | DICT_CLUSTERED;
  618. }
  619. if (key->flags & HA_NOSAME ) {
  620. ind_type = ind_type | DICT_UNIQUE;
  621. }
  622. /* We pass 0 as the space id, and determine at a lower level the space
  623. id where to store the table */
  624. index = dict_mem_index_create((char*) table_name, key->name, 0,
  625. ind_type, n_fields);
  626. for (i = 0; i < n_fields; i++) {
  627. key_part = key->key_part + i;
  628. /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
  629. field in an index: we only store a specified number of first
  630. bytes of the column to the index field.) The flag does not
  631. seem to be properly set by MySQL. Let us fall back on testing
  632. the length of the key part versus the column. */
  633. field = NULL;
  634. for (j = 0; j < form->fields; j++) {
  635. field = form->field[j];
  636. if (0 == innobase_strcasecmp(
  637. field->field_name,
  638. key_part->field->field_name)) {
  639. /* Found the corresponding column */
  640. break;
  641. }
  642. }
  643. ut_a(j < form->fields);
  644. col_type = get_innobase_type_from_mysql_type(
  645. &is_unsigned, key_part->field);
  646. if (DATA_BLOB == col_type
  647.     || key_part->length < field->pack_length()) {
  648.         prefix_len = key_part->length;
  649. if (col_type == DATA_INT
  650.     || col_type == DATA_FLOAT
  651.     || col_type == DATA_DOUBLE
  652.     || col_type == DATA_DECIMAL) {
  653.         fprintf(stderr,
  654. "InnoDB: error: MySQL is trying to create a column prefix index fieldn"
  655. "InnoDB: on an inappropriate data type. Table name %s, column name %s.n",
  656.   table_name, key_part->field->field_name);
  657.         
  658.         prefix_len = 0;
  659. }
  660. } else {
  661.         prefix_len = 0;
  662. }
  663. /* We assume all fields should be sorted in ascending
  664. order, hence the '0': */
  665. dict_mem_index_add_field(index,
  666. (char*) key_part->field->field_name,
  667. 0, prefix_len);
  668. }
  669. error = row_create_index_for_mysql(index, trx);
  670. error = convert_error_code_to_mysql(error, NULL);
  671. DBUG_RETURN(error);
  672. }
  673. /*********************************************************************
  674. Creates an index to an InnoDB table when the user has defined no
  675. primary index. */
  676. static
  677. int
  678. create_clustered_index_when_no_primary(
  679. /*===================================*/
  680. trx_t* trx, /* in: InnoDB transaction handle */
  681. const char* table_name) /* in: table name */
  682. {
  683. dict_index_t* index;
  684.    int  error;
  685. /* We pass 0 as the space id, and determine at a lower level the space
  686. id where to store the table */
  687. index = dict_mem_index_create((char*) table_name,
  688.       (char*) "GEN_CLUST_INDEX",
  689.       0, DICT_CLUSTERED, 0);
  690. error = row_create_index_for_mysql(index, trx);
  691. error = convert_error_code_to_mysql(error, NULL);
  692. return(error);
  693. }
  694. /*********************************************************************
  695. Creates a new table to an InnoDB database. */
  696. int
  697. ha_innobase::create(
  698. /*================*/
  699. /* out: error number */
  700. const char* name, /* in: table name */
  701. TABLE* form, /* in: information on table
  702. columns and indexes */
  703. HA_CREATE_INFO* create_info) /* in: more information of the
  704. created table, contains also the
  705. create statement string */
  706. {
  707. int error;
  708. dict_table_t* innobase_table;
  709. trx_t* parent_trx;
  710. trx_t* trx;
  711. int primary_key_no;
  712. uint i;
  713. char name2[FN_REFLEN];
  714. char norm_name[FN_REFLEN];
  715. THD *thd= current_thd;
  716. ib_longlong     auto_inc_value;
  717.    DBUG_ENTER("ha_innobase::create");
  718. DBUG_ASSERT(thd != NULL);
  719. if (form->fields > 1000) {
  720. /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
  721. but we play safe here */
  722.         DBUG_RETURN(HA_ERR_TO_BIG_ROW);
  723. /* Get the transaction associated with the current thd, or create one
  724. if not yet created */
  725. parent_trx = check_trx_exists(current_thd);
  726. /* In case MySQL calls this in the middle of a SELECT query, release
  727. possible adaptive hash latch to avoid deadlocks of threads */
  728. trx_search_latch_release_if_reserved(parent_trx);
  729. trx = trx_allocate_for_mysql();
  730. trx->mysql_thd = thd;
  731. trx->mysql_query_str = &((*thd).query);
  732. if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
  733. trx->check_foreigns = FALSE;
  734. }
  735. if (thd->options & OPTION_RELAXED_UNIQUE_CHECKS) {
  736. trx->check_unique_secondary = FALSE;
  737. }
  738. if (lower_case_table_names) {
  739. srv_lower_case_table_names = TRUE;
  740. } else {
  741. srv_lower_case_table_names = FALSE;
  742. }
  743. fn_format(name2, name, "", "", 2); // Remove the .frm extension
  744. normalize_table_name(norm_name, name2);
  745. /* Latch the InnoDB data dictionary exclusively so that no deadlocks
  746. or lock waits can happen in it during a table create operation.
  747. Drop table etc. do this latching in row0mysql.c. */
  748. row_mysql_lock_data_dictionary(trx);
  749. /* Create the table definition in InnoDB */
  750. if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
  751.    error = create_table_def(trx, form, norm_name, name2);
  752. } else {
  753. error = create_table_def(trx, form, norm_name, NULL);
  754. }
  755.    if (error) {
  756. innobase_commit_low(trx);
  757. row_mysql_unlock_data_dictionary(trx);
  758.    trx_free_for_mysql(trx);
  759.   DBUG_RETURN(error);
  760.   }
  761. /* Look for a primary key */
  762. primary_key_no= (table->primary_key != MAX_KEY ?
  763.  (int) table->primary_key : 
  764.  -1);
  765. /* Our function row_get_mysql_key_number_for_index assumes
  766. the primary key is always number 0, if it exists */
  767. DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
  768. /* Create the keys */
  769. if (form->keys == 0 || primary_key_no == -1) {
  770. /* Create an index which is used as the clustered index;
  771. order the rows by their row id which is internally generated
  772. by InnoDB */
  773. error = create_clustered_index_when_no_primary(trx,
  774. norm_name);
  775.    if (error) {
  776. innobase_commit_low(trx);
  777. row_mysql_unlock_data_dictionary(trx);
  778. trx_free_for_mysql(trx);
  779. DBUG_RETURN(error);
  780.        }
  781. }
  782. if (primary_key_no != -1) {
  783. /* In InnoDB the clustered index must always be created
  784. first */
  785.      if ((error = create_index(trx, form, norm_name,
  786.   (uint) primary_key_no))) {
  787. innobase_commit_low(trx);
  788. row_mysql_unlock_data_dictionary(trx);
  789.    trx_free_for_mysql(trx);
  790. DBUG_RETURN(error);
  791.        }
  792.        }
  793. for (i = 0; i < form->keys; i++) {
  794. if (i != (uint) primary_key_no) {
  795.      if ((error = create_index(trx, form, norm_name, i))) {
  796.    innobase_commit_low(trx);
  797. row_mysql_unlock_data_dictionary(trx);
  798.    trx_free_for_mysql(trx);
  799. DBUG_RETURN(error);
  800.        }
  801.        }
  802.    }
  803. if (current_thd->query != NULL) {
  804. LEX_STRING q;
  805. if (thd->convert_string(&q, system_charset_info,
  806. current_thd->query,
  807. current_thd->query_length,
  808. current_thd->charset())) {
  809. error = HA_ERR_OUT_OF_MEM;
  810. } else {
  811. error = row_table_add_foreign_constraints(trx,
  812. q.str, norm_name);
  813. error = convert_error_code_to_mysql(error, NULL);
  814. }
  815. if (error) {
  816. innobase_commit_low(trx);
  817. row_mysql_unlock_data_dictionary(trx);
  818.    trx_free_for_mysql(trx);
  819. DBUG_RETURN(error);
  820. }
  821. }
  822.    innobase_commit_low(trx);
  823. row_mysql_unlock_data_dictionary(trx);
  824. /* Flush the log to reduce probability that the .frm files and
  825. the InnoDB data dictionary get out-of-sync if the user runs
  826. with innodb_flush_log_at_trx_commit = 0 */
  827. log_buffer_flush_to_disk();
  828. innobase_table = dict_table_get(norm_name, NULL);
  829. DBUG_ASSERT(innobase_table != 0);
  830. if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
  831.    (create_info->auto_increment_value != 0)) {
  832. /* Query was ALTER TABLE...AUTO_INCREMENT = x; or 
  833. CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
  834. definition from the dictionary and get the current value
  835. of the auto increment field. Set a new value to the
  836. auto increment field if the value is greater than the
  837. maximum value in the column. */
  838. auto_inc_value = create_info->auto_increment_value;
  839. dict_table_autoinc_initialize(innobase_table, auto_inc_value);
  840. }
  841. /* Tell the InnoDB server that there might be work for
  842. utility threads: */
  843. srv_active_wake_master_thread();
  844.    trx_free_for_mysql(trx);
  845. DBUG_RETURN(0);
  846. }
  847. /*********************************************************************
  848. Discards or imports an InnoDB tablespace. */
  849. int
  850. ha_innobase::discard_or_import_tablespace(
  851. /*======================================*/
  852. /* out: 0 == success, -1 == error */
  853. my_bool discard) /* in: TRUE if discard, else import */
  854. {
  855. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  856. dict_table_t* dict_table;
  857. trx_t* trx;
  858. int err;
  859.   DBUG_ENTER("ha_innobase::discard_or_import_tablespace");
  860. ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
  861. ut_a(prebuilt->trx ==
  862. (trx_t*) current_thd->transaction.all.innobase_tid);
  863. dict_table = prebuilt->table;
  864. trx = prebuilt->trx;
  865. if (discard) {
  866. err = row_discard_tablespace_for_mysql(dict_table->name, trx);
  867. } else {
  868. err = row_import_tablespace_for_mysql(dict_table->name, trx);
  869. }
  870. err = convert_error_code_to_mysql(err, NULL);
  871. DBUG_RETURN(err);
  872. }
  873. /*********************************************************************
  874. Drops a table from an InnoDB database. Before calling this function,
  875. MySQL calls innobase_commit to commit the transaction of the current user.
  876. Then the current user cannot have locks set on the table. Drop table
  877. operation inside InnoDB will remove all locks any user has on the table
  878. inside InnoDB. */
  879. int
  880. ha_innobase::delete_table(
  881. /*======================*/
  882. /* out: error number */
  883. const char* name) /* in: table name */
  884. {
  885. ulint name_len;
  886. int error;
  887. trx_t* parent_trx;
  888. trx_t* trx;
  889. THD     *thd= current_thd;
  890. char norm_name[1000];
  891.   DBUG_ENTER("ha_innobase::delete_table");
  892. /* Get the transaction associated with the current thd, or create one
  893. if not yet created */
  894. parent_trx = check_trx_exists(current_thd);
  895. /* In case MySQL calls this in the middle of a SELECT query, release
  896. possible adaptive hash latch to avoid deadlocks of threads */
  897. trx_search_latch_release_if_reserved(parent_trx);
  898. if (lower_case_table_names) {
  899. srv_lower_case_table_names = TRUE;
  900. } else {
  901. srv_lower_case_table_names = FALSE;
  902. }
  903. trx = trx_allocate_for_mysql();
  904. trx->mysql_thd = current_thd;
  905. trx->mysql_query_str = &((*current_thd).query);
  906. if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
  907. trx->check_foreigns = FALSE;
  908. }
  909. if (thd->options & OPTION_RELAXED_UNIQUE_CHECKS) {
  910. trx->check_unique_secondary = FALSE;
  911. }
  912. name_len = strlen(name);
  913. assert(name_len < 1000);
  914. /* Strangely, MySQL passes the table name without the '.frm'
  915. extension, in contrast to ::create */
  916. normalize_table_name(norm_name, name);
  917.    /* Drop the table in InnoDB */
  918. error = row_drop_table_for_mysql(norm_name, trx,
  919. thd->lex->sql_command == SQLCOM_DROP_DB);
  920. /* Flush the log to reduce probability that the .frm files and
  921. the InnoDB data dictionary get out-of-sync if the user runs
  922. with innodb_flush_log_at_trx_commit = 0 */
  923. log_buffer_flush_to_disk();
  924. /* Tell the InnoDB server that there might be work for
  925. utility threads: */
  926. srv_active_wake_master_thread();
  927.    innobase_commit_low(trx);
  928.    trx_free_for_mysql(trx);
  929. error = convert_error_code_to_mysql(error, NULL);
  930. DBUG_RETURN(error);
  931. }
  932. /*********************************************************************
  933. Removes all tables in the named database inside InnoDB. */
  934. int
  935. innobase_drop_database(
  936. /*===================*/
  937. /* out: error number */
  938. char* path) /* in: database path; inside InnoDB the name
  939. of the last directory in the path is used as
  940. the database name: for example, in 'mysql/data/test'
  941. the database name is 'test' */
  942. {
  943. ulint len = 0;
  944. trx_t* parent_trx;
  945. trx_t* trx;
  946. char* ptr;
  947. int error;
  948. char* namebuf;
  949. /* Get the transaction associated with the current thd, or create one
  950. if not yet created */
  951. parent_trx = check_trx_exists(current_thd);
  952. /* In case MySQL calls this in the middle of a SELECT query, release
  953. possible adaptive hash latch to avoid deadlocks of threads */
  954. trx_search_latch_release_if_reserved(parent_trx);
  955. ptr = strend(path) - 2;
  956. while (ptr >= path && *ptr != '\' && *ptr != '/') {
  957. ptr--;
  958. len++;
  959. }
  960. ptr++;
  961. namebuf = my_malloc(len + 2, MYF(0));
  962. memcpy(namebuf, ptr, len);
  963. namebuf[len] = '/';
  964. namebuf[len + 1] = '';
  965. #ifdef  __WIN__
  966. innobase_casedn_str(namebuf);
  967. #endif
  968. trx = trx_allocate_for_mysql();
  969. trx->mysql_thd = current_thd;
  970. trx->mysql_query_str = &((*current_thd).query);
  971. if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
  972. trx->check_foreigns = FALSE;
  973. }
  974.    error = row_drop_database_for_mysql(namebuf, trx);
  975. my_free(namebuf, MYF(0));
  976. /* Flush the log to reduce probability that the .frm files and
  977. the InnoDB data dictionary get out-of-sync if the user runs
  978. with innodb_flush_log_at_trx_commit = 0 */
  979. log_buffer_flush_to_disk();
  980. /* Tell the InnoDB server that there might be work for
  981. utility threads: */
  982. srv_active_wake_master_thread();
  983.    innobase_commit_low(trx);
  984.    trx_free_for_mysql(trx);
  985. error = convert_error_code_to_mysql(error, NULL);
  986. return(error);
  987. }
  988. /*************************************************************************
  989. Renames an InnoDB table. */
  990. int
  991. ha_innobase::rename_table(
  992. /*======================*/
  993. /* out: 0 or error code */
  994. const char* from, /* in: old name of the table */
  995. const char* to) /* in: new name of the table */
  996. {
  997. ulint name_len1;
  998. ulint name_len2;
  999. int error;
  1000. trx_t* parent_trx;
  1001. trx_t* trx;
  1002. char norm_from[1000];
  1003. char norm_to[1000];
  1004.    DBUG_ENTER("ha_innobase::rename_table");
  1005. /* Get the transaction associated with the current thd, or create one
  1006. if not yet created */
  1007. parent_trx = check_trx_exists(current_thd);
  1008. /* In case MySQL calls this in the middle of a SELECT query, release
  1009. possible adaptive hash latch to avoid deadlocks of threads */
  1010. trx_search_latch_release_if_reserved(parent_trx);
  1011. if (lower_case_table_names) {
  1012. srv_lower_case_table_names = TRUE;
  1013. } else {
  1014. srv_lower_case_table_names = FALSE;
  1015. }
  1016. trx = trx_allocate_for_mysql();
  1017. trx->mysql_thd = current_thd;
  1018. trx->mysql_query_str = &((*current_thd).query);
  1019. if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
  1020. trx->check_foreigns = FALSE;
  1021. }
  1022. name_len1 = strlen(from);
  1023. name_len2 = strlen(to);
  1024. assert(name_len1 < 1000);
  1025. assert(name_len2 < 1000);
  1026. normalize_table_name(norm_from, from);
  1027. normalize_table_name(norm_to, to);
  1028.    /* Rename the table in InnoDB */
  1029.    error = row_rename_table_for_mysql(norm_from, norm_to, trx);
  1030. /* Flush the log to reduce probability that the .frm files and
  1031. the InnoDB data dictionary get out-of-sync if the user runs
  1032. with innodb_flush_log_at_trx_commit = 0 */
  1033. log_buffer_flush_to_disk();
  1034. /* Tell the InnoDB server that there might be work for
  1035. utility threads: */
  1036. srv_active_wake_master_thread();
  1037.    innobase_commit_low(trx);
  1038.    trx_free_for_mysql(trx);
  1039. error = convert_error_code_to_mysql(error, NULL);
  1040. DBUG_RETURN(error);
  1041. }
  1042. /*************************************************************************
  1043. Estimates the number of index records in a range. */
  1044. ha_rows
  1045. ha_innobase::records_in_range(
  1046. /*==========================*/
  1047. /* out: estimated number of
  1048. rows */
  1049. uint  keynr, /* in: index number */
  1050.         key_range *min_key, /* in: start key value of the
  1051.                                                    range, may also be 0 */
  1052. key_range *max_key) /* in: range end key val, may
  1053.                                                    also be 0 */
  1054. {
  1055. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1056. KEY* key;
  1057. dict_index_t* index;
  1058. mysql_byte* key_val_buff2  = (mysql_byte*) my_malloc(
  1059.   table->reclength
  1060.        + table->max_key_length + 100,
  1061. MYF(MY_WME));
  1062. ulint buff2_len = table->reclength
  1063.        + table->max_key_length + 100;
  1064. dtuple_t* range_start;
  1065. dtuple_t* range_end;
  1066. ib_longlong n_rows;
  1067. ulint mode1;
  1068. ulint mode2;
  1069. void*           heap1;
  1070. void*           heap2;
  1071.     DBUG_ENTER("records_in_range");
  1072. prebuilt->trx->op_info = (char*)"estimating records in index range";
  1073. /* In case MySQL calls this in the middle of a SELECT query, release
  1074. possible adaptive hash latch to avoid deadlocks of threads */
  1075. trx_search_latch_release_if_reserved(prebuilt->trx);
  1076. active_index = keynr;
  1077. key = table->key_info + active_index;
  1078. index = dict_table_get_index_noninline(prebuilt->table, key->name);
  1079. range_start = dtuple_create_for_mysql(&heap1, key->key_parts);
  1080.   dict_index_copy_types(range_start, index, key->key_parts);
  1081. range_end = dtuple_create_for_mysql(&heap2, key->key_parts);
  1082.   dict_index_copy_types(range_end, index, key->key_parts);
  1083. row_sel_convert_mysql_key_to_innobase(
  1084. range_start, (byte*) key_val_buff,
  1085. (ulint)upd_and_key_val_buff_len,
  1086. index,
  1087. (byte*) (min_key ? min_key->key :
  1088.                                          (const mysql_byte*) 0),
  1089. (ulint) (min_key ? min_key->length : 0),
  1090. prebuilt->trx);
  1091. row_sel_convert_mysql_key_to_innobase(
  1092. range_end, (byte*) key_val_buff2,
  1093. buff2_len, index,
  1094. (byte*) (max_key ? max_key->key :
  1095.                                          (const mysql_byte*) 0),
  1096. (ulint) (max_key ? max_key->length : 0),
  1097. prebuilt->trx);
  1098. mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
  1099.                                                 HA_READ_KEY_EXACT);
  1100. mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
  1101.                                                 HA_READ_KEY_EXACT);
  1102. n_rows = btr_estimate_n_rows_in_range(index, range_start,
  1103. mode1, range_end, mode2);
  1104. dtuple_free_for_mysql(heap1);
  1105. dtuple_free_for_mysql(heap2);
  1106.      my_free((char*) key_val_buff2, MYF(0));
  1107. prebuilt->trx->op_info = (char*)"";
  1108. /* The MySQL optimizer seems to believe an estimate of 0 rows is
  1109. always accurate and may return the result 'Empty set' based on that.
  1110. The accuracy is not guaranteed, and even if it were, for a locking
  1111. read we should anyway perform the search to set the next-key lock.
  1112. Add 1 to the value to make sure MySQL does not make the assumption! */
  1113. if (n_rows == 0) {
  1114.         n_rows = 1;
  1115. }
  1116. DBUG_RETURN((ha_rows) n_rows);
  1117. }
  1118. /*************************************************************************
  1119. Gives an UPPER BOUND to the number of rows in a table. This is used in
  1120. filesort.cc. */
  1121. ha_rows
  1122. ha_innobase::estimate_rows_upper_bound(void)
  1123. /*======================================*/
  1124. /* out: upper bound of rows */
  1125. {
  1126. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1127. dict_index_t* index;
  1128. ulonglong estimate;
  1129. ulonglong local_data_file_length;
  1130.   DBUG_ENTER("estimate_rows_upper_bound");
  1131. /* We do not know if MySQL can call this function before calling
  1132. external_lock(). To be safe, update the thd of the current table
  1133. handle. */
  1134. update_thd(current_thd);
  1135. prebuilt->trx->op_info = (char*)
  1136.                          "calculating upper bound for table rows";
  1137. /* In case MySQL calls this in the middle of a SELECT query, release
  1138. possible adaptive hash latch to avoid deadlocks of threads */
  1139. trx_search_latch_release_if_reserved(prebuilt->trx);
  1140. index = dict_table_get_first_index_noninline(prebuilt->table);
  1141. local_data_file_length = ((ulonglong) index->stat_n_leaf_pages)
  1142.      * UNIV_PAGE_SIZE;
  1143. /* Calculate a minimum length for a clustered index record and from
  1144. that an upper bound for the number of rows. Since we only calculate
  1145. new statistics in row0mysql.c when a table has grown by a threshold
  1146. factor, we must add a safety factor 2 in front of the formula below. */
  1147. estimate = 2 * local_data_file_length /
  1148.  dict_index_calc_min_rec_len(index);
  1149. prebuilt->trx->op_info = (char*)"";
  1150. DBUG_RETURN((ha_rows) estimate);
  1151. }
  1152. /*************************************************************************
  1153. How many seeks it will take to read through the table. This is to be
  1154. comparable to the number returned by records_in_range so that we can
  1155. decide if we should scan the table or use keys. */
  1156. double
  1157. ha_innobase::scan_time()
  1158. /*====================*/
  1159. /* out: estimated time measured in disk seeks */
  1160. {
  1161. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1162. /* Since MySQL seems to favor table scans too much over index
  1163. searches, we pretend that a sequential read takes the same time
  1164. as a random disk read, that is, we do not divide the following
  1165. by 10, which would be physically realistic. */
  1166. return((double) (prebuilt->table->stat_clustered_index_size));
  1167. }
  1168. /**********************************************************************
  1169. Calculate the time it takes to read a set of ranges through an index
  1170. This enables us to optimise reads for clustered indexes. */
  1171. double
  1172. ha_innobase::read_time(
  1173. /*===================*/
  1174. /* out: estimated time measured in disk seeks */
  1175. uint    index, /* in: key number */
  1176. uint ranges, /* in: how many ranges */
  1177. ha_rows rows) /* in: estimated number of rows in the ranges */
  1178. {
  1179. ha_rows total_rows;
  1180. double  time_for_scan;
  1181.   
  1182. if (index != table->primary_key)
  1183.   return handler::read_time(index, ranges, rows); // Not clustered
  1184. if (rows <= 2)
  1185.   return (double) rows;
  1186. /* Assume that the read time is proportional to the scan time for all
  1187. rows + at most one seek per range. */
  1188. time_for_scan = scan_time();
  1189. if ((total_rows = estimate_rows_upper_bound()) < rows)
  1190.   return time_for_scan;
  1191. return (ranges + (double) rows / (double) total_rows * time_for_scan);
  1192. }
  1193. /*************************************************************************
  1194. Returns statistics information of the table to the MySQL interpreter,
  1195. in various fields of the handle object. */
  1196. void
  1197. ha_innobase::info(
  1198. /*==============*/
  1199. uint flag) /* in: what information MySQL requests */
  1200. {
  1201. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1202. dict_table_t* ib_table;
  1203. dict_index_t* index;
  1204. ha_rows rec_per_key;
  1205. ib_longlong n_rows;
  1206. ulong j;
  1207. ulong i;
  1208. char path[FN_REFLEN];
  1209. os_file_stat_t  stat_info;
  1210.   DBUG_ENTER("info");
  1211.         /* If we are forcing recovery at a high level, we will suppress
  1212. statistics calculation on tables, because that may crash the
  1213. server if an index is badly corrupted. */
  1214.         if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
  1215.                 DBUG_VOID_RETURN;
  1216.         }
  1217. /* We do not know if MySQL can call this function before calling
  1218. external_lock(). To be safe, update the thd of the current table
  1219. handle. */
  1220. update_thd(current_thd);
  1221. /* In case MySQL calls this in the middle of a SELECT query, release
  1222. possible adaptive hash latch to avoid deadlocks of threads */
  1223. prebuilt->trx->op_info = (char*)"returning various info to MySQL";
  1224. trx_search_latch_release_if_reserved(prebuilt->trx);
  1225.   ib_table = prebuilt->table;
  1226.   if (flag & HA_STATUS_TIME) {
  1227.   /* In sql_show we call with this flag: update then statistics
  1228.   so that they are up-to-date */
  1229.         prebuilt->trx->op_info = (char*)"updating table statistics";
  1230.   dict_update_statistics(ib_table);
  1231. prebuilt->trx->op_info = (char*)
  1232.                           "returning various info to MySQL";
  1233. if (ib_table->space != 0) {
  1234. my_snprintf(path, sizeof(path), "%s/%s%s",
  1235.     mysql_data_home, ib_table->name,
  1236.     ".ibd");
  1237. unpack_filename(path,path);
  1238. } else {
  1239. my_snprintf(path, sizeof(path), "%s/%s%s", 
  1240.     mysql_data_home, ib_table->name,
  1241.     reg_ext);
  1242. unpack_filename(path,path);
  1243. }
  1244. /* Note that we do not know the access time of the table, 
  1245. nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
  1246. if (os_file_get_status(path,&stat_info)) {
  1247. create_time = stat_info.ctime;
  1248. }
  1249.   }
  1250. if (flag & HA_STATUS_VARIABLE) {
  1251. n_rows = ib_table->stat_n_rows;
  1252. /* Because we do not protect stat_n_rows by any mutex in a
  1253. delete, it is theoretically possible that the value can be
  1254. smaller than zero! TODO: fix this race.
  1255. The MySQL optimizer seems to assume in a left join that n_rows
  1256. is an accurate estimate if it is zero. Of course, it is not,
  1257. since we do not have any locks on the rows yet at this phase.
  1258. Since SHOW TABLE STATUS seems to call this function with the
  1259. HA_STATUS_TIME flag set, while the left join optizer does not
  1260. set that flag, we add one to a zero value if the flag is not
  1261. set. That way SHOW TABLE STATUS will show the best estimate,
  1262. while the optimizer never sees the table empty. */
  1263. if (n_rows < 0) {
  1264. n_rows = 0;
  1265. }
  1266. if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
  1267. n_rows++;
  1268. }
  1269.      records = (ha_rows)n_rows;
  1270.      deleted = 0;
  1271.      data_file_length = ((ulonglong)
  1272. ib_table->stat_clustered_index_size)
  1273.      * UNIV_PAGE_SIZE;
  1274.      index_file_length = ((ulonglong)
  1275. ib_table->stat_sum_of_other_index_sizes)
  1276.      * UNIV_PAGE_SIZE;
  1277.      delete_length = 0;
  1278.      check_time = 0;
  1279.      if (records == 0) {
  1280.      mean_rec_length = 0;
  1281.      } else {
  1282.      mean_rec_length = (ulong) (data_file_length / records);
  1283.      }
  1284.      }
  1285. if (flag & HA_STATUS_CONST) {
  1286. index = dict_table_get_first_index_noninline(ib_table);
  1287. if (prebuilt->clust_index_was_generated) {
  1288. index = dict_table_get_next_index_noninline(index);
  1289. }
  1290. for (i = 0; i < table->keys; i++) {
  1291. if (index == NULL) {
  1292. ut_print_timestamp(stderr);
  1293.         fprintf(stderr,
  1294. "  InnoDB: Error: table %s contains less indexes inside InnoDBn"
  1295. "InnoDB: than are defined in the MySQL .frm file. Have you mixed upn"
  1296. "InnoDB: .frm files from different installations? See sectionn"
  1297. "InnoDB: 15.1 at http://www.innodb.com/ibman.htmln",
  1298.    ib_table->name);
  1299. break;
  1300. }
  1301. for (j = 0; j < table->key_info[i].key_parts; j++) {
  1302. if (j + 1 > index->n_uniq) {
  1303.         ut_print_timestamp(stderr);
  1304.                 fprintf(stderr,
  1305. "  InnoDB: Error: index %s of %s has %lu columns unique inside InnoDBn"
  1306. "InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed upn"
  1307. "InnoDB: .frm files from different installations? See sectionn"
  1308. "InnoDB: 15.1 at http://www.innodb.com/ibman.htmln",
  1309. index->name,
  1310. ib_table->name,
  1311. (unsigned long) index->n_uniq,
  1312. j + 1);
  1313.         break;
  1314. }
  1315. if (index->stat_n_diff_key_vals[j + 1] == 0) {
  1316. rec_per_key = records;
  1317. } else {
  1318. rec_per_key = (ha_rows)(records /
  1319.              index->stat_n_diff_key_vals[j + 1]);
  1320. }
  1321. /* Since MySQL seems to favor table scans
  1322. too much over index searches, we pretend
  1323. index selectivity is 2 times better than
  1324. our estimate: */
  1325. rec_per_key = rec_per_key / 2;
  1326. if (rec_per_key == 0) {
  1327. rec_per_key = 1;
  1328. }
  1329.   table->key_info[i].rec_per_key[j]=
  1330.   rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
  1331.   rec_per_key;
  1332. }
  1333. index = dict_table_get_next_index_noninline(index);
  1334. }
  1335. }
  1336.    if (flag & HA_STATUS_ERRKEY) {
  1337. ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
  1338. errkey = (unsigned int) row_get_mysql_key_number_for_index(
  1339.        (dict_index_t*)
  1340.        trx_get_error_info(prebuilt->trx));
  1341.    }
  1342. prebuilt->trx->op_info = (char*)"";
  1343.    DBUG_VOID_RETURN;
  1344. }
  1345. /**************************************************************************
  1346. Updates index cardinalities of the table, based on 8 random dives into
  1347. each index tree. This does NOT calculate exact statistics on the table. */
  1348. int
  1349. ha_innobase::analyze(
  1350. /*=================*/  
  1351. /* out: returns always 0 (success) */
  1352. THD* thd, /* in: connection thread handle */
  1353. HA_CHECK_OPT* check_opt) /* in: currently ignored */
  1354. {
  1355. /* Simply call ::info() with all the flags */
  1356. info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
  1357. return(0);
  1358. }
  1359. /**************************************************************************
  1360. This is mapped to "ALTER TABLE tablename TYPE=InnoDB", which rebuilds
  1361. the table in MySQL. */
  1362. int
  1363. ha_innobase::optimize(
  1364. /*==================*/
  1365. THD* thd, /* in: connection thread handle */
  1366. HA_CHECK_OPT* check_opt) /* in: currently ignored */
  1367. {
  1368.         return(HA_ADMIN_TRY_ALTER);
  1369. }
  1370. /***********************************************************************
  1371. Tries to check that an InnoDB table is not corrupted. If corruption is
  1372. noticed, prints to stderr information about it. In case of corruption
  1373. may also assert a failure and crash the server. */
  1374. int
  1375. ha_innobase::check(
  1376. /*===============*/
  1377. /* out: HA_ADMIN_CORRUPT or
  1378. HA_ADMIN_OK */
  1379. THD*  thd, /* in: user thread handle */
  1380. HA_CHECK_OPT*  check_opt) /* in: check options, currently
  1381. ignored */
  1382. {
  1383. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1384. ulint ret;
  1385. ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
  1386. ut_a(prebuilt->trx ==
  1387. (trx_t*) current_thd->transaction.all.innobase_tid);
  1388. if (prebuilt->mysql_template == NULL) {
  1389. /* Build the template; we will use a dummy template
  1390. in index scans done in checking */
  1391. build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
  1392. }
  1393. ret = row_check_table_for_mysql(prebuilt);
  1394. if (ret == DB_SUCCESS) {
  1395. return(HA_ADMIN_OK);
  1396. }
  1397.    return(HA_ADMIN_CORRUPT); 
  1398. }
  1399. /*****************************************************************
  1400. Adds information about free space in the InnoDB tablespace to a table comment
  1401. which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
  1402. foreign keys. */
  1403. char*
  1404. ha_innobase::update_table_comment(
  1405. /*==============================*/
  1406. /* out: table comment + InnoDB free space +
  1407. info on foreign keys */
  1408.         const char* comment)/* in: table comment defined by user */
  1409. {
  1410. uint length = strlen(comment);
  1411. char* str;
  1412. row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
  1413. /* We do not know if MySQL can call this function before calling
  1414. external_lock(). To be safe, update the thd of the current table
  1415. handle. */
  1416. if(length > 64000 - 3) {
  1417. return((char*)comment); /* string too long */
  1418. }
  1419. update_thd(current_thd);
  1420. prebuilt->trx->op_info = (char*)"returning table comment";
  1421. /* In case MySQL calls this in the middle of a SELECT query, release
  1422. possible adaptive hash latch to avoid deadlocks of threads */
  1423. trx_search_latch_release_if_reserved(prebuilt->trx);
  1424. str = NULL;
  1425. if (FILE* file = os_file_create_tmpfile()) {
  1426. long flen;
  1427. /* output the data to a temporary file */
  1428. fprintf(file, "InnoDB free: %lu kB",
  1429.           (ulong) fsp_get_available_space_in_free_extents(
  1430.        prebuilt->table->space));
  1431. dict_print_info_on_foreign_keys(FALSE, file,
  1432. prebuilt->trx, prebuilt->table);
  1433. flen = ftell(file);
  1434. if (flen < 0) {
  1435. flen = 0;
  1436. } else if (length + flen + 3 > 64000) {
  1437. flen = 64000 - 3 - length;
  1438. }
  1439. /* allocate buffer for the full string, and
  1440. read the contents of the temporary file */
  1441. str = my_malloc(length + flen + 3, MYF(0));
  1442. if (str) {
  1443. char* pos = str + length;
  1444. if(length) {
  1445. memcpy(str, comment, length);
  1446. *pos++ = ';';
  1447. *pos++ = ' ';
  1448. }
  1449. rewind(file);
  1450. flen = fread(pos, 1, flen, file);
  1451. pos[flen] = 0;
  1452. }
  1453. fclose(file);
  1454. }
  1455.         prebuilt->trx->op_info = (char*)"";
  1456.    return(str ? str : (char*) comment);
  1457. }
  1458. /***********************************************************************
  1459. Gets the foreign key create info for a table stored in InnoDB. */
  1460. char*
  1461. ha_innobase::get_foreign_key_create_info(void)
  1462. /*==========================================*/
  1463. /* out, own: character string in the form which
  1464. can be inserted to the CREATE TABLE statement,
  1465. MUST be freed with ::free_foreign_key_create_info */
  1466. {
  1467. row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
  1468. char* str = 0;
  1469. ut_a(prebuilt != NULL);
  1470. /* We do not know if MySQL can call this function before calling
  1471. external_lock(). To be safe, update the thd of the current table
  1472. handle. */
  1473. update_thd(current_thd);
  1474. if (FILE* file = os_file_create_tmpfile()) {
  1475. long flen;
  1476. prebuilt->trx->op_info = (char*)"getting info on foreign keys";
  1477. /* In case MySQL calls this in the middle of a SELECT query,
  1478. release possible adaptive hash latch to avoid
  1479. deadlocks of threads */
  1480. trx_search_latch_release_if_reserved(prebuilt->trx);
  1481. /* output the data to a temporary file */
  1482. dict_print_info_on_foreign_keys(TRUE, file,
  1483. prebuilt->trx, prebuilt->table);
  1484. prebuilt->trx->op_info = (char*)"";
  1485. flen = ftell(file);
  1486. if (flen < 0) {
  1487. flen = 0;
  1488. } else if(flen > 64000 - 1) {
  1489. flen = 64000 - 1;
  1490. }
  1491. /* allocate buffer for the string, and
  1492. read the contents of the temporary file */
  1493. str = my_malloc(flen + 1, MYF(0));
  1494. if (str) {
  1495. rewind(file);
  1496. flen = fread(str, 1, flen, file);
  1497. str[flen] = 0;
  1498. }
  1499. fclose(file);
  1500. } else {
  1501. /* unable to create temporary file */
  1502.            str = my_strdup(
  1503. "/* Error: cannot display foreign key constraints */", MYF(0));
  1504. }
  1505.    return(str);
  1506. }
  1507. /*********************************************************************
  1508. Checks if ALTER TABLE may change the storage engine of the table.
  1509. Changing storage engines is not allowed for tables for which there
  1510. are foreign key constraints (parent or child tables). */
  1511. bool
  1512. ha_innobase::can_switch_engines(void)
  1513. /*=================================*/
  1514. {
  1515. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1516. bool can_switch;
  1517.   DBUG_ENTER("ha_innobase::can_switch_engines");
  1518. prebuilt->trx->op_info =
  1519. "determining if there are foreign key constraints";
  1520. row_mysql_lock_data_dictionary(prebuilt->trx);
  1521. can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
  1522. && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
  1523. row_mysql_unlock_data_dictionary(prebuilt->trx);
  1524. prebuilt->trx->op_info = "";
  1525. DBUG_RETURN(can_switch);
  1526. }
  1527. /***********************************************************************
  1528. Checks if a table is referenced by a foreign key. The MySQL manual states that
  1529. a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
  1530. delete is then allowed internally to resolve a duplicate key conflict in
  1531. REPLACE, not an update. */
  1532. uint
  1533. ha_innobase::referenced_by_foreign_key(void)
  1534. /*========================================*/
  1535. /* out: > 0 if referenced by a FOREIGN KEY */
  1536. {
  1537. row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
  1538. if (dict_table_referenced_by_foreign_key(prebuilt->table)) {
  1539. return(1);
  1540. }
  1541. return(0);
  1542. }
  1543. /***********************************************************************
  1544. Frees the foreign key create info for a table stored in InnoDB, if it is
  1545. non-NULL. */
  1546. void
  1547. ha_innobase::free_foreign_key_create_info(
  1548. /*======================================*/
  1549. char* str) /* in, own: create info string to free  */
  1550. {
  1551. if (str) {
  1552. my_free(str, MYF(0));
  1553. }
  1554. }
  1555. /***********************************************************************
  1556. Tells something additional to the handler about how to do things. */
  1557. int
  1558. ha_innobase::extra(
  1559. /*===============*/
  1560.    /* out: 0 or error number */
  1561. enum ha_extra_function operation)
  1562.                            /* in: HA_EXTRA_RETRIEVE_ALL_COLS or some
  1563.    other flag */
  1564. {
  1565. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1566. /* Warning: since it is not sure that MySQL calls external_lock
  1567. before calling this function, the trx field in prebuilt can be
  1568. obsolete! */
  1569. switch (operation) {
  1570.                 case HA_EXTRA_FLUSH:
  1571.                         if (prebuilt->blob_heap) {
  1572.                                 row_mysql_prebuilt_free_blob_heap(prebuilt);
  1573.                         }
  1574.                         break;
  1575.                 case HA_EXTRA_RESET:
  1576.                         if (prebuilt->blob_heap) {
  1577.                                 row_mysql_prebuilt_free_blob_heap(prebuilt);
  1578.                         }
  1579.                         prebuilt->read_just_key = 0;
  1580.                         break;
  1581.    case HA_EXTRA_RESET_STATE:
  1582.          prebuilt->read_just_key = 0;
  1583.               break;
  1584. case HA_EXTRA_NO_KEYREAD:
  1585.      prebuilt->read_just_key = 0;
  1586.      break;
  1587.         case HA_EXTRA_RETRIEVE_ALL_COLS:
  1588. prebuilt->hint_need_to_fetch_extra_cols
  1589. = ROW_RETRIEVE_ALL_COLS;
  1590. break;
  1591.         case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
  1592. if (prebuilt->hint_need_to_fetch_extra_cols == 0) {
  1593. prebuilt->hint_need_to_fetch_extra_cols
  1594. = ROW_RETRIEVE_PRIMARY_KEY;
  1595. }
  1596. break;
  1597.         case HA_EXTRA_KEYREAD:
  1598.          prebuilt->read_just_key = 1;
  1599.          break;
  1600. default:/* Do nothing */
  1601. ;
  1602. }
  1603. return(0);
  1604. }
  1605. /**********************************************************************
  1606. MySQL calls this function at the start of each SQL statement inside LOCK
  1607. TABLES. Inside LOCK TABLES the ::external_lock method does not work to
  1608. mark SQL statement borders. Note also a special case: if a temporary table
  1609. is created inside LOCK TABLES, MySQL has not called external_lock() at all
  1610. on that table. */
  1611. int
  1612. ha_innobase::start_stmt(
  1613. /*====================*/
  1614.               /* out: 0 or error code */
  1615. THD*    thd)  /* in: handle to the user thread */
  1616. {
  1617. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1618. trx_t* trx;
  1619. update_thd(thd);
  1620. trx = prebuilt->trx;
  1621. /* Here we release the search latch and the InnoDB thread FIFO ticket
  1622. if they were reserved. They should have been released already at the
  1623. end of the previous statement, but because inside LOCK TABLES the
  1624. lock count method does not work to mark the end of a SELECT statement,
  1625. that may not be the case. We MUST release the search latch before an
  1626. INSERT, for example. */
  1627. innobase_release_stat_resources(trx);
  1628. if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
  1629.      && trx->read_view) {
  1630.      /* At low transaction isolation levels we let
  1631. each consistent read set its own snapshot */
  1632.      read_view_close_for_mysql(trx);
  1633. }
  1634. auto_inc_counter_for_this_stat = 0;
  1635. prebuilt->sql_stat_start = TRUE;
  1636. prebuilt->hint_need_to_fetch_extra_cols = 0;
  1637. prebuilt->read_just_key = 0;
  1638. if (!prebuilt->mysql_has_locked) {
  1639.         /* This handle is for a temporary table created inside
  1640.         this same LOCK TABLES; since MySQL does NOT call external_lock
  1641.         in this case, we must use x-row locks inside InnoDB to be
  1642.         prepared for an update of a row */
  1643.   
  1644.         prebuilt->select_lock_type = LOCK_X;
  1645. } else {
  1646. if (trx->isolation_level != TRX_ISO_SERIALIZABLE
  1647.     && thd->lex->sql_command == SQLCOM_SELECT
  1648.     && thd->lex->lock_option == TL_READ) {
  1649. /* For other than temporary tables, we obtain
  1650. no lock for consistent read (plain SELECT). */
  1651. prebuilt->select_lock_type = LOCK_NONE;
  1652. } else {
  1653. /* Not a consistent read: restore the
  1654. select_lock_type value. The value of
  1655. stored_select_lock_type was decided in:
  1656. 1) ::store_lock(),
  1657. 2) ::external_lock(), and
  1658. 3) ::init_table_handle_for_HANDLER(). */
  1659. prebuilt->select_lock_type =
  1660. prebuilt->stored_select_lock_type;
  1661. }
  1662. if (prebuilt->stored_select_lock_type != LOCK_S
  1663.     && prebuilt->stored_select_lock_type != LOCK_X) {
  1664. fprintf(stderr,
  1665. "InnoDB: Error: stored_select_lock_type is %lu inside ::start_stmt()!n",
  1666. prebuilt->stored_select_lock_type);
  1667. /* Set the value to LOCK_X: this is just fault
  1668. tolerance, we do not know what the correct value
  1669. should be! */
  1670. prebuilt->select_lock_type = LOCK_X;
  1671. }
  1672. }
  1673. /* Set the MySQL flag to mark that there is an active transaction */
  1674. thd->transaction.all.innodb_active_trans = 1;
  1675. return(0);
  1676. }
  1677. /**********************************************************************
  1678. Maps a MySQL trx isolation level code to the InnoDB isolation level code */
  1679. inline
  1680. ulint
  1681. innobase_map_isolation_level(
  1682. /*=========================*/
  1683. /* out: InnoDB isolation level */
  1684. enum_tx_isolation iso) /* in: MySQL isolation level code */
  1685. {
  1686. switch(iso) {
  1687. case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
  1688. case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
  1689. case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
  1690. case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
  1691. default: ut_a(0); return(0);
  1692. }
  1693. }
  1694. /**********************************************************************
  1695. As MySQL will execute an external lock for every new table it uses when it
  1696. starts to process an SQL statement (an exception is when MySQL calls
  1697. start_stmt for the handle) we can use this function to store the pointer to
  1698. the THD in the handle. We will also use this function to communicate
  1699. to InnoDB that a new SQL statement has started and that we must store a
  1700. savepoint to our transaction handle, so that we are able to roll back
  1701. the SQL statement in case of an error. */
  1702. int
  1703. ha_innobase::external_lock(
  1704. /*=======================*/
  1705.         /* out: 0 */
  1706. THD* thd, /* in: handle to the user thread */
  1707. int  lock_type) /* in: lock type */
  1708. {
  1709. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1710. trx_t* trx;
  1711.    DBUG_ENTER("ha_innobase::external_lock");
  1712. DBUG_PRINT("enter",("lock_type: %d", lock_type));
  1713. update_thd(thd);
  1714. trx = prebuilt->trx;
  1715. prebuilt->sql_stat_start = TRUE;
  1716. prebuilt->hint_need_to_fetch_extra_cols = 0;
  1717. prebuilt->read_just_key = 0;
  1718. if (lock_type == F_WRLCK) {
  1719. /* If this is a SELECT, then it is in UPDATE TABLE ...
  1720. or SELECT ... FOR UPDATE */
  1721. prebuilt->select_lock_type = LOCK_X;
  1722. prebuilt->stored_select_lock_type = LOCK_X;
  1723. }
  1724. if (lock_type != F_UNLCK) {
  1725. /* MySQL is setting a new table lock */
  1726. /* Set the MySQL flag to mark that there is an active
  1727. transaction */
  1728. thd->transaction.all.innodb_active_trans = 1;
  1729. trx->n_mysql_tables_in_use++;
  1730. prebuilt->mysql_has_locked = TRUE;
  1731. if (trx->n_mysql_tables_in_use == 1) {
  1732.         trx->isolation_level = innobase_map_isolation_level(
  1733. (enum_tx_isolation)
  1734. thd->variables.tx_isolation);
  1735. }
  1736. if (trx->isolation_level == TRX_ISO_SERIALIZABLE
  1737.     && prebuilt->select_lock_type == LOCK_NONE
  1738.     && (thd->options
  1739. & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
  1740. /* To get serializable execution, we let InnoDB
  1741. conceptually add 'LOCK IN SHARE MODE' to all SELECTs
  1742. which otherwise would have been consistent reads. An
  1743. exception is consistent reads in the AUTOCOMMIT=1 mode:
  1744. we know that they are read-only transactions, and they
  1745. can be serialized also if performed as consistent
  1746. reads. */
  1747. prebuilt->select_lock_type = LOCK_S;
  1748. }
  1749. /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
  1750. TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
  1751. an InnoDB table lock if it is released immediately at the end
  1752. of LOCK TABLES, and InnoDB's table locks in that case cause
  1753. VERY easily deadlocks. */
  1754. if (prebuilt->select_lock_type != LOCK_NONE) {
  1755. if (thd->in_lock_tables &&
  1756.     thd->variables.innodb_table_locks &&
  1757.     (thd->options & OPTION_NOT_AUTOCOMMIT)) {
  1758. ulint error;
  1759. error = row_lock_table_for_mysql(prebuilt,
  1760. NULL, LOCK_TABLE_EXP);
  1761. if (error != DB_SUCCESS) {
  1762. error = convert_error_code_to_mysql(
  1763. error, user_thd);
  1764. DBUG_RETURN(error);
  1765. }
  1766. }
  1767.    trx->mysql_n_tables_locked++;
  1768. }
  1769. DBUG_RETURN(0);
  1770. }
  1771. /* MySQL is releasing a table lock */
  1772. trx->n_mysql_tables_in_use--;
  1773. prebuilt->mysql_has_locked = FALSE;
  1774. auto_inc_counter_for_this_stat = 0;
  1775. if (trx->n_lock_table_exp) {
  1776. row_unlock_tables_for_mysql(trx);
  1777. }
  1778. /* If the MySQL lock count drops to zero we know that the current SQL
  1779. statement has ended */
  1780. if (trx->n_mysql_tables_in_use == 0) {
  1781.         trx->mysql_n_tables_locked = 0;
  1782. prebuilt->used_in_HANDLER = FALSE;
  1783. /* Release a possible FIFO ticket and search latch. Since we
  1784. may reserve the kernel mutex, we have to release the search
  1785. system latch first to obey the latching order. */
  1786. innobase_release_stat_resources(trx);
  1787. if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
  1788. if (thd->transaction.all.innodb_active_trans != 0) {
  1789.              innobase_commit(thd, trx);
  1790. }
  1791. } else {
  1792. if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
  1793.      && trx->read_view) {
  1794. /* At low transaction isolation levels we let
  1795. each consistent read set its own snapshot */
  1796. read_view_close_for_mysql(trx);
  1797. }
  1798. }
  1799. }
  1800. DBUG_RETURN(0);
  1801. }
  1802. /****************************************************************************
  1803. Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
  1804. Monitor to the client. */
  1805. int
  1806. innodb_show_status(
  1807. /*===============*/
  1808. THD* thd) /* in: the MySQL query thread of the caller */
  1809. {
  1810. Protocol* protocol = thd->protocol;
  1811. trx_t* trx;
  1812. static const char truncated_msg[] = "... truncated...n";
  1813. const long MAX_STATUS_SIZE = 64000;
  1814. ulint trx_list_start = ULINT_UNDEFINED;
  1815. ulint trx_list_end = ULINT_UNDEFINED;
  1816.         DBUG_ENTER("innodb_show_status");
  1817.         if (have_innodb != SHOW_OPTION_YES) {
  1818.                 my_message(ER_NOT_SUPPORTED_YET,
  1819.           "Cannot call SHOW INNODB STATUS because skip-innodb is defined",
  1820.                            MYF(0));
  1821.                 DBUG_RETURN(-1);
  1822.         }
  1823. trx = check_trx_exists(thd);
  1824. innobase_release_stat_resources(trx);
  1825. /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
  1826. bytes of text. */
  1827. long flen, usable_len;
  1828. char* str;
  1829. mutex_enter_noninline(&srv_monitor_file_mutex);
  1830. rewind(srv_monitor_file);
  1831. srv_printf_innodb_monitor(srv_monitor_file,
  1832. &trx_list_start, &trx_list_end);
  1833. flen = ftell(srv_monitor_file);
  1834. os_file_set_eof(srv_monitor_file);
  1835. if (flen < 0) {
  1836. flen = 0;
  1837. }
  1838. if (flen > MAX_STATUS_SIZE) {
  1839. usable_len = MAX_STATUS_SIZE;
  1840. } else {
  1841. usable_len = flen;
  1842. }
  1843. /* allocate buffer for the string, and
  1844. read the contents of the temporary file */
  1845. if (!(str = my_malloc(usable_len + 1, MYF(0))))
  1846.         {
  1847.           mutex_exit_noninline(&srv_monitor_file_mutex);
  1848.           DBUG_RETURN(-1);
  1849.         }
  1850. rewind(srv_monitor_file);
  1851. if (flen < MAX_STATUS_SIZE) {
  1852. /* Display the entire output. */
  1853. flen = fread(str, 1, flen, srv_monitor_file);
  1854. } else if (trx_list_end < (ulint) flen
  1855. && trx_list_start < trx_list_end
  1856. && trx_list_start + (flen - trx_list_end)
  1857. < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
  1858. /* Omit the beginning of the list of active transactions. */
  1859. long len = fread(str, 1, trx_list_start, srv_monitor_file);
  1860. memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
  1861. len += sizeof truncated_msg - 1;
  1862. usable_len = (MAX_STATUS_SIZE - 1) - len;
  1863. fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
  1864. len += fread(str + len, 1, usable_len, srv_monitor_file);
  1865. flen = len;
  1866. } else {
  1867. /* Omit the end of the output. */
  1868. flen = fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
  1869. }
  1870. mutex_exit_noninline(&srv_monitor_file_mutex);
  1871. List<Item> field_list;
  1872. field_list.push_back(new Item_empty_string("Status", flen));
  1873. if (protocol->send_fields(&field_list, 1)) {
  1874. my_free(str, MYF(0));
  1875. DBUG_RETURN(-1);
  1876. }
  1877.         protocol->prepare_for_resend();
  1878.         protocol->store(str, flen, system_charset_info);
  1879.         my_free(str, MYF(0));
  1880.         if (protocol->write())
  1881.           DBUG_RETURN(-1);
  1882. send_eof(thd);
  1883.    DBUG_RETURN(0);
  1884. }
  1885. /****************************************************************************
  1886.  Handling the shared INNOBASE_SHARE structure that is needed to provide table
  1887.  locking.
  1888. ****************************************************************************/
  1889. static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
  1890.       my_bool not_used __attribute__((unused)))
  1891. {
  1892.   *length=share->table_name_length;
  1893.   return (mysql_byte*) share->table_name;
  1894. }
  1895. static INNOBASE_SHARE *get_share(const char *table_name)
  1896. {
  1897.   INNOBASE_SHARE *share;
  1898.   pthread_mutex_lock(&innobase_mutex);
  1899.   uint length=(uint) strlen(table_name);
  1900.   if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables,
  1901. (mysql_byte*) table_name,
  1902.     length)))
  1903.   {
  1904.     if ((share=(INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
  1905.        MYF(MY_WME | MY_ZEROFILL))))
  1906.     {
  1907.       share->table_name_length=length;
  1908.       share->table_name=(char*) (share+1);
  1909.       strmov(share->table_name,table_name);
  1910.       if (my_hash_insert(&innobase_open_tables, (mysql_byte*) share))
  1911.       {
  1912. pthread_mutex_unlock(&innobase_mutex);
  1913. my_free((gptr) share,0);
  1914. return 0;
  1915.       }
  1916.       thr_lock_init(&share->lock);
  1917.       pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
  1918.     }
  1919.   }
  1920.   share->use_count++;
  1921.   pthread_mutex_unlock(&innobase_mutex);
  1922.   return share;
  1923. }
  1924. static void free_share(INNOBASE_SHARE *share)
  1925. {
  1926.   pthread_mutex_lock(&innobase_mutex);
  1927.   if (!--share->use_count)
  1928.   {
  1929.     hash_delete(&innobase_open_tables, (mysql_byte*) share);
  1930.     thr_lock_delete(&share->lock);
  1931.     pthread_mutex_destroy(&share->mutex);
  1932.     my_free((gptr) share, MYF(0));
  1933.   }
  1934.   pthread_mutex_unlock(&innobase_mutex);
  1935. }
  1936. /*********************************************************************
  1937. Converts a MySQL table lock stored in the 'lock' field of the handle to
  1938. a proper type before storing pointer to the lock into an array of pointers.
  1939. MySQL also calls this if it wants to reset some table locks to a not-locked
  1940. state during the processing of an SQL query. An example is that during a
  1941. SELECT the read lock is released early on the 'const' tables where we only
  1942. fetch one row. MySQL does not call this when it releases all locks at the
  1943. end of an SQL statement. */
  1944. THR_LOCK_DATA**
  1945. ha_innobase::store_lock(
  1946. /*====================*/
  1947. /* out: pointer to the next
  1948. element in the 'to' array */
  1949. THD* thd, /* in: user thread handle */
  1950. THR_LOCK_DATA** to, /* in: pointer to an array
  1951. of pointers to lock structs;
  1952. pointer to the 'lock' field
  1953. of current handle is stored
  1954. next to this array */
  1955. enum thr_lock_type  lock_type) /* in: lock type to store in
  1956. 'lock' */
  1957. {
  1958. row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  1959. if ((lock_type == TL_READ && thd->in_lock_tables) ||
  1960.     (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
  1961.     lock_type == TL_READ_WITH_SHARED_LOCKS ||
  1962.     lock_type == TL_READ_NO_INSERT ||
  1963.     (thd->lex->sql_command != SQLCOM_SELECT
  1964.      && lock_type != TL_IGNORE)) {
  1965. /* The OR cases above are in this order:
  1966. 1) MySQL is doing LOCK TABLES ... READ LOCAL, or
  1967. 2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
  1968. 3) this is a SELECT ... IN SHARE MODE, or
  1969. 4) we are doing a complex SQL statement like
  1970. INSERT INTO ... SELECT ... and the logical logging (MySQL
  1971. binlog) requires the use of a locking read, or
  1972. MySQL is doing LOCK TABLES ... READ.
  1973. 5) we let InnoDB do locking reads for all SQL statements that
  1974. are not simple SELECTs; note that select_lock_type in this
  1975. case may get strengthened in ::external_lock() to LOCK_X. */
  1976. if (srv_locks_unsafe_for_binlog &&
  1977.     prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE &&
  1978.     (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) &&
  1979.     thd->lex->sql_command != SQLCOM_SELECT &&
  1980.     thd->lex->sql_command != SQLCOM_UPDATE_MULTI &&
  1981.     thd->lex->sql_command != SQLCOM_DELETE_MULTI &&
  1982.     thd->lex->sql_command != SQLCOM_LOCK_TABLES) {
  1983. /* In case we have innobase_locks_unsafe_for_binlog
  1984. option set and isolation level of the transaction
  1985. is not set to serializable and MySQL is doing
  1986. INSERT INTO...SELECT or UPDATE ... = (SELECT ...)
  1987. without FOR UPDATE or IN SHARE MODE in select, then
  1988. we use consistent read for select. */
  1989. prebuilt->select_lock_type = LOCK_NONE;
  1990. prebuilt->stored_select_lock_type = LOCK_NONE;
  1991. } else if (thd->lex->sql_command == SQLCOM_CHECKSUM) {
  1992. /* Use consistent read for checksum table and
  1993. convert lock type to the TL_READ */
  1994. prebuilt->select_lock_type = LOCK_NONE;
  1995. prebuilt->stored_select_lock_type = LOCK_NONE;
  1996. lock.type = TL_READ;
  1997. } else {
  1998. prebuilt->select_lock_type = LOCK_S;
  1999. prebuilt->stored_select_lock_type = LOCK_S;
  2000. }
  2001. } else if (lock_type != TL_IGNORE) {
  2002.         /* In ha_berkeley.cc there is a comment that MySQL
  2003.         may in exceptional cases call this with TL_IGNORE also
  2004.         when it is NOT going to release the lock. */
  2005.         /* We set possible LOCK_X value in external_lock, not yet
  2006. here even if this would be SELECT ... FOR UPDATE */
  2007. prebuilt->select_lock_type = LOCK_NONE;
  2008. prebuilt->stored_select_lock_type = LOCK_NONE;
  2009. }
  2010. if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
  2011. if (lock_type == TL_READ && thd->in_lock_tables) {
  2012. /* We come here if MySQL is processing LOCK TABLES
  2013. ... READ LOCAL. MyISAM under that table lock type
  2014. reads the table as it was at the time the lock was
  2015. granted (new inserts are allowed, but not seen by the
  2016. reader). To get a similar effect on an InnoDB table,
  2017. we must use LOCK TABLES ... READ. We convert the lock
  2018. type here, so that for InnoDB, READ LOCAL is
  2019. equivalent to READ. This will change the InnoDB
  2020. behavior in mysqldump, so that dumps of InnoDB tables
  2021. are consistent with dumps of MyISAM tables. */
  2022. lock_type = TL_READ_NO_INSERT;
  2023. }
  2024.      /* If we are not doing a LOCK TABLE or DISCARD/IMPORT
  2025. TABLESPACE, then allow multiple writers */
  2026.      if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
  2027.       lock_type <= TL_WRITE) && !thd->in_lock_tables
  2028.     && !thd->tablespace_op
  2029.                     && thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
  2030.        lock_type = TL_WRITE_ALLOW_WRITE;
  2031.        }
  2032. /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
  2033. MySQL would use the lock TL_READ_NO_INSERT on t2, and that
  2034. would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
  2035. to t2. Convert the lock to a normal read lock to allow
  2036. concurrent inserts to t2. */
  2037.       
  2038. if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) {
  2039. lock_type = TL_READ;
  2040. }
  2041.   lock.type=lock_type;
  2042.    }
  2043.    *to++= &lock;
  2044. return(to);
  2045. }
  2046. /***********************************************************************
  2047. This function initializes the auto-inc counter if it has not been
  2048. initialized yet. This function does not change the value of the auto-inc
  2049. counter if it already has been initialized. In paramete ret returns
  2050. the value of the auto-inc counter. */
  2051. int
  2052. ha_innobase::innobase_read_and_init_auto_inc(
  2053. /*=========================================*/
  2054. /* out: 0 or error code: deadlock or
  2055. lock wait timeout */
  2056. longlong* ret) /* out: auto-inc value */
  2057. {
  2058.    row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
  2059.      longlong        auto_inc;
  2060.    int      error;
  2061.    ut_a(prebuilt);
  2062. ut_a(prebuilt->trx ==
  2063. (trx_t*) current_thd->transaction.all.innobase_tid);
  2064. ut_a(prebuilt->table);
  2065. /* In case MySQL calls this in the middle of a SELECT query, release
  2066. possible adaptive hash latch to avoid deadlocks of threads */
  2067. trx_search_latch_release_if_reserved(prebuilt->trx);
  2068. auto_inc = dict_table_autoinc_read(prebuilt->table);
  2069. if (auto_inc != 0) {
  2070. /* Already initialized */
  2071. *ret = auto_inc;
  2072. return(0);
  2073. }
  2074. error = row_lock_table_autoinc_for_mysql(prebuilt);
  2075. if (error != DB_SUCCESS) {
  2076. error = convert_error_code_to_mysql(error, user_thd);
  2077. goto func_exit;
  2078. }
  2079. /* Check again if someone has initialized the counter meanwhile */
  2080. auto_inc = dict_table_autoinc_read(prebuilt->table);
  2081. if (auto_inc != 0) {
  2082. *ret = auto_inc;
  2083. return(0);
  2084. }
  2085.    (void) extra(HA_EXTRA_KEYREAD);
  2086.    index_init(table->next_number_index);
  2087. /* We use an exclusive lock when we read the max key value from the
  2088.    auto-increment column index. This is because then build_template will
  2089.    advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
  2090.    id of the auto-increment column is not changed, and previously InnoDB
  2091.    did not fetch it, causing SHOW TABLE STATUS to show wrong values
  2092.    for the autoinc column. */
  2093.    prebuilt->select_lock_type = LOCK_X;
  2094.    /* Play safe and also give in another way the hint to fetch
  2095.    all columns in the key: */
  2096.   
  2097. prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
  2098. prebuilt->trx->mysql_n_tables_locked += 1;
  2099.   
  2100. error = index_last(table->record[1]);
  2101.    if (error) {
  2102. if (error == HA_ERR_END_OF_FILE) {
  2103. /* The table was empty, initialize to 1 */
  2104. auto_inc = 1;
  2105. error = 0;
  2106. } else {
  2107. /* Deadlock or a lock wait timeout */
  2108.    auto_inc = -1;
  2109.    goto func_exit;
  2110.    }
  2111.    } else {
  2112. /* Initialize to max(col) + 1 */
  2113.      auto_inc = (longlong) table->next_number_field->
  2114.                          val_int_offset(table->rec_buff_length) + 1;
  2115.    }
  2116. dict_table_autoinc_initialize(prebuilt->table, auto_inc);
  2117. func_exit:
  2118.    (void) extra(HA_EXTRA_NO_KEYREAD);
  2119. index_end();
  2120. *ret = auto_inc;
  2121.    return(error);
  2122. }
  2123. /***********************************************************************
  2124. This function initializes the auto-inc counter if it has not been
  2125. initialized yet. This function does not change the value of the auto-inc
  2126. counter if it already has been initialized. Returns the value of the
  2127. auto-inc counter. */
  2128. longlong
  2129. ha_innobase::get_auto_increment()
  2130. /*=============================*/
  2131.                          /* out: auto-increment column value, -1 if error
  2132.                          (deadlock or lock wait timeout) */
  2133. {
  2134.    longlong        nr;
  2135.    int      error;
  2136. error = innobase_read_and_init_auto_inc(&nr);
  2137. if (error) {
  2138. return(-1);
  2139. }
  2140. return(nr);
  2141. }
  2142. /***********************************************************************
  2143. This function stores the binlog offset and flushes logs. */
  2144. void 
  2145. innobase_store_binlog_offset_and_flush_log(
  2146. /*=======================================*/
  2147.     char  *binlog_name, /* in: binlog name */
  2148.     longlong  offset) /* in: binlog offset */
  2149. {
  2150. mtr_t mtr;
  2151. assert(binlog_name != NULL);
  2152. /* Start a mini-transaction */
  2153.         mtr_start_noninline(&mtr); 
  2154. /* Update the latest MySQL binlog name and offset info
  2155.         in trx sys header */
  2156.         trx_sys_update_mysql_binlog_offset(
  2157.             binlog_name,
  2158.             offset,
  2159.             TRX_SYS_MYSQL_LOG_INFO, &mtr);
  2160.         /* Commits the mini-transaction */
  2161.         mtr_commit(&mtr);
  2162.         
  2163. /* Syncronous flush of the log buffer to disk */
  2164. log_buffer_flush_to_disk();
  2165. }
  2166. char*
  2167. ha_innobase::get_mysql_bin_log_name()
  2168. {
  2169. return(trx_sys_mysql_bin_log_name);
  2170. }
  2171. ulonglong
  2172. ha_innobase::get_mysql_bin_log_pos()
  2173. {
  2174.    /* trx... is ib_longlong, which is a typedef for a 64-bit integer
  2175. (__int64 or longlong) so it's ok to cast it to ulonglong. */
  2176.    return(trx_sys_mysql_bin_log_pos);
  2177. }
  2178. extern "C" {
  2179. /**********************************************************************
  2180. This function is used to find the storage length in bytes of the first n
  2181. characters for prefix indexes using a multibyte character set. The function
  2182. finds charset information and returns length of prefix_len characters in the
  2183. index field in bytes.
  2184. NOTE: the prototype of this function is copied to data0type.c! If you change
  2185. this function, you MUST change also data0type.c! */
  2186. ulint
  2187. innobase_get_at_most_n_mbchars(
  2188. /*===========================*/
  2189. /* out: number of bytes occupied by the first
  2190. n characters */
  2191. ulint charset_id, /* in: character set id */
  2192. ulint prefix_len, /* in: prefix length in bytes of the index
  2193. (this has to be divided by mbmaxlen to get the
  2194. number of CHARACTERS n in the prefix) */
  2195. ulint data_len,         /* in: length of the string in bytes */
  2196. const char* str) /* in: character string */
  2197. {
  2198. ulint char_length; /* character length in bytes */
  2199. ulint n_chars; /* number of characters in prefix */
  2200. CHARSET_INFO* charset; /* charset used in the field */
  2201. charset = get_charset(charset_id, MYF(MY_WME));
  2202. ut_ad(charset);
  2203. ut_ad(charset->mbmaxlen);
  2204. /* Calculate how many characters at most the prefix index contains */
  2205. n_chars = prefix_len / charset->mbmaxlen;
  2206. /* If the charset is multi-byte, then we must find the length of the
  2207. first at most n chars in the string. If the string contains less
  2208. characters than n, then we return the length to the end of the last
  2209. character. */
  2210. if (charset->mbmaxlen > 1) {
  2211. /* my_charpos() returns the byte length of the first n_chars
  2212. characters, or a value bigger than the length of str, if
  2213. there were not enough full characters in str.
  2214. Why does the code below work:
  2215. Suppose that we are looking for n UTF-8 characters.
  2216. 1) If the string is long enough, then the prefix contains at
  2217. least n complete UTF-8 characters + maybe some extra
  2218. characters + an incomplete UTF-8 character. No problem in
  2219. this case. The function returns the pointer to the
  2220. end of the nth character.
  2221. 2) If the string is not long enough, then the string contains
  2222. the complete value of a column, that is, only complete UTF-8
  2223. characters, and we can store in the column prefix index the
  2224. whole string. */
  2225. char_length = my_charpos(charset, str,
  2226. str + data_len, n_chars);
  2227. if (char_length > data_len) {
  2228. char_length = data_len;
  2229. }
  2230. } else {
  2231. if (data_len < prefix_len) {
  2232. char_length = data_len;
  2233. } else {
  2234. char_length = prefix_len;
  2235. }
  2236. }
  2237. return(char_length);
  2238. }
  2239. }
  2240. extern "C" {
  2241. /**********************************************************************
  2242. This function returns true if 
  2243. 1) SQL-query in the current thread
  2244. is either REPLACE or LOAD DATA INFILE REPLACE. 
  2245. 2) SQL-query in the current thread
  2246. is INSERT ON DUPLICATE KEY UPDATE.
  2247. NOTE that /mysql/innobase/row/row0ins.c must contain the 
  2248. prototype for this function ! */
  2249. ibool
  2250. innobase_query_is_update(void)
  2251. /*==========================*/
  2252. {
  2253. THD* thd;
  2254. thd = (THD *)innobase_current_thd();
  2255. if ( thd->lex->sql_command == SQLCOM_REPLACE ||
  2256.      thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
  2257.      ( thd->lex->sql_command == SQLCOM_LOAD &&
  2258.        thd->lex->duplicates == DUP_REPLACE )) {
  2259. return(1);
  2260. }
  2261. if ( thd->lex->sql_command == SQLCOM_INSERT &&
  2262.      thd->lex->duplicates  == DUP_UPDATE ) {
  2263. return(1);
  2264. }
  2265. return(0);
  2266. }
  2267. }
  2268. #endif /* HAVE_INNOBASE_DB */