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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3   misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      21: /* $Id$ */
1.1       misho      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:
1.1.1.4 ! misho    1124:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Command failed, canceling rest");
1.1       misho    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. */
1.1.1.4 ! misho    1134:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, canceling current");
1.1       misho    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:
1.1.1.4 ! misho    1144:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, canceling all");
1.1       misho    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: 
1.1.1.2   misho    1194: static int php_sybase_fetch_result_row(sybase_result *result, int numrows TSRMLS_DC)
1.1       misho    1195: {
                   1196:        int i, j;
                   1197:        CS_INT retcode;
                   1198:        
                   1199:        /* We've already fetched everything */
                   1200:        if (result->last_retcode == CS_END_DATA || result->last_retcode == CS_END_RESULTS) {
                   1201:                return result->last_retcode;
                   1202:        }
                   1203:        
                   1204:        if (numrows!=-1) numrows+= result->num_rows;
                   1205:        while ((retcode=ct_fetch(result->sybase_ptr->cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL))==CS_SUCCEED || retcode == CS_ROW_FAIL) {
                   1206:                result->num_rows++;
                   1207:                i= result->store ? result->num_rows- 1 : 0;
                   1208:                if (i >= result->blocks_initialized*SYBASE_ROWS_BLOCK) {
                   1209:                        result->data = (zval **) safe_erealloc(result->data, SYBASE_ROWS_BLOCK*(++result->blocks_initialized), sizeof(zval *), 0);
                   1210:                }
                   1211:                if (result->store || 1 == result->num_rows) {
                   1212:                        result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
                   1213:                }
                   1214: 
                   1215:                for (j = 0; j < result->num_fields; j++) {
                   1216: 
                   1217:                        /* If we are in non-storing mode, free the previous result */
                   1218:                        if (!result->store && result->num_rows > 1 && Z_TYPE(result->data[i][j]) == IS_STRING) {
                   1219:                                efree(Z_STRVAL(result->data[i][j]));
                   1220:                        }
                   1221: 
                   1222:                        if (result->indicators[j] == -1) { /* null value */
                   1223:                                ZVAL_NULL(&result->data[i][j]);
                   1224:                        } else {
                   1225:                                switch (result->numerics[j]) {
                   1226:                                        case 1: {
                   1227:                                                /* This indicates a long */
                   1228:                                                ZVAL_LONG(&result->data[i][j], strtol(result->tmp_buffer[j], NULL, 10));
                   1229:                                                break;
                   1230:                                        }
                   1231:                                        
                   1232:                                        case 2: {
                   1233:                                                /* This indicates a float */
                   1234:                                                RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
                   1235:                                                break;
                   1236:                                        }
                   1237: 
                   1238:                                        case 3: {
                   1239:                                                /* This indicates either a long or a float, which ever fits */
                   1240:                                                errno = 0;
                   1241:                                                Z_LVAL(result->data[i][j]) = strtol(result->tmp_buffer[j], NULL, 10);
                   1242:                                                if (errno == ERANGE) {
                   1243:                                                
                   1244:                                                        /* An overflow occurred, so try to fit it into a double */
                   1245:                                                        RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
                   1246:                                                        break;
                   1247:                                                }
                   1248:                                                Z_TYPE(result->data[i][j]) = IS_LONG;
                   1249:                                                break;
                   1250:                                        }
                   1251:                                        
                   1252:                                        default: {
                   1253:                                                /* This indicates anything else, return it as string
                   1254:                                                 * FreeTDS doesn't correctly set result->indicators[j] correctly
                   1255:                                                 * for NULL fields in some version in conjunction with ASE 12.5
                   1256:                                                 * but instead sets result->lengths[j] to 0, which would lead to
                   1257:                                                 * a negative memory allocation (and thus a segfault).
                   1258:                                                 */
                   1259:                                                if (result->lengths[j] < 1) {
                   1260:                                                        ZVAL_NULL(&result->data[i][j]);
                   1261:                                                } else {
                   1262:                                                        ZVAL_STRINGL(&result->data[i][j], result->tmp_buffer[j], result->lengths[j]- 1, 1);
                   1263:                                                }
                   1264:                                                break;
                   1265:                                        }
                   1266:                                }
                   1267:                        }
                   1268:                }
                   1269:                if (numrows!=-1 && result->num_rows>=numrows) break;
                   1270:        }
                   1271: 
                   1272:        if (retcode==CS_ROW_FAIL) {
                   1273:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Error reading row %d", result->num_rows);
                   1274:                return retcode;
                   1275:        }
                   1276:        result->last_retcode= retcode;
                   1277:        switch (retcode) {
                   1278:                case CS_END_DATA:
                   1279:                        retcode = php_sybase_finish_results(result TSRMLS_CC);
                   1280:                        break;
                   1281:                        
                   1282:                case CS_ROW_FAIL:
                   1283:                case CS_SUCCEED:
                   1284:                        break;
                   1285:                        
                   1286:                default:
                   1287:                        FREE_SYBASE_RESULT(result);
                   1288:                        result = NULL;
                   1289:                        retcode = CS_FAIL;              /* Just to be sure */
                   1290:                        break;
                   1291:        }
                   1292:        
                   1293:        return retcode;
                   1294: }
                   1295: 
