~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/ut/ut0mem.cc

  • Committer: Monty Taylor
  • Date: 2008-11-16 05:36:13 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116053613-bld4rqxhlkb49c02
Split out cache_row and type_holder.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/********************************************************************//**
20
 
@file ut/ut0mem.c
21
 
Memory primitives
22
 
 
23
 
Created 5/11/1994 Heikki Tuuri
24
 
*************************************************************************/
25
 
 
26
 
#include "ut0mem.h"
27
 
 
28
 
#ifdef UNIV_NONINL
29
 
#include "ut0mem.ic"
30
 
#endif
31
 
 
32
 
#ifndef UNIV_HOTBACKUP
33
 
# include "os0thread.h"
34
 
# include "srv0srv.h"
35
 
 
36
 
#include <stdlib.h>
37
 
#include <errno.h>
38
 
 
39
 
/** This struct is placed first in every allocated memory block */
40
 
typedef struct ut_mem_block_struct ut_mem_block_t;
41
 
 
42
 
/** The total amount of memory currently allocated from the operating
43
 
system with os_mem_alloc_large() or malloc().  Does not count malloc()
44
 
if srv_use_sys_malloc is set.  Protected by ut_list_mutex. */
45
 
UNIV_INTERN ulint               ut_total_allocated_memory       = 0;
46
 
 
47
 
/** Mutex protecting ut_total_allocated_memory and ut_mem_block_list */
48
 
UNIV_INTERN os_fast_mutex_t     ut_list_mutex;
49
 
 
50
 
/** Dynamically allocated memory block */
51
 
struct ut_mem_block_struct{
52
 
        UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
53
 
                        /*!< mem block list node */
54
 
        ulint   size;   /*!< size of allocated memory */
55
 
        ulint   magic_n;/*!< magic number (UT_MEM_MAGIC_N) */
56
 
};
57
 
 
58
 
/** The value of ut_mem_block_struct::magic_n.  Used in detecting
59
 
memory corruption. */
60
 
#define UT_MEM_MAGIC_N  1601650166
61
 
 
62
 
/** List of all memory blocks allocated from the operating system
63
 
with malloc.  Protected by ut_list_mutex. */
64
 
static UT_LIST_BASE_NODE_T(ut_mem_block_t)   ut_mem_block_list;
65
 
 
66
 
/** Flag: has ut_mem_block_list been initialized? */
67
 
static ibool  ut_mem_block_list_inited = FALSE;
68
 
 
69
 
/** A dummy pointer for generating a null pointer exception in
70
 
ut_malloc_low() */
71
 
static ulint*   ut_mem_null_ptr = NULL;
72
 
 
73
 
/**********************************************************************//**
74
 
Initializes the mem block list at database startup. */
75
 
UNIV_INTERN
76
 
void
77
 
ut_mem_init(void)
78
 
/*=============*/
79
 
{
80
 
        ut_a(!ut_mem_block_list_inited);
81
 
        os_fast_mutex_init(&ut_list_mutex);
82
 
        UT_LIST_INIT(ut_mem_block_list);
83
 
        ut_mem_block_list_inited = TRUE;
84
 
}
85
 
#endif /* !UNIV_HOTBACKUP */
86
 
 
87
 
/**********************************************************************//**
88
 
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
89
 
defined and set_to_zero is TRUE.
90
 
@return own: allocated memory */
91
 
UNIV_INTERN
92
 
void*
93
 
ut_malloc_low(
94
 
/*==========*/
95
 
        ulint   n,              /*!< in: number of bytes to allocate */
96
 
        ibool   set_to_zero,    /*!< in: TRUE if allocated memory should be
97
 
                                set to zero if UNIV_SET_MEM_TO_ZERO is
98
 
                                defined */
99
 
        ibool   assert_on_error)/*!< in: if TRUE, we crash mysqld if the
100
 
                                memory cannot be allocated */
101
 
