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