~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

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., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 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
 
                /* Intentional segfault on NetWare causes an abend. Avoid this
184
 
                by graceful exit handling in ut_a(). */
185
 
#if (!defined __NETWARE__)
186
 
                if (assert_on_error) {
187
 
                        ut_print_timestamp(stderr);
188
 
 
189
 
                        fprintf(stderr,
190
 
                                "  InnoDB: We now intentionally"
191
 
                                " generate a seg fault so that\n"
192
 
                                "InnoDB: on Linux we get a stack trace.\n");
193
 
 
194
 
                        if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
195
 
                } else {
196
 
                        return(NULL);
197
 
                }
198
 
#else
199
 
                ut_a(0);
200
 
#endif
201
 
        }
202
 
 
203
 
        if (set_to_zero) {
204
 
#ifdef UNIV_SET_MEM_TO_ZERO
205
 
                memset(ret, '\0', n + sizeof(ut_mem_block_t));
206
 
#endif
207
 
        }
208
 
 
209
 
        UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
210
 
 
211
 
        ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
212
 
        ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
213
 
 
214
 
        ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
215
 
 
216
 
        UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
217
 
                          ((ut_mem_block_t*)ret));
218
 
        os_fast_mutex_unlock(&ut_list_mutex);
219
 
 
220
 
        return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
221
 
#else /* !UNIV_HOTBACKUP */
222
 
        void*   ret = malloc(n);
223
 
        ut_a(ret || !assert_on_error);
224
 
 
225
 
# ifdef UNIV_SET_MEM_TO_ZERO
226
 
        if (set_to_zero) {
227
 
                memset(ret, '\0', n);
228
 
        }
229
 
# endif
230
 
        return(ret);
231
 
#endif /* !UNIV_HOTBACKUP */
232
 
}
233
 
 
234
 
/**********************************************************************//**
235
 
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
236
 
defined.
237
 
@return own: allocated memory */
238
 
UNIV_INTERN
239
 
void*
240
 
ut_malloc(
241
 
/*======*/
242
 
        ulint   n)      /*!< in: number of bytes to allocate */
243
 
{
244
 
#ifndef UNIV_HOTBACKUP
245
 
        return(ut_malloc_low(n, TRUE, TRUE));
246
 
#else /* !UNIV_HOTBACKUP */
247
 
        return(malloc(n));
248
 
#endif /* !UNIV_HOTBACKUP */
249
 
}
250
 
 
251
 
#ifndef UNIV_HOTBACKUP
252
 
/**********************************************************************//**
253
 
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
254
 
out. It cannot be used if we want to return an error message. Prints to
255
 
stderr a message if fails.
256
 
@return TRUE if succeeded */
257
 
UNIV_INTERN
258
 
ibool
259
 
ut_test_malloc(
260
 
/*===========*/
261
 
        ulint   n)      /*!< in: try to allocate this many bytes */
262
 
{
263
 
        void*   ret;
264
 
 
265
 
        ret = malloc(n);
266
 
 
267
 
        if (ret == NULL) {
268
 
                ut_print_timestamp(stderr);
269
 
                fprintf(stderr,
270
 
                        "  InnoDB: Error: cannot allocate"
271
 
                        " %lu bytes of memory for\n"
272
 
                        "InnoDB: a BLOB with malloc! Total allocated memory\n"
273
 
                        "InnoDB: by InnoDB %lu bytes."
274
 
                        " Operating system errno: %d\n"
275
 
                        "InnoDB: Check if you should increase"
276
 
                        " the swap file or\n"
277
 
                        "InnoDB: ulimits of your operating system.\n"
278
 
                        "InnoDB: On FreeBSD check you have"
279
 
                        " compiled the OS with\n"
280
 
                        "InnoDB: a big enough maximum process size.\n",
281
 
                        (ulong) n,
282
 
                        (ulong) ut_total_allocated_memory,
283
 
                        (int) errno);
284
 
                return(FALSE);
285
 
        }
286
 
 
287
 
        free(ret);
288
 
 
289
 
        return(TRUE);
290
 
}
291
 
#endif /* !UNIV_HOTBACKUP */
292
 
 
293
 
/**********************************************************************//**
294
 
Frees a memory block allocated with ut_malloc. */
295
 
UNIV_INTERN
296
 
void
297
 
ut_free(
298
 
/*====*/
299
 
        void* ptr)  /*!< in, own: memory block */
300
 