1.1.1.2   misho    1296: static sybase_result * php_sybase_fetch_result_set(sybase_link *sybase_ptr, int buffered, int store TSRMLS_DC)
1.1       misho    1297: {
                   1298:        int num_fields;
                   1299:        sybase_result *result;
                   1300:        int i, j;
                   1301:        CS_INT retcode;
                   1302: 
                   1303:        /* The following (if unbuffered) is more or less the equivalent of mysql_store_result().
                   1304:         * fetch all rows from the server into the row buffer, thus:
                   1305:         * 1)  Being able to fire up another query without explicitly reading all rows
                   1306:         * 2)  Having numrows accessible
                   1307:         */
                   1308:        if (ct_res_info(sybase_ptr->cmd, CS_NUMDATA, &num_fields, CS_UNUSED, NULL)!=CS_SUCCEED) {
                   1309:                return NULL;
                   1310:        }
                   1311:        
                   1312:        result = (sybase_result *) emalloc(sizeof(sybase_result));
                   1313:        result->data = (zval **) safe_emalloc(sizeof(zval *), SYBASE_ROWS_BLOCK, 0);
                   1314:        result->fields = NULL;
                   1315:        result->sybase_ptr = sybase_ptr;
                   1316:        result->cur_field=result->cur_row=result->num_rows=0;
                   1317:        result->num_fields = num_fields;
                   1318:        result->last_retcode = 0;
                   1319:        result->store= store;
                   1320:        result->blocks_initialized= 1;
                   1321:        result->tmp_buffer = (char **) safe_emalloc(sizeof(char *), num_fields, 0);
                   1322:        result->lengths = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
                   1323:        result->indicators = (CS_SMALLINT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
                   1324:        result->datafmt = (CS_DATAFMT *) safe_emalloc(sizeof(CS_DATAFMT), num_fields, 0);
                   1325:        result->numerics = (unsigned char *) safe_emalloc(sizeof(unsigned char), num_fields, 0);
                   1326:        result->types = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
                   1327:        
                   1328:        for (i=0; i<num_fields; i++) {
                   1329:                ct_describe(sybase_ptr->cmd, i+1, &result->datafmt[i]);
                   1330:                result->types[i] = result->datafmt[i].datatype;
                   1331:                switch (result->datafmt[i].datatype) {
                   1332:                        case CS_CHAR_TYPE:
                   1333:                        case CS_VARCHAR_TYPE:
                   1334:                        case CS_TEXT_TYPE:
                   1335:                        case CS_IMAGE_TYPE:
                   1336:                                result->datafmt[i].maxlength++;
                   1337:                                result->numerics[i] = 0;
                   1338:                                break;
                   1339:                        case CS_BINARY_TYPE:
                   1340:                        case CS_VARBINARY_TYPE:
                   1341:                                result->datafmt[i].maxlength *= 2;
                   1342:                                result->datafmt[i].maxlength++;
                   1343:                                result->numerics[i] = 0;
                   1344:                                break;
                   1345:                        case CS_BIT_TYPE:
                   1346:                        case CS_TINYINT_TYPE:
                   1347:                                result->datafmt[i].maxlength = 4;
                   1348:                                result->numerics[i] = 1;
                   1349:                                break;
                   1350:                        case CS_SMALLINT_TYPE:
                   1351:                                result->datafmt[i].maxlength = 7;
                   1352:                                result->numerics[i] = 1;
                   1353:                                break;
                   1354:                        case CS_INT_TYPE:
                   1355:                                result->datafmt[i].maxlength = 12;
                   1356:                                result->numerics[i] = 1;
                   1357:                                break;
                   1358:                        case CS_REAL_TYPE:
                   1359:                        case CS_FLOAT_TYPE:
                   1360:                                result->datafmt[i].maxlength = 24;
                   1361:                                result->numerics[i] = 2;
                   1362:                                break;
                   1363:                        case CS_MONEY_TYPE:
                   1364:                        case CS_MONEY4_TYPE:
                   1365:                                result->datafmt[i].maxlength = 24;
                   1366:                                result->numerics[i] = 2;
                   1367:                                break;
                   1368:                        case CS_DATETIME_TYPE:
                   1369:                        case CS_DATETIME4_TYPE:
                   1370:                                result->datafmt[i].maxlength = 30;
                   1371:                                result->numerics[i] = 0;
                   1372:                                break;
                   1373:                        case CS_NUMERIC_TYPE:
                   1374:                        case CS_DECIMAL_TYPE:
                   1375:                                result->datafmt[i].maxlength = result->datafmt[i].precision + 3;
                   1376:                                /* numeric(10) vs numeric(10, 1) */
                   1377:                                result->numerics[i] = (result->datafmt[i].scale == 0) ? 3 : 2;
                   1378:                                break;
                   1379:                        default:
                   1380:                                result->datafmt[i].maxlength++;
                   1381:                                result->numerics[i] = 0;
                   1382:                                break;
                   1383:                }
                   1384:                result->tmp_buffer[i] = (char *)emalloc(result->datafmt[i].maxlength);
                   1385:                result->datafmt[i].datatype = CS_CHAR_TYPE;
                   1386:                result->datafmt[i].format = CS_FMT_NULLTERM;
                   1387:                ct_bind(sybase_ptr->cmd, i+1, &result->datafmt[i], result->tmp_buffer[i], &result->lengths[i], &result->indicators[i]);
                   1388:        }
                   1389: 
                   1390:        result->fields = (sybase_field *) safe_emalloc(sizeof(sybase_field), num_fields, 0);
                   1391:        j=0;
                   1392:        for (i=0; i<num_fields; i++) {
                   1393:                char computed_buf[16];
                   1394: 
                   1395:                if (result->datafmt[i].namelen>0) {
                   1396:                        result->fields[i].name = estrndup(result->datafmt[i].name, result->datafmt[i].namelen);
                   1397:                } else {
                   1398:                        if (j>0) {
                   1399:                                snprintf(computed_buf, 16, "computed%d", j);
                   1400:                        } else {
                   1401:                                strcpy(computed_buf, "computed");
                   1402:                        }
                   1403:                        result->fields[i].name = estrdup(computed_buf);
                   1404:                        j++;
                   1405:                }
                   1406:                result->fields[i].column_source = STR_EMPTY_ALLOC();
                   1407:                result->fields[i].max_length = result->datafmt[i].maxlength-1;
                   1408:                result->fields[i].numeric = result->numerics[i];
                   1409:                Z_TYPE(result->fields[i]) = result->types[i];
                   1410:        }
                   1411:        
                   1412:        if (buffered) {
                   1413:                retcode = CS_SUCCEED;
                   1414:        } else {
1.1.1.2   misho    1415:                if ((retcode = php_sybase_fetch_result_row(result, -1 TSRMLS_CC)) == CS_FAIL) {
1.1       misho    1416:                        return NULL;
                   1417:                }
                   1418:        }
                   1419: 
                   1420:        result->last_retcode = retcode;
                   1421:        return result;
                   1422: }
                   1423: 
                   1424: static void php_sybase_query (INTERNAL_FUNCTION_PARAMETERS, int buffered)
                   1425: {
                   1426:        zval *sybase_link_index = NULL;
                   1427:        zend_bool store = 1;
                   1428:        char *query;
                   1429:        int len, id, deadlock_count;
                   1430:        sybase_link *sybase_ptr;
                   1431:        sybase_result *result;
                   1432:        CS_INT restype;
                   1433:        CS_RETCODE retcode;
                   1434:        enum {
                   1435:                Q_RESULT,                               /* Success with results. */
                   1436:                Q_SUCCESS,                              /* Success but no results. */
                   1437:                Q_FAILURE,                              /* Failure, no results. */
                   1438:        } status;
                   1439: 
                   1440:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|rb", &query, &len, &sybase_link_index, &store) == FAILURE) {
                   1441:                return;
                   1442:        }
                   1443: 
                   1444:        if (!store && !buffered) {
                   1445:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Cannot use non-storing mode with buffered queries");
                   1446:                store = 1;
                   1447:        }
                   1448: 
                   1449:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
                   1450:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
                   1451:                RETURN_FALSE;
                   1452:        }
                   1453: 
                   1454:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
                   1455: 
                   1456:        /* Fail if we already marked this connection dead. */
                   1457:        if (sybase_ptr->dead) {
                   1458:                RETURN_FALSE;
                   1459:        }
                   1460:        
                   1461:        /* Check to see if a previous sybase_unbuffered_query has read all rows */
                   1462:        if (sybase_ptr->active_result_index) {
                   1463:                zval *tmp = NULL;
                   1464:                
                   1465:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Called without first fetching all rows from a previous unbuffered query");
                   1466:                if (sybase_ptr->cmd) {
                   1467:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1468:                }
                   1469:                
                   1470:                /* Get the resultset and free it */
                   1471:                ALLOC_ZVAL(tmp);
                   1472:                Z_LVAL_P(tmp)= sybase_ptr->active_result_index;
                   1473:                Z_TYPE_P(tmp)= IS_RESOURCE;
                   1474:                INIT_PZVAL(tmp);
                   1475:                ZEND_FETCH_RESOURCE(result, sybase_result *, &tmp, -1, "Sybase result", le_result);
                   1476:                
                   1477:                if (result) {
                   1478:                        php_sybase_finish_results(result TSRMLS_CC);
                   1479:                }
                   1480:                
                   1481:                zval_ptr_dtor(&tmp);
                   1482:                zend_list_delete(sybase_ptr->active_result_index);
                   1483:                sybase_ptr->active_result_index= 0;
                   1484:        }
                   1485: 
                   1486:        /* Repeat until we don't deadlock. */
                   1487:        deadlock_count= 0;
                   1488:        for (;;) {
                   1489:                result = NULL;
                   1490:                sybase_ptr->deadlock = 0;
                   1491:                sybase_ptr->affected_rows = 0;
                   1492: 
                   1493:                /* On Solaris 11.5, ct_command() can be moved outside the
                   1494:                 * loop, but not on Linux 11.0.
                   1495:                 */
                   1496:                if (ct_command(sybase_ptr->cmd, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED)!=CS_SUCCEED) {
                   1497:                        /* If this didn't work, the connection is screwed but
                   1498:                         * ct-lib might not set CS_CONSTAT_DEAD.  So set our own
                   1499:                         * flag.  This happens sometimes when the database is restarted
                   1500:                         * and/or its machine is rebooted, and ct_command() returns
                   1501:                         * CS_BUSY for some reason.
                   1502:                         */
                   1503:                        sybase_ptr->dead = 1;
                   1504:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Connection is dead");
                   1505:                        RETURN_FALSE;
                   1506:                }
                   1507: 
                   1508:                if (ct_send(sybase_ptr->cmd)!=CS_SUCCEED) {
                   1509:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1510:                        sybase_ptr->dead = 1;
                   1511:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot send command");
                   1512:                        RETURN_FALSE;
                   1513:                }
                   1514: 
                   1515:                /* Use the first result set or succeed/fail status and discard the
                   1516:                 * others.  Applications really shouldn't be making calls that
                   1517:                 * return multiple result sets, but if they do then we need to
                   1518:                 * properly read or cancel them or the connection will become
                   1519:                 * unusable.
                   1520:                 */
                   1521:                if (ct_results(sybase_ptr->cmd, &restype)!=CS_SUCCEED) {
                   1522:                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1523:                        sybase_ptr->dead = 1;
                   1524:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot read results");
                   1525:                        RETURN_FALSE;
                   1526:                }
                   1527:                switch ((int) restype) {
                   1528:                        case CS_CMD_FAIL:
                   1529:                        default:
                   1530:                                status = Q_FAILURE;
                   1531:                                break;
                   1532:                        case CS_CMD_SUCCEED:
                   1533:                        case CS_CMD_DONE: {
                   1534:                                        CS_INT row_count;
                   1535:                                        if (ct_res_info(sybase_ptr->cmd, CS_ROW_COUNT, &row_count, CS_UNUSED, NULL)==CS_SUCCEED) {
                   1536:                                                sybase_ptr->affected_rows = (long)row_count;
                   1537:                                        }
                   1538:                                }
                   1539:                                /* Fall through */
                   1540:                        case CS_COMPUTEFMT_RESULT:
                   1541:                        case CS_ROWFMT_RESULT:
                   1542:                        case CS_DESCRIBE_RESULT:
                   1543:                        case CS_MSG_RESULT:
                   1544:                                buffered= 0;                            /* These queries have no need for buffering */
                   1545:                                status = Q_SUCCESS;
                   1546:                                break;
                   1547:                        case CS_COMPUTE_RESULT:
                   1548:                        case CS_CURSOR_RESULT:
                   1549:                        case CS_PARAM_RESULT:
                   1550:                        case CS_ROW_RESULT:
                   1551:                        case CS_STATUS_RESULT:
1.1.1.2   misho    1552:                                result = php_sybase_fetch_result_set(sybase_ptr, buffered, store TSRMLS_CC);
1.1       misho    1553:                                if (result == NULL) {
                   1554:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1555:                                        RETURN_FALSE;
                   1556:                                }
                   1557:                                status = Q_RESULT;
                   1558:                                break;
                   1559:                }
                   1560:                
                   1561:                /* Check for left-over results */
                   1562:                if (!buffered && status != Q_RESULT) {
                   1563:                        while ((retcode = ct_results(sybase_ptr->cmd, &restype))==CS_SUCCEED) {
                   1564:                                switch ((int) restype) {
                   1565:                                        case CS_CMD_SUCCEED:
                   1566:                                        case CS_CMD_DONE:
                   1567:                                                break;
                   1568: 
                   1569:                                        case CS_CMD_FAIL:
                   1570:                                                status = Q_FAILURE;
                   1571:                                                break;
                   1572: 
                   1573:                                        case CS_COMPUTE_RESULT:
                   1574:                                        case CS_CURSOR_RESULT:
                   1575:                                        case CS_PARAM_RESULT:
                   1576:                                        case CS_ROW_RESULT:
                   1577:                                                if (status != Q_RESULT) {
1.1.1.2   misho    1578:                                                        result = php_sybase_fetch_result_set(sybase_ptr, buffered, store TSRMLS_CC);
1.1       misho    1579:                                                        if (result == NULL) {
                   1580:                                                                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1581:                                                                sybase_ptr->dead = 1;
                   1582:                                                                RETURN_FALSE;
                   1583:                                                        }
                   1584:                                                        status = Q_RESULT;
                   1585:                                                        retcode = result->last_retcode; 
                   1586:                                                } else {
                   1587:                                                        /* Unexpected results, cancel them. */
                   1588:                                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
                   1589:                                                }
                   1590:                                                break;
                   1591:                                        case CS_STATUS_RESULT:
                   1592:                                                /* Unexpected results, cancel them. */
                   1593:                                                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
                   1594:                                                break;
                   1595: 
                   1596:                                        default:
                   1597:                                                status = Q_FAILURE;
                   1598:                                                break;
                   1599:                                }
                   1600:                                if (status == Q_FAILURE) {
                   1601:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1602:                                }
                   1603:                                if (retcode == CS_END_RESULTS) {
                   1604:                                        break;
                   1605:                                }
                   1606:                        }
                   1607:                        switch (retcode) {
                   1608:                                case CS_END_RESULTS:
                   1609:                                        /* Normal. */
                   1610:                                        break;
                   1611: 
                   1612:                                case CS_FAIL:
                   1613:                                        /* Hopefully this either cleans up the connection, or the
                   1614:                                         * connection ends up marked dead so it will be reopened
                   1615:                                         * if it is persistent.  We may want to do
                   1616:                                         * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
                   1617:                                         * doc for ct_results()==CS_FAIL.
                   1618:                                         */
                   1619:                                        ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                   1620:                                        /* Don't take chances with the vagaries of ct-lib.  Mark it
                   1621:                                         * dead ourselves.
                   1622:                                         */
                   1623:                                        sybase_ptr->dead = 1;
                   1624:                                case CS_CANCELED:
                   1625:                                default:
                   1626:                                        status = Q_FAILURE;
                   1627:                                        break;
                   1628:                        }
                   1629:                }
                   1630: 
                   1631:                /* Retry deadlocks up until deadlock_retry_count times */               
                   1632:                if (sybase_ptr->deadlock && SybCtG(deadlock_retry_count) != -1 && ++deadlock_count > SybCtG(deadlock_retry_count)) {
                   1633:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Retried deadlock %d times [max: %ld], giving up", deadlock_count- 1, SybCtG(deadlock_retry_count));
                   1634:                        FREE_SYBASE_RESULT(result);
                   1635:                        break;
                   1636:                }
                   1637: 
                   1638:                /* If query completed without deadlock, break out of the loop.
                   1639:                 * Sometimes deadlock results in failures and sometimes not,
                   1640:                 * it seems to depend on the server flavor.  But we want to
                   1641:                 * retry all deadlocks.
                   1642:                 */
                   1643:                if (sybase_ptr->dead || sybase_ptr->deadlock == 0) {
                   1644:                        break;
                   1645:                }
                   1646: 
                   1647:                /* Get rid of any results we may have fetched.  This happens:
                   1648:                 * e.g., our result set may be a stored procedure status which
                   1649:                 * is returned even if the stored procedure deadlocks.  As an
                   1650:                 * optimization, we could try not to fetch results in known
                   1651:                 * deadlock conditions, but deadlock is (should be) rare.
                   1652:                 */
                   1653:                FREE_SYBASE_RESULT(result);
                   1654:        }
                   1655: 
                   1656:        if (status == Q_SUCCESS) {
                   1657:                RETURN_TRUE;
                   1658:        }
                   1659: 
                   1660:        if (status == Q_FAILURE) {
                   1661:                FREE_SYBASE_RESULT(result);
                   1662:                RETURN_FALSE;
                   1663:        }
                   1664: 
                   1665:        /* Indicate we have data in case of buffered queries */
                   1666:        id= ZEND_REGISTER_RESOURCE(return_value, result, le_result);
                   1667:        sybase_ptr->active_result_index= buffered ? id : 0;
                   1668: }
                   1669: 
                   1670: /* {{{ proto int sybase_query(string query [, resource link_id])
                   1671:    Send Sybase query */
                   1672: PHP_FUNCTION(sybase_query)
                   1673: {
                   1674:        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                   1675: }
                   1676: /* }}} */
                   1677: 
                   1678: /* {{{ proto int sybase_unbuffered_query(string query [, resource link_id])
                   1679:    Send Sybase query */
                   1680: PHP_FUNCTION(sybase_unbuffered_query)
                   1681: {
                   1682:        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                   1683: }
                   1684: 
                   1685: /* {{{ proto bool sybase_free_result(resource result)
                   1686:    Free result memory */
                   1687: PHP_FUNCTION(sybase_free_result)
                   1688: {
                   1689:        zval *sybase_result_index = NULL;
                   1690:        sybase_result *result;
                   1691: 
                   1692:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
                   1693:                return;
                   1694:        }
                   1695:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1696:        
                   1697:        /* Did we fetch up until the end? */
                   1698:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
