ut0mem.cc 15.2 KB
Newer Older
Vadim Tkachenko's avatar
Vadim Tkachenko committed
1 2
/*****************************************************************************

3
Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
Vadim Tkachenko's avatar
Vadim Tkachenko committed
4 5 6 7 8 9 10 11 12 13

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
14 15
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
Vadim Tkachenko's avatar
Vadim Tkachenko committed
16 17 18

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

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
19
/********************************************************************//**
20
@file ut/ut0mem.cc
21 22 23 24 25 26 27 28 29 30 31
Memory primitives

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

#include "ut0mem.h"

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

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
32 33 34
#ifndef UNIV_HOTBACKUP
# include "os0thread.h"
# include "srv0srv.h"
Vadim Tkachenko's avatar
Vadim Tkachenko committed
35 36

#include <stdlib.h>
37

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
38
/** The total amount of memory currently allocated from the operating
Vadim Tkachenko's avatar
Vadim Tkachenko committed
39 40 41 42
system with os_mem_alloc_large() or malloc().  Does not count malloc()
if srv_use_sys_malloc is set.  Protected by ut_list_mutex. */
UNIV_INTERN ulint		ut_total_allocated_memory	= 0;

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
43
/** Mutex protecting ut_total_allocated_memory and ut_mem_block_list */
Vadim Tkachenko's avatar
Vadim Tkachenko committed
44
UNIV_INTERN os_fast_mutex_t	ut_list_mutex;
45

46 47 48 49 50
#ifdef UNIV_PFS_MUTEX
/* Key to register server_mutex with performance schema */
UNIV_INTERN mysql_pfs_key_t	ut_list_mutex_key;
#endif

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
51
/** Dynamically allocated memory block */
52
struct ut_mem_block_t{
53
	UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
54 55 56
			/*!< mem block list node */
	ulint	size;	/*!< size of allocated memory */
	ulint	magic_n;/*!< magic number (UT_MEM_MAGIC_N) */
57 58
};

