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