1.1.1.4 ! misho    1699:                /* php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  canceling the rest of the results"); */
1.1       misho    1700:                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
                   1701:                php_sybase_finish_results(result TSRMLS_CC);
                   1702:        }
                   1703:        
                   1704:        zend_list_delete(Z_LVAL_P(sybase_result_index));
                   1705:        RETURN_TRUE;
                   1706: }
                   1707: 
                   1708: /* }}} */
                   1709: 
                   1710: /* {{{ proto string sybase_get_last_message(void)
                   1711:    Returns the last message from server (over min_message_severity) */
                   1712: PHP_FUNCTION(sybase_get_last_message)
                   1713: {
                   1714:        RETURN_STRING(SybCtG(server_message), 1);
                   1715: }
                   1716: /* }}} */
                   1717: 
                   1718: /* {{{ proto int sybase_num_rows(resource result)
                   1719:    Get number of rows in result */
                   1720: PHP_FUNCTION(sybase_num_rows)
                   1721: {
                   1722:        zval *sybase_result_index = NULL;
                   1723:        sybase_result *result;
                   1724: 
                   1725:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
                   1726:                return;
                   1727:        }
                   1728:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1729: 
                   1730:        Z_LVAL_P(return_value) = result->num_rows;
                   1731:        Z_TYPE_P(return_value) = IS_LONG;
                   1732: }
                   1733: 
                   1734: /* }}} */
                   1735: 
                   1736: /* {{{ proto int sybase_num_fields(resource result)
                   1737:    Get number of fields in result */
                   1738: PHP_FUNCTION(sybase_num_fields)
                   1739: {
                   1740:        zval *sybase_result_index = NULL;
                   1741:        sybase_result *result;
                   1742: 
                   1743:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
                   1744:                return;
                   1745:        }
                   1746:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1747: 
                   1748:        Z_LVAL_P(return_value) = result->num_fields;
                   1749:        Z_TYPE_P(return_value) = IS_LONG;
                   1750: }
                   1751: 
                   1752: /* }}} */
                   1753: 
                   1754: /* {{{ proto array sybase_fetch_row(resource result)
                   1755:    Get row as enumerated array */
                   1756: PHP_FUNCTION(sybase_fetch_row)
                   1757: {
                   1758:        zval *sybase_result_index = NULL;
                   1759:        int i;
                   1760:        sybase_result *result;
                   1761:        zval *field_content;
                   1762: 
                   1763:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
                   1764:                return;
                   1765:        }
                   1766:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1767: 
                   1768:        /* Unbuffered? */
                   1769:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
