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 | |