Annotation of embedaddon/php/ext/sybase_ct/php_sybase_ct.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-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: Zeev Suraski <zeev@zend.com>                                |
        !            16:    |          Tom May <tom@go2net.com>                                    |
        !            17:    |          Timm Friebe <php_sybase_ct@thekid.de>                       |
        !            18:    +----------------------------------------------------------------------+
        !            19:  */
        !            20: 
        !            21: /* $Id: php_sybase_ct.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            22: 
        !            23: 
        !            24: #ifdef HAVE_CONFIG_H
        !            25: #include "config.h"
        !            26: #endif
        !            27: 
        !            28: #include "php.h"
        !            29: #include "php_sybase_ct.h"
        !            30: #include "ext/standard/php_standard.h"
        !            31: #include "ext/standard/info.h"
        !            32: #include "php_globals.h"
        !            33: #include "php_ini.h"
        !            34: 
        !            35: /* True globals, no need for thread safety */
        !            36: static int le_link, le_plink, le_result;
        !            37: 
        !            38: #if HAVE_SYBASE_CT
        !            39: 
        !            40: ZEND_DECLARE_MODULE_GLOBALS(sybase)
        !            41: static PHP_GINIT_FUNCTION(sybase);
        !            42: static PHP_GSHUTDOWN_FUNCTION(sybase);
        !            43: 
        !            44: /* {{{ arginfo */
        !            45: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_connect, 0, 0, 0)
        !            46:        ZEND_ARG_INFO(0, host)
        !            47:        ZEND_ARG_INFO(0, user)
        !            48:        ZEND_ARG_INFO(0, password)
        !            49:        ZEND_ARG_INFO(0, charset)
        !            50:        ZEND_ARG_INFO(0, appname)
        !            51:        ZEND_ARG_INFO(0, new)
        !            52: ZEND_END_ARG_INFO()
        !            53: 
        !            54: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_pconnect, 0, 0, 0)
        !            55:        ZEND_ARG_INFO(0, host)
        !            56:        ZEND_ARG_INFO(0, user)
        !            57:        ZEND_ARG_INFO(0, password)
        !            58:        ZEND_ARG_INFO(0, charset)
        !            59:        ZEND_ARG_INFO(0, appname)
        !            60: ZEND_END_ARG_INFO()
        !            61: 
        !            62: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_close, 0, 0, 0)
        !            63:        ZEND_ARG_INFO(0, link_id)
        !            64: ZEND_END_ARG_INFO()
        !            65: 
        !            66: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_select_db, 0, 0, 1)
        !            67:        ZEND_ARG_INFO(0, database)
        !            68:        ZEND_ARG_INFO(0, link_id)
        !            69: ZEND_END_ARG_INFO()
        !            70: 
        !            71: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_query, 0, 0, 1)
        !            72:        ZEND_ARG_INFO(0, query)
        !            73:        ZEND_ARG_INFO(0, link_id)
        !            74: ZEND_END_ARG_INFO()
        !            75: 
        !            76: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_unbuffered_query, 0, 0, 1)
        !            77:        ZEND_ARG_INFO(0, query)
        !            78:        ZEND_ARG_INFO(0, link_id)
        !            79: ZEND_END_ARG_INFO()
        !            80: 
        !            81: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_free_result, 0, 0, 1)
        !            82:        ZEND_ARG_INFO(0, result)
        !            83: ZEND_END_ARG_INFO()
        !            84: 
        !            85: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_get_last_message, 0, 0, 1)
        !            86:        ZEND_ARG_INFO(0, d)
        !            87: ZEND_END_ARG_INFO()
        !            88: 
        !            89: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_num_rows, 0, 0, 1)
        !            90:        ZEND_ARG_INFO(0, result)
        !            91: ZEND_END_ARG_INFO()
        !            92: 
        !            93: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_num_fields, 0, 0, 1)
        !            94:        ZEND_ARG_INFO(0, result)
        !            95: ZEND_END_ARG_INFO()
        !            96: 
        !            97: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_row, 0, 0, 1)
        !            98:        ZEND_ARG_INFO(0, result)
        !            99: ZEND_END_ARG_INFO()
        !           100: 
        !           101: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_object, 0, 0, 1)
        !           102:        ZEND_ARG_INFO(0, result)
        !           103:        ZEND_ARG_INFO(0, object)
        !           104: ZEND_END_ARG_INFO()
        !           105: 
        !           106: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_array, 0, 0, 1)
        !           107:        ZEND_ARG_INFO(0, result)
        !           108: ZEND_END_ARG_INFO()
        !           109: 
        !           110: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_assoc, 0, 0, 1)
        !           111:        ZEND_ARG_INFO(0, result)
        !           112: ZEND_END_ARG_INFO()
        !           113: 
        !           114: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_data_seek, 0, 0, 2)
        !           115:        ZEND_ARG_INFO(0, result)
        !           116:        ZEND_ARG_INFO(0, offset)
        !           117: ZEND_END_ARG_INFO()
        !           118: 
        !           119: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_field, 0, 0, 1)
        !           120:        ZEND_ARG_INFO(0, result)
        !           121:        ZEND_ARG_INFO(0, offset)
        !           122: ZEND_END_ARG_INFO()
        !           123: 
        !           124: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_field_seek, 0, 0, 2)
        !           125:        ZEND_ARG_INFO(0, result)
        !           126:        ZEND_ARG_INFO(0, offset)
        !           127: ZEND_END_ARG_INFO()
        !           128: 
        !           129: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_result, 0, 0, 3)
        !           130:        ZEND_ARG_INFO(0, result)
        !           131:        ZEND_ARG_INFO(0, row)
        !           132:        ZEND_ARG_INFO(0, field)
        !           133: ZEND_END_ARG_INFO()
        !           134: 
        !           135: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_affected_rows, 0, 0, 0)
        !           136:        ZEND_ARG_INFO(0, link_id)
        !           137: ZEND_END_ARG_INFO()
        !           138: 
        !           139: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_min_client_severity, 0, 0, 1)
        !           140:        ZEND_ARG_INFO(0, severity)
        !           141: ZEND_END_ARG_INFO()
        !           142: 
        !           143: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_min_server_severity, 0, 0, 1)
        !           144:        ZEND_ARG_INFO(0, severity)
        !           145: ZEND_END_ARG_INFO()
        !           146: 
        !           147: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_deadlock_retry_count, 0, 0, 1)
        !           148:        ZEND_ARG_INFO(0, retry_count)
        !           149: ZEND_END_ARG_INFO()
        !           150: 
        !           151: ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_set_message_handler, 0, 0, 1)
        !           152:        ZEND_ARG_INFO(0, error_func)
        !           153:        ZEND_ARG_INFO(0, connection)
        !           154: ZEND_END_ARG_INFO()
        !           155: /* }}} */
        !           156: 
        !           157: const zend_function_entry sybase_functions[] = {
        !           158:        PHP_FE(sybase_connect,                          arginfo_sybase_connect)
        !           159:        PHP_FE(sybase_pconnect,                         arginfo_sybase_pconnect)
        !           160:        PHP_FE(sybase_close,                            arginfo_sybase_close)
        !           161:        PHP_FE(sybase_select_db,                        arginfo_sybase_select_db)
        !           162:        PHP_FE(sybase_query,                            arginfo_sybase_query)
        !           163:        PHP_FE(sybase_unbuffered_query,         arginfo_sybase_unbuffered_query)
        !           164:        PHP_FE(sybase_free_result,                      arginfo_sybase_free_result)
        !           165:        PHP_FE(sybase_get_last_message,         arginfo_sybase_get_last_message)
        !           166:        PHP_FE(sybase_num_rows,                         arginfo_sybase_num_rows)
        !           167:        PHP_FE(sybase_num_fields,                       arginfo_sybase_num_fields)
        !           168:        PHP_FE(sybase_fetch_row,                        arginfo_sybase_fetch_row)
        !           169:        PHP_FE(sybase_fetch_array,                      arginfo_sybase_fetch_array)
        !           170:        PHP_FE(sybase_fetch_assoc,                      arginfo_sybase_fetch_assoc)
        !           171:        PHP_FE(sybase_fetch_object,                     arginfo_sybase_fetch_object)
        !           172:        PHP_FE(sybase_data_seek,                        arginfo_sybase_data_seek)
        !           173:        PHP_FE(sybase_fetch_field,                      arginfo_sybase_fetch_field)
        !           174:        PHP_FE(sybase_field_seek,                       arginfo_sybase_field_seek)
        !           175:        PHP_FE(sybase_result,                           arginfo_sybase_result)
        !           176:        PHP_FE(sybase_affected_rows,            arginfo_sybase_affected_rows)
        !           177:        PHP_FE(sybase_min_client_severity,      arginfo_sybase_min_client_severity)
        !           178:        PHP_FE(sybase_min_server_severity,      arginfo_sybase_min_server_severity)
        !           179:        PHP_FE(sybase_set_message_handler,      arginfo_sybase_set_message_handler)
        !           180:        PHP_FE(sybase_deadlock_retry_count, arginfo_sybase_deadlock_retry_count)
        !           181: 
        !           182: #if !defined(PHP_WIN32) && !defined(HAVE_MSSQL)
        !           183:        PHP_FALIAS(mssql_connect,       sybase_connect,         arginfo_sybase_connect)
        !           184:        PHP_FALIAS(mssql_pconnect,      sybase_pconnect,        arginfo_sybase_pconnect)
        !           185:        PHP_FALIAS(mssql_close,         sybase_close,           arginfo_sybase_close)
        !           186:        PHP_FALIAS(mssql_select_db, sybase_select_db,   arginfo_sybase_select_db)
        !           187:        PHP_FALIAS(mssql_query,         sybase_query,           arginfo_sybase_query)
        !           188:        PHP_FALIAS(mssql_unbuffered_query,      sybase_unbuffered_query,        arginfo_sybase_unbuffered_query)
        !           189:        PHP_FALIAS(mssql_free_result,           sybase_free_result,             arginfo_sybase_free_result)
        !           190:        PHP_FALIAS(mssql_get_last_message,      sybase_get_last_message,        arginfo_sybase_get_last_message)
        !           191:        PHP_FALIAS(mssql_num_rows,              sybase_num_rows,                arginfo_sybase_num_rows)
        !           192:        PHP_FALIAS(mssql_num_fields,    sybase_num_fields,              arginfo_sybase_num_fields)
        !           193:        PHP_FALIAS(mssql_fetch_row,     sybase_fetch_row,               arginfo_sybase_fetch_row)
        !           194:        PHP_FALIAS(mssql_fetch_array,   sybase_fetch_array,     arginfo_sybase_fetch_array)
        !           195:        PHP_FALIAS(mssql_fetch_assoc,   sybase_fetch_assoc,     arginfo_sybase_fetch_assoc)
        !           196:        PHP_FALIAS(mssql_fetch_object,  sybase_fetch_object,    arginfo_sybase_fetch_object)
        !           197:        PHP_FALIAS(mssql_data_seek,     sybase_data_seek,               arginfo_sybase_data_seek)
        !           198:        PHP_FALIAS(mssql_fetch_field,   sybase_fetch_field,     arginfo_sybase_fetch_field)
        !           199:        PHP_FALIAS(mssql_field_seek,    sybase_field_seek,              arginfo_sybase_field_seek)
        !           200:        PHP_FALIAS(mssql_result,                sybase_result,                  arginfo_sybase_result)
        !           201:        PHP_FALIAS(mssql_affected_rows, sybase_affected_rows,   arginfo_sybase_affected_rows)
        !           202:        PHP_FALIAS(mssql_min_client_severity,   sybase_min_client_severity,     arginfo_sybase_min_client_severity)
        !           203:        PHP_FALIAS(mssql_min_server_severity,   sybase_min_server_severity,     arginfo_sybase_min_server_severity)
        !           204:        PHP_FALIAS(mssql_set_message_handler,   sybase_set_message_handler,     arginfo_sybase_set_message_handler)
        !           205:        PHP_FALIAS(mssql_deadlock_retry_count,  sybase_deadlock_retry_count,    arginfo_sybase_deadlock_retry_count)
        !           206: #endif
        !           207:        PHP_FE_END
        !           208: };
        !           209: 
        !           210: zend_module_entry sybase_module_entry = {
        !           211:        STANDARD_MODULE_HEADER,
        !           212:        "sybase_ct",
        !           213:        sybase_functions,
        !           214:        PHP_MINIT(sybase),
        !           215:        PHP_MSHUTDOWN(sybase),
        !           216:        PHP_RINIT(sybase),
        !           217:        PHP_RSHUTDOWN(sybase),
        !           218:        PHP_MINFO(sybase),
        !           219:        NO_VERSION_YET,
        !           220:        PHP_MODULE_GLOBALS(sybase),
        !           221:        PHP_GINIT(sybase),
        !           222:        PHP_GSHUTDOWN(sybase),
        !           223:        NULL,
        !           224:        STANDARD_MODULE_PROPERTIES_EX
        !           225: };
        !           226: 
        !           227: /* static CS_CONTEXT *context; */
        !           228: 
        !           229: #ifdef COMPILE_DL_SYBASE_CT
        !           230: ZEND_GET_MODULE(sybase)
        !           231: #endif
        !           232: 
        !           233: ZEND_DECLARE_MODULE_GLOBALS(sybase)
        !           234: 
        !           235: #define CHECK_LINK(link) { if (link==-1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  A link to the server could not be established"); RETURN_FALSE; } }
        !           236: 
        !           237: 
        !           238: static int _clean_invalid_results(zend_rsrc_list_entry *le TSRMLS_DC)
        !           239: {
        !           240:        if (Z_TYPE_P(le) == le_result) {
        !           241:                sybase_link *sybase_ptr = ((sybase_result *) le->ptr)->sybase_ptr;
        !           242: 
        !           243:                if (!sybase_ptr->valid) {
        !           244:                        return 1;
        !           245:                }
        !           246:        }
        !           247:        return 0;
        !           248: }
        !           249: 
        !           250: #define efree_n(x)  { efree(x); x = NULL; }
        !           251: #define efree_if(x) if (x) efree_n(x)
        !           252: 
        !           253: #ifdef PHP_SYBASE_DEBUG
        !           254: #define FREE_SYBASE_RESULT(result)                                                            \
        !           255:        if (result) {                                                                             \
        !           256:            fprintf(stderr, "_free_sybase_result(%p) called from line #%d\n", result, __LINE__);  \
        !           257:                fflush(stderr);                                                                       \
        !           258:                _free_sybase_result(result);                                                          \
        !           259:                result = NULL;                                                                        \
        !           260:        }
        !           261: #else
        !           262: #define FREE_SYBASE_RESULT(result)                                                            \
        !           263:        if (result) {                                                                             \
        !           264:                _free_sybase_result(result);                                                          \
        !           265:                result = NULL;                                                                        \
        !           266:        }
        !           267: #endif
        !           268: static void _free_sybase_result(sybase_result *result)
        !           269: {
        !           270:        int i, j;
        !           271: 
        !           272:        if (result->data) {
        !           273:                for (i = 0; i < (result->store ? result->num_rows : MIN(1, result->num_rows)); i++) {
        !           274:                        for (j=0; j<result->num_fields; j++) {
        !           275:                                zval_dtor(&result->data[i][j]);
        !           276:                        }
        !           277:                        efree(result->data[i]);
        !           278:                }
        !           279:                efree(result->data);
        !           280:        }
        !           281: 
        !           282:        if (result->fields) {
        !           283:                for (i=0; i<result->num_fields; i++) {
        !           284:                        STR_FREE(result->fields[i].name);
        !           285:                        STR_FREE(result->fields[i].column_source);
        !           286:                }
        !           287:                efree(result->fields);
        !           288:        }
        !           289: 
        !           290:        if (result->tmp_buffer) {
        !           291:                for (i=0; i<result->num_fields; i++) {
        !           292:                        efree(result->tmp_buffer[i]);
        !           293:                }
        !           294:                efree(result->tmp_buffer);
        !           295:        }
        !           296: 
        !           297:        efree_if(result->lengths);
        !           298:        efree_if(result->indicators);
        !           299:        efree_if(result->datafmt);
        !           300:        efree_if(result->numerics);
        !           301:        efree_if(result->types);
        !           302: 
        !           303:        efree(result);
        !           304: }
        !           305: 
        !           306: /* Forward declaration */
        !           307: static int php_sybase_finish_results (sybase_result *result TSRMLS_DC);
        !           308: 
        !           309: static void php_free_sybase_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        !           310: {
        !           311:        sybase_result *result = (sybase_result *)rsrc->ptr;
        !           312: 
        !           313:        /* Check to see if we've read all rows */
        !           314:        if (result->sybase_ptr && result->sybase_ptr->active_result_index) {
        !           315:                if (result->sybase_ptr->cmd) {
        !           316:                        ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
        !           317:                }
        !           318:                php_sybase_finish_results(result TSRMLS_CC);
        !           319:        }
        !           320: 
        !           321:        FREE_SYBASE_RESULT(result);
        !           322: }
        !           323: 
        !           324: static void _close_sybase_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        !           325: {
        !           326:        sybase_link *sybase_ptr = (sybase_link *)rsrc->ptr;
        !           327:        CS_INT con_status;
        !           328: 
        !           329:        sybase_ptr->valid = 0;
        !           330:        if (sybase_ptr->callback_name != NULL) {
        !           331:                zval_ptr_dtor(&sybase_ptr->callback_name);
        !           332:                sybase_ptr->callback_name= NULL;
        !           333:        }
        !           334:        zend_hash_apply(&EG(regular_list), (apply_func_t) _clean_invalid_results TSRMLS_CC);
        !           335: 
        !           336:        /* Non-persistent connections will always be connected or we wouldn't
        !           337:         * get here, but since we want to check the death status anyway
        !           338:         * we might as well double-check the connect status.
        !           339:         */
        !           340:        if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
        !           341:                                         &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           342:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status on close");
        !           343:                /* Assume the worst. */
        !           344:                con_status = CS_CONSTAT_CONNECTED | CS_CONSTAT_DEAD;
        !           345:        }
        !           346:        if (con_status & CS_CONSTAT_CONNECTED) {
        !           347:                if ((con_status & CS_CONSTAT_DEAD) || ct_close(sybase_ptr->connection, CS_UNUSED)!=CS_SUCCEED) {
        !           348:                        ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
        !           349:                }
        !           350:        }
        !           351: 
        !           352:        ct_cmd_drop(sybase_ptr->cmd);
        !           353:        ct_con_drop(sybase_ptr->connection);
        !           354:        efree(sybase_ptr);
        !           355:        SybCtG(num_links)--;
        !           356: }
        !           357: 
        !           358: 
        !           359: static void _close_sybase_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        !           360: {
        !           361:        sybase_link *sybase_ptr = (sybase_link *)rsrc->ptr;
        !           362:        CS_INT con_status;
        !           363: 
        !           364:        /* Persistent connections may have been closed before a failed
        !           365:         * reopen attempt.
        !           366:         */
        !           367:        if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
        !           368:                                         &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           369:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status on close");
        !           370:                /* Assume the worst. */
        !           371:                con_status = CS_CONSTAT_CONNECTED | CS_CONSTAT_DEAD;
        !           372:        }
        !           373:        if (con_status & CS_CONSTAT_CONNECTED) {
        !           374:                if ((con_status & CS_CONSTAT_DEAD) || ct_close(sybase_ptr->connection, CS_UNUSED)!=CS_SUCCEED) {
        !           375:                        ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
        !           376:                }
        !           377:        }
        !           378: 
        !           379:        ct_con_drop(sybase_ptr->connection);
        !           380:        free(sybase_ptr);
        !           381:        SybCtG(num_persistent)--;
        !           382:        SybCtG(num_links)--;
        !           383: }
        !           384: 
        !           385: 
        !           386: static CS_RETCODE CS_PUBLIC _client_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_CLIENTMSG *errmsg)
        !           387: {
        !           388:        TSRMLS_FETCH();
        !           389: 
        !           390:        if (CS_SEVERITY(errmsg->msgnumber) >= SybCtG(min_client_severity)) {
        !           391:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Client message:  %s (severity %ld)", errmsg->msgstring, (long)CS_SEVERITY(errmsg->msgnumber));
        !           392:        }
        !           393:        STR_FREE(SybCtG(server_message));
        !           394:        SybCtG(server_message) = estrdup(errmsg->msgstring);
        !           395: 
        !           396: 
        !           397:        /* If this is a timeout message, return CS_FAIL to cancel the
        !           398:         * operation and mark the connection as dead.
        !           399:         */
        !           400:        if (CS_SEVERITY(errmsg->msgnumber) == CS_SV_RETRY_FAIL &&
        !           401:                CS_NUMBER(errmsg->msgnumber) == 63 &&
        !           402:                CS_ORIGIN(errmsg->msgnumber) == 2 &&
        !           403:                CS_LAYER(errmsg->msgnumber) == 1)
        !           404:        {
        !           405:                return CS_FAIL;
        !           406:        }
        !           407: 
        !           408:        return CS_SUCCEED;
        !           409: }
        !           410: 
        !           411: static int _call_message_handler(zval *callback_name, CS_SERVERMSG *srvmsg TSRMLS_DC)
        !           412: {
        !           413:        int handled = 0;
        !           414:        zval *msgnumber, *severity, *state, *line, *text, *retval = NULL;
        !           415:        zval **args[5];
        !           416: 
        !           417:        /* Border case - empty fcall */
        !           418:        if (NULL == callback_name) return 0;
        !           419: 
        !           420:        /* Build arguments */
        !           421:        MAKE_STD_ZVAL(msgnumber);
        !           422:        ZVAL_LONG(msgnumber, srvmsg->msgnumber);
        !           423:        args[0] = &msgnumber;
        !           424: 
        !           425:        MAKE_STD_ZVAL(severity);
        !           426:        ZVAL_LONG(severity, srvmsg->severity);
        !           427:        args[1] = &severity;
        !           428: 
        !           429:        MAKE_STD_ZVAL(state);
        !           430:        ZVAL_LONG(state, srvmsg->state);
        !           431:        args[2] = &state;
        !           432: 
        !           433:        MAKE_STD_ZVAL(line);
        !           434:        ZVAL_LONG(line, srvmsg->line);
        !           435:        args[3] = &line;
        !           436: 
        !           437:        MAKE_STD_ZVAL(text);    
        !           438:        ZVAL_STRING(text, srvmsg->text, 1);
        !           439:        args[4] = &text;
        !           440: 
        !           441:        if (call_user_function_ex(EG(function_table), NULL, callback_name, &retval, 5, args, 0, NULL TSRMLS_CC) == FAILURE) {
        !           442:                zval expr_copy;
        !           443:                int use_copy;
        !           444: 
        !           445:                zend_make_printable_zval(callback_name, &expr_copy, &use_copy);
        !           446:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot call the messagehandler %s", Z_STRVAL(expr_copy));
        !           447:                zval_dtor(&expr_copy);
        !           448:        }
        !           449: 
        !           450:        if (retval) {
        !           451:                handled = ((Z_TYPE_P(retval) != IS_BOOL) || (Z_BVAL_P(retval) != 0));
        !           452:                zval_ptr_dtor(&retval);
        !           453:        } else {
        !           454:                handled = 0;
        !           455:        }
        !           456: 
        !           457:        zval_ptr_dtor(&msgnumber);
        !           458:        zval_ptr_dtor(&severity);
        !           459:        zval_ptr_dtor(&state);
        !           460:        zval_ptr_dtor(&line);
        !           461:        zval_ptr_dtor(&text);
        !           462: 
        !           463:        return handled;
        !           464: }
        !           465: 
        !           466: static CS_RETCODE CS_PUBLIC _server_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_SERVERMSG *srvmsg)
        !           467: {
        !           468:        sybase_link *sybase;
        !           469:        int handled = 0;
        !           470:        TSRMLS_FETCH();
        !           471: 
        !           472:        /* Remember the last server message in any case */
        !           473:        STR_FREE(SybCtG(server_message));
        !           474:        SybCtG(server_message) = estrdup(srvmsg->text);
        !           475: 
        !           476:        /* Retrieve sybase link */
        !           477:        if (ct_con_props(connection, CS_GET, CS_USERDATA, &sybase, CS_SIZEOF(sybase), NULL) != CS_SUCCEED) {
        !           478:                sybase = NULL;
        !           479:        }
        !           480: 
        !           481:        /* If this is a deadlock message, set the connection's deadlock flag
        !           482:         * so we will retry the request.  Sorry about the bare constant here,
        !           483:         * but it's not defined anywhere and it's a "well-known" number.
        !           484:         */
        !           485:        if (sybase && (srvmsg->msgnumber == 1205)) {
        !           486:                sybase->deadlock = 1;
        !           487:        }
        !           488: 
        !           489:        /* Check mininum server severity level */
        !           490:        if (srvmsg->severity < SybCtG(min_server_severity)) {
        !           491:                return CS_SUCCEED;
        !           492:        }
        !           493: 
        !           494:        /* Call global message handler */
        !           495:        handled = handled | _call_message_handler(SybCtG(callback_name), srvmsg TSRMLS_CC);
        !           496: 
        !           497:        /* Call link specific message handler */
        !           498:        if (sybase) {
        !           499:                handled = handled | _call_message_handler(sybase->callback_name, srvmsg TSRMLS_CC);
        !           500:        }
        !           501: 
        !           502:        /* Spit out a warning if neither of them has handled this message */
        !           503:        if (!handled) {
        !           504:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Server message:  %s (severity %ld, procedure %s)",
        !           505:                                srvmsg->text, (long)srvmsg->severity, ((srvmsg->proclen>0) ? srvmsg->proc : "N/A"));
        !           506:        }
        !           507: 
        !           508:        return CS_SUCCEED;
        !           509: }
        !           510: 
        !           511: 
        !           512: PHP_INI_BEGIN()
        !           513:        STD_PHP_INI_BOOLEAN("sybct.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_sybase_globals, sybase_globals)
        !           514:        STD_PHP_INI_ENTRY_EX("sybct.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_sybase_globals, sybase_globals, display_link_numbers)
        !           515:        STD_PHP_INI_ENTRY_EX("sybct.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_sybase_globals, sybase_globals, display_link_numbers)
        !           516:        STD_PHP_INI_ENTRY("sybct.min_server_severity", "10", PHP_INI_ALL, OnUpdateLong, min_server_severity, zend_sybase_globals, sybase_globals)
        !           517:        STD_PHP_INI_ENTRY("sybct.min_client_severity", "10", PHP_INI_ALL, OnUpdateLong, min_client_severity, zend_sybase_globals, sybase_globals)
        !           518:        STD_PHP_INI_ENTRY("sybct.login_timeout", "-1", PHP_INI_ALL, OnUpdateLong, login_timeout, zend_sybase_globals, sybase_globals)
        !           519:        STD_PHP_INI_ENTRY("sybct.hostname", NULL, PHP_INI_ALL, OnUpdateString, hostname, zend_sybase_globals, sybase_globals)
        !           520:        STD_PHP_INI_ENTRY_EX("sybct.deadlock_retry_count", "0", PHP_INI_ALL, OnUpdateLong, deadlock_retry_count, zend_sybase_globals, sybase_globals, display_link_numbers)
        !           521: PHP_INI_END()
        !           522: 
        !           523: 
        !           524: static PHP_GINIT_FUNCTION(sybase)
        !           525: {
        !           526:        long opt;
        !           527: 
        !           528:        if (cs_ctx_alloc(CTLIB_VERSION, &sybase_globals->context)!=CS_SUCCEED || ct_init(sybase_globals->context, CTLIB_VERSION)!=CS_SUCCEED) {
        !           529:                return;
        !           530:        }
        !           531: 
        !           532:        /* Initialize message handlers */
        !           533:        if (ct_callback(sybase_globals->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)_server_message_handler)!=CS_SUCCEED) {
        !           534:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set server message handler");
        !           535:        }
        !           536: 
        !           537:        if (ct_callback(sybase_globals->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)_client_message_handler)!=CS_SUCCEED) {
        !           538:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set client message handler");
        !           539:        }
        !           540: 
        !           541:        /* Set datetime conversion format to "Nov  3 1998  8:06PM".
        !           542:         * This is the default format for the ct-lib that comes with
        !           543:         * Sybase ASE 11.5.1 for Solaris, but the Linux libraries that
        !           544:         * come with 11.0.3.3 default to "03/11/98" which is singularly
        !           545:         * useless.  This levels the playing field for all platforms.
        !           546:         */
        !           547:        {
        !           548:                CS_INT dt_convfmt = CS_DATES_SHORT;
        !           549:                if (cs_dt_info(sybase_globals->context, CS_SET, NULL, CS_DT_CONVFMT, CS_UNUSED, &dt_convfmt, sizeof(dt_convfmt), NULL)!=CS_SUCCEED) {
        !           550:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set datetime conversion format");
        !           551:                }
        !           552:        }
        !           553: 
        !           554:        /* Set the timeout, which is per context and can't be set with 
        !           555:         * ct_con_props(), so set it globally from the config value if 
        !           556:         * requested.  The default is CS_NO_LIMIT.
        !           557:         * 
        !           558:         * Note that despite some noise in the documentation about using
        !           559:         * signals to implement timeouts, they are actually implemented
        !           560:         * by using poll() or select() on Solaris and Linux.
        !           561:         */
        !           562:        if (cfg_get_long("sybct.timeout", &opt)==SUCCESS) {
        !           563:                CS_INT cs_timeout = opt;
        !           564:                if (ct_config(sybase_globals->context, CS_SET, CS_TIMEOUT, &cs_timeout, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           565:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to update the timeout");
        !           566:                }
        !           567:        }
        !           568: 
        !           569:        sybase_globals->num_persistent=0;
        !           570:        sybase_globals->callback_name = NULL;
        !           571: }
        !           572: 
        !           573: 
        !           574: static PHP_GSHUTDOWN_FUNCTION(sybase)
        !           575: {
        !           576:        ct_exit(sybase_globals->context, CS_UNUSED);
        !           577:        cs_ctx_drop(sybase_globals->context);
        !           578: }
        !           579: 
        !           580: PHP_MINIT_FUNCTION(sybase)
        !           581: {
        !           582:        REGISTER_INI_ENTRIES();
        !           583: 
        !           584:        le_link = zend_register_list_destructors_ex(_close_sybase_link, NULL, "sybase-ct link", module_number);
        !           585:        le_plink = zend_register_list_destructors_ex(NULL, _close_sybase_plink, "sybase-ct link persistent", module_number);
        !           586:        le_result = zend_register_list_destructors_ex(php_free_sybase_result, NULL, "sybase-ct result", module_number);
        !           587: 
        !           588:        return SUCCESS;
        !           589: }
        !           590: 
        !           591: 
        !           592: 
        !           593: PHP_RINIT_FUNCTION(sybase)
        !           594: {
        !           595:        SybCtG(default_link)=-1;
        !           596:        SybCtG(num_links) = SybCtG(num_persistent);
        !           597:        SybCtG(appname) = estrndup("PHP " PHP_VERSION, sizeof("PHP " PHP_VERSION));
        !           598:        SybCtG(server_message) = STR_EMPTY_ALLOC();
        !           599:        return SUCCESS;
        !           600: }
        !           601: 
        !           602: 
        !           603: 
        !           604: PHP_MSHUTDOWN_FUNCTION(sybase)
        !           605: {
        !           606:        UNREGISTER_INI_ENTRIES();
        !           607: #if 0
        !           608:        ct_exit(context, CS_UNUSED);
        !           609:        cs_ctx_drop(context);
        !           610: #endif
        !           611:        return SUCCESS;
        !           612: }
        !           613: 
        !           614: 
        !           615: PHP_RSHUTDOWN_FUNCTION(sybase)
        !           616: {
        !           617:        efree(SybCtG(appname));
        !           618:        SybCtG(appname) = NULL;
        !           619:        if (SybCtG(callback_name)) {
        !           620:                zval_ptr_dtor(&SybCtG(callback_name));
        !           621:                SybCtG(callback_name)= NULL;
        !           622:        }
        !           623:        STR_FREE(SybCtG(server_message));
        !           624:        SybCtG(server_message) = NULL;
        !           625:        return SUCCESS;
        !           626: }
        !           627: 
        !           628: 
        !           629: static int php_sybase_do_connect_internal(sybase_link *sybase, char *host, char *user, char *passwd, char *charset, char *appname TSRMLS_DC)
        !           630: {
        !           631:        CS_LOCALE *tmp_locale;
        !           632:        long packetsize;
        !           633: 
        !           634:        /* set a CS_CONNECTION record */
        !           635:        if (ct_con_alloc(SybCtG(context), &sybase->connection)!=CS_SUCCEED) {
        !           636:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to allocate connection record");
        !           637:                return 0;
        !           638:        }
        !           639: 
        !           640:        /* Note - this saves a copy of sybase, not a pointer to it. */
        !           641:        if (ct_con_props(sybase->connection, CS_SET, CS_USERDATA, &sybase, CS_SIZEOF(sybase), NULL)!=CS_SUCCEED) {
        !           642:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set userdata");
        !           643:                ct_con_drop(sybase->connection);
        !           644:                return 0;
        !           645:        }
        !           646: 
        !           647:        if (user) {
        !           648:                ct_con_props(sybase->connection, CS_SET, CS_USERNAME, user, CS_NULLTERM, NULL);
        !           649:        }
        !           650:        if (passwd) {
        !           651:                ct_con_props(sybase->connection, CS_SET, CS_PASSWORD, passwd, CS_NULLTERM, NULL);
        !           652:        }
        !           653:        if (appname) {
        !           654:                ct_con_props(sybase->connection, CS_SET, CS_APPNAME, appname, CS_NULLTERM, NULL);
        !           655:        } else { 
        !           656:                ct_con_props(sybase->connection, CS_SET, CS_APPNAME, SybCtG(appname), CS_NULLTERM, NULL);
        !           657:        }
        !           658: 
        !           659:        if (SybCtG(hostname)) {
        !           660:                ct_con_props(sybase->connection, CS_SET, CS_HOSTNAME, SybCtG(hostname), CS_NULLTERM, NULL);
        !           661:        }
        !           662: 
        !           663:        if (charset) {
        !           664:                if (cs_loc_alloc(SybCtG(context), &tmp_locale)!=CS_SUCCEED) {
        !           665:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to allocate locale information");
        !           666:                } else {
        !           667:                        if (cs_locale(SybCtG(context), CS_SET, tmp_locale, CS_LC_ALL, NULL, CS_NULLTERM, NULL)!=CS_SUCCEED) {
        !           668:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to load default locale data");
        !           669:                        } else {
        !           670:                                if (cs_locale(SybCtG(context), CS_SET, tmp_locale, CS_SYB_CHARSET, charset, CS_NULLTERM, NULL)!=CS_SUCCEED) {
        !           671:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update character set");
        !           672:                                } else {
        !           673:                                        if (ct_con_props(sybase->connection, CS_SET, CS_LOC_PROP, tmp_locale, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           674:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update connection properties");
        !           675:                                        }
        !           676:                                }
        !           677:                        }
        !           678:                }
        !           679:        }
        !           680:        
        !           681:        if (cfg_get_long("sybct.packet_size", &packetsize) == SUCCESS) {
        !           682:                if (ct_con_props(sybase->connection, CS_SET, CS_PACKETSIZE, (CS_VOID *)&packetsize, CS_UNUSED, NULL) != CS_SUCCEED) {
        !           683:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update connection packetsize");
        !           684:                }
        !           685:        }
        !           686: 
        !           687:        /* Set the login timeout. Actually, the login timeout is per context
        !           688:         * and not per connection, but we will update the context here to 
        !           689:         * allow for code such as the following:
        !           690:         * 
        !           691:         *   ini_set('sybct.login_timeout', $timeout);
        !           692:         *   sybase_connect(...)
        !           693:         * 
        !           694:         * Note that preceding calls to sybase_connect() will now use the 
        !           695:         * updated value and not the default one!
        !           696:         * 
        !           697:         * The default value for CS_LOGIN_TIMEOUT is 60 (1 minute).
        !           698:         */
        !           699:        if (SybCtG(login_timeout) != -1) {
        !           700:                CS_INT cs_login_timeout = SybCtG(login_timeout);
        !           701:                if (ct_config(SybCtG(context), CS_SET, CS_LOGIN_TIMEOUT, &cs_login_timeout, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           702:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to update the login timeout");
        !           703:                }
        !           704:        }
        !           705: 
        !           706:        sybase->valid = 1;
        !           707:        sybase->dead = 0;
        !           708:        sybase->active_result_index = 0;
        !           709:        sybase->callback_name = NULL;
        !           710: 
        !           711:        /* create the link */
        !           712:        if (ct_connect(sybase->connection, host, CS_NULLTERM)!=CS_SUCCEED) {
        !           713:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to connect");
        !           714:                ct_con_drop(sybase->connection);
        !           715:                return 0;
        !           716:        }
        !           717: 
        !           718:        if (ct_cmd_alloc(sybase->connection, &sybase->cmd)!=CS_SUCCEED) {
        !           719:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to allocate command record");
        !           720:                ct_close(sybase->connection, CS_UNUSED);
        !           721:                ct_con_drop(sybase->connection);
        !           722:                return 0;
        !           723:        }
        !           724: 
        !           725:        return 1;
        !           726: }
        !           727: 
        !           728: 
        !           729: static void php_sybase_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
        !           730: {
        !           731:        char *user = NULL, *passwd = NULL, *host = NULL, *charset = NULL, *appname = NULL;
        !           732:        char *hashed_details;
        !           733:        int hashed_details_length, len;
        !           734:        zend_bool new = 0;
        !           735:        sybase_link *sybase_ptr;
        !           736: 
        !           737:        host= user= passwd= charset= appname= NULL;
        !           738:        if (persistent) {
        !           739:                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!s!s!", &host, &len, &user, &len, &passwd, &len, &charset, &len, &appname, &len) == FAILURE) {
        !           740:                        return;
        !           741:                }
        !           742:        } else {
        !           743:                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!s!s!b", &host, &len, &user, &len, &passwd, &len, &charset, &len, &appname, &len, &new) == FAILURE) {
        !           744:                        return;
        !           745:                }
        !           746:        }
        !           747:        hashed_details_length = spprintf(
        !           748:                &hashed_details, 
        !           749:                0, 
        !           750:                "sybase_%s_%s_%s_%s_%s",
        !           751:                host ? host : "", 
        !           752:                user ? user : "", 
        !           753:                passwd ? passwd : "", 
        !           754:                charset ? charset : "", 
        !           755:                appname ? appname : ""
        !           756:        );
        !           757: 
        !           758:        if (!SybCtG(allow_persistent)) {
        !           759:                persistent=0;
        !           760:        }
        !           761:        if (persistent) {
        !           762:                zend_rsrc_list_entry *le;
        !           763: 
        !           764:                /* try to find if we already have this link in our persistent list */
        !           765:                if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {  /* we don't */
        !           766:                        zend_rsrc_list_entry new_le;
        !           767: 
        !           768:                        if (SybCtG(max_links)!=-1 && SybCtG(num_links)>=SybCtG(max_links)) {
        !           769:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open links (%ld)", SybCtG(num_links));
        !           770:                                efree(hashed_details);
        !           771:                                RETURN_FALSE;
        !           772:                        }
        !           773:                        if (SybCtG(max_persistent)!=-1 && SybCtG(num_persistent)>=SybCtG(max_persistent)) {
        !           774:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open persistent links (%ld)", SybCtG(num_persistent));
        !           775:                                efree(hashed_details);
        !           776:                                RETURN_FALSE;
        !           777:                        }
        !           778: 
        !           779:                        sybase_ptr = (sybase_link *) malloc(sizeof(sybase_link));
        !           780:                        if (!sybase_ptr) {
        !           781:                                efree(hashed_details);
        !           782:                                RETURN_FALSE;
        !           783:                        }
        !           784:                        if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
        !           785:                                free(sybase_ptr);
        !           786:                                efree(hashed_details);
        !           787:                                RETURN_FALSE;
        !           788:                        }
        !           789: 
        !           790:                        /* hash it up */
        !           791:                        Z_TYPE(new_le) = le_plink;
        !           792:                        new_le.ptr = sybase_ptr;
        !           793:                        if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
        !           794:                                ct_close(sybase_ptr->connection, CS_UNUSED);
        !           795:                                ct_con_drop(sybase_ptr->connection);
        !           796:                                free(sybase_ptr);
        !           797:                                efree(hashed_details);
        !           798:                                RETURN_FALSE;
        !           799:                        }
        !           800:                        SybCtG(num_persistent)++;
        !           801:                        SybCtG(num_links)++;
        !           802:                } else {  /* we do */
        !           803:                        CS_INT con_status;
        !           804: 
        !           805:                        if (Z_TYPE_P(le) != le_plink) {
        !           806:                                efree(hashed_details);
        !           807:                                RETURN_FALSE;
        !           808:                        }
        !           809: 
        !           810:                        sybase_ptr = (sybase_link *) le->ptr;
        !           811: 
        !           812:                        /* If the link has died, close it and overwrite it with a new one. */
        !           813: 
        !           814:                        if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
        !           815:                                                         &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !           816:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status");
        !           817:                                efree(hashed_details);
        !           818:                                RETURN_FALSE;
        !           819:                        }
        !           820:                        if (!(con_status & CS_CONSTAT_CONNECTED) || (con_status & CS_CONSTAT_DEAD) || sybase_ptr->dead) {
        !           821:                                sybase_link sybase;
        !           822: 
        !           823:                                if (con_status & CS_CONSTAT_CONNECTED) {
        !           824:                                        ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
        !           825:                                }
        !           826:                                /* Create a new connection, then replace the old
        !           827:                                 * connection.  If we fail to create a new connection,
        !           828:                                 * put the old one back so there will be a connection,
        !           829:                                 * even if it is a non-functional one.  This is because
        !           830:                                 * code may still be holding an id for this connection
        !           831:                                 * so we can't free the CS_CONNECTION.
        !           832:                                 * (This is actually totally hokey, it would be better
        !           833:                                 * to just ct_con_drop() the connection and set
        !           834:                                 * sybase_ptr->connection to NULL, then test it for
        !           835:                                 * NULL before trying to use it elsewhere . . .)
        !           836:                                 */
        !           837:                                memcpy(&sybase, sybase_ptr, sizeof(sybase_link));
        !           838:                                if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
        !           839:                                        memcpy(sybase_ptr, &sybase, sizeof(sybase_link));
        !           840:                                        efree(hashed_details);
        !           841:                                        RETURN_FALSE;
        !           842:                                }
        !           843:                                ct_con_drop(sybase.connection); /* drop old connection */
        !           844:                        }
        !           845:                }
        !           846:                ZEND_REGISTER_RESOURCE(return_value, sybase_ptr, le_plink);
        !           847:        } else { /* non persistent */
        !           848:                zend_rsrc_list_entry *index_ptr, new_index_ptr;
        !           849: 
        !           850:                /* first we check the hash for the hashed_details key.  if it exists,
        !           851:                 * it should point us to the right offset where the actual sybase link sits.
        !           852:                 * if it doesn't, open a new sybase link, add it to the resource list,
        !           853:                 * and add a pointer to it with hashed_details as the key.
        !           854:                 */
        !           855:                if (!new && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length+1, (void **) &index_ptr)==SUCCESS) {
        !           856:                        int type, link;
        !           857:                        void *ptr;
        !           858: 
        !           859:                        if (Z_TYPE_P(index_ptr) != le_index_ptr) {
        !           860:                                efree(hashed_details);
        !           861:                                RETURN_FALSE;
        !           862:                        }
        !           863:                        link = (int) index_ptr->ptr;
        !           864:                        ptr = zend_list_find(link, &type);   /* check if the link is still there */
        !           865:                        if (ptr && (type==le_link || type==le_plink)) {
        !           866:                                zend_list_addref(link);
        !           867:                                Z_LVAL_P(return_value) = SybCtG(default_link) = link;
        !           868:                                Z_TYPE_P(return_value) = IS_RESOURCE;
        !           869:                                efree(hashed_details);
        !           870:                                return;
        !           871:                        } else {
        !           872:                                zend_hash_del(&EG(regular_list), hashed_details, hashed_details_length+1);
        !           873:                        }
        !           874:                }
        !           875:                if (SybCtG(max_links)!=-1 && SybCtG(num_links)>=SybCtG(max_links)) {
        !           876:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open links (%ld)", SybCtG(num_links));
        !           877:                        efree(hashed_details);
        !           878:                        RETURN_FALSE;
        !           879:                }
        !           880: 
        !           881:                sybase_ptr = (sybase_link *) emalloc(sizeof(sybase_link));
        !           882:                if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
        !           883:                        efree(sybase_ptr);
        !           884:                        efree(hashed_details);
        !           885:                        RETURN_FALSE;
        !           886:                }
        !           887: 
        !           888:                /* add it to the list */
        !           889:                ZEND_REGISTER_RESOURCE(return_value, sybase_ptr, le_link);
        !           890: 
        !           891:                /* add it to the hash */
        !           892:                new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
        !           893:                Z_TYPE(new_index_ptr) = le_index_ptr;
        !           894:                if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length+1, (void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
        !           895:                        ct_close(sybase_ptr->connection, CS_UNUSED);
        !           896:                        ct_con_drop(sybase_ptr->connection);
        !           897:                        efree(sybase_ptr);
        !           898:                        efree(hashed_details);
        !           899:                        RETURN_FALSE;
        !           900:                }
        !           901:                SybCtG(num_links)++;
        !           902:        }
        !           903:        efree(hashed_details);
        !           904:        SybCtG(default_link)=Z_LVAL_P(return_value);
        !           905:        zend_list_addref(SybCtG(default_link));
        !           906: }
        !           907: 
        !           908: 
        !           909: static int php_sybase_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
        !           910: {
        !           911:        if (SybCtG(default_link)==-1) { /* no link opened yet, implicitly open one */
        !           912:                ht = 0;
        !           913:                php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
        !           914:        }
        !           915:        return SybCtG(default_link);
        !           916: }
        !           917: 
        !           918: 
        !           919: /* {{{ proto int sybase_connect([string host [, string user [, string password [, string charset [, string appname [, bool new]]]]]])
        !           920:    Open Sybase server connection */
        !           921: PHP_FUNCTION(sybase_connect)
        !           922: {
        !           923:        php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
        !           924: }
        !           925: 
        !           926: /* }}} */
        !           927: 
        !           928: /* {{{ proto int sybase_pconnect([string host [, string user [, string password [, string charset [, string appname]]]]])
        !           929:    Open persistent Sybase connection */
        !           930: PHP_FUNCTION(sybase_pconnect)
        !           931: {
        !           932:        php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
        !           933: }
        !           934: 
        !           935: /* }}} */
        !           936: 
        !           937: inline static int php_sybase_connection_id(zval *sybase_link_index, int *id TSRMLS_DC)
        !           938: {
        !           939:        if (NULL == sybase_link_index) {
        !           940:                if (-1 == SybCtG(default_link)) {
        !           941:                        return FAILURE;
        !           942:                }
        !           943:                *id = SybCtG(default_link);
        !           944:        } else {
        !           945:                *id = -1;   /* explicit resource number */
        !           946:        }
        !           947:        return SUCCESS;
        !           948: }
        !           949: 
        !           950: /* {{{ proto bool sybase_close([resource link_id])
        !           951:    Close Sybase connection */
        !           952: PHP_FUNCTION(sybase_close)
        !           953: {
        !           954:        zval *sybase_link_index = NULL;
        !           955:        sybase_link *sybase_ptr;
        !           956:        int id;
        !           957: 
        !           958:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &sybase_link_index) == FAILURE) {
        !           959:                return;
        !           960:        }
        !           961: 
        !           962:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
        !           963:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection to close");
        !           964:                RETURN_FALSE;
        !           965:        }
        !           966: 
        !           967:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
        !           968: 
        !           969:        if (id == -1) {
        !           970:                zend_list_delete(Z_RESVAL_P(sybase_link_index));
        !           971:        }
        !           972:        if (id != -1 || (sybase_link_index && Z_RESVAL_P(sybase_link_index) == SybCtG(default_link))) {
        !           973:                zend_list_delete(SybCtG(default_link));
        !           974:                SybCtG(default_link) = -1;
        !           975:        }
        !           976: 
        !           977:        RETURN_TRUE;
        !           978: }
        !           979: 
        !           980: /* }}} */
        !           981: 
        !           982: 
        !           983: static int exec_cmd(sybase_link *sybase_ptr, char *cmdbuf)
        !           984: {
        !           985:        CS_RETCODE retcode;
        !           986:        CS_INT restype;
        !           987:        int failure=0;
        !           988: 
        !           989:        /* Fail if we already marked this connection dead. */
        !           990: 
        !           991:        if (sybase_ptr->dead) {
        !           992:                return FAILURE;
        !           993:        }
        !           994: 
        !           995:        /*
        !           996:         ** Get a command handle, store the command string in it, and
        !           997:         ** send it to the server.
        !           998:         */
        !           999: 
        !          1000:        if (ct_command(sybase_ptr->cmd, CS_LANG_CMD, cmdbuf, CS_NULLTERM, CS_UNUSED)!=CS_SUCCEED) {
        !          1001:                sybase_ptr->dead = 1;
        !          1002:                return FAILURE;
        !          1003:        }
        !          1004:        if (ct_send(sybase_ptr->cmd)!=CS_SUCCEED) {
        !          1005:                sybase_ptr->dead = 1;
        !          1006:                return FAILURE;
        !          1007:        }
        !          1008: 
        !          1009:        while ((retcode = ct_results(sybase_ptr->cmd, &restype))==CS_SUCCEED) {
        !          1010:                switch ((int) restype) {
        !          1011:                        case CS_CMD_SUCCEED:
        !          1012:                        case CS_CMD_DONE:
        !          1013:                                break;
        !          1014: 
        !          1015:                        case CS_CMD_FAIL:
        !          1016:                                failure=1;
        !          1017:                                break;
        !          1018: 
        !          1019:                        case CS_STATUS_RESULT:
        !          1020:                                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
        !          1021:                                break;
        !          1022: 
        !          1023:                        default:
        !          1024:                                failure=1;
        !          1025:                                break;
        !          1026:                }
        !          1027:                if (failure) {
        !          1028:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1029:                        return FAILURE;
        !          1030:                }
        !          1031:        }
        !          1032: 
        !          1033:        switch (retcode) {
        !          1034:                case CS_END_RESULTS:
        !          1035:                        return SUCCESS;
        !          1036:                        break;
        !          1037: 
        !          1038:                case CS_FAIL:
        !          1039:                        /* Hopefully this either cleans up the connection, or the
        !          1040:                         * connection ends up marked dead so it will be reopened
        !          1041:                         * if it is persistent.  We may want to do
        !          1042:                         * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
        !          1043:                         * doc for ct_results()==CS_FAIL.
        !          1044:                         */
        !          1045:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1046:                        /* Don't take chances with the vagaries of ct-lib.  Mark it
        !          1047:                         * dead ourselves.
        !          1048:                         */
        !          1049:                        sybase_ptr->dead = 1;
        !          1050:                        return FAILURE;
        !          1051: 
        !          1052:                default:
        !          1053:                        return FAILURE;
        !          1054:        }
        !          1055: }
        !          1056: 
        !          1057: 
        !          1058: /* {{{ proto bool sybase_select_db(string database [, resource link_id])
        !          1059:    Select Sybase database */
        !          1060: PHP_FUNCTION(sybase_select_db)
        !          1061: {
        !          1062:        zval *sybase_link_index = NULL;
        !          1063:        char *db, *cmdbuf;
        !          1064:        int id, len;
        !          1065:        sybase_link *sybase_ptr;
        !          1066: 
        !          1067:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &db, &len, &sybase_link_index) == FAILURE) {
        !          1068:                return;
        !          1069:        }
        !          1070: 
        !          1071:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
        !          1072:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
        !          1073:                RETURN_FALSE;
        !          1074:        }
        !          1075: 
        !          1076:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
        !          1077: 
        !          1078:        spprintf(&cmdbuf, 4 + len + 1, "use %s", db);
        !          1079:        if (exec_cmd(sybase_ptr, cmdbuf) == FAILURE) {
        !          1080:                efree(cmdbuf);
        !          1081:                RETURN_FALSE;
        !          1082:        } else {
        !          1083:                efree(cmdbuf);
        !          1084:                RETURN_TRUE;
        !          1085:        }
        !          1086: }
        !          1087: 
        !          1088: /* }}} */
        !          1089: 
        !          1090: static int php_sybase_finish_results(sybase_result *result TSRMLS_DC) 
        !          1091: {
        !          1092:        int i, fail;
        !          1093:        CS_RETCODE retcode;
        !          1094:        CS_INT restype;
        !          1095:        
        !          1096:        efree_n(result->datafmt);
        !          1097:        efree_n(result->lengths);
        !          1098:        efree_n(result->indicators);
        !          1099:        efree_n(result->numerics);
        !          1100:        efree_n(result->types);
        !          1101:        for (i=0; i<result->num_fields; i++) {
        !          1102:                efree(result->tmp_buffer[i]);
        !          1103:        }
        !          1104:        efree_n(result->tmp_buffer);
        !          1105: 
        !          1106:        /* Indicate we have read all rows */
        !          1107:        result->sybase_ptr->active_result_index= 0;
        !          1108: 
        !          1109:        /* The only restype we should get now is CS_CMD_DONE, possibly
        !          1110:         * followed by a CS_STATUS_RESULT/CS_CMD_SUCCEED/CS_CMD_DONE
        !          1111:         * sequence if the command was a stored procedure call.  But we
        !          1112:         * still need to read and discard unexpected results.  We might
        !          1113:         * want to return a failure in this case because the application
        !          1114:         * won't be getting all the results it asked for.
        !          1115:         */
        !          1116:        fail = 0;
        !          1117:        while ((retcode = ct_results(result->sybase_ptr->cmd, &restype))==CS_SUCCEED) {
        !          1118:                switch ((int) restype) {
        !          1119:                        case CS_CMD_SUCCEED:
        !          1120:                        case CS_CMD_DONE:
        !          1121:                                break;
        !          1122: 
        !          1123:                        case CS_CMD_FAIL:
        !          1124:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Command failed, cancelling rest");
        !          1125:                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1126:                                fail = 1;
        !          1127:                                break;
        !          1128: 
        !          1129:                        case CS_COMPUTE_RESULT:
        !          1130:                        case CS_CURSOR_RESULT:
        !          1131:                        case CS_PARAM_RESULT:
        !          1132:                        case CS_ROW_RESULT:
        !          1133:                                /* Unexpected results, cancel them. */
        !          1134:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling current");
        !          1135:                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
        !          1136:                                break;
        !          1137: 
        !          1138:                        case CS_STATUS_RESULT:
        !          1139:                                /* Status result from a stored procedure, cancel it but do not tell user */
        !          1140:                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
        !          1141:                                break;
        !          1142: 
        !          1143:                        default:
        !          1144:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling all");
        !          1145:                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1146:                                break;
        !          1147:                }
        !          1148: 
        !          1149:                if (fail) {
        !          1150:                        break;
        !          1151:                }
        !          1152:        }
        !          1153: 
        !          1154:        switch (retcode) {
        !          1155:                case CS_END_RESULTS:
        !          1156:                        /* Normal. */
        !          1157:                        break;
        !          1158: 
        !          1159:                case CS_FAIL:
        !          1160:                        /* Hopefully this either cleans up the connection, or the
        !          1161:                         * connection ends up marked dead so it will be reopened
        !          1162:                         * if it is persistent.  We may want to do
        !          1163:                         * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
        !          1164:                         * doc for ct_results()==CS_FAIL.
        !          1165:                         */
        !          1166:                        ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1167:                        /* Don't take chances with the vagaries of ct-lib.  Mark it
        !          1168:                         * dead ourselves.
        !          1169:                         */
        !          1170:                        result->sybase_ptr->dead = 1;
        !          1171:                        
        !          1172:                case CS_CANCELED:
        !          1173:                default:
        !          1174:                        retcode = CS_FAIL;
        !          1175:                        break;
        !          1176:        }
        !          1177: 
        !          1178:        return retcode;
        !          1179: }
        !          1180: 
        !          1181: #define RETURN_DOUBLE_VAL(result, buf, length)          \
        !          1182:        if ((length - 1) <= EG(precision)) {                \
        !          1183:                errno = 0;                                      \
        !          1184:                Z_DVAL(result) = zend_strtod(buf, NULL);        \
        !          1185:                if (errno != ERANGE) {                          \
        !          1186:                        Z_TYPE(result) = IS_DOUBLE;                 \
        !          1187:                } else {                                        \
        !          1188:                        ZVAL_STRINGL(&result, buf, length- 1, 1);   \
        !          1189:                }                                               \
        !          1190:        } else {                                            \
        !          1191:                ZVAL_STRINGL(&result, buf, length- 1, 1);       \
        !          1192:        }
        !          1193: 
        !          1194: static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
        !          1195: {
        !          1196:        int i, j;
        !          1197:        CS_INT retcode;
        !          1198:        TSRMLS_FETCH();
        !          1199:        
        !          1200:        /* We've already fetched everything */
        !          1201:        if (result->last_retcode == CS_END_DATA || result->last_retcode == CS_END_RESULTS) {
        !          1202:                return result->last_retcode;
        !          1203:        }
        !          1204:        
        !          1205:        if (numrows!=-1) numrows+= result->num_rows;
        !          1206:        while ((retcode=ct_fetch(result->sybase_ptr->cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL))==CS_SUCCEED || retcode == CS_ROW_FAIL) {
        !          1207:                result->num_rows++;
        !          1208:                i= result->store ? result->num_rows- 1 : 0;
        !          1209:                if (i >= result->blocks_initialized*SYBASE_ROWS_BLOCK) {
        !          1210:                        result->data = (zval **) safe_erealloc(result->data, SYBASE_ROWS_BLOCK*(++result->blocks_initialized), sizeof(zval *), 0);
        !          1211:                }
        !          1212:                if (result->store || 1 == result->num_rows) {
        !          1213:                        result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
        !          1214:                }
        !          1215: 
        !          1216:                for (j = 0; j < result->num_fields; j++) {
        !          1217: 
        !          1218:                        /* If we are in non-storing mode, free the previous result */
        !          1219:                        if (!result->store && result->num_rows > 1 && Z_TYPE(result->data[i][j]) == IS_STRING) {
        !          1220:                                efree(Z_STRVAL(result->data[i][j]));
        !          1221:                        }
        !          1222: 
        !          1223:                        if (result->indicators[j] == -1) { /* null value */
        !          1224:                                ZVAL_NULL(&result->data[i][j]);
        !          1225:                        } else {
        !          1226:                                switch (result->numerics[j]) {
        !          1227:                                        case 1: {
        !          1228:                                                /* This indicates a long */
        !          1229:                                                ZVAL_LONG(&result->data[i][j], strtol(result->tmp_buffer[j], NULL, 10));
        !          1230:                                                break;
        !          1231:                                        }
        !          1232:                                        
        !          1233:                                        case 2: {
        !          1234:                                                /* This indicates a float */
        !          1235:                                                RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
        !          1236:                                                break;
        !          1237:                                        }
        !          1238: 
        !          1239:                                        case 3: {
        !          1240:                                                /* This indicates either a long or a float, which ever fits */
        !          1241:                                                errno = 0;
        !          1242:                                                Z_LVAL(result->data[i][j]) = strtol(result->tmp_buffer[j], NULL, 10);
        !          1243:                                                if (errno == ERANGE) {
        !          1244:                                                
        !          1245:                                                        /* An overflow occurred, so try to fit it into a double */
        !          1246:                                                        RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
        !          1247:                                                        break;
        !          1248:                                                }
        !          1249:                                                Z_TYPE(result->data[i][j]) = IS_LONG;
        !          1250:                                                break;
        !          1251:                                        }
        !          1252:                                        
        !          1253:                                        default: {
        !          1254:                                                /* This indicates anything else, return it as string
        !          1255:                                                 * FreeTDS doesn't correctly set result->indicators[j] correctly
        !          1256:                                                 * for NULL fields in some version in conjunction with ASE 12.5
        !          1257:                                                 * but instead sets result->lengths[j] to 0, which would lead to
        !          1258:                                                 * a negative memory allocation (and thus a segfault).
        !          1259:                                                 */
        !          1260:                                                if (result->lengths[j] < 1) {
        !          1261:                                                        ZVAL_NULL(&result->data[i][j]);
        !          1262:                                                } else {
        !          1263:                                                        ZVAL_STRINGL(&result->data[i][j], result->tmp_buffer[j], result->lengths[j]- 1, 1);
        !          1264:                                                }
        !          1265:                                                break;
        !          1266:                                        }
        !          1267:                                }
        !          1268:                        }
        !          1269:                }
        !          1270:                if (numrows!=-1 && result->num_rows>=numrows) break;
        !          1271:        }
        !          1272: 
        !          1273:        if (retcode==CS_ROW_FAIL) {
        !          1274:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Error reading row %d", result->num_rows);
        !          1275:                return retcode;
        !          1276:        }
        !          1277:        result->last_retcode= retcode;
        !          1278:        switch (retcode) {
        !          1279:                case CS_END_DATA:
        !          1280:                        retcode = php_sybase_finish_results(result TSRMLS_CC);
        !          1281:                        break;
        !          1282:                        
        !          1283:                case CS_ROW_FAIL:
        !          1284:                case CS_SUCCEED:
        !          1285:                        break;
        !          1286:                        
        !          1287:                default:
        !          1288:                        FREE_SYBASE_RESULT(result);
        !          1289:                        result = NULL;
        !          1290:                        retcode = CS_FAIL;              /* Just to be sure */
        !          1291:                        break;
        !          1292:        }
        !          1293:        
        !          1294:        return retcode;
        !          1295: }
        !          1296: 
        !          1297: static sybase_result * php_sybase_fetch_result_set (sybase_link *sybase_ptr, int buffered, int store)
        !          1298: {
        !          1299:        int num_fields;
        !          1300:        sybase_result *result;
        !          1301:        int i, j;
        !          1302:        CS_INT retcode;
        !          1303: 
        !          1304:        /* The following (if unbuffered) is more or less the equivalent of mysql_store_result().
        !          1305:         * fetch all rows from the server into the row buffer, thus:
        !          1306:         * 1)  Being able to fire up another query without explicitly reading all rows
        !          1307:         * 2)  Having numrows accessible
        !          1308:         */
        !          1309:        if (ct_res_info(sybase_ptr->cmd, CS_NUMDATA, &num_fields, CS_UNUSED, NULL)!=CS_SUCCEED) {
        !          1310:                return NULL;
        !          1311:        }
        !          1312:        
        !          1313:        result = (sybase_result *) emalloc(sizeof(sybase_result));
        !          1314:        result->data = (zval **) safe_emalloc(sizeof(zval *), SYBASE_ROWS_BLOCK, 0);
        !          1315:        result->fields = NULL;
        !          1316:        result->sybase_ptr = sybase_ptr;
        !          1317:        result->cur_field=result->cur_row=result->num_rows=0;
        !          1318:        result->num_fields = num_fields;
        !          1319:        result->last_retcode = 0;
        !          1320:        result->store= store;
        !          1321:        result->blocks_initialized= 1;
        !          1322:        result->tmp_buffer = (char **) safe_emalloc(sizeof(char *), num_fields, 0);
        !          1323:        result->lengths = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
        !          1324:        result->indicators = (CS_SMALLINT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
        !          1325:        result->datafmt = (CS_DATAFMT *) safe_emalloc(sizeof(CS_DATAFMT), num_fields, 0);
        !          1326:        result->numerics = (unsigned char *) safe_emalloc(sizeof(unsigned char), num_fields, 0);
        !          1327:        result->types = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
        !          1328:        
        !          1329:        for (i=0; i<num_fields; i++) {
        !          1330:                ct_describe(sybase_ptr->cmd, i+1, &result->datafmt[i]);
        !          1331:                result->types[i] = result->datafmt[i].datatype;
        !          1332:                switch (result->datafmt[i].datatype) {
        !          1333:                        case CS_CHAR_TYPE:
        !          1334:                        case CS_VARCHAR_TYPE:
        !          1335:                        case CS_TEXT_TYPE:
        !          1336:                        case CS_IMAGE_TYPE:
        !          1337:                                result->datafmt[i].maxlength++;
        !          1338:                                result->numerics[i] = 0;
        !          1339:                                break;
        !          1340:                        case CS_BINARY_TYPE:
        !          1341:                        case CS_VARBINARY_TYPE:
        !          1342:                                result->datafmt[i].maxlength *= 2;
        !          1343:                                result->datafmt[i].maxlength++;
        !          1344:                                result->numerics[i] = 0;
        !          1345:                                break;
        !          1346:                        case CS_BIT_TYPE:
        !          1347:                        case CS_TINYINT_TYPE:
        !          1348:                                result->datafmt[i].maxlength = 4;
        !          1349:                                result->numerics[i] = 1;
        !          1350:                                break;
        !          1351:                        case CS_SMALLINT_TYPE:
        !          1352:                                result->datafmt[i].maxlength = 7;
        !          1353:                                result->numerics[i] = 1;
        !          1354:                                break;
        !          1355:                        case CS_INT_TYPE:
        !          1356:                                result->datafmt[i].maxlength = 12;
        !          1357:                                result->numerics[i] = 1;
        !          1358:                                break;
        !          1359:                        case CS_REAL_TYPE:
        !          1360:                        case CS_FLOAT_TYPE:
        !          1361:                                result->datafmt[i].maxlength = 24;
        !          1362:                                result->numerics[i] = 2;
        !          1363:                                break;
        !          1364:                        case CS_MONEY_TYPE:
        !          1365:                        case CS_MONEY4_TYPE:
        !          1366:                                result->datafmt[i].maxlength = 24;
        !          1367:                                result->numerics[i] = 2;
        !          1368:                                break;
        !          1369:                        case CS_DATETIME_TYPE:
        !          1370:                        case CS_DATETIME4_TYPE:
        !          1371:                                result->datafmt[i].maxlength = 30;
        !          1372:                                result->numerics[i] = 0;
        !          1373:                                break;
        !          1374:                        case CS_NUMERIC_TYPE:
        !          1375:                        case CS_DECIMAL_TYPE:
        !          1376:                                result->datafmt[i].maxlength = result->datafmt[i].precision + 3;
        !          1377:                                /* numeric(10) vs numeric(10, 1) */
        !          1378:                                result->numerics[i] = (result->datafmt[i].scale == 0) ? 3 : 2;
        !          1379:                                break;
        !          1380:                        default:
        !          1381:                                result->datafmt[i].maxlength++;
        !          1382:                                result->numerics[i] = 0;
        !          1383:                                break;
        !          1384:                }
        !          1385:                result->tmp_buffer[i] = (char *)emalloc(result->datafmt[i].maxlength);
        !          1386:                result->datafmt[i].datatype = CS_CHAR_TYPE;
        !          1387:                result->datafmt[i].format = CS_FMT_NULLTERM;
        !          1388:                ct_bind(sybase_ptr->cmd, i+1, &result->datafmt[i], result->tmp_buffer[i], &result->lengths[i], &result->indicators[i]);
        !          1389:        }
        !          1390: 
        !          1391:        result->fields = (sybase_field *) safe_emalloc(sizeof(sybase_field), num_fields, 0);
        !          1392:        j=0;
        !          1393:        for (i=0; i<num_fields; i++) {
        !          1394:                char computed_buf[16];
        !          1395: 
        !          1396:                if (result->datafmt[i].namelen>0) {
        !          1397:                        result->fields[i].name = estrndup(result->datafmt[i].name, result->datafmt[i].namelen);
        !          1398:                } else {
        !          1399:                        if (j>0) {
        !          1400:                                snprintf(computed_buf, 16, "computed%d", j);
        !          1401:                        } else {
        !          1402:                                strcpy(computed_buf, "computed");
        !          1403:                        }
        !          1404:                        result->fields[i].name = estrdup(computed_buf);
        !          1405:                        j++;
        !          1406:                }
        !          1407:                result->fields[i].column_source = STR_EMPTY_ALLOC();
        !          1408:                result->fields[i].max_length = result->datafmt[i].maxlength-1;
        !          1409:                result->fields[i].numeric = result->numerics[i];
        !          1410:                Z_TYPE(result->fields[i]) = result->types[i];
        !          1411:        }
        !          1412:        
        !          1413:        if (buffered) {
        !          1414:                retcode = CS_SUCCEED;
        !          1415:        } else {
        !          1416:                if ((retcode = php_sybase_fetch_result_row(result, -1)) == CS_FAIL) {
        !          1417:                        return NULL;
        !          1418:                }
        !          1419:        }
        !          1420: 
        !          1421:        result->last_retcode = retcode;
        !          1422:        return result;
        !          1423: }
        !          1424: 
        !          1425: static void php_sybase_query (INTERNAL_FUNCTION_PARAMETERS, int buffered)
        !          1426: {
        !          1427:        zval *sybase_link_index = NULL;
        !          1428:        zend_bool store = 1;
        !          1429:        char *query;
        !          1430:        int len, id, deadlock_count;
        !          1431:        sybase_link *sybase_ptr;
        !          1432:        sybase_result *result;
        !          1433:        CS_INT restype;
        !          1434:        CS_RETCODE retcode;
        !          1435:        enum {
        !          1436:                Q_RESULT,                               /* Success with results. */
        !          1437:                Q_SUCCESS,                              /* Success but no results. */
        !          1438:                Q_FAILURE,                              /* Failure, no results. */
        !          1439:        } status;
        !          1440: 
        !          1441:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|rb", &query, &len, &sybase_link_index, &store) == FAILURE) {
        !          1442:                return;
        !          1443:        }
        !          1444: 
        !          1445:        if (!store && !buffered) {
        !          1446:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Cannot use non-storing mode with buffered queries");
        !          1447:                store = 1;
        !          1448:        }
        !          1449: 
        !          1450:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
        !          1451:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
        !          1452:                RETURN_FALSE;
        !          1453:        }
        !          1454: 
        !          1455:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
        !          1456: 
        !          1457:        /* Fail if we already marked this connection dead. */
        !          1458:        if (sybase_ptr->dead) {
        !          1459:                RETURN_FALSE;
        !          1460:        }
        !          1461:        
        !          1462:        /* Check to see if a previous sybase_unbuffered_query has read all rows */
        !          1463:        if (sybase_ptr->active_result_index) {
        !          1464:                zval *tmp = NULL;
        !          1465:                
        !          1466:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Called without first fetching all rows from a previous unbuffered query");
        !          1467:                if (sybase_ptr->cmd) {
        !          1468:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1469:                }
        !          1470:                
        !          1471:                /* Get the resultset and free it */
        !          1472:                ALLOC_ZVAL(tmp);
        !          1473:                Z_LVAL_P(tmp)= sybase_ptr->active_result_index;
        !          1474:                Z_TYPE_P(tmp)= IS_RESOURCE;
        !          1475:                INIT_PZVAL(tmp);
        !          1476:                ZEND_FETCH_RESOURCE(result, sybase_result *, &tmp, -1, "Sybase result", le_result);
        !          1477:                
        !          1478:                if (result) {
        !          1479:                        php_sybase_finish_results(result TSRMLS_CC);
        !          1480:                }
        !          1481:                
        !          1482:                zval_ptr_dtor(&tmp);
        !          1483:                zend_list_delete(sybase_ptr->active_result_index);
        !          1484:                sybase_ptr->active_result_index= 0;
        !          1485:        }
        !          1486: 
        !          1487:        /* Repeat until we don't deadlock. */
        !          1488:        deadlock_count= 0;
        !          1489:        for (;;) {
        !          1490:                result = NULL;
        !          1491:                sybase_ptr->deadlock = 0;
        !          1492:                sybase_ptr->affected_rows = 0;
        !          1493: 
        !          1494:                /* On Solaris 11.5, ct_command() can be moved outside the
        !          1495:                 * loop, but not on Linux 11.0.
        !          1496:                 */
        !          1497:                if (ct_command(sybase_ptr->cmd, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED)!=CS_SUCCEED) {
        !          1498:                        /* If this didn't work, the connection is screwed but
        !          1499:                         * ct-lib might not set CS_CONSTAT_DEAD.  So set our own
        !          1500:                         * flag.  This happens sometimes when the database is restarted
        !          1501:                         * and/or its machine is rebooted, and ct_command() returns
        !          1502:                         * CS_BUSY for some reason.
        !          1503:                         */
        !          1504:                        sybase_ptr->dead = 1;
        !          1505:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Connection is dead");
        !          1506:                        RETURN_FALSE;
        !          1507:                }
        !          1508: 
        !          1509:                if (ct_send(sybase_ptr->cmd)!=CS_SUCCEED) {
        !          1510:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1511:                        sybase_ptr->dead = 1;
        !          1512:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot send command");
        !          1513:                        RETURN_FALSE;
        !          1514:                }
        !          1515: 
        !          1516:                /* Use the first result set or succeed/fail status and discard the
        !          1517:                 * others.  Applications really shouldn't be making calls that
        !          1518:                 * return multiple result sets, but if they do then we need to
        !          1519:                 * properly read or cancel them or the connection will become
        !          1520:                 * unusable.
        !          1521:                 */
        !          1522:                if (ct_results(sybase_ptr->cmd, &restype)!=CS_SUCCEED) {
        !          1523:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1524:                        sybase_ptr->dead = 1;
        !          1525:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot read results");
        !          1526:                        RETURN_FALSE;
        !          1527:                }
        !          1528:                switch ((int) restype) {
        !          1529:                        case CS_CMD_FAIL:
        !          1530:                        default:
        !          1531:                                status = Q_FAILURE;
        !          1532:                                break;
        !          1533:                        case CS_CMD_SUCCEED:
        !          1534:                        case CS_CMD_DONE: {
        !          1535:                                        CS_INT row_count;
        !          1536:                                        if (ct_res_info(sybase_ptr->cmd, CS_ROW_COUNT, &row_count, CS_UNUSED, NULL)==CS_SUCCEED) {
        !          1537:                                                sybase_ptr->affected_rows = (long)row_count;
        !          1538:                                        }
        !          1539:                                }
        !          1540:                                /* Fall through */
        !          1541:                        case CS_COMPUTEFMT_RESULT:
        !          1542:                        case CS_ROWFMT_RESULT:
        !          1543:                        case CS_DESCRIBE_RESULT:
        !          1544:                        case CS_MSG_RESULT:
        !          1545:                                buffered= 0;                            /* These queries have no need for buffering */
        !          1546:                                status = Q_SUCCESS;
        !          1547:                                break;
        !          1548:                        case CS_COMPUTE_RESULT:
        !          1549:                        case CS_CURSOR_RESULT:
        !          1550:                        case CS_PARAM_RESULT:
        !          1551:                        case CS_ROW_RESULT:
        !          1552:                        case CS_STATUS_RESULT:
        !          1553:                                result = php_sybase_fetch_result_set(sybase_ptr, buffered, store);
        !          1554:                                if (result == NULL) {
        !          1555:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1556:                                        RETURN_FALSE;
        !          1557:                                }
        !          1558:                                status = Q_RESULT;
        !          1559:                                break;
        !          1560:                }
        !          1561:                
        !          1562:                /* Check for left-over results */
        !          1563:                if (!buffered && status != Q_RESULT) {
        !          1564:                        while ((retcode = ct_results(sybase_ptr->cmd, &restype))==CS_SUCCEED) {
        !          1565:                                switch ((int) restype) {
        !          1566:                                        case CS_CMD_SUCCEED:
        !          1567:                                        case CS_CMD_DONE:
        !          1568:                                                break;
        !          1569: 
        !          1570:                                        case CS_CMD_FAIL:
        !          1571:                                                status = Q_FAILURE;
        !          1572:                                                break;
        !          1573: 
        !          1574:                                        case CS_COMPUTE_RESULT:
        !          1575:                                        case CS_CURSOR_RESULT:
        !          1576:                                        case CS_PARAM_RESULT:
        !          1577:                                        case CS_ROW_RESULT:
        !          1578:                                                if (status != Q_RESULT) {
        !          1579:                                                        result = php_sybase_fetch_result_set(sybase_ptr, buffered, store);
        !          1580:                                                        if (result == NULL) {
        !          1581:                                                                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1582:                                                                sybase_ptr->dead = 1;
        !          1583:                                                                RETURN_FALSE;
        !          1584:                                                        }
        !          1585:                                                        status = Q_RESULT;
        !          1586:                                                        retcode = result->last_retcode; 
        !          1587:                                                } else {
        !          1588:                                                        /* Unexpected results, cancel them. */
        !          1589:                                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
        !          1590:                                                }
        !          1591:                                                break;
        !          1592:                                        case CS_STATUS_RESULT:
        !          1593:                                                /* Unexpected results, cancel them. */
        !          1594:                                                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
        !          1595:                                                break;
        !          1596: 
        !          1597:                                        default:
        !          1598:                                                status = Q_FAILURE;
        !          1599:                                                break;
        !          1600:                                }
        !          1601:                                if (status == Q_FAILURE) {
        !          1602:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1603:                                }
        !          1604:                                if (retcode == CS_END_RESULTS) {
        !          1605:                                        break;
        !          1606:                                }
        !          1607:                        }
        !          1608:                        switch (retcode) {
        !          1609:                                case CS_END_RESULTS:
        !          1610:                                        /* Normal. */
        !          1611:                                        break;
        !          1612: 
        !          1613:                                case CS_FAIL:
        !          1614:                                        /* Hopefully this either cleans up the connection, or the
        !          1615:                                         * connection ends up marked dead so it will be reopened
        !          1616:                                         * if it is persistent.  We may want to do
        !          1617:                                         * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
        !          1618:                                         * doc for ct_results()==CS_FAIL.
        !          1619:                                         */
        !          1620:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1621:                                        /* Don't take chances with the vagaries of ct-lib.  Mark it
        !          1622:                                         * dead ourselves.
        !          1623:                                         */
        !          1624:                                        sybase_ptr->dead = 1;
        !          1625:                                case CS_CANCELED:
        !          1626:                                default:
        !          1627:                                        status = Q_FAILURE;
        !          1628:                                        break;
        !          1629:                        }
        !          1630:                }
        !          1631: 
        !          1632:                /* Retry deadlocks up until deadlock_retry_count times */               
        !          1633:                if (sybase_ptr->deadlock && SybCtG(deadlock_retry_count) != -1 && ++deadlock_count > SybCtG(deadlock_retry_count)) {
        !          1634:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Retried deadlock %d times [max: %ld], giving up", deadlock_count- 1, SybCtG(deadlock_retry_count));
        !          1635:                        FREE_SYBASE_RESULT(result);
        !          1636:                        break;
        !          1637:                }
        !          1638: 
        !          1639:                /* If query completed without deadlock, break out of the loop.
        !          1640:                 * Sometimes deadlock results in failures and sometimes not,
        !          1641:                 * it seems to depend on the server flavor.  But we want to
        !          1642:                 * retry all deadlocks.
        !          1643:                 */
        !          1644:                if (sybase_ptr->dead || sybase_ptr->deadlock == 0) {
        !          1645:                        break;
        !          1646:                }
        !          1647: 
        !          1648:                /* Get rid of any results we may have fetched.  This happens:
        !          1649:                 * e.g., our result set may be a stored procedure status which
        !          1650:                 * is returned even if the stored procedure deadlocks.  As an
        !          1651:                 * optimization, we could try not to fetch results in known
        !          1652:                 * deadlock conditions, but deadlock is (should be) rare.
        !          1653:                 */
        !          1654:                FREE_SYBASE_RESULT(result);
        !          1655:        }
        !          1656: 
        !          1657:        if (status == Q_SUCCESS) {
        !          1658:                RETURN_TRUE;
        !          1659:        }
        !          1660: 
        !          1661:        if (status == Q_FAILURE) {
        !          1662:                FREE_SYBASE_RESULT(result);
        !          1663:                RETURN_FALSE;
        !          1664:        }
        !          1665: 
        !          1666:        /* Indicate we have data in case of buffered queries */
        !          1667:        id= ZEND_REGISTER_RESOURCE(return_value, result, le_result);
        !          1668:        sybase_ptr->active_result_index= buffered ? id : 0;
        !          1669: }
        !          1670: 
        !          1671: /* {{{ proto int sybase_query(string query [, resource link_id])
        !          1672:    Send Sybase query */
        !          1673: PHP_FUNCTION(sybase_query)
        !          1674: {
        !          1675:        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
        !          1676: }
        !          1677: /* }}} */
        !          1678: 
        !          1679: /* {{{ proto int sybase_unbuffered_query(string query [, resource link_id])
        !          1680:    Send Sybase query */
        !          1681: PHP_FUNCTION(sybase_unbuffered_query)
        !          1682: {
        !          1683:        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
        !          1684: }
        !          1685: 
        !          1686: /* {{{ proto bool sybase_free_result(resource result)
        !          1687:    Free result memory */
        !          1688: PHP_FUNCTION(sybase_free_result)
        !          1689: {
        !          1690:        zval *sybase_result_index = NULL;
        !          1691:        sybase_result *result;
        !          1692: 
        !          1693:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
        !          1694:                return;
        !          1695:        }
        !          1696:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1697:        
        !          1698:        /* Did we fetch up until the end? */
        !          1699:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
        !          1700:                /* php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cancelling the rest of the results"); */
        !          1701:                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
        !          1702:                php_sybase_finish_results(result TSRMLS_CC);
        !          1703:        }
        !          1704:        
        !          1705:        zend_list_delete(Z_LVAL_P(sybase_result_index));
        !          1706:        RETURN_TRUE;
        !          1707: }
        !          1708: 
        !          1709: /* }}} */
        !          1710: 
        !          1711: /* {{{ proto string sybase_get_last_message(void)
        !          1712:    Returns the last message from server (over min_message_severity) */
        !          1713: PHP_FUNCTION(sybase_get_last_message)
        !          1714: {
        !          1715:        RETURN_STRING(SybCtG(server_message), 1);
        !          1716: }
        !          1717: /* }}} */
        !          1718: 
        !          1719: /* {{{ proto int sybase_num_rows(resource result)
        !          1720:    Get number of rows in result */
        !          1721: PHP_FUNCTION(sybase_num_rows)
        !          1722: {
        !          1723:        zval *sybase_result_index = NULL;
        !          1724:        sybase_result *result;
        !          1725: 
        !          1726:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
        !          1727:                return;
        !          1728:        }
        !          1729:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1730: 
        !          1731:        Z_LVAL_P(return_value) = result->num_rows;
        !          1732:        Z_TYPE_P(return_value) = IS_LONG;
        !          1733: }
        !          1734: 
        !          1735: /* }}} */
        !          1736: 
        !          1737: /* {{{ proto int sybase_num_fields(resource result)
        !          1738:    Get number of fields in result */
        !          1739: PHP_FUNCTION(sybase_num_fields)
        !          1740: {
        !          1741:        zval *sybase_result_index = NULL;
        !          1742:        sybase_result *result;
        !          1743: 
        !          1744:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
        !          1745:                return;
        !          1746:        }
        !          1747:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1748: 
        !          1749:        Z_LVAL_P(return_value) = result->num_fields;
        !          1750:        Z_TYPE_P(return_value) = IS_LONG;
        !          1751: }
        !          1752: 
        !          1753: /* }}} */
        !          1754: 
        !          1755: /* {{{ proto array sybase_fetch_row(resource result)
        !          1756:    Get row as enumerated array */
        !          1757: PHP_FUNCTION(sybase_fetch_row)
        !          1758: {
        !          1759:        zval *sybase_result_index = NULL;
        !          1760:        int i;
        !          1761:        sybase_result *result;
        !          1762:        zval *field_content;
        !          1763: 
        !          1764:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
        !          1765:                return;
        !          1766:        }
        !          1767:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1768: 
        !          1769:        /* Unbuffered? */
        !          1770:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
        !          1771:                php_sybase_fetch_result_row(result, 1);
        !          1772:        }
        !          1773:        
        !          1774:        /* At the end? */
        !          1775:        if (result->cur_row >= result->num_rows) {
        !          1776:                RETURN_FALSE;
        !          1777:        }
        !          1778: 
        !          1779:        array_init(return_value);
        !          1780:        for (i=0; i<result->num_fields; i++) {
        !          1781:                ALLOC_ZVAL(field_content);
        !          1782:                *field_content = result->data[result->store ? result->cur_row : 0][i];
        !          1783:                INIT_PZVAL(field_content);
        !          1784:                zval_copy_ctor(field_content);
        !          1785:                zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &field_content, sizeof(zval* ), NULL);
        !          1786:        }
        !          1787:        result->cur_row++;
        !          1788: }
        !          1789: 
        !          1790: /* }}} */
        !          1791: 
        !          1792: static void php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int numerics)
        !          1793: {
        !          1794:        zval *sybase_result_index = NULL;
        !          1795:        sybase_result *result;
        !          1796:        int i, j;
        !          1797:        zval *tmp;
        !          1798:        char name[32];
        !          1799: 
        !          1800:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
        !          1801:                return;
        !          1802:        }
        !          1803:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1804: 
        !          1805:        /* Unbuffered ? Fetch next row */
        !          1806:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
        !          1807:                php_sybase_fetch_result_row(result, 1);
        !          1808:        }
        !          1809: 
        !          1810:        /* At the end? */
        !          1811:        if (result->cur_row >= result->num_rows) {
        !          1812:                RETURN_FALSE;
        !          1813:        }
        !          1814: 
        !          1815:        array_init(return_value);
        !          1816:        
        !          1817:        j= 1;
        !          1818:        for (i=0; i<result->num_fields; i++) {
        !          1819:                ALLOC_ZVAL(tmp);
        !          1820:                *tmp = result->data[result->store ? result->cur_row : 0][i];
        !          1821:                INIT_PZVAL(tmp);
        !          1822:                if (PG(magic_quotes_runtime) && Z_TYPE_P(tmp) == IS_STRING) {
        !          1823:                        Z_STRVAL_P(tmp) = php_addslashes(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &Z_STRLEN_P(tmp), 0 TSRMLS_CC);
        !          1824:                } else {
        !          1825:                        zval_copy_ctor(tmp);
        !          1826:                }
        !          1827:                if (numerics) {
        !          1828:                        zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &tmp, sizeof(zval *), NULL);
        !          1829:                        Z_ADDREF_P(tmp);
        !          1830:                }
        !          1831:                
        !          1832:                if (zend_hash_exists(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1)) {
        !          1833:                        snprintf(name, 32, "%s%d", result->fields[i].name, j);
        !          1834:                        result->fields[i].name= estrdup(name);
        !          1835:                        j++;
        !          1836:                }
        !          1837:                zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(zval *), NULL);
        !          1838:        }
        !          1839:        result->cur_row++;
        !          1840: }
        !          1841: 
        !          1842: 
        !          1843: /* {{{ proto object sybase_fetch_object(resource result [, mixed object])
        !          1844:    Fetch row as object */
        !          1845: PHP_FUNCTION(sybase_fetch_object)
        !          1846: {
        !          1847:        zval *object = NULL;
        !          1848:        zval *sybase_result_index = NULL;
        !          1849:        zend_class_entry *ce = NULL;
        !          1850:        sybase_result *result;
        !          1851:        
        !          1852:        /* Was a second parameter given? */
        !          1853:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &sybase_result_index, &object) == FAILURE) {
        !          1854:                return;
        !          1855:        }
        !          1856:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1857: 
        !          1858:        ce = ZEND_STANDARD_CLASS_DEF_PTR;
        !          1859:        if (NULL != object) {           
        !          1860:                switch (Z_TYPE_P(object)) {
        !          1861:                        case IS_OBJECT: {
        !          1862:                                ce = Z_OBJCE_P(object);
        !          1863:                                break;
        !          1864:                        }
        !          1865: 
        !          1866:                        case IS_NULL: {
        !          1867:                                /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
        !          1868:                                break;
        !          1869:                        }
        !          1870: 
        !          1871:                        default: {
        !          1872:                                zend_class_entry **pce = NULL;
        !          1873:                                convert_to_string(object);
        !          1874: 
        !          1875:                                if (zend_lookup_class(Z_STRVAL_P(object), Z_STRLEN_P(object), &pce TSRMLS_CC) == FAILURE) {
        !          1876:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Class %s has not been declared", Z_STRVAL_P(object));
        !          1877:                                        /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
        !          1878:                                } else {
        !          1879:                                        ce = *pce;
        !          1880:                                }
        !          1881:                        }
        !          1882:                }
        !          1883:        }
        !          1884: 
        !          1885:        /* Reset no. of arguments to 1 so that we can use INTERNAL_FUNCTION_PARAM_PASSTHRU */
        !          1886:        ht= 1;
        !          1887:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
        !          1888:        if (Z_TYPE_P(return_value) == IS_ARRAY) {
        !          1889:                object_and_properties_init(return_value, ce, Z_ARRVAL_P(return_value));
        !          1890:        }
        !          1891: }
        !          1892: /* }}} */
        !          1893: 
        !          1894: /* {{{ proto array sybase_fetch_array(resource result)
        !          1895:    Fetch row as array */
        !          1896: PHP_FUNCTION(sybase_fetch_array)
        !          1897: {
        !          1898:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
        !          1899: }
        !          1900: /* }}} */
        !          1901: 
        !          1902: /* {{{ proto array sybase_fetch_assoc(resource result)
        !          1903:    Fetch row as array without numberic indices */
        !          1904: PHP_FUNCTION(sybase_fetch_assoc)
        !          1905: {
        !          1906:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
        !          1907: }
        !          1908: /* }}} */
        !          1909: 
        !          1910: /* {{{ proto bool sybase_data_seek(resource result, int offset)
        !          1911:    Move internal row pointer */
        !          1912: PHP_FUNCTION(sybase_data_seek)
        !          1913: {
        !          1914:        zval *sybase_result_index = NULL;
        !          1915:        long offset;
        !          1916:        sybase_result *result;
        !          1917: 
        !          1918:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &offset) == FAILURE) {
        !          1919:                return;
        !          1920:        }
        !          1921:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1922: 
        !          1923:        /* Unbuffered ? */
        !          1924:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && offset >= result->num_rows) {
        !          1925:                php_sybase_fetch_result_row(result, offset+ 1);
        !          1926:        }
        !          1927:        
        !          1928:        if (offset < 0 || offset >= result->num_rows) {
        !          1929:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset %ld, must be betweem 0 and %d", offset, result->num_rows - 1);
        !          1930:                RETURN_FALSE;
        !          1931:        }
        !          1932: 
        !          1933:        result->cur_row = offset;
        !          1934:        RETURN_TRUE;
        !          1935: }
        !          1936: /* }}} */
        !          1937: 
        !          1938: static char *php_sybase_get_field_name(CS_INT type)
        !          1939: {
        !          1940:        switch (type) {
        !          1941:                case CS_CHAR_TYPE:
        !          1942:                case CS_VARCHAR_TYPE:
        !          1943:                case CS_TEXT_TYPE:
        !          1944:                        return "string";
        !          1945:                        break;
        !          1946:                case CS_IMAGE_TYPE:
        !          1947:                        return "image";
        !          1948:                        break;
        !          1949:                case CS_BINARY_TYPE:
        !          1950:                case CS_VARBINARY_TYPE:
        !          1951:                        return "blob";
        !          1952:                        break;
        !          1953:                case CS_BIT_TYPE:
        !          1954:                        return "bit";
        !          1955:                        break;
        !          1956:                case CS_TINYINT_TYPE:
        !          1957:                case CS_SMALLINT_TYPE:
        !          1958:                case CS_INT_TYPE:
        !          1959:                        return "int";
        !          1960:                        break;
        !          1961:                case CS_REAL_TYPE:
        !          1962:                case CS_FLOAT_TYPE:
        !          1963:                case CS_NUMERIC_TYPE:
        !          1964:                case CS_DECIMAL_TYPE:
        !          1965:                        return "real";
        !          1966:                        break;
        !          1967:                case CS_MONEY_TYPE:
        !          1968:                case CS_MONEY4_TYPE:
        !          1969:                        return "money";
        !          1970:                        break;
        !          1971:                case CS_DATETIME_TYPE:
        !          1972:                case CS_DATETIME4_TYPE:
        !          1973:                        return "datetime";
        !          1974:                        break;
        !          1975:                default:
        !          1976:                        return "unknown";
        !          1977:                        break;
        !          1978:        }
        !          1979: }
        !          1980: 
        !          1981: 
        !          1982: /* {{{ proto object sybase_fetch_field(resource result [, int offset])
        !          1983:    Get field information */
        !          1984: PHP_FUNCTION(sybase_fetch_field)
        !          1985: {
        !          1986:        zval *sybase_result_index = NULL;
        !          1987:        long field_offset = -1;
        !          1988:        sybase_result *result;
        !          1989: 
        !          1990:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &sybase_result_index, &field_offset) == FAILURE) {
        !          1991:                return;
        !          1992:        }
        !          1993:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          1994: 
        !          1995:        if (field_offset == -1) {
        !          1996:                field_offset = result->cur_field;
        !          1997:                result->cur_field++;
        !          1998:        }
        !          1999: 
        !          2000:        if (field_offset < 0 || field_offset >= result->num_fields) {
        !          2001:                if (ZEND_NUM_ARGS() == 2) { /* field specified explicitly */
        !          2002:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
        !          2003:                }
        !          2004:                RETURN_FALSE;
        !          2005:        }
        !          2006: 
        !          2007:        object_init(return_value);
        !          2008: 
        !          2009:        add_property_string(return_value, "name", result->fields[field_offset].name, 1);
        !          2010:        add_property_long(return_value, "max_length", result->fields[field_offset].max_length);
        !          2011:        add_property_string(return_value, "column_source", result->fields[field_offset].column_source, 1);
        !          2012:        add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
        !          2013:        add_property_string(return_value, "type", php_sybase_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
        !          2014: }
        !          2015: /* }}} */
        !          2016: 
        !          2017: 
        !          2018: /* {{{ proto bool sybase_field_seek(resource result, int offset)
        !          2019:    Set field offset */
        !          2020: PHP_FUNCTION(sybase_field_seek)
        !          2021: {
        !          2022:        zval *sybase_result_index = NULL;
        !          2023:        long field_offset;
        !          2024:        sybase_result *result;
        !          2025: 
        !          2026:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &field_offset) == FAILURE) {
        !          2027:                return;
        !          2028:        }
        !          2029:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          2030: 
        !          2031:        if (field_offset < 0 || field_offset >= result->num_fields) {
        !          2032:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
        !          2033:                RETURN_FALSE;
        !          2034:        }
        !          2035: 
        !          2036:        result->cur_field = field_offset;
        !          2037:        RETURN_TRUE;
        !          2038: }
        !          2039: /* }}} */
        !          2040: 
        !          2041: 
        !          2042: /* {{{ proto string sybase_result(resource result, int row, mixed field)
        !          2043:    Get result data */
        !          2044: PHP_FUNCTION(sybase_result)
        !          2045: {
        !          2046:        zval *field;
        !          2047:        zval *sybase_result_index = NULL;
        !          2048:        long row;
        !          2049:        int field_offset = 0;
        !          2050:        sybase_result *result;
        !          2051: 
        !          2052:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &sybase_result_index, &row, &field) == FAILURE) {
        !          2053:                return;
        !          2054:        }
        !          2055:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
        !          2056:        
        !          2057:        /* Unbuffered ? */
        !          2058:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && row >= result->num_rows) {
        !          2059:                php_sybase_fetch_result_row(result, row);
        !          2060:        }
        !          2061: 
        !          2062:        if (row < 0 || row >= result->num_rows) {
        !          2063:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset (%ld)", row);
        !          2064:                RETURN_FALSE;
        !          2065:        }
        !          2066: 
        !          2067:        switch(Z_TYPE_P(field)) {
        !          2068:                case IS_STRING: {
        !          2069:                        int i;
        !          2070: 
        !          2071:                        for (i = 0; i < result->num_fields; i++) {
        !          2072:                                if (strcasecmp(result->fields[i].name, Z_STRVAL_P(field)) == 0) {
        !          2073:                                        field_offset = i;
        !          2074:                                        break;
        !          2075:                                }
        !          2076:                        }
        !          2077:                        if (i >= result->num_fields) { /* no match found */
        !          2078:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  %s field not found in result", Z_STRVAL_P(field));
        !          2079:                                RETURN_FALSE;
        !          2080:                        }
        !          2081:                        break;
        !          2082:                }
        !          2083:                default:
        !          2084:                        convert_to_long(field);
        !          2085:                        field_offset = Z_LVAL_P(field);
        !          2086:                        if (field_offset < 0 || field_offset >= result->num_fields) {
        !          2087:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset specified");
        !          2088:                                RETURN_FALSE;
        !          2089:                        }
        !          2090:                        break;
        !          2091:        }
        !          2092: 
        !          2093:        *return_value = result->data[row][field_offset];
        !          2094:        zval_copy_ctor(return_value);
        !          2095: }
        !          2096: /* }}} */
        !          2097: 
        !          2098: 
        !          2099: /* {{{ proto int sybase_affected_rows([resource link_id])
        !          2100:    Get number of affected rows in last query */
        !          2101: PHP_FUNCTION(sybase_affected_rows)
        !          2102: {
        !          2103:        zval *sybase_link_index = NULL;
        !          2104:        sybase_link *sybase_ptr;
        !          2105:        int id;
        !          2106: 
        !          2107:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &sybase_link_index) == FAILURE) {
        !          2108:                return;
        !          2109:        }
        !          2110: 
        !          2111:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
        !          2112:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
        !          2113:                RETURN_FALSE;
        !          2114:        }
        !          2115: 
        !          2116:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
        !          2117: 
        !          2118:        Z_LVAL_P(return_value) = sybase_ptr->affected_rows;
        !          2119:        Z_TYPE_P(return_value) = IS_LONG;
        !          2120: }
        !          2121: /* }}} */
        !          2122: 
        !          2123: 
        !          2124: PHP_MINFO_FUNCTION(sybase)
        !          2125: {
        !          2126:        char buf[32];
        !          2127: 
        !          2128:        php_info_print_table_start();
        !          2129:        php_info_print_table_header(2, "Sybase_CT Support", "enabled" );
        !          2130:        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_persistent));
        !          2131:        php_info_print_table_row(2, "Active Persistent Links", buf);
        !          2132:        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_links));
        !          2133:        php_info_print_table_row(2, "Active Links", buf);
        !          2134:        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_server_severity));
        !          2135:        php_info_print_table_row(2, "Min server severity", buf);
        !          2136:        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_client_severity));
        !          2137:        php_info_print_table_row(2, "Min client severity", buf);        
        !          2138:        php_info_print_table_row(2, "Application Name", SybCtG(appname));
        !          2139:        snprintf(buf, sizeof(buf), "%ld", SybCtG(deadlock_retry_count));
        !          2140:        php_info_print_table_row(2, "Deadlock retry count", buf);
        !          2141:        php_info_print_table_end();
        !          2142: 
        !          2143:        DISPLAY_INI_ENTRIES();
        !          2144: }
        !          2145: 
        !          2146: 
        !          2147: /* {{{ proto void sybase_min_client_severity(int severity)
        !          2148:    Sets minimum client severity */
        !          2149: PHP_FUNCTION(sybase_min_client_severity)
        !          2150: {
        !          2151:        long severity;
        !          2152: 
        !          2153:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
        !          2154:                return;
        !          2155:        }
        !          2156:        
        !          2157:        SybCtG(min_client_severity) = severity;
        !          2158: }
        !          2159: /* }}} */
        !          2160: 
        !          2161: 
        !          2162: /* {{{ proto void sybase_min_server_severity(int severity)
        !          2163:    Sets minimum server severity */
        !          2164: PHP_FUNCTION(sybase_min_server_severity)
        !          2165: {
        !          2166:        long severity;
        !          2167: 
        !          2168:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
        !          2169:                return;
        !          2170:        }
        !          2171:        
        !          2172:        SybCtG(min_server_severity) = severity;
        !          2173: }
        !          2174: /* }}} */
        !          2175: 
        !          2176: /* {{{ proto void sybase_deadlock_retry_count(int retry_count)
        !          2177:    Sets deadlock retry count */
        !          2178: PHP_FUNCTION(sybase_deadlock_retry_count)
        !          2179: {
        !          2180:        long retry_count;
        !          2181: 
        !          2182:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &retry_count) == FAILURE) {
        !          2183:                return;
        !          2184:        }
        !          2185:        
        !          2186:        SybCtG(deadlock_retry_count) = retry_count;
        !          2187: }
        !          2188: /* }}} */
        !          2189: 
        !          2190: 
        !          2191: /* {{{ proto bool sybase_set_message_handler(mixed error_func [, resource connection])
        !          2192:    Set the error handler, to be called when a server message is raised. 
        !          2193:    If error_func is NULL the handler will be deleted */
        !          2194: PHP_FUNCTION(sybase_set_message_handler)
        !          2195: {
        !          2196:        zend_fcall_info fci = empty_fcall_info;
        !          2197:        zend_fcall_info_cache cache = empty_fcall_info_cache;
        !          2198:        zval *sybase_link_index= NULL;
        !          2199:        sybase_link *sybase_ptr;
        !          2200:        zval **callback;
        !          2201:        int id;
        !          2202: 
        !          2203:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!|r", &fci, &cache, &sybase_link_index) == FAILURE) {
        !          2204:                return;
        !          2205:        }
        !          2206: 
        !          2207:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
        !          2208: 
        !          2209:                /* Doesn't matter if we're not connected yet, use default */
        !          2210:                callback= &SybCtG(callback_name);
        !          2211:        } else if (-1 == id) {
        !          2212: 
        !          2213:                /* Connection-based message handler */
        !          2214:                ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
        !          2215:                callback= &sybase_ptr->callback_name;
        !          2216:        } else {
        !          2217: 
        !          2218:                /* Default message handler */
        !          2219:                callback= &SybCtG(callback_name);
        !          2220:        }
        !          2221: 
        !          2222:        /* Clean old callback */
        !          2223:        if (*callback) {
        !          2224:                zval_ptr_dtor(callback);
        !          2225:                *callback = NULL;
        !          2226:        }
        !          2227: 
        !          2228:        if (ZEND_FCI_INITIALIZED(fci)) {
        !          2229:                ALLOC_ZVAL(*callback);
        !          2230:                **callback = *fci.function_name;
        !          2231:                INIT_PZVAL(*callback);
        !          2232:                zval_copy_ctor(*callback);
        !          2233:        } else {
        !          2234:                callback= NULL;
        !          2235:        }
        !          2236: 
        !          2237:        RETURN_TRUE;
        !          2238: }
        !          2239: /* }}} */
        !          2240: 
        !          2241: 
        !          2242: #endif
        !          2243: 
        !          2244: /*
        !          2245:  * Local variables:
        !          2246:  * tab-width: 4
        !          2247:  * c-basic-offset: 4
        !          2248:  * End:
        !          2249:  */

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