ut0ut.c 17.4 KB
Newer Older
1 2
/*****************************************************************************

3
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
4 5 6 7 8 9 10
Copyright (c) 2009, Sun Microsystems, Inc.

Portions of this file contain modifications contributed and copyrighted by
Sun Microsystems, Inc. Those modifications are gratefully acknowledged and
are described briefly in the InnoDB documentation. The contributions by
Sun Microsystems are incorporated with their permission, and subject to the
conditions contained in the file COPYING.Sun_Microsystems.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA

*****************************************************************************/

26 27
/***************************************************************//**
@file ut/ut0ut.c
osku's avatar
osku committed
28 29 30 31 32 33 34 35 36 37 38 39 40
Various utilities for Innobase.

Created 5/11/1994 Heikki Tuuri
********************************************************************/

#include "ut0ut.h"

#ifdef UNIV_NONINL
#include "ut0ut.ic"
#endif

#include <stdarg.h>
#include <string.h>
41
#include <ctype.h>
osku's avatar
osku committed
42

43
#ifndef UNIV_HOTBACKUP
44 45
# include "trx0trx.h"
# include "ha_prototypes.h"
46 47
# include "mysql_com.h" /* NAME_LEN */
#endif /* UNIV_HOTBACKUP */
osku's avatar
osku committed
48

49
/** A constant to prevent the compiler from optimizing ut_delay() away. */
50
UNIV_INTERN ibool	ut_always_false	= FALSE;
osku's avatar
osku committed
51

52
#ifdef __WIN__
53
/*****************************************************************//**
54 55 56
NOTE: The Windows epoch starts from 1601/01/01 whereas the Unix
epoch starts from 1970/1/1. For selection of constant see:
http://support.microsoft.com/kb/167296/ */
57
#define WIN_TO_UNIX_DELTA_USEC  ((ib_int64_t) 11644473600000000ULL)
58 59


60
/*****************************************************************//**
61 62
This is the Windows version of gettimeofday(2).
@return	0 if all OK else -1 */
63 64 65 66
static
int
ut_gettimeofday(
/*============*/
67 68
	struct timeval*	tv,	/*!< out: Values are relative to Unix epoch */
	void*		tz)	/*!< in: not used */
69 70
{
	FILETIME	ft;
71
	ib_int64_t	tm;
72 73 74 75 76 77 78 79

	if (!tv) {
		errno = EINVAL;
		return(-1);
	}

	GetSystemTimeAsFileTime(&ft);

80
	tm = (ib_int64_t) ft.dwHighDateTime << 32;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
	tm |= ft.dwLowDateTime;

	ut_a(tm >= 0);	/* If tm wraps over to negative, the quotient / 10
			does not work */

	tm /= 10;	/* Convert from 100 nsec periods to usec */

	/* If we don't convert to the Unix epoch the value for
	struct timeval::tv_sec will overflow.*/
	tm -= WIN_TO_UNIX_DELTA_USEC;

	tv->tv_sec  = (long) (tm / 1000000L);
	tv->tv_usec = (long) (tm % 1000000L);

	return(0);
}
#else
98 99
/** An alias for gettimeofday(2).  On Microsoft Windows, we have to
reimplement this function. */
100 101 102
#define	ut_gettimeofday		gettimeofday
#endif

103
/********************************************************//**
osku's avatar
osku committed
104 105
Gets the high 32 bits in a ulint. That is makes a shift >> 32,
but since there seem to be compiler bugs in both gcc and Visual C++,
106 107
we do this by a special conversion.
@return	a >> 32 */
108
UNIV_INTERN
osku's avatar
osku committed
109 110 111
ulint
ut_get_high32(
/*==========*/
112
	ulint	a)	/*!< in: ulint */
osku's avatar
osku committed
113
{
114
	ib_int64_t	i;
osku's avatar
osku committed
115

116
	i = (ib_int64_t)a;
osku's avatar
osku committed
117 118 119 120 121 122

	i = i >> 32;

	return((ulint)i);
}

123
/**********************************************************//**
osku's avatar
osku committed
124
Returns system time. We do not specify the format of the time returned:
125 126
the only way to manipulate it is to use the function ut_difftime.
@return	system time */
127
UNIV_INTERN
osku's avatar
osku committed
128 129 130 131 132 133 134
ib_time_t
ut_time(void)
/*=========*/
{
	return(time(NULL));
}

