Return to php_sybase_ct.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / sybase_ct |
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: */