| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1994, 2017, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2017, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /***************************************************************//** |
| 21 | @file ut/ut0ut.cc |
| 22 | Various utilities for Innobase. |
| 23 | |
| 24 | Created 5/11/1994 Heikki Tuuri |
| 25 | ********************************************************************/ |
| 26 | |
| 27 | #include "ha_prototypes.h" |
| 28 | |
| 29 | #if HAVE_SYS_TIME_H |
| 30 | #include <sys/time.h> |
| 31 | #endif |
| 32 | |
| 33 | #ifndef UNIV_INNOCHECKSUM |
| 34 | #include <mysql_com.h> |
| 35 | #include "os0thread.h" |
| 36 | #include "ut0ut.h" |
| 37 | #include "trx0trx.h" |
| 38 | #include <string> |
| 39 | #include "log.h" |
| 40 | #include "my_cpu.h" |
| 41 | |
| 42 | #ifdef _WIN32 |
| 43 | typedef VOID(WINAPI *time_fn)(LPFILETIME); |
| 44 | static time_fn ut_get_system_time_as_file_time = GetSystemTimeAsFileTime; |
| 45 | |
| 46 | /*****************************************************************//** |
| 47 | NOTE: The Windows epoch starts from 1601/01/01 whereas the Unix |
| 48 | epoch starts from 1970/1/1. For selection of constant see: |
| 49 | http://support.microsoft.com/kb/167296/ */ |
| 50 | #define WIN_TO_UNIX_DELTA_USEC 11644473600000000LL |
| 51 | |
| 52 | |
| 53 | /*****************************************************************//** |
| 54 | This is the Windows version of gettimeofday(2). |
| 55 | @return 0 if all OK else -1 */ |
| 56 | static |
| 57 | int |
| 58 | ut_gettimeofday( |
| 59 | /*============*/ |
| 60 | struct timeval* tv, /*!< out: Values are relative to Unix epoch */ |
| 61 | void* tz) /*!< in: not used */ |
| 62 | { |
| 63 | FILETIME ft; |
| 64 | int64_t tm; |
| 65 | |
| 66 | if (!tv) { |
| 67 | errno = EINVAL; |
| 68 | return(-1); |
| 69 | } |
| 70 | |
| 71 | ut_get_system_time_as_file_time(&ft); |
| 72 | |
| 73 | tm = (int64_t) ft.dwHighDateTime << 32; |
| 74 | tm |= ft.dwLowDateTime; |
| 75 | |
| 76 | ut_a(tm >= 0); /* If tm wraps over to negative, the quotient / 10 |
| 77 | does not work */ |
| 78 | |
| 79 | tm /= 10; /* Convert from 100 nsec periods to usec */ |
| 80 | |
| 81 | /* If we don't convert to the Unix epoch the value for |
| 82 | struct timeval::tv_sec will overflow.*/ |
| 83 | tm -= WIN_TO_UNIX_DELTA_USEC; |
| 84 | |
| 85 | tv->tv_sec = (long) (tm / 1000000L); |
| 86 | tv->tv_usec = (long) (tm % 1000000L); |
| 87 | |
| 88 | return(0); |
| 89 | } |
| 90 | #else |
| 91 | /** An alias for gettimeofday(2). On Microsoft Windows, we have to |
| 92 | reimplement this function. */ |
| 93 | #define ut_gettimeofday gettimeofday |
| 94 | #endif |
| 95 | |
| 96 | /**********************************************************//** |
| 97 | Returns system time. We do not specify the format of the time returned: |
| 98 | the only way to manipulate it is to use the function ut_difftime. |
| 99 | @return system time */ |
| 100 | ib_time_t |
| 101 | ut_time(void) |
| 102 | /*=========*/ |
| 103 | { |
| 104 | return(time(NULL)); |
| 105 | } |
| 106 | |
| 107 | |
| 108 | /**********************************************************//** |
| 109 | Returns system time. |
| 110 | Upon successful completion, the value 0 is returned; otherwise the |
| 111 | value -1 is returned and the global variable errno is set to indicate the |
| 112 | error. |
| 113 | @return 0 on success, -1 otherwise */ |
| 114 | int |
| 115 | ut_usectime( |
| 116 | /*========*/ |
| 117 | ulint* sec, /*!< out: seconds since the Epoch */ |
| 118 | ulint* ms) /*!< out: microseconds since the Epoch+*sec */ |
| 119 | { |
| 120 | struct timeval tv; |
| 121 | int ret; |
| 122 | int errno_gettimeofday; |
| 123 | int i; |
| 124 | |
| 125 | for (i = 0; i < 10; i++) { |
| 126 | |
| 127 | ret = ut_gettimeofday(&tv, NULL); |
| 128 | |
| 129 | if (ret == -1) { |
| 130 | errno_gettimeofday = errno; |
| 131 | ib::error() << "gettimeofday(): " |
| 132 | << strerror(errno_gettimeofday); |
| 133 | os_thread_sleep(100000); /* 0.1 sec */ |
| 134 | errno = errno_gettimeofday; |
| 135 | } else { |
| 136 | break; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | if (ret != -1) { |
| 141 | *sec = (ulint) tv.tv_sec; |
| 142 | *ms = (ulint) tv.tv_usec; |
| 143 | } |
| 144 | |
| 145 | return(ret); |
| 146 | } |
| 147 | |
| 148 | /**********************************************************//** |
| 149 | Returns the number of microseconds since epoch. Similar to |
| 150 | time(3), the return value is also stored in *tloc, provided |
| 151 | that tloc is non-NULL. |
| 152 | @return us since epoch */ |
| 153 | uintmax_t |
| 154 | ut_time_us( |
| 155 | /*=======*/ |
| 156 | uintmax_t* tloc) /*!< out: us since epoch, if non-NULL */ |
| 157 | { |
| 158 | struct timeval tv; |
| 159 | uintmax_t us; |
| 160 | |
| 161 | ut_gettimeofday(&tv, NULL); |
| 162 | |
| 163 | us = uintmax_t(tv.tv_sec) * 1000000 + uintmax_t(tv.tv_usec); |
| 164 | |
| 165 | if (tloc != NULL) { |
| 166 | *tloc = us; |
| 167 | } |
| 168 | |
| 169 | return(us); |
| 170 | } |
| 171 | |
| 172 | /**********************************************************//** |
| 173 | Returns the number of milliseconds since some epoch. The |
| 174 | value may wrap around. It should only be used for heuristic |
| 175 | purposes. |
| 176 | @return ms since epoch */ |
| 177 | ulint |
| 178 | ut_time_ms(void) |
| 179 | /*============*/ |
| 180 | { |
| 181 | struct timeval tv; |
| 182 | |
| 183 | ut_gettimeofday(&tv, NULL); |
| 184 | |
| 185 | return(ulint(tv.tv_sec) * 1000 + ulint(tv.tv_usec / 1000)); |
| 186 | } |
| 187 | |
| 188 | /**********************************************************//** |
| 189 | Returns the difference of two times in seconds. |
| 190 | @return time2 - time1 expressed in seconds */ |
| 191 | double |
| 192 | ut_difftime( |
| 193 | /*========*/ |
| 194 | ib_time_t time2, /*!< in: time */ |
| 195 | ib_time_t time1) /*!< in: time */ |
| 196 | { |
| 197 | return(difftime(time2, time1)); |
| 198 | } |
| 199 | |
| 200 | #endif /* !UNIV_INNOCHECKSUM */ |
| 201 | |
| 202 | /**********************************************************//** |
| 203 | Prints a timestamp to a file. */ |
| 204 | void |
| 205 | ut_print_timestamp( |
| 206 | /*===============*/ |
| 207 | FILE* file) /*!< in: file where to print */ |
| 208 | { |
| 209 | ulint thread_id = 0; |
| 210 | |
| 211 | #ifndef UNIV_INNOCHECKSUM |
| 212 | thread_id = os_thread_pf(os_thread_get_curr_id()); |
| 213 | #endif /* !UNIV_INNOCHECKSUM */ |
| 214 | |
| 215 | #ifdef _WIN32 |
| 216 | SYSTEMTIME cal_tm; |
| 217 | |
| 218 | GetLocalTime(&cal_tm); |
| 219 | |
| 220 | fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %#zx" , |
| 221 | (int) cal_tm.wYear, |
| 222 | (int) cal_tm.wMonth, |
| 223 | (int) cal_tm.wDay, |
| 224 | (int) cal_tm.wHour, |
| 225 | (int) cal_tm.wMinute, |
| 226 | (int) cal_tm.wSecond, |
| 227 | thread_id); |
| 228 | #else |
| 229 | struct tm* cal_tm_ptr; |
| 230 | time_t tm; |
| 231 | |
| 232 | struct tm cal_tm; |
| 233 | time(&tm); |
| 234 | localtime_r(&tm, &cal_tm); |
| 235 | cal_tm_ptr = &cal_tm; |
| 236 | fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %#zx" , |
| 237 | cal_tm_ptr->tm_year + 1900, |
| 238 | cal_tm_ptr->tm_mon + 1, |
| 239 | cal_tm_ptr->tm_mday, |
| 240 | cal_tm_ptr->tm_hour, |
| 241 | cal_tm_ptr->tm_min, |
| 242 | cal_tm_ptr->tm_sec, |
| 243 | thread_id); |
| 244 | #endif |
| 245 | } |
| 246 | |
| 247 | #ifndef UNIV_INNOCHECKSUM |
| 248 | |
| 249 | /**********************************************************//** |
| 250 | Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */ |
| 251 | void |
| 252 | ut_sprintf_timestamp( |
| 253 | /*=================*/ |
| 254 | char* buf) /*!< in: buffer where to sprintf */ |
| 255 | { |
| 256 | #ifdef _WIN32 |
| 257 | SYSTEMTIME cal_tm; |
| 258 | |
| 259 | GetLocalTime(&cal_tm); |
| 260 | |
| 261 | sprintf(buf, "%02d%02d%02d %2d:%02d:%02d" , |
| 262 | (int) cal_tm.wYear % 100, |
| 263 | (int) cal_tm.wMonth, |
| 264 | (int) cal_tm.wDay, |
| 265 | (int) cal_tm.wHour, |
| 266 | (int) cal_tm.wMinute, |
| 267 | (int) cal_tm.wSecond); |
| 268 | #else |
| 269 | struct tm* cal_tm_ptr; |
| 270 | time_t tm; |
| 271 | |
| 272 | struct tm cal_tm; |
| 273 | time(&tm); |
| 274 | localtime_r(&tm, &cal_tm); |
| 275 | cal_tm_ptr = &cal_tm; |
| 276 | sprintf(buf, "%02d%02d%02d %2d:%02d:%02d" , |
| 277 | cal_tm_ptr->tm_year % 100, |
| 278 | cal_tm_ptr->tm_mon + 1, |
| 279 | cal_tm_ptr->tm_mday, |
| 280 | cal_tm_ptr->tm_hour, |
| 281 | cal_tm_ptr->tm_min, |
| 282 | cal_tm_ptr->tm_sec); |
| 283 | #endif |
| 284 | } |
| 285 | |
| 286 | /*************************************************************//** |
| 287 | Runs an idle loop on CPU. The argument gives the desired delay |
| 288 | in microseconds on 100 MHz Pentium + Visual C++. |
| 289 | @return dummy value */ |
| 290 | void |
| 291 | ut_delay( |
| 292 | /*=====*/ |
| 293 | ulint delay) /*!< in: delay in microseconds on 100 MHz Pentium */ |
| 294 | { |
| 295 | ulint i; |
| 296 | |
| 297 | HMT_low(); |
| 298 | |
| 299 | for (i = 0; i < delay * 50; i++) { |
| 300 | MY_RELAX_CPU(); |
| 301 | UT_COMPILER_BARRIER(); |
| 302 | } |
| 303 | |
| 304 | HMT_medium(); |
| 305 | } |
| 306 | |
| 307 | /*************************************************************//** |
| 308 | Prints the contents of a memory buffer in hex and ascii. */ |
| 309 | void |
| 310 | ut_print_buf( |
| 311 | /*=========*/ |
| 312 | FILE* file, /*!< in: file where to print */ |
| 313 | const void* buf, /*!< in: memory buffer */ |
| 314 | ulint len) /*!< in: length of the buffer */ |
| 315 | { |
| 316 | const byte* data; |
| 317 | ulint i; |
| 318 | |
| 319 | UNIV_MEM_ASSERT_RW(buf, len); |
| 320 | |
| 321 | fprintf(file, " len " ULINTPF "; hex " , len); |
| 322 | |
| 323 | for (data = (const byte*) buf, i = 0; i < len; i++) { |
| 324 | fprintf(file, "%02x" , *data++); |
| 325 | } |
| 326 | |
| 327 | fputs("; asc " , file); |
| 328 | |
| 329 | data = (const byte*) buf; |
| 330 | |
| 331 | for (i = 0; i < len; i++) { |
| 332 | int c = (int) *data++; |
| 333 | putc(isprint(c) ? c : ' ', file); |
| 334 | } |
| 335 | |
| 336 | putc(';', file); |
| 337 | } |
| 338 | |
| 339 | /*************************************************************//** |
| 340 | Prints the contents of a memory buffer in hex. */ |
| 341 | void |
| 342 | ut_print_buf_hex( |
| 343 | /*=============*/ |
| 344 | std::ostream& o, /*!< in/out: output stream */ |
| 345 | const void* buf, /*!< in: memory buffer */ |
| 346 | ulint len) /*!< in: length of the buffer */ |
| 347 | { |
| 348 | const byte* data; |
| 349 | ulint i; |
| 350 | |
| 351 | static const char hexdigit[16] = { |
| 352 | '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' |
| 353 | }; |
| 354 | |
| 355 | UNIV_MEM_ASSERT_RW(buf, len); |
| 356 | |
| 357 | o << "(0x" ; |
| 358 | |
| 359 | for (data = static_cast<const byte*>(buf), i = 0; i < len; i++) { |
| 360 | byte b = *data++; |
| 361 | o << hexdigit[(int) b >> 16] << hexdigit[b & 15]; |
| 362 | } |
| 363 | |
| 364 | o << ")" ; |
| 365 | } |
| 366 | |
| 367 | /*************************************************************//** |
| 368 | Prints the contents of a memory buffer in hex and ascii. */ |
| 369 | void |
| 370 | ut_print_buf( |
| 371 | /*=========*/ |
| 372 | std::ostream& o, /*!< in/out: output stream */ |
| 373 | const void* buf, /*!< in: memory buffer */ |
| 374 | ulint len) /*!< in: length of the buffer */ |
| 375 | { |
| 376 | const byte* data; |
| 377 | ulint i; |
| 378 | |
| 379 | UNIV_MEM_ASSERT_RW(buf, len); |
| 380 | |
| 381 | for (data = static_cast<const byte*>(buf), i = 0; i < len; i++) { |
| 382 | int c = static_cast<int>(*data++); |
| 383 | o << (isprint(c) ? static_cast<char>(c) : ' '); |
| 384 | } |
| 385 | |
| 386 | ut_print_buf_hex(o, buf, len); |
| 387 | } |
| 388 | |
| 389 | /*************************************************************//** |
| 390 | Calculates fast the number rounded up to the nearest power of 2. |
| 391 | @return first power of 2 which is >= n */ |
| 392 | ulint |
| 393 | ut_2_power_up( |
| 394 | /*==========*/ |
| 395 | ulint n) /*!< in: number != 0 */ |
| 396 | { |
| 397 | ulint res; |
| 398 | |
| 399 | res = 1; |
| 400 | |
| 401 | ut_ad(n > 0); |
| 402 | |
| 403 | while (res < n) { |
| 404 | res = res * 2; |
| 405 | } |
| 406 | |
| 407 | return(res); |
| 408 | } |
| 409 | |
| 410 | /** Get a fixed-length string, quoted as an SQL identifier. |
| 411 | If the string contains a slash '/', the string will be |
| 412 | output as two identifiers separated by a period (.), |
| 413 | as in SQL database_name.identifier. |
| 414 | @param [in] trx transaction (NULL=no quotes). |
| 415 | @param [in] name table name. |
| 416 | @retval String quoted as an SQL identifier. |
| 417 | */ |
| 418 | std::string |
| 419 | ut_get_name( |
| 420 | const trx_t* trx, |
| 421 | const char* name) |
| 422 | { |
| 423 | /* 2 * NAME_LEN for database and table name, |
| 424 | and some slack for the #mysql50# prefix and quotes */ |
| 425 | char buf[3 * NAME_LEN]; |
| 426 | const char* bufend; |
| 427 | |
| 428 | bufend = innobase_convert_name(buf, sizeof buf, |
| 429 | name, strlen(name), |
| 430 | trx ? trx->mysql_thd : NULL); |
| 431 | buf[bufend - buf] = '\0'; |
| 432 | return(std::string(buf, 0, size_t(bufend - buf))); |
| 433 | } |
| 434 | |
| 435 | /**********************************************************************//** |
| 436 | Outputs a fixed-length string, quoted as an SQL identifier. |
| 437 | If the string contains a slash '/', the string will be |
| 438 | output as two identifiers separated by a period (.), |
| 439 | as in SQL database_name.identifier. */ |
| 440 | void |
| 441 | ut_print_name( |
| 442 | /*==========*/ |
| 443 | FILE* f, /*!< in: output stream */ |
| 444 | const trx_t* trx, /*!< in: transaction */ |
| 445 | const char* name) /*!< in: name to print */ |
| 446 | { |
| 447 | /* 2 * NAME_LEN for database and table name, |
| 448 | and some slack for the #mysql50# prefix and quotes */ |
| 449 | char buf[3 * NAME_LEN]; |
| 450 | const char* bufend; |
| 451 | |
| 452 | bufend = innobase_convert_name(buf, sizeof buf, |
| 453 | name, strlen(name), |
| 454 | trx ? trx->mysql_thd : NULL); |
| 455 | |
| 456 | if (fwrite(buf, 1, size_t(bufend - buf), f) != size_t(bufend - buf)) { |
| 457 | perror("fwrite" ); |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | /** Format a table name, quoted as an SQL identifier. |
| 462 | If the name contains a slash '/', the result will contain two |
| 463 | identifiers separated by a period (.), as in SQL |
| 464 | database_name.table_name. |
| 465 | @see table_name_t |
| 466 | @param[in] name table or index name |
| 467 | @param[out] formatted formatted result, will be NUL-terminated |
| 468 | @param[in] formatted_size size of the buffer in bytes |
| 469 | @return pointer to 'formatted' */ |
| 470 | char* |
| 471 | ut_format_name( |
| 472 | const char* name, |
| 473 | char* formatted, |
| 474 | ulint formatted_size) |
| 475 | { |
| 476 | switch (formatted_size) { |
| 477 | case 1: |
| 478 | formatted[0] = '\0'; |
| 479 | /* FALL-THROUGH */ |
| 480 | case 0: |
| 481 | return(formatted); |
| 482 | } |
| 483 | |
| 484 | char* end; |
| 485 | |
| 486 | end = innobase_convert_name(formatted, formatted_size, |
| 487 | name, strlen(name), NULL); |
| 488 | |
| 489 | /* If the space in 'formatted' was completely used, then sacrifice |
| 490 | the last character in order to write '\0' at the end. */ |
| 491 | if ((ulint) (end - formatted) == formatted_size) { |
| 492 | end--; |
| 493 | } |
| 494 | |
| 495 | ut_a((ulint) (end - formatted) < formatted_size); |
| 496 | |
| 497 | *end = '\0'; |
| 498 | |
| 499 | return(formatted); |
| 500 | } |
| 501 | |
| 502 | /**********************************************************************//** |
| 503 | Catenate files. */ |
| 504 | void |
| 505 | ut_copy_file( |
| 506 | /*=========*/ |
| 507 | FILE* dest, /*!< in: output file */ |
| 508 | FILE* src) /*!< in: input file to be appended to output */ |
| 509 | { |
| 510 | long len = ftell(src); |
| 511 | char buf[4096]; |
| 512 | |
| 513 | rewind(src); |
| 514 | do { |
| 515 | size_t maxs = len < (long) sizeof buf |
| 516 | ? (size_t) len |
| 517 | : sizeof buf; |
| 518 | size_t size = fread(buf, 1, maxs, src); |
| 519 | if (fwrite(buf, 1, size, dest) != size) { |
| 520 | perror("fwrite" ); |
| 521 | } |
| 522 | len -= (long) size; |
| 523 | if (size < maxs) { |
| 524 | break; |
| 525 | } |
| 526 | } while (len > 0); |
| 527 | } |
| 528 | |
| 529 | /** Convert an error number to a human readable text message. |
| 530 | The returned string is static and should not be freed or modified. |
| 531 | @param[in] num InnoDB internal error number |
| 532 | @return string, describing the error */ |
| 533 | const char* |
| 534 | ut_strerr( |
| 535 | dberr_t num) |
| 536 | { |
| 537 | switch (num) { |
| 538 | case DB_SUCCESS: |
| 539 | return("Success" ); |
| 540 | case DB_SUCCESS_LOCKED_REC: |
| 541 | return("Success, record lock created" ); |
| 542 | case DB_ERROR: |
| 543 | return("Generic error" ); |
| 544 | case DB_READ_ONLY: |
| 545 | return("Read only transaction" ); |
| 546 | case DB_INTERRUPTED: |
| 547 | return("Operation interrupted" ); |
| 548 | case DB_OUT_OF_MEMORY: |
| 549 | return("Cannot allocate memory" ); |
| 550 | case DB_OUT_OF_FILE_SPACE: |
| 551 | return("Out of disk space" ); |
| 552 | case DB_LOCK_WAIT: |
| 553 | return("Lock wait" ); |
| 554 | case DB_DEADLOCK: |
| 555 | return("Deadlock" ); |
| 556 | case DB_ROLLBACK: |
| 557 | return("Rollback" ); |
| 558 | case DB_DUPLICATE_KEY: |
| 559 | return("Duplicate key" ); |
| 560 | case DB_MISSING_HISTORY: |
| 561 | return("Required history data has been deleted" ); |
| 562 | case DB_CLUSTER_NOT_FOUND: |
| 563 | return("Cluster not found" ); |
| 564 | case DB_TABLE_NOT_FOUND: |
| 565 | return("Table not found" ); |
| 566 | case DB_MUST_GET_MORE_FILE_SPACE: |
| 567 | return("More file space needed" ); |
| 568 | case DB_TABLE_IS_BEING_USED: |
| 569 | return("Table is being used" ); |
| 570 | case DB_TOO_BIG_RECORD: |
| 571 | return("Record too big" ); |
| 572 | case DB_TOO_BIG_INDEX_COL: |
| 573 | return("Index columns size too big" ); |
| 574 | case DB_LOCK_WAIT_TIMEOUT: |
| 575 | return("Lock wait timeout" ); |
| 576 | case DB_NO_REFERENCED_ROW: |
| 577 | return("Referenced key value not found" ); |
| 578 | case DB_ROW_IS_REFERENCED: |
| 579 | return("Row is referenced" ); |
| 580 | case DB_CANNOT_ADD_CONSTRAINT: |
| 581 | return("Cannot add constraint" ); |
| 582 | case DB_CORRUPTION: |
| 583 | return("Data structure corruption" ); |
| 584 | case DB_CANNOT_DROP_CONSTRAINT: |
| 585 | return("Cannot drop constraint" ); |
| 586 | case DB_NO_SAVEPOINT: |
| 587 | return("No such savepoint" ); |
| 588 | case DB_TABLESPACE_EXISTS: |
| 589 | return("Tablespace already exists" ); |
| 590 | case DB_TABLESPACE_DELETED: |
| 591 | return("Tablespace deleted or being deleted" ); |
| 592 | case DB_TABLESPACE_TRUNCATED: |
| 593 | return("Tablespace was truncated" ); |
| 594 | case DB_TABLESPACE_NOT_FOUND: |
| 595 | return("Tablespace not found" ); |
| 596 | case DB_LOCK_TABLE_FULL: |
| 597 | return("Lock structs have exhausted the buffer pool" ); |
| 598 | case DB_FOREIGN_DUPLICATE_KEY: |
| 599 | return("Foreign key activated with duplicate keys" ); |
| 600 | case DB_FOREIGN_EXCEED_MAX_CASCADE: |
| 601 | return("Foreign key cascade delete/update exceeds max depth" ); |
| 602 | case DB_TOO_MANY_CONCURRENT_TRXS: |
| 603 | return("Too many concurrent transactions" ); |
| 604 | case DB_UNSUPPORTED: |
| 605 | return("Unsupported" ); |
| 606 | case DB_INVALID_NULL: |
| 607 | return("NULL value encountered in NOT NULL column" ); |
| 608 | case DB_STATS_DO_NOT_EXIST: |
| 609 | return("Persistent statistics do not exist" ); |
| 610 | case DB_FAIL: |
| 611 | return("Failed, retry may succeed" ); |
| 612 | case DB_OVERFLOW: |
| 613 | return("Overflow" ); |
| 614 | case DB_UNDERFLOW: |
| 615 | return("Underflow" ); |
| 616 | case DB_STRONG_FAIL: |
| 617 | return("Failed, retry will not succeed" ); |
| 618 | case DB_ZIP_OVERFLOW: |
| 619 | return("Zip overflow" ); |
| 620 | case DB_RECORD_NOT_FOUND: |
| 621 | return("Record not found" ); |
| 622 | case DB_CHILD_NO_INDEX: |
| 623 | return("No index on referencing keys in referencing table" ); |
| 624 | case DB_PARENT_NO_INDEX: |
| 625 | return("No index on referenced keys in referenced table" ); |
| 626 | case DB_FTS_INVALID_DOCID: |
| 627 | return("FTS Doc ID cannot be zero" ); |
| 628 | case DB_INDEX_CORRUPT: |
| 629 | return("Index corrupted" ); |
| 630 | case DB_UNDO_RECORD_TOO_BIG: |
| 631 | return("Undo record too big" ); |
| 632 | case DB_END_OF_INDEX: |
| 633 | return("End of index" ); |
| 634 | case DB_IO_ERROR: |
| 635 | return("I/O error" ); |
| 636 | case DB_TABLE_IN_FK_CHECK: |
| 637 | return("Table is being used in foreign key check" ); |
| 638 | case DB_NOT_FOUND: |
| 639 | return("not found" ); |
| 640 | case DB_ONLINE_LOG_TOO_BIG: |
| 641 | return("Log size exceeded during online index creation" ); |
| 642 | case DB_IDENTIFIER_TOO_LONG: |
| 643 | return("Identifier name is too long" ); |
| 644 | case DB_FTS_EXCEED_RESULT_CACHE_LIMIT: |
| 645 | return("FTS query exceeds result cache limit" ); |
| 646 | case DB_TEMP_FILE_WRITE_FAIL: |
| 647 | return("Temp file write failure" ); |
| 648 | case DB_CANT_CREATE_GEOMETRY_OBJECT: |
| 649 | return("Can't create specificed geometry data object" ); |
| 650 | case DB_CANNOT_OPEN_FILE: |
| 651 | return("Cannot open a file" ); |
| 652 | case DB_TABLE_CORRUPT: |
| 653 | return("Table is corrupted" ); |
| 654 | case DB_FTS_TOO_MANY_WORDS_IN_PHRASE: |
| 655 | return("Too many words in a FTS phrase or proximity search" ); |
| 656 | case DB_DECRYPTION_FAILED: |
| 657 | return("Table is encrypted but decrypt failed." ); |
| 658 | case DB_IO_PARTIAL_FAILED: |
| 659 | return("Partial IO failed" ); |
| 660 | case DB_FORCED_ABORT: |
| 661 | return("Transaction aborted by another higher priority " |
| 662 | "transaction" ); |
| 663 | case DB_COMPUTE_VALUE_FAILED: |
| 664 | return("Compute generated column failed" ); |
| 665 | case DB_NO_FK_ON_S_BASE_COL: |
| 666 | return("Cannot add foreign key on the base column " |
| 667 | "of stored column" ); |
| 668 | case DB_IO_NO_PUNCH_HOLE: |
| 669 | return ("File system does not support punch hole (trim) operation." ); |
| 670 | case DB_PAGE_CORRUPTED: |
| 671 | return("Page read from tablespace is corrupted." ); |
| 672 | |
| 673 | /* do not add default: in order to produce a warning if new code |
| 674 | is added to the enum but not added here */ |
| 675 | } |
| 676 | |
| 677 | /* we abort here because if unknown error code is given, this could |
| 678 | mean that memory corruption has happened and someone's error-code |
| 679 | variable has been overwritten with bogus data */ |
| 680 | ut_error; |
| 681 | |
| 682 | /* NOT REACHED */ |
| 683 | return("Unknown error" ); |
| 684 | } |
| 685 | |
| 686 | #ifdef UNIV_PFS_MEMORY |
| 687 | |
| 688 | /** Extract the basename of a file without its extension. |
| 689 | For example, extract "foo0bar" out of "/path/to/foo0bar.cc". |
| 690 | @param[in] file file path, e.g. "/path/to/foo0bar.cc" |
| 691 | @param[out] base result, e.g. "foo0bar" |
| 692 | @param[in] base_size size of the output buffer 'base', if there |
| 693 | is not enough space, then the result will be truncated, but always |
| 694 | '\0'-terminated |
| 695 | @return number of characters that would have been printed if the size |
| 696 | were unlimited (not including the final ‘\0’) */ |
| 697 | size_t |
| 698 | ut_basename_noext( |
| 699 | const char* file, |
| 700 | char* base, |
| 701 | size_t base_size) |
| 702 | { |
| 703 | /* Assuming 'file' contains something like the following, |
| 704 | extract the file name without the extenstion out of it by |
| 705 | setting 'beg' and 'len'. |
| 706 | ...mysql-trunk/storage/innobase/dict/dict0dict.cc:302 |
| 707 | ^-- beg, len=9 |
| 708 | */ |
| 709 | |
| 710 | const char* beg = strrchr(file, OS_PATH_SEPARATOR); |
| 711 | |
| 712 | if (beg == NULL) { |
| 713 | beg = file; |
| 714 | } else { |
| 715 | beg++; |
| 716 | } |
| 717 | |
| 718 | size_t len = strlen(beg); |
| 719 | |
| 720 | const char* end = strrchr(beg, '.'); |
| 721 | |
| 722 | if (end != NULL) { |
| 723 | len = end - beg; |
| 724 | } |
| 725 | |
| 726 | const size_t copy_len = std::min(len, base_size - 1); |
| 727 | |
| 728 | memcpy(base, beg, copy_len); |
| 729 | |
| 730 | base[copy_len] = '\0'; |
| 731 | |
| 732 | return(len); |
| 733 | } |
| 734 | |
| 735 | #endif /* UNIV_PFS_MEMORY */ |
| 736 | |
| 737 | namespace ib { |
| 738 | |
| 739 | info::~info() |
| 740 | { |
| 741 | sql_print_information("InnoDB: %s" , m_oss.str().c_str()); |
| 742 | } |
| 743 | |
| 744 | warn::~warn() |
| 745 | { |
| 746 | sql_print_warning("InnoDB: %s" , m_oss.str().c_str()); |
| 747 | } |
| 748 | |
| 749 | error::~error() |
| 750 | { |
| 751 | sql_print_error("InnoDB: %s" , m_oss.str().c_str()); |
| 752 | } |
| 753 | |
| 754 | #ifdef _MSC_VER |
| 755 | /* disable warning |
| 756 | "ib::fatal::~fatal': destructor never returns, potential memory leak" |
| 757 | on Windows. |
| 758 | */ |
| 759 | #pragma warning (push) |
| 760 | #pragma warning (disable : 4722) |
| 761 | #endif |
| 762 | |
| 763 | ATTRIBUTE_NORETURN |
| 764 | fatal::~fatal() |
| 765 | { |
| 766 | sql_print_error("[FATAL] InnoDB: %s" , m_oss.str().c_str()); |
| 767 | abort(); |
| 768 | } |
| 769 | |
| 770 | #ifdef _MSC_VER |
| 771 | #pragma warning (pop) |
| 772 | #endif |
| 773 | |
| 774 | error_or_warn::~error_or_warn() |
| 775 | { |
| 776 | if (m_error) { |
| 777 | sql_print_error("InnoDB: %s" , m_oss.str().c_str()); |
| 778 | } else { |
| 779 | sql_print_warning("InnoDB: %s" , m_oss.str().c_str()); |
| 780 | } |
| 781 | } |
| 782 | |
| 783 | fatal_or_error::~fatal_or_error() |
| 784 | { |
| 785 | sql_print_error(m_fatal ? "[FATAL] InnoDB: %s" : "InnoDB: %s" , |
| 786 | m_oss.str().c_str()); |
| 787 | if (m_fatal) { |
| 788 | abort(); |
| 789 | } |
| 790 | } |
| 791 | |
| 792 | } // namespace ib |
| 793 | |
| 794 | #endif /* !UNIV_INNOCHECKSUM */ |
| 795 | |