135
#ifndef UNIV_HOTBACKUP
136
/**********************************************************//**
137 138 139
Returns system time.
Upon successful completion, the value 0 is returned; otherwise the
value -1 is returned and the global variable errno is set to indicate the
140 141
error.
@return	0 on success, -1 otherwise */
142
UNIV_INTERN
143
int
osku's avatar
osku committed
144 145
ut_usectime(
/*========*/
146 147
	ulint*	sec,	/*!< out: seconds since the Epoch */
	ulint*	ms)	/*!< out: microseconds since the Epoch+*sec */
osku's avatar
osku committed
148 149
{
	struct timeval	tv;
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	int		ret;
	int		errno_gettimeofday;
	int		i;

	for (i = 0; i < 10; i++) {

		ret = ut_gettimeofday(&tv, NULL);

		if (ret == -1) {
			errno_gettimeofday = errno;
			ut_print_timestamp(stderr);
			fprintf(stderr, "  InnoDB: gettimeofday(): %s\n",
				strerror(errno_gettimeofday));
			os_thread_sleep(100000);  /* 0.1 sec */
			errno = errno_gettimeofday;
		} else {
			break;
		}
	}
169

170 171 172 173 174 175
	if (ret != -1) {
		*sec = (ulint) tv.tv_sec;
		*ms  = (ulint) tv.tv_usec;
	}

	return(ret);
osku's avatar
osku committed
176 177
}

178
/**********************************************************//**
179 180
Returns the number of microseconds since epoch. Similar to
time(3), the return value is also stored in *tloc, provided
181 182
that tloc is non-NULL.
@return	us since epoch */
183
UNIV_INTERN
184 185 186
ullint
ut_time_us(
/*=======*/
187
	ullint*	tloc)	/*!< out: us since epoch, if non-NULL */
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
{
	struct timeval	tv;
	ullint		us;

	ut_gettimeofday(&tv, NULL);

	us = (ullint) tv.tv_sec * 1000000 + tv.tv_usec;

	if (tloc != NULL) {
		*tloc = us;
	}

	return(us);
}

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
/**********************************************************//**
Returns the number of milliseconds since some epoch.  The
value may wrap around.  It should only be used for heuristic
purposes.
@return	ms since epoch */
UNIV_INTERN
ulint
ut_time_ms(void)
/*============*/
{
	struct timeval	tv;

	ut_gettimeofday(&tv, NULL);

	return((ulint) tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
#endif /* !UNIV_HOTBACKUP */

221
/**********************************************************//**
222 223
Returns the difference of two times in seconds.
@return	time2 - time1 expressed in seconds */
224
UNIV_INTERN
osku's avatar
osku committed
225 226 227
double
ut_difftime(
/*========*/
228 229
	ib_time_t	time2,	/*!< in: time */
	ib_time_t	time1)	/*!< in: time */
osku's avatar
osku committed
230 231 232 233
{
	return(difftime(time2, time1));
}

234
/**********************************************************//**
osku's avatar
osku committed
235
Prints a timestamp to a file. */
236
UNIV_INTERN
osku's avatar
osku committed
237 238 239
void
ut_print_timestamp(
/*===============*/
240
	FILE*  file) /*!< in: file where to print */
osku's avatar
osku committed
241 242
{
#ifdef __WIN__
243
	SYSTEMTIME cal_tm;
osku's avatar
osku committed
244

245
	GetLocalTime(&cal_tm);
osku's avatar
osku committed
246

247
	fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
248 249 250 251 252 253
		(int)cal_tm.wYear % 100,
		(int)cal_tm.wMonth,
		(int)cal_tm.wDay,
		(int)cal_tm.wHour,
		(int)cal_tm.wMinute,
		(int)cal_tm.wSecond);
osku's avatar
osku committed
254 255
#else
	struct tm  cal_tm;
256 257
	struct tm* cal_tm_ptr;
	time_t	   tm;
osku's avatar
osku committed
258

259
	time(&tm);
osku's avatar
osku committed
260 261

#ifdef HAVE_LOCALTIME_R
262 263
	localtime_r(&tm, &cal_tm);
	cal_tm_ptr = &cal_tm;
osku's avatar
osku committed
264
#else
265
	cal_tm_ptr = localtime(&tm);
osku's avatar
osku committed
266
#endif
267
	fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
268 269 270 271 272 273
		cal_tm_ptr->tm_year % 100,
		cal_tm_ptr->tm_mon + 1,
		cal_tm_ptr->tm_mday,
		cal_tm_ptr->tm_hour,
		cal_tm_ptr->tm_min,
		cal_tm_ptr->tm_sec);
osku's avatar
osku committed
274 275 276
#endif
}

