Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_debug.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | PHP Version 5                                                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 2006-2012 The PHP Group                                |
        !             6:   +----------------------------------------------------------------------+
        !             7:   | This source file is subject to version 3.01 of the PHP license,      |
        !             8:   | that is bundled with this package in the file LICENSE, and is        |
        !             9:   | available through the world-wide-web at the following url:           |
        !            10:   | http://www.php.net/license/3_01.txt                                  |
        !            11:   | If you did not receive a copy of the PHP license and are unable to   |
        !            12:   | obtain it through the world-wide-web, please send a note to          |
        !            13:   | license@php.net so we can mail you a copy immediately.               |
        !            14:   +----------------------------------------------------------------------+
        !            15:   | Authors: Georg Richter <georg@mysql.com>                             |
        !            16:   |          Andrey Hristov <andrey@mysql.com>                           |
        !            17:   |          Ulf Wendel <uwendel@mysql.com>                              |
        !            18:   +----------------------------------------------------------------------+
        !            19: */
        !            20: 
        !            21: /* $Id: mysqlnd_debug.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            22: 
        !            23: #include "php.h"
        !            24: #include "mysqlnd.h"
        !            25: #include "mysqlnd_priv.h"
        !            26: #include "mysqlnd_debug.h"
        !            27: #include "mysqlnd_wireprotocol.h"
        !            28: #include "mysqlnd_statistics.h"
        !            29: #include "zend_builtin_functions.h"
        !            30: 
        !            31: static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
        !            32: 
        !            33: #ifdef ZTS 
        !            34: #define MYSQLND_ZTS(self) TSRMLS_D = (self)->TSRMLS_C
        !            35: #else
        !            36: #define MYSQLND_ZTS(self)
        !            37: #endif
        !            38: 
        !            39: static const char mysqlnd_emalloc_name[]       = "_mysqlnd_emalloc";
        !            40: static const char mysqlnd_pemalloc_name[]      = "_mysqlnd_pemalloc";
        !            41: static const char mysqlnd_ecalloc_name[]       = "_mysqlnd_ecalloc";
        !            42: static const char mysqlnd_pecalloc_name[]      = "_mysqlnd_pecalloc";
        !            43: static const char mysqlnd_erealloc_name[]      = "_mysqlnd_erealloc";
        !            44: static const char mysqlnd_perealloc_name[]     = "_mysqlnd_perealloc";
        !            45: static const char mysqlnd_efree_name[]         = "_mysqlnd_efree";
        !            46: static const char mysqlnd_pefree_name[]                = "_mysqlnd_pefree";
        !            47: static const char mysqlnd_malloc_name[]                = "_mysqlnd_malloc";
        !            48: static const char mysqlnd_calloc_name[]                = "_mysqlnd_calloc";
        !            49: static const char mysqlnd_realloc_name[]       = "_mysqlnd_realloc";
        !            50: static const char mysqlnd_free_name[]          = "_mysqlnd_free";
        !            51: static const char mysqlnd_pestrndup_name[]     = "_mysqlnd_pestrndup";
        !            52: static const char mysqlnd_pestrdup_name[]      = "_mysqlnd_pestrdup";
        !            53: 
        !            54: const char * mysqlnd_debug_std_no_trace_funcs[] =
        !            55: {
        !            56:        mysqlnd_emalloc_name,
        !            57:        mysqlnd_ecalloc_name,
        !            58:        mysqlnd_efree_name,
        !            59:        mysqlnd_erealloc_name,
        !            60:        mysqlnd_pemalloc_name,
        !            61:        mysqlnd_pecalloc_name,
        !            62:        mysqlnd_pefree_name,
        !            63:        mysqlnd_perealloc_name,
        !            64:        mysqlnd_malloc_name,
        !            65:        mysqlnd_calloc_name,
        !            66:        mysqlnd_realloc_name,
        !            67:        mysqlnd_free_name,
        !            68:        mysqlnd_pestrndup_name,
        !            69:        mysqlnd_read_header_name,
        !            70:        mysqlnd_read_body_name,
        !            71:        NULL /* must be always last */
        !            72: };
        !            73: 
        !            74: 
        !            75: /* {{{ mysqlnd_debug::open */
        !            76: static enum_func_status
        !            77: MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen)
        !            78: {
        !            79:        MYSQLND_ZTS(self);
        !            80: 
        !            81:        if (!self->file_name) {
        !            82:                return FAIL;
        !            83:        }
        !            84: 
        !            85:        self->stream = php_stream_open_wrapper(self->file_name,
        !            86:                                                                                   reopen == TRUE || self->flags & MYSQLND_DEBUG_APPEND? "ab":"wb",
        !            87:                                                                                   REPORT_ERRORS, NULL);
        !            88:        return self->stream? PASS:FAIL;
        !            89: }
        !            90: /* }}} */
        !            91: 
        !            92: 
        !            93: /* {{{ mysqlnd_debug::log */
        !            94: static enum_func_status
        !            95: MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * self,
        !            96:                                                                   unsigned int line, const char * const file,
        !            97:                                                                   unsigned int level, const char * type, const char * message)
        !            98: {
        !            99:        char pipe_buffer[512];
        !           100:        enum_func_status ret;
        !           101:        int i;
        !           102:        char * message_line;
        !           103:        unsigned int message_line_len;
        !           104:        unsigned int flags = self->flags;
        !           105:        char pid_buffer[10], time_buffer[30], file_buffer[200],
        !           106:                 line_buffer[6], level_buffer[7];
        !           107:        MYSQLND_ZTS(self);
        !           108: 
        !           109:        if (!self->stream && FAIL == self->m->open(self, FALSE)) {
        !           110:                return FAIL;
        !           111:        }
        !           112: 
        !           113:        if (level == -1) {
        !           114:                level = zend_stack_count(&self->call_stack);
        !           115:        }
        !           116:        i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
        !           117:        pipe_buffer[i*2] = '\0';
        !           118:        for (;i > 0;i--) {
        !           119:                pipe_buffer[i*2 - 1] = ' ';
        !           120:                pipe_buffer[i*2 - 2] = '|';
        !           121:        }
        !           122: 
        !           123: 
        !           124:        if (flags & MYSQLND_DEBUG_DUMP_PID) {
        !           125:                snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
        !           126:                pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
        !           127:        }
        !           128:        if (flags & MYSQLND_DEBUG_DUMP_TIME) {
        !           129:                /* The following from FF's DBUG library, which is in the public domain */
        !           130: #if defined(PHP_WIN32)
        !           131:                /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
        !           132:                in system ticks, 10 ms intervals. See my_getsystime.c for high res */
        !           133:                SYSTEMTIME loc_t;
        !           134:                GetLocalTime(&loc_t);
        !           135:                snprintf(time_buffer, sizeof(time_buffer) - 1,
        !           136:                                 /* "%04d-%02d-%02d " */
        !           137:                                 "%02d:%02d:%02d.%06d ",
        !           138:                                 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
        !           139:                                 loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
        !           140:                time_buffer[sizeof(time_buffer) - 1 ] = '\0';
        !           141: #else
        !           142:                struct timeval tv;
        !           143:                struct tm *tm_p;
        !           144:                if (gettimeofday(&tv, NULL) != -1) {
        !           145:                        if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
        !           146:                                snprintf(time_buffer, sizeof(time_buffer) - 1,
        !           147:                                                 /* "%04d-%02d-%02d " */
        !           148:                                                 "%02d:%02d:%02d.%06d ",
        !           149:                                                 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
        !           150:                                                 tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
        !           151:                                                 (int) (tv.tv_usec));
        !           152:                                time_buffer[sizeof(time_buffer) - 1 ] = '\0';
        !           153:                        }
        !           154:                }
        !           155: #endif
        !           156:        }
        !           157:        if (flags & MYSQLND_DEBUG_DUMP_FILE) {
        !           158:                snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
        !           159:                file_buffer[sizeof(file_buffer) - 1 ] = '\0';
        !           160:        }
        !           161:        if (flags & MYSQLND_DEBUG_DUMP_LINE) {
        !           162:                snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
        !           163:                line_buffer[sizeof(line_buffer) - 1 ] = '\0';
        !           164:        }
        !           165:        if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
        !           166:                snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
        !           167:                level_buffer[sizeof(level_buffer) - 1 ] = '\0';
        !           168:        }
        !           169: 
        !           170:        message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
        !           171:                                                                flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
        !           172:                                                                flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
        !           173:                                                                flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
        !           174:                                                                flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
        !           175:                                                                flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
        !           176:                                                                pipe_buffer, type? type:"", message);
        !           177: 
        !           178:        ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
        !           179:        efree(message_line); /* allocated by spprintf */
        !           180:        if (flags & MYSQLND_DEBUG_FLUSH) {
        !           181:                self->m->close(self);
        !           182:                self->m->open(self, TRUE);
        !           183:        }
        !           184:        return ret;
        !           185: }
        !           186: /* }}} */
        !           187: 
        !           188: 
        !           189: /* {{{ mysqlnd_debug::log_va */
        !           190: static enum_func_status
        !           191: MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self,
        !           192:                                                                          unsigned int line, const char * const file,
        !           193:                                                                          unsigned int level, const char * type,
        !           194:                                                                          const char *format, ...)
        !           195: {
        !           196:        char pipe_buffer[512];
        !           197:        int i;
        !           198:        enum_func_status ret;
        !           199:        char * message_line, *buffer;
        !           200:        unsigned int message_line_len;
        !           201:        va_list args;
        !           202:        unsigned int flags = self->flags;
        !           203:        char pid_buffer[10], time_buffer[30], file_buffer[200],
        !           204:                 line_buffer[6], level_buffer[7];
        !           205:        MYSQLND_ZTS(self);
        !           206: 
        !           207:        if (!self->stream && FAIL == self->m->open(self, FALSE)) {
        !           208:                return FAIL;
        !           209:        }
        !           210: 
        !           211:        if (level == -1) {
        !           212:                level = zend_stack_count(&self->call_stack);
        !           213:        }
        !           214:        i = MIN(level, sizeof(pipe_buffer) / 2  - 1);
        !           215:        pipe_buffer[i*2] = '\0';
        !           216:        for (;i > 0;i--) {
        !           217:                pipe_buffer[i*2 - 1] = ' ';
        !           218:                pipe_buffer[i*2 - 2] = '|';
        !           219:        }
        !           220: 
        !           221: 
        !           222:        if (flags & MYSQLND_DEBUG_DUMP_PID) {
        !           223:                snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
        !           224:                pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
        !           225:        }
        !           226:        if (flags & MYSQLND_DEBUG_DUMP_TIME) {
        !           227:                /* The following from FF's DBUG library, which is in the public domain */
        !           228: #if defined(PHP_WIN32)
        !           229:                /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
        !           230:                in system ticks, 10 ms intervals. See my_getsystime.c for high res */
        !           231:                SYSTEMTIME loc_t;
        !           232:                GetLocalTime(&loc_t);
        !           233:                snprintf(time_buffer, sizeof(time_buffer) - 1,
        !           234:                                 /* "%04d-%02d-%02d " */
        !           235:                                 "%02d:%02d:%02d.%06d ",
        !           236:                                 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
        !           237:                                 loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
        !           238:                time_buffer[sizeof(time_buffer) - 1 ] = '\0';
        !           239: #else
        !           240:                struct timeval tv;
        !           241:                struct tm *tm_p;
        !           242:                if (gettimeofday(&tv, NULL) != -1) {
        !           243:                        if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
        !           244:                                snprintf(time_buffer, sizeof(time_buffer) - 1,
        !           245:                                                 /* "%04d-%02d-%02d " */
        !           246:                                                 "%02d:%02d:%02d.%06d ",
        !           247:                                                 /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
        !           248:                                                 tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
        !           249:                                                 (int) (tv.tv_usec));
        !           250:                                time_buffer[sizeof(time_buffer) - 1 ] = '\0';
        !           251:                        }
        !           252:                }
        !           253: #endif
        !           254:        }
        !           255:        if (flags & MYSQLND_DEBUG_DUMP_FILE) {
        !           256:                snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
        !           257:                file_buffer[sizeof(file_buffer) - 1 ] = '\0';
        !           258:        }
        !           259:        if (flags & MYSQLND_DEBUG_DUMP_LINE) {
        !           260:                snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
        !           261:                line_buffer[sizeof(line_buffer) - 1 ] = '\0';
        !           262:        }
        !           263:        if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
        !           264:                snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
        !           265:                level_buffer[sizeof(level_buffer) - 1 ] = '\0';
        !           266:        }
        !           267: 
        !           268: 
        !           269:        va_start(args, format);
        !           270:        vspprintf(&buffer, 0, format, args);
        !           271:        va_end(args);
        !           272: 
        !           273:        message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
        !           274:                                                                flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
        !           275:                                                                flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
        !           276:                                                                flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
        !           277:                                                                flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
        !           278:                                                                flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
        !           279:                                                                pipe_buffer, type? type:"", buffer);
        !           280:        efree(buffer);
        !           281:        ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
        !           282:        efree(message_line); /* allocated by spprintf */
        !           283: 
        !           284:        if (flags & MYSQLND_DEBUG_FLUSH) {
        !           285:                self->m->close(self);
        !           286:                self->m->open(self, TRUE);
        !           287:        }
        !           288:        return ret;
        !           289: }
        !           290: /* }}} */
        !           291: 
        !           292: 
        !           293: /* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */
        !           294: /* {{{ mysqlnd_debug::func_enter */
        !           295: static zend_bool
        !           296: MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self,
        !           297:                                                                                  unsigned int line, const char * const file,
        !           298:                                                                                  const char * const func_name, unsigned int func_name_len)
        !           299: {
        !           300:        if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
        !           301:                return FALSE;
        !           302:        }
        !           303:        if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
        !           304:                return FALSE;
        !           305:        }
        !           306: 
        !           307:        if ((self->flags & MYSQLND_DEBUG_TRACE_MEMORY_CALLS) == 0 && self->skip_functions) {
        !           308:                const char ** p = self->skip_functions;
        !           309:                while (*p) {
        !           310:                        if (*p == func_name) {
        !           311:                                zend_stack_push(&self->call_stack, "", sizeof(""));
        !           312: #ifndef MYSQLND_PROFILING_DISABLED
        !           313:                                if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
        !           314:                                        uint64_t some_time = 0;
        !           315:                                        zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
        !           316:                                }
        !           317: #endif
        !           318:                                return FALSE;
        !           319:                        }
        !           320:                        p++;
        !           321:                }
        !           322:        }
        !           323: 
        !           324:        zend_stack_push(&self->call_stack, func_name, func_name_len + 1);
        !           325: #ifndef MYSQLND_PROFILING_DISABLED
        !           326:        if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) {
        !           327:                uint64_t some_time = 0;
        !           328:                zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time));
        !           329:        }
        !           330: #endif
        !           331: 
        !           332:        if (zend_hash_num_elements(&self->not_filtered_functions) &&
        !           333:                0 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
        !           334:        {
        !           335:                return FALSE;
        !           336:        }
        !           337: 
        !           338:        self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, ">%s", func_name);
        !           339:        return TRUE;
        !           340: }
        !           341: /* }}} */
        !           342: 
        !           343: #ifndef MYSQLND_PROFILING_DISABLED
        !           344: struct st_mysqlnd_dbg_function_profile {
        !           345:        uint64_t calls;
        !           346:        uint64_t min_own;
        !           347:        uint64_t max_own;
        !           348:        uint64_t avg_own;
        !           349:        uint64_t own_underporm_calls;
        !           350:        uint64_t min_in_calls;
        !           351:        uint64_t max_in_calls;
        !           352:        uint64_t avg_in_calls;
        !           353:        uint64_t in_calls_underporm_calls;
        !           354:        uint64_t min_total;
        !           355:        uint64_t max_total;
        !           356:        uint64_t avg_total;     
        !           357:        uint64_t total_underporm_calls;
        !           358: };
        !           359: #define PROFILE_UNDERPERFORM_THRESHOLD 10
        !           360: #endif
        !           361: 
        !           362: /* {{{ mysqlnd_debug::func_leave */
        !           363: static enum_func_status
        !           364: MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time)
        !           365: {
        !           366:        char *func_name;
        !           367:        uint64_t * parent_non_own_time_ptr = NULL, * mine_non_own_time_ptr = NULL;
        !           368:        uint64_t mine_non_own_time = 0;
        !           369:        zend_bool profile_calls = self->flags & MYSQLND_DEBUG_PROFILE_CALLS? TRUE:FALSE;
        !           370: 
        !           371:        if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
        !           372:                return PASS;
        !           373:        }
        !           374:        if ((uint) zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
        !           375:                return PASS;
        !           376:        }
        !           377: 
        !           378:        zend_stack_top(&self->call_stack, (void **)&func_name);
        !           379: 
        !           380: #ifndef MYSQLND_PROFILING_DISABLED
        !           381:        if (profile_calls) {
        !           382:                zend_stack_top(&self->call_time_stack, (void **)&mine_non_own_time_ptr);
        !           383:                mine_non_own_time = *mine_non_own_time_ptr;
        !           384:                zend_stack_del_top(&self->call_time_stack); /* callee - removing ourselves */
        !           385:        }
        !           386: #endif
        !           387: 
        !           388:        if (func_name[0] == '\0') {
        !           389:                ; /* don't log that function */
        !           390:        } else if (!zend_hash_num_elements(&self->not_filtered_functions) ||
        !           391:                           1 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
        !           392:        {
        !           393: #ifndef MYSQLND_PROFILING_DISABLED
        !           394:                if (FALSE == profile_calls) {
        !           395: #endif
        !           396:                        self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name);
        !           397: 
        !           398: #ifndef MYSQLND_PROFILING_DISABLED
        !           399:                } else {
        !           400:                        struct st_mysqlnd_dbg_function_profile f_profile_stack = {0};
        !           401:                        struct st_mysqlnd_dbg_function_profile * f_profile = NULL;
        !           402:                        uint64_t own_time = call_time - mine_non_own_time;
        !           403:                        uint func_name_len = strlen(func_name);
        !           404: 
        !           405:                        self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s (total=%u own=%u in_calls=%u)",
        !           406:                                                func_name, (unsigned int) call_time, (unsigned int) own_time, (unsigned int) mine_non_own_time
        !           407:                                        );
        !           408: 
        !           409:                        if (SUCCESS == zend_hash_find(&self->function_profiles, func_name, func_name_len + 1, (void **) &f_profile)) {
        !           410:                                /* found */
        !           411:                                        if (f_profile) {
        !           412:                                        if (mine_non_own_time < f_profile->min_in_calls) {
        !           413:                                                f_profile->min_in_calls = mine_non_own_time;
        !           414:                                        } else if (mine_non_own_time > f_profile->max_in_calls) {
        !           415:                                                f_profile->max_in_calls = mine_non_own_time;
        !           416:                                        }
        !           417:                                        f_profile->avg_in_calls = (f_profile->avg_in_calls * f_profile->calls + mine_non_own_time) / (f_profile->calls + 1);
        !           418: 
        !           419:                                        if (own_time < f_profile->min_own) {
        !           420:                                                f_profile->min_own = own_time;
        !           421:                                        } else if (own_time > f_profile->max_own) {
        !           422:                                                f_profile->max_own = own_time;
        !           423:                                        }
        !           424:                                        f_profile->avg_own = (f_profile->avg_own * f_profile->calls + own_time) / (f_profile->calls + 1);
        !           425: 
        !           426:                                        if (call_time < f_profile->min_total) {
        !           427:                                                f_profile->min_total = call_time;
        !           428:                                        } else if (call_time > f_profile->max_total) {
        !           429:                                                f_profile->max_total = call_time;
        !           430:                                        }
        !           431:                                        f_profile->avg_total = (f_profile->avg_total * f_profile->calls + call_time) / (f_profile->calls + 1);
        !           432: 
        !           433:                                        ++f_profile->calls;
        !           434:                                        if (f_profile->calls > PROFILE_UNDERPERFORM_THRESHOLD) {
        !           435:                                                if (f_profile->avg_in_calls < mine_non_own_time) {
        !           436:                                                        f_profile->in_calls_underporm_calls++;
        !           437:                                                }
        !           438:                                                if (f_profile->avg_own < own_time) {
        !           439:                                                        f_profile->own_underporm_calls++;
        !           440:                                                }
        !           441:                                                if (f_profile->avg_total < call_time) {
        !           442:                                                        f_profile->total_underporm_calls++;
        !           443:                                                }
        !           444:                                        }
        !           445:                                }
        !           446:                        } else {
        !           447:                                /* add */
        !           448:                                f_profile = &f_profile_stack;
        !           449:                                f_profile->min_in_calls = f_profile->max_in_calls = f_profile->avg_in_calls = mine_non_own_time;
        !           450:                                f_profile->min_total = f_profile->max_total = f_profile->avg_total = call_time;
        !           451:                                f_profile->min_own = f_profile->max_own = f_profile->avg_own = own_time;
        !           452:                                f_profile->calls = 1;
        !           453:                                zend_hash_add(&self->function_profiles, func_name, func_name_len+1, f_profile, sizeof(struct st_mysqlnd_dbg_function_profile), NULL);
        !           454:                        }
        !           455:                        if ((uint) zend_stack_count(&self->call_time_stack)) {
        !           456:                                uint64_t parent_non_own_time = 0;
        !           457: 
        !           458:                                zend_stack_top(&self->call_time_stack, (void **)&parent_non_own_time_ptr);
        !           459:                                parent_non_own_time = *parent_non_own_time_ptr;
        !           460:                                parent_non_own_time += call_time;
        !           461:                                zend_stack_del_top(&self->call_time_stack); /* the caller */
        !           462:                                zend_stack_push(&self->call_time_stack, &parent_non_own_time, sizeof(parent_non_own_time)); /* add back the caller */
        !           463:                        }
        !           464:                }
        !           465: #endif
        !           466:        }
        !           467: 
        !           468:        return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL;
        !           469: }
        !           470: /* }}} */
        !           471: 
        !           472: 
        !           473: /* {{{ mysqlnd_debug::close */
        !           474: static enum_func_status
        !           475: MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self)
        !           476: {
        !           477:        MYSQLND_ZTS(self);
        !           478:        if (self->stream) {
        !           479: #ifndef MYSQLND_PROFILING_DISABLED
        !           480:                if (!(self->flags & MYSQLND_DEBUG_FLUSH) && (self->flags & MYSQLND_DEBUG_PROFILE_CALLS)) {
        !           481:                        struct st_mysqlnd_dbg_function_profile * f_profile;
        !           482:                        HashPosition pos_values;
        !           483: 
        !           484:                        self->m->log_va(self, __LINE__, __FILE__, 0, "info : ", 
        !           485:                                        "number of functions: %d", zend_hash_num_elements(&self->function_profiles));
        !           486:                        zend_hash_internal_pointer_reset_ex(&self->function_profiles, &pos_values);
        !           487:                        while (zend_hash_get_current_data_ex(&self->function_profiles, (void **) &f_profile, &pos_values) == SUCCESS) {
        !           488:                                char    *string_key = NULL;
        !           489:                                uint    string_key_len;
        !           490:                                ulong   num_key;
        !           491: 
        !           492:                                zend_hash_get_current_key_ex(&self->function_profiles, &string_key, &string_key_len, &num_key, 0, &pos_values);
        !           493: 
        !           494:                                self->m->log_va(self, __LINE__, __FILE__, -1, "info : ",
        !           495:                                                "%-40s\tcalls=%5llu  own_slow=%5llu  in_calls_slow=%5llu  total_slow=%5llu"
        !           496:                                                "   min_own=%5llu  max_own=%7llu  avg_own=%7llu   "
        !           497:                                                "   min_in_calls=%5llu  max_in_calls=%7llu  avg_in_calls=%7llu"
        !           498:                                                "   min_total=%5llu  max_total=%7llu  avg_total=%7llu"
        !           499:                                                ,string_key
        !           500:                                                ,(uint64_t) f_profile->calls
        !           501:                                                ,(uint64_t) f_profile->own_underporm_calls
        !           502:                                                ,(uint64_t) f_profile->in_calls_underporm_calls
        !           503:                                                ,(uint64_t) f_profile->total_underporm_calls
        !           504:                                                
        !           505:                                                ,(uint64_t) f_profile->min_own
        !           506:                                                ,(uint64_t) f_profile->max_own
        !           507:                                                ,(uint64_t) f_profile->avg_own
        !           508:                                                ,(uint64_t) f_profile->min_in_calls
        !           509:                                                ,(uint64_t) f_profile->max_in_calls
        !           510:                                                ,(uint64_t) f_profile->avg_in_calls
        !           511:                                                ,(uint64_t) f_profile->min_total
        !           512:                                                ,(uint64_t) f_profile->max_total
        !           513:                                                ,(uint64_t) f_profile->avg_total
        !           514:                                                );
        !           515:                                zend_hash_move_forward_ex(&self->function_profiles, &pos_values);
        !           516:                        }
        !           517:                }
        !           518: #endif 
        !           519: 
        !           520:                php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE);
        !           521:                self->stream = NULL;
        !           522:        }
        !           523:        /* no DBG_RETURN please */
        !           524:        return PASS;
        !           525: }
        !           526: /* }}} */
        !           527: 
        !           528: 
        !           529: /* {{{ mysqlnd_res_meta::free */
        !           530: static enum_func_status
        !           531: MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self)
        !           532: {
        !           533:        if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
        !           534:                efree(self->file_name);
        !           535:                self->file_name = NULL;
        !           536:        }
        !           537:        zend_stack_destroy(&self->call_stack);
        !           538:        zend_stack_destroy(&self->call_time_stack);
        !           539:        zend_hash_destroy(&self->not_filtered_functions);
        !           540:        zend_hash_destroy(&self->function_profiles);
        !           541:        efree(self);
        !           542:        return PASS;
        !           543: }
        !           544: /* }}} */
        !           545: 
        !           546: enum mysqlnd_debug_parser_state
        !           547: {
        !           548:        PARSER_WAIT_MODIFIER,
        !           549:        PARSER_WAIT_COLON,
        !           550:        PARSER_WAIT_VALUE
        !           551: };
        !           552: 
        !           553: 
        !           554: /* {{{ mysqlnd_res_meta::set_mode */
        !           555: static void
        !           556: MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
        !           557: {
        !           558:        unsigned int mode_len = strlen(mode), i;
        !           559:        enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
        !           560: 
        !           561:        self->flags = 0;
        !           562:        self->nest_level_limit = 0;
        !           563:        if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
        !           564:                efree(self->file_name);
        !           565:                self->file_name = NULL;
        !           566:        }
        !           567:        if (zend_hash_num_elements(&self->not_filtered_functions)) {
        !           568:                zend_hash_destroy(&self->not_filtered_functions);
        !           569:                zend_hash_init(&self->not_filtered_functions, 0, NULL, NULL, 0);
        !           570:        }
        !           571: 
        !           572:        for (i = 0; i < mode_len; i++) {
        !           573:                switch (mode[i]) {
        !           574:                        case 'O':
        !           575:                        case 'A':
        !           576:                                self->flags |= MYSQLND_DEBUG_FLUSH;
        !           577:                        case 'a':
        !           578:                        case 'o':
        !           579:                                if (mode[i] == 'a' || mode[i] == 'A') {
        !           580:                                        self->flags |= MYSQLND_DEBUG_APPEND;
        !           581:                                }
        !           582:                                if (i + 1 < mode_len && mode[i+1] == ',') {
        !           583:                                        unsigned int j = i + 2;
        !           584: #ifdef PHP_WIN32
        !           585:                                        if (i+4 < mode_len && mode[i+3] == ':' && (mode[i+4] == '\\' || mode[i+5] == '/')) {
        !           586:                                                j = i + 5;
        !           587:                                        }
        !           588: #endif
        !           589:                                        while (j < mode_len) {
        !           590:                                                if (mode[j] == ':') {
        !           591:                                                        break;
        !           592:                                                }
        !           593:                                                j++;
        !           594:                                        }
        !           595:                                        if (j > i + 2) {
        !           596:                                                self->file_name = estrndup(mode + i + 2, j - i - 2);
        !           597:                                        }
        !           598:                                        i = j;
        !           599:                                } else {
        !           600:                                        if (!self->file_name)
        !           601:                                                self->file_name = (char *) mysqlnd_debug_default_trace_file;
        !           602:                                }
        !           603:                                state = PARSER_WAIT_COLON;
        !           604:                                break;
        !           605:                        case ':':
        !           606: #if 0
        !           607:                                if (state != PARSER_WAIT_COLON) {
        !           608:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Consecutive semicolons at position %u", i);
        !           609:                                }
        !           610: #endif
        !           611:                                state = PARSER_WAIT_MODIFIER;
        !           612:                                break;
        !           613:                        case 'f': /* limit output to these functions */
        !           614:                                if (i + 1 < mode_len && mode[i+1] == ',') {
        !           615:                                        unsigned int j = i + 2;
        !           616:                                        i++;
        !           617:                                        while (j < mode_len) {
        !           618:                                                if (mode[j] == ':') {
        !           619:                                                        /* function names with :: */
        !           620:                                                        if ((j + 1 < mode_len) && mode[j+1] == ':') {
        !           621:                                                                j += 2;
        !           622:                                                                continue;
        !           623:                                                        }
        !           624:                                                }
        !           625:                                                if (mode[j] == ',' || mode[j] == ':') {
        !           626:                                                        if (j > i + 2) {
        !           627:                                                                char func_name[1024];
        !           628:                                                                unsigned int func_name_len = MIN(sizeof(func_name) - 1, j - i - 1);
        !           629:                                                                memcpy(func_name, mode + i + 1, func_name_len);
        !           630:                                                                func_name[func_name_len] = '\0'; 
        !           631: 
        !           632:                                                                zend_hash_add_empty_element(&self->not_filtered_functions,
        !           633:                                                                                                                        func_name, func_name_len + 1);
        !           634:                                                                i = j;
        !           635:                                                        }
        !           636:                                                        if (mode[j] == ':') {
        !           637:                                                                break;
        !           638:                                                        }
        !           639:                                                }
        !           640:                                                j++;
        !           641:                                        }
        !           642:                                        i = j;
        !           643:                                } else {
        !           644: #if 0
        !           645:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
        !           646:                                                                         "Expected list of functions for '%c' found none", mode[i]);
        !           647: #endif
        !           648:                                }
        !           649:                                state = PARSER_WAIT_COLON;
        !           650:                                break;
        !           651:                        case 'D':
        !           652:                        case 'd':
        !           653:                        case 'g':
        !           654:                        case 'p':
        !           655:                                /* unsupported */
        !           656:                                if ((i + 1) < mode_len && mode[i+1] == ',') {
        !           657:                                        i+= 2;
        !           658:                                        while (i < mode_len) {
        !           659:                                                if (mode[i] == ':') {
        !           660:                                                        break;
        !           661:                                                }
        !           662:                                                i++;
        !           663:                                        }
        !           664:                                }
        !           665:                                state = PARSER_WAIT_COLON;
        !           666:                                break;
        !           667:                        case 'F':
        !           668:                                self->flags |= MYSQLND_DEBUG_DUMP_FILE;
        !           669:                                state = PARSER_WAIT_COLON;
        !           670:                                break;
        !           671:                        case 'i':
        !           672:                                self->flags |= MYSQLND_DEBUG_DUMP_PID;
        !           673:                                state = PARSER_WAIT_COLON;
        !           674:                                break;
        !           675:                        case 'L':
        !           676:                                self->flags |= MYSQLND_DEBUG_DUMP_LINE;
        !           677:                                state = PARSER_WAIT_COLON;
        !           678:                                break;
        !           679:                        case 'n':
        !           680:                                self->flags |= MYSQLND_DEBUG_DUMP_LEVEL;
        !           681:                                state = PARSER_WAIT_COLON;
        !           682:                                break;
        !           683:                        case 't':
        !           684:                                if (mode[i+1] == ',') {
        !           685:                                        unsigned int j = i + 2;
        !           686:                                        while (j < mode_len) {
        !           687:                                                if (mode[j] == ':') {
        !           688:                                                        break;
        !           689:                                                }
        !           690:                                                j++;
        !           691:                                        }
        !           692:                                        if (j > i + 2) {
        !           693:                                                char *value_str = estrndup(mode + i + 2, j - i - 2);
        !           694:                                                self->nest_level_limit = atoi(value_str);
        !           695:                                                efree(value_str);
        !           696:                                        }
        !           697:                                        i = j;
        !           698:                                } else {
        !           699:                                        self->nest_level_limit = 200; /* default value for FF DBUG */
        !           700:                                }
        !           701:                                self->flags |= MYSQLND_DEBUG_DUMP_TRACE;
        !           702:                                state = PARSER_WAIT_COLON;
        !           703:                                break;
        !           704:                        case 'T':
        !           705:                                self->flags |= MYSQLND_DEBUG_DUMP_TIME;
        !           706:                                state = PARSER_WAIT_COLON;
        !           707:                                break;
        !           708:                        case 'N':
        !           709:                        case 'P':
        !           710:                        case 'r':
        !           711:                        case 'S':
        !           712:                                state = PARSER_WAIT_COLON;
        !           713:                                break;
        !           714:                        case 'm': /* mysqlnd extension - trace memory functions */
        !           715:                                self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS;
        !           716:                                state = PARSER_WAIT_COLON;
        !           717:                                break;
        !           718:                        case 'x': /* mysqlnd extension - profile calls */
        !           719:                                self->flags |= MYSQLND_DEBUG_PROFILE_CALLS;
        !           720:                                state = PARSER_WAIT_COLON;
        !           721:                                break;                          
        !           722:                        default:
        !           723:                                if (state == PARSER_WAIT_MODIFIER) {
        !           724: #if 0
        !           725:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized format '%c'", mode[i]);
        !           726: #endif
        !           727:                                        if (i+1 < mode_len && mode[i+1] == ',') {
        !           728:                                                i+= 2;
        !           729:                                                while (i < mode_len) {
        !           730:                                                        if (mode[i] == ':') {
        !           731:                                                                break;
        !           732:                                                        }
        !           733:                                                        i++;
        !           734:                                                }
        !           735:                                        }
        !           736:                                        state = PARSER_WAIT_COLON;
        !           737:                                } else if (state == PARSER_WAIT_COLON) {
        !           738: #if 0
        !           739:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Colon expected, '%c' found", mode[i]);
        !           740: #endif
        !           741:                                }
        !           742:                                break;
        !           743:                }
        !           744:        }
        !           745: }
        !           746: /* }}} */
        !           747: 
        !           748: MYSQLND_CLASS_METHODS_START(mysqlnd_debug)
        !           749:        MYSQLND_METHOD(mysqlnd_debug, open),
        !           750:        MYSQLND_METHOD(mysqlnd_debug, set_mode),
        !           751:        MYSQLND_METHOD(mysqlnd_debug, log),
        !           752:        MYSQLND_METHOD(mysqlnd_debug, log_va),
        !           753:        MYSQLND_METHOD(mysqlnd_debug, func_enter),
        !           754:        MYSQLND_METHOD(mysqlnd_debug, func_leave),
        !           755:        MYSQLND_METHOD(mysqlnd_debug, close),
        !           756:        MYSQLND_METHOD(mysqlnd_debug, free),
        !           757: MYSQLND_CLASS_METHODS_END;
        !           758: 
        !           759: 
        !           760: /* {{{ mysqlnd_debug_init */
        !           761: PHPAPI MYSQLND_DEBUG *
        !           762: mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC)
        !           763: {
        !           764:        MYSQLND_DEBUG *ret = ecalloc(1, sizeof(MYSQLND_DEBUG));
        !           765: #ifdef ZTS
        !           766:        ret->TSRMLS_C = TSRMLS_C;
        !           767: #endif
        !           768:        ret->nest_level_limit = 0;
        !           769:        ret->pid = getpid();
        !           770:        zend_stack_init(&ret->call_stack);
        !           771:        zend_stack_init(&ret->call_time_stack);
        !           772:        zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0);
        !           773:        zend_hash_init(&ret->function_profiles, 0, NULL, NULL, 0);
        !           774: 
        !           775:        ret->m = & mysqlnd_mysqlnd_debug_methods;
        !           776:        ret->skip_functions = skip_functions;
        !           777: 
        !           778:        return ret;
        !           779: }
        !           780: /* }}} */
        !           781: 
        !           782: 
        !           783: /* {{{ _mysqlnd_debug */
        !           784: PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC)
        !           785: {
        !           786: #ifdef PHP_DEBUG
        !           787:        MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
        !           788:        if (!dbg) {
        !           789:                MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(mysqlnd_debug_std_no_trace_funcs TSRMLS_CC);
        !           790:                if (!dbg) {
        !           791:                        return;
        !           792:                }
        !           793:        }
        !           794: 
        !           795:        dbg->m->close(dbg);
        !           796:        dbg->m->set_mode(dbg, mode);
        !           797:        while (zend_stack_count(&dbg->call_stack)) {
        !           798:                zend_stack_del_top(&dbg->call_stack);
        !           799:        }
        !           800:        while (zend_stack_count(&dbg->call_time_stack)) {
        !           801:                zend_stack_del_top(&dbg->call_time_stack);
        !           802:        }
        !           803: #endif
        !           804: }
        !           805: /* }}} */
        !           806: 
        !           807: 
        !           808: #if ZEND_DEBUG
        !           809: #else
        !           810: #define __zend_filename "/unknown/unknown"
        !           811: #define __zend_lineno   0
        !           812: #endif
        !           813: 
        !           814: #define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s))
        !           815: #define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p))
        !           816: #define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p))
        !           817: 
        !           818: /* {{{ _mysqlnd_emalloc */
        !           819: void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
        !           820: {
        !           821:        void *ret;
        !           822:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           823:        long * threshold = &MYSQLND_G(debug_emalloc_fail_threshold);
        !           824:        DBG_ENTER(mysqlnd_emalloc_name);
        !           825: 
        !           826:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           827: 
        !           828: #ifdef PHP_DEBUG
        !           829:        /* -1 is also "true" */
        !           830:        if (*threshold) {
        !           831: #endif
        !           832:                ret = emalloc(REAL_SIZE(size));
        !           833: #ifdef PHP_DEBUG
        !           834:                --*threshold;
        !           835:        } else if (*threshold == 0) {
        !           836:                ret = NULL;
        !           837:        }
        !           838: #endif
        !           839: 
        !           840:        DBG_INF_FMT("size=%lu ptr=%p", size, ret);
        !           841: 
        !           842:        if (ret && collect_memory_statistics) {
        !           843:                *(size_t *) ret = size;
        !           844:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size);
        !           845:        }
        !           846:        DBG_RETURN(FAKE_PTR(ret));
        !           847: }
        !           848: /* }}} */
        !           849: 
        !           850: 
        !           851: /* {{{ _mysqlnd_pemalloc */
        !           852: void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
        !           853: {
        !           854:        void *ret;
        !           855:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           856:        long * threshold = persistent? &MYSQLND_G(debug_malloc_fail_threshold):&MYSQLND_G(debug_emalloc_fail_threshold);
        !           857:        DBG_ENTER(mysqlnd_pemalloc_name);
        !           858:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           859: 
        !           860: #ifdef PHP_DEBUG
        !           861:        /* -1 is also "true" */
        !           862:        if (*threshold) {
        !           863: #endif
        !           864:                ret = pemalloc(REAL_SIZE(size), persistent);
        !           865: #ifdef PHP_DEBUG
        !           866:                --*threshold;
        !           867:        } else if (*threshold == 0) {
        !           868:                ret = NULL;
        !           869:        }
        !           870: #endif
        !           871: 
        !           872:        DBG_INF_FMT("size=%lu ptr=%p persistent=%u", size, ret, persistent);
        !           873: 
        !           874:        if (ret && collect_memory_statistics) {
        !           875:                enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT;
        !           876:                enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMOUNT:STAT_MEM_EMALLOC_AMOUNT;
        !           877:                *(size_t *) ret = size;
        !           878:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
        !           879:        }
        !           880: 
        !           881:        DBG_RETURN(FAKE_PTR(ret));
        !           882: }
        !           883: /* }}} */
        !           884: 
        !           885: 
        !           886: /* {{{ _mysqlnd_ecalloc */
        !           887: void * _mysqlnd_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
        !           888: {
        !           889:        void *ret;
        !           890:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           891:        long * threshold = &MYSQLND_G(debug_ecalloc_fail_threshold);
        !           892:        DBG_ENTER(mysqlnd_ecalloc_name);
        !           893:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           894:        DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
        !           895: 
        !           896: #ifdef PHP_DEBUG
        !           897:        /* -1 is also "true" */
        !           898:        if (*threshold) {
        !           899: #endif
        !           900:                ret = ecalloc(nmemb, REAL_SIZE(size));
        !           901: #ifdef PHP_DEBUG
        !           902:                --*threshold;
        !           903:        } else if (*threshold == 0) {
        !           904:                ret = NULL;
        !           905:        }
        !           906: #endif
        !           907: 
        !           908:        DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
        !           909:        DBG_INF_FMT("size=%lu ptr=%p", size, ret);
        !           910:        if (ret && collect_memory_statistics) {
        !           911:                *(size_t *) ret = size;
        !           912:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMOUNT, size);
        !           913:        }
        !           914:        DBG_RETURN(FAKE_PTR(ret));
        !           915: }
        !           916: /* }}} */
        !           917: 
        !           918: 
        !           919: /* {{{ _mysqlnd_pecalloc */
        !           920: void * _mysqlnd_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
        !           921: {
        !           922:        void *ret;
        !           923:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           924:        long * threshold = persistent? &MYSQLND_G(debug_calloc_fail_threshold):&MYSQLND_G(debug_ecalloc_fail_threshold);
        !           925:        DBG_ENTER(mysqlnd_pecalloc_name);
        !           926:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           927: 
        !           928: #ifdef PHP_DEBUG
        !           929:        /* -1 is also "true" */
        !           930:        if (*threshold) {
        !           931: #endif
        !           932:                ret = pecalloc(nmemb, REAL_SIZE(size), persistent);
        !           933: #ifdef PHP_DEBUG
        !           934:                --*threshold;
        !           935:        } else if (*threshold == 0) {
        !           936:                ret = NULL;
        !           937:        }
        !           938: #endif
        !           939: 
        !           940:        DBG_INF_FMT("size=%lu ptr=%p", size, ret);
        !           941: 
        !           942:        if (ret && collect_memory_statistics) {
        !           943:                enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT;
        !           944:                enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMOUNT:STAT_MEM_ECALLOC_AMOUNT;
        !           945:                *(size_t *) ret = size;
        !           946:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, size);
        !           947:        }
        !           948: 
        !           949:        DBG_RETURN(FAKE_PTR(ret));
        !           950: }
        !           951: /* }}} */
        !           952: 
        !           953: 
        !           954: /* {{{ _mysqlnd_erealloc */
        !           955: void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
        !           956: {
        !           957:        void *ret;
        !           958:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           959:        size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
        !           960:        long * threshold = &MYSQLND_G(debug_erealloc_fail_threshold);
        !           961:        DBG_ENTER(mysqlnd_erealloc_name);
        !           962:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           963:        DBG_INF_FMT("ptr=%p old_size=%lu, new_size=%lu", ptr, old_size, new_size); 
        !           964: 
        !           965: #ifdef PHP_DEBUG
        !           966:        /* -1 is also "true" */
        !           967:        if (*threshold) {
        !           968: #endif
        !           969:                ret = erealloc(REAL_PTR(ptr), REAL_SIZE(new_size));
        !           970: #ifdef PHP_DEBUG
        !           971:                --*threshold;
        !           972:        } else if (*threshold == 0) {
        !           973:                ret = NULL;
        !           974:        }
        !           975: #endif
        !           976: 
        !           977:        DBG_INF_FMT("new_ptr=%p", (char*)ret);
        !           978:        if (ret && collect_memory_statistics) {
        !           979:                *(size_t *) ret = new_size;
        !           980:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMOUNT, new_size);
        !           981:        }
        !           982:        DBG_RETURN(FAKE_PTR(ret));
        !           983: }
        !           984: /* }}} */
        !           985: 
        !           986: 
        !           987: /* {{{ _mysqlnd_perealloc */
        !           988: void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
        !           989: {
        !           990:        void *ret;
        !           991:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !           992:        size_t old_size = collect_memory_statistics && ptr? *(size_t *) (((char*)ptr) - sizeof(size_t)) : 0;
        !           993:        long * threshold = persistent? &MYSQLND_G(debug_realloc_fail_threshold):&MYSQLND_G(debug_erealloc_fail_threshold);
        !           994:        DBG_ENTER(mysqlnd_perealloc_name);
        !           995:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !           996:        DBG_INF_FMT("ptr=%p old_size=%lu new_size=%lu persistent=%u", ptr, old_size, new_size, persistent); 
        !           997: 
        !           998: #ifdef PHP_DEBUG
        !           999:        /* -1 is also "true" */
        !          1000:        if (*threshold) {
        !          1001: #endif
        !          1002:                ret = perealloc(REAL_PTR(ptr), REAL_SIZE(new_size), persistent);
        !          1003: #ifdef PHP_DEBUG
        !          1004:                --*threshold;
        !          1005:        } else if (*threshold == 0) {
        !          1006:                ret = NULL;
        !          1007:        }
        !          1008: #endif
        !          1009: 
        !          1010:        DBG_INF_FMT("new_ptr=%p", (char*)ret);
        !          1011: 
        !          1012:        if (ret && collect_memory_statistics) {
        !          1013:                enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT;
        !          1014:                enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMOUNT:STAT_MEM_EREALLOC_AMOUNT;
        !          1015:                *(size_t *) ret = new_size;
        !          1016:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(s1, 1, s2, new_size);
        !          1017:        }
        !          1018:        DBG_RETURN(FAKE_PTR(ret));
        !          1019: }
        !          1020: /* }}} */
        !          1021: 
        !          1022: 
        !          1023: /* {{{ _mysqlnd_efree */
        !          1024: void _mysqlnd_efree(void *ptr MYSQLND_MEM_D)
        !          1025: {
        !          1026:        size_t free_amount = 0;
        !          1027:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1028:        DBG_ENTER(mysqlnd_efree_name);
        !          1029:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1030:        DBG_INF_FMT("ptr=%p", ptr); 
        !          1031: 
        !          1032:        if (ptr) {
        !          1033:                if (collect_memory_statistics) {
        !          1034:                        free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
        !          1035:                        DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
        !          1036:                }
        !          1037:                efree(REAL_PTR(ptr));
        !          1038:        }
        !          1039: 
        !          1040:        if (collect_memory_statistics) {
        !          1041:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EFREE_COUNT, 1, STAT_MEM_EFREE_AMOUNT, free_amount);
        !          1042:        }
        !          1043:        DBG_VOID_RETURN;
        !          1044: }
        !          1045: /* }}} */
        !          1046: 
        !          1047: 
        !          1048: /* {{{ _mysqlnd_pefree */
        !          1049: void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D)
        !          1050: {
        !          1051:        size_t free_amount = 0;
        !          1052:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1053:        DBG_ENTER(mysqlnd_pefree_name);
        !          1054:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1055:        DBG_INF_FMT("ptr=%p persistent=%u", ptr, persistent); 
        !          1056: 
        !          1057:        if (ptr) {
        !          1058:                if (collect_memory_statistics) {
        !          1059:                        free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
        !          1060:                        DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
        !          1061:                }
        !          1062:                pefree(REAL_PTR(ptr), persistent);
        !          1063:        }
        !          1064: 
        !          1065:        if (collect_memory_statistics) {
        !          1066:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT, 1,
        !          1067:                                                                                          persistent? STAT_MEM_FREE_AMOUNT:STAT_MEM_EFREE_AMOUNT, free_amount);
        !          1068:        }
        !          1069:        DBG_VOID_RETURN;
        !          1070: }
        !          1071: 
        !          1072: 
        !          1073: /* {{{ _mysqlnd_malloc */
        !          1074: void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D)
        !          1075: {
        !          1076:        void *ret;
        !          1077:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1078:        long * threshold = &MYSQLND_G(debug_malloc_fail_threshold);
        !          1079:        DBG_ENTER(mysqlnd_malloc_name);
        !          1080:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1081: 
        !          1082: #ifdef PHP_DEBUG
        !          1083:        /* -1 is also "true" */
        !          1084:        if (*threshold) {
        !          1085: #endif
        !          1086:                ret = malloc(REAL_SIZE(size));
        !          1087: #ifdef PHP_DEBUG
        !          1088:                --*threshold;
        !          1089:        } else if (*threshold == 0) {
        !          1090:                ret = NULL;
        !          1091:        }
        !          1092: #endif
        !          1093: 
        !          1094:        DBG_INF_FMT("size=%lu ptr=%p", size, ret);
        !          1095:        if (ret && collect_memory_statistics) {
        !          1096:                *(size_t *) ret = size;
        !          1097:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMOUNT, size);
        !          1098:        }
        !          1099:        DBG_RETURN(FAKE_PTR(ret));
        !          1100: }
        !          1101: /* }}} */
        !          1102: 
        !          1103: 
        !          1104: /* {{{ _mysqlnd_calloc */
        !          1105: void * _mysqlnd_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
        !          1106: {
        !          1107:        void *ret;
        !          1108:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1109:        long * threshold = &MYSQLND_G(debug_calloc_fail_threshold);
        !          1110:        DBG_ENTER(mysqlnd_calloc_name);
        !          1111:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1112: 
        !          1113: #ifdef PHP_DEBUG
        !          1114:        /* -1 is also "true" */
        !          1115:        if (*threshold) {
        !          1116: #endif
        !          1117:                ret = calloc(nmemb, REAL_SIZE(size));
        !          1118: #ifdef PHP_DEBUG
        !          1119:                --*threshold;
        !          1120:        } else if (*threshold == 0) {
        !          1121:                ret = NULL;
        !          1122:        }
        !          1123: #endif
        !          1124: 
        !          1125:        DBG_INF_FMT("size=%lu ptr=%p", size, ret);
        !          1126:        if (ret && collect_memory_statistics) {
        !          1127:                *(size_t *) ret = size;
        !          1128:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMOUNT, size);
        !          1129:        }
        !          1130:        DBG_RETURN(FAKE_PTR(ret));
        !          1131: }
        !          1132: /* }}} */
        !          1133: 
        !          1134: 
        !          1135: /* {{{ _mysqlnd_realloc */
        !          1136: void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D)
        !          1137: {
        !          1138:        void *ret;
        !          1139:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1140:        long * threshold = &MYSQLND_G(debug_realloc_fail_threshold);
        !          1141:        DBG_ENTER(mysqlnd_realloc_name);
        !          1142:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1143:        DBG_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr); 
        !          1144:        DBG_INF_FMT("before: %lu", zend_memory_usage(TRUE TSRMLS_CC));
        !          1145: 
        !          1146: #ifdef PHP_DEBUG
        !          1147:        /* -1 is also "true" */
        !          1148:        if (*threshold) {
        !          1149: #endif
        !          1150:                ret = realloc(REAL_PTR(ptr), REAL_SIZE(new_size));
        !          1151: #ifdef PHP_DEBUG
        !          1152:                --*threshold;
        !          1153:        } else if (*threshold == 0) {
        !          1154:                ret = NULL;
        !          1155:        }
        !          1156: #endif
        !          1157: 
        !          1158:        DBG_INF_FMT("new_ptr=%p", (char*)ret);
        !          1159: 
        !          1160:        if (ret && collect_memory_statistics) {
        !          1161:                *(size_t *) ret = new_size;
        !          1162:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMOUNT, new_size);
        !          1163:        }
        !          1164:        DBG_RETURN(FAKE_PTR(ret));
        !          1165: }
        !          1166: /* }}} */
        !          1167: 
        !          1168: 
        !          1169: /* {{{ _mysqlnd_free */
        !          1170: void _mysqlnd_free(void *ptr MYSQLND_MEM_D)
        !          1171: {
        !          1172:        size_t free_amount = 0;
        !          1173:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1174:        DBG_ENTER(mysqlnd_free_name);
        !          1175:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1176:        DBG_INF_FMT("ptr=%p", ptr); 
        !          1177: 
        !          1178:        if (ptr) {
        !          1179:                if (collect_memory_statistics) {
        !          1180:                        free_amount = *(size_t *)(((char*)ptr) - sizeof(size_t));
        !          1181:                        DBG_INF_FMT("ptr=%p size=%u", ((char*)ptr) - sizeof(size_t), (unsigned int) free_amount);
        !          1182:                }
        !          1183:                free(REAL_PTR(ptr));
        !          1184:        }
        !          1185: 
        !          1186:        if (collect_memory_statistics) {
        !          1187:                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_FREE_COUNT, 1, STAT_MEM_FREE_AMOUNT, free_amount);
        !          1188:        }
        !          1189:        DBG_VOID_RETURN;
        !          1190: }
        !          1191: /* }}} */
        !          1192: 
        !          1193: #define SMART_STR_START_SIZE 2048
        !          1194: #define SMART_STR_PREALLOC 512
        !          1195: #include "ext/standard/php_smart_str.h"
        !          1196: 
        !          1197: 
        !          1198: /* {{{ _mysqlnd_pestrndup */
        !          1199: char * _mysqlnd_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
        !          1200: {
        !          1201:        char * ret;
        !          1202:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1203:        DBG_ENTER(mysqlnd_pestrndup_name);
        !          1204:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1205:        DBG_INF_FMT("ptr=%p", ptr); 
        !          1206: 
        !          1207:        ret = pemalloc(REAL_SIZE(length) + 1, persistent);
        !          1208:        {
        !          1209:                size_t l = length;
        !          1210:                char * p = (char *) ptr;
        !          1211:                char * dest = (char *) FAKE_PTR(ret);
        !          1212:                while (*p && l--) {
        !          1213:                        *dest++ = *p++;
        !          1214:                }
        !          1215:                *dest = '\0';
        !          1216:        }
        !          1217: 
        !          1218:        if (collect_memory_statistics) {
        !          1219:                *(size_t *) ret = length;
        !          1220:                MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRNDUP_COUNT : STAT_MEM_ESTRNDUP_COUNT);
        !          1221:        }
        !          1222: 
        !          1223:        DBG_RETURN(FAKE_PTR(ret));
        !          1224: }
        !          1225: /* }}} */
        !          1226: 
        !          1227: 
        !          1228: /* {{{ _mysqlnd_pestrdup */
        !          1229: char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
        !          1230: {
        !          1231:        char * ret;
        !          1232:        smart_str tmp_str = {0, 0, 0};
        !          1233:        const char * p = ptr;
        !          1234:        zend_bool collect_memory_statistics = MYSQLND_G(collect_memory_statistics);
        !          1235:        DBG_ENTER(mysqlnd_pestrdup_name);
        !          1236:        DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
        !          1237:        DBG_INF_FMT("ptr=%p", ptr);
        !          1238:        do {
        !          1239:                smart_str_appendc(&tmp_str, *p);
        !          1240:        } while (*p++);
        !          1241: 
        !          1242:        ret = pemalloc(tmp_str.len + sizeof(size_t), persistent);
        !          1243:        memcpy(FAKE_PTR(ret), tmp_str.c, tmp_str.len);
        !          1244: 
        !          1245:        if (ret && collect_memory_statistics) {
        !          1246:                *(size_t *) ret = tmp_str.len;
        !          1247:                MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_STRDUP_COUNT : STAT_MEM_ESTRDUP_COUNT);
        !          1248:        }
        !          1249:        smart_str_free(&tmp_str);
        !          1250: 
        !          1251:        DBG_RETURN(FAKE_PTR(ret));
        !          1252: }
        !          1253: /* }}} */
        !          1254: 
        !          1255: #define MYSQLND_DEBUG_MEMORY 1
        !          1256: 
        !          1257: #if MYSQLND_DEBUG_MEMORY == 0
        !          1258: 
        !          1259: /* {{{ mysqlnd_zend_mm_emalloc */
        !          1260: static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D)
        !          1261: {
        !          1262:        return emalloc(size);
        !          1263: }
        !          1264: /* }}} */
        !          1265: 
        !          1266: 
        !          1267: /* {{{ mysqlnd_zend_mm_pemalloc */
        !          1268: static void * mysqlnd_zend_mm_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
        !          1269: {
        !          1270:        return pemalloc(size, persistent);
        !          1271: }
        !          1272: /* }}} */
        !          1273: 
        !          1274: 
        !          1275: /* {{{ mysqlnd_zend_mm_ecalloc */
        !          1276: static void * mysqlnd_zend_mm_ecalloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
        !          1277: {
        !          1278:        return ecalloc(nmemb, size);
        !          1279: }
        !          1280: /* }}} */
        !          1281: 
        !          1282: 
        !          1283: /* {{{ mysqlnd_zend_mm_pecalloc */
        !          1284: static void * mysqlnd_zend_mm_pecalloc(unsigned int nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
        !          1285: {
        !          1286:        return pecalloc(nmemb, size, persistent);
        !          1287: }
        !          1288: /* }}} */
        !          1289: 
        !          1290: 
        !          1291: /* {{{ mysqlnd_zend_mm_erealloc */
        !          1292: static void * mysqlnd_zend_mm_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
        !          1293: {
        !          1294:        return erealloc(ptr, new_size);
        !          1295: }
        !          1296: /* }}} */
        !          1297: 
        !          1298: 
        !          1299: /* {{{ mysqlnd_zend_mm_perealloc */
        !          1300: static void * mysqlnd_zend_mm_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
        !          1301: {
        !          1302:        return perealloc(ptr, new_size, persistent);
        !          1303: }
        !          1304: /* }}} */
        !          1305: 
        !          1306: 
        !          1307: /* {{{ mysqlnd_zend_mm_efree */
        !          1308: static void mysqlnd_zend_mm_efree(void * ptr MYSQLND_MEM_D)
        !          1309: {
        !          1310:        efree(ptr);
        !          1311: }
        !          1312: /* }}} */
        !          1313: 
        !          1314: 
        !          1315: /* {{{ mysqlnd_zend_mm_pefree */
        !          1316: static void mysqlnd_zend_mm_pefree(void * ptr, zend_bool persistent MYSQLND_MEM_D)
        !          1317: {
        !          1318:        pefree(ptr, persistent);
        !          1319: }
        !          1320: /* }}} */
        !          1321: 
        !          1322: 
        !          1323: /* {{{ mysqlnd_zend_mm_malloc */
        !          1324: static void * mysqlnd_zend_mm_malloc(size_t size MYSQLND_MEM_D)
        !          1325: {
        !          1326:        return malloc(size);
        !          1327: }
        !          1328: /* }}} */
        !          1329: 
        !          1330: 
        !          1331: /* {{{ mysqlnd_zend_mm_calloc */
        !          1332: static void * mysqlnd_zend_mm_calloc(unsigned int nmemb, size_t size MYSQLND_MEM_D)
        !          1333: {
        !          1334:        return calloc(nmemb, size);
        !          1335: }
        !          1336: /* }}} */
        !          1337: 
        !          1338: 
        !          1339: /* {{{ mysqlnd_zend_mm_realloc */
        !          1340: static void * mysqlnd_zend_mm_realloc(void * ptr, size_t new_size MYSQLND_MEM_D)
        !          1341: {
        !          1342:        return realloc(ptr, new_size);
        !          1343: }
        !          1344: /* }}} */
        !          1345: 
        !          1346: 
        !          1347: /* {{{ mysqlnd_zend_mm_free */
        !          1348: static void mysqlnd_zend_mm_free(void * ptr MYSQLND_MEM_D)
        !          1349: {
        !          1350:        free(ptr);
        !          1351: }
        !          1352: /* }}} */
        !          1353: 
        !          1354: 
        !          1355: /* {{{ mysqlnd_zend_mm_pestrndup */
        !          1356: static char * mysqlnd_zend_mm_pestrndup(const char * const ptr, size_t length, zend_bool persistent MYSQLND_MEM_D)
        !          1357: {
        !          1358:        return pestrndup(ptr, length, persistent);
        !          1359: }
        !          1360: /* }}} */
        !          1361: 
        !          1362: 
        !          1363: /* {{{ mysqlnd_zend_mm_pestrdup */
        !          1364: static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_MEM_D)
        !          1365: {
        !          1366:        return pestrdup(ptr, persistent);
        !          1367: }
        !          1368: /* }}} */
        !          1369: 
        !          1370: #endif
        !          1371: 
        !          1372: 
        !          1373: PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator = 
        !          1374: {
        !          1375: #if MYSQLND_DEBUG_MEMORY
        !          1376:        _mysqlnd_emalloc,
        !          1377:        _mysqlnd_pemalloc,
        !          1378:        _mysqlnd_ecalloc,
        !          1379:        _mysqlnd_pecalloc,
        !          1380:        _mysqlnd_erealloc,
        !          1381:        _mysqlnd_perealloc,
        !          1382:        _mysqlnd_efree,
        !          1383:        _mysqlnd_pefree,
        !          1384:        _mysqlnd_malloc,
        !          1385:        _mysqlnd_calloc,
        !          1386:        _mysqlnd_realloc,
        !          1387:        _mysqlnd_free,
        !          1388:        _mysqlnd_pestrndup,
        !          1389:        _mysqlnd_pestrdup
        !          1390: #else
        !          1391:        mysqlnd_zend_mm_emalloc,
        !          1392:        mysqlnd_zend_mm_pemalloc,
        !          1393:        mysqlnd_zend_mm_ecalloc,
        !          1394:        mysqlnd_zend_mm_pecalloc,
        !          1395:        mysqlnd_zend_mm_erealloc,
        !          1396:        mysqlnd_zend_mm_perealloc,
        !          1397:        mysqlnd_zend_mm_efree,
        !          1398:        mysqlnd_zend_mm_pefree,
        !          1399:        mysqlnd_zend_mm_malloc,
        !          1400:        mysqlnd_zend_mm_calloc,
        !          1401:        mysqlnd_zend_mm_realloc,
        !          1402:        mysqlnd_zend_mm_free,
        !          1403:        mysqlnd_zend_mm_pestrndup,
        !          1404:        mysqlnd_zend_mm_pestrdup
        !          1405: #endif
        !          1406: };
        !          1407: 
        !          1408: 
        !          1409: 
        !          1410: /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
        !          1411: 
        !          1412: #if MYSQLND_UNICODE
        !          1413: /* {{{ gettraceasstring() macros */
        !          1414: #define TRACE_APPEND_CHR(chr)                                            \
        !          1415:        *str = (char*)erealloc(*str, *len + 1 + 1);                          \
        !          1416:        (*str)[(*len)++] = chr
        !          1417: 
        !          1418: #define TRACE_APPEND_STRL(val, vallen)                                   \
        !          1419:        {                                                                    \
        !          1420:                int l = vallen;                                                  \
        !          1421:                *str = (char*)erealloc(*str, *len + l + 1);                      \
        !          1422:                memcpy((*str) + *len, val, l);                                   \
        !          1423:                *len += l;                                                       \
        !          1424:        }
        !          1425: 
        !          1426: #define TRACE_APPEND_USTRL(val, vallen) \
        !          1427:        { \
        !          1428:                zval tmp, copy; \
        !          1429:                int use_copy; \
        !          1430:                ZVAL_UNICODEL(&tmp, val, vallen, 1); \
        !          1431:                zend_make_printable_zval(&tmp, &copy, &use_copy); \
        !          1432:                TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !          1433:                zval_dtor(&copy); \
        !          1434:                zval_dtor(&tmp); \
        !          1435:        }
        !          1436: 
        !          1437: #define TRACE_APPEND_ZVAL(zv) \
        !          1438:        if (Z_TYPE_P((zv)) == IS_UNICODE) { \
        !          1439:                zval copy; \
        !          1440:                int use_copy; \
        !          1441:                zend_make_printable_zval((zv), &copy, &use_copy); \
        !          1442:                TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !          1443:                zval_dtor(&copy); \
        !          1444:        } else { \
        !          1445:                TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
        !          1446:        }
        !          1447: 
        !          1448: #define TRACE_APPEND_STR(val)                                            \
        !          1449:        TRACE_APPEND_STRL(val, sizeof(val)-1)
        !          1450: 
        !          1451: #define TRACE_APPEND_KEY(key)                                            \
        !          1452:        if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
        !          1453:                if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
        !          1454:                        zval copy; \
        !          1455:                        int use_copy; \
        !          1456:                        zend_make_printable_zval(*tmp, &copy, &use_copy); \
        !          1457:                        TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
        !          1458:                        zval_dtor(&copy); \
        !          1459:                } else { \
        !          1460:                TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
        !          1461:                } \
        !          1462:        }
        !          1463: /* }}} */
        !          1464: 
        !          1465: /* {{{ mysqlnd_build_trace_args */
        !          1466: static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
        !          1467: {
        !          1468:        char **str;
        !          1469:        int *len;
        !          1470: 
        !          1471:        str = va_arg(args, char**);
        !          1472:        len = va_arg(args, int*);
        !          1473: 
        !          1474:        /* the trivial way would be to do:
        !          1475:         * conver_to_string_ex(arg);
        !          1476:         * append it and kill the now tmp arg.
        !          1477:         * but that could cause some E_NOTICE and also damn long lines.
        !          1478:         */
        !          1479: 
        !          1480:        switch (Z_TYPE_PP(arg)) {
        !          1481:                case IS_NULL:
        !          1482:                        TRACE_APPEND_STR("NULL, ");
        !          1483:                        break;
        !          1484:                case IS_STRING: {
        !          1485:                        int l_added;
        !          1486:                        TRACE_APPEND_CHR('\'');
        !          1487:                        if (Z_STRLEN_PP(arg) > 15) {
        !          1488:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
        !          1489:                                TRACE_APPEND_STR("...', ");
        !          1490:                                l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
        !          1491:                        } else {
        !          1492:                                l_added = Z_STRLEN_PP(arg);
        !          1493:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
        !          1494:                                TRACE_APPEND_STR("', ");
        !          1495:                                l_added += 3 + 1;
        !          1496:                        }
        !          1497:                        while (--l_added) {
        !          1498:                                if ((unsigned char)(*str)[*len - l_added] < 32) {
        !          1499:                                        (*str)[*len - l_added] = '?';
        !          1500:                                }
        !          1501:                        }
        !          1502:                        break;
        !          1503:                }
        !          1504:                case IS_UNICODE: {
        !          1505:                        int l_added;
        !          1506: 
        !          1507:                        /*
        !          1508:                         * We do not want to apply current error mode here, since
        !          1509:                         * zend_make_printable_zval() uses output encoding converter.
        !          1510:                         * Temporarily set output encoding converter to escape offending
        !          1511:                         * chars with \uXXXX notation.
        !          1512:                         */
        !          1513:                        zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
        !          1514:                        TRACE_APPEND_CHR('\'');
        !          1515:                        if (Z_USTRLEN_PP(arg) > 15) {
        !          1516:                                TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
        !          1517:                                TRACE_APPEND_STR("...', ");
        !          1518:                                l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
        !          1519:                        } else {
        !          1520:                                l_added = Z_USTRLEN_PP(arg);
        !          1521:                                TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
        !          1522:                                TRACE_APPEND_STR("', ");
        !          1523:                                l_added += 3 + 1;
        !          1524:                        }
        !          1525:                        /*
        !          1526:                         * Reset output encoding converter error mode.
        !          1527:                         */
        !          1528:                        zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode));
        !          1529:                        while (--l_added) {
        !          1530:                                if ((unsigned char)(*str)[*len - l_added] < 32) {
        !          1531:                                        (*str)[*len - l_added] = '?';
        !          1532:                                }
        !          1533:                        }
        !          1534:                        break;
        !          1535:                }
        !          1536:                case IS_BOOL:
        !          1537:                        if (Z_LVAL_PP(arg)) {
        !          1538:                                TRACE_APPEND_STR("true, ");
        !          1539:                        } else {
        !          1540:                                TRACE_APPEND_STR("false, ");
        !          1541:                        }
        !          1542:                        break;
        !          1543:                case IS_RESOURCE:
        !          1544:                        TRACE_APPEND_STR("Resource id #");
        !          1545:                        /* break; */
        !          1546:                case IS_LONG: {
        !          1547:                        long lval = Z_LVAL_PP(arg);
        !          1548:                        char s_tmp[MAX_LENGTH_OF_LONG + 1];
        !          1549:                        int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
        !          1550:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !          1551:                        TRACE_APPEND_STR(", ");
        !          1552:                        break;
        !          1553:                }
        !          1554:                case IS_DOUBLE: {
        !          1555:                        double dval = Z_DVAL_PP(arg);
        !          1556:                        char *s_tmp;
        !          1557:                        int l_tmp;
        !          1558: 
        !          1559:                        s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
        !          1560:                        l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
        !          1561:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !          1562:                        /* %G already handles removing trailing zeros from the fractional part, yay */
        !          1563:                        efree(s_tmp);
        !          1564:                        TRACE_APPEND_STR(", ");
        !          1565:                        break;
        !          1566:                }
        !          1567:                case IS_ARRAY:
        !          1568:                        TRACE_APPEND_STR("Array, ");
        !          1569:                        break;
        !          1570:                case IS_OBJECT: {
        !          1571:                        zval tmp;
        !          1572:                        zstr class_name;
        !          1573:                        zend_uint class_name_len;
        !          1574:                        int dup;
        !          1575: 
        !          1576:                        TRACE_APPEND_STR("Object(");
        !          1577: 
        !          1578:                        dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
        !          1579: 
        !          1580:                        ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
        !          1581:                        convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv)));
        !          1582:                        TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
        !          1583:                        zval_dtor(&tmp);
        !          1584: 
        !          1585:                        if(!dup) {
        !          1586:                                efree(class_name.v);
        !          1587:                        }
        !          1588: 
        !          1589:                        TRACE_APPEND_STR("), ");
        !          1590:                        break;
        !          1591:                }
        !          1592:                default:
        !          1593:                        break;
        !          1594:        }
        !          1595:        return ZEND_HASH_APPLY_KEEP;
        !          1596: }
        !          1597: /* }}} */
        !          1598: 
        !          1599: 
        !          1600: static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
        !          1601: {
        !          1602:        char *s_tmp, **str;
        !          1603:        int *len, *num;
        !          1604:        long line;
        !          1605:        HashTable *ht = Z_ARRVAL_PP(frame);
        !          1606:        zval **file, **tmp;
        !          1607:        uint * level;
        !          1608: 
        !          1609:        level = va_arg(args, uint *);
        !          1610:        str = va_arg(args, char**);
        !          1611:        len = va_arg(args, int*);
        !          1612:        num = va_arg(args, int*);
        !          1613: 
        !          1614:        if (!*level) {
        !          1615:                return ZEND_HASH_APPLY_KEEP;
        !          1616:        }
        !          1617:        --*level;
        !          1618: 
        !          1619:        s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
        !          1620:        sprintf(s_tmp, "#%d ", (*num)++);
        !          1621:        TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !          1622:        efree(s_tmp);
        !          1623:        if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
        !          1624:                if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
        !          1625:                        line = Z_LVAL_PP(tmp);
        !          1626:                } else {
        !          1627:                        line = 0;
        !          1628:                }
        !          1629:                TRACE_APPEND_ZVAL(*file);
        !          1630:                s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
        !          1631:                sprintf(s_tmp, "(%ld): ", line);
        !          1632:                TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !          1633:                efree(s_tmp);
        !          1634:        } else {
        !          1635:                TRACE_APPEND_STR("[internal function]: ");
        !          1636:        }
        !          1637:        TRACE_APPEND_KEY("class");
        !          1638:        TRACE_APPEND_KEY("type");
        !          1639:        TRACE_APPEND_KEY("function");
        !          1640:        TRACE_APPEND_CHR('(');
        !          1641:        if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
        !          1642:                int last_len = *len;
        !          1643:                zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
        !          1644:                if (last_len != *len) {
        !          1645:                        *len -= 2; /* remove last ', ' */
        !          1646:                }
        !          1647:        }
        !          1648:        TRACE_APPEND_STR(")\n");
        !          1649:        return ZEND_HASH_APPLY_KEEP;
        !          1650: }
        !          1651: /* }}} */
        !          1652: 
        !          1653: 
        !          1654: #else /* PHP 5*/
        !          1655: 
        !          1656: 
        !          1657: /* {{{ gettraceasstring() macros */
        !          1658: #define TRACE_APPEND_CHR(chr)                                            \
        !          1659:        *str = (char*)erealloc(*str, *len + 1 + 1);                          \
        !          1660:        (*str)[(*len)++] = chr
        !          1661: 
        !          1662: #define TRACE_APPEND_STRL(val, vallen)                                   \
        !          1663:        {                                                                    \
        !          1664:                int l = vallen;                                                  \
        !          1665:                *str = (char*)erealloc(*str, *len + l + 1);                      \
        !          1666:                memcpy((*str) + *len, val, l);                                   \
        !          1667:                *len += l;                                                       \
        !          1668:        }
        !          1669: 
        !          1670: #define TRACE_APPEND_STR(val)                                            \
        !          1671:        TRACE_APPEND_STRL(val, sizeof(val)-1)
        !          1672: 
        !          1673: #define TRACE_APPEND_KEY(key)                                            \
        !          1674:        if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
        !          1675:            TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
        !          1676:        }
        !          1677: 
        !          1678: /* }}} */
        !          1679: 
        !          1680: 
        !          1681: static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
        !          1682: {
        !          1683:        char **str;
        !          1684:        int *len;
        !          1685: 
        !          1686:        str = va_arg(args, char**);
        !          1687:        len = va_arg(args, int*);
        !          1688: 
        !          1689:        /* the trivial way would be to do:
        !          1690:         * conver_to_string_ex(arg);
        !          1691:         * append it and kill the now tmp arg.
        !          1692:         * but that could cause some E_NOTICE and also damn long lines.
        !          1693:         */
        !          1694: 
        !          1695:        switch (Z_TYPE_PP(arg)) {
        !          1696:                case IS_NULL:
        !          1697:                        TRACE_APPEND_STR("NULL, ");
        !          1698:                        break;
        !          1699:                case IS_STRING: {
        !          1700:                        int l_added;
        !          1701:                        TRACE_APPEND_CHR('\'');
        !          1702:                        if (Z_STRLEN_PP(arg) > 15) {
        !          1703:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
        !          1704:                                TRACE_APPEND_STR("...', ");
        !          1705:                                l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
        !          1706:                        } else {
        !          1707:                                l_added = Z_STRLEN_PP(arg);
        !          1708:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
        !          1709:                                TRACE_APPEND_STR("', ");
        !          1710:                                l_added += 3 + 1;
        !          1711:                        }
        !          1712:                        while (--l_added) {
        !          1713:                                if ((*str)[*len - l_added] < 32) {
        !          1714:                                        (*str)[*len - l_added] = '?';
        !          1715:                                }
        !          1716:                        }
        !          1717:                        break;
        !          1718:                }
        !          1719:                case IS_BOOL:
        !          1720:                        if (Z_LVAL_PP(arg)) {
        !          1721:                                TRACE_APPEND_STR("true, ");
        !          1722:                        } else {
        !          1723:                                TRACE_APPEND_STR("false, ");
        !          1724:                        }
        !          1725:                        break;
        !          1726:                case IS_RESOURCE:
        !          1727:                        TRACE_APPEND_STR("Resource id #");
        !          1728:                        /* break; */
        !          1729:                case IS_LONG: {
        !          1730:                        long lval = Z_LVAL_PP(arg);
        !          1731:                        char s_tmp[MAX_LENGTH_OF_LONG + 1];
        !          1732:                        int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
        !          1733:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !          1734:                        TRACE_APPEND_STR(", ");
        !          1735:                        break;
        !          1736:                }
        !          1737:                case IS_DOUBLE: {
        !          1738:                        double dval = Z_DVAL_PP(arg);
        !          1739:                        char *s_tmp;
        !          1740:                        int l_tmp;
        !          1741: 
        !          1742:                        s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
        !          1743:                        l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
        !          1744:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !          1745:                        /* %G already handles removing trailing zeros from the fractional part, yay */
        !          1746:                        efree(s_tmp);
        !          1747:                        TRACE_APPEND_STR(", ");
        !          1748:                        break;
        !          1749:                }
        !          1750:                case IS_ARRAY:
        !          1751:                        TRACE_APPEND_STR("Array, ");
        !          1752:                        break;
        !          1753:                case IS_OBJECT: {
        !          1754:                        char *class_name;
        !          1755:                        zend_uint class_name_len;
        !          1756:                        int dupl;
        !          1757: 
        !          1758:                        TRACE_APPEND_STR("Object(");
        !          1759: 
        !          1760:                        dupl = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
        !          1761: 
        !          1762:                        TRACE_APPEND_STRL(class_name, class_name_len);
        !          1763:                        if (!dupl) {
        !          1764:                                efree(class_name);
        !          1765:                        }
        !          1766: 
        !          1767:                        TRACE_APPEND_STR("), ");
        !          1768:                        break;
        !          1769:                }
        !          1770:                default:
        !          1771:                        break;
        !          1772:        }
        !          1773:        return ZEND_HASH_APPLY_KEEP;
        !          1774: }
        !          1775: /* }}} */
        !          1776: 
        !          1777: static int mysqlnd_build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
        !          1778: {
        !          1779:        char *s_tmp, **str;
        !          1780:        int *len, *num;
        !          1781:        long line;
        !          1782:        HashTable *ht = Z_ARRVAL_PP(frame);
        !          1783:        zval **file, **tmp;
        !          1784:        uint * level;
        !          1785: 
        !          1786:        level = va_arg(args, uint *);
        !          1787:        str = va_arg(args, char**);
        !          1788:        len = va_arg(args, int*);
        !          1789:        num = va_arg(args, int*);
        !          1790: 
        !          1791:        if (!*level) {
        !          1792:                return ZEND_HASH_APPLY_KEEP;
        !          1793:        }
        !          1794:        --*level;
        !          1795: 
        !          1796:        s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
        !          1797:        sprintf(s_tmp, "#%d ", (*num)++);
        !          1798:        TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !          1799:        efree(s_tmp);
        !          1800:        if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
        !          1801:                if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
        !          1802:                        line = Z_LVAL_PP(tmp);
        !          1803:                } else {
        !          1804:                        line = 0;
        !          1805:                }
        !          1806:                s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
        !          1807:                sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
        !          1808:                TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !          1809:                efree(s_tmp);
        !          1810:        } else {
        !          1811:                TRACE_APPEND_STR("[internal function]: ");
        !          1812:        }
        !          1813:        TRACE_APPEND_KEY("class");
        !          1814:        TRACE_APPEND_KEY("type");
        !          1815:        TRACE_APPEND_KEY("function");
        !          1816:        TRACE_APPEND_CHR('(');
        !          1817:        if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
        !          1818:                int last_len = *len;
        !          1819:                zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
        !          1820:                if (last_len != *len) {
        !          1821:                        *len -= 2; /* remove last ', ' */
        !          1822:                }
        !          1823:        }
        !          1824:        TRACE_APPEND_STR(")\n");
        !          1825:        return ZEND_HASH_APPLY_KEEP;
        !          1826: }
        !          1827: /* }}} */
        !          1828: #endif
        !          1829: 
        !          1830: 
        !          1831: PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC)
        !          1832: {
        !          1833:        zval *trace;
        !          1834:        char *res = estrdup(""), **str = &res, *s_tmp;
        !          1835:        int res_len = 0, *len = &res_len, num = 0;
        !          1836:        if (max_levels == 0) {
        !          1837:                max_levels = 99999;
        !          1838:        }
        !          1839: 
        !          1840:        MAKE_STD_ZVAL(trace);
        !          1841:        zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
        !          1842: 
        !          1843:        zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC, (apply_func_args_t)mysqlnd_build_trace_string, 4, &max_levels, str, len, &num);
        !          1844:        zval_ptr_dtor(&trace);
        !          1845: 
        !          1846:        if (max_levels) {
        !          1847:                s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
        !          1848:                sprintf(s_tmp, "#%d {main}", num);
        !          1849:                TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !          1850:                efree(s_tmp);
        !          1851:        }
        !          1852: 
        !          1853:        res[res_len] = '\0';
        !          1854:        *length = res_len;
        !          1855: 
        !          1856:        return res;
        !          1857: }
        !          1858: 
        !          1859: /*
        !          1860:  * Local variables:
        !          1861:  * tab-width: 4
        !          1862:  * c-basic-offset: 4
        !          1863:  * End:
        !          1864:  * vim600: noet sw=4 ts=4 fdm=marker
        !          1865:  * vim<600: noet sw=4 ts=4
        !          1866:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>