1.1.1.2   misho    1770:                php_sybase_fetch_result_row(result, 1 TSRMLS_CC);
1.1       misho    1771:        }
                   1772:        
                   1773:        /* At the end? */
                   1774:        if (result->cur_row >= result->num_rows) {
                   1775:                RETURN_FALSE;
                   1776:        }
                   1777: 
                   1778:        array_init(return_value);
                   1779:        for (i=0; i<result->num_fields; i++) {
                   1780:                ALLOC_ZVAL(field_content);
                   1781:                *field_content = result->data[result->store ? result->cur_row : 0][i];
                   1782:                INIT_PZVAL(field_content);
                   1783:                zval_copy_ctor(field_content);
                   1784:                zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &field_content, sizeof(zval* ), NULL);
                   1785:        }
                   1786:        result->cur_row++;
                   1787: }
                   1788: 
                   1789: /* }}} */
                   1790: 
                   1791: static void php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int numerics)
                   1792: {
                   1793:        zval *sybase_result_index = NULL;
                   1794:        sybase_result *result;
                   1795:        int i, j;
                   1796:        zval *tmp;
                   1797:        char name[32];
                   1798: 
                   1799:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
                   1800:                return;
                   1801:        }
                   1802:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1803: 
                   1804:        /* Unbuffered ? Fetch next row */
                   1805:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
