00001 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* Handler-calling-functions */ 00019 00020 #ifdef USE_PRAGMA_IMPLEMENTATION 00021 #pragma implementation // gcc: Class implementation 00022 #endif 00023 00024 #include "mysql_priv.h" 00025 #include "rpl_filter.h" 00026 #include "ha_heap.h" 00027 #include "ha_myisam.h" 00028 #include "ha_myisammrg.h" 00029 00030 00031 #include <myisampack.h> 00032 #include <errno.h> 00033 00034 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 00035 #define NDB_MAX_ATTRIBUTES_IN_TABLE 128 00036 #include "ha_ndbcluster.h" 00037 #endif 00038 00039 #ifdef WITH_PARTITION_STORAGE_ENGINE 00040 #include "ha_partition.h" 00041 #endif 00042 00043 #ifdef WITH_INNOBASE_STORAGE_ENGINE 00044 #include "ha_innodb.h" 00045 #endif 00046 00047 /* 00048 While we have legacy_db_type, we have this array to 00049 check for dups and to find handlerton from legacy_db_type. 00050 Remove when legacy_db_type is finally gone 00051 */ 00052 st_plugin_int *hton2plugin[MAX_HA]; 00053 00054 static handlerton *installed_htons[128]; 00055 00056 #define BITMAP_STACKBUF_SIZE (128/8) 00057 00058 KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} }; 00059 00060 /* static functions defined in this file */ 00061 00062 static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root); 00063 00064 static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; 00065 00066 /* number of entries in handlertons[] */ 00067 ulong total_ha= 0; 00068 /* number of storage engines (from handlertons[]) that support 2pc */ 00069 ulong total_ha_2pc= 0; 00070 /* size of savepoint storage area (see ha_init) */ 00071 ulong savepoint_alloc_size= 0; 00072 00073 static const LEX_STRING sys_table_aliases[]= 00074 { 00075 { C_STRING_WITH_LEN("INNOBASE") }, { C_STRING_WITH_LEN("INNODB") }, 00076 { C_STRING_WITH_LEN("NDB") }, { C_STRING_WITH_LEN("NDBCLUSTER") }, 00077 { C_STRING_WITH_LEN("HEAP") }, { C_STRING_WITH_LEN("MEMORY") }, 00078 { C_STRING_WITH_LEN("MERGE") }, { C_STRING_WITH_LEN("MRG_MYISAM") }, 00079 {NullS, 0} 00080 }; 00081 00082 const char *ha_row_type[] = { 00083 "", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "?","?","?" 00084 }; 00085 00086 const char *tx_isolation_names[] = 00087 { "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE", 00088 NullS}; 00089 TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"", 00090 tx_isolation_names, NULL}; 00091 00092 static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; 00093 uint known_extensions_id= 0; 00094 00095 00096 /* 00097 Return the default storage engine handlerton for thread 00098 00099 SYNOPSIS 00100 ha_default_handlerton(thd) 00101 thd current thread 00102 00103 RETURN 00104 pointer to handlerton 00105 */ 00106 00107 handlerton *ha_default_handlerton(THD *thd) 00108 { 00109 return (thd->variables.table_type != NULL) ? 00110 thd->variables.table_type : 00111 (global_system_variables.table_type != NULL ? 00112 global_system_variables.table_type : &myisam_hton); 00113 } 00114 00115 00116 /* 00117 Return the storage engine handlerton for the supplied name 00118 00119 SYNOPSIS 00120 ha_resolve_by_name(thd, name) 00121 thd current thread 00122 name name of storage engine 00123 00124 RETURN 00125 pointer to handlerton 00126 */ 00127 00128 handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name) 00129 { 00130 const LEX_STRING *table_alias; 00131 st_plugin_int *plugin; 00132 00133 redo: 00134 /* my_strnncoll is a macro and gcc doesn't do early expansion of macro */ 00135 if (thd && !my_charset_latin1.coll->strnncoll(&my_charset_latin1, 00136 (const uchar *)name->str, name->length, 00137 (const uchar *)STRING_WITH_LEN("DEFAULT"), 0)) 00138 return ha_default_handlerton(thd); 00139 00140 if ((plugin= plugin_lock(name, MYSQL_STORAGE_ENGINE_PLUGIN))) 00141 { 00142 handlerton *hton= (handlerton *)plugin->data; 00143 if (!(hton->flags & HTON_NOT_USER_SELECTABLE)) 00144 return hton; 00145 plugin_unlock(plugin); 00146 } 00147 00148 /* 00149 We check for the historical aliases. 00150 */ 00151 for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2) 00152 { 00153 if (!my_strnncoll(&my_charset_latin1, 00154 (const uchar *)name->str, name->length, 00155 (const uchar *)table_alias->str, table_alias->length)) 00156 { 00157 name= table_alias + 1; 00158 goto redo; 00159 } 00160 } 00161 00162 return NULL; 00163 } 00164 00165 00166 const char *ha_get_storage_engine(enum legacy_db_type db_type) 00167 { 00168 switch (db_type) { 00169 case DB_TYPE_DEFAULT: 00170 return "DEFAULT"; 00171 default: 00172 if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT && 00173 installed_htons[db_type]) 00174 return hton2plugin[installed_htons[db_type]->slot]->name.str; 00175 /* fall through */ 00176 case DB_TYPE_UNKNOWN: 00177 return "UNKNOWN"; 00178 } 00179 } 00180 00181 00182 static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root) 00183 { 00184 handlerton *hton= ha_default_handlerton(current_thd); 00185 return (hton && hton->create) ? hton->create(table, mem_root) : NULL; 00186 } 00187 00188 00189 handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) 00190 { 00191 switch (db_type) { 00192 case DB_TYPE_DEFAULT: 00193 return ha_default_handlerton(thd); 00194 case DB_TYPE_UNKNOWN: 00195 return NULL; 00196 default: 00197 if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT) 00198 return installed_htons[db_type]; 00199 return NULL; 00200 } 00201 } 00202 00203 00204 /* Use other database handler if databasehandler is not compiled in */ 00205 00206 handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, 00207 bool no_substitute, bool report_error) 00208 { 00209 handlerton *hton= ha_resolve_by_legacy_type(thd, database_type); 00210 if (ha_storage_engine_is_enabled(hton)) 00211 return hton; 00212 00213 if (no_substitute) 00214 { 00215 if (report_error) 00216 { 00217 const char *engine_name= ha_get_storage_engine(database_type); 00218 my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name); 00219 } 00220 return NULL; 00221 } 00222 00223 switch (database_type) { 00224 #ifndef NO_HASH 00225 case DB_TYPE_HASH: 00226 return ha_resolve_by_legacy_type(thd, DB_TYPE_HASH); 00227 #endif 00228 case DB_TYPE_MRG_ISAM: 00229 return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM); 00230 default: 00231 break; 00232 } 00233 00234 return ha_default_handlerton(thd); 00235 } /* ha_checktype */ 00236 00237 00238 handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, 00239 handlerton *db_type) 00240 { 00241 handler *file; 00242 DBUG_ENTER("get_new_handler"); 00243 DBUG_PRINT("enter", ("alloc: 0x%lx", (long) alloc)); 00244 00245 if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create) 00246 { 00247 if ((file= db_type->create(share, alloc))) 00248 file->init(); 00249 DBUG_RETURN(file); 00250 } 00251 /* 00252 Try the default table type 00253 Here the call to current_thd() is ok as we call this function a lot of 00254 times but we enter this branch very seldom. 00255 */ 00256 DBUG_RETURN(get_new_handler(share, alloc, 00257 current_thd->variables.table_type)); 00258 } 00259 00260 00261 #ifdef WITH_PARTITION_STORAGE_ENGINE 00262 handler *get_ha_partition(partition_info *part_info) 00263 { 00264 ha_partition *partition; 00265 DBUG_ENTER("get_ha_partition"); 00266 if ((partition= new ha_partition(part_info))) 00267 { 00268 if (partition->initialise_partition(current_thd->mem_root)) 00269 { 00270 delete partition; 00271 partition= 0; 00272 } 00273 else 00274 partition->init(); 00275 } 00276 else 00277 { 00278 my_error(ER_OUTOFMEMORY, MYF(0), sizeof(ha_partition)); 00279 } 00280 DBUG_RETURN(((handler*) partition)); 00281 } 00282 #endif 00283 00284 00285 /* 00286 Register handler error messages for use with my_error(). 00287 00288 SYNOPSIS 00289 ha_init_errors() 00290 00291 RETURN 00292 0 OK 00293 != 0 Error 00294 */ 00295 00296 static int ha_init_errors(void) 00297 { 00298 #define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg) 00299 const char **errmsgs; 00300 00301 /* Allocate a pointer array for the error message strings. */ 00302 /* Zerofill it to avoid uninitialized gaps. */ 00303 if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*), 00304 MYF(MY_WME | MY_ZEROFILL)))) 00305 return 1; 00306 00307 /* Set the dedicated error messages. */ 00308 SETMSG(HA_ERR_KEY_NOT_FOUND, ER(ER_KEY_NOT_FOUND)); 00309 SETMSG(HA_ERR_FOUND_DUPP_KEY, ER(ER_DUP_KEY)); 00310 SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable"); 00311 SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function"); 00312 SETMSG(HA_ERR_CRASHED, ER(ER_NOT_KEYFILE)); 00313 SETMSG(HA_ERR_WRONG_IN_RECORD, ER(ER_CRASHED_ON_USAGE)); 00314 SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory"); 00315 SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'"); 00316 SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported"); 00317 SETMSG(HA_ERR_OLD_FILE, ER(ER_OLD_KEYFILE)); 00318 SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update"); 00319 SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted"); 00320 SETMSG(HA_ERR_RECORD_FILE_FULL, ER(ER_RECORD_FILE_FULL)); 00321 SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'"); 00322 SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last"); 00323 SETMSG(HA_ERR_UNSUPPORTED, ER(ER_ILLEGAL_HA)); 00324 SETMSG(HA_ERR_TO_BIG_ROW, "Too big row"); 00325 SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option"); 00326 SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER(ER_DUP_UNIQUE)); 00327 SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset"); 00328 SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER(ER_WRONG_MRG_TABLE)); 00329 SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER(ER_CRASHED_ON_REPAIR)); 00330 SETMSG(HA_ERR_CRASHED_ON_USAGE, ER(ER_CRASHED_ON_USAGE)); 00331 SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER(ER_LOCK_WAIT_TIMEOUT)); 00332 SETMSG(HA_ERR_LOCK_TABLE_FULL, ER(ER_LOCK_TABLE_FULL)); 00333 SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION)); 00334 SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK)); 00335 SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN)); 00336 SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2)); 00337 SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2)); 00338 SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name"); 00339 SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size"); 00340 SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'"); 00341 SETMSG(HA_ERR_TABLE_EXIST, ER(ER_TABLE_EXISTS_ERROR)); 00342 SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine"); 00343 SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED)); 00344 SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, "FK constraint would lead to duplicate key"); 00345 SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER(ER_TABLE_NEEDS_UPGRADE)); 00346 SETMSG(HA_ERR_TABLE_READONLY, ER(ER_OPEN_AS_READONLY)); 00347 00348 /* Register the error messages for use with my_error(). */ 00349 return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST); 00350 } 00351 00352 00353 /* 00354 Unregister handler error messages. 00355 00356 SYNOPSIS 00357 ha_finish_errors() 00358 00359 RETURN 00360 0 OK 00361 != 0 Error 00362 */ 00363 00364 static int ha_finish_errors(void) 00365 { 00366 const char **errmsgs; 00367 00368 /* Allocate a pointer array for the error message strings. */ 00369 if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST))) 00370 return 1; 00371 my_free((gptr) errmsgs, MYF(0)); 00372 return 0; 00373 } 00374 00375 00376 int ha_finalize_handlerton(st_plugin_int *plugin) 00377 { 00378 handlerton *hton= (handlerton *)plugin->data; 00379 DBUG_ENTER("ha_finalize_handlerton"); 00380 00381 switch (hton->state) 00382 { 00383 case SHOW_OPTION_NO: 00384 case SHOW_OPTION_DISABLED: 00385 break; 00386 case SHOW_OPTION_YES: 00387 if (installed_htons[hton->db_type] == hton) 00388 installed_htons[hton->db_type]= NULL; 00389 if (hton->panic && hton->panic(HA_PANIC_CLOSE)) 00390 DBUG_RETURN(1); 00391 break; 00392 }; 00393 DBUG_RETURN(0); 00394 } 00395 00396 00397 int ha_initialize_handlerton(st_plugin_int *plugin) 00398 { 00399 handlerton *hton= ((st_mysql_storage_engine *)plugin->plugin->info)->handlerton; 00400 DBUG_ENTER("ha_initialize_handlerton"); 00401 00402 plugin->data= hton; // shortcut for the future 00403 00404 /* 00405 the switch below and hton->state should be removed when 00406 command-line options for plugins will be implemented 00407 */ 00408 switch (hton->state) { 00409 case SHOW_OPTION_NO: 00410 break; 00411 case SHOW_OPTION_YES: 00412 { 00413 uint tmp; 00414 /* now check the db_type for conflict */ 00415 if (hton->db_type <= DB_TYPE_UNKNOWN || 00416 hton->db_type >= DB_TYPE_DEFAULT || 00417 installed_htons[hton->db_type]) 00418 { 00419 int idx= (int) DB_TYPE_FIRST_DYNAMIC; 00420 00421 while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx]) 00422 idx++; 00423 00424 if (idx == (int) DB_TYPE_DEFAULT) 00425 { 00426 sql_print_warning("Too many storage engines!"); 00427 DBUG_RETURN(1); 00428 } 00429 if (hton->db_type != DB_TYPE_UNKNOWN) 00430 sql_print_warning("Storage engine '%s' has conflicting typecode. " 00431 "Assigning value %d.", plugin->plugin->name, idx); 00432 hton->db_type= (enum legacy_db_type) idx; 00433 } 00434 installed_htons[hton->db_type]= hton; 00435 tmp= hton->savepoint_offset; 00436 hton->savepoint_offset= savepoint_alloc_size; 00437 savepoint_alloc_size+= tmp; 00438 hton->slot= total_ha++; 00439 hton2plugin[hton->slot]=plugin; 00440 if (hton->prepare) 00441 total_ha_2pc++; 00442 break; 00443 } 00444 /* fall through */ 00445 default: 00446 hton->state= SHOW_OPTION_DISABLED; 00447 break; 00448 } 00449 DBUG_RETURN(0); 00450 } 00451 00452 int ha_init() 00453 { 00454 int error= 0; 00455 DBUG_ENTER("ha_init"); 00456 00457 if (ha_init_errors()) 00458 DBUG_RETURN(1); 00459 00460 DBUG_ASSERT(total_ha < MAX_HA); 00461 /* 00462 Check if there is a transaction-capable storage engine besides the 00463 binary log (which is considered a transaction-capable storage engine in 00464 counting total_ha) 00465 */ 00466 opt_using_transactions= total_ha>(ulong)opt_bin_log; 00467 savepoint_alloc_size+= sizeof(SAVEPOINT); 00468 DBUG_RETURN(error); 00469 } 00470 00471 /* 00472 close, flush or restart databases 00473 Ignore this for other databases than ours 00474 */ 00475 00476 static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin, void *arg) 00477 { 00478 handlerton *hton= (handlerton *)plugin->data; 00479 if (hton->state == SHOW_OPTION_YES && hton->panic) 00480 ((int*)arg)[0]|= hton->panic((enum ha_panic_function)((int*)arg)[1]); 00481 return FALSE; 00482 } 00483 00484 00485 int ha_panic(enum ha_panic_function flag) 00486 { 00487 int error[2]; 00488 00489 error[0]= 0; error[1]= (int)flag; 00490 plugin_foreach(NULL, panic_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, error); 00491 00492 if (flag == HA_PANIC_CLOSE && ha_finish_errors()) 00493 error[0]= 1; 00494 return error[0]; 00495 } /* ha_panic */ 00496 00497 static my_bool dropdb_handlerton(THD *unused1, st_plugin_int *plugin, 00498 void *path) 00499 { 00500 handlerton *hton= (handlerton *)plugin->data; 00501 if (hton->state == SHOW_OPTION_YES && hton->drop_database) 00502 hton->drop_database((char *)path); 00503 return FALSE; 00504 } 00505 00506 00507 void ha_drop_database(char* path) 00508 { 00509 plugin_foreach(NULL, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path); 00510 } 00511 00512 00513 static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin, 00514 void *unused) 00515 { 00516 handlerton *hton= (handlerton *)plugin->data; 00517 /* 00518 there's no need to rollback here as all transactions must 00519 be rolled back already 00520 */ 00521 if (hton->state == SHOW_OPTION_YES && hton->close_connection && 00522 thd->ha_data[hton->slot]) 00523 hton->close_connection(thd); 00524 return FALSE; 00525 } 00526 00527 00528 /* don't bother to rollback here, it's done already */ 00529 void ha_close_connection(THD* thd) 00530 { 00531 plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0); 00532 } 00533 00534 /* ======================================================================== 00535 ======================= TRANSACTIONS ===================================*/ 00536 00537 /* 00538 Register a storage engine for a transaction 00539 00540 DESCRIPTION 00541 Every storage engine MUST call this function when it starts 00542 a transaction or a statement (that is it must be called both for the 00543 "beginning of transaction" and "beginning of statement"). 00544 Only storage engines registered for the transaction/statement 00545 will know when to commit/rollback it. 00546 00547 NOTE 00548 trans_register_ha is idempotent - storage engine may register many 00549 times per transaction. 00550 00551 */ 00552 void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) 00553 { 00554 THD_TRANS *trans; 00555 handlerton **ht; 00556 DBUG_ENTER("trans_register_ha"); 00557 DBUG_PRINT("enter",("%s", all ? "all" : "stmt")); 00558 00559 if (all) 00560 { 00561 trans= &thd->transaction.all; 00562 thd->server_status|= SERVER_STATUS_IN_TRANS; 00563 } 00564 else 00565 trans= &thd->transaction.stmt; 00566 00567 for (ht=trans->ht; *ht; ht++) 00568 if (*ht == ht_arg) 00569 DBUG_VOID_RETURN; /* already registered, return */ 00570 00571 trans->ht[trans->nht++]=ht_arg; 00572 DBUG_ASSERT(*ht == ht_arg); 00573 trans->no_2pc|=(ht_arg->prepare==0); 00574 if (thd->transaction.xid_state.xid.is_null()) 00575 thd->transaction.xid_state.xid.set(thd->query_id); 00576 DBUG_VOID_RETURN; 00577 } 00578 00579 /* 00580 RETURN 00581 0 - ok 00582 1 - error, transaction was rolled back 00583 */ 00584 int ha_prepare(THD *thd) 00585 { 00586 int error=0, all=1; 00587 THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; 00588 handlerton **ht=trans->ht; 00589 DBUG_ENTER("ha_prepare"); 00590 #ifdef USING_TRANSACTIONS 00591 if (trans->nht) 00592 { 00593 for (; *ht; ht++) 00594 { 00595 int err; 00596 statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status); 00597 if ((*ht)->prepare) 00598 { 00599 if ((err= (*(*ht)->prepare)(thd, all))) 00600 { 00601 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); 00602 ha_rollback_trans(thd, all); 00603 error=1; 00604 break; 00605 } 00606 } 00607 else 00608 { 00609 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 00610 ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), 00611 hton2plugin[(*ht)->slot]->name.str); 00612 } 00613 } 00614 } 00615 #endif /* USING_TRANSACTIONS */ 00616 DBUG_RETURN(error); 00617 } 00618 00619 /* 00620 RETURN 00621 0 - ok 00622 1 - transaction was rolled back 00623 2 - error during commit, data may be inconsistent 00624 */ 00625 int ha_commit_trans(THD *thd, bool all) 00626 { 00627 int error= 0, cookie= 0; 00628 THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt; 00629 bool is_real_trans= all || thd->transaction.all.nht == 0; 00630 handlerton **ht= trans->ht; 00631 my_xid xid= thd->transaction.xid_state.xid.get_my_xid(); 00632 DBUG_ENTER("ha_commit_trans"); 00633 00634 if (thd->in_sub_stmt) 00635 { 00636 /* 00637 Since we don't support nested statement transactions in 5.0, 00638 we can't commit or rollback stmt transactions while we are inside 00639 stored functions or triggers. So we simply do nothing now. 00640 TODO: This should be fixed in later ( >= 5.1) releases. 00641 */ 00642 if (!all) 00643 DBUG_RETURN(0); 00644 /* 00645 We assume that all statements which commit or rollback main transaction 00646 are prohibited inside of stored functions or triggers. So they should 00647 bail out with error even before ha_commit_trans() call. To be 100% safe 00648 let us throw error in non-debug builds. 00649 */ 00650 DBUG_ASSERT(0); 00651 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); 00652 DBUG_RETURN(2); 00653 } 00654 #ifdef USING_TRANSACTIONS 00655 if (trans->nht) 00656 { 00657 if (is_real_trans && wait_if_global_read_lock(thd, 0, 0)) 00658 { 00659 ha_rollback_trans(thd, all); 00660 DBUG_RETURN(1); 00661 } 00662 DBUG_EXECUTE_IF("crash_commit_before", abort();); 00663 00664 /* Close all cursors that can not survive COMMIT */ 00665 if (is_real_trans) /* not a statement commit */ 00666 thd->stmt_map.close_transient_cursors(); 00667 00668 if (!trans->no_2pc && trans->nht > 1) 00669 { 00670 for (; *ht && !error; ht++) 00671 { 00672 int err; 00673 if ((err= (*(*ht)->prepare)(thd, all))) 00674 { 00675 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); 00676 error= 1; 00677 } 00678 statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status); 00679 } 00680 DBUG_EXECUTE_IF("crash_commit_after_prepare", abort();); 00681 if (error || (is_real_trans && xid && 00682 (error= !(cookie= tc_log->log(thd, xid))))) 00683 { 00684 ha_rollback_trans(thd, all); 00685 error= 1; 00686 goto end; 00687 } 00688 DBUG_EXECUTE_IF("crash_commit_after_log", abort();); 00689 } 00690 error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0; 00691 DBUG_EXECUTE_IF("crash_commit_before_unlog", abort();); 00692 if (cookie) 00693 tc_log->unlog(cookie, xid); 00694 DBUG_EXECUTE_IF("crash_commit_after", abort();); 00695 end: 00696 if (is_real_trans) 00697 start_waiting_global_read_lock(thd); 00698 } 00699 #endif /* USING_TRANSACTIONS */ 00700 DBUG_RETURN(error); 00701 } 00702 00703 /* 00704 NOTE - this function does not care about global read lock. 00705 A caller should. 00706 */ 00707 int ha_commit_one_phase(THD *thd, bool all) 00708 { 00709 int error=0; 00710 THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; 00711 bool is_real_trans=all || thd->transaction.all.nht == 0; 00712 handlerton **ht=trans->ht; 00713 DBUG_ENTER("ha_commit_one_phase"); 00714 #ifdef USING_TRANSACTIONS 00715 if (trans->nht) 00716 { 00717 for (ht=trans->ht; *ht; ht++) 00718 { 00719 int err; 00720 if ((err= (*(*ht)->commit)(thd, all))) 00721 { 00722 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); 00723 error=1; 00724 } 00725 statistic_increment(thd->status_var.ha_commit_count,&LOCK_status); 00726 *ht= 0; 00727 } 00728 trans->nht=0; 00729 trans->no_2pc=0; 00730 if (is_real_trans) 00731 thd->transaction.xid_state.xid.null(); 00732 if (all) 00733 { 00734 #ifdef HAVE_QUERY_CACHE 00735 if (thd->transaction.changed_tables) 00736 query_cache.invalidate(thd->transaction.changed_tables); 00737 #endif 00738 thd->variables.tx_isolation=thd->session_tx_isolation; 00739 thd->transaction.cleanup(); 00740 } 00741 } 00742 #endif /* USING_TRANSACTIONS */ 00743 DBUG_RETURN(error); 00744 } 00745 00746 00747 int ha_rollback_trans(THD *thd, bool all) 00748 { 00749 int error=0; 00750 THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; 00751 bool is_real_trans=all || thd->transaction.all.nht == 0; 00752 DBUG_ENTER("ha_rollback_trans"); 00753 if (thd->in_sub_stmt) 00754 { 00755 /* 00756 If we are inside stored function or trigger we should not commit or 00757 rollback current statement transaction. See comment in ha_commit_trans() 00758 call for more information. 00759 */ 00760 if (!all) 00761 DBUG_RETURN(0); 00762 DBUG_ASSERT(0); 00763 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); 00764 DBUG_RETURN(1); 00765 } 00766 #ifdef USING_TRANSACTIONS 00767 if (trans->nht) 00768 { 00769 /* Close all cursors that can not survive ROLLBACK */ 00770 if (is_real_trans) /* not a statement commit */ 00771 thd->stmt_map.close_transient_cursors(); 00772 00773 for (handlerton **ht=trans->ht; *ht; ht++) 00774 { 00775 int err; 00776 if ((err= (*(*ht)->rollback)(thd, all))) 00777 { // cannot happen 00778 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); 00779 error=1; 00780 } 00781 statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status); 00782 *ht= 0; 00783 } 00784 trans->nht=0; 00785 trans->no_2pc=0; 00786 if (is_real_trans) 00787 thd->transaction.xid_state.xid.null(); 00788 if (all) 00789 { 00790 thd->variables.tx_isolation=thd->session_tx_isolation; 00791 thd->transaction.cleanup(); 00792 } 00793 } 00794 #endif /* USING_TRANSACTIONS */ 00795 /* 00796 If a non-transactional table was updated, warn; don't warn if this is a 00797 slave thread (because when a slave thread executes a ROLLBACK, it has 00798 been read from the binary log, so it's 100% sure and normal to produce 00799 error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the 00800 slave SQL thread, it would not stop the thread but just be printed in 00801 the error log; but we don't want users to wonder why they have this 00802 message in the error log, so we don't send it. 00803 */ 00804 if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && 00805 !thd->slave_thread) 00806 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 00807 ER_WARNING_NOT_COMPLETE_ROLLBACK, 00808 ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); 00809 DBUG_RETURN(error); 00810 } 00811 00812 /* 00813 This is used to commit or rollback a single statement depending on the value 00814 of error. Note that if the autocommit is on, then the following call inside 00815 InnoDB will commit or rollback the whole transaction (= the statement). The 00816 autocommit mechanism built into InnoDB is based on counting locks, but if 00817 the user has used LOCK TABLES then that mechanism does not know to do the 00818 commit. 00819 */ 00820 00821 int ha_autocommit_or_rollback(THD *thd, int error) 00822 { 00823 DBUG_ENTER("ha_autocommit_or_rollback"); 00824 #ifdef USING_TRANSACTIONS 00825 if (thd->transaction.stmt.nht) 00826 { 00827 if (!error) 00828 { 00829 if (ha_commit_stmt(thd)) 00830 error=1; 00831 } 00832 else 00833 (void) ha_rollback_stmt(thd); 00834 00835 thd->variables.tx_isolation=thd->session_tx_isolation; 00836 } 00837 #endif 00838 DBUG_RETURN(error); 00839 } 00840 00841 00842 struct xahton_st { 00843 XID *xid; 00844 int result; 00845 }; 00846 00847 static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin, 00848 void *arg) 00849 { 00850 handlerton *hton= (handlerton *)plugin->data; 00851 if (hton->state == SHOW_OPTION_YES && hton->recover) 00852 { 00853 hton->commit_by_xid(((struct xahton_st *)arg)->xid); 00854 ((struct xahton_st *)arg)->result= 0; 00855 } 00856 return FALSE; 00857 } 00858 00859 static my_bool xarollback_handlerton(THD *unused1, st_plugin_int *plugin, 00860 void *arg) 00861 { 00862 handlerton *hton= (handlerton *)plugin->data; 00863 if (hton->state == SHOW_OPTION_YES && hton->recover) 00864 { 00865 hton->rollback_by_xid(((struct xahton_st *)arg)->xid); 00866 ((struct xahton_st *)arg)->result= 0; 00867 } 00868 return FALSE; 00869 } 00870 00871 00872 int ha_commit_or_rollback_by_xid(XID *xid, bool commit) 00873 { 00874 struct xahton_st xaop; 00875 xaop.xid= xid; 00876 xaop.result= 1; 00877 00878 plugin_foreach(NULL, commit ? xacommit_handlerton : xarollback_handlerton, 00879 MYSQL_STORAGE_ENGINE_PLUGIN, &xaop); 00880 00881 return xaop.result; 00882 } 00883 00884 00885 #ifndef DBUG_OFF 00886 /* this does not need to be multi-byte safe or anything */ 00887 static char* xid_to_str(char *buf, XID *xid) 00888 { 00889 int i; 00890 char *s=buf; 00891 *s++='\''; 00892 for (i=0; i < xid->gtrid_length+xid->bqual_length; i++) 00893 { 00894 uchar c=(uchar)xid->data[i]; 00895 /* is_next_dig is set if next character is a number */ 00896 bool is_next_dig= FALSE; 00897 if (i < XIDDATASIZE) 00898 { 00899 char ch= xid->data[i+1]; 00900 is_next_dig= (ch >= '0' && ch <='9'); 00901 } 00902 if (i == xid->gtrid_length) 00903 { 00904 *s++='\''; 00905 if (xid->bqual_length) 00906 { 00907 *s++='.'; 00908 *s++='\''; 00909 } 00910 } 00911 if (c < 32 || c > 126) 00912 { 00913 *s++='\\'; 00914 /* 00915 If next character is a number, write current character with 00916 3 octal numbers to ensure that the next number is not seen 00917 as part of the octal number 00918 */ 00919 if (c > 077 || is_next_dig) 00920 *s++=_dig_vec_lower[c >> 6]; 00921 if (c > 007 || is_next_dig) 00922 *s++=_dig_vec_lower[(c >> 3) & 7]; 00923 *s++=_dig_vec_lower[c & 7]; 00924 } 00925 else 00926 { 00927 if (c == '\'' || c == '\\') 00928 *s++='\\'; 00929 *s++=c; 00930 } 00931 } 00932 *s++='\''; 00933 *s=0; 00934 return buf; 00935 } 00936 #endif 00937 00938 /* 00939 recover() step of xa 00940 00941 NOTE 00942 there are three modes of operation: 00943 00944 - automatic recover after a crash 00945 in this case commit_list != 0, tc_heuristic_recover==0 00946 all xids from commit_list are committed, others are rolled back 00947 00948 - manual (heuristic) recover 00949 in this case commit_list==0, tc_heuristic_recover != 0 00950 DBA has explicitly specified that all prepared transactions should 00951 be committed (or rolled back). 00952 00953 - no recovery (MySQL did not detect a crash) 00954 in this case commit_list==0, tc_heuristic_recover == 0 00955 there should be no prepared transactions in this case. 00956 */ 00957 00958 struct xarecover_st 00959 { 00960 int len, found_foreign_xids, found_my_xids; 00961 XID *list; 00962 HASH *commit_list; 00963 bool dry_run; 00964 }; 00965 00966 static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin, 00967 void *arg) 00968 { 00969 handlerton *hton= (handlerton *)plugin->data; 00970 struct xarecover_st *info= (struct xarecover_st *) arg; 00971 int got; 00972 00973 if (hton->state == SHOW_OPTION_YES && hton->recover) 00974 { 00975 while ((got= hton->recover(info->list, info->len)) > 0 ) 00976 { 00977 sql_print_information("Found %d prepared transaction(s) in %s", 00978 got, hton2plugin[hton->slot]->name.str); 00979 for (int i=0; i < got; i ++) 00980 { 00981 my_xid x=info->list[i].get_my_xid(); 00982 if (!x) // not "mine" - that is generated by external TM 00983 { 00984 #ifndef DBUG_OFF 00985 char buf[XIDDATASIZE*4+6]; // see xid_to_str 00986 sql_print_information("ignore xid %s", xid_to_str(buf, info->list+i)); 00987 #endif 00988 xid_cache_insert(info->list+i, XA_PREPARED); 00989 info->found_foreign_xids++; 00990 continue; 00991 } 00992 if (info->dry_run) 00993 { 00994 info->found_my_xids++; 00995 continue; 00996 } 00997 // recovery mode 00998 if (info->commit_list ? 00999 hash_search(info->commit_list, (byte *)&x, sizeof(x)) != 0 : 01000 tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT) 01001 { 01002 #ifndef DBUG_OFF 01003 char buf[XIDDATASIZE*4+6]; // see xid_to_str 01004 sql_print_information("commit xid %s", xid_to_str(buf, info->list+i)); 01005 #endif 01006 hton->commit_by_xid(info->list+i); 01007 } 01008 else 01009 { 01010 #ifndef DBUG_OFF 01011 char buf[XIDDATASIZE*4+6]; // see xid_to_str 01012 sql_print_information("rollback xid %s", 01013 xid_to_str(buf, info->list+i)); 01014 #endif 01015 hton->rollback_by_xid(info->list+i); 01016 } 01017 } 01018 if (got < info->len) 01019 break; 01020 } 01021 } 01022 return FALSE; 01023 } 01024 01025 int ha_recover(HASH *commit_list) 01026 { 01027 struct xarecover_st info; 01028 DBUG_ENTER("ha_recover"); 01029 info.found_foreign_xids= info.found_my_xids= 0; 01030 info.commit_list= commit_list; 01031 info.dry_run= (info.commit_list==0 && tc_heuristic_recover==0); 01032 info.list= NULL; 01033 01034 /* commit_list and tc_heuristic_recover cannot be set both */ 01035 DBUG_ASSERT(info.commit_list==0 || tc_heuristic_recover==0); 01036 /* if either is set, total_ha_2pc must be set too */ 01037 DBUG_ASSERT(info.dry_run || total_ha_2pc>(ulong)opt_bin_log); 01038 01039 if (total_ha_2pc <= (ulong)opt_bin_log) 01040 DBUG_RETURN(0); 01041 01042 if (info.commit_list) 01043 sql_print_information("Starting crash recovery..."); 01044 01045 #ifndef WILL_BE_DELETED_LATER 01046 /* 01047 for now, only InnoDB supports 2pc. It means we can always safely 01048 rollback all pending transactions, without risking inconsistent data 01049 */ 01050 DBUG_ASSERT(total_ha_2pc == (ulong) opt_bin_log+1); // only InnoDB and binlog 01051 tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK 01052 info.dry_run=FALSE; 01053 #endif 01054 01055 for (info.len= MAX_XID_LIST_SIZE ; 01056 info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2) 01057 { 01058 info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0)); 01059 } 01060 if (!info.list) 01061 { 01062 sql_print_error(ER(ER_OUTOFMEMORY), info.len*sizeof(XID)); 01063 DBUG_RETURN(1); 01064 } 01065 01066 plugin_foreach(NULL, xarecover_handlerton, 01067 MYSQL_STORAGE_ENGINE_PLUGIN, &info); 01068 01069 my_free((gptr)info.list, MYF(0)); 01070 if (info.found_foreign_xids) 01071 sql_print_warning("Found %d prepared XA transactions", 01072 info.found_foreign_xids); 01073 if (info.dry_run && info.found_my_xids) 01074 { 01075 sql_print_error("Found %d prepared transactions! It means that mysqld was " 01076 "not shut down properly last time and critical recovery " 01077 "information (last binlog or %s file) was manually deleted " 01078 "after a crash. You have to start mysqld with " 01079 "--tc-heuristic-recover switch to commit or rollback " 01080 "pending transactions.", 01081 info.found_my_xids, opt_tc_log_file); 01082 DBUG_RETURN(1); 01083 } 01084 if (info.commit_list) 01085 sql_print_information("Crash recovery finished."); 01086 DBUG_RETURN(0); 01087 } 01088 01089 /* 01090 return the list of XID's to a client, the same way SHOW commands do 01091 01092 NOTE 01093 I didn't find in XA specs that an RM cannot return the same XID twice, 01094 so mysql_xa_recover does not filter XID's to ensure uniqueness. 01095 It can be easily fixed later, if necessary. 01096 */ 01097 bool mysql_xa_recover(THD *thd) 01098 { 01099 List<Item> field_list; 01100 Protocol *protocol= thd->protocol; 01101 int i=0; 01102 XID_STATE *xs; 01103 DBUG_ENTER("mysql_xa_recover"); 01104 01105 field_list.push_back(new Item_int("formatID",0,11)); 01106 field_list.push_back(new Item_int("gtrid_length",0,11)); 01107 field_list.push_back(new Item_int("bqual_length",0,11)); 01108 field_list.push_back(new Item_empty_string("data",XIDDATASIZE)); 01109 01110 if (protocol->send_fields(&field_list, 01111 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 01112 DBUG_RETURN(1); 01113 01114 pthread_mutex_lock(&LOCK_xid_cache); 01115 while ((xs= (XID_STATE*)hash_element(&xid_cache, i++))) 01116 { 01117 if (xs->xa_state==XA_PREPARED) 01118 { 01119 protocol->prepare_for_resend(); 01120 protocol->store_longlong((longlong)xs->xid.formatID, FALSE); 01121 protocol->store_longlong((longlong)xs->xid.gtrid_length, FALSE); 01122 protocol->store_longlong((longlong)xs->xid.bqual_length, FALSE); 01123 protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length, 01124 &my_charset_bin); 01125 if (protocol->write()) 01126 { 01127 pthread_mutex_unlock(&LOCK_xid_cache); 01128 DBUG_RETURN(1); 01129 } 01130 } 01131 } 01132 01133 pthread_mutex_unlock(&LOCK_xid_cache); 01134 send_eof(thd); 01135 DBUG_RETURN(0); 01136 } 01137 01138 /* 01139 This function should be called when MySQL sends rows of a SELECT result set 01140 or the EOF mark to the client. It releases a possible adaptive hash index 01141 S-latch held by thd in InnoDB and also releases a possible InnoDB query 01142 FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a thd to 01143 keep them over several calls of the InnoDB handler interface when a join 01144 is executed. But when we let the control to pass to the client they have 01145 to be released because if the application program uses mysql_use_result(), 01146 it may deadlock on the S-latch if the application on another connection 01147 performs another SQL query. In MySQL-4.1 this is even more important because 01148 there a connection can have several SELECT queries open at the same time. 01149 01150 arguments: 01151 thd: the thread handle of the current connection 01152 return value: always 0 01153 */ 01154 01155 static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin, 01156 void *unused) 01157 { 01158 handlerton *hton= (handlerton *)plugin->data; 01159 01160 if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches) 01161 hton->release_temporary_latches(thd); 01162 01163 return FALSE; 01164 } 01165 01166 01167 int ha_release_temporary_latches(THD *thd) 01168 { 01169 plugin_foreach(thd, release_temporary_latches, MYSQL_STORAGE_ENGINE_PLUGIN, 01170 NULL); 01171 01172 return 0; 01173 } 01174 01175 int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) 01176 { 01177 int error=0; 01178 THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : 01179 &thd->transaction.all); 01180 handlerton **ht=trans->ht, **end_ht; 01181 DBUG_ENTER("ha_rollback_to_savepoint"); 01182 01183 trans->nht=sv->nht; 01184 trans->no_2pc=0; 01185 end_ht=ht+sv->nht; 01186 /* 01187 rolling back to savepoint in all storage engines that were part of the 01188 transaction when the savepoint was set 01189 */ 01190 for (; ht < end_ht; ht++) 01191 { 01192 int err; 01193 DBUG_ASSERT((*ht)->savepoint_set != 0); 01194 if ((err= (*(*ht)->savepoint_rollback)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) 01195 { // cannot happen 01196 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); 01197 error=1; 01198 } 01199 statistic_increment(thd->status_var.ha_savepoint_rollback_count, 01200 &LOCK_status); 01201 trans->no_2pc|=(*ht)->prepare == 0; 01202 } 01203 /* 01204 rolling back the transaction in all storage engines that were not part of 01205 the transaction when the savepoint was set 01206 */ 01207 for (; *ht ; ht++) 01208 { 01209 int err; 01210 if ((err= (*(*ht)->rollback)(thd, !thd->in_sub_stmt))) 01211 { // cannot happen 01212 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); 01213 error=1; 01214 } 01215 statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status); 01216 *ht=0; // keep it conveniently zero-filled 01217 } 01218 DBUG_RETURN(error); 01219 } 01220 01221 /* 01222 note, that according to the sql standard (ISO/IEC 9075-2:2003) 01223 section "4.33.4 SQL-statements and transaction states", 01224 SAVEPOINT is *not* transaction-initiating SQL-statement 01225 */ 01226 01227 int ha_savepoint(THD *thd, SAVEPOINT *sv) 01228 { 01229 int error=0; 01230 THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : 01231 &thd->transaction.all); 01232 handlerton **ht=trans->ht; 01233 DBUG_ENTER("ha_savepoint"); 01234 #ifdef USING_TRANSACTIONS 01235 for (; *ht; ht++) 01236 { 01237 int err; 01238 if (! (*ht)->savepoint_set) 01239 { 01240 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT"); 01241 error=1; 01242 break; 01243 } 01244 if ((err= (*(*ht)->savepoint_set)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) 01245 { // cannot happen 01246 my_error(ER_GET_ERRNO, MYF(0), err); 01247 error=1; 01248 } 01249 statistic_increment(thd->status_var.ha_savepoint_count,&LOCK_status); 01250 } 01251 sv->nht=trans->nht; 01252 #endif /* USING_TRANSACTIONS */ 01253 DBUG_RETURN(error); 01254 } 01255 01256 int ha_release_savepoint(THD *thd, SAVEPOINT *sv) 01257 { 01258 int error=0; 01259 THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : 01260 &thd->transaction.all); 01261 handlerton **ht=trans->ht, **end_ht; 01262 DBUG_ENTER("ha_release_savepoint"); 01263 01264 end_ht=ht+sv->nht; 01265 for (; ht < end_ht; ht++) 01266 { 01267 int err; 01268 if (!(*ht)->savepoint_release) 01269 continue; 01270 if ((err= (*(*ht)->savepoint_release)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) 01271 { // cannot happen 01272 my_error(ER_GET_ERRNO, MYF(0), err); 01273 error=1; 01274 } 01275 } 01276 DBUG_RETURN(error); 01277 } 01278 01279 01280 static my_bool snapshot_handlerton(THD *thd, st_plugin_int *plugin, 01281 void *arg) 01282 { 01283 handlerton *hton= (handlerton *)plugin->data; 01284 if (hton->state == SHOW_OPTION_YES && 01285 hton->start_consistent_snapshot) 01286 { 01287 hton->start_consistent_snapshot(thd); 01288 *((bool *)arg)= false; 01289 } 01290 return FALSE; 01291 } 01292 01293 int ha_start_consistent_snapshot(THD *thd) 01294 { 01295 bool warn= true; 01296 01297 plugin_foreach(thd, snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &warn); 01298 01299 /* 01300 Same idea as when one wants to CREATE TABLE in one engine which does not 01301 exist: 01302 */ 01303 if (warn) 01304 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, 01305 "This MySQL server does not support any " 01306 "consistent-read capable storage engine"); 01307 return 0; 01308 } 01309 01310 01311 static my_bool flush_handlerton(THD *thd, st_plugin_int *plugin, 01312 void *arg) 01313 { 01314 handlerton *hton= (handlerton *)plugin->data; 01315 if (hton->state == SHOW_OPTION_YES && hton->flush_logs && hton->flush_logs()) 01316 return TRUE; 01317 return FALSE; 01318 } 01319 01320 01321 bool ha_flush_logs(handlerton *db_type) 01322 { 01323 if (db_type == NULL) 01324 { 01325 if (plugin_foreach(NULL, flush_handlerton, 01326 MYSQL_STORAGE_ENGINE_PLUGIN, 0)) 01327 return TRUE; 01328 } 01329 else 01330 { 01331 if (db_type->state != SHOW_OPTION_YES || 01332 (db_type->flush_logs && db_type->flush_logs())) 01333 return TRUE; 01334 } 01335 return FALSE; 01336 } 01337 01338 /* 01339 This should return ENOENT if the file doesn't exists. 01340 The .frm file will be deleted only if we return 0 or ENOENT 01341 */ 01342 01343 int ha_delete_table(THD *thd, handlerton *table_type, const char *path, 01344 const char *db, const char *alias, bool generate_warning) 01345 { 01346 handler *file; 01347 char tmp_path[FN_REFLEN]; 01348 int error; 01349 TABLE dummy_table; 01350 TABLE_SHARE dummy_share; 01351 DBUG_ENTER("ha_delete_table"); 01352 01353 bzero((char*) &dummy_table, sizeof(dummy_table)); 01354 bzero((char*) &dummy_share, sizeof(dummy_share)); 01355 dummy_table.s= &dummy_share; 01356 01357 /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */ 01358 if (table_type == NULL || 01359 ! (file=get_new_handler(&dummy_share, thd->mem_root, table_type))) 01360 DBUG_RETURN(ENOENT); 01361 01362 if (lower_case_table_names == 2 && !(file->ha_table_flags() & HA_FILE_BASED)) 01363 { 01364 /* Ensure that table handler get path in lower case */ 01365 strmov(tmp_path, path); 01366 my_casedn_str(files_charset_info, tmp_path); 01367 path= tmp_path; 01368 } 01369 if ((error= file->delete_table(path)) && generate_warning) 01370 { 01371 /* 01372 Because file->print_error() use my_error() to generate the error message 01373 we must store the error state in thd, reset it and restore it to 01374 be able to get hold of the error message. 01375 (We should in the future either rewrite handler::print_error() or make 01376 a nice method of this. 01377 */ 01378 bool query_error= thd->query_error; 01379 sp_rcontext *spcont= thd->spcont; 01380 SELECT_LEX *current_select= thd->lex->current_select; 01381 char buff[sizeof(thd->net.last_error)]; 01382 char new_error[sizeof(thd->net.last_error)]; 01383 int last_errno= thd->net.last_errno; 01384 01385 strmake(buff, thd->net.last_error, sizeof(buff)-1); 01386 thd->query_error= 0; 01387 thd->spcont= 0; 01388 thd->lex->current_select= 0; 01389 thd->net.last_error[0]= 0; 01390 01391 /* Fill up strucutures that print_error may need */ 01392 dummy_share.path.str= (char*) path; 01393 dummy_share.path.length= strlen(path); 01394 dummy_share.db.str= (char*) db; 01395 dummy_share.db.length= strlen(db); 01396 dummy_share.table_name.str= (char*) alias; 01397 dummy_share.table_name.length= strlen(alias); 01398 dummy_table.alias= alias; 01399 01400 file->print_error(error, 0); 01401 strmake(new_error, thd->net.last_error, sizeof(buff)-1); 01402 01403 /* restore thd */ 01404 thd->query_error= query_error; 01405 thd->spcont= spcont; 01406 thd->lex->current_select= current_select; 01407 thd->net.last_errno= last_errno; 01408 strmake(thd->net.last_error, buff, sizeof(buff)-1); 01409 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error); 01410 } 01411 delete file; 01412 DBUG_RETURN(error); 01413 } 01414 01415 /**************************************************************************** 01416 ** General handler functions 01417 ****************************************************************************/ 01418 01419 01420 void handler::ha_statistic_increment(ulong SSV::*offset) const 01421 { 01422 statistic_increment(table->in_use->status_var.*offset, &LOCK_status); 01423 } 01424 01425 01426 bool handler::check_if_log_table_locking_is_allowed(uint sql_command, 01427 ulong type, TABLE *table) 01428 { 01429 /* 01430 Deny locking of the log tables, which is incompatible with 01431 concurrent insert. Unless called from a logger THD: 01432 general_log_thd or slow_log_thd. 01433 */ 01434 if (table->s->log_table && 01435 sql_command != SQLCOM_TRUNCATE && 01436 sql_command != SQLCOM_ALTER_TABLE && 01437 !(sql_command == SQLCOM_FLUSH && 01438 type & REFRESH_LOG) && 01439 (table->reginfo.lock_type >= TL_READ_NO_INSERT)) 01440 { 01441 /* 01442 The check >= TL_READ_NO_INSERT denies all write locks 01443 plus the only read lock (TL_READ_NO_INSERT itself) 01444 */ 01445 table->reginfo.lock_type == TL_READ_NO_INSERT ? 01446 my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0)) : 01447 my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0)); 01448 return FALSE; 01449 } 01450 return TRUE; 01451 } 01452 01453 /* 01454 Open database-handler. 01455 01456 IMPLEMENTATION 01457 Try O_RDONLY if cannot open as O_RDWR 01458 Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set 01459 */ 01460 01461 int handler::ha_open(TABLE *table_arg, const char *name, int mode, 01462 int test_if_locked) 01463 { 01464 int error; 01465 DBUG_ENTER("handler::ha_open"); 01466 DBUG_PRINT("enter", 01467 ("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d", 01468 name, table_share->db_type, table_arg->db_stat, mode, 01469 test_if_locked)); 01470 01471 table= table_arg; 01472 DBUG_ASSERT(table->s == table_share); 01473 DBUG_ASSERT(alloc_root_inited(&table->mem_root)); 01474 01475 if ((error=open(name,mode,test_if_locked))) 01476 { 01477 if ((error == EACCES || error == EROFS) && mode == O_RDWR && 01478 (table->db_stat & HA_TRY_READ_ONLY)) 01479 { 01480 table->db_stat|=HA_READ_ONLY; 01481 error=open(name,O_RDONLY,test_if_locked); 01482 } 01483 } 01484 if (error) 01485 { 01486 my_errno= error; /* Safeguard */ 01487 DBUG_PRINT("error",("error: %d errno: %d",error,errno)); 01488 } 01489 else 01490 { 01491 if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA) 01492 table->db_stat|=HA_READ_ONLY; 01493 (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL 01494 01495 if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2))) 01496 { 01497 close(); 01498 error=HA_ERR_OUT_OF_MEM; 01499 } 01500 else 01501 dup_ref=ref+ALIGN_SIZE(ref_length); 01502 cached_table_flags= table_flags(); 01503 } 01504 DBUG_RETURN(error); 01505 } 01506 01507 01508 /* 01509 Read first row (only) from a table 01510 This is never called for InnoDB tables, as these table types 01511 has the HA_STATS_RECORDS_IS_EXACT set. 01512 */ 01513 01514 int handler::read_first_row(byte * buf, uint primary_key) 01515 { 01516 register int error; 01517 DBUG_ENTER("handler::read_first_row"); 01518 01519 statistic_increment(table->in_use->status_var.ha_read_first_count, 01520 &LOCK_status); 01521 01522 /* 01523 If there is very few deleted rows in the table, find the first row by 01524 scanning the table. 01525 TODO remove the test for HA_READ_ORDER 01526 */ 01527 if (stats.deleted < 10 || primary_key >= MAX_KEY || 01528 !(index_flags(primary_key, 0, 0) & HA_READ_ORDER)) 01529 { 01530 (void) ha_rnd_init(1); 01531 while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; 01532 (void) ha_rnd_end(); 01533 } 01534 else 01535 { 01536 /* Find the first row through the primary key */ 01537 (void) ha_index_init(primary_key, 0); 01538 error=index_first(buf); 01539 (void) ha_index_end(); 01540 } 01541 DBUG_RETURN(error); 01542 } 01543 01544 /* 01545 Generate the next auto-increment number based on increment and offset: 01546 computes the lowest number 01547 - strictly greater than "nr" 01548 - of the form: auto_increment_offset + N * auto_increment_increment 01549 01550 In most cases increment= offset= 1, in which case we get: 01551 1,2,3,4,5,... 01552 If increment=10 and offset=5 and previous number is 1, we get: 01553 1,5,15,25,35,... 01554 */ 01555 01556 inline ulonglong 01557 compute_next_insert_id(ulonglong nr,struct system_variables *variables) 01558 { 01559 if (variables->auto_increment_increment == 1) 01560 return (nr+1); // optimization of the formula below 01561 nr= (((nr+ variables->auto_increment_increment - 01562 variables->auto_increment_offset)) / 01563 (ulonglong) variables->auto_increment_increment); 01564 return (nr* (ulonglong) variables->auto_increment_increment + 01565 variables->auto_increment_offset); 01566 } 01567 01568 01569 void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) 01570 { 01571 /* 01572 If we have set THD::next_insert_id previously and plan to insert an 01573 explicitely-specified value larger than this, we need to increase 01574 THD::next_insert_id to be greater than the explicit value. 01575 */ 01576 if ((next_insert_id > 0) && (nr >= next_insert_id)) 01577 set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables)); 01578 } 01579 01580 01581 /* 01582 Computes the largest number X: 01583 - smaller than or equal to "nr" 01584 - of the form: auto_increment_offset + N * auto_increment_increment 01585 where N>=0. 01586 01587 SYNOPSIS 01588 prev_insert_id 01589 nr Number to "round down" 01590 variables variables struct containing auto_increment_increment and 01591 auto_increment_offset 01592 01593 RETURN 01594 The number X if it exists, "nr" otherwise. 01595 */ 01596 01597 inline ulonglong 01598 prev_insert_id(ulonglong nr, struct system_variables *variables) 01599 { 01600 if (unlikely(nr < variables->auto_increment_offset)) 01601 { 01602 /* 01603 There's nothing good we can do here. That is a pathological case, where 01604 the offset is larger than the column's max possible value, i.e. not even 01605 the first sequence value may be inserted. User will receive warning. 01606 */ 01607 DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour " 01608 "auto_increment_offset: %lu", 01609 nr, variables->auto_increment_offset)); 01610 return nr; 01611 } 01612 if (variables->auto_increment_increment == 1) 01613 return nr; // optimization of the formula below 01614 nr= (((nr - variables->auto_increment_offset)) / 01615 (ulonglong) variables->auto_increment_increment); 01616 return (nr * (ulonglong) variables->auto_increment_increment + 01617 variables->auto_increment_offset); 01618 } 01619 01620 01621 /* 01622 Update the auto_increment field if necessary 01623 01624 SYNOPSIS 01625 update_auto_increment() 01626 01627 RETURN 01628 0 ok 01629 1 get_auto_increment() was called and returned ~(ulonglong) 0 01630 01631 01632 IMPLEMENTATION 01633 01634 Updates the record's Field of type NEXT_NUMBER if: 01635 01636 - If column value is set to NULL (in which case 01637 auto_increment_field_not_null is 0) 01638 - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not 01639 set. In the future we will only set NEXT_NUMBER fields if one sets them 01640 to NULL (or they are not included in the insert list). 01641 01642 In those cases, we check if the currently reserved interval still has 01643 values we have not used. If yes, we pick the smallest one and use it. 01644 Otherwise: 01645 01646 - If a list of intervals has been provided to the statement via SET 01647 INSERT_ID or via an Intvar_log_event (in a replication slave), we pick the 01648 first unused interval from this list, consider it as reserved. 01649 01650 - Otherwise we set the column for the first row to the value 01651 next_insert_id(get_auto_increment(column))) which is usually 01652 max-used-column-value+1. 01653 We call get_auto_increment() for the first row in a multi-row 01654 statement. get_auto_increment() will tell us the interval of values it 01655 reserved for us. 01656 01657 - In both cases, for the following rows we use those reserved values without 01658 calling the handler again (we just progress in the interval, computing 01659 each new value from the previous one). Until we have exhausted them, then 01660 we either take the next provided interval or call get_auto_increment() 01661 again to reserve a new interval. 01662 01663 - In both cases, the reserved intervals are remembered in 01664 thd->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based 01665 binlogging; the last reserved interval is remembered in 01666 auto_inc_interval_for_cur_row. 01667 01668 The idea is that generated auto_increment values are predictable and 01669 independent of the column values in the table. This is needed to be 01670 able to replicate into a table that already has rows with a higher 01671 auto-increment value than the one that is inserted. 01672 01673 After we have already generated an auto-increment number and the user 01674 inserts a column with a higher value than the last used one, we will 01675 start counting from the inserted value. 01676 01677 This function's "outputs" are: the table's auto_increment field is filled 01678 with a value, thd->next_insert_id is filled with the value to use for the 01679 next row, if a value was autogenerated for the current row it is stored in 01680 thd->insert_id_for_cur_row, if get_auto_increment() was called 01681 thd->auto_inc_interval_for_cur_row is modified, if that interval is not 01682 present in thd->auto_inc_intervals_in_cur_stmt_for_binlog it is added to 01683 this list. 01684 01685 TODO 01686 01687 Replace all references to "next number" or NEXT_NUMBER to 01688 "auto_increment", everywhere (see below: there is 01689 table->auto_increment_field_not_null, and there also exists 01690 table->next_number_field, it's not consistent). 01691 01692 */ 01693 01694 #define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here 01695 #define AUTO_INC_DEFAULT_NB_MAX_BITS 16 01696 #define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1) 01697 01698 bool handler::update_auto_increment() 01699 { 01700 ulonglong nr, nb_reserved_values; 01701 bool append= FALSE; 01702 THD *thd= table->in_use; 01703 struct system_variables *variables= &thd->variables; 01704 bool auto_increment_field_not_null; 01705 bool result= 0; 01706 DBUG_ENTER("handler::update_auto_increment"); 01707 01708 /* 01709 next_insert_id is a "cursor" into the reserved interval, it may go greater 01710 than the interval, but not smaller. 01711 */ 01712 DBUG_ASSERT(next_insert_id >= auto_inc_interval_for_cur_row.minimum()); 01713 auto_increment_field_not_null= table->auto_increment_field_not_null; 01714 table->auto_increment_field_not_null= FALSE; // to reset for next row 01715 01716 if ((nr= table->next_number_field->val_int()) != 0 || 01717 auto_increment_field_not_null && 01718 thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) 01719 { 01720 /* 01721 Update next_insert_id if we had already generated a value in this 01722 statement (case of INSERT VALUES(null),(3763),(null): 01723 the last NULL needs to insert 3764, not the value of the first NULL plus 01724 1). 01725 */ 01726 adjust_next_insert_id_after_explicit_value(nr); 01727 insert_id_for_cur_row= 0; // didn't generate anything 01728 DBUG_RETURN(0); 01729 } 01730 01731 if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum()) 01732 { 01733 /* next_insert_id is beyond what is reserved, so we reserve more. */ 01734 const Discrete_interval *forced= 01735 thd->auto_inc_intervals_forced.get_next(); 01736 if (forced != NULL) 01737 { 01738 nr= forced->minimum(); 01739 nb_reserved_values= forced->values(); 01740 } 01741 else 01742 { 01743 /* 01744 handler::estimation_rows_to_insert was set by 01745 handler::ha_start_bulk_insert(); if 0 it means "unknown". 01746 */ 01747 uint nb_already_reserved_intervals= 01748 thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements(); 01749 ulonglong nb_desired_values; 01750 /* 01751 If an estimation was given to the engine: 01752 - use it. 01753 - if we already reserved numbers, it means the estimation was 01754 not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd 01755 time, twice that the 3rd time etc. 01756 If no estimation was given, use those increasing defaults from the 01757 start, starting from AUTO_INC_DEFAULT_NB_ROWS. 01758 Don't go beyond a max to not reserve "way too much" (because 01759 reservation means potentially losing unused values). 01760 */ 01761 if (nb_already_reserved_intervals == 0 && 01762 (estimation_rows_to_insert > 0)) 01763 nb_desired_values= estimation_rows_to_insert; 01764 else /* go with the increasing defaults */ 01765 { 01766 /* avoid overflow in formula, with this if() */ 01767 if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS) 01768 { 01769 nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS * 01770 (1 << nb_already_reserved_intervals); 01771 set_if_smaller(nb_desired_values, AUTO_INC_DEFAULT_NB_MAX); 01772 } 01773 else 01774 nb_desired_values= AUTO_INC_DEFAULT_NB_MAX; 01775 } 01776 /* This call ignores all its parameters but nr, currently */ 01777 get_auto_increment(variables->auto_increment_offset, 01778 variables->auto_increment_increment, 01779 nb_desired_values, &nr, 01780 &nb_reserved_values); 01781 if (nr == ~(ulonglong) 0) 01782 result= 1; // Mark failure 01783 01784 /* 01785 That rounding below should not be needed when all engines actually 01786 respect offset and increment in get_auto_increment(). But they don't 01787 so we still do it. Wonder if for the not-first-in-index we should do 01788 it. Hope that this rounding didn't push us out of the interval; even 01789 if it did we cannot do anything about it (calling the engine again 01790 will not help as we inserted no row). 01791 */ 01792 nr= compute_next_insert_id(nr-1, variables); 01793 } 01794 01795 if (table->s->next_number_key_offset == 0) 01796 { 01797 /* We must defer the appending until "nr" has been possibly truncated */ 01798 append= TRUE; 01799 } 01800 else 01801 { 01802 /* 01803 For such auto_increment there is no notion of interval, just a 01804 singleton. The interval is not even stored in 01805 thd->auto_inc_interval_for_cur_row, so we are sure to call the engine 01806 for next row. 01807 */ 01808 DBUG_PRINT("info",("auto_increment: special not-first-in-index")); 01809 } 01810 } 01811 01812 DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); 01813 01814 if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) 01815 { 01816 /* 01817 field refused this value (overflow) and truncated it, use the result of 01818 the truncation (which is going to be inserted); however we try to 01819 decrease it to honour auto_increment_* variables. 01820 That will shift the left bound of the reserved interval, we don't 01821 bother shifting the right bound (anyway any other value from this 01822 interval will cause a duplicate key). 01823 */ 01824 nr= prev_insert_id(table->next_number_field->val_int(), variables); 01825 if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) 01826 nr= table->next_number_field->val_int(); 01827 } 01828 if (append) 01829 { 01830 auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values, 01831 variables->auto_increment_increment); 01832 /* Row-based replication does not need to store intervals in binlog */ 01833 if (!thd->current_stmt_binlog_row_based) 01834 result= result || 01835 thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(), 01836 auto_inc_interval_for_cur_row.values(), 01837 variables->auto_increment_increment); 01838 } 01839 01840 /* 01841 Record this autogenerated value. If the caller then 01842 succeeds to insert this value, it will call 01843 record_first_successful_insert_id_in_cur_stmt() 01844 which will set first_successful_insert_id_in_cur_stmt if it's not 01845 already set. 01846 */ 01847 insert_id_for_cur_row= nr; 01848 /* 01849 Set next insert id to point to next auto-increment value to be able to 01850 handle multi-row statements. 01851 */ 01852 set_next_insert_id(compute_next_insert_id(nr, variables)); 01853 01854 DBUG_RETURN(result); 01855 } 01856 01857 01858 /* 01859 MySQL signal that it changed the column bitmap 01860 01861 USAGE 01862 This is for handlers that needs to setup their own column bitmaps. 01863 Normally the handler should set up their own column bitmaps in 01864 index_init() or rnd_init() and in any column_bitmaps_signal() call after 01865 this. 01866 01867 The handler is allowd to do changes to the bitmap after a index_init or 01868 rnd_init() call is made as after this, MySQL will not use the bitmap 01869 for any program logic checking. 01870 */ 01871 01872 void handler::column_bitmaps_signal() 01873 { 01874 DBUG_ENTER("column_bitmaps_signal"); 01875 DBUG_PRINT("info", ("read_set: 0x%lx write_set: 0x%lx", table->read_set, 01876 table->write_set)); 01877 DBUG_VOID_RETURN; 01878 } 01879 01880 01881 /* 01882 Reserves an interval of auto_increment values from the handler. 01883 01884 SYNOPSIS 01885 get_auto_increment() 01886 offset 01887 increment 01888 nb_desired_values how many values we want 01889 first_value (OUT) the first value reserved by the handler 01890 nb_reserved_values (OUT) how many values the handler reserved 01891 01892 offset and increment means that we want values to be of the form 01893 offset + N * increment, where N>=0 is integer. 01894 If the function sets *first_value to ~(ulonglong)0 it means an error. 01895 If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has 01896 reserved to "positive infinite". 01897 */ 01898 01899 void handler::get_auto_increment(ulonglong offset, ulonglong increment, 01900 ulonglong nb_desired_values, 01901 ulonglong *first_value, 01902 ulonglong *nb_reserved_values) 01903 { 01904 ulonglong nr; 01905 int error; 01906 01907 (void) extra(HA_EXTRA_KEYREAD); 01908 table->mark_columns_used_by_index_no_reset(table->s->next_number_index, 01909 table->read_set); 01910 column_bitmaps_signal(); 01911 index_init(table->s->next_number_index, 1); 01912 if (!table->s->next_number_key_offset) 01913 { // Autoincrement at key-start 01914 error=index_last(table->record[1]); 01915 /* 01916 MySQL implicitely assumes such method does locking (as MySQL decides to 01917 use nr+increment without checking again with the handler, in 01918 handler::update_auto_increment()), so reserves to infinite. 01919 */ 01920 *nb_reserved_values= ULONGLONG_MAX; 01921 } 01922 else 01923 { 01924 byte key[MAX_KEY_LENGTH]; 01925 key_copy(key, table->record[0], 01926 table->key_info + table->s->next_number_index, 01927 table->s->next_number_key_offset); 01928 error= index_read(table->record[1], key, table->s->next_number_key_offset, 01929 HA_READ_PREFIX_LAST); 01930 /* 01931 MySQL needs to call us for next row: assume we are inserting ("a",null) 01932 here, we return 3, and next this statement will want to insert 01933 ("b",null): there is no reason why ("b",3+1) would be the good row to 01934 insert: maybe it already exists, maybe 3+1 is too large... 01935 */ 01936 *nb_reserved_values= 1; 01937 } 01938 01939 if (error) 01940 nr=1; 01941 else 01942 nr= ((ulonglong) table->next_number_field-> 01943 val_int_offset(table->s->rec_buff_length)+1); 01944 index_end(); 01945 (void) extra(HA_EXTRA_NO_KEYREAD); 01946 *first_value= nr; 01947 } 01948 01949 01950 void handler::ha_release_auto_increment() 01951 { 01952 release_auto_increment(); 01953 insert_id_for_cur_row= 0; 01954 auto_inc_interval_for_cur_row.replace(0, 0, 0); 01955 if (next_insert_id > 0) 01956 { 01957 next_insert_id= 0; 01958 /* 01959 this statement used forced auto_increment values if there were some, 01960 wipe them away for other statements. 01961 */ 01962 table->in_use->auto_inc_intervals_forced.empty(); 01963 } 01964 } 01965 01966 01967 void handler::print_keydup_error(uint key_nr, const char *msg) 01968 { 01969 /* Write the duplicated key in the error message */ 01970 char key[MAX_KEY_LENGTH]; 01971 String str(key,sizeof(key),system_charset_info); 01972 /* Table is opened and defined at this point */ 01973 key_unpack(&str,table,(uint) key_nr); 01974 uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(msg); 01975 if (str.length() >= max_length) 01976 { 01977 str.length(max_length-4); 01978 str.append(STRING_WITH_LEN("...")); 01979 } 01980 my_printf_error(ER_DUP_ENTRY, msg, 01981 MYF(0), str.c_ptr(), table->key_info[key_nr].name); 01982 } 01983 01984 01985 /* 01986 Print error that we got from handler function 01987 01988 NOTE 01989 In case of delete table it's only safe to use the following parts of 01990 the 'table' structure: 01991 table->s->path 01992 table->alias 01993 */ 01994 01995 void handler::print_error(int error, myf errflag) 01996 { 01997 DBUG_ENTER("handler::print_error"); 01998 DBUG_PRINT("enter",("error: %d",error)); 01999 02000 int textno=ER_GET_ERRNO; 02001 switch (error) { 02002 case EACCES: 02003 textno=ER_OPEN_AS_READONLY; 02004 break; 02005 case EAGAIN: 02006 textno=ER_FILE_USED; 02007 break; 02008 case ENOENT: 02009 textno=ER_FILE_NOT_FOUND; 02010 break; 02011 case HA_ERR_KEY_NOT_FOUND: 02012 case HA_ERR_NO_ACTIVE_RECORD: 02013 case HA_ERR_END_OF_FILE: 02014 textno=ER_KEY_NOT_FOUND; 02015 break; 02016 case HA_ERR_WRONG_MRG_TABLE_DEF: 02017 textno=ER_WRONG_MRG_TABLE; 02018 break; 02019 case HA_ERR_FOUND_DUPP_KEY: 02020 { 02021 uint key_nr=get_dup_key(error); 02022 if ((int) key_nr >= 0) 02023 { 02024 print_keydup_error(key_nr, ER(ER_DUP_ENTRY)); 02025 DBUG_VOID_RETURN; 02026 } 02027 textno=ER_DUP_KEY; 02028 break; 02029 } 02030 case HA_ERR_FOREIGN_DUPLICATE_KEY: 02031 { 02032 uint key_nr= get_dup_key(error); 02033 if ((int) key_nr >= 0) 02034 { 02035 uint max_length; 02036 /* Write the key in the error message */ 02037 char key[MAX_KEY_LENGTH]; 02038 String str(key,sizeof(key),system_charset_info); 02039 /* Table is opened and defined at this point */ 02040 key_unpack(&str,table,(uint) key_nr); 02041 max_length= (MYSQL_ERRMSG_SIZE- 02042 (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY))); 02043 if (str.length() >= max_length) 02044 { 02045 str.length(max_length-4); 02046 str.append(STRING_WITH_LEN("...")); 02047 } 02048 my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str, 02049 str.c_ptr(), key_nr+1); 02050 DBUG_VOID_RETURN; 02051 } 02052 textno= ER_DUP_KEY; 02053 break; 02054 } 02055 case HA_ERR_NULL_IN_SPATIAL: 02056 textno= ER_UNKNOWN_ERROR; 02057 break; 02058 case HA_ERR_FOUND_DUPP_UNIQUE: 02059 textno=ER_DUP_UNIQUE; 02060 break; 02061 case HA_ERR_RECORD_CHANGED: 02062 textno=ER_CHECKREAD; 02063 break; 02064 case HA_ERR_CRASHED: 02065 textno=ER_NOT_KEYFILE; 02066 break; 02067 case HA_ERR_WRONG_IN_RECORD: 02068 textno= ER_CRASHED_ON_USAGE; 02069 break; 02070 case HA_ERR_CRASHED_ON_USAGE: 02071 textno=ER_CRASHED_ON_USAGE; 02072 break; 02073 case HA_ERR_NOT_A_TABLE: 02074 textno= error; 02075 break; 02076 case HA_ERR_CRASHED_ON_REPAIR: 02077 textno=ER_CRASHED_ON_REPAIR; 02078 break; 02079 case HA_ERR_OUT_OF_MEM: 02080 textno=ER_OUT_OF_RESOURCES; 02081 break; 02082 case HA_ERR_WRONG_COMMAND: 02083 textno=ER_ILLEGAL_HA; 02084 break; 02085 case HA_ERR_OLD_FILE: 02086 textno=ER_OLD_KEYFILE; 02087 break; 02088 case HA_ERR_UNSUPPORTED: 02089 textno=ER_UNSUPPORTED_EXTENSION; 02090 break; 02091 case HA_ERR_RECORD_FILE_FULL: 02092 case HA_ERR_INDEX_FILE_FULL: 02093 textno=ER_RECORD_FILE_FULL; 02094 break; 02095 case HA_ERR_LOCK_WAIT_TIMEOUT: 02096 textno=ER_LOCK_WAIT_TIMEOUT; 02097 break; 02098 case HA_ERR_LOCK_TABLE_FULL: 02099 textno=ER_LOCK_TABLE_FULL; 02100 break; 02101 case HA_ERR_LOCK_DEADLOCK: 02102 textno=ER_LOCK_DEADLOCK; 02103 break; 02104 case HA_ERR_READ_ONLY_TRANSACTION: 02105 textno=ER_READ_ONLY_TRANSACTION; 02106 break; 02107 case HA_ERR_CANNOT_ADD_FOREIGN: 02108 textno=ER_CANNOT_ADD_FOREIGN; 02109 break; 02110 case HA_ERR_ROW_IS_REFERENCED: 02111 { 02112 String str; 02113 get_error_message(error, &str); 02114 my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe()); 02115 DBUG_VOID_RETURN; 02116 } 02117 case HA_ERR_NO_REFERENCED_ROW: 02118 { 02119 String str; 02120 get_error_message(error, &str); 02121 my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe()); 02122 DBUG_VOID_RETURN; 02123 } 02124 case HA_ERR_TABLE_DEF_CHANGED: 02125 textno=ER_TABLE_DEF_CHANGED; 02126 break; 02127 case HA_ERR_NO_SUCH_TABLE: 02128 my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str, 02129 table_share->table_name.str); 02130 break; 02131 case HA_ERR_RBR_LOGGING_FAILED: 02132 textno= ER_BINLOG_ROW_LOGGING_FAILED; 02133 break; 02134 case HA_ERR_DROP_INDEX_FK: 02135 { 02136 const char *ptr= "???"; 02137 uint key_nr= get_dup_key(error); 02138 if ((int) key_nr >= 0) 02139 ptr= table->key_info[key_nr].name; 02140 my_error(ER_DROP_INDEX_FK, MYF(0), ptr); 02141 DBUG_VOID_RETURN; 02142 } 02143 case HA_ERR_TABLE_NEEDS_UPGRADE: 02144 textno=ER_TABLE_NEEDS_UPGRADE; 02145 break; 02146 case HA_ERR_TABLE_READONLY: 02147 textno= ER_OPEN_AS_READONLY; 02148 break; 02149 default: 02150 { 02151 /* The error was "unknown" to this function. 02152 Ask handler if it has got a message for this error */ 02153 bool temporary= FALSE; 02154 String str; 02155 temporary= get_error_message(error, &str); 02156 if (!str.is_empty()) 02157 { 02158 const char* engine= table_type(); 02159 if (temporary) 02160 my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine); 02161 else 02162 my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine); 02163 } 02164 else 02165 my_error(ER_GET_ERRNO,errflag,error); 02166 DBUG_VOID_RETURN; 02167 } 02168 } 02169 my_error(textno, errflag, table_share->table_name.str, error); 02170 DBUG_VOID_RETURN; 02171 } 02172 02173 02174 /* 02175 Return an error message specific to this handler 02176 02177 SYNOPSIS 02178 error error code previously returned by handler 02179 buf Pointer to String where to add error message 02180 02181 Returns true if this is a temporary error 02182 */ 02183 02184 bool handler::get_error_message(int error, String* buf) 02185 { 02186 return FALSE; 02187 } 02188 02189 02190 int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) 02191 { 02192 KEY *keyinfo, *keyend; 02193 KEY_PART_INFO *keypart, *keypartend; 02194 02195 if (!table->s->mysql_version) 02196 { 02197 /* check for blob-in-key error */ 02198 keyinfo= table->key_info; 02199 keyend= table->key_info + table->s->keys; 02200 for (; keyinfo < keyend; keyinfo++) 02201 { 02202 keypart= keyinfo->key_part; 02203 keypartend= keypart + keyinfo->key_parts; 02204 for (; keypart < keypartend; keypart++) 02205 { 02206 if (!keypart->fieldnr) 02207 continue; 02208 Field *field= table->field[keypart->fieldnr-1]; 02209 if (field->type() == FIELD_TYPE_BLOB) 02210 { 02211 if (check_opt->sql_flags & TT_FOR_UPGRADE) 02212 check_opt->flags= T_MEDIUM; 02213 return HA_ADMIN_NEEDS_CHECK; 02214 } 02215 } 02216 } 02217 } 02218 return check_for_upgrade(check_opt); 02219 } 02220 02221 02222 int handler::check_old_types() 02223 { 02224 Field** field; 02225 02226 if (!table->s->mysql_version) 02227 { 02228 /* check for bad DECIMAL field */ 02229 for (field= table->field; (*field); field++) 02230 { 02231 if ((*field)->type() == FIELD_TYPE_NEWDECIMAL) 02232 { 02233 return HA_ADMIN_NEEDS_ALTER; 02234 } 02235 } 02236 } 02237 return 0; 02238 } 02239 02240 02241 static bool update_frm_version(TABLE *table, bool needs_lock) 02242 { 02243 char path[FN_REFLEN]; 02244 File file; 02245 int result= 1; 02246 DBUG_ENTER("update_frm_version"); 02247 02248 if (table->s->mysql_version != MYSQL_VERSION_ID) 02249 DBUG_RETURN(0); 02250 02251 strxmov(path, table->s->normalized_path.str, reg_ext, NullS); 02252 02253 if (needs_lock) 02254 pthread_mutex_lock(&LOCK_open); 02255 02256 if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0) 02257 { 02258 uchar version[4]; 02259 char *key= table->s->table_cache_key.str; 02260 uint key_length= table->s->table_cache_key.length; 02261 TABLE *entry; 02262 HASH_SEARCH_STATE state; 02263 02264 int4store(version, MYSQL_VERSION_ID); 02265 02266 if ((result= my_pwrite(file,(byte*) version,4,51L,MYF_RW))) 02267 goto err; 02268 02269 for (entry=(TABLE*) hash_first(&open_cache,(byte*) key,key_length, &state); 02270 entry; 02271 entry= (TABLE*) hash_next(&open_cache,(byte*) key,key_length, &state)) 02272 entry->s->mysql_version= MYSQL_VERSION_ID; 02273 } 02274 err: 02275 if (file >= 0) 02276 VOID(my_close(file,MYF(MY_WME))); 02277 if (needs_lock) 02278 pthread_mutex_unlock(&LOCK_open); 02279 DBUG_RETURN(result); 02280 } 02281 02282 02283 02284 /* Return key if error because of duplicated keys */ 02285 02286 uint handler::get_dup_key(int error) 02287 { 02288 DBUG_ENTER("handler::get_dup_key"); 02289 table->file->errkey = (uint) -1; 02290 if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY || 02291 error == HA_ERR_FOUND_DUPP_UNIQUE || error == HA_ERR_NULL_IN_SPATIAL || 02292 error == HA_ERR_DROP_INDEX_FK) 02293 info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK); 02294 DBUG_RETURN(table->file->errkey); 02295 } 02296 02297 02298 /* 02299 Delete all files with extension from bas_ext() 02300 02301 SYNOPSIS 02302 delete_table() 02303 name Base name of table 02304 02305 NOTES 02306 We assume that the handler may return more extensions than 02307 was actually used for the file. 02308 02309 RETURN 02310 0 If we successfully deleted at least one file from base_ext and 02311 didn't get any other errors than ENOENT 02312 # Error 02313 */ 02314 02315 int handler::delete_table(const char *name) 02316 { 02317 int error= 0; 02318 int enoent_or_zero= ENOENT; // Error if no file was deleted 02319 char buff[FN_REFLEN]; 02320 02321 for (const char **ext=bas_ext(); *ext ; ext++) 02322 { 02323 fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT); 02324 if (my_delete_with_symlink(buff, MYF(0))) 02325 { 02326 if ((error= my_errno) != ENOENT) 02327 break; 02328 } 02329 else 02330 enoent_or_zero= 0; // No error for ENOENT 02331 error= enoent_or_zero; 02332 } 02333 return error; 02334 } 02335 02336 02337 int handler::rename_table(const char * from, const char * to) 02338 { 02339 int error= 0; 02340 for (const char **ext= bas_ext(); *ext ; ext++) 02341 { 02342 if (rename_file_ext(from, to, *ext)) 02343 { 02344 if ((error=my_errno) != ENOENT) 02345 break; 02346 error= 0; 02347 } 02348 } 02349 return error; 02350 } 02351 02352 02353 void handler::drop_table(const char *name) 02354 { 02355 close(); 02356 delete_table(name); 02357 } 02358 02359 02360 /* 02361 Performs checks upon the table. 02362 02363 SYNOPSIS 02364 check() 02365 thd thread doing CHECK TABLE operation 02366 check_opt options from the parser 02367 02368 NOTES 02369 02370 RETURN 02371 HA_ADMIN_OK Successful upgrade 02372 HA_ADMIN_NEEDS_UPGRADE Table has structures requiring upgrade 02373 HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE 02374 HA_ADMIN_NOT_IMPLEMENTED 02375 */ 02376 02377 int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) 02378 { 02379 int error; 02380 02381 if ((table->s->mysql_version >= MYSQL_VERSION_ID) && 02382 (check_opt->sql_flags & TT_FOR_UPGRADE)) 02383 return 0; 02384 02385 if (table->s->mysql_version < MYSQL_VERSION_ID) 02386 { 02387 if ((error= check_old_types())) 02388 return error; 02389 error= ha_check_for_upgrade(check_opt); 02390 if (error && (error != HA_ADMIN_NEEDS_CHECK)) 02391 return error; 02392 if (!error && (check_opt->sql_flags & TT_FOR_UPGRADE)) 02393 return 0; 02394 } 02395 if ((error= check(thd, check_opt))) 02396 return error; 02397 return update_frm_version(table, 0); 02398 } 02399 02400 02401 int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) 02402 { 02403 int result; 02404 if ((result= repair(thd, check_opt))) 02405 return result; 02406 return update_frm_version(table, 0); 02407 } 02408 02409 02410 /* 02411 Tell the storage engine that it is allowed to "disable transaction" in the 02412 handler. It is a hint that ACID is not required - it is used in NDB for 02413 ALTER TABLE, for example, when data are copied to temporary table. 02414 A storage engine may treat this hint any way it likes. NDB for example 02415 starts to commit every now and then automatically. 02416 This hint can be safely ignored. 02417 */ 02418 02419 int ha_enable_transaction(THD *thd, bool on) 02420 { 02421 int error=0; 02422 02423 DBUG_ENTER("ha_enable_transaction"); 02424 thd->transaction.on= on; 02425 if (on) 02426 { 02427 /* 02428 Now all storage engines should have transaction handling enabled. 02429 But some may have it enabled all the time - "disabling" transactions 02430 is an optimization hint that storage engine is free to ignore. 02431 So, let's commit an open transaction (if any) now. 02432 */ 02433 if (!(error= ha_commit_stmt(thd))) 02434 error= end_trans(thd, COMMIT); 02435 } 02436 DBUG_RETURN(error); 02437 } 02438 02439 int handler::index_next_same(byte *buf, const byte *key, uint keylen) 02440 { 02441 int error; 02442 if (!(error=index_next(buf))) 02443 { 02444 if (key_cmp_if_same(table, key, active_index, keylen)) 02445 { 02446 table->status=STATUS_NOT_FOUND; 02447 error=HA_ERR_END_OF_FILE; 02448 } 02449 } 02450 return error; 02451 } 02452 02453 02454 void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, 02455 uint part_id) 02456 { 02457 info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE | 02458 HA_STATUS_NO_LOCK); 02459 stat_info->records= stats.records; 02460 stat_info->mean_rec_length= stats.mean_rec_length; 02461 stat_info->data_file_length= stats.data_file_length; 02462 stat_info->max_data_file_length= stats.max_data_file_length; 02463 stat_info->index_file_length= stats.index_file_length; 02464 stat_info->delete_length= stats.delete_length; 02465 stat_info->create_time= stats.create_time; 02466 stat_info->update_time= stats.update_time; 02467 stat_info->check_time= stats.check_time; 02468 stat_info->check_sum= 0; 02469 if (table_flags() & (ulong) HA_HAS_CHECKSUM) 02470 stat_info->check_sum= checksum(); 02471 return; 02472 } 02473 02474 02475 /**************************************************************************** 02476 ** Some general functions that isn't in the handler class 02477 ****************************************************************************/ 02478 02479 /* 02480 Initiates table-file and calls appropriate database-creator 02481 02482 NOTES 02483 We must have a write lock on LOCK_open to be sure no other thread 02484 interferes with table 02485 02486 RETURN 02487 0 ok 02488 1 error 02489 */ 02490 02491 int ha_create_table(THD *thd, const char *path, 02492 const char *db, const char *table_name, 02493 HA_CREATE_INFO *create_info, 02494 bool update_create_info) 02495 { 02496 int error= 1; 02497 TABLE table; 02498 char name_buff[FN_REFLEN]; 02499 const char *name; 02500 TABLE_SHARE share; 02501 DBUG_ENTER("ha_create_table"); 02502 02503 init_tmp_table_share(&share, db, 0, table_name, path); 02504 if (open_table_def(thd, &share, 0) || 02505 open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, 0, &table, 02506 TRUE)) 02507 goto err; 02508 02509 if (update_create_info) 02510 update_create_info_from_table(create_info, &table); 02511 02512 name= share.path.str; 02513 if (lower_case_table_names == 2 && 02514 !(table.file->ha_table_flags() & HA_FILE_BASED)) 02515 { 02516 /* Ensure that handler gets name in lower case */ 02517 strmov(name_buff, name); 02518 my_casedn_str(files_charset_info, name_buff); 02519 name= name_buff; 02520 } 02521 02522 error= table.file->create(name, &table, create_info); 02523 VOID(closefrm(&table, 0)); 02524 if (error) 02525 { 02526 strxmov(name_buff, db, ".", table_name, NullS); 02527 my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error); 02528 } 02529 err: 02530 free_table_share(&share); 02531 DBUG_RETURN(error != 0); 02532 } 02533 02534 /* 02535 Try to discover table from engine 02536 02537 NOTES 02538 If found, write the frm file to disk. 02539 02540 RETURN VALUES: 02541 -1 Table did not exists 02542 0 Table created ok 02543 > 0 Error, table existed but could not be created 02544 02545 */ 02546 02547 int ha_create_table_from_engine(THD* thd, const char *db, const char *name) 02548 { 02549 int error; 02550 const void *frmblob; 02551 uint frmlen; 02552 char path[FN_REFLEN]; 02553 HA_CREATE_INFO create_info; 02554 TABLE table; 02555 TABLE_SHARE share; 02556 DBUG_ENTER("ha_create_table_from_engine"); 02557 DBUG_PRINT("enter", ("name '%s'.'%s'", db, name)); 02558 02559 bzero((char*) &create_info,sizeof(create_info)); 02560 if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) 02561 { 02562 /* Table could not be discovered and thus not created */ 02563 DBUG_RETURN(error); 02564 } 02565 02566 /* 02567 Table exists in handler and could be discovered 02568 frmblob and frmlen are set, write the frm to disk 02569 */ 02570 02571 (void)strxnmov(path,FN_REFLEN-1,mysql_data_home,"/",db,"/",name,NullS); 02572 // Save the frm file 02573 error= writefrm(path, frmblob, frmlen); 02574 my_free((char*) frmblob, MYF(0)); 02575 if (error) 02576 DBUG_RETURN(2); 02577 02578 init_tmp_table_share(&share, db, 0, name, path); 02579 if (open_table_def(thd, &share, 0)) 02580 { 02581 DBUG_RETURN(3); 02582 } 02583 if (open_table_from_share(thd, &share, "" ,0, 0, 0, &table, FALSE)) 02584 { 02585 free_table_share(&share); 02586 DBUG_RETURN(3); 02587 } 02588 02589 update_create_info_from_table(&create_info, &table); 02590 create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE; 02591 02592 if (lower_case_table_names == 2 && 02593 !(table.file->ha_table_flags() & HA_FILE_BASED)) 02594 { 02595 /* Ensure that handler gets name in lower case */ 02596 my_casedn_str(files_charset_info, path); 02597 } 02598 error=table.file->create(path,&table,&create_info); 02599 VOID(closefrm(&table, 1)); 02600 02601 DBUG_RETURN(error != 0); 02602 } 02603 02604 void st_ha_check_opt::init() 02605 { 02606 flags= sql_flags= 0; 02607 sort_buffer_size = current_thd->variables.myisam_sort_buff_size; 02608 } 02609 02610 02611 /***************************************************************************** 02612 Key cache handling. 02613 02614 This code is only relevant for ISAM/MyISAM tables 02615 02616 key_cache->cache may be 0 only in the case where a key cache is not 02617 initialized or when we where not able to init the key cache in a previous 02618 call to ha_init_key_cache() (probably out of memory) 02619 *****************************************************************************/ 02620 02621 /* Init a key cache if it has not been initied before */ 02622 02623 02624 int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) 02625 { 02626 DBUG_ENTER("ha_init_key_cache"); 02627 02628 if (!key_cache->key_cache_inited) 02629 { 02630 pthread_mutex_lock(&LOCK_global_system_variables); 02631 long tmp_buff_size= (long) key_cache->param_buff_size; 02632 long tmp_block_size= (long) key_cache->param_block_size; 02633 uint division_limit= key_cache->param_division_limit; 02634 uint age_threshold= key_cache->param_age_threshold; 02635 pthread_mutex_unlock(&LOCK_global_system_variables); 02636 DBUG_RETURN(!init_key_cache(key_cache, 02637 tmp_block_size, 02638 tmp_buff_size, 02639 division_limit, age_threshold)); 02640 } 02641 DBUG_RETURN(0); 02642 } 02643 02644 02645 /* Resize key cache */ 02646 02647 int ha_resize_key_cache(KEY_CACHE *key_cache) 02648 { 02649 DBUG_ENTER("ha_resize_key_cache"); 02650 02651 if (key_cache->key_cache_inited) 02652 { 02653 pthread_mutex_lock(&LOCK_global_system_variables); 02654 long tmp_buff_size= (long) key_cache->param_buff_size; 02655 long tmp_block_size= (long) key_cache->param_block_size; 02656 uint division_limit= key_cache->param_division_limit; 02657 uint age_threshold= key_cache->param_age_threshold; 02658 pthread_mutex_unlock(&LOCK_global_system_variables); 02659 DBUG_RETURN(!resize_key_cache(key_cache, tmp_block_size, 02660 tmp_buff_size, 02661 division_limit, age_threshold)); 02662 } 02663 DBUG_RETURN(0); 02664 } 02665 02666 02667 /* Change parameters for key cache (like size) */ 02668 02669 int ha_change_key_cache_param(KEY_CACHE *key_cache) 02670 { 02671 if (key_cache->key_cache_inited) 02672 { 02673 pthread_mutex_lock(&LOCK_global_system_variables); 02674 uint division_limit= key_cache->param_division_limit; 02675 uint age_threshold= key_cache->param_age_threshold; 02676 pthread_mutex_unlock(&LOCK_global_system_variables); 02677 change_key_cache_param(key_cache, division_limit, age_threshold); 02678 } 02679 return 0; 02680 } 02681 02682 /* Free memory allocated by a key cache */ 02683 02684 int ha_end_key_cache(KEY_CACHE *key_cache) 02685 { 02686 end_key_cache(key_cache, 1); // Can never fail 02687 return 0; 02688 } 02689 02690 /* Move all tables from one key cache to another one */ 02691 02692 int ha_change_key_cache(KEY_CACHE *old_key_cache, 02693 KEY_CACHE *new_key_cache) 02694 { 02695 mi_change_key_cache(old_key_cache, new_key_cache); 02696 return 0; 02697 } 02698 02699 02700 /* 02701 Try to discover one table from handler(s) 02702 02703 RETURN 02704 -1 : Table did not exists 02705 0 : OK. In this case *frmblob and *frmlen are set 02706 >0 : error. frmblob and frmlen may not be set 02707 */ 02708 02709 int ha_discover(THD *thd, const char *db, const char *name, 02710 const void **frmblob, uint *frmlen) 02711 { 02712 int error= -1; // Table does not exist in any handler 02713 DBUG_ENTER("ha_discover"); 02714 DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); 02715 if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */ 02716 DBUG_RETURN(error); 02717 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 02718 if (have_ndbcluster == SHOW_OPTION_YES) 02719 error= ndbcluster_discover(thd, db, name, frmblob, frmlen); 02720 #endif 02721 if (!error) 02722 statistic_increment(thd->status_var.ha_discover_count,&LOCK_status); 02723 DBUG_RETURN(error); 02724 } 02725 02726 02727 /* 02728 Call this function in order to give the handler the possibility 02729 to ask engine if there are any new tables that should be written to disk 02730 or any dropped tables that need to be removed from disk 02731 */ 02732 02733 int 02734 ha_find_files(THD *thd,const char *db,const char *path, 02735 const char *wild, bool dir, List<char> *files) 02736 { 02737 int error= 0; 02738 DBUG_ENTER("ha_find_files"); 02739 DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d", 02740 db, path, wild, dir)); 02741 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 02742 if (have_ndbcluster == SHOW_OPTION_YES) 02743 error= ndbcluster_find_files(thd, db, path, wild, dir, files); 02744 #endif 02745 DBUG_RETURN(error); 02746 } 02747 02748 02749 /* 02750 Ask handler if the table exists in engine 02751 02752 RETURN 02753 0 Table does not exist 02754 1 Table exists 02755 # Error code 02756 02757 */ 02758 int ha_table_exists_in_engine(THD* thd, const char* db, const char* name) 02759 { 02760 int error= 0; 02761 DBUG_ENTER("ha_table_exists_in_engine"); 02762 DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); 02763 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 02764 if (have_ndbcluster == SHOW_OPTION_YES) 02765 error= ndbcluster_table_exists_in_engine(thd, db, name); 02766 #endif 02767 DBUG_PRINT("exit", ("error: %d", error)); 02768 DBUG_RETURN(error); 02769 } 02770 02771 #ifdef HAVE_NDB_BINLOG 02772 /* 02773 TODO: change this into a dynamic struct 02774 List<handlerton> does not work as 02775 1. binlog_end is called when MEM_ROOT is gone 02776 2. cannot work with thd MEM_ROOT as memory should be freed 02777 */ 02778 #define MAX_HTON_LIST_ST 63 02779 struct hton_list_st 02780 { 02781 handlerton *hton[MAX_HTON_LIST_ST]; 02782 uint sz; 02783 }; 02784 02785 struct binlog_func_st 02786 { 02787 enum_binlog_func fn; 02788 void *arg; 02789 }; 02790 02791 /* 02792 Listing handlertons first to avoid recursive calls and deadlock 02793 */ 02794 static my_bool binlog_func_list(THD *thd, st_plugin_int *plugin, void *arg) 02795 { 02796 hton_list_st *hton_list= (hton_list_st *)arg; 02797 handlerton *hton= (handlerton *)plugin->data; 02798 if (hton->state == SHOW_OPTION_YES && hton->binlog_func) 02799 { 02800 uint sz= hton_list->sz; 02801 if (sz == MAX_HTON_LIST_ST-1) 02802 { 02803 /* list full */ 02804 return FALSE; 02805 } 02806 hton_list->hton[sz]= hton; 02807 hton_list->sz= sz+1; 02808 } 02809 return FALSE; 02810 } 02811 02812 static my_bool binlog_func_foreach(THD *thd, binlog_func_st *bfn) 02813 { 02814 handlerton *hton; 02815 hton_list_st hton_list; 02816 hton_list.sz= 0; 02817 plugin_foreach(thd, binlog_func_list, 02818 MYSQL_STORAGE_ENGINE_PLUGIN, &hton_list); 02819 02820 uint i= 0, sz= hton_list.sz; 02821 while(i < sz) 02822 hton_list.hton[i++]->binlog_func(thd, bfn->fn, bfn->arg); 02823 return FALSE; 02824 } 02825 02826 int ha_reset_logs(THD *thd) 02827 { 02828 binlog_func_st bfn= {BFN_RESET_LOGS, 0}; 02829 binlog_func_foreach(thd, &bfn); 02830 return 0; 02831 } 02832 02833 void ha_reset_slave(THD* thd) 02834 { 02835 binlog_func_st bfn= {BFN_RESET_SLAVE, 0}; 02836 binlog_func_foreach(thd, &bfn); 02837 } 02838 02839 void ha_binlog_wait(THD* thd) 02840 { 02841 binlog_func_st bfn= {BFN_BINLOG_WAIT, 0}; 02842 binlog_func_foreach(thd, &bfn); 02843 } 02844 02845 int ha_binlog_end(THD* thd) 02846 { 02847 binlog_func_st bfn= {BFN_BINLOG_END, 0}; 02848 binlog_func_foreach(thd, &bfn); 02849 return 0; 02850 } 02851 02852 int ha_binlog_index_purge_file(THD *thd, const char *file) 02853 { 02854 binlog_func_st bfn= {BFN_BINLOG_PURGE_FILE, (void *)file}; 02855 binlog_func_foreach(thd, &bfn); 02856 return 0; 02857 } 02858 02859 struct binlog_log_query_st 02860 { 02861 enum_binlog_command binlog_command; 02862 const char *query; 02863 uint query_length; 02864 const char *db; 02865 const char *table_name; 02866 }; 02867 02868 static my_bool binlog_log_query_handlerton2(THD *thd, 02869 const handlerton *hton, 02870 void *args) 02871 { 02872 struct binlog_log_query_st *b= (struct binlog_log_query_st*)args; 02873 if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) 02874 hton->binlog_log_query(thd, 02875 b->binlog_command, 02876 b->query, 02877 b->query_length, 02878 b->db, 02879 b->table_name); 02880 return FALSE; 02881 } 02882 02883 static my_bool binlog_log_query_handlerton(THD *thd, 02884 st_plugin_int *plugin, 02885 void *args) 02886 { 02887 return binlog_log_query_handlerton2(thd, (const handlerton *)plugin->data, args); 02888 } 02889 02890 void ha_binlog_log_query(THD *thd, const handlerton *hton, 02891 enum_binlog_command binlog_command, 02892 const char *query, uint query_length, 02893 const char *db, const char *table_name) 02894 { 02895 struct binlog_log_query_st b; 02896 b.binlog_command= binlog_command; 02897 b.query= query; 02898 b.query_length= query_length; 02899 b.db= db; 02900 b.table_name= table_name; 02901 if (hton == 0) 02902 plugin_foreach(thd, binlog_log_query_handlerton, 02903 MYSQL_STORAGE_ENGINE_PLUGIN, &b); 02904 else 02905 binlog_log_query_handlerton2(thd, hton, &b); 02906 } 02907 #endif 02908 02909 /* 02910 Read the first row of a multi-range set. 02911 02912 SYNOPSIS 02913 read_multi_range_first() 02914 found_range_p Returns a pointer to the element in 'ranges' that 02915 corresponds to the returned row. 02916 ranges An array of KEY_MULTI_RANGE range descriptions. 02917 range_count Number of ranges in 'ranges'. 02918 sorted If result should be sorted per key. 02919 buffer A HANDLER_BUFFER for internal handler usage. 02920 02921 NOTES 02922 Record is read into table->record[0]. 02923 *found_range_p returns a valid value only if read_multi_range_first() 02924 returns 0. 02925 Sorting is done within each range. If you want an overall sort, enter 02926 'ranges' with sorted ranges. 02927 02928 RETURN 02929 0 OK, found a row 02930 HA_ERR_END_OF_FILE No rows in range 02931 # Error code 02932 */ 02933 02934 int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, 02935 KEY_MULTI_RANGE *ranges, uint range_count, 02936 bool sorted, HANDLER_BUFFER *buffer) 02937 { 02938 int result= HA_ERR_END_OF_FILE; 02939 DBUG_ENTER("handler::read_multi_range_first"); 02940 multi_range_sorted= sorted; 02941 multi_range_buffer= buffer; 02942 02943 table->mark_columns_used_by_index_no_reset(active_index, table->read_set); 02944 table->column_bitmaps_set(table->read_set, table->write_set); 02945 02946 for (multi_range_curr= ranges, multi_range_end= ranges + range_count; 02947 multi_range_curr < multi_range_end; 02948 multi_range_curr++) 02949 { 02950 result= read_range_first(multi_range_curr->start_key.length ? 02951 &multi_range_curr->start_key : 0, 02952 multi_range_curr->end_key.length ? 02953 &multi_range_curr->end_key : 0, 02954 test(multi_range_curr->range_flag & EQ_RANGE), 02955 multi_range_sorted); 02956 if (result != HA_ERR_END_OF_FILE) 02957 break; 02958 } 02959 02960 *found_range_p= multi_range_curr; 02961 DBUG_PRINT("exit",("result %d", result)); 02962 DBUG_RETURN(result); 02963 } 02964 02965 02966 /* 02967 Read the next row of a multi-range set. 02968 02969 SYNOPSIS 02970 read_multi_range_next() 02971 found_range_p Returns a pointer to the element in 'ranges' that 02972 corresponds to the returned row. 02973 02974 NOTES 02975 Record is read into table->record[0]. 02976 *found_range_p returns a valid value only if read_multi_range_next() 02977 returns 0. 02978 02979 RETURN 02980 0 OK, found a row 02981 HA_ERR_END_OF_FILE No (more) rows in range 02982 # Error code 02983 */ 02984 02985 int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) 02986 { 02987 int result; 02988 DBUG_ENTER("handler::read_multi_range_next"); 02989 02990 /* We should not be called after the last call returned EOF. */ 02991 DBUG_ASSERT(multi_range_curr < multi_range_end); 02992 02993 do 02994 { 02995 /* Save a call if there can be only one row in range. */ 02996 if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE)) 02997 { 02998 result= read_range_next(); 02999 03000 /* On success or non-EOF errors jump to the end. */ 03001 if (result != HA_ERR_END_OF_FILE) 03002 break; 03003 } 03004 else 03005 { 03006 /* 03007 We need to set this for the last range only, but checking this 03008 condition is more expensive than just setting the result code. 03009 */ 03010 result= HA_ERR_END_OF_FILE; 03011 } 03012 03013 /* Try the next range(s) until one matches a record. */ 03014 for (multi_range_curr++; 03015 multi_range_curr < multi_range_end; 03016 multi_range_curr++) 03017 { 03018 result= read_range_first(multi_range_curr->start_key.length ? 03019 &multi_range_curr->start_key : 0, 03020 multi_range_curr->end_key.length ? 03021 &multi_range_curr->end_key : 0, 03022 test(multi_range_curr->range_flag & EQ_RANGE), 03023 multi_range_sorted); 03024 if (result != HA_ERR_END_OF_FILE) 03025 break; 03026 } 03027 } 03028 while ((result == HA_ERR_END_OF_FILE) && 03029 (multi_range_curr < multi_range_end)); 03030 03031 *found_range_p= multi_range_curr; 03032 DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result)); 03033 DBUG_RETURN(result); 03034 } 03035 03036 03037 /* 03038 Read first row between two ranges. 03039 Store ranges for future calls to read_range_next 03040 03041 SYNOPSIS 03042 read_range_first() 03043 start_key Start key. Is 0 if no min range 03044 end_key End key. Is 0 if no max range 03045 eq_range_arg Set to 1 if start_key == end_key 03046 sorted Set to 1 if result should be sorted per key 03047 03048 NOTES 03049 Record is read into table->record[0] 03050 03051 RETURN 03052 0 Found row 03053 HA_ERR_END_OF_FILE No rows in range 03054 # Error code 03055 */ 03056 03057 int handler::read_range_first(const key_range *start_key, 03058 const key_range *end_key, 03059 bool eq_range_arg, bool sorted) 03060 { 03061 int result; 03062 DBUG_ENTER("handler::read_range_first"); 03063 03064 eq_range= eq_range_arg; 03065 end_range= 0; 03066 if (end_key) 03067 { 03068 end_range= &save_end_range; 03069 save_end_range= *end_key; 03070 key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 : 03071 (end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0); 03072 } 03073 range_key_part= table->key_info[active_index].key_part; 03074 03075 if (!start_key) // Read first record 03076 result= index_first(table->record[0]); 03077 else 03078 result= index_read(table->record[0], 03079 start_key->key, 03080 start_key->length, 03081 start_key->flag); 03082 if (result) 03083 DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND) 03084 ? HA_ERR_END_OF_FILE 03085 : result); 03086 03087 DBUG_RETURN (compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE); 03088 } 03089 03090 03091 /* 03092 Read next row between two ranges. 03093 03094 SYNOPSIS 03095 read_range_next() 03096 03097 NOTES 03098 Record is read into table->record[0] 03099 03100 RETURN 03101 0 Found row 03102 HA_ERR_END_OF_FILE No rows in range 03103 # Error code 03104 */ 03105 03106 int handler::read_range_next() 03107 { 03108 int result; 03109 DBUG_ENTER("handler::read_range_next"); 03110 03111 if (eq_range) 03112 { 03113 /* We trust that index_next_same always gives a row in range */ 03114 DBUG_RETURN(index_next_same(table->record[0], 03115 end_range->key, 03116 end_range->length)); 03117 } 03118 result= index_next(table->record[0]); 03119 if (result) 03120 DBUG_RETURN(result); 03121 DBUG_RETURN(compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE); 03122 } 03123 03124 03125 /* 03126 Compare if found key (in row) is over max-value 03127 03128 SYNOPSIS 03129 compare_key 03130 range range to compare to row. May be 0 for no range 03131 03132 NOTES 03133 See key.cc::key_cmp() for details 03134 03135 RETURN 03136 The return value is SIGN(key_in_row - range_key): 03137 03138 0 Key is equal to range or 'range' == 0 (no range) 03139 -1 Key is less than range 03140 1 Key is larger than range 03141 */ 03142 03143 int handler::compare_key(key_range *range) 03144 { 03145 int cmp; 03146 if (!range) 03147 return 0; // No max range 03148 cmp= key_cmp(range_key_part, range->key, range->length); 03149 if (!cmp) 03150 cmp= key_compare_result_on_equal; 03151 return cmp; 03152 } 03153 03154 int handler::index_read_idx(byte * buf, uint index, const byte * key, 03155 uint key_len, enum ha_rkey_function find_flag) 03156 { 03157 int error= ha_index_init(index, 0); 03158 if (!error) 03159 error= index_read(buf, key, key_len, find_flag); 03160 if (!error) 03161 error= ha_index_end(); 03162 return error; 03163 } 03164 03165 03166 /* 03167 Returns a list of all known extensions. 03168 03169 SYNOPSIS 03170 ha_known_exts() 03171 03172 NOTES 03173 No mutexes, worst case race is a minor surplus memory allocation 03174 We have to recreate the extension map if mysqld is restarted (for example 03175 within libmysqld) 03176 03177 RETURN VALUE 03178 pointer pointer to TYPELIB structure 03179 */ 03180 03181 static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin, 03182 void *arg) 03183 { 03184 List<char> *found_exts= (List<char> *) arg; 03185 handlerton *hton= (handlerton *)plugin->data; 03186 handler *file; 03187 if (hton->state == SHOW_OPTION_YES && hton->create && 03188 (file= hton->create((TABLE_SHARE*) 0, current_thd->mem_root))) 03189 { 03190 List_iterator_fast<char> it(*found_exts); 03191 const char **ext, *old_ext; 03192 03193 for (ext= file->bas_ext(); *ext; ext++) 03194 { 03195 while ((old_ext= it++)) 03196 { 03197 if (!strcmp(old_ext, *ext)) 03198 break; 03199 } 03200 if (!old_ext) 03201 found_exts->push_back((char *) *ext); 03202 03203 it.rewind(); 03204 } 03205 delete file; 03206 } 03207 return FALSE; 03208 } 03209 03210 TYPELIB *ha_known_exts(void) 03211 { 03212 MEM_ROOT *mem_root= current_thd->mem_root; 03213 if (!known_extensions.type_names || mysys_usage_id != known_extensions_id) 03214 { 03215 List<char> found_exts; 03216 const char **ext, *old_ext; 03217 03218 known_extensions_id= mysys_usage_id; 03219 found_exts.push_back((char*) triggers_file_ext); 03220 found_exts.push_back((char*) trigname_file_ext); 03221 03222 plugin_foreach(NULL, exts_handlerton, 03223 MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts); 03224 03225 ext= (const char **) my_once_alloc(sizeof(char *)* 03226 (found_exts.elements+1), 03227 MYF(MY_WME | MY_FAE)); 03228 03229 DBUG_ASSERT(ext != 0); 03230 known_extensions.count= found_exts.elements; 03231 known_extensions.type_names= ext; 03232 03233 List_iterator_fast<char> it(found_exts); 03234 while ((old_ext= it++)) 03235 *ext++= old_ext; 03236 *ext= 0; 03237 } 03238 return &known_extensions; 03239 } 03240 03241 03242 static bool stat_print(THD *thd, const char *type, uint type_len, 03243 const char *file, uint file_len, 03244 const char *status, uint status_len) 03245 { 03246 Protocol *protocol= thd->protocol; 03247 protocol->prepare_for_resend(); 03248 protocol->store(type, type_len, system_charset_info); 03249 protocol->store(file, file_len, system_charset_info); 03250 protocol->store(status, status_len, system_charset_info); 03251 if (protocol->write()) 03252 return TRUE; 03253 return FALSE; 03254 } 03255 03256 03257 static my_bool showstat_handlerton(THD *thd, st_plugin_int *plugin, 03258 void *arg) 03259 { 03260 enum ha_stat_type stat= *(enum ha_stat_type *) arg; 03261 handlerton *hton= (handlerton *)plugin->data; 03262 if (hton->state == SHOW_OPTION_YES && hton->show_status && 03263 hton->show_status(thd, stat_print, stat)) 03264 return TRUE; 03265 return FALSE; 03266 } 03267 03268 bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) 03269 { 03270 List<Item> field_list; 03271 Protocol *protocol= thd->protocol; 03272 bool result; 03273 03274 field_list.push_back(new Item_empty_string("Type",10)); 03275 field_list.push_back(new Item_empty_string("Name",FN_REFLEN)); 03276 field_list.push_back(new Item_empty_string("Status",10)); 03277 03278 if (protocol->send_fields(&field_list, 03279 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 03280 return TRUE; 03281 03282 if (db_type == NULL) 03283 { 03284 result= plugin_foreach(thd, showstat_handlerton, 03285 MYSQL_STORAGE_ENGINE_PLUGIN, &stat); 03286 } 03287 else 03288 { 03289 if (db_type->state != SHOW_OPTION_YES) 03290 { 03291 const LEX_STRING *name=&hton2plugin[db_type->slot]->name; 03292 result= stat_print(thd, name->str, name->length, 03293 "", 0, "DISABLED", 8) ? 1 : 0; 03294 } 03295 else 03296 result= db_type->show_status && 03297 db_type->show_status(thd, stat_print, stat) ? 1 : 0; 03298 } 03299 03300 if (!result) 03301 send_eof(thd); 03302 return result; 03303 } 03304 03305 /* 03306 Function to check if the conditions for row-based binlogging is 03307 correct for the table. 03308 03309 A row in the given table should be replicated if: 03310 - Row-based replication is enabled in the current thread 03311 - The binlog is enabled 03312 - It is not a temporary table 03313 - The binary log is open 03314 - The database the table resides in shall be binlogged (binlog_*_db rules) 03315 - table is not mysql.event 03316 */ 03317 03318 #ifdef HAVE_ROW_BASED_REPLICATION 03319 /* The Sun compiler cannot instantiate the template below if this is 03320 declared static, but it works by putting it into an anonymous 03321 namespace. */ 03322 namespace { 03323 struct st_table_data { 03324 char const *db; 03325 char const *name; 03326 }; 03327 03328 static int table_name_compare(void const *a, void const *b) 03329 { 03330 st_table_data const *x = (st_table_data const*) a; 03331 st_table_data const *y = (st_table_data const*) b; 03332 03333 /* Doing lexical compare in order (db,name) */ 03334 int const res= strcmp(x->db, y->db); 03335 return res != 0 ? res : strcmp(x->name, y->name); 03336 } 03337 03338 bool check_table_binlog_row_based(THD *thd, TABLE *table) 03339 { 03340 static st_table_data const ignore[] = { 03341 { "mysql", "event" }, 03342 { "mysql", "general_log" }, 03343 { "mysql", "slow_log" } 03344 }; 03345 03346 my_size_t const ignore_size = sizeof(ignore)/sizeof(*ignore); 03347 st_table_data const item = { table->s->db.str, table->s->table_name.str }; 03348 03349 if (table->s->cached_row_logging_check == -1) 03350 table->s->cached_row_logging_check= 03351 (table->s->tmp_table == NO_TMP_TABLE) && 03352 binlog_filter->db_ok(table->s->db.str) && 03353 bsearch(&item, ignore, ignore_size, 03354 sizeof(st_table_data), table_name_compare) == NULL; 03355 03356 DBUG_ASSERT(table->s->cached_row_logging_check == 0 || 03357 table->s->cached_row_logging_check == 1); 03358 03359 return (thd->current_stmt_binlog_row_based && 03360 (thd->options & OPTION_BIN_LOG) && 03361 mysql_bin_log.is_open() && 03362 table->s->cached_row_logging_check); 03363 } 03364 } 03365 03366 /* 03367 Write table maps for all (manually or automatically) locked tables 03368 to the binary log. 03369 03370 SYNOPSIS 03371 write_locked_table_maps() 03372 thd Pointer to THD structure 03373 03374 DESCRIPTION 03375 This function will generate and write table maps for all tables 03376 that are locked by the thread 'thd'. Either manually locked 03377 (stored in THD::locked_tables) and automatically locked (stored 03378 in THD::lock) are considered. 03379 03380 RETURN VALUE 03381 0 All OK 03382 1 Failed to write all table maps 03383 03384 SEE ALSO 03385 THD::lock 03386 THD::locked_tables 03387 */ 03388 namespace 03389 { 03390 int write_locked_table_maps(THD *thd) 03391 { 03392 DBUG_ENTER("write_locked_table_maps"); 03393 DBUG_PRINT("enter", ("thd=%p, thd->lock=%p, thd->locked_tables=%p, thd->extra_lock", 03394 thd, thd->lock, thd->locked_tables, thd->extra_lock)); 03395 03396 if (thd->get_binlog_table_maps() == 0) 03397 { 03398 MYSQL_LOCK *locks[3]; 03399 locks[0]= thd->extra_lock; 03400 locks[1]= thd->lock; 03401 locks[2]= thd->locked_tables; 03402 for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i ) 03403 { 03404 MYSQL_LOCK const *const lock= locks[i]; 03405 if (lock == NULL) 03406 continue; 03407 03408 TABLE **const end_ptr= lock->table + lock->table_count; 03409 for (TABLE **table_ptr= lock->table ; 03410 table_ptr != end_ptr ; 03411 ++table_ptr) 03412 { 03413 TABLE *const table= *table_ptr; 03414 DBUG_PRINT("info", ("Checking table %s", table->s->table_name)); 03415 if (table->current_lock == F_WRLCK && 03416 check_table_binlog_row_based(thd, table)) 03417 { 03418 int const has_trans= table->file->has_transactions(); 03419 int const error= thd->binlog_write_table_map(table, has_trans); 03420 /* 03421 If an error occurs, it is the responsibility of the caller to 03422 roll back the transaction. 03423 */ 03424 if (unlikely(error)) 03425 DBUG_RETURN(1); 03426 } 03427 } 03428 } 03429 } 03430 DBUG_RETURN(0); 03431 } 03432 03433 template<class RowsEventT> int 03434 binlog_log_row(TABLE* table, 03435 const byte *before_record, 03436 const byte *after_record) 03437 { 03438 if (table->file->ha_table_flags() & HA_HAS_OWN_BINLOGGING) 03439 return 0; 03440 bool error= 0; 03441 THD *const thd= table->in_use; 03442 03443 if (check_table_binlog_row_based(thd, table)) 03444 { 03445 MY_BITMAP cols; 03446 /* Potential buffer on the stack for the bitmap */ 03447 uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)]; 03448 uint n_fields= table->s->fields; 03449 my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8; 03450 03451 /* 03452 If there are no table maps written to the binary log, this is 03453 the first row handled in this statement. In that case, we need 03454 to write table maps for all locked tables to the binary log. 03455 */ 03456 if (likely(!(error= bitmap_init(&cols, 03457 use_bitbuf ? bitbuf : NULL, 03458 (n_fields + 7) & ~7UL, 03459 FALSE)))) 03460 { 03461 bitmap_set_all(&cols); 03462 if (likely(!(error= write_locked_table_maps(thd)))) 03463 { 03464 error= 03465 RowsEventT::binlog_row_logging_function(thd, table, 03466 table->file-> 03467 has_transactions(), 03468 &cols, table->s->fields, 03469 before_record, 03470 after_record); 03471 } 03472 if (!use_bitbuf) 03473 bitmap_free(&cols); 03474 } 03475 } 03476 return error ? HA_ERR_RBR_LOGGING_FAILED : 0; 03477 } 03478 03479 /* 03480 Instantiate the versions we need for the above template function, 03481 because we have -fno-implicit-template as compiling option. 03482 */ 03483 03484 template int 03485 binlog_log_row<Write_rows_log_event>(TABLE *, const byte *, const byte *); 03486 03487 template int 03488 binlog_log_row<Delete_rows_log_event>(TABLE *, const byte *, const byte *); 03489 03490 template int 03491 binlog_log_row<Update_rows_log_event>(TABLE *, const byte *, const byte *); 03492 } 03493 03494 #endif /* HAVE_ROW_BASED_REPLICATION */ 03495 03496 int handler::ha_external_lock(THD *thd, int lock_type) 03497 { 03498 DBUG_ENTER("handler::ha_external_lock"); 03499 /* 03500 Whether this is lock or unlock, this should be true, and is to verify that 03501 if get_auto_increment() was called (thus may have reserved intervals or 03502 taken a table lock), ha_release_auto_increment() was too. 03503 */ 03504 DBUG_ASSERT(next_insert_id == 0); 03505 DBUG_RETURN(external_lock(thd, lock_type)); 03506 } 03507 03508 03509 /* 03510 Check handler usage and reset state of file to after 'open' 03511 */ 03512 03513 int handler::ha_reset() 03514 { 03515 DBUG_ENTER("ha_reset"); 03516 /* Check that we have called all proper delallocation functions */ 03517 DBUG_ASSERT((byte*) table->def_read_set.bitmap + 03518 table->s->column_bitmap_size == 03519 (char*) table->def_write_set.bitmap); 03520 DBUG_ASSERT(bitmap_is_set_all(&table->s->all_set)); 03521 DBUG_ASSERT(table->key_read == 0); 03522 /* ensure that ha_index_end / ha_rnd_end has been called */ 03523 DBUG_ASSERT(inited == NONE); 03524 /* Free cache used by filesort */ 03525 free_io_cache(table); 03526 DBUG_RETURN(reset()); 03527 } 03528 03529 03530 int handler::ha_write_row(byte *buf) 03531 { 03532 int error; 03533 if (unlikely(error= write_row(buf))) 03534 return error; 03535 #ifdef HAVE_ROW_BASED_REPLICATION 03536 if (unlikely(error= binlog_log_row<Write_rows_log_event>(table, 0, buf))) 03537 return error; 03538 #endif 03539 return 0; 03540 } 03541 03542 int handler::ha_update_row(const byte *old_data, byte *new_data) 03543 { 03544 int error; 03545 03546 /* 03547 Some storage engines require that the new record is in record[0] 03548 (and the old record is in record[1]). 03549 */ 03550 DBUG_ASSERT(new_data == table->record[0]); 03551 03552 if (unlikely(error= update_row(old_data, new_data))) 03553 return error; 03554 #ifdef HAVE_ROW_BASED_REPLICATION 03555 if (unlikely(error= binlog_log_row<Update_rows_log_event>(table, old_data, new_data))) 03556 return error; 03557 #endif 03558 return 0; 03559 } 03560 03561 int handler::ha_delete_row(const byte *buf) 03562 { 03563 int error; 03564 if (unlikely(error= delete_row(buf))) 03565 return error; 03566 #ifdef HAVE_ROW_BASED_REPLICATION 03567 if (unlikely(error= binlog_log_row<Delete_rows_log_event>(table, buf, 0))) 03568 return error; 03569 #endif 03570 return 0; 03571 } 03572 03573 03574 03575 /* 03576 use_hidden_primary_key() is called in case of an update/delete when 03577 (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined 03578 but we don't have a primary key 03579 */ 03580 03581 void handler::use_hidden_primary_key() 03582 { 03583 /* fallback to use all columns in the table to identify row */ 03584 table->use_all_columns(); 03585 } 03586 03587 03588 /* 03589 Dummy function which accept information about log files which is not need 03590 by handlers 03591 */ 03592 03593 void signal_log_not_needed(struct handlerton, char *log_file) 03594 { 03595 DBUG_ENTER("signal_log_not_needed"); 03596 DBUG_PRINT("enter", ("logfile '%s'", log_file)); 03597 DBUG_VOID_RETURN; 03598 } 03599 03600 03601 #ifdef TRANS_LOG_MGM_EXAMPLE_CODE 03602 /* 03603 Example of transaction log management functions based on assumption that logs 03604 placed into a directory 03605 */ 03606 #include <my_dir.h> 03607 #include <my_sys.h> 03608 int example_of_iterator_using_for_logs_cleanup(handlerton *hton) 03609 { 03610 void *buffer; 03611 int res= 1; 03612 struct handler_iterator iterator; 03613 struct handler_log_file_data data; 03614 03615 if (!hton->create_iterator) 03616 return 1; /* iterator creator is not supported */ 03617 03618 if ((*hton->create_iterator)(HA_TRANSACTLOG_ITERATOR, &iterator) != 03619 HA_ITERATOR_OK) 03620 { 03621 /* error during creation of log iterator or iterator is not supported */ 03622 return 1; 03623 } 03624 while((*iterator.next)(&iterator, (void*)&data) == 0) 03625 { 03626 printf("%s\n", data.filename.str); 03627 if (data.status == HA_LOG_STATUS_FREE && 03628 my_delete(data.filename.str, MYF(MY_WME))) 03629 goto err; 03630 } 03631 res= 0; 03632 err: 03633 (*iterator.destroy)(&iterator); 03634 return res; 03635 } 03636 03637 03638 /* 03639 Here we should get info from handler where it save logs but here is 03640 just example, so we use constant. 03641 IMHO FN_ROOTDIR ("/") is safe enough for example, because nobody has 03642 rights on it except root and it consist of directories only at lest for 03643 *nix (sorry, can't find windows-safe solution here, but it is only example). 03644 */ 03645 #define fl_dir FN_ROOTDIR 03646 03647 03648 /* 03649 Dummy function to return log status should be replaced by function which 03650 really detect the log status and check that the file is a log of this 03651 handler. 03652 */ 03653 03654 enum log_status fl_get_log_status(char *log) 03655 { 03656 MY_STAT stat_buff; 03657 if (my_stat(log, &stat_buff, MYF(0))) 03658 return HA_LOG_STATUS_INUSE; 03659 return HA_LOG_STATUS_NOSUCHLOG; 03660 } 03661 03662 03663 struct fl_buff 03664 { 03665 LEX_STRING *names; 03666 enum log_status *statuses; 03667 uint32 entries; 03668 uint32 current; 03669 }; 03670 03671 03672 int fl_log_iterator_next(struct handler_iterator *iterator, 03673 void *iterator_object) 03674 { 03675 struct fl_buff *buff= (struct fl_buff *)iterator->buffer; 03676 struct handler_log_file_data *data= 03677 (struct handler_log_file_data *) iterator_object; 03678 if (buff->current >= buff->entries) 03679 return 1; 03680 data->filename= buff->names[buff->current]; 03681 data->status= buff->statuses[buff->current]; 03682 buff->current++; 03683 return 0; 03684 } 03685 03686 03687 void fl_log_iterator_destroy(struct handler_iterator *iterator) 03688 { 03689 my_free((gptr)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR)); 03690 } 03691 03692 03693 /* 03694 returns buffer, to be assigned in handler_iterator struct 03695 */ 03696 enum handler_create_iterator_result 03697 fl_log_iterator_buffer_init(struct handler_iterator *iterator) 03698 { 03699 MY_DIR *dirp; 03700 struct fl_buff *buff; 03701 char *name_ptr; 03702 byte *ptr; 03703 FILEINFO *file; 03704 uint32 i; 03705 03706 /* to be able to make my_free without crash in case of error */ 03707 iterator->buffer= 0; 03708 03709 if (!(dirp = my_dir(fl_dir, MYF(0)))) 03710 { 03711 return HA_ITERATOR_ERROR; 03712 } 03713 if ((ptr= (byte*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) + 03714 ((ALIGN_SIZE(sizeof(LEX_STRING)) + 03715 sizeof(enum log_status) + 03716 + FN_REFLEN) * 03717 (uint) dirp->number_off_files), 03718 MYF(0))) == 0) 03719 { 03720 return HA_ITERATOR_ERROR; 03721 } 03722 buff= (struct fl_buff *)ptr; 03723 buff->entries= buff->current= 0; 03724 ptr= ptr + (ALIGN_SIZE(sizeof(fl_buff))); 03725 buff->names= (LEX_STRING*) (ptr); 03726 ptr= ptr + ((ALIGN_SIZE(sizeof(LEX_STRING)) * 03727 (uint) dirp->number_off_files)); 03728 buff->statuses= (enum log_status *)(ptr); 03729 name_ptr= (char *)(ptr + (sizeof(enum log_status) * 03730 (uint) dirp->number_off_files)); 03731 for (i=0 ; i < (uint) dirp->number_off_files ; i++) 03732 { 03733 enum log_status st; 03734 file= dirp->dir_entry + i; 03735 if ((file->name[0] == '.' && 03736 ((file->name[1] == '.' && file->name[2] == '\0') || 03737 file->name[1] == '\0'))) 03738 continue; 03739 if ((st= fl_get_log_status(file->name)) == HA_LOG_STATUS_NOSUCHLOG) 03740 continue; 03741 name_ptr= strxnmov(buff->names[buff->entries].str= name_ptr, 03742 FN_REFLEN, fl_dir, file->name, NullS); 03743 buff->names[buff->entries].length= (name_ptr - 03744 buff->names[buff->entries].str) - 1; 03745 buff->statuses[buff->entries]= st; 03746 buff->entries++; 03747 } 03748 03749 iterator->buffer= buff; 03750 iterator->next= &fl_log_iterator_next; 03751 iterator->destroy= &fl_log_iterator_destroy; 03752 return HA_ITERATOR_OK; 03753 } 03754 03755 03756 /* An example of a iterator creator */ 03757 enum handler_create_iterator_result 03758 fl_create_iterator(enum handler_iterator_type type, 03759 struct handler_iterator *iterator) 03760 { 03761 switch(type) { 03762 case HA_TRANSACTLOG_ITERATOR: 03763 return fl_log_iterator_buffer_init(iterator); 03764 default: 03765 return HA_ITERATOR_UNSUPPORTED; 03766 } 03767 } 03768 #endif /*TRANS_LOG_MGM_EXAMPLE_CODE*/
1.4.7