{
301
 
#ifndef UNIV_HOTBACKUP
302
 
        ut_mem_block_t* block;
303
 
 
304
 
        if (UNIV_LIKELY(srv_use_sys_malloc)) {
305
 
                free(ptr);
306
 
                return;
307
 
        }
308
 
 
309
 
        block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
310
 
 
311
 
        os_fast_mutex_lock(&ut_list_mutex);
312
 
 
313
 
        ut_a(block->magic_n == UT_MEM_MAGIC_N);
314
 
        ut_a(ut_total_allocated_memory >= block->size);
315
 
 
316
 
        ut_total_allocated_memory -= block->size;
317
 
 
318
 
        UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
319
 
        free(block);
320
 
 
321
 
        os_fast_mutex_unlock(&ut_list_mutex);
322
 
#else /* !UNIV_HOTBACKUP */
323
 
        free(ptr);
324
 
#endif /* !UNIV_HOTBACKUP */
325
 
}
326
 
 
327
 
#ifndef UNIV_HOTBACKUP
328
 
/**********************************************************************//**
329
 
Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
330
 
use this function because the allocation functions in mem0mem.h are the
331
 
recommended ones in InnoDB.
332
 
 
333
 
man realloc in Linux, 2004:
334
 
 
335
 
       realloc()  changes the size of the memory block pointed to
336
 
       by ptr to size bytes.  The contents will be  unchanged  to
337
 
       the minimum of the old and new sizes; newly allocated mem-
338
 
       ory will be uninitialized.  If ptr is NULL,  the  call  is
339
 
       equivalent  to malloc(size); if size is equal to zero, the
340
 
       call is equivalent to free(ptr).  Unless ptr is  NULL,  it
341
 
       must  have  been  returned by an earlier call to malloc(),
342
 
       calloc() or realloc().
343
 
 
344
 
RETURN VALUE
345
 
       realloc() returns a pointer to the newly allocated memory,
346
 
       which is suitably aligned for any kind of variable and may
347
 
       be different from ptr, or NULL if the  request  fails.  If
348
 
       size  was equal to 0, either NULL or a pointer suitable to
349
 
       be passed to free() is returned.  If realloc()  fails  the
350
 
       original  block  is  left  untouched  - it is not freed or
351
 
       moved.
352
 
@return own: pointer to new mem block or NULL */
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
 
#endif /* !UNIV_HOTBACKUP */
439
 
 
440
 
/**********************************************************************//**
441
 
Copies up to size - 1 characters from the NUL-terminated string src to
442
 
dst, NUL-terminating the result. Returns strlen(src), so truncation
443
 
occurred if the return value >= size.
444
 
@return strlen(src) */
445
 
UNIV_INTERN
446
 
ulint
447
 
ut_strlcpy(
448
 
/*=======*/
449
 
        char*           dst,    /*!< in: destination buffer */
450
 
        const char*     src,    /*!< in: source buffer */
451
 
        ulint           size)   /*!< in: size of destination buffer */
452
 
{
453
 
        ulint   src_size = strlen(src);
454
 
 
455
 
        if (size != 0) {
456
 
                ulint   n = ut_min(src_size, size - 1);
457
 
 
458
 
                memcpy(dst, src, n);
459
 
                dst[n] = '\0';
460
 
        }
461
 
 
462
 
        return(src_size);
463
 
}
464
 
 
465
 
/**********************************************************************//**
466
 
Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
467
 
(size - 1) bytes of src, not the first.
468
 
@return strlen(src) */
469
 
UNIV_INTERN
470
 
ulint
471
 
ut_strlcpy_rev(
472
 
/*===========*/
473
 
        char*           dst,    /*!< in: destination buffer */
474
 
        const char*     src,    /*!< in: source buffer */
475
 
        ulint           size)   /*!< in: size of destination buffer */
476
 
{
477
 
        ulint   src_size = strlen(src);
478
 
 
479
 
        if (size != 0) {
480
 
                ulint   n = ut_min(src_size, size - 1);
481
 
 
482
 
                memcpy(dst, src + src_size - n, n + 1);
483
 
        }
484
 
 
485
 
        return(src_size);
486
 
}
487
 
 
488
 
/**********************************************************************//**
489
 
Make a quoted copy of a NUL-terminated string.  Leading and trailing
490
 
quotes will not be included; only embedded quotes will be escaped.
491
 
See also ut_strlenq() and ut_memcpyq().
492
 
@return pointer to end of dest */
493
 
UNIV_INTERN
494
 
char*
495
 
ut_strcpyq(
496
 
/*=======*/
497
 
        char*           dest,   /*!< in: output buffer */
498
 
        char            q,      /*!< in: the quote character */
499
 
        const char*     src)    /*!< in: null-terminated string */
500
 