{
102
 
#ifndef UNIV_HOTBACKUP
103
 
        ulint   retry_count;
104
 
        void*   ret;
105
 
 
106
 
        if (UNIV_LIKELY(srv_use_sys_malloc)) {
107
 
                ret = malloc(n);
108
 
                ut_a(ret || !assert_on_error);
109
 
 
110
 
#ifdef UNIV_SET_MEM_TO_ZERO
111
 
                if (set_to_zero) {
112
 
                        memset(ret, '\0', n);
113
 
                        UNIV_MEM_ALLOC(ret, n);
114
 
                }
115
 
#endif
116
 
                return(ret);
117
 
        }
118
 
 
119
 
        ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
120
 
        ut_a(ut_mem_block_list_inited);
121
 
 
122
 
        retry_count = 0;
123
 
retry:
124
 
        os_fast_mutex_lock(&ut_list_mutex);
125
 
 
126
 
        ret = malloc(n + sizeof(ut_mem_block_t));
127
 
 
128
 
        if (ret == NULL && retry_count < 60) {
129
 
                if (retry_count == 0) {
130
 
                        ut_print_timestamp(stderr);
131
 
 
132
 
                        fprintf(stderr,
133
 
                                "  InnoDB: Error: cannot allocate"
134
 
                                " %lu bytes of\n"
135
 
                                "InnoDB: memory with malloc!"
136
 
                                " Total allocated memory\n"
137
 
                                "InnoDB: by InnoDB %lu bytes."
138
 
                                " Operating system errno: %lu\n"
139
 
                                "InnoDB: Check if you should"
140
 
                                " increase the swap file or\n"
141
 
                                "InnoDB: ulimits of your operating system.\n"
142
 
                                "InnoDB: On FreeBSD check you"
143
 
                                " have compiled the OS with\n"
144
 
                                "InnoDB: a big enough maximum process size.\n"
145
 
                                "InnoDB: Note that in most 32-bit"
146
 
                                " computers the process\n"
147
 
                                "InnoDB: memory space is limited"
148
 
                                " to 2 GB or 4 GB.\n"
149
 
                                "InnoDB: We keep retrying"
150
 
                                " the allocation for 60 seconds...\n",
151
 
                                (ulong) n, (ulong) ut_total_allocated_memory,
152
 
#ifdef __WIN__
153
 
                                (ulong) GetLastError()
154
 
#else
155
 
                                (ulong) errno
156
 
#endif
157
 
                                );
158
 
                }
159
 
 
160
 
                os_fast_mutex_unlock(&ut_list_mutex);
161
 
 
162
 
                /* Sleep for a second and retry the allocation; maybe this is
163
 
                just a temporary shortage of memory */
164
 
 
165
 
                os_thread_sleep(1000000);
166
 
 
167
 
                retry_count++;
168
 
 
169
 
                goto retry;
170
 
        }
171
 
 
172
 
        if (ret == NULL) {
173
 
                /* Flush stderr to make more probable that the error
174
 
                message gets in the error file before we generate a seg
175
 
                fault */
176
 
 
177
 
                fflush(stderr);
178
 
 
179
 
                os_fast_mutex_unlock(&ut_list_mutex);
180
 
 
181
 
                /* Make an intentional seg fault so that we get a stack
182
 
                trace */
183
 
                if (assert_on_error) {
184
 
                        ut_print_timestamp(stderr);
185
 
 
186
 
                        fprintf(stderr,
187
 
                                "  InnoDB: We now intentionally"
188
 
                                " generate a seg fault so that\n"
189
 
                                "InnoDB: on Linux we get a stack trace.\n");
190
 
 
191
 
                        if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
192
 
                } else {
193
 
                        return(NULL);
194
 
                }
195
 
        }
196
 
 
197
 
        if (set_to_zero) {
198
 
#ifdef UNIV_SET_MEM_TO_ZERO
199
 
                memset(ret, '\0', n + sizeof(ut_mem_block_t));
200
 
#endif
201
 
        }
202
 
 
203
 
        UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
204
 
 
205
 
        ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
206
 
        ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
207
 
 
208
 
        ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
209
 
 
210
 
        UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
211
 
                          ((ut_mem_block_t*)ret));
212
 
        os_fast_mutex_unlock(&ut_list_mutex);