277
/**********************************************************//**
osku's avatar
osku committed
278
Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */
279
UNIV_INTERN
osku's avatar
osku committed
280 281 282
void
ut_sprintf_timestamp(
/*=================*/
283
	char*	buf) /*!< in: buffer where to sprintf */
osku's avatar
osku committed
284 285
{
#ifdef __WIN__
286
	SYSTEMTIME cal_tm;
osku's avatar
osku committed
287

288
	GetLocalTime(&cal_tm);
osku's avatar
osku committed
289

290
	sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
291 292 293 294 295 296
		(int)cal_tm.wYear % 100,
		(int)cal_tm.wMonth,
		(int)cal_tm.wDay,
		(int)cal_tm.wHour,
		(int)cal_tm.wMinute,
		(int)cal_tm.wSecond);
osku's avatar
osku committed
297 298
#else
	struct tm  cal_tm;
299 300
	struct tm* cal_tm_ptr;
	time_t	   tm;
osku's avatar
osku committed
301

302
	time(&tm);
osku's avatar
osku committed
303 304

#ifdef HAVE_LOCALTIME_R
305 306
	localtime_r(&tm, &cal_tm);
	cal_tm_ptr = &cal_tm;
osku's avatar
osku committed
307
#else
308
	cal_tm_ptr = localtime(&tm);
osku's avatar
osku committed
309
#endif
310
	sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
311 312 313 314 315 316
		cal_tm_ptr->tm_year % 100,
		cal_tm_ptr->tm_mon + 1,
		cal_tm_ptr->tm_mday,
		cal_tm_ptr->tm_hour,
		cal_tm_ptr->tm_min,
		cal_tm_ptr->tm_sec);
osku's avatar
osku committed
317 318 319
#endif
}

320
#ifdef UNIV_HOTBACKUP
321
/**********************************************************//**
osku's avatar
osku committed
322 323
Sprintfs a timestamp to a buffer with no spaces and with ':' characters
replaced by '_'. */
324
UNIV_INTERN
osku's avatar
osku committed
325 326 327
void
ut_sprintf_timestamp_without_extra_chars(
/*=====================================*/
328
	char*	buf) /*!< in: buffer where to sprintf */
osku's avatar
osku committed
329 330
{
#ifdef __WIN__
331
	SYSTEMTIME cal_tm;
osku's avatar
osku committed
332

333
	GetLocalTime(&cal_tm);
osku's avatar
osku committed
334

335
	sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
336 337 338 339 340 341
		(int)cal_tm.wYear % 100,
		(int)cal_tm.wMonth,
		(int)cal_tm.wDay,
		(int)cal_tm.wHour,
		(int)cal_tm.wMinute,
		(int)cal_tm.wSecond);
osku's avatar
osku committed
342 343
#else
	struct tm  cal_tm;
344 345
	struct tm* cal_tm_ptr;
	time_t	   tm;
osku's avatar
osku committed
346

347
	time(&tm);
osku's avatar
osku committed
348 349

#ifdef HAVE_LOCALTIME_R
350 351
	localtime_r(&tm, &cal_tm);
	cal_tm_ptr = &cal_tm;
osku's avatar
osku committed
352
#else
353
	cal_tm_ptr = localtime(&tm);
osku's avatar
osku committed
354
#endif
355
	sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
356 357 358 359 360 361
		cal_tm_ptr->tm_year % 100,
		cal_tm_ptr->tm_mon + 1,
		cal_tm_ptr->tm_mday,
		cal_tm_ptr->tm_hour,
		cal_tm_ptr->tm_min,
		cal_tm_ptr->tm_sec);
osku's avatar
osku committed
362 363 364
#endif
}

365
/**********************************************************//**
osku's avatar
osku committed
366
Returns current year, month, day. */
367
UNIV_INTERN
osku's avatar
osku committed
368 369 370
void
ut_get_year_month_day(
/*==================*/
371 372 373
	ulint*	year,	/*!< out: current year */
	ulint*	month,	/*!< out: month */
	ulint*	day)	/*!< out: day */