{
501
 
        while (*src) {
502
 
                if ((*dest++ = *src++) == q) {
503
 
                        *dest++ = q;
504
 
                }
505
 
        }
506
 
 
507
 
        return(dest);
508
 
}
509
 
 
510
 
/**********************************************************************//**
511
 
Make a quoted copy of a fixed-length string.  Leading and trailing
512
 
quotes will not be included; only embedded quotes will be escaped.
513
 
See also ut_strlenq() and ut_strcpyq().
514
 
@return pointer to end of dest */
515
 
UNIV_INTERN
516
 
char*
517
 
ut_memcpyq(
518
 
/*=======*/
519
 
        char*           dest,   /*!< in: output buffer */
520
 
        char            q,      /*!< in: the quote character */
521
 
        const char*     src,    /*!< in: string to be quoted */
522
 
        ulint           len)    /*!< in: length of src */
523
 
{
524
 
        const char*     srcend = src + len;
525
 
 
526
 
        while (src < srcend) {
527
 
                if ((*dest++ = *src++) == q) {
528
 
                        *dest++ = q;
529
 
                }
530
 
        }
531
 
 
532
 
        return(dest);
533
 
}
534
 
 
535
 
#ifndef UNIV_HOTBACKUP
536
 
/**********************************************************************//**
537
 
Return the number of times s2 occurs in s1. Overlapping instances of s2
538
 
are only counted once.
539
 
@return the number of times s2 occurs in s1 */
540
 
UNIV_INTERN
541
 
ulint
542
 
ut_strcount(
543
 
/*========*/
544
 
        const char*     s1,     /*!< in: string to search in */
545
 
        const char*     s2)     /*!< in: string to search for */
546
 
{
547
 
        ulint   count = 0;
548
 
        ulint   len = strlen(s2);
549
 
 
550
 
        if (len == 0) {
551
 
 
552
 
                return(0);
553
 
        }
554
 
 
555
 
        for (;;) {
556
 
                s1 = strstr(s1, s2);
557
 
 
558
 
                if (!s1) {
559
 
 
560
 
                        break;
561
 
                }
562
 
 
563
 
                count++;
564
 
                s1 += len;
565
 
        }
566
 
 
567
 
        return(count);
568
 
}
569
 
 
570
 
/**********************************************************************//**
571
 
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
572
 
are only replaced once.
573
 
@return own: modified string, must be freed with mem_free() */
574
 
UNIV_INTERN
575
 
char*
576
 
ut_strreplace(
577
 
/*==========*/
578
 
        const char*     str,    /*!< in: string to operate on */
579
 
        const char*     s1,     /*!< in: string to replace */
580
 
        const char*     s2)     /*!< in: string to replace s1 with */
581
 
{
582
 
        char*           new_str;
583
 
        char*           ptr;
584
 
        const char*     str_end;
585
 
        ulint           str_len = strlen(str);
586
 
        ulint           s1_len = strlen(s1);
587
 
        ulint           s2_len = strlen(s2);
588
 
        ulint           count = 0;
589
 
        int             len_delta = (int)s2_len - (int)s1_len;
590
 
 
591
 
        str_end = str + str_len;
592
 
 
593
 
        if (len_delta <= 0) {
594
 
                len_delta = 0;
595
 
        } else {
596
 
                count = ut_strcount(str, s1);
597
 
        }
598
 
 
599
 
        new_str = mem_alloc(str_len + count * len_delta + 1);
600
 
        ptr = new_str;
601
 
 
602
 
        while (str) {
603
 
                const char*     next = strstr(str, s1);
604
 
 
605
 
                if (!next) {
606
 
                        next = str_end;
607
 
                }
608
 
 
609
 
                memcpy(ptr, str, next - str);
610
 
                ptr += next - str;
611
 
 
612
 
                if (next == str_end) {
613
 
 
614
 
                        break;
615
 
                }
616
 
 
617
 
                memcpy(ptr, s2, s2_len);
618
 
                ptr += s2_len;
619
 
 
620
 
                str = next + s1_len;
621
 
        }
622
 
 
623
 
        *ptr = '\0';
624
 
 
625
 
        return(new_str);
626
 
}
627
 
 
628
 
#ifdef UNIV_COMPILE_TEST_FUNCS
629
 
 
630
 
void
631
 
test_ut_str_sql_format()
632
 
