1 /*****************************************************************************
2
3 Copyright (c) 1994, 2020, Oracle and/or its affiliates. All Rights Reserved.
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 "ut0ut.h"
35
36 #ifndef UNIV_INNOCHECKSUM
37
38 #include "ut0sort.h"
39 #include "os0thread.h" /* thread-ID */
40
41 #ifdef UNIV_NONINL
42 #include "ut0ut.ic"
43 #endif
44
45 #include <stdarg.h>
46 #include <string.h>
47 #include <ctype.h>
48
49 #ifndef UNIV_HOTBACKUP
50 # include "trx0trx.h"
51 # include "ha_prototypes.h"
52 # include "mysql_com.h" /* NAME_LEN */
53 #endif /* UNIV_HOTBACKUP */
54
55 /** A constant to prevent the compiler from optimizing ut_delay() away. */
56 UNIV_INTERN ibool ut_always_false = FALSE;
57
58 #ifdef __WIN__
59 #include <mysql/innodb_priv.h> /* For sql_print_error */
60 typedef VOID(WINAPI *time_fn)(LPFILETIME);
61 static time_fn ut_get_system_time_as_file_time = GetSystemTimeAsFileTime;
62
63 /*****************************************************************//**
64 NOTE: The Windows epoch starts from 1601/01/01 whereas the Unix
65 epoch starts from 1970/1/1. For selection of constant see:
66 http://support.microsoft.com/kb/167296/ */
67 #define WIN_TO_UNIX_DELTA_USEC ((ib_int64_t) 11644473600000000ULL)
68
69
70 /**
71 Initialise highest available time resolution API on Windows
72 @return 0 if all OK else -1 */
73 int
ut_win_init_time()74 ut_win_init_time()
75 {
76 HMODULE h = LoadLibrary("kernel32.dll");
77 if (h != NULL)
78 {
79 time_fn pfn = (time_fn)GetProcAddress(h, "GetSystemTimePreciseAsFileTime");
80 if (pfn != NULL)
81 {
82 ut_get_system_time_as_file_time = pfn;
83 }
84 return false;
85 }
86 DWORD error = GetLastError();
87 sql_print_error(
88 "LoadLibrary(\"kernel32.dll\") failed: GetLastError returns %lu", error);
89 return(-1);
90 }
91
92 /*****************************************************************//**
93 This is the Windows version of gettimeofday(2).
94 @return 0 if all OK else -1 */
95 static
96 int
ut_gettimeofday(struct timeval * tv,void * tz)97 ut_gettimeofday(
98 /*============*/
99 struct timeval* tv, /*!< out: Values are relative to Unix epoch */
100 void* tz) /*!< in: not used */
101 {
102 FILETIME ft;
103 ib_int64_t tm;
104
105 if (!tv) {
106 errno = EINVAL;
107 return(-1);
108 }
109
110 ut_get_system_time_as_file_time(&ft);
111
112 tm = (ib_int64_t) ft.dwHighDateTime << 32;
113 tm |= ft.dwLowDateTime;
114
115 ut_a(tm >= 0); /* If tm wraps over to negative, the quotient / 10
116 does not work */
117
118 tm /= 10; /* Convert from 100 nsec periods to usec */
119
120 /* If we don't convert to the Unix epoch the value for
121 struct timeval::tv_sec will overflow.*/
122 tm -= WIN_TO_UNIX_DELTA_USEC;
123
124 tv->tv_sec = (long) (tm / 1000000L);
125 tv->tv_usec = (long) (tm % 1000000L);
126
127 return(0);
128 }
129 #else
130 /** An alias for gettimeofday(2). On Microsoft Windows, we have to
131 reimplement this function. */
132 #define ut_gettimeofday gettimeofday
133 #endif
134
135 /**********************************************************//**
136 Returns system time. We do not specify the format of the time returned:
137 the only way to manipulate it is to use the function ut_difftime.
138 @return system time */
139 UNIV_INTERN
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 system time.
150 Upon successful completion, the value 0 is returned; otherwise the
151 value -1 is returned and the global variable errno is set to indicate the
152 error.
153 @return 0 on success, -1 otherwise */
154 UNIV_INTERN
155 int
ut_usectime(ulint * sec,ulint * ms)156 ut_usectime(
157 /*========*/
158 ulint* sec, /*!< out: seconds since the Epoch */
159 ulint* ms) /*!< out: microseconds since the Epoch+*sec */
160 {
161 struct timeval tv;
162 int ret;
163 int errno_gettimeofday;
164 int i;
165
166 for (i = 0; i < 10; i++) {
167
168 ret = ut_gettimeofday(&tv, NULL);
169
170 if (ret == -1) {
171 errno_gettimeofday = errno;
172 ut_print_timestamp(stderr);
173 fprintf(stderr, " InnoDB: gettimeofday(): %s\n",
174 strerror(errno_gettimeofday));
175 os_thread_sleep(100000); /* 0.1 sec */
176 errno = errno_gettimeofday;
177 } else {
178 break;
179 }
180 }
181
182 if (ret != -1) {
183 *sec = (ulint) tv.tv_sec;
184 *ms = (ulint) tv.tv_usec;
185 }
186
187 return(ret);
188 }
189
190 /**********************************************************//**
191 Returns the number of microseconds since epoch. Similar to
192 time(3), the return value is also stored in *tloc, provided
193 that tloc is non-NULL.
194 @return us since epoch */
195 UNIV_INTERN
196 ullint
ut_time_us(ullint * tloc)197 ut_time_us(
198 /*=======*/
199 ullint* tloc) /*!< out: us since epoch, if non-NULL */
200 {
201 struct timeval tv;
202 ullint us;
203
204 ut_gettimeofday(&tv, NULL);
205
206 us = (ullint) tv.tv_sec * 1000000 + tv.tv_usec;
207
208 if (tloc != NULL) {
209 *tloc = us;
210 }
211
212 return(us);
213 }
214
215 /**********************************************************//**
216 Returns the number of milliseconds since some epoch. The
217 value may wrap around. It should only be used for heuristic
218 purposes.
219 @return ms since epoch */
220 UNIV_INTERN
221 ulint
ut_time_ms(void)222 ut_time_ms(void)
223 /*============*/
224 {
225 struct timeval tv;
226
227 ut_gettimeofday(&tv, NULL);
228
229 return((ulint) tv.tv_sec * 1000 + tv.tv_usec / 1000);
230 }
231 #endif /* !UNIV_HOTBACKUP */
232
233 /** Returns the number of milliseconds since some epoch using monotonic clock.
234 The value may wrap around. This should not be used as an accurate Time Of Day.
235 It is only intended to be used as a means of calculating transient elapsed or
236 projected time that will not be influenced by changes to the systems real time
237 clock. Returns a small structure that contains the result so as to poison the
238 code and reveal any changes that might later be introduced by upstream.
239 */
240 ut_monotonic_time
ut_monotonic_time_ms(void)241 ut_monotonic_time_ms(void) {
242 timespec tp;
243 ut_monotonic_time ret;
244 clock_gettime(CLOCK_MONOTONIC, &tp);
245
246 ret.ms = (ulint) tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
247 return ret;
248 }
249
250 /**********************************************************//**
251 Returns the difference of two times in seconds.
252 @return time2 - time1 expressed in seconds */
253 UNIV_INTERN
254 double
ut_difftime(ib_time_t time2,ib_time_t time1)255 ut_difftime(
256 /*========*/
257 ib_time_t time2, /*!< in: time */
258 ib_time_t time1) /*!< in: time */
259 {
260 return(difftime(time2, time1));
261 }
262
263 #endif /* !UNIV_INNOCHECKSUM */
264
265 /**********************************************************//**
266 Prints a timestamp to a file. */
267 UNIV_INTERN
268 void
ut_print_timestamp(FILE * file)269 ut_print_timestamp(
270 /*===============*/
271 FILE* file) /*!< in: file where to print */
272 {
273 ulint thread_id = 0;
274
275 #ifndef UNIV_INNOCHECKSUM
276 thread_id = os_thread_pf(os_thread_get_curr_id());
277 #endif
278
279 #ifdef __WIN__
280 SYSTEMTIME cal_tm;
281
282 GetLocalTime(&cal_tm);
283
284 fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %lx",
285 (int) cal_tm.wYear,
286 (int) cal_tm.wMonth,
287 (int) cal_tm.wDay,
288 (int) cal_tm.wHour,
289 (int) cal_tm.wMinute,
290 (int) cal_tm.wSecond,
291 thread_id);
292 #else
293 struct tm* cal_tm_ptr;
294 time_t tm;
295
296 #ifdef HAVE_LOCALTIME_R
297 struct tm cal_tm;
298 time(&tm);
299 localtime_r(&tm, &cal_tm);
300 cal_tm_ptr = &cal_tm;
301 #else
302 time(&tm);
303 cal_tm_ptr = localtime(&tm);
304 #endif
305 fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %lx",
306 cal_tm_ptr->tm_year + 1900,
307 cal_tm_ptr->tm_mon + 1,
308 cal_tm_ptr->tm_mday,
309 cal_tm_ptr->tm_hour,
310 cal_tm_ptr->tm_min,
311 cal_tm_ptr->tm_sec,
312 thread_id);
313 #endif
314 }
315
316 #ifndef UNIV_INNOCHECKSUM
317
318 /**********************************************************//**
319 Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */
320 UNIV_INTERN
321 void
ut_sprintf_timestamp(char * buf)322 ut_sprintf_timestamp(
323 /*=================*/
324 char* buf) /*!< in: buffer where to sprintf */
325 {
326 #ifdef __WIN__
327 SYSTEMTIME cal_tm;
328
329 GetLocalTime(&cal_tm);
330
331 sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
332 (int) cal_tm.wYear % 100,
333 (int) cal_tm.wMonth,
334 (int) cal_tm.wDay,
335 (int) cal_tm.wHour,
336 (int) cal_tm.wMinute,
337 (int) cal_tm.wSecond);
338 #else
339 struct tm* cal_tm_ptr;
340 time_t tm;
341
342 #ifdef HAVE_LOCALTIME_R
343 struct tm cal_tm;
344 time(&tm);
345 localtime_r(&tm, &cal_tm);
346 cal_tm_ptr = &cal_tm;
347 #else
348 time(&tm);
349 cal_tm_ptr = localtime(&tm);
350 #endif
351 sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
352 cal_tm_ptr->tm_year % 100,
353 cal_tm_ptr->tm_mon + 1,
354 cal_tm_ptr->tm_mday,
355 cal_tm_ptr->tm_hour,
356 cal_tm_ptr->tm_min,
357 cal_tm_ptr->tm_sec);
358 #endif
359 }
360
361 #ifdef UNIV_HOTBACKUP
362 /**********************************************************//**
363 Sprintfs a timestamp to a buffer with no spaces and with ':' characters
364 replaced by '_'. */
365 UNIV_INTERN
366 void
ut_sprintf_timestamp_without_extra_chars(char * buf)367 ut_sprintf_timestamp_without_extra_chars(
368 /*=====================================*/
369 char* buf) /*!< in: buffer where to sprintf */
370 {
371 #ifdef __WIN__
372 SYSTEMTIME cal_tm;
373
374 GetLocalTime(&cal_tm);
375
376 sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
377 (int) cal_tm.wYear % 100,
378 (int) cal_tm.wMonth,
379 (int) cal_tm.wDay,
380 (int) cal_tm.wHour,
381 (int) cal_tm.wMinute,
382 (int) cal_tm.wSecond);
383 #else
384 struct tm* cal_tm_ptr;
385 time_t tm;
386
387 #ifdef HAVE_LOCALTIME_R
388 struct tm cal_tm;
389 time(&tm);
390 localtime_r(&tm, &cal_tm);
391 cal_tm_ptr = &cal_tm;
392 #else
393 time(&tm);
394 cal_tm_ptr = localtime(&tm);
395 #endif
396 sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
397 cal_tm_ptr->tm_year % 100,
398 cal_tm_ptr->tm_mon + 1,
399 cal_tm_ptr->tm_mday,
400 cal_tm_ptr->tm_hour,
401 cal_tm_ptr->tm_min,
402 cal_tm_ptr->tm_sec);
403 #endif
404 }
405
406 /**********************************************************//**
407 Returns current year, month, day. */
408 UNIV_INTERN
409 void
ut_get_year_month_day(ulint * year,ulint * month,ulint * day)410 ut_get_year_month_day(
411 /*==================*/
412 ulint* year, /*!< out: current year */
413 ulint* month, /*!< out: month */
414 ulint* day) /*!< out: day */
415 {
416 #ifdef __WIN__
417 SYSTEMTIME cal_tm;
418
419 GetLocalTime(&cal_tm);
420
421 *year = (ulint) cal_tm.wYear;
422 *month = (ulint) cal_tm.wMonth;
423 *day = (ulint) cal_tm.wDay;
424 #else
425 struct tm* cal_tm_ptr;
426 time_t tm;
427
428 #ifdef HAVE_LOCALTIME_R
429 struct tm cal_tm;
430 time(&tm);
431 localtime_r(&tm, &cal_tm);
432 cal_tm_ptr = &cal_tm;
433 #else
434 time(&tm);
435 cal_tm_ptr = localtime(&tm);
436 #endif
437 *year = (ulint) cal_tm_ptr->tm_year + 1900;
438 *month = (ulint) cal_tm_ptr->tm_mon + 1;
439 *day = (ulint) cal_tm_ptr->tm_mday;
440 #endif
441 }
442 #endif /* UNIV_HOTBACKUP */
443
444 #ifndef UNIV_HOTBACKUP
445 /*************************************************************//**
446 Runs an idle loop on CPU. The argument gives the desired delay
447 in microseconds on 100 MHz Pentium + Visual C++.
448 @return dummy value */
449 UNIV_INTERN
450 ulint
ut_delay(ulint delay)451 ut_delay(
452 /*=====*/
453 ulint delay) /*!< in: delay in microseconds on 100 MHz Pentium */
454 {
455 ulint i, j;
456
457 j = 0;
458
459 for (i = 0; i < delay * 50; i++) {
460 j += i;
461 UT_RELAX_CPU();
462 }
463
464 if (ut_always_false) {
465 ut_always_false = (ibool) j;
466 }
467
468 return(j);
469 }
470 #endif /* !UNIV_HOTBACKUP */
471
472 /*************************************************************//**
473 Prints the contents of a memory buffer in hex and ascii. */
474 UNIV_INTERN
475 void
ut_print_buf(FILE * file,const void * buf,ulint len)476 ut_print_buf(
477 /*=========*/
478 FILE* file, /*!< in: file where to print */
479 const void* buf, /*!< in: memory buffer */
480 ulint len) /*!< in: length of the buffer */
481 {
482 const byte* data;
483 ulint i;
484
485 UNIV_MEM_ASSERT_RW(buf, len);
486
487 fprintf(file, " len %lu; hex ", len);
488
489 for (data = (const byte*) buf, i = 0; i < len; i++) {
490 fprintf(file, "%02lx", (ulong)*data++);
491 }
492
493 fputs("; asc ", file);
494
495 data = (const byte*) buf;
496
497 for (i = 0; i < len; i++) {
498 int c = (int) *data++;
499 putc(isprint(c) ? c : ' ', file);
500 }
501
502 putc(';', file);
503 }
504
505 /**********************************************************************//**
506 Sort function for ulint arrays. */
507 UNIV_INTERN
508 void
ut_ulint_sort(ulint * arr,ulint * aux_arr,ulint low,ulint high)509 ut_ulint_sort(
510 /*==========*/
511 ulint* arr, /*!< in/out: array to sort */
512 ulint* aux_arr, /*!< in/out: aux array to use in sort */
513 ulint low, /*!< in: lower bound */
514 ulint high) /*!< in: upper bound */
515 {
516 UT_SORT_FUNCTION_BODY(ut_ulint_sort, arr, aux_arr, low, high,
517 ut_ulint_cmp);
518 }
519
520 /*************************************************************//**
521 Calculates fast the number rounded up to the nearest power of 2.
522 @return first power of 2 which is >= n */
523 UNIV_INTERN
524 ulint
ut_2_power_up(ulint n)525 ut_2_power_up(
526 /*==========*/
527 ulint n) /*!< in: number != 0 */
528 {
529 ulint res;
530
531 res = 1;
532
533 ut_ad(n > 0);
534
535 while (res < n) {
536 res = res * 2;
537 }
538
539 return(res);
540 }
541
542 /**********************************************************************//**
543 Outputs a NUL-terminated file name, quoted with apostrophes. */
544 UNIV_INTERN
545 void
ut_print_filename(FILE * f,const char * name)546 ut_print_filename(
547 /*==============*/
548 FILE* f, /*!< in: output stream */
549 const char* name) /*!< in: name to print */
550 {
551 putc('\'', f);
552 for (;;) {
553 int c = *name++;
554 switch (c) {
555 case 0:
556 goto done;
557 case '\'':
558 putc(c, f);
559 /* fall through */
560 default:
561 putc(c, f);
562 }
563 }
564 done:
565 putc('\'', f);
566 }
567 #ifndef UNIV_HOTBACKUP
568 /**********************************************************************//**
569 Outputs a fixed-length string, quoted as an SQL identifier.
570 If the string contains a slash '/', the string will be
571 output as two identifiers separated by a period (.),
572 as in SQL database_name.identifier. */
573 UNIV_INTERN
574 void
ut_print_name(FILE * f,const trx_t * trx,ibool table_id,const char * name)575 ut_print_name(
576 /*==========*/
577 FILE* f, /*!< in: output stream */
578 const trx_t* trx, /*!< in: transaction */
579 ibool table_id,/*!< in: TRUE=print a table name,
580 FALSE=print other identifier */
581 const char* name) /*!< in: name to print */
582 {
583 ut_print_namel(f, trx, table_id, name, strlen(name));
584 }
585
586 /**********************************************************************//**
587 Outputs a fixed-length string, quoted as an SQL identifier.
588 If the string contains a slash '/', the string will be
589 output as two identifiers separated by a period (.),
590 as in SQL database_name.identifier. */
591 UNIV_INTERN
592 void
ut_print_namel(FILE * f,const trx_t * trx,ibool table_id,const char * name,ulint namelen)593 ut_print_namel(
594 /*===========*/
595 FILE* f, /*!< in: output stream */
596 const trx_t* trx, /*!< in: transaction (NULL=no quotes) */
597 ibool table_id,/*!< in: TRUE=print a table name,
598 FALSE=print other identifier */
599 const char* name, /*!< in: name to print */
600 ulint namelen)/*!< in: length of name */
601 {
602 /* 2 * NAME_LEN for database and table name,
603 and some slack for the #mysql50# prefix and quotes */
604 char buf[3 * NAME_LEN];
605 const char* bufend;
606
607 bufend = innobase_convert_name(buf, sizeof buf,
608 name, namelen,
609 trx ? trx->mysql_thd : NULL,
610 table_id);
611
612 fwrite(buf, 1, bufend - buf, f);
613 }
614
615 /**********************************************************************//**
616 Formats a table or index name, quoted as an SQL identifier. If the name
617 contains a slash '/', the result will contain two identifiers separated by
618 a period (.), as in SQL database_name.identifier.
619 @return pointer to 'formatted' */
620 UNIV_INTERN
621 char*
ut_format_name(const char * name,ibool is_table,char * formatted,ulint formatted_size)622 ut_format_name(
623 /*===========*/
624 const char* name, /*!< in: table or index name, must be
625 '\0'-terminated */
626 ibool is_table, /*!< in: if TRUE then 'name' is a table
627 name */
628 char* formatted, /*!< out: formatted result, will be
629 '\0'-terminated */
630 ulint formatted_size) /*!< out: no more than this number of
631 bytes will be written to 'formatted' */
632 {
633 switch (formatted_size) {
634 case 1:
635 formatted[0] = '\0';
636 /* FALL-THROUGH */
637 case 0:
638 return(formatted);
639 }
640
641 char* end;
642
643 end = innobase_convert_name(formatted, formatted_size,
644 name, strlen(name), NULL, is_table);
645
646 /* If the space in 'formatted' was completely used, then sacrifice
647 the last character in order to write '\0' at the end. */
648 if ((ulint) (end - formatted) == formatted_size) {
649 end--;
650 }
651
652 ut_a((ulint) (end - formatted) < formatted_size);
653
654 *end = '\0';
655
656 return(formatted);
657 }
658
659 /**********************************************************************//**
660 Catenate files. */
661 UNIV_INTERN
662 void
ut_copy_file(FILE * dest,FILE * src)663 ut_copy_file(
664 /*=========*/
665 FILE* dest, /*!< in: output file */
666 FILE* src) /*!< in: input file to be appended to output */
667 {
668 long len = ftell(src);
669 char buf[4096];
670
671 rewind(src);
672 do {
673 size_t maxs = len < (long) sizeof buf
674 ? (size_t) len
675 : sizeof buf;
676 size_t size = fread(buf, 1, maxs, src);
677 fwrite(buf, 1, size, dest);
678 len -= (long) size;
679 if (size < maxs) {
680 break;
681 }
682 } while (len > 0);
683 }
684 #endif /* !UNIV_HOTBACKUP */
685
686 #ifdef __WIN__
687 # include <stdarg.h>
688 /**********************************************************************//**
689 A substitute for vsnprintf(3), formatted output conversion into
690 a limited buffer. Note: this function DOES NOT return the number of
691 characters that would have been printed if the buffer was unlimited because
692 VC's _vsnprintf() returns -1 in this case and we would need to call
693 _vscprintf() in addition to estimate that but we would need another copy
694 of "ap" for that and VC does not provide va_copy(). */
695 UNIV_INTERN
696 void
ut_vsnprintf(char * str,size_t size,const char * fmt,va_list ap)697 ut_vsnprintf(
698 /*=========*/
699 char* str, /*!< out: string */
700 size_t size, /*!< in: str size */
701 const char* fmt, /*!< in: format */
702 va_list ap) /*!< in: format values */
703 {
704 _vsnprintf(str, size, fmt, ap);
705 str[size - 1] = '\0';
706 }
707
708 /**********************************************************************//**
709 A substitute for snprintf(3), formatted output conversion into
710 a limited buffer.
711 @return number of characters that would have been printed if the size
712 were unlimited, not including the terminating '\0'. */
713 UNIV_INTERN
714 int
ut_snprintf(char * str,size_t size,const char * fmt,...)715 ut_snprintf(
716 /*========*/
717 char* str, /*!< out: string */
718 size_t size, /*!< in: str size */
719 const char* fmt, /*!< in: format */
720 ...) /*!< in: format values */
721 {
722 int res;
723 va_list ap1;
724 va_list ap2;
725
726 va_start(ap1, fmt);
727 va_start(ap2, fmt);
728
729 res = _vscprintf(fmt, ap1);
730 ut_a(res != -1);
731
732 if (size > 0) {
733 _vsnprintf(str, size, fmt, ap2);
734
735 if ((size_t) res >= size) {
736 str[size - 1] = '\0';
737 }
738 }
739
740 va_end(ap1);
741 va_end(ap2);
742
743 return(res);
744 }
745 #endif /* __WIN__ */
746
747 /*************************************************************//**
748 Convert an error number to a human readable text message. The
749 returned string is static and should not be freed or modified.
750 @return string, describing the error */
751 UNIV_INTERN
752 const char*
ut_strerr(dberr_t num)753 ut_strerr(
754 /*======*/
755 dberr_t num) /*!< in: error number */
756 {
757 switch (num) {
758 case DB_SUCCESS:
759 return("Success");
760 case DB_SUCCESS_LOCKED_REC:
761 return("Success, record lock created");
762 case DB_ERROR:
763 return("Generic error");
764 case DB_READ_ONLY:
765 return("Read only transaction");
766 case DB_INTERRUPTED:
767 return("Operation interrupted");
768 case DB_OUT_OF_MEMORY:
769 return("Cannot allocate memory");
770 case DB_OUT_OF_FILE_SPACE:
771 return("Out of disk space");
772 case DB_LOCK_WAIT:
773 return("Lock wait");
774 case DB_DEADLOCK:
775 return("Deadlock");
776 case DB_ROLLBACK:
777 return("Rollback");
778 case DB_DUPLICATE_KEY:
779 return("Duplicate key");
780 case DB_QUE_THR_SUSPENDED:
781 return("The queue thread has been suspended");
782 case DB_MISSING_HISTORY:
783 return("Required history data has been deleted");
784 case DB_CLUSTER_NOT_FOUND:
785 return("Cluster not found");
786 case DB_TABLE_NOT_FOUND:
787 return("Table not found");
788 case DB_MUST_GET_MORE_FILE_SPACE:
789 return("More file space needed");
790 case DB_TABLE_IS_BEING_USED:
791 return("Table is being used");
792 case DB_TOO_BIG_RECORD:
793 return("Record too big");
794 case DB_TOO_BIG_INDEX_COL:
795 return("Index columns size too big");
796 case DB_LOCK_WAIT_TIMEOUT:
797 return("Lock wait timeout");
798 case DB_NO_REFERENCED_ROW:
799 return("Referenced key value not found");
800 case DB_ROW_IS_REFERENCED:
801 return("Row is referenced");
802 case DB_CANNOT_ADD_CONSTRAINT:
803 return("Cannot add constraint");
804 case DB_CORRUPTION:
805 return("Data structure corruption");
806 case DB_CANNOT_DROP_CONSTRAINT:
807 return("Cannot drop constraint");
808 case DB_NO_SAVEPOINT:
809 return("No such savepoint");
810 case DB_TABLESPACE_EXISTS:
811 return("Tablespace already exists");
812 case DB_TABLESPACE_DELETED:
813 return("Tablespace deleted or being deleted");
814 case DB_TABLESPACE_NOT_FOUND:
815 return("Tablespace not found");
816 case DB_LOCK_TABLE_FULL:
817 return("Lock structs have exhausted the buffer pool");
818 case DB_FOREIGN_DUPLICATE_KEY:
819 return("Foreign key activated with duplicate keys");
820 case DB_FOREIGN_EXCEED_MAX_CASCADE:
821 return("Foreign key cascade delete/update exceeds max depth");
822 case DB_TOO_MANY_CONCURRENT_TRXS:
823 return("Too many concurrent transactions");
824 case DB_UNSUPPORTED:
825 return("Unsupported");
826 case DB_INVALID_NULL:
827 return("NULL value encountered in NOT NULL column");
828 case DB_STATS_DO_NOT_EXIST:
829 return("Persistent statistics do not exist");
830 case DB_FAIL:
831 return("Failed, retry may succeed");
832 case DB_OVERFLOW:
833 return("Overflow");
834 case DB_UNDERFLOW:
835 return("Underflow");
836 case DB_STRONG_FAIL:
837 return("Failed, retry will not succeed");
838 case DB_ZIP_OVERFLOW:
839 return("Zip overflow");
840 case DB_RECORD_NOT_FOUND:
841 return("Record not found");
842 case DB_CHILD_NO_INDEX:
843 return("No index on referencing keys in referencing table");
844 case DB_PARENT_NO_INDEX:
845 return("No index on referenced keys in referenced table");
846 case DB_FTS_INVALID_DOCID:
847 return("FTS Doc ID cannot be zero");
848 case DB_INDEX_CORRUPT:
849 return("Index corrupted");
850 case DB_UNDO_RECORD_TOO_BIG:
851 return("Undo record too big");
852 case DB_END_OF_INDEX:
853 return("End of index");
854 case DB_IO_ERROR:
855 return("I/O error");
856 case DB_TABLE_IN_FK_CHECK:
857 return("Table is being used in foreign key check");
858 case DB_DATA_MISMATCH:
859 return("data mismatch");
860 case DB_SCHEMA_NOT_LOCKED:
861 return("schema not locked");
862 case DB_NOT_FOUND:
863 return("not found");
864 case DB_ONLINE_LOG_TOO_BIG:
865 return("Log size exceeded during online index creation");
866 case DB_DICT_CHANGED:
867 return("Table dictionary has changed");
868 case DB_IDENTIFIER_TOO_LONG:
869 return("Identifier name is too long");
870 case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
871 return("FTS query exceeds result cache limit");
872 case DB_TEMP_FILE_WRITE_FAILURE:
873 return("Temp file write failure");
874 case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
875 return("Too many words in a FTS phrase or proximity search");
876 case DB_TOO_BIG_FOR_REDO:
877 return("BLOB record length is greater than 10%% of redo log");
878 case DB_FTS_TOO_MANY_NESTED_EXP:
879 return("Too many nested sub-expressions in a full-text search");
880
881 /* do not add default: in order to produce a warning if new code
882 is added to the enum but not added here */
883 }
884
885 /* we abort here because if unknown error code is given, this could
886 mean that memory corruption has happened and someone's error-code
887 variable has been overwritten with bogus data */
888 ut_error;
889
890 /* NOT REACHED */
891 return("Unknown error");
892 }
893 #endif /* !UNIV_INNOCHECKSUM */
894