The world's most popular open source database
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->