213
 
 
214
 
        return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
215
 
#else /* !UNIV_HOTBACKUP */
216
 
        void*   ret = malloc(n);
217
 
        ut_a(ret || !assert_on_error);
218
 
 
219
 
# ifdef UNIV_SET_MEM_TO_ZERO
220
 
        if (set_to_zero) {
221
 
                memset(ret, '\0', n);
222
 
        }
223
 
# endif
224
 
        return(ret);
225
 
#endif /* !UNIV_HOTBACKUP */
226
 
}
227
 
 
228
 
/**********************************************************************//**
229
 
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
230
 
defined.
231
 
@return own: allocated memory */
232
 
extern "C"
233
 
UNIV_INTERN
234
 
void*
235
 
ut_malloc(
236
 
/*======*/
237
 
        ulint   n)      /*!< in: number of bytes to allocate */
238
 
{
239
 
#ifndef UNIV_HOTBACKUP
240
 
        return(ut_malloc_low(n, TRUE, TRUE));
241
 
#else /* !UNIV_HOTBACKUP */
242
 
        return(malloc(n));
243
 
#endif /* !UNIV_HOTBACKUP */
244
 
}
245
 
 
246
 
#ifndef UNIV_HOTBACKUP
247
 
/**********************************************************************//**
248
 
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
249
 
out. It cannot be used if we want to return an error message. Prints to
250
 
stderr a message if fails.
251
 
@return TRUE if succeeded */
252
 
UNIV_INTERN
253
 
ibool
254
 
ut_test_malloc(
255
 
/*===========*/
256
 
        ulint   n)      /*!< in: try to allocate this many bytes */
257
 
{
258
 
        void*   ret;
259
 
 
260
 
        ret = malloc(n);
261
 
 
262
 
        if (ret == NULL) {
263
 
                ut_print_timestamp(stderr);
264
 
                fprintf(stderr,
265
 
                        "  InnoDB: Error: cannot allocate"
266
 
                        " %lu bytes of memory for\n"
267
 
                        "InnoDB: a BLOB with malloc! Total allocated memory\n"
268
 
                        "InnoDB: by InnoDB %lu bytes."
269
 
                        " Operating system errno: %d\n"
270
 
                        "InnoDB: Check if you should increase"
271
 
                        " the swap file or\n"
272
 
                        "InnoDB: ulimits of your operating system.\n"
273
 
                        "InnoDB: On FreeBSD check you have"
274
 
                        " compiled the OS with\n"
275
 
                        "InnoDB: a big enough maximum process size.\n",
276
 
                        (ulong) n,
277
 
                        (ulong) ut_total_allocated_memory,
278
 
                        (int) errno);
279
 
                return(FALSE);
280
 
        }
281
 
 
282
 
        free(ret);
283
 
 
284
 
        return(TRUE);
285
 
}
286
 
#endif /* !UNIV_HOTBACKUP */
287
 
 
288
 
/**********************************************************************//**
289
 
Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is
290
 
a nop. */
291
 
extern "C"
292
 
UNIV_INTERN
293
 
void
294
 
ut_free(
295
 
/*====*/
296
 
        void* ptr)  /*!< in, own: memory block, can be NULL */
297
 
{
298
 
#ifndef UNIV_HOTBACKUP
299
 
        ut_mem_block_t* block;
300
 
 
301
 
        if (ptr == NULL) {
302
 
                return;
303
 
        } else if (UNIV_LIKELY(srv_use_sys_malloc)) {
304
 
                free(ptr);
305
 
                return;
306
 
        }
307
 
 
308
 
        block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
309
 
 
310
 
        os_fast_mutex_lock(&ut_list_mutex);
311
 
 
312
 
        ut_a(block->magic_n == UT_MEM_MAGIC_N);
313
 
        ut_a(ut_total_allocated_memory >= block->size);
314
 
 
315
 
        ut_total_allocated_memory -= block->size;
316
 
 
317
 
        UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
318
 
        free(block);
319
 
 
320
 
        os_fast_mutex_unlock(&ut_list_mutex);
321
 
#else /* !UNIV_HOTBACKUP */
322
 
        free(ptr);
323
 
#endif /* !UNIV_HOTBACKUP */
324
 
}
325
 
 
326
 
