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