59
/** The value of ut_mem_block_t::magic_n.  Used in detecting
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
60
memory corruption. */
61 62
#define UT_MEM_MAGIC_N	1601650166

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
63
/** List of all memory blocks allocated from the operating system
Vadim Tkachenko's avatar
Vadim Tkachenko committed
64
with malloc.  Protected by ut_list_mutex. */
65 66
static UT_LIST_BASE_NODE_T(ut_mem_block_t)   ut_mem_block_list;

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
67
/** Flag: has ut_mem_block_list been initialized? */
68 69
static ibool  ut_mem_block_list_inited = FALSE;

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
70 71
/** A dummy pointer for generating a null pointer exception in
ut_malloc_low() */
72 73
static ulint*	ut_mem_null_ptr	= NULL;

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
74
/**********************************************************************//**
75
Initializes the mem block list at database startup. */
Vadim Tkachenko's avatar
Vadim Tkachenko committed
76
UNIV_INTERN
77
void
Vadim Tkachenko's avatar
Vadim Tkachenko committed
78 79
ut_mem_init(void)
/*=============*/
80
{
Vadim Tkachenko's avatar
Vadim Tkachenko committed
81
	ut_a(!ut_mem_block_list_inited);
82
	os_fast_mutex_init(ut_list_mutex_key, &ut_list_mutex);
83 84 85
	UT_LIST_INIT(ut_mem_block_list);
	ut_mem_block_list_inited = TRUE;
}
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
86
#endif /* !UNIV_HOTBACKUP */
87

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
88
/**********************************************************************//**
Sergei Golubchik's avatar
Sergei Golubchik committed
89
Allocates memory.
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
90
@return	own: allocated memory */
91 92 93 94
UNIV_INTERN
void*
ut_malloc_low(
/*==========*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
95 96
	ulint	n,		/*!< in: number of bytes to allocate */
	ibool	assert_on_error)/*!< in: if TRUE, we crash mysqld if the
97 98
				memory cannot be allocated */
{
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
99
#ifndef UNIV_HOTBACKUP
Vadim Tkachenko's avatar
Vadim Tkachenko committed
100
	ulint	retry_count;
101 102
	void*	ret;

Vadim Tkachenko's avatar
Vadim Tkachenko committed
103 104 105
	if (UNIV_LIKELY(srv_use_sys_malloc)) {
		ret = malloc(n);
		ut_a(ret || !assert_on_error);
106

Vadim Tkachenko's avatar
Vadim Tkachenko committed
107
		return(ret);
108
	}
Vadim Tkachenko's avatar
Vadim Tkachenko committed
109 110 111 112 113

	ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
	ut_a(ut_mem_block_list_inited);

	retry_count = 0;
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
retry:
	os_fast_mutex_lock(&ut_list_mutex);

	ret = malloc(n + sizeof(ut_mem_block_t));

	if (ret == NULL && retry_count < 60) {
		if (retry_count == 0) {
			ut_print_timestamp(stderr);

			fprintf(stderr,
				"  InnoDB: Error: cannot allocate"
				" %lu bytes of\n"
				"InnoDB: memory with malloc!"
				" Total allocated memory\n"
				"InnoDB: by InnoDB %lu bytes."
				" Operating system errno: %lu\n"
				"InnoDB: Check if you should"
				" increase the swap file or\n"
				"InnoDB: ulimits of your operating system.\n"
				"InnoDB: On FreeBSD check you"
				" have compiled the OS with\n"
				"InnoDB: a big enough maximum process size.\n"
				"InnoDB: Note that in most 32-bit"
				" computers the process\n"
				"InnoDB: memory space is limited"
				" to 2 GB or 4 GB.\n"
				"InnoDB: We keep retrying"
				" the allocation for 60 seconds...\n",
				(ulong) n, (ulong) ut_total_allocated_memory,
#ifdef __WIN__
				(ulong) GetLastError()
#else
				(ulong) errno
#endif
				);
		}

		os_fast_mutex_unlock(&ut_list_mutex);

		/* Sleep for a second and retry the allocation; maybe this is
		just a temporary shortage of memory */

		os_thread_sleep(1000000);

		retry_count++;

		goto retry;
	}

	if (ret == NULL) {
		/* Flush stderr to make more probable that the error
		message gets in the error file before we generate a seg
		fault */

		fflush(stderr);

		os_fast_mutex_unlock(&ut_list_mutex);

		/* Make an intentional seg fault so that we get a stack
		trace */
		if (assert_on_error) {
			ut_print_timestamp(stderr);

			fprintf(stderr,
				"  InnoDB: We now intentionally"
				" generate a seg fault so that\n"
				"InnoDB: on Linux we get a stack trace.\n");

			if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
		} else {
			return(NULL);
		}
	}

	UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));

190 191
	((ut_mem_block_t*) ret)->size = n + sizeof(ut_mem_block_t);
	((ut_mem_block_t*) ret)->magic_n = UT_MEM_MAGIC_N;
192 193 194 195

	ut_total_allocated_memory += n + sizeof(ut_mem_block_t);

	UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
196
			  ((ut_mem_block_t*) ret));
197 198
	os_fast_mutex_unlock(&ut_list_mutex);

199
	return((void*)((byte*) ret + sizeof(ut_mem_block_t)));
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
200 201 202 203 204 205
#else /* !UNIV_HOTBACKUP */
	void*	ret = malloc(n);
	ut_a(ret || !assert_on_error);

	return(ret);
#endif /* !UNIV_HOTBACKUP */
206 207
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
208
/**********************************************************************//**
209 210
Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is
a nop. */
211 212 213 214
UNIV_INTERN
void
ut_free(
/*====*/
Sergei Golubchik's avatar
Sergei Golubchik committed
215
	void* ptr)  /*!< in, own: memory block, can be NULL */