{
633
 
        char    buf[128];
634
 
        ulint   ret;
635
 
 
636
 
#define CALL_AND_TEST(str, str_len, buf, buf_size, ret_expected, buf_expected)\
637
 
        do {\
638
 
                ibool   ok = TRUE;\
639
 
                memset(buf, 'x', 10);\
640
 
                buf[10] = '\0';\
641
 
                fprintf(stderr, "TESTING \"%s\", %lu, %lu\n",\
642
 
                        str, (ulint) str_len, (ulint) buf_size);\
643
 
                ret = ut_str_sql_format(str, str_len, buf, buf_size);\
644
 
                if (ret != ret_expected) {\
645
 
                        fprintf(stderr, "expected ret %lu, got %lu\n",\
646
 
                                (ulint) ret_expected, ret);\
647
 
                        ok = FALSE;\
648
 
                }\
649
 
                if (strcmp((char*) buf, buf_expected) != 0) {\
650
 
                        fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
651
 
                                buf_expected, buf);\
652
 
                        ok = FALSE;\
653
 
                }\
654
 
                if (ok) {\
655
 
                        fprintf(stderr, "OK: %lu, \"%s\"\n\n",\
656
 
                                (ulint) ret, buf);\
657
 
                } else {\
658
 
                        return;\
659
 
                }\
660
 
        } while (0)
661
 
 
662
 
        CALL_AND_TEST("abcd", 4, buf, 0, 0, "xxxxxxxxxx");
663
 
 
664
 
        CALL_AND_TEST("abcd", 4, buf, 1, 1, "");
665
 
 
666
 
        CALL_AND_TEST("abcd", 4, buf, 2, 1, "");
667
 
 
668
 
        CALL_AND_TEST("abcd", 0, buf, 3, 3, "''");
669
 
        CALL_AND_TEST("abcd", 1, buf, 3, 1, "");
670
 
        CALL_AND_TEST("abcd", 2, buf, 3, 1, "");
671
 
        CALL_AND_TEST("abcd", 3, buf, 3, 1, "");
672
 
        CALL_AND_TEST("abcd", 4, buf, 3, 1, "");
673
 
 
674
 
        CALL_AND_TEST("abcd", 0, buf, 4, 3, "''");
675
 
        CALL_AND_TEST("abcd", 1, buf, 4, 4, "'a'");
676
 
        CALL_AND_TEST("abcd", 2, buf, 4, 4, "'a'");
677
 
        CALL_AND_TEST("abcd", 3, buf, 4, 4, "'a'");
678
 
        CALL_AND_TEST("abcd", 4, buf, 4, 4, "'a'");
679
 
        CALL_AND_TEST("abcde", 5, buf, 4, 4, "'a'");
680
 
        CALL_AND_TEST("'", 1, buf, 4, 3, "''");
681
 
        CALL_AND_TEST("''", 2, buf, 4, 3, "''");
682
 
        CALL_AND_TEST("a'", 2, buf, 4, 4, "'a'");
683
 
        CALL_AND_TEST("'a", 2, buf, 4, 3, "''");
684
 
        CALL_AND_TEST("ab", 2, buf, 4, 4, "'a'");
685
 
 
686
 
        CALL_AND_TEST("abcdef", 0, buf, 5, 3, "''");
687
 
        CALL_AND_TEST("abcdef", 1, buf, 5, 4, "'a'");
688
 
        CALL_AND_TEST("abcdef", 2, buf, 5, 5, "'ab'");
689
 
        CALL_AND_TEST("abcdef", 3, buf, 5, 5, "'ab'");
690
 
        CALL_AND_TEST("abcdef", 4, buf, 5, 5, "'ab'");
691
 
        CALL_AND_TEST("abcdef", 5, buf, 5, 5, "'ab'");
692
 
        CALL_AND_TEST("abcdef", 6, buf, 5, 5, "'ab'");
693
 
        CALL_AND_TEST("'", 1, buf, 5, 5, "''''");
694
 
        CALL_AND_TEST("''", 2, buf, 5, 5, "''''");
695
 
        CALL_AND_TEST("a'", 2, buf, 5, 4, "'a'");
696
 
        CALL_AND_TEST("'a", 2, buf, 5, 5, "''''");
697
 
        CALL_AND_TEST("ab", 2, buf, 5, 5, "'ab'");
698
 
        CALL_AND_TEST("abc", 3, buf, 5, 5, "'ab'");
699
 
 
700
 
        CALL_AND_TEST("ab", 2, buf, 6, 5, "'ab'");
701
 
 
702
 
        CALL_AND_TEST("a'b'c", 5, buf, 32, 10, "'a''b''c'");
703
 
        CALL_AND_TEST("a'b'c'", 6, buf, 32, 12, "'a''b''c'''");
704
 
}
705
 
 
706
 
#endif /* UNIV_COMPILE_TEST_FUNCS */
707
 
#endif /* !UNIV_HOTBACKUP */