#ifndef UNIV_HOTBACKUP
327
 
/**********************************************************************//**
328
 
Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
329
 
use this function because the allocation functions in mem0mem.h are the
330
 
recommended ones in InnoDB.
331
 
 
332
 
man realloc in Linux, 2004:
333
 
 
334
 
       realloc()  changes the size of the memory block pointed to
335
 
       by ptr to size bytes.  The contents will be  unchanged  to
336
 
       the minimum of the old and new sizes; newly allocated mem-
337
 
       ory will be uninitialized.  If ptr is NULL,  the  call  is
338
 
       equivalent  to malloc(size); if size is equal to zero, the
339
 
       call is equivalent to free(ptr).  Unless ptr is  NULL,  it
340
 
       must  have  been  returned by an earlier call to malloc(),
341
 
       calloc() or realloc().
342
 
 
343
 
RETURN VALUE
344
 
       realloc() returns a pointer to the newly allocated memory,
345
 
       which is suitably aligned for any kind of variable and may
346
 
       be different from ptr, or NULL if the  request  fails.  If
347
 
       size  was equal to 0, either NULL or a pointer suitable to
348
 
       be passed to free() is returned.  If realloc()  fails  the
349
 
       original  block  is  left  untouched  - it is not freed or
350
 
       moved.
351
 
@return own: pointer to new mem block or NULL */
352
 
extern "C"
353
 
UNIV_INTERN
354
 
void*
355
 
ut_realloc(
356
 
/*=======*/
357
 
        void*   ptr,    /*!< in: pointer to old block or NULL */
358
 
        ulint   size)   /*!< in: desired size */
359
 
{
360
 
        ut_mem_block_t* block;
361
 
        ulint           old_size;
362
 
        ulint           min_size;
363
 
        void*           new_ptr;
364
 
 
365
 
        if (UNIV_LIKELY(srv_use_sys_malloc)) {
366
 
                return(realloc(ptr, size));
367
 
        }
368
 
 
369
 
        if (ptr == NULL) {
370
 
 
371
 
                return(ut_malloc(size));
372
 
        }
373
 
 
374
 
        if (size == 0) {
375
 
                ut_free(ptr);
376
 
 
377
 
                return(NULL);
378
 
        }
379
 
 
380
 
        block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
381
 
 
382
 
        ut_a(block->magic_n == UT_MEM_MAGIC_N);
383
 
 
384
 
        old_size = block->size - sizeof(ut_mem_block_t);
385
 
 
386
 
        if (size < old_size) {
387
 
                min_size = size;
388
 
        } else {
389
 
                min_size = old_size;
390
 
        }
391
 
 
392
 
        new_ptr = ut_malloc(size);
393
 
 
394
 
        if (new_ptr == NULL) {
395
 
 
396
 
                return(NULL);
397
 
        }
398
 
 
399
 
        /* Copy the old data from ptr */
400
 
        ut_memcpy(new_ptr, ptr, min_size);
401
 
 
402
 
        ut_free(ptr);
403
 
 
404
 
        return(new_ptr);
405
 
}
406
 
 
407
 
/**********************************************************************//**
408
 
Frees in shutdown all allocated memory not freed yet. */
409
 
UNIV_INTERN
410
 
void
411
 
ut_free_all_mem(void)
412
 
/*=================*/
413
 
{
414
 
        ut_mem_block_t* block;
415
 
 
416
 
        ut_a(ut_mem_block_list_inited);
417
 
        ut_mem_block_list_inited = FALSE;
418
 
        os_fast_mutex_free(&ut_list_mutex);
419
 
 
420
 
        while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
421
 
 
422
 
                ut_a(block->magic_n == UT_MEM_MAGIC_N);
423
 
                ut_a(ut_total_allocated_memory >= block->size);
424
 
 
425
 
                ut_total_allocated_memory -= block->size;
426
 
 
427
 
                UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
428
 
                free(block);
429
 
        }