1.1.1.2   misho    1806:                php_sybase_fetch_result_row(result, 1 TSRMLS_CC);
1.1       misho    1807:        }
                   1808: 
                   1809:        /* At the end? */
                   1810:        if (result->cur_row >= result->num_rows) {
                   1811:                RETURN_FALSE;
                   1812:        }
                   1813: 
                   1814:        array_init(return_value);
                   1815:        
                   1816:        j= 1;
                   1817:        for (i=0; i<result->num_fields; i++) {
                   1818:                ALLOC_ZVAL(tmp);
                   1819:                *tmp = result->data[result->store ? result->cur_row : 0][i];
                   1820:                INIT_PZVAL(tmp);
1.1.1.2   misho    1821:                zval_copy_ctor(tmp);
1.1       misho    1822:                if (numerics) {
                   1823:                        zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &tmp, sizeof(zval *), NULL);
                   1824:                        Z_ADDREF_P(tmp);
                   1825:                }
                   1826:                
                   1827:                if (zend_hash_exists(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1)) {
                   1828:                        snprintf(name, 32, "%s%d", result->fields[i].name, j);
                   1829:                        result->fields[i].name= estrdup(name);
                   1830:                        j++;
                   1831:                }
                   1832:                zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(zval *), NULL);
                   1833:        }
                   1834:        result->cur_row++;
                   1835: }
                   1836: 
                   1837: 
                   1838: /* {{{ proto object sybase_fetch_object(resource result [, mixed object])
                   1839:    Fetch row as object */
                   1840: PHP_FUNCTION(sybase_fetch_object)
                   1841: {
                   1842:        zval *object = NULL;
                   1843:        zval *sybase_result_index = NULL;
                   1844:        zend_class_entry *ce = NULL;
                   1845:        sybase_result *result;
                   1846:        
                   1847:        /* Was a second parameter given? */
                   1848:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &sybase_result_index, &object) == FAILURE) {
                   1849:                return;
                   1850:        }
                   1851:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1852: 
                   1853:        ce = ZEND_STANDARD_CLASS_DEF_PTR;
                   1854:        if (NULL != object) {           
                   1855:                switch (Z_TYPE_P(object)) {
                   1856:                        case IS_OBJECT: {
                   1857:                                ce = Z_OBJCE_P(object);
                   1858:                                break;
                   1859:                        }
                   1860: 
                   1861:                        case IS_NULL: {
                   1862:                                /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
                   1863:                                break;
                   1864:                        }
                   1865: 
                   1866:                        default: {
                   1867:                                zend_class_entry **pce = NULL;
                   1868:                                convert_to_string(object);
                   1869: 
                   1870:                                if (zend_lookup_class(Z_STRVAL_P(object), Z_STRLEN_P(object), &pce TSRMLS_CC) == FAILURE) {
                   1871:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Class %s has not been declared", Z_STRVAL_P(object));
                   1872:                                        /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
                   1873:                                } else {
                   1874:                                        ce = *pce;
                   1875:                                }
                   1876:                        }
                   1877:                }
                   1878:        }
                   1879: 
                   1880:        /* Reset no. of arguments to 1 so that we can use INTERNAL_FUNCTION_PARAM_PASSTHRU */
                   1881:        ht= 1;
                   1882:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                   1883:        if (Z_TYPE_P(return_value) == IS_ARRAY) {
                   1884:                object_and_properties_init(return_value, ce, Z_ARRVAL_P(return_value));
                   1885:        }
                   1886: }
                   1887: /* }}} */
                   1888: 
                   1889: /* {{{ proto array sybase_fetch_array(resource result)
                   1890:    Fetch row as array */
                   1891: PHP_FUNCTION(sybase_fetch_array)
                   1892: {
                   1893:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                   1894: }
                   1895: /* }}} */
                   1896: 
                   1897: /* {{{ proto array sybase_fetch_assoc(resource result)
                   1898:    Fetch row as array without numberic indices */
                   1899: PHP_FUNCTION(sybase_fetch_assoc)
                   1900: {
                   1901:        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                   1902: }
                   1903: /* }}} */
                   1904: 
                   1905: /* {{{ proto bool sybase_data_seek(resource result, int offset)
                   1906:    Move internal row pointer */
                   1907: PHP_FUNCTION(sybase_data_seek)
                   1908: {
                   1909:        zval *sybase_result_index = NULL;
                   1910:        long offset;
                   1911:        sybase_result *result;
                   1912: 
                   1913:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &offset) == FAILURE) {
                   1914:                return;
                   1915:        }
                   1916:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1917: 
                   1918:        /* Unbuffered ? */
                   1919:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && offset >= result->num_rows) {
1.1.1.2   misho    1920:                php_sybase_fetch_result_row(result, offset+ 1 TSRMLS_CC);
1.1       misho    1921:        }
                   1922:        
                   1923:        if (offset < 0 || offset >= result->num_rows) {
                   1924:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset %ld, must be betweem 0 and %d", offset, result->num_rows - 1);
                   1925:                RETURN_FALSE;
                   1926:        }
                   1927: 
                   1928:        result->cur_row = offset;
                   1929:        RETURN_TRUE;
                   1930: }
                   1931: /* }}} */
                   1932: 
                   1933: static char *php_sybase_get_field_name(CS_INT type)
                   1934: {
                   1935:        switch (type) {
                   1936:                case CS_CHAR_TYPE:
                   1937:                case CS_VARCHAR_TYPE:
                   1938:                case CS_TEXT_TYPE:
                   1939:                        return "string";
                   1940:                        break;
                   1941:                case CS_IMAGE_TYPE:
                   1942:                        return "image";
                   1943:                        break;
                   1944:                case CS_BINARY_TYPE:
                   1945:                case CS_VARBINARY_TYPE:
                   1946:                        return "blob";
                   1947:                        break;
                   1948:                case CS_BIT_TYPE:
                   1949:                        return "bit";
                   1950:                        break;
                   1951:                case CS_TINYINT_TYPE:
                   1952:                case CS_SMALLINT_TYPE:
                   1953:                case CS_INT_TYPE:
                   1954:                        return "int";
                   1955:                        break;
                   1956:                case CS_REAL_TYPE:
                   1957:                case CS_FLOAT_TYPE:
                   1958:                case CS_NUMERIC_TYPE:
                   1959:                case CS_DECIMAL_TYPE:
                   1960:                        return "real";
                   1961:                        break;
                   1962:                case CS_MONEY_TYPE:
                   1963:                case CS_MONEY4_TYPE:
                   1964:                        return "money";
                   1965:                        break;
                   1966:                case CS_DATETIME_TYPE:
                   1967:                case CS_DATETIME4_TYPE:
                   1968:                        return "datetime";
                   1969:                        break;
                   1970:                default:
                   1971:                        return "unknown";
                   1972:                        break;
                   1973:        }
                   1974: }
                   1975: 
                   1976: 
                   1977: /* {{{ proto object sybase_fetch_field(resource result [, int offset])
                   1978:    Get field information */
                   1979: PHP_FUNCTION(sybase_fetch_field)
                   1980: {
                   1981:        zval *sybase_result_index = NULL;
                   1982:        long field_offset = -1;
                   1983:        sybase_result *result;
                   1984: 
                   1985:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &sybase_result_index, &field_offset) == FAILURE) {
                   1986:                return;
                   1987:        }
                   1988:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   1989: 
                   1990:        if (field_offset == -1) {
                   1991:                field_offset = result->cur_field;
                   1992:                result->cur_field++;
                   1993:        }
                   1994: 
                   1995:        if (field_offset < 0 || field_offset >= result->num_fields) {
                   1996:                if (ZEND_NUM_ARGS() == 2) { /* field specified explicitly */
                   1997:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
                   1998:                }
                   1999:                RETURN_FALSE;
                   2000:        }
                   2001: 
                   2002:        object_init(return_value);
                   2003: 
                   2004:        add_property_string(return_value, "name", result->fields[field_offset].name, 1);
                   2005:        add_property_long(return_value, "max_length", result->fields[field_offset].max_length);
                   2006:        add_property_string(return_value, "column_source", result->fields[field_offset].column_source, 1);
                   2007:        add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
                   2008:        add_property_string(return_value, "type", php_sybase_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
                   2009: }
                   2010: /* }}} */
                   2011: 
                   2012: 
                   2013: /* {{{ proto bool sybase_field_seek(resource result, int offset)
                   2014:    Set field offset */
                   2015: PHP_FUNCTION(sybase_field_seek)
                   2016: {
                   2017:        zval *sybase_result_index = NULL;
                   2018:        long field_offset;
                   2019:        sybase_result *result;
                   2020: 
                   2021:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &field_offset) == FAILURE) {
                   2022:                return;
                   2023:        }
                   2024:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   2025: 
                   2026:        if (field_offset < 0 || field_offset >= result->num_fields) {
                   2027:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
                   2028:                RETURN_FALSE;
                   2029:        }
                   2030: 
                   2031:        result->cur_field = field_offset;
                   2032:        RETURN_TRUE;
                   2033: }
                   2034: /* }}} */
                   2035: 
                   2036: 
                   2037: /* {{{ proto string sybase_result(resource result, int row, mixed field)
                   2038:    Get result data */
                   2039: PHP_FUNCTION(sybase_result)
                   2040: {
                   2041:        zval *field;
                   2042:        zval *sybase_result_index = NULL;
                   2043:        long row;
                   2044:        int field_offset = 0;
                   2045:        sybase_result *result;
                   2046: 
                   2047:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &sybase_result_index, &row, &field) == FAILURE) {
                   2048:                return;
                   2049:        }
                   2050:        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
                   2051:        
                   2052:        /* Unbuffered ? */
                   2053:        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && row >= result->num_rows) {
1.1.1.2   misho    2054:                php_sybase_fetch_result_row(result, row TSRMLS_CC);
1.1       misho    2055:        }
                   2056: 
                   2057:        if (row < 0 || row >= result->num_rows) {
                   2058:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset (%ld)", row);
                   2059:                RETURN_FALSE;
                   2060:        }
                   2061: 
                   2062:        switch(Z_TYPE_P(field)) {
                   2063:                case IS_STRING: {
                   2064:                        int i;
                   2065: 
                   2066:                        for (i = 0; i < result->num_fields; i++) {
                   2067:                                if (strcasecmp(result->fields[i].name, Z_STRVAL_P(field)) == 0) {
                   2068:                                        field_offset = i;
                   2069:                                        break;
                   2070:                                }
                   2071:                        }
                   2072:                        if (i >= result->num_fields) { /* no match found */
                   2073:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  %s field not found in result", Z_STRVAL_P(field));
                   2074:                                RETURN_FALSE;
                   2075:                        }
                   2076:                        break;
                   2077:                }
                   2078:                default:
                   2079:                        convert_to_long(field);
                   2080:                        field_offset = Z_LVAL_P(field);
                   2081:                        if (field_offset < 0 || field_offset >= result->num_fields) {
                   2082:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset specified");
                   2083:                                RETURN_FALSE;
                   2084:                        }
                   2085:                        break;
                   2086:        }
                   2087: 
                   2088:        *return_value = result->data[row][field_offset];
                   2089:        zval_copy_ctor(return_value);
                   2090: }
                   2091: /* }}} */
                   2092: 
                   2093: 
                   2094: /* {{{ proto int sybase_affected_rows([resource link_id])
                   2095:    Get number of affected rows in last query */
                   2096: PHP_FUNCTION(sybase_affected_rows)
                   2097: {
                   2098:        zval *sybase_link_index = NULL;
                   2099:        sybase_link *sybase_ptr;
                   2100:        int id;
                   2101: 
                   2102:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &sybase_link_index) == FAILURE) {
                   2103:                return;
                   2104:        }
                   2105: 
                   2106:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
                   2107:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
                   2108:                RETURN_FALSE;
                   2109:        }
                   2110: 
                   2111:        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
                   2112: 
                   2113:        Z_LVAL_P(return_value) = sybase_ptr->affected_rows;
                   2114:        Z_TYPE_P(return_value) = IS_LONG;
                   2115: }
                   2116: /* }}} */
                   2117: 
                   2118: 
                   2119: PHP_MINFO_FUNCTION(sybase)
                   2120: {
                   2121:        char buf[32];
                   2122: 
                   2123:        php_info_print_table_start();
                   2124:        php_info_print_table_header(2, "Sybase_CT Support", "enabled" );
                   2125:        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_persistent));
                   2126:        php_info_print_table_row(2, "Active Persistent Links", buf);
                   2127:        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_links));
                   2128:        php_info_print_table_row(2, "Active Links", buf);
                   2129:        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_server_severity));
                   2130:        php_info_print_table_row(2, "Min server severity", buf);
                   2131:        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_client_severity));
                   2132:        php_info_print_table_row(2, "Min client severity", buf);        
                   2133:        php_info_print_table_row(2, "Application Name", SybCtG(appname));
                   2134:        snprintf(buf, sizeof(buf), "%ld", SybCtG(deadlock_retry_count));
                   2135:        php_info_print_table_row(2, "Deadlock retry count", buf);
                   2136:        php_info_print_table_end();
                   2137: 
                   2138:        DISPLAY_INI_ENTRIES();
                   2139: }
                   2140: 
                   2141: 
                   2142: /* {{{ proto void sybase_min_client_severity(int severity)
                   2143:    Sets minimum client severity */
                   2144: PHP_FUNCTION(sybase_min_client_severity)
                   2145: {
                   2146:        long severity;
                   2147: 
                   2148:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
                   2149:                return;
                   2150:        }
                   2151:        
                   2152:        SybCtG(min_client_severity) = severity;
                   2153: }
                   2154: /* }}} */
                   2155: 
                   2156: 
                   2157: /* {{{ proto void sybase_min_server_severity(int severity)
                   2158:    Sets minimum server severity */
                   2159: PHP_FUNCTION(sybase_min_server_severity)
                   2160: {
                   2161:        long severity;
                   2162: 
                   2163:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
                   2164:                return;
                   2165:        }
                   2166:        
                   2167:        SybCtG(min_server_severity) = severity;
                   2168: }
                   2169: /* }}} */
                   2170: 
                   2171: /* {{{ proto void sybase_deadlock_retry_count(int retry_count)
                   2172:    Sets deadlock retry count */
                   2173: PHP_FUNCTION(sybase_deadlock_retry_count)
                   2174: {
                   2175:        long retry_count;
                   2176: 
                   2177:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &retry_count) == FAILURE) {
                   2178:                return;
                   2179:        }
                   2180:        
                   2181:        SybCtG(deadlock_retry_count) = retry_count;
                   2182: }
                   2183: /* }}} */
                   2184: 
                   2185: 
                   2186: /* {{{ proto bool sybase_set_message_handler(mixed error_func [, resource connection])
                   2187:    Set the error handler, to be called when a server message is raised. 
                   2188:    If error_func is NULL the handler will be deleted */
                   2189: PHP_FUNCTION(sybase_set_message_handler)
                   2190: {
                   2191:        zend_fcall_info fci = empty_fcall_info;
                   2192:        zend_fcall_info_cache cache = empty_fcall_info_cache;
                   2193:        zval *sybase_link_index= NULL;
                   2194:        sybase_link *sybase_ptr;
                   2195:        zval **callback;
                   2196:        int id;
                   2197: 
                   2198:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!|r", &fci, &cache, &sybase_link_index) == FAILURE) {
                   2199:                return;
                   2200:        }
                   2201: 
                   2202:        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
                   2203: 
                   2204:                /* Doesn't matter if we're not connected yet, use default */
                   2205:                callback= &SybCtG(callback_name);
                   2206:        } else if (-1 == id) {
                   2207: 
                   2208:                /* Connection-based message handler */
                   2209:                ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
                   2210:                callback= &sybase_ptr->callback_name;
                   2211:        } else {
                   2212: 
                   2213:                /* Default message handler */
                   2214:                callback= &SybCtG(callback_name);
                   2215:        }
                   2216: 
                   2217:        /* Clean old callback */
                   2218:        if (*callback) {
                   2219:                zval_ptr_dtor(callback);
                   2220:                *callback = NULL;
                   2221:        }
                   2222: 
                   2223:        if (ZEND_FCI_INITIALIZED(fci)) {
                   2224:                ALLOC_ZVAL(*callback);
                   2225:                **callback = *fci.function_name;
                   2226:                INIT_PZVAL(*callback);
                   2227:                zval_copy_ctor(*callback);
                   2228:        } else {
                   2229:                callback= NULL;
                   2230:        }
                   2231: 
                   2232:        RETURN_TRUE;
                   2233: }
                   2234: /* }}} */
                   2235: 
                   2236: 
                   2237: #endif
                   2238: 
                   2239: /*
                   2240:  * Local variables:
                   2241:  * tab-width: 4
                   2242:  * c-basic-offset: 4
                   2243:  * End:
                   2244:  */

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