osku's avatar
osku committed
374 375
{
#ifdef __WIN__
376
	SYSTEMTIME cal_tm;
osku's avatar
osku committed
377

378
	GetLocalTime(&cal_tm);
osku's avatar
osku committed
379

380 381 382
	*year = (ulint)cal_tm.wYear;
	*month = (ulint)cal_tm.wMonth;
	*day = (ulint)cal_tm.wDay;
osku's avatar
osku committed
383 384
#else
	struct tm  cal_tm;
385 386
	struct tm* cal_tm_ptr;
	time_t	   tm;
osku's avatar
osku committed
387

388
	time(&tm);
osku's avatar
osku committed
389 390

#ifdef HAVE_LOCALTIME_R
391 392
	localtime_r(&tm, &cal_tm);
	cal_tm_ptr = &cal_tm;
osku's avatar
osku committed
393
#else
394
	cal_tm_ptr = localtime(&tm);
osku's avatar
osku committed
395
#endif
396 397 398
	*year = (ulint)cal_tm_ptr->tm_year + 1900;
	*month = (ulint)cal_tm_ptr->tm_mon + 1;
	*day = (ulint)cal_tm_ptr->tm_mday;
osku's avatar
osku committed
399 400
#endif
}
401
#endif /* UNIV_HOTBACKUP */
osku's avatar
osku committed
402

403
#ifndef UNIV_HOTBACKUP
404
/*************************************************************//**
osku's avatar
osku committed
405
Runs an idle loop on CPU. The argument gives the desired delay
406 407
in microseconds on 100 MHz Pentium + Visual C++.
@return	dummy value */
408
UNIV_INTERN
osku's avatar
osku committed
409 410 411
ulint
ut_delay(
/*=====*/
412
	ulint	delay)	/*!< in: delay in microseconds on 100 MHz Pentium */
osku's avatar
osku committed
413 414 415 416 417 418 419
{
	ulint	i, j;

	j = 0;

	for (i = 0; i < delay * 50; i++) {
		j += i;
420
		UT_RELAX_CPU();
osku's avatar
osku committed
421 422 423 424 425
	}

	if (ut_always_false) {
		ut_always_false = (ibool) j;
	}
426

osku's avatar
osku committed
427
	return(j);
428
}
429
#endif /* !UNIV_HOTBACKUP */
osku's avatar
osku committed
430

431
/*************************************************************//**
osku's avatar
osku committed
432
Prints the contents of a memory buffer in hex and ascii. */
433
UNIV_INTERN
osku's avatar
osku committed
434 435 436
void
ut_print_buf(
/*=========*/
437 438 439
	FILE*		file,	/*!< in: file where to print */
	const void*	buf,	/*!< in: memory buffer */
	ulint		len)	/*!< in: length of the buffer */
osku's avatar
osku committed
440 441 442 443
{
	const byte*	data;
	ulint		i;

444 445
	UNIV_MEM_ASSERT_RW(buf, len);

osku's avatar
osku committed
446 447
	fprintf(file, " len %lu; hex ", len);

448
	for (data = (const byte*)buf, i = 0; i < len; i++) {
osku's avatar
osku committed
449 450 451 452 453
		fprintf(file, "%02lx", (ulong)*data++);
	}

	fputs("; asc ", file);

454
	data = (const byte*)buf;
osku's avatar
osku committed
455 456 457 458 459 460 461 462 463

	for (i = 0; i < len; i++) {
		int	c = (int) *data++;
		putc(isprint(c) ? c : ' ', file);
	}

	putc(';', file);
}

464
/*************************************************************//**
465 466
Calculates fast the number rounded up to the nearest power of 2.
@return	first power of 2 which is >= n */
467
UNIV_INTERN
osku's avatar
osku committed
468 469 470
ulint
ut_2_power_up(
/*==========*/
471
	ulint	n)	/*!< in: number != 0 */
osku's avatar
osku committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485
{
	ulint	res;

	res = 1;

	ut_ad(n > 0);

	while (res < n) {
		res = res * 2;
	}

	return(res);
}

486
/**********************************************************************//**
osku's avatar
osku committed
487
Outputs a NUL-terminated file name, quoted with apostrophes. */
488
UNIV_INTERN
osku's avatar
osku committed
489 490 491
void
ut_print_filename(
/*==============*/
492 493
	FILE*		f,	/*!< in: output stream */
	const char*	name)	/*!< in: name to print */
osku's avatar
osku committed
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
{
	putc('\'', f);
	for (;;) {
		int	c = *name++;
		switch (c) {
		case 0:
			goto done;
		case '\'':
			putc(c, f);
			/* fall through */
		default:
			putc(c, f);
		}
	}
done:
	putc('\'', f);
}
511
#ifndef UNIV_HOTBACKUP
512
/**********************************************************************//**
513 514 515 516
Outputs a fixed-length string, quoted as an SQL identifier.
If the string contains a slash '/', the string will be
output as two identifiers separated by a period (.),
as in SQL database_name.identifier. */
517
UNIV_INTERN
osku's avatar
osku committed
518 519 520
void
ut_print_name(
/*==========*/
521 522 523
	FILE*		f,	/*!< in: output stream */
	trx_t*		trx,	/*!< in: transaction */
	ibool		table_id,/*!< in: TRUE=print a table name,
524
				FALSE=print other identifier */
525
	const char*	name)	/*!< in: name to print */
osku's avatar
osku committed
526
{
527
	ut_print_namel(f, trx, table_id, name, strlen(name));
osku's avatar
osku committed
528 529
}

530
/**********************************************************************//**
531 532 533 534
Outputs a fixed-length string, quoted as an SQL identifier.
If the string contains a slash '/', the string will be
output as two identifiers separated by a period (.),
as in SQL database_name.identifier. */
535
UNIV_INTERN
osku's avatar
osku committed
536 537
void
ut_print_namel(
538
/*===========*/
539 540 541
	FILE*		f,	/*!< in: output stream */
	trx_t*		trx,	/*!< in: transaction (NULL=no quotes) */
	ibool		table_id,/*!< in: TRUE=print a table name,
542
				FALSE=print other identifier */
543 544
	const char*	name,	/*!< in: name to print */
	ulint		namelen)/*!< in: length of name */
osku's avatar
osku committed
545
{
546 547 548 549
	/* 2 * NAME_LEN for database and table name,
	and some slack for the #mysql50# prefix and quotes */
	char		buf[3 * NAME_LEN];
	const char*	bufend;
550

551 552 553 554
	bufend = innobase_convert_name(buf, sizeof buf,
				       name, namelen,
				       trx ? trx->mysql_thd : NULL,
				       table_id);
555

556
	fwrite(buf, 1, bufend - buf, f);
osku's avatar
osku committed
557 558
}

559
/**********************************************************************//**
osku's avatar
osku committed
560
Catenate files. */
561
UNIV_INTERN
osku's avatar
osku committed
562 563 564
void
ut_copy_file(
/*=========*/
565 566
	FILE*	dest,	/*!< in: output file */
	FILE*	src)	/*!< in: input file to be appended to output */
osku's avatar
osku committed
567 568 569 570 571 572
{
	long	len = ftell(src);
	char	buf[4096];

	rewind(src);
	do {
573 574 575
		size_t	maxs = len < (long) sizeof buf
			? (size_t) len
			: sizeof buf;
osku's avatar
osku committed
576 577 578 579 580 581 582 583
		size_t	size = fread(buf, 1, maxs, src);
		fwrite(buf, 1, size, dest);
		len -= (long) size;
		if (size < maxs) {
			break;
		}
	} while (len > 0);
}
584
#endif /* !UNIV_HOTBACKUP */
585 586

#ifdef __WIN__
587
# include <stdarg.h>
588
/**********************************************************************//**
589
A substitute for snprintf(3), formatted output conversion into
590
a limited buffer.
591 592
@return number of characters that would have been printed if the size
were unlimited, not including the terminating '\0'. */
593
UNIV_INTERN
594 595
int
ut_snprintf(
596
/*========*/
597 598 599 600
	char*		str,	/*!< out: string */
	size_t		size,	/*!< in: str size */
	const char*	fmt,	/*!< in: format */
	...)			/*!< in: format values */
601 602 603 604 605 606 607 608 609
{
	int	res;
	va_list	ap1;
	va_list	ap2;

	va_start(ap1, fmt);
	va_start(ap2, fmt);

	res = _vscprintf(fmt, ap1);
610
	ut_a(res != -1);
611 612 613 614

	if (size > 0) {
		_vsnprintf(str, size, fmt, ap2);

615
		if ((size_t) res >= size) {
616 617 618 619 620 621 622 623 624 625
			str[size - 1] = '\0';
		}
	}

	va_end(ap1);
	va_end(ap2);

	return(res);
}
#endif /* __WIN__ */
626 627 628 629 630 631 632 633 634 635 636 637 638 639

/*************************************************************//**
Convert an error number to a human readable text message. The
returned string is static and should not be freed or modified.
@return	string, describing the error */
UNIV_INTERN
const char*
ut_strerr(
/*======*/
	enum db_err	num)	/*!< in: error number */
{
	switch (num) {
	case DB_SUCCESS:
		return("Success");
640 641
	case DB_SUCCESS_LOCKED_REC:
		return("Success, record lock created");
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
	case DB_ERROR:
		return("Generic error");
	case DB_INTERRUPTED:
		return("Operation interrupted");
	case DB_OUT_OF_MEMORY:
		return("Cannot allocate memory");
	case DB_OUT_OF_FILE_SPACE:
		return("Out of disk space");
	case DB_LOCK_WAIT:
		return("Lock wait");
	case DB_DEADLOCK:
		return("Deadlock");
	case DB_ROLLBACK:
		return("Rollback");
	case DB_DUPLICATE_KEY:
		return("Duplicate key");
	case DB_QUE_THR_SUSPENDED:
		return("The queue thread has been suspended");
	case DB_MISSING_HISTORY:
		return("Required history data has been deleted");
	case DB_CLUSTER_NOT_FOUND:
		return("Cluster not found");
	case DB_TABLE_NOT_FOUND:
		return("Table not found");
	case DB_MUST_GET_MORE_FILE_SPACE:
		return("More file space needed");
	case DB_TABLE_IS_BEING_USED:
		return("Table is being used");
	case DB_TOO_BIG_RECORD:
		return("Record too big");
	case DB_LOCK_WAIT_TIMEOUT:
		return("Lock wait timeout");
	case DB_NO_REFERENCED_ROW:
		return("Referenced key value not found");
	case DB_ROW_IS_REFERENCED:
		return("Row is referenced");
	case DB_CANNOT_ADD_CONSTRAINT:
		return("Cannot add constraint");
	case DB_CORRUPTION:
		return("Data structure corruption");
	case DB_COL_APPEARS_TWICE_IN_INDEX:
		return("Column appears twice in index");
	case DB_CANNOT_DROP_CONSTRAINT:
		return("Cannot drop constraint");
	case DB_NO_SAVEPOINT:
		return("No such savepoint");
	case DB_TABLESPACE_ALREADY_EXISTS:
		return("Tablespace already exists");
	case DB_TABLESPACE_DELETED:
		return("No such tablespace");
	case DB_LOCK_TABLE_FULL:
		return("Lock structs have exhausted the buffer pool");
	case DB_FOREIGN_DUPLICATE_KEY:
		return("Foreign key activated with duplicate keys");
696 697
	case DB_FOREIGN_EXCEED_MAX_CASCADE:
		return("Foreign key cascade delete/update exceeds max depth");
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
	case DB_TOO_MANY_CONCURRENT_TRXS:
		return("Too many concurrent transactions");
	case DB_UNSUPPORTED:
		return("Unsupported");
	case DB_PRIMARY_KEY_IS_NULL:
		return("Primary key is NULL");
	case DB_STATS_DO_NOT_EXIST:
		return("Persistent statistics do not exist");
	case DB_FAIL:
		return("Failed, retry may succeed");
	case DB_OVERFLOW:
		return("Overflow");
	case DB_UNDERFLOW:
		return("Underflow");
	case DB_STRONG_FAIL:
		return("Failed, retry will not succeed");
	case DB_ZIP_OVERFLOW:
		return("Zip overflow");
	case DB_RECORD_NOT_FOUND:
		return("Record not found");
718 719 720 721
	case DB_CHILD_NO_INDEX:
		return("No index on referencing keys in referencing table");
	case DB_PARENT_NO_INDEX:
		return("No index on referenced keys in referenced table");
722 723 724 725 726 727 728 729 730 731 732 733 734 735
	case DB_END_OF_INDEX:
		return("End of index");
	/* do not add default: in order to produce a warning if new code
	is added to the enum but not added here */
	}

	/* we abort here because if unknown error code is given, this could
	mean that memory corruption has happened and someone's error-code
	variable has been overwritten with bogus data */
	ut_error;

	/* NOT REACHED */
	return("Unknown error");
}