430
 
 
431
 
        if (ut_total_allocated_memory != 0) {
432
 
                fprintf(stderr,
433
 
                        "InnoDB: Warning: after shutdown"
434
 
                        " total allocated memory is %lu\n",
435
 
                        (ulong) ut_total_allocated_memory);
436
 
        }
437
 
 
438
 
        ut_mem_block_list_inited = FALSE;
439
 
}
440
 
#endif /* !UNIV_HOTBACKUP */
441
 
 
442
 
/**********************************************************************//**
443
 
Copies up to size - 1 characters from the NUL-terminated string src to
444
 
dst, NUL-terminating the result. Returns strlen(src), so truncation
445
 
occurred if the return value >= size.
446
 
@return strlen(src) */
447
 
UNIV_INTERN
448
 
ulint
449
 
ut_strlcpy(
450
 
/*=======*/
451
 
        char*           dst,    /*!< in: destination buffer */
452
 
        const char*     src,    /*!< in: source buffer */
453
 
        ulint           size)   /*!< in: size of destination buffer */
454
 
{
455
 
        ulint   src_size = strlen(src);
456
 
 
457
 
        if (size != 0) {
458
 
                ulint   n = ut_min(src_size, size - 1);
459
 
 
460
 
                memcpy(dst, src, n);
461
 
                dst[n] = '\0';
462
 
        }
463
 
 
464
 
        return(src_size);
465
 
}
466
 
 
467
 
/**********************************************************************//**
468
 
Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
469
 
(size - 1) bytes of src, not the first.
470
 
@return strlen(src) */
471
 
UNIV_INTERN
472
 
ulint
473
 
ut_strlcpy_rev(
474
 
/*===========*/
475
 
        char*           dst,    /*!< in: destination buffer */
476
 
        const char*     src,    /*!< in: source buffer */
477
 
        ulint           size)   /*!< in: size of destination buffer */
478
 
{
479
 
        ulint   src_size = strlen(src);
480
 
 
481
 
        if (size != 0) {
482
 
                ulint   n = ut_min(src_size, size - 1);
483
 
 
484
 
                memcpy(dst, src + src_size - n, n + 1);
485
 
        }
486
 
 
487
 
        return(src_size);
488
 
}
489
 
 
490
 
/**********************************************************************//**
491
 
Make a quoted copy of a NUL-terminated string.  Leading and trailing
492
 
quotes will not be included; only embedded quotes will be escaped.
493
 
See also ut_strlenq() and ut_memcpyq().
494
 
@return pointer to end of dest */
495
 
UNIV_INTERN
496
 
char*
497
 
ut_strcpyq(
498
 
/*=======*/
499
 
        char*           dest,   /*!< in: output buffer */
500
 
        char            q,      /*!< in: the quote character */
501
 
        const char*     src)    /*!< in: null-terminated string */
502
 
{
503
 
        while (*src) {
504
 
                if ((*dest++ = *src++) == q) {
505
 
                        *dest++ = q;
506
 
                }
507
 
        }
508
 
 
509
 
        return(dest);
510
 
}
511
 
 
512
 
/**********************************************************************//**
513
 
Make a quoted copy of a fixed-length string.  Leading and trailing
514
 
quotes will not be included; only embedded quotes will be escaped.
515
 
See also ut_strlenq() and ut_strcpyq().
516
 
@return pointer to end of dest */
517
 
UNIV_INTERN
518
 
char*
519
 
ut_memcpyq(
520
 
/*=======*/
521
 
        char*           dest,   /*!< in: output buffer */
522
 
        char            q,      /*!< in: the quote character */
523
 
        const char*     src,    /*!< in: string to be quoted */
524
 
        ulint           len)    /*!< in: length of src */
525
 
{
526
 
        const char*     srcend = src + len;
527
 
 
528
 
        while (src < srcend) {
529
 
                if ((*dest++ = *src++) == q) {
530
 
                        *dest++ = q;
531
 
                }
532
 
        }
533
 
 
534
 
        return(dest);
535
 
}
536
 
 
537
 
#ifndef UNIV_HOTBACKUP
538
 
/**********************************************************************//**
539
 
Return the number of times s2 occurs in s1. Overlapping instances of s2
540
 
are only counted once.
541
 
@return the number of times s2 occurs in s1 */
542
 
UNIV_INTERN
543
 
ulint
544
 
ut_strcount(
545
 
/*========*/
546
 
        const char*     s1,     /*!< in: string to search in */
547
 
        const char*     s2)     /*!< in: string to search for */
548
 
{
549
 
        ulint   count = 0;
550
 
        ulint   len = strlen(s2);
551
 
 
552
 
        if (len == 0) {
553
 
 
554
 
                return(0);
555
 
        }
556
 
 
557
 
        for (;;) {
558
 
                s1 = strstr(s1, s2);
559
 
 
560
 
                if (!s1) {
561
 
 
562
 
                        break;
563
 
                }
564
 
 
565
 
                count++;
566
 
                s1 += len;
567
 
        }
568
 
 
569
 
        return(count);
570
 
}
571
 
 
572
 
/**********************************************************************//**
573
 
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
574
 
are only replaced once.
575
 
@return own: modified string, must be freed with mem_free() */
576
 
UNIV_INTERN
577
 
char*
578
 
ut_strreplace(
579
 
/*==========*/
580
 
        const char*     str,    /*!< in: string to operate on */
581
 
        const char*     s1,     /*!< in: string to replace */
582
 
        const char*     s2)     /*!< in: string to replace s1 with */
583
 
{
584
 
        char*           new_str;
585
 
        char*           ptr;
586
 
        const char*     str_end;
587
 
        ulint           str_len = strlen(str);
588
 
        ulint           s1_len = strlen(s1);
589
 
        ulint           s2_len = strlen(s2);
590
 
        ulint           count = 0;
591
 
        int             len_delta = (int)s2_len - (int)s1_len;
592
 
 
593
 
        str_end = str + str_len;
594
 
 
595
 
        if (len_delta <= 0) {
596
 
                len_delta = 0;
597
 
        } else {
598
 
                count = ut_strcount(str, s1);
599
 
        }
600
 
 
601
 
        new_str = static_cast<char *>(mem_alloc(str_len + count * len_delta + 1));
602
 
        ptr = new_str;
603
 
 
604
 
        while (str) {
605
 
                const char*     next = strstr(str, s1);
606
 
 
607
 
                if (!next) {
608
 
                        next = str_end;
609
 
                }
610
 
 
611
 
                memcpy(ptr, str, next - str);
612
 
                ptr += next - str;
613
 
 
614
 
                if (next == str_end) {
615
 
 
616
 
                        break;
617
 
                }
618
 
 
619
 
                memcpy(ptr, s2, s2_len);
620
 
                ptr += s2_len;
621
 
 
622
 
                str = next + s1_len;
623
 
        }
624
 
 
625
 
        *ptr = '\0';
626
 
 
627
 
        return(new_str);
628
 
}
629
 
 
630
 
#ifdef UNIV_COMPILE_TEST_FUNCS
631
 
 
632
 
void
633
 
test_ut_str_sql_format()
634
 
{
635
 
        char    buf[128];
636
 
        ulint   ret;
637
 
 
638
 
#define CALL_AND_TEST(str, str_len, buf, buf_size, ret_expected, buf_expected)\
639
 
        do {\
640
 
                ibool   ok = TRUE;\
641
 
                memset(buf, 'x', 10);\
642
 
                buf[10] = '\0';\
643
 
                fprintf(stderr, "TESTING \"%s\", %lu, %lu\n",\
644
 
                        str, (ulint) str_len, (ulint) buf_size);\
645
 
                ret = ut_str_sql_format(str, str_len, buf, buf_size);\
646
 
                if (ret != ret_expected) {\
647
 
                        fprintf(stderr, "expected ret %lu, got %lu\n",\
648
 
                                (ulint) ret_expected, ret);\
649
 
                        ok = FALSE;\
650
 
                }\
651
 
                if (strcmp((char*) buf, buf_expected) != 0) {\
652
 
                        fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
653
 
                                buf_expected, buf);\
654
 
                        ok = FALSE;\
655
 
                }\
656
 
                if (ok) {\
657
 
                        fprintf(stderr, "OK: %lu, \"%s\"\n\n",\
658
 
                                (ulint) ret, buf);\
659
 
                } else {\
660
 
                        return;\
661
 
                }\
662
 
        } while (0)
663
 
 
664
 
        CALL_AND_TEST("abcd", 4, buf, 0, 0, "xxxxxxxxxx");
665
 
 
666
 
        CALL_AND_TEST("abcd", 4, buf, 1, 1, "");
667
 
 
668
 
        CALL_AND_TEST("abcd", 4, buf, 2, 1, "");
669
 
 
670
 
        CALL_AND_TEST("abcd", 0, buf, 3, 3, "''");
671
 
        CALL_AND_TEST("abcd", 1, buf, 3, 1, "");
672
 
        CALL_AND_TEST("abcd", 2, buf, 3, 1, "");
673
 
        CALL_AND_TEST("abcd", 3, buf, 3, 1, "");
674
 
        CALL_AND_TEST("abcd", 4, buf, 3, 1, "");
675
 
 
676
 
        CALL_AND_TEST("abcd", 0, buf, 4, 3, "''");
677
 
        CALL_AND_TEST("abcd", 1, buf, 4, 4, "'a'");
678
 
        CALL_AND_TEST("abcd", 2, buf, 4, 4, "'a'");
679
 
        CALL_AND_TEST("abcd", 3, buf, 4, 4, "'a'");
680
 
        CALL_AND_TEST("abcd", 4, buf, 4, 4, "'a'");
681
 
        CALL_AND_TEST("abcde", 5, buf, 4, 4, "'a'");
682
 
        CALL_AND_TEST("'", 1, buf, 4, 3, "''");
683
 
        CALL_AND_TEST("''", 2, buf, 4, 3, "''");
684
 
        CALL_AND_TEST("a'", 2, buf, 4, 4, "'a'");
685
 
        CALL_AND_TEST("'a", 2, buf, 4, 3, "''");
686
 
        CALL_AND_TEST("ab", 2, buf, 4, 4, "'a'");
687
 
 
688
 
        CALL_AND_TEST("abcdef", 0, buf, 5, 3, "''");
689
 
        CALL_AND_TEST("abcdef", 1, buf, 5, 4, "'a'");
690
 
        CALL_AND_TEST("abcdef", 2, buf, 5, 5, "'ab'");
691
 
        CALL_AND_TEST("abcdef", 3, buf, 5, 5, "'ab'");
692
 
        CALL_AND_TEST("abcdef", 4, buf, 5, 5, "'ab'");
693
 
        CALL_AND_TEST("abcdef", 5, buf, 5, 5, "'ab'");
694
 
        CALL_AND_TEST("abcdef", 6, buf, 5, 5, "'ab'");
695
 
        CALL_AND_TEST("'", 1, buf, 5, 5, "''''");
696
 
        CALL_AND_TEST("''", 2, buf, 5, 5, "''''");
697
 
        CALL_AND_TEST("a'", 2, buf, 5, 4, "'a'");
698
 
        CALL_AND_TEST("'a", 2, buf, 5, 5, "''''");
699
 
        CALL_AND_TEST("ab", 2, buf, 5, 5, "'ab'");
700
 
        CALL_AND_TEST("abc", 3, buf, 5, 5, "'ab'");
701
 
 
702
 
        CALL_AND_TEST("ab", 2, buf, 6, 5, "'ab'");
703
 
 
704
 
        CALL_AND_TEST("a'b'c", 5, buf, 32, 10, "'a''b''c'");
705
 
        CALL_AND_TEST("a'b'c'", 6, buf, 32, 12, "'a''b''c'''");
706
 
}
707
 
 
708
 
#endif /* UNIV_COMPILE_TEST_FUNCS */
709
 
#endif /* !UNIV_HOTBACKUP */