216
{
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
217
#ifndef UNIV_HOTBACKUP
218 219
	ut_mem_block_t* block;

220 221 222
	if (ptr == NULL) {
		return;
	} else if (UNIV_LIKELY(srv_use_sys_malloc)) {
Vadim Tkachenko's avatar
Vadim Tkachenko committed
223 224 225 226
		free(ptr);
		return;
	}

227
	block = (ut_mem_block_t*)((byte*) ptr - sizeof(ut_mem_block_t));
228 229 230 231 232 233 234 235 236 237 238 239

	os_fast_mutex_lock(&ut_list_mutex);

	ut_a(block->magic_n == UT_MEM_MAGIC_N);
	ut_a(ut_total_allocated_memory >= block->size);

	ut_total_allocated_memory -= block->size;

	UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
	free(block);

	os_fast_mutex_unlock(&ut_list_mutex);
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
240 241 242
#else /* !UNIV_HOTBACKUP */
	free(ptr);
#endif /* !UNIV_HOTBACKUP */
243 244
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
245 246
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
247
Implements realloc. This is needed by /pars/lexyy.cc. Otherwise, you should not
248 249 250 251 252 253 254
use this function because the allocation functions in mem0mem.h are the
recommended ones in InnoDB.

man realloc in Linux, 2004:

       realloc()  changes the size of the memory block pointed to
       by ptr to size bytes.  The contents will be  unchanged  to
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
255
       the minimum of the old and new sizes; newly allocated mem-
256 257 258 259 260 261 262 263 264 265 266 267 268
       ory will be uninitialized.  If ptr is NULL,  the	 call  is
       equivalent  to malloc(size); if size is equal to zero, the
       call is equivalent to free(ptr).	 Unless ptr is	NULL,  it
       must  have  been	 returned by an earlier call to malloc(),
       calloc() or realloc().

RETURN VALUE
       realloc() returns a pointer to the newly allocated memory,
       which is suitably aligned for any kind of variable and may
       be different from ptr, or NULL if the  request  fails.  If
       size  was equal to 0, either NULL or a pointer suitable to
       be passed to free() is returned.	 If realloc()  fails  the
       original	 block	is  left  untouched  - it is not freed or
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
269 270
       moved.
@return	own: pointer to new mem block or NULL */
271 272 273 274
UNIV_INTERN
void*
ut_realloc(
/*=======*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
275 276
	void*	ptr,	/*!< in: pointer to old block or NULL */
	ulint	size)	/*!< in: desired size */
277 278 279 280 281 282
{
	ut_mem_block_t* block;
	ulint		old_size;
	ulint		min_size;
	void*		new_ptr;

Vadim Tkachenko's avatar
Vadim Tkachenko committed
283 284 285 286
	if (UNIV_LIKELY(srv_use_sys_malloc)) {
		return(realloc(ptr, size));
	}

287 288 289 290 291 292 293 294 295 296 297
	if (ptr == NULL) {

		return(ut_malloc(size));
	}

	if (size == 0) {
		ut_free(ptr);

		return(NULL);
	}

298
	block = (ut_mem_block_t*)((byte*) ptr - sizeof(ut_mem_block_t));
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

	ut_a(block->magic_n == UT_MEM_MAGIC_N);

	old_size = block->size - sizeof(ut_mem_block_t);

	if (size < old_size) {
		min_size = size;
	} else {
		min_size = old_size;
	}

	new_ptr = ut_malloc(size);

	if (new_ptr == NULL) {

		return(NULL);
	}

	/* Copy the old data from ptr */
	ut_memcpy(new_ptr, ptr, min_size);

	ut_free(ptr);

	return(new_ptr);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
325
/**********************************************************************//**
326 327 328 329 330 331 332 333
Frees in shutdown all allocated memory not freed yet. */
UNIV_INTERN
void
ut_free_all_mem(void)
/*=================*/
{
	ut_mem_block_t* block;

Vadim Tkachenko's avatar
Vadim Tkachenko committed
334 335
	ut_a(ut_mem_block_list_inited);
	ut_mem_block_list_inited = FALSE;
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
	os_fast_mutex_free(&ut_list_mutex);

	while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {

		ut_a(block->magic_n == UT_MEM_MAGIC_N);
		ut_a(ut_total_allocated_memory >= block->size);

		ut_total_allocated_memory -= block->size;

		UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
		free(block);
	}

	if (ut_total_allocated_memory != 0) {
		fprintf(stderr,
			"InnoDB: Warning: after shutdown"
			" total allocated memory is %lu\n",
			(ulong) ut_total_allocated_memory);
	}
355 356

	ut_mem_block_list_inited = FALSE;
357
}
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
358
#endif /* !UNIV_HOTBACKUP */
359

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
360
/**********************************************************************//**
361 362
Copies up to size - 1 characters from the NUL-terminated string src to
dst, NUL-terminating the result. Returns strlen(src), so truncation
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
363 364
occurred if the return value >= size.
@return	strlen(src) */
365 366 367 368
UNIV_INTERN
ulint
ut_strlcpy(
/*=======*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
369 370 371
	char*		dst,	/*!< in: destination buffer */
	const char*	src,	/*!< in: source buffer */
	ulint		size)	/*!< in: size of destination buffer */
372 373 374 375 376 377 378 379 380 381 382 383 384
{
	ulint	src_size = strlen(src);

	if (size != 0) {
		ulint	n = ut_min(src_size, size - 1);

		memcpy(dst, src, n);
		dst[n] = '\0';
	}

	return(src_size);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
385
/**********************************************************************//**
386
Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
387 388
(size - 1) bytes of src, not the first.
@return	strlen(src) */
389 390 391 392
UNIV_INTERN
ulint
ut_strlcpy_rev(
/*===========*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
393 394 395
	char*		dst,	/*!< in: destination buffer */
	const char*	src,	/*!< in: source buffer */
	ulint		size)	/*!< in: size of destination buffer */
396 397 398 399 400 401 402 403 404 405 406 407
{
	ulint	src_size = strlen(src);

	if (size != 0) {
		ulint	n = ut_min(src_size, size - 1);

		memcpy(dst, src + src_size - n, n + 1);
	}

	return(src_size);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
408 409
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
410
Return the number of times s2 occurs in s1. Overlapping instances of s2
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
411 412
are only counted once.
@return	the number of times s2 occurs in s1 */
413 414 415 416
UNIV_INTERN
ulint
ut_strcount(
/*========*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
417 418
	const char*	s1,	/*!< in: string to search in */
	const char*	s2)	/*!< in: string to search for */
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
{
	ulint	count = 0;
	ulint	len = strlen(s2);

	if (len == 0) {

		return(0);
	}

	for (;;) {
		s1 = strstr(s1, s2);

		if (!s1) {

			break;
		}

		count++;
		s1 += len;
	}

	return(count);
}

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
/********************************************************************
Concatenate 3 strings.*/

char*
ut_str3cat(
/*=======*/
				/* out, own: concatenated string, must be
				freed with mem_free() */
	const char*	s1,	/* in: string 1 */
	const char*	s2,	/* in: string 2 */
	const char*	s3)	/* in: string 3 */
{
	char*	s;
	ulint	s1_len = strlen(s1);
	ulint	s2_len = strlen(s2);
	ulint	s3_len = strlen(s3);

	s = static_cast<char*>(mem_alloc(s1_len + s2_len + s3_len + 1));

	memcpy(s, s1, s1_len);
	memcpy(s + s1_len, s2, s2_len);
	memcpy(s + s1_len + s2_len, s3, s3_len);

	s[s1_len + s2_len + s3_len] = '\0';

	return(s);
}
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
470
/**********************************************************************//**
471
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
472 473
are only replaced once.
@return	own: modified string, must be freed with mem_free() */
474 475 476 477
UNIV_INTERN
char*
ut_strreplace(
/*==========*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
478 479 480
	const char*	str,	/*!< in: string to operate on */
	const char*	s1,	/*!< in: string to replace */
	const char*	s2)	/*!< in: string to replace s1 with */
481 482 483 484 485 486 487 488
{
	char*		new_str;
	char*		ptr;
	const char*	str_end;
	ulint		str_len = strlen(str);
	ulint		s1_len = strlen(s1);
	ulint		s2_len = strlen(s2);
	ulint		count = 0;
489
	int		len_delta = (int) s2_len - (int) s1_len;
490 491 492 493 494 495 496 497 498

	str_end = str + str_len;

	if (len_delta <= 0) {
		len_delta = 0;
	} else {
		count = ut_strcount(str, s1);
	}

499 500 501
	new_str = static_cast<char*>(
		mem_alloc(str_len + count * len_delta + 1));

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	ptr = new_str;

	while (str) {
		const char*	next = strstr(str, s1);

		if (!next) {
			next = str_end;
		}

		memcpy(ptr, str, next - str);
		ptr += next - str;

		if (next == str_end) {

			break;
		}

		memcpy(ptr, s2, s2_len);
		ptr += s2_len;

		str = next + s1_len;
	}

	*ptr = '\0';

	return(new_str);
}

#ifdef UNIV_COMPILE_TEST_FUNCS

void
test_ut_str_sql_format()
{
	char	buf[128];
	ulint	ret;

#define CALL_AND_TEST(str, str_len, buf, buf_size, ret_expected, buf_expected)\
	do {\
		ibool	ok = TRUE;\
		memset(buf, 'x', 10);\
		buf[10] = '\0';\
		fprintf(stderr, "TESTING \"%s\", %lu, %lu\n",\
			str, (ulint) str_len, (ulint) buf_size);\
		ret = ut_str_sql_format(str, str_len, buf, buf_size);\
		if (ret != ret_expected) {\
			fprintf(stderr, "expected ret %lu, got %lu\n",\
				(ulint) ret_expected, ret);\
			ok = FALSE;\
		}\
		if (strcmp((char*) buf, buf_expected) != 0) {\
			fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
				buf_expected, buf);\
			ok = FALSE;\
		}\
		if (ok) {\
			fprintf(stderr, "OK: %lu, \"%s\"\n\n",\
				(ulint) ret, buf);\
		} else {\
			return;\
		}\
	} while (0)

	CALL_AND_TEST("abcd", 4, buf, 0, 0, "xxxxxxxxxx");

	CALL_AND_TEST("abcd", 4, buf, 1, 1, "");

	CALL_AND_TEST("abcd", 4, buf, 2, 1, "");

	CALL_AND_TEST("abcd", 0, buf, 3, 3, "''");
	CALL_AND_TEST("abcd", 1, buf, 3, 1, "");
	CALL_AND_TEST("abcd", 2, buf, 3, 1, "");
	CALL_AND_TEST("abcd", 3, buf, 3, 1, "");
	CALL_AND_TEST("abcd", 4, buf, 3, 1, "");

	CALL_AND_TEST("abcd", 0, buf, 4, 3, "''");
	CALL_AND_TEST("abcd", 1, buf, 4, 4, "'a'");
	CALL_AND_TEST("abcd", 2, buf, 4, 4, "'a'");
	CALL_AND_TEST("abcd", 3, buf, 4, 4, "'a'");
	CALL_AND_TEST("abcd", 4, buf, 4, 4, "'a'");
	CALL_AND_TEST("abcde", 5, buf, 4, 4, "'a'");
	CALL_AND_TEST("'", 1, buf, 4, 3, "''");
	CALL_AND_TEST("''", 2, buf, 4, 3, "''");
	CALL_AND_TEST("a'", 2, buf, 4, 4, "'a'");
	CALL_AND_TEST("'a", 2, buf, 4, 3, "''");
	CALL_AND_TEST("ab", 2, buf, 4, 4, "'a'");

	CALL_AND_TEST("abcdef", 0, buf, 5, 3, "''");
	CALL_AND_TEST("abcdef", 1, buf, 5, 4, "'a'");
	CALL_AND_TEST("abcdef", 2, buf, 5, 5, "'ab'");
	CALL_AND_TEST("abcdef", 3, buf, 5, 5, "'ab'");
	CALL_AND_TEST("abcdef", 4, buf, 5, 5, "'ab'");
	CALL_AND_TEST("abcdef", 5, buf, 5, 5, "'ab'");
	CALL_AND_TEST("abcdef", 6, buf, 5, 5, "'ab'");
	CALL_AND_TEST("'", 1, buf, 5, 5, "''''");
	CALL_AND_TEST("''", 2, buf, 5, 5, "''''");
	CALL_AND_TEST("a'", 2, buf, 5, 4, "'a'");
	CALL_AND_TEST("'a", 2, buf, 5, 5, "''''");
	CALL_AND_TEST("ab", 2, buf, 5, 5, "'ab'");
	CALL_AND_TEST("abc", 3, buf, 5, 5, "'ab'");

	CALL_AND_TEST("ab", 2, buf, 6, 5, "'ab'");

	CALL_AND_TEST("a'b'c", 5, buf, 32, 10, "'a''b''c'");
	CALL_AND_TEST("a'b'c'", 6, buf, 32, 12, "'a''b''c'''");
}

#endif /* UNIV_COMPILE_TEST_FUNCS */
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
609
#endif /* !UNIV_HOTBACKUP */