Back to index

php5  5.3.10
php_sybase_ct.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Zeev Suraski <zeev@zend.com>                                |
00016    |          Tom May <tom@go2net.com>                                    |
00017    |          Timm Friebe <php_sybase_ct@thekid.de>                       |
00018    +----------------------------------------------------------------------+
00019  */
00020 
00021 /* $Id: php_sybase_ct.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "php.h"
00029 #include "php_sybase_ct.h"
00030 #include "ext/standard/php_standard.h"
00031 #include "ext/standard/info.h"
00032 #include "php_globals.h"
00033 #include "php_ini.h"
00034 
00035 /* True globals, no need for thread safety */
00036 static int le_link, le_plink, le_result;
00037 
00038 #if HAVE_SYBASE_CT
00039 
00040 ZEND_DECLARE_MODULE_GLOBALS(sybase)
00041 static PHP_GINIT_FUNCTION(sybase);
00042 static PHP_GSHUTDOWN_FUNCTION(sybase);
00043 
00044 /* {{{ arginfo */
00045 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_connect, 0, 0, 0)
00046        ZEND_ARG_INFO(0, host)
00047        ZEND_ARG_INFO(0, user)
00048        ZEND_ARG_INFO(0, password)
00049        ZEND_ARG_INFO(0, charset)
00050        ZEND_ARG_INFO(0, appname)
00051        ZEND_ARG_INFO(0, new)
00052 ZEND_END_ARG_INFO()
00053 
00054 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_pconnect, 0, 0, 0)
00055        ZEND_ARG_INFO(0, host)
00056        ZEND_ARG_INFO(0, user)
00057        ZEND_ARG_INFO(0, password)
00058        ZEND_ARG_INFO(0, charset)
00059        ZEND_ARG_INFO(0, appname)
00060 ZEND_END_ARG_INFO()
00061 
00062 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_close, 0, 0, 0)
00063        ZEND_ARG_INFO(0, link_id)
00064 ZEND_END_ARG_INFO()
00065 
00066 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_select_db, 0, 0, 1)
00067        ZEND_ARG_INFO(0, database)
00068        ZEND_ARG_INFO(0, link_id)
00069 ZEND_END_ARG_INFO()
00070 
00071 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_query, 0, 0, 1)
00072        ZEND_ARG_INFO(0, query)
00073        ZEND_ARG_INFO(0, link_id)
00074 ZEND_END_ARG_INFO()
00075 
00076 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_unbuffered_query, 0, 0, 1)
00077        ZEND_ARG_INFO(0, query)
00078        ZEND_ARG_INFO(0, link_id)
00079 ZEND_END_ARG_INFO()
00080 
00081 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_free_result, 0, 0, 1)
00082        ZEND_ARG_INFO(0, result)
00083 ZEND_END_ARG_INFO()
00084 
00085 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_get_last_message, 0, 0, 1)
00086        ZEND_ARG_INFO(0, d)
00087 ZEND_END_ARG_INFO()
00088 
00089 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_num_rows, 0, 0, 1)
00090        ZEND_ARG_INFO(0, result)
00091 ZEND_END_ARG_INFO()
00092 
00093 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_num_fields, 0, 0, 1)
00094        ZEND_ARG_INFO(0, result)
00095 ZEND_END_ARG_INFO()
00096 
00097 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_row, 0, 0, 1)
00098        ZEND_ARG_INFO(0, result)
00099 ZEND_END_ARG_INFO()
00100 
00101 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_object, 0, 0, 1)
00102        ZEND_ARG_INFO(0, result)
00103        ZEND_ARG_INFO(0, object)
00104 ZEND_END_ARG_INFO()
00105 
00106 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_array, 0, 0, 1)
00107        ZEND_ARG_INFO(0, result)
00108 ZEND_END_ARG_INFO()
00109 
00110 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_assoc, 0, 0, 1)
00111        ZEND_ARG_INFO(0, result)
00112 ZEND_END_ARG_INFO()
00113 
00114 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_data_seek, 0, 0, 2)
00115        ZEND_ARG_INFO(0, result)
00116        ZEND_ARG_INFO(0, offset)
00117 ZEND_END_ARG_INFO()
00118 
00119 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_fetch_field, 0, 0, 1)
00120        ZEND_ARG_INFO(0, result)
00121        ZEND_ARG_INFO(0, offset)
00122 ZEND_END_ARG_INFO()
00123 
00124 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_field_seek, 0, 0, 2)
00125        ZEND_ARG_INFO(0, result)
00126        ZEND_ARG_INFO(0, offset)
00127 ZEND_END_ARG_INFO()
00128 
00129 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_result, 0, 0, 3)
00130        ZEND_ARG_INFO(0, result)
00131        ZEND_ARG_INFO(0, row)
00132        ZEND_ARG_INFO(0, field)
00133 ZEND_END_ARG_INFO()
00134 
00135 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_affected_rows, 0, 0, 0)
00136        ZEND_ARG_INFO(0, link_id)
00137 ZEND_END_ARG_INFO()
00138 
00139 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_min_client_severity, 0, 0, 1)
00140        ZEND_ARG_INFO(0, severity)
00141 ZEND_END_ARG_INFO()
00142 
00143 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_min_server_severity, 0, 0, 1)
00144        ZEND_ARG_INFO(0, severity)
00145 ZEND_END_ARG_INFO()
00146 
00147 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_deadlock_retry_count, 0, 0, 1)
00148        ZEND_ARG_INFO(0, retry_count)
00149 ZEND_END_ARG_INFO()
00150 
00151 ZEND_BEGIN_ARG_INFO_EX(arginfo_sybase_set_message_handler, 0, 0, 1)
00152        ZEND_ARG_INFO(0, error_func)
00153        ZEND_ARG_INFO(0, connection)
00154 ZEND_END_ARG_INFO()
00155 /* }}} */
00156 
00157 const zend_function_entry sybase_functions[] = {
00158        PHP_FE(sybase_connect,                           arginfo_sybase_connect)
00159        PHP_FE(sybase_pconnect,                          arginfo_sybase_pconnect)
00160        PHP_FE(sybase_close,                             arginfo_sybase_close)
00161        PHP_FE(sybase_select_db,                  arginfo_sybase_select_db)
00162        PHP_FE(sybase_query,                      arginfo_sybase_query)
00163        PHP_FE(sybase_unbuffered_query,           arginfo_sybase_unbuffered_query)
00164        PHP_FE(sybase_free_result,                arginfo_sybase_free_result)
00165        PHP_FE(sybase_get_last_message,           arginfo_sybase_get_last_message)
00166        PHP_FE(sybase_num_rows,                          arginfo_sybase_num_rows)
00167        PHP_FE(sybase_num_fields,                 arginfo_sybase_num_fields)
00168        PHP_FE(sybase_fetch_row,                  arginfo_sybase_fetch_row)
00169        PHP_FE(sybase_fetch_array,                arginfo_sybase_fetch_array)
00170        PHP_FE(sybase_fetch_assoc,                arginfo_sybase_fetch_assoc)
00171        PHP_FE(sybase_fetch_object,               arginfo_sybase_fetch_object)
00172        PHP_FE(sybase_data_seek,                  arginfo_sybase_data_seek)
00173        PHP_FE(sybase_fetch_field,                arginfo_sybase_fetch_field)
00174        PHP_FE(sybase_field_seek,                 arginfo_sybase_field_seek)
00175        PHP_FE(sybase_result,                            arginfo_sybase_result)
00176        PHP_FE(sybase_affected_rows,              arginfo_sybase_affected_rows)
00177        PHP_FE(sybase_min_client_severity, arginfo_sybase_min_client_severity)
00178        PHP_FE(sybase_min_server_severity, arginfo_sybase_min_server_severity)
00179        PHP_FE(sybase_set_message_handler, arginfo_sybase_set_message_handler)
00180        PHP_FE(sybase_deadlock_retry_count, arginfo_sybase_deadlock_retry_count)
00181 
00182 #if !defined(PHP_WIN32) && !defined(HAVE_MSSQL)
00183        PHP_FALIAS(mssql_connect,   sybase_connect,      arginfo_sybase_connect)
00184        PHP_FALIAS(mssql_pconnect,  sybase_pconnect,     arginfo_sybase_pconnect)
00185        PHP_FALIAS(mssql_close,     sybase_close,               arginfo_sybase_close)
00186        PHP_FALIAS(mssql_select_db, sybase_select_db,    arginfo_sybase_select_db)
00187        PHP_FALIAS(mssql_query,     sybase_query,               arginfo_sybase_query)
00188        PHP_FALIAS(mssql_unbuffered_query,        sybase_unbuffered_query,    arginfo_sybase_unbuffered_query)
00189        PHP_FALIAS(mssql_free_result,             sybase_free_result,         arginfo_sybase_free_result)
00190        PHP_FALIAS(mssql_get_last_message,        sybase_get_last_message,    arginfo_sybase_get_last_message)
00191        PHP_FALIAS(mssql_num_rows,         sybase_num_rows,            arginfo_sybase_num_rows)
00192        PHP_FALIAS(mssql_num_fields,       sybase_num_fields,          arginfo_sybase_num_fields)
00193        PHP_FALIAS(mssql_fetch_row,        sybase_fetch_row,           arginfo_sybase_fetch_row)
00194        PHP_FALIAS(mssql_fetch_array,      sybase_fetch_array,  arginfo_sybase_fetch_array)
00195        PHP_FALIAS(mssql_fetch_assoc,      sybase_fetch_assoc,  arginfo_sybase_fetch_assoc)
00196        PHP_FALIAS(mssql_fetch_object,     sybase_fetch_object,        arginfo_sybase_fetch_object)
00197        PHP_FALIAS(mssql_data_seek,        sybase_data_seek,           arginfo_sybase_data_seek)
00198        PHP_FALIAS(mssql_fetch_field,      sybase_fetch_field,  arginfo_sybase_fetch_field)
00199        PHP_FALIAS(mssql_field_seek,       sybase_field_seek,          arginfo_sybase_field_seek)
00200        PHP_FALIAS(mssql_result,           sybase_result,                     arginfo_sybase_result)
00201        PHP_FALIAS(mssql_affected_rows, sybase_affected_rows,   arginfo_sybase_affected_rows)
00202        PHP_FALIAS(mssql_min_client_severity,   sybase_min_client_severity,   arginfo_sybase_min_client_severity)
00203        PHP_FALIAS(mssql_min_server_severity,     sybase_min_server_severity,        arginfo_sybase_min_server_severity)
00204        PHP_FALIAS(mssql_set_message_handler,     sybase_set_message_handler,        arginfo_sybase_set_message_handler)
00205        PHP_FALIAS(mssql_deadlock_retry_count,    sybase_deadlock_retry_count,       arginfo_sybase_deadlock_retry_count)
00206 #endif
00207        PHP_FE_END
00208 };
00209 
00210 zend_module_entry sybase_module_entry = {
00211        STANDARD_MODULE_HEADER,
00212        "sybase_ct",
00213        sybase_functions,
00214        PHP_MINIT(sybase),
00215        PHP_MSHUTDOWN(sybase),
00216        PHP_RINIT(sybase),
00217        PHP_RSHUTDOWN(sybase),
00218        PHP_MINFO(sybase),
00219        NO_VERSION_YET,
00220        PHP_MODULE_GLOBALS(sybase),
00221        PHP_GINIT(sybase),
00222        PHP_GSHUTDOWN(sybase),
00223        NULL,
00224        STANDARD_MODULE_PROPERTIES_EX
00225 };
00226 
00227 /* static CS_CONTEXT *context; */
00228 
00229 #ifdef COMPILE_DL_SYBASE_CT
00230 ZEND_GET_MODULE(sybase)
00231 #endif
00232 
00233 ZEND_DECLARE_MODULE_GLOBALS(sybase)
00234 
00235 #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; } }
00236 
00237 
00238 static int _clean_invalid_results(zend_rsrc_list_entry *le TSRMLS_DC)
00239 {
00240        if (Z_TYPE_P(le) == le_result) {
00241               sybase_link *sybase_ptr = ((sybase_result *) le->ptr)->sybase_ptr;
00242 
00243               if (!sybase_ptr->valid) {
00244                      return 1;
00245               }
00246        }
00247        return 0;
00248 }
00249 
00250 #define efree_n(x)  { efree(x); x = NULL; }
00251 #define efree_if(x) if (x) efree_n(x)
00252 
00253 #ifdef PHP_SYBASE_DEBUG
00254 #define FREE_SYBASE_RESULT(result)                                                            \
00255        if (result) {                                                                             \
00256            fprintf(stderr, "_free_sybase_result(%p) called from line #%d\n", result, __LINE__);  \
00257               fflush(stderr);                                                                       \
00258               _free_sybase_result(result);                                                          \
00259               result = NULL;                                                                        \
00260        }
00261 #else
00262 #define FREE_SYBASE_RESULT(result)                                                            \
00263        if (result) {                                                                             \
00264               _free_sybase_result(result);                                                          \
00265               result = NULL;                                                                        \
00266        }
00267 #endif
00268 static void _free_sybase_result(sybase_result *result)
00269 {
00270        int i, j;
00271 
00272        if (result->data) {
00273               for (i = 0; i < (result->store ? result->num_rows : MIN(1, result->num_rows)); i++) {
00274                      for (j=0; j<result->num_fields; j++) {
00275                             zval_dtor(&result->data[i][j]);
00276                      }
00277                      efree(result->data[i]);
00278               }
00279               efree(result->data);
00280        }
00281 
00282        if (result->fields) {
00283               for (i=0; i<result->num_fields; i++) {
00284                      STR_FREE(result->fields[i].name);
00285                      STR_FREE(result->fields[i].column_source);
00286               }
00287               efree(result->fields);
00288        }
00289 
00290        if (result->tmp_buffer) {
00291               for (i=0; i<result->num_fields; i++) {
00292                      efree(result->tmp_buffer[i]);
00293               }
00294               efree(result->tmp_buffer);
00295        }
00296 
00297        efree_if(result->lengths);
00298        efree_if(result->indicators);
00299        efree_if(result->datafmt);
00300        efree_if(result->numerics);
00301        efree_if(result->types);
00302 
00303        efree(result);
00304 }
00305 
00306 /* Forward declaration */
00307 static int php_sybase_finish_results (sybase_result *result TSRMLS_DC);
00308 
00309 static void php_free_sybase_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00310 {
00311        sybase_result *result = (sybase_result *)rsrc->ptr;
00312 
00313        /* Check to see if we've read all rows */
00314        if (result->sybase_ptr && result->sybase_ptr->active_result_index) {
00315               if (result->sybase_ptr->cmd) {
00316                      ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
00317               }
00318               php_sybase_finish_results(result TSRMLS_CC);
00319        }
00320 
00321        FREE_SYBASE_RESULT(result);
00322 }
00323 
00324 static void _close_sybase_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00325 {
00326        sybase_link *sybase_ptr = (sybase_link *)rsrc->ptr;
00327        CS_INT con_status;
00328 
00329        sybase_ptr->valid = 0;
00330        if (sybase_ptr->callback_name != NULL) {
00331               zval_ptr_dtor(&sybase_ptr->callback_name);
00332               sybase_ptr->callback_name= NULL;
00333        }
00334        zend_hash_apply(&EG(regular_list), (apply_func_t) _clean_invalid_results TSRMLS_CC);
00335 
00336        /* Non-persistent connections will always be connected or we wouldn't
00337         * get here, but since we want to check the death status anyway
00338         * we might as well double-check the connect status.
00339         */
00340        if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
00341                                     &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
00342               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status on close");
00343               /* Assume the worst. */
00344               con_status = CS_CONSTAT_CONNECTED | CS_CONSTAT_DEAD;
00345        }
00346        if (con_status & CS_CONSTAT_CONNECTED) {
00347               if ((con_status & CS_CONSTAT_DEAD) || ct_close(sybase_ptr->connection, CS_UNUSED)!=CS_SUCCEED) {
00348                      ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
00349               }
00350        }
00351 
00352        ct_cmd_drop(sybase_ptr->cmd);
00353        ct_con_drop(sybase_ptr->connection);
00354        efree(sybase_ptr);
00355        SybCtG(num_links)--;
00356 }
00357 
00358 
00359 static void _close_sybase_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00360 {
00361        sybase_link *sybase_ptr = (sybase_link *)rsrc->ptr;
00362        CS_INT con_status;
00363 
00364        /* Persistent connections may have been closed before a failed
00365         * reopen attempt.
00366         */
00367        if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
00368                                     &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
00369               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status on close");
00370               /* Assume the worst. */
00371               con_status = CS_CONSTAT_CONNECTED | CS_CONSTAT_DEAD;
00372        }
00373        if (con_status & CS_CONSTAT_CONNECTED) {
00374               if ((con_status & CS_CONSTAT_DEAD) || ct_close(sybase_ptr->connection, CS_UNUSED)!=CS_SUCCEED) {
00375                      ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
00376               }
00377        }
00378 
00379        ct_con_drop(sybase_ptr->connection);
00380        free(sybase_ptr);
00381        SybCtG(num_persistent)--;
00382        SybCtG(num_links)--;
00383 }
00384 
00385 
00386 static CS_RETCODE CS_PUBLIC _client_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_CLIENTMSG *errmsg)
00387 {
00388        TSRMLS_FETCH();
00389 
00390        if (CS_SEVERITY(errmsg->msgnumber) >= SybCtG(min_client_severity)) {
00391               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Client message:  %s (severity %ld)", errmsg->msgstring, (long)CS_SEVERITY(errmsg->msgnumber));
00392        }
00393        STR_FREE(SybCtG(server_message));
00394        SybCtG(server_message) = estrdup(errmsg->msgstring);
00395 
00396 
00397        /* If this is a timeout message, return CS_FAIL to cancel the
00398         * operation and mark the connection as dead.
00399         */
00400        if (CS_SEVERITY(errmsg->msgnumber) == CS_SV_RETRY_FAIL &&
00401               CS_NUMBER(errmsg->msgnumber) == 63 &&
00402               CS_ORIGIN(errmsg->msgnumber) == 2 &&
00403               CS_LAYER(errmsg->msgnumber) == 1)
00404        {
00405               return CS_FAIL;
00406        }
00407 
00408        return CS_SUCCEED;
00409 }
00410 
00411 static int _call_message_handler(zval *callback_name, CS_SERVERMSG *srvmsg TSRMLS_DC)
00412 {
00413        int handled = 0;
00414        zval *msgnumber, *severity, *state, *line, *text, *retval = NULL;
00415        zval **args[5];
00416 
00417        /* Border case - empty fcall */
00418        if (NULL == callback_name) return 0;
00419 
00420        /* Build arguments */
00421        MAKE_STD_ZVAL(msgnumber);
00422        ZVAL_LONG(msgnumber, srvmsg->msgnumber);
00423        args[0] = &msgnumber;
00424 
00425        MAKE_STD_ZVAL(severity);
00426        ZVAL_LONG(severity, srvmsg->severity);
00427        args[1] = &severity;
00428 
00429        MAKE_STD_ZVAL(state);
00430        ZVAL_LONG(state, srvmsg->state);
00431        args[2] = &state;
00432 
00433        MAKE_STD_ZVAL(line);
00434        ZVAL_LONG(line, srvmsg->line);
00435        args[3] = &line;
00436 
00437        MAKE_STD_ZVAL(text); 
00438        ZVAL_STRING(text, srvmsg->text, 1);
00439        args[4] = &text;
00440 
00441        if (call_user_function_ex(EG(function_table), NULL, callback_name, &retval, 5, args, 0, NULL TSRMLS_CC) == FAILURE) {
00442               zval expr_copy;
00443               int use_copy;
00444 
00445               zend_make_printable_zval(callback_name, &expr_copy, &use_copy);
00446               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot call the messagehandler %s", Z_STRVAL(expr_copy));
00447               zval_dtor(&expr_copy);
00448        }
00449 
00450        if (retval) {
00451               handled = ((Z_TYPE_P(retval) != IS_BOOL) || (Z_BVAL_P(retval) != 0));
00452               zval_ptr_dtor(&retval);
00453        } else {
00454               handled = 0;
00455        }
00456 
00457        zval_ptr_dtor(&msgnumber);
00458        zval_ptr_dtor(&severity);
00459        zval_ptr_dtor(&state);
00460        zval_ptr_dtor(&line);
00461        zval_ptr_dtor(&text);
00462 
00463        return handled;
00464 }
00465 
00466 static CS_RETCODE CS_PUBLIC _server_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_SERVERMSG *srvmsg)
00467 {
00468        sybase_link *sybase;
00469        int handled = 0;
00470        TSRMLS_FETCH();
00471 
00472        /* Remember the last server message in any case */
00473        STR_FREE(SybCtG(server_message));
00474        SybCtG(server_message) = estrdup(srvmsg->text);
00475 
00476        /* Retrieve sybase link */
00477        if (ct_con_props(connection, CS_GET, CS_USERDATA, &sybase, CS_SIZEOF(sybase), NULL) != CS_SUCCEED) {
00478               sybase = NULL;
00479        }
00480 
00481        /* If this is a deadlock message, set the connection's deadlock flag
00482         * so we will retry the request.  Sorry about the bare constant here,
00483         * but it's not defined anywhere and it's a "well-known" number.
00484         */
00485        if (sybase && (srvmsg->msgnumber == 1205)) {
00486               sybase->deadlock = 1;
00487        }
00488 
00489        /* Check mininum server severity level */
00490        if (srvmsg->severity < SybCtG(min_server_severity)) {
00491               return CS_SUCCEED;
00492        }
00493 
00494        /* Call global message handler */
00495        handled = handled | _call_message_handler(SybCtG(callback_name), srvmsg TSRMLS_CC);
00496 
00497        /* Call link specific message handler */
00498        if (sybase) {
00499               handled = handled | _call_message_handler(sybase->callback_name, srvmsg TSRMLS_CC);
00500        }
00501 
00502        /* Spit out a warning if neither of them has handled this message */
00503        if (!handled) {
00504               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Server message:  %s (severity %ld, procedure %s)",
00505                             srvmsg->text, (long)srvmsg->severity, ((srvmsg->proclen>0) ? srvmsg->proc : "N/A"));
00506        }
00507 
00508        return CS_SUCCEED;
00509 }
00510 
00511 
00512 PHP_INI_BEGIN()
00513        STD_PHP_INI_BOOLEAN("sybct.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_sybase_globals, sybase_globals)
00514        STD_PHP_INI_ENTRY_EX("sybct.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_sybase_globals, sybase_globals, display_link_numbers)
00515        STD_PHP_INI_ENTRY_EX("sybct.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_sybase_globals, sybase_globals, display_link_numbers)
00516        STD_PHP_INI_ENTRY("sybct.min_server_severity", "10", PHP_INI_ALL, OnUpdateLong, min_server_severity, zend_sybase_globals, sybase_globals)
00517        STD_PHP_INI_ENTRY("sybct.min_client_severity", "10", PHP_INI_ALL, OnUpdateLong, min_client_severity, zend_sybase_globals, sybase_globals)
00518        STD_PHP_INI_ENTRY("sybct.login_timeout", "-1", PHP_INI_ALL, OnUpdateLong, login_timeout, zend_sybase_globals, sybase_globals)
00519        STD_PHP_INI_ENTRY("sybct.hostname", NULL, PHP_INI_ALL, OnUpdateString, hostname, zend_sybase_globals, sybase_globals)
00520        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)
00521 PHP_INI_END()
00522 
00523 
00524 static PHP_GINIT_FUNCTION(sybase)
00525 {
00526        long opt;
00527 
00528        if (cs_ctx_alloc(CTLIB_VERSION, &sybase_globals->context)!=CS_SUCCEED || ct_init(sybase_globals->context, CTLIB_VERSION)!=CS_SUCCEED) {
00529               return;
00530        }
00531 
00532        /* Initialize message handlers */
00533        if (ct_callback(sybase_globals->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)_server_message_handler)!=CS_SUCCEED) {
00534               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set server message handler");
00535        }
00536 
00537        if (ct_callback(sybase_globals->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)_client_message_handler)!=CS_SUCCEED) {
00538               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set client message handler");
00539        }
00540 
00541        /* Set datetime conversion format to "Nov  3 1998  8:06PM".
00542         * This is the default format for the ct-lib that comes with
00543         * Sybase ASE 11.5.1 for Solaris, but the Linux libraries that
00544         * come with 11.0.3.3 default to "03/11/98" which is singularly
00545         * useless.  This levels the playing field for all platforms.
00546         */
00547        {
00548               CS_INT dt_convfmt = CS_DATES_SHORT;
00549               if (cs_dt_info(sybase_globals->context, CS_SET, NULL, CS_DT_CONVFMT, CS_UNUSED, &dt_convfmt, sizeof(dt_convfmt), NULL)!=CS_SUCCEED) {
00550                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set datetime conversion format");
00551               }
00552        }
00553 
00554        /* Set the timeout, which is per context and can't be set with 
00555         * ct_con_props(), so set it globally from the config value if 
00556         * requested.  The default is CS_NO_LIMIT.
00557         * 
00558         * Note that despite some noise in the documentation about using
00559         * signals to implement timeouts, they are actually implemented
00560         * by using poll() or select() on Solaris and Linux.
00561         */
00562        if (cfg_get_long("sybct.timeout", &opt)==SUCCESS) {
00563               CS_INT cs_timeout = opt;
00564               if (ct_config(sybase_globals->context, CS_SET, CS_TIMEOUT, &cs_timeout, CS_UNUSED, NULL)!=CS_SUCCEED) {
00565                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to update the timeout");
00566               }
00567        }
00568 
00569        sybase_globals->num_persistent=0;
00570        sybase_globals->callback_name = NULL;
00571 }
00572 
00573 
00574 static PHP_GSHUTDOWN_FUNCTION(sybase)
00575 {
00576        ct_exit(sybase_globals->context, CS_UNUSED);
00577        cs_ctx_drop(sybase_globals->context);
00578 }
00579 
00580 PHP_MINIT_FUNCTION(sybase)
00581 {
00582        REGISTER_INI_ENTRIES();
00583 
00584        le_link = zend_register_list_destructors_ex(_close_sybase_link, NULL, "sybase-ct link", module_number);
00585        le_plink = zend_register_list_destructors_ex(NULL, _close_sybase_plink, "sybase-ct link persistent", module_number);
00586        le_result = zend_register_list_destructors_ex(php_free_sybase_result, NULL, "sybase-ct result", module_number);
00587 
00588        return SUCCESS;
00589 }
00590 
00591 
00592 
00593 PHP_RINIT_FUNCTION(sybase)
00594 {
00595        SybCtG(default_link)=-1;
00596        SybCtG(num_links) = SybCtG(num_persistent);
00597        SybCtG(appname) = estrndup("PHP " PHP_VERSION, sizeof("PHP " PHP_VERSION));
00598        SybCtG(server_message) = STR_EMPTY_ALLOC();
00599        return SUCCESS;
00600 }
00601 
00602 
00603 
00604 PHP_MSHUTDOWN_FUNCTION(sybase)
00605 {
00606        UNREGISTER_INI_ENTRIES();
00607 #if 0
00608        ct_exit(context, CS_UNUSED);
00609        cs_ctx_drop(context);
00610 #endif
00611        return SUCCESS;
00612 }
00613 
00614 
00615 PHP_RSHUTDOWN_FUNCTION(sybase)
00616 {
00617        efree(SybCtG(appname));
00618        SybCtG(appname) = NULL;
00619        if (SybCtG(callback_name)) {
00620               zval_ptr_dtor(&SybCtG(callback_name));
00621               SybCtG(callback_name)= NULL;
00622        }
00623        STR_FREE(SybCtG(server_message));
00624        SybCtG(server_message) = NULL;
00625        return SUCCESS;
00626 }
00627 
00628 
00629 static int php_sybase_do_connect_internal(sybase_link *sybase, char *host, char *user, char *passwd, char *charset, char *appname TSRMLS_DC)
00630 {
00631        CS_LOCALE *tmp_locale;
00632        long packetsize;
00633 
00634        /* set a CS_CONNECTION record */
00635        if (ct_con_alloc(SybCtG(context), &sybase->connection)!=CS_SUCCEED) {
00636               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to allocate connection record");
00637               return 0;
00638        }
00639 
00640        /* Note - this saves a copy of sybase, not a pointer to it. */
00641        if (ct_con_props(sybase->connection, CS_SET, CS_USERDATA, &sybase, CS_SIZEOF(sybase), NULL)!=CS_SUCCEED) {
00642               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to set userdata");
00643               ct_con_drop(sybase->connection);
00644               return 0;
00645        }
00646 
00647        if (user) {
00648               ct_con_props(sybase->connection, CS_SET, CS_USERNAME, user, CS_NULLTERM, NULL);
00649        }
00650        if (passwd) {
00651               ct_con_props(sybase->connection, CS_SET, CS_PASSWORD, passwd, CS_NULLTERM, NULL);
00652        }
00653        if (appname) {
00654               ct_con_props(sybase->connection, CS_SET, CS_APPNAME, appname, CS_NULLTERM, NULL);
00655        } else { 
00656               ct_con_props(sybase->connection, CS_SET, CS_APPNAME, SybCtG(appname), CS_NULLTERM, NULL);
00657        }
00658 
00659        if (SybCtG(hostname)) {
00660               ct_con_props(sybase->connection, CS_SET, CS_HOSTNAME, SybCtG(hostname), CS_NULLTERM, NULL);
00661        }
00662 
00663        if (charset) {
00664               if (cs_loc_alloc(SybCtG(context), &tmp_locale)!=CS_SUCCEED) {
00665                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to allocate locale information");
00666               } else {
00667                      if (cs_locale(SybCtG(context), CS_SET, tmp_locale, CS_LC_ALL, NULL, CS_NULLTERM, NULL)!=CS_SUCCEED) {
00668                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to load default locale data");
00669                      } else {
00670                             if (cs_locale(SybCtG(context), CS_SET, tmp_locale, CS_SYB_CHARSET, charset, CS_NULLTERM, NULL)!=CS_SUCCEED) {
00671                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update character set");
00672                             } else {
00673                                    if (ct_con_props(sybase->connection, CS_SET, CS_LOC_PROP, tmp_locale, CS_UNUSED, NULL)!=CS_SUCCEED) {
00674                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update connection properties");
00675                                    }
00676                             }
00677                      }
00678               }
00679        }
00680        
00681        if (cfg_get_long("sybct.packet_size", &packetsize) == SUCCESS) {
00682               if (ct_con_props(sybase->connection, CS_SET, CS_PACKETSIZE, (CS_VOID *)&packetsize, CS_UNUSED, NULL) != CS_SUCCEED) {
00683                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase: Unable to update connection packetsize");
00684               }
00685        }
00686 
00687        /* Set the login timeout. Actually, the login timeout is per context
00688         * and not per connection, but we will update the context here to 
00689         * allow for code such as the following:
00690         * 
00691         *   ini_set('sybct.login_timeout', $timeout);
00692         *   sybase_connect(...)
00693         * 
00694         * Note that preceding calls to sybase_connect() will now use the 
00695         * updated value and not the default one!
00696         * 
00697         * The default value for CS_LOGIN_TIMEOUT is 60 (1 minute).
00698         */
00699        if (SybCtG(login_timeout) != -1) {
00700               CS_INT cs_login_timeout = SybCtG(login_timeout);
00701               if (ct_config(SybCtG(context), CS_SET, CS_LOGIN_TIMEOUT, &cs_login_timeout, CS_UNUSED, NULL)!=CS_SUCCEED) {
00702                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to update the login timeout");
00703               }
00704        }
00705 
00706        sybase->valid = 1;
00707        sybase->dead = 0;
00708        sybase->active_result_index = 0;
00709        sybase->callback_name = NULL;
00710 
00711        /* create the link */
00712        if (ct_connect(sybase->connection, host, CS_NULLTERM)!=CS_SUCCEED) {
00713               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to connect");
00714               ct_con_drop(sybase->connection);
00715               return 0;
00716        }
00717 
00718        if (ct_cmd_alloc(sybase->connection, &sybase->cmd)!=CS_SUCCEED) {
00719               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to allocate command record");
00720               ct_close(sybase->connection, CS_UNUSED);
00721               ct_con_drop(sybase->connection);
00722               return 0;
00723        }
00724 
00725        return 1;
00726 }
00727 
00728 
00729 static void php_sybase_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
00730 {
00731        char *user = NULL, *passwd = NULL, *host = NULL, *charset = NULL, *appname = NULL;
00732        char *hashed_details;
00733        int hashed_details_length, len;
00734        zend_bool new = 0;
00735        sybase_link *sybase_ptr;
00736 
00737        host= user= passwd= charset= appname= NULL;
00738        if (persistent) {
00739               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) {
00740                      return;
00741               }
00742        } else {
00743               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) {
00744                      return;
00745               }
00746        }
00747        hashed_details_length = spprintf(
00748               &hashed_details, 
00749               0, 
00750               "sybase_%s_%s_%s_%s_%s",
00751               host ? host : "", 
00752               user ? user : "", 
00753               passwd ? passwd : "", 
00754               charset ? charset : "", 
00755               appname ? appname : ""
00756        );
00757 
00758        if (!SybCtG(allow_persistent)) {
00759               persistent=0;
00760        }
00761        if (persistent) {
00762               zend_rsrc_list_entry *le;
00763 
00764               /* try to find if we already have this link in our persistent list */
00765               if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {  /* we don't */
00766                      zend_rsrc_list_entry new_le;
00767 
00768                      if (SybCtG(max_links)!=-1 && SybCtG(num_links)>=SybCtG(max_links)) {
00769                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open links (%ld)", SybCtG(num_links));
00770                             efree(hashed_details);
00771                             RETURN_FALSE;
00772                      }
00773                      if (SybCtG(max_persistent)!=-1 && SybCtG(num_persistent)>=SybCtG(max_persistent)) {
00774                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open persistent links (%ld)", SybCtG(num_persistent));
00775                             efree(hashed_details);
00776                             RETURN_FALSE;
00777                      }
00778 
00779                      sybase_ptr = (sybase_link *) malloc(sizeof(sybase_link));
00780                      if (!sybase_ptr) {
00781                             efree(hashed_details);
00782                             RETURN_FALSE;
00783                      }
00784                      if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
00785                             free(sybase_ptr);
00786                             efree(hashed_details);
00787                             RETURN_FALSE;
00788                      }
00789 
00790                      /* hash it up */
00791                      Z_TYPE(new_le) = le_plink;
00792                      new_le.ptr = sybase_ptr;
00793                      if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
00794                             ct_close(sybase_ptr->connection, CS_UNUSED);
00795                             ct_con_drop(sybase_ptr->connection);
00796                             free(sybase_ptr);
00797                             efree(hashed_details);
00798                             RETURN_FALSE;
00799                      }
00800                      SybCtG(num_persistent)++;
00801                      SybCtG(num_links)++;
00802               } else {  /* we do */
00803                      CS_INT con_status;
00804 
00805                      if (Z_TYPE_P(le) != le_plink) {
00806                             efree(hashed_details);
00807                             RETURN_FALSE;
00808                      }
00809 
00810                      sybase_ptr = (sybase_link *) le->ptr;
00811 
00812                      /* If the link has died, close it and overwrite it with a new one. */
00813 
00814                      if (ct_con_props(sybase_ptr->connection, CS_GET, CS_CON_STATUS,
00815                                                   &con_status, CS_UNUSED, NULL)!=CS_SUCCEED) {
00816                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Unable to get connection status");
00817                             efree(hashed_details);
00818                             RETURN_FALSE;
00819                      }
00820                      if (!(con_status & CS_CONSTAT_CONNECTED) || (con_status & CS_CONSTAT_DEAD) || sybase_ptr->dead) {
00821                             sybase_link sybase;
00822 
00823                             if (con_status & CS_CONSTAT_CONNECTED) {
00824                                    ct_close(sybase_ptr->connection, CS_FORCE_CLOSE);
00825                             }
00826                             /* Create a new connection, then replace the old
00827                              * connection.  If we fail to create a new connection,
00828                              * put the old one back so there will be a connection,
00829                              * even if it is a non-functional one.  This is because
00830                              * code may still be holding an id for this connection
00831                              * so we can't free the CS_CONNECTION.
00832                              * (This is actually totally hokey, it would be better
00833                              * to just ct_con_drop() the connection and set
00834                              * sybase_ptr->connection to NULL, then test it for
00835                              * NULL before trying to use it elsewhere . . .)
00836                              */
00837                             memcpy(&sybase, sybase_ptr, sizeof(sybase_link));
00838                             if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
00839                                    memcpy(sybase_ptr, &sybase, sizeof(sybase_link));
00840                                    efree(hashed_details);
00841                                    RETURN_FALSE;
00842                             }
00843                             ct_con_drop(sybase.connection); /* drop old connection */
00844                      }
00845               }
00846               ZEND_REGISTER_RESOURCE(return_value, sybase_ptr, le_plink);
00847        } else { /* non persistent */
00848               zend_rsrc_list_entry *index_ptr, new_index_ptr;
00849 
00850               /* first we check the hash for the hashed_details key.  if it exists,
00851                * it should point us to the right offset where the actual sybase link sits.
00852                * if it doesn't, open a new sybase link, add it to the resource list,
00853                * and add a pointer to it with hashed_details as the key.
00854                */
00855               if (!new && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length+1, (void **) &index_ptr)==SUCCESS) {
00856                      int type, link;
00857                      void *ptr;
00858 
00859                      if (Z_TYPE_P(index_ptr) != le_index_ptr) {
00860                             efree(hashed_details);
00861                             RETURN_FALSE;
00862                      }
00863                      link = (int) index_ptr->ptr;
00864                      ptr = zend_list_find(link, &type);   /* check if the link is still there */
00865                      if (ptr && (type==le_link || type==le_plink)) {
00866                             zend_list_addref(link);
00867                             Z_LVAL_P(return_value) = SybCtG(default_link) = link;
00868                             Z_TYPE_P(return_value) = IS_RESOURCE;
00869                             efree(hashed_details);
00870                             return;
00871                      } else {
00872                             zend_hash_del(&EG(regular_list), hashed_details, hashed_details_length+1);
00873                      }
00874               }
00875               if (SybCtG(max_links)!=-1 && SybCtG(num_links)>=SybCtG(max_links)) {
00876                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Too many open links (%ld)", SybCtG(num_links));
00877                      efree(hashed_details);
00878                      RETURN_FALSE;
00879               }
00880 
00881               sybase_ptr = (sybase_link *) emalloc(sizeof(sybase_link));
00882               if (!php_sybase_do_connect_internal(sybase_ptr, host, user, passwd, charset, appname TSRMLS_CC)) {
00883                      efree(sybase_ptr);
00884                      efree(hashed_details);
00885                      RETURN_FALSE;
00886               }
00887 
00888               /* add it to the list */
00889               ZEND_REGISTER_RESOURCE(return_value, sybase_ptr, le_link);
00890 
00891               /* add it to the hash */
00892               new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
00893               Z_TYPE(new_index_ptr) = le_index_ptr;
00894               if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length+1, (void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
00895                      ct_close(sybase_ptr->connection, CS_UNUSED);
00896                      ct_con_drop(sybase_ptr->connection);
00897                      efree(sybase_ptr);
00898                      efree(hashed_details);
00899                      RETURN_FALSE;
00900               }
00901               SybCtG(num_links)++;
00902        }
00903        efree(hashed_details);
00904        SybCtG(default_link)=Z_LVAL_P(return_value);
00905        zend_list_addref(SybCtG(default_link));
00906 }
00907 
00908 
00909 static int php_sybase_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
00910 {
00911        if (SybCtG(default_link)==-1) { /* no link opened yet, implicitly open one */
00912               ht = 0;
00913               php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00914        }
00915        return SybCtG(default_link);
00916 }
00917 
00918 
00919 /* {{{ proto int sybase_connect([string host [, string user [, string password [, string charset [, string appname [, bool new]]]]]])
00920    Open Sybase server connection */
00921 PHP_FUNCTION(sybase_connect)
00922 {
00923        php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00924 }
00925 
00926 /* }}} */
00927 
00928 /* {{{ proto int sybase_pconnect([string host [, string user [, string password [, string charset [, string appname]]]]])
00929    Open persistent Sybase connection */
00930 PHP_FUNCTION(sybase_pconnect)
00931 {
00932        php_sybase_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
00933 }
00934 
00935 /* }}} */
00936 
00937 inline static int php_sybase_connection_id(zval *sybase_link_index, int *id TSRMLS_DC)
00938 {
00939        if (NULL == sybase_link_index) {
00940               if (-1 == SybCtG(default_link)) {
00941                      return FAILURE;
00942               }
00943               *id = SybCtG(default_link);
00944        } else {
00945               *id = -1;   /* explicit resource number */
00946        }
00947        return SUCCESS;
00948 }
00949 
00950 /* {{{ proto bool sybase_close([resource link_id])
00951    Close Sybase connection */
00952 PHP_FUNCTION(sybase_close)
00953 {
00954        zval *sybase_link_index = NULL;
00955        sybase_link *sybase_ptr;
00956        int id;
00957 
00958        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &sybase_link_index) == FAILURE) {
00959               return;
00960        }
00961 
00962        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
00963               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection to close");
00964               RETURN_FALSE;
00965        }
00966 
00967        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
00968 
00969        if (id == -1) {
00970               zend_list_delete(Z_RESVAL_P(sybase_link_index));
00971        }
00972        if (id != -1 || (sybase_link_index && Z_RESVAL_P(sybase_link_index) == SybCtG(default_link))) {
00973               zend_list_delete(SybCtG(default_link));
00974               SybCtG(default_link) = -1;
00975        }
00976 
00977        RETURN_TRUE;
00978 }
00979 
00980 /* }}} */
00981 
00982 
00983 static int exec_cmd(sybase_link *sybase_ptr, char *cmdbuf)
00984 {
00985        CS_RETCODE retcode;
00986        CS_INT restype;
00987        int failure=0;
00988 
00989        /* Fail if we already marked this connection dead. */
00990 
00991        if (sybase_ptr->dead) {
00992               return FAILURE;
00993        }
00994 
00995        /*
00996         ** Get a command handle, store the command string in it, and
00997         ** send it to the server.
00998         */
00999 
01000        if (ct_command(sybase_ptr->cmd, CS_LANG_CMD, cmdbuf, CS_NULLTERM, CS_UNUSED)!=CS_SUCCEED) {
01001               sybase_ptr->dead = 1;
01002               return FAILURE;
01003        }
01004        if (ct_send(sybase_ptr->cmd)!=CS_SUCCEED) {
01005               sybase_ptr->dead = 1;
01006               return FAILURE;
01007        }
01008 
01009        while ((retcode = ct_results(sybase_ptr->cmd, &restype))==CS_SUCCEED) {
01010               switch ((int) restype) {
01011                      case CS_CMD_SUCCEED:
01012                      case CS_CMD_DONE:
01013                             break;
01014 
01015                      case CS_CMD_FAIL:
01016                             failure=1;
01017                             break;
01018 
01019                      case CS_STATUS_RESULT:
01020                             ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
01021                             break;
01022 
01023                      default:
01024                             failure=1;
01025                             break;
01026               }
01027               if (failure) {
01028                      ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01029                      return FAILURE;
01030               }
01031        }
01032 
01033        switch (retcode) {
01034               case CS_END_RESULTS:
01035                      return SUCCESS;
01036                      break;
01037 
01038               case CS_FAIL:
01039                      /* Hopefully this either cleans up the connection, or the
01040                       * connection ends up marked dead so it will be reopened
01041                       * if it is persistent.  We may want to do
01042                       * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
01043                       * doc for ct_results()==CS_FAIL.
01044                       */
01045                      ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01046                      /* Don't take chances with the vagaries of ct-lib.  Mark it
01047                       * dead ourselves.
01048                       */
01049                      sybase_ptr->dead = 1;
01050                      return FAILURE;
01051 
01052               default:
01053                      return FAILURE;
01054        }
01055 }
01056 
01057 
01058 /* {{{ proto bool sybase_select_db(string database [, resource link_id])
01059    Select Sybase database */
01060 PHP_FUNCTION(sybase_select_db)
01061 {
01062        zval *sybase_link_index = NULL;
01063        char *db, *cmdbuf;
01064        int id, len;
01065        sybase_link *sybase_ptr;
01066 
01067        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &db, &len, &sybase_link_index) == FAILURE) {
01068               return;
01069        }
01070 
01071        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
01072               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
01073               RETURN_FALSE;
01074        }
01075 
01076        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
01077 
01078        spprintf(&cmdbuf, 4 + len + 1, "use %s", db);
01079        if (exec_cmd(sybase_ptr, cmdbuf) == FAILURE) {
01080               efree(cmdbuf);
01081               RETURN_FALSE;
01082        } else {
01083               efree(cmdbuf);
01084               RETURN_TRUE;
01085        }
01086 }
01087 
01088 /* }}} */
01089 
01090 static int php_sybase_finish_results(sybase_result *result TSRMLS_DC) 
01091 {
01092        int i, fail;
01093        CS_RETCODE retcode;
01094        CS_INT restype;
01095        
01096        efree_n(result->datafmt);
01097        efree_n(result->lengths);
01098        efree_n(result->indicators);
01099        efree_n(result->numerics);
01100        efree_n(result->types);
01101        for (i=0; i<result->num_fields; i++) {
01102               efree(result->tmp_buffer[i]);
01103        }
01104        efree_n(result->tmp_buffer);
01105 
01106        /* Indicate we have read all rows */
01107        result->sybase_ptr->active_result_index= 0;
01108 
01109        /* The only restype we should get now is CS_CMD_DONE, possibly
01110         * followed by a CS_STATUS_RESULT/CS_CMD_SUCCEED/CS_CMD_DONE
01111         * sequence if the command was a stored procedure call.  But we
01112         * still need to read and discard unexpected results.  We might
01113         * want to return a failure in this case because the application
01114         * won't be getting all the results it asked for.
01115         */
01116        fail = 0;
01117        while ((retcode = ct_results(result->sybase_ptr->cmd, &restype))==CS_SUCCEED) {
01118               switch ((int) restype) {
01119                      case CS_CMD_SUCCEED:
01120                      case CS_CMD_DONE:
01121                             break;
01122 
01123                      case CS_CMD_FAIL:
01124                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Command failed, cancelling rest");
01125                             ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
01126                             fail = 1;
01127                             break;
01128 
01129                      case CS_COMPUTE_RESULT:
01130                      case CS_CURSOR_RESULT:
01131                      case CS_PARAM_RESULT:
01132                      case CS_ROW_RESULT:
01133                             /* Unexpected results, cancel them. */
01134                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling current");
01135                             ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
01136                             break;
01137 
01138                      case CS_STATUS_RESULT:
01139                             /* Status result from a stored procedure, cancel it but do not tell user */
01140                             ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
01141                             break;
01142 
01143                      default:
01144                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling all");
01145                             ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
01146                             break;
01147               }
01148 
01149               if (fail) {
01150                      break;
01151               }
01152        }
01153 
01154        switch (retcode) {
01155               case CS_END_RESULTS:
01156                      /* Normal. */
01157                      break;
01158 
01159               case CS_FAIL:
01160                      /* Hopefully this either cleans up the connection, or the
01161                       * connection ends up marked dead so it will be reopened
01162                       * if it is persistent.  We may want to do
01163                       * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
01164                       * doc for ct_results()==CS_FAIL.
01165                       */
01166                      ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
01167                      /* Don't take chances with the vagaries of ct-lib.  Mark it
01168                       * dead ourselves.
01169                       */
01170                      result->sybase_ptr->dead = 1;
01171                      
01172               case CS_CANCELED:
01173               default:
01174                      retcode = CS_FAIL;
01175                      break;
01176        }
01177 
01178        return retcode;
01179 }
01180 
01181 #define RETURN_DOUBLE_VAL(result, buf, length)          \
01182        if ((length - 1) <= EG(precision)) {                \
01183               errno = 0;                                      \
01184               Z_DVAL(result) = zend_strtod(buf, NULL);        \
01185               if (errno != ERANGE) {                          \
01186                      Z_TYPE(result) = IS_DOUBLE;                 \
01187               } else {                                        \
01188                      ZVAL_STRINGL(&result, buf, length- 1, 1);   \
01189               }                                               \
01190        } else {                                            \
01191               ZVAL_STRINGL(&result, buf, length- 1, 1);       \
01192        }
01193 
01194 static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
01195 {
01196        int i, j;
01197        CS_INT retcode;
01198        TSRMLS_FETCH();
01199        
01200        /* We've already fetched everything */
01201        if (result->last_retcode == CS_END_DATA || result->last_retcode == CS_END_RESULTS) {
01202               return result->last_retcode;
01203        }
01204        
01205        if (numrows!=-1) numrows+= result->num_rows;
01206        while ((retcode=ct_fetch(result->sybase_ptr->cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL))==CS_SUCCEED || retcode == CS_ROW_FAIL) {
01207               result->num_rows++;
01208               i= result->store ? result->num_rows- 1 : 0;
01209               if (i >= result->blocks_initialized*SYBASE_ROWS_BLOCK) {
01210                      result->data = (zval **) safe_erealloc(result->data, SYBASE_ROWS_BLOCK*(++result->blocks_initialized), sizeof(zval *), 0);
01211               }
01212               if (result->store || 1 == result->num_rows) {
01213                      result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
01214               }
01215 
01216               for (j = 0; j < result->num_fields; j++) {
01217 
01218                      /* If we are in non-storing mode, free the previous result */
01219                      if (!result->store && result->num_rows > 1 && Z_TYPE(result->data[i][j]) == IS_STRING) {
01220                             efree(Z_STRVAL(result->data[i][j]));
01221                      }
01222 
01223                      if (result->indicators[j] == -1) { /* null value */
01224                             ZVAL_NULL(&result->data[i][j]);
01225                      } else {
01226                             switch (result->numerics[j]) {
01227                                    case 1: {
01228                                           /* This indicates a long */
01229                                           ZVAL_LONG(&result->data[i][j], strtol(result->tmp_buffer[j], NULL, 10));
01230                                           break;
01231                                    }
01232                                    
01233                                    case 2: {
01234                                           /* This indicates a float */
01235                                           RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
01236                                           break;
01237                                    }
01238 
01239                                    case 3: {
01240                                           /* This indicates either a long or a float, which ever fits */
01241                                           errno = 0;
01242                                           Z_LVAL(result->data[i][j]) = strtol(result->tmp_buffer[j], NULL, 10);
01243                                           if (errno == ERANGE) {
01244                                           
01245                                                  /* An overflow occurred, so try to fit it into a double */
01246                                                  RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
01247                                                  break;
01248                                           }
01249                                           Z_TYPE(result->data[i][j]) = IS_LONG;
01250                                           break;
01251                                    }
01252                                    
01253                                    default: {
01254                                           /* This indicates anything else, return it as string
01255                                            * FreeTDS doesn't correctly set result->indicators[j] correctly
01256                                            * for NULL fields in some version in conjunction with ASE 12.5
01257                                            * but instead sets result->lengths[j] to 0, which would lead to
01258                                            * a negative memory allocation (and thus a segfault).
01259                                            */
01260                                           if (result->lengths[j] < 1) {
01261                                                  ZVAL_NULL(&result->data[i][j]);
01262                                           } else {
01263                                                  ZVAL_STRINGL(&result->data[i][j], result->tmp_buffer[j], result->lengths[j]- 1, 1);
01264                                           }
01265                                           break;
01266                                    }
01267                             }
01268                      }
01269               }
01270               if (numrows!=-1 && result->num_rows>=numrows) break;
01271        }
01272 
01273        if (retcode==CS_ROW_FAIL) {
01274               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Error reading row %d", result->num_rows);
01275               return retcode;
01276        }
01277        result->last_retcode= retcode;
01278        switch (retcode) {
01279               case CS_END_DATA:
01280                      retcode = php_sybase_finish_results(result TSRMLS_CC);
01281                      break;
01282                      
01283               case CS_ROW_FAIL:
01284               case CS_SUCCEED:
01285                      break;
01286                      
01287               default:
01288                      FREE_SYBASE_RESULT(result);
01289                      result = NULL;
01290                      retcode = CS_FAIL;          /* Just to be sure */
01291                      break;
01292        }
01293        
01294        return retcode;
01295 }
01296 
01297 static sybase_result * php_sybase_fetch_result_set (sybase_link *sybase_ptr, int buffered, int store)
01298 {
01299        int num_fields;
01300        sybase_result *result;
01301        int i, j;
01302        CS_INT retcode;
01303 
01304        /* The following (if unbuffered) is more or less the equivalent of mysql_store_result().
01305         * fetch all rows from the server into the row buffer, thus:
01306         * 1)  Being able to fire up another query without explicitly reading all rows
01307         * 2)  Having numrows accessible
01308         */
01309        if (ct_res_info(sybase_ptr->cmd, CS_NUMDATA, &num_fields, CS_UNUSED, NULL)!=CS_SUCCEED) {
01310               return NULL;
01311        }
01312        
01313        result = (sybase_result *) emalloc(sizeof(sybase_result));
01314        result->data = (zval **) safe_emalloc(sizeof(zval *), SYBASE_ROWS_BLOCK, 0);
01315        result->fields = NULL;
01316        result->sybase_ptr = sybase_ptr;
01317        result->cur_field=result->cur_row=result->num_rows=0;
01318        result->num_fields = num_fields;
01319        result->last_retcode = 0;
01320        result->store= store;
01321        result->blocks_initialized= 1;
01322        result->tmp_buffer = (char **) safe_emalloc(sizeof(char *), num_fields, 0);
01323        result->lengths = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
01324        result->indicators = (CS_SMALLINT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
01325        result->datafmt = (CS_DATAFMT *) safe_emalloc(sizeof(CS_DATAFMT), num_fields, 0);
01326        result->numerics = (unsigned char *) safe_emalloc(sizeof(unsigned char), num_fields, 0);
01327        result->types = (CS_INT *) safe_emalloc(sizeof(CS_INT), num_fields, 0);
01328        
01329        for (i=0; i<num_fields; i++) {
01330               ct_describe(sybase_ptr->cmd, i+1, &result->datafmt[i]);
01331               result->types[i] = result->datafmt[i].datatype;
01332               switch (result->datafmt[i].datatype) {
01333                      case CS_CHAR_TYPE:
01334                      case CS_VARCHAR_TYPE:
01335                      case CS_TEXT_TYPE:
01336                      case CS_IMAGE_TYPE:
01337                             result->datafmt[i].maxlength++;
01338                             result->numerics[i] = 0;
01339                             break;
01340                      case CS_BINARY_TYPE:
01341                      case CS_VARBINARY_TYPE:
01342                             result->datafmt[i].maxlength *= 2;
01343                             result->datafmt[i].maxlength++;
01344                             result->numerics[i] = 0;
01345                             break;
01346                      case CS_BIT_TYPE:
01347                      case CS_TINYINT_TYPE:
01348                             result->datafmt[i].maxlength = 4;
01349                             result->numerics[i] = 1;
01350                             break;
01351                      case CS_SMALLINT_TYPE:
01352                             result->datafmt[i].maxlength = 7;
01353                             result->numerics[i] = 1;
01354                             break;
01355                      case CS_INT_TYPE:
01356                             result->datafmt[i].maxlength = 12;
01357                             result->numerics[i] = 1;
01358                             break;
01359                      case CS_REAL_TYPE:
01360                      case CS_FLOAT_TYPE:
01361                             result->datafmt[i].maxlength = 24;
01362                             result->numerics[i] = 2;
01363                             break;
01364                      case CS_MONEY_TYPE:
01365                      case CS_MONEY4_TYPE:
01366                             result->datafmt[i].maxlength = 24;
01367                             result->numerics[i] = 2;
01368                             break;
01369                      case CS_DATETIME_TYPE:
01370                      case CS_DATETIME4_TYPE:
01371                             result->datafmt[i].maxlength = 30;
01372                             result->numerics[i] = 0;
01373                             break;
01374                      case CS_NUMERIC_TYPE:
01375                      case CS_DECIMAL_TYPE:
01376                             result->datafmt[i].maxlength = result->datafmt[i].precision + 3;
01377                             /* numeric(10) vs numeric(10, 1) */
01378                             result->numerics[i] = (result->datafmt[i].scale == 0) ? 3 : 2;
01379                             break;
01380                      default:
01381                             result->datafmt[i].maxlength++;
01382                             result->numerics[i] = 0;
01383                             break;
01384               }
01385               result->tmp_buffer[i] = (char *)emalloc(result->datafmt[i].maxlength);
01386               result->datafmt[i].datatype = CS_CHAR_TYPE;
01387               result->datafmt[i].format = CS_FMT_NULLTERM;
01388               ct_bind(sybase_ptr->cmd, i+1, &result->datafmt[i], result->tmp_buffer[i], &result->lengths[i], &result->indicators[i]);
01389        }
01390 
01391        result->fields = (sybase_field *) safe_emalloc(sizeof(sybase_field), num_fields, 0);
01392        j=0;
01393        for (i=0; i<num_fields; i++) {
01394               char computed_buf[16];
01395 
01396               if (result->datafmt[i].namelen>0) {
01397                      result->fields[i].name = estrndup(result->datafmt[i].name, result->datafmt[i].namelen);
01398               } else {
01399                      if (j>0) {
01400                             snprintf(computed_buf, 16, "computed%d", j);
01401                      } else {
01402                             strcpy(computed_buf, "computed");
01403                      }
01404                      result->fields[i].name = estrdup(computed_buf);
01405                      j++;
01406               }
01407               result->fields[i].column_source = STR_EMPTY_ALLOC();
01408               result->fields[i].max_length = result->datafmt[i].maxlength-1;
01409               result->fields[i].numeric = result->numerics[i];
01410               Z_TYPE(result->fields[i]) = result->types[i];
01411        }
01412        
01413        if (buffered) {
01414               retcode = CS_SUCCEED;
01415        } else {
01416               if ((retcode = php_sybase_fetch_result_row(result, -1)) == CS_FAIL) {
01417                      return NULL;
01418               }
01419        }
01420 
01421        result->last_retcode = retcode;
01422        return result;
01423 }
01424 
01425 static void php_sybase_query (INTERNAL_FUNCTION_PARAMETERS, int buffered)
01426 {
01427        zval *sybase_link_index = NULL;
01428        zend_bool store = 1;
01429        char *query;
01430        int len, id, deadlock_count;
01431        sybase_link *sybase_ptr;
01432        sybase_result *result;
01433        CS_INT restype;
01434        CS_RETCODE retcode;
01435        enum {
01436               Q_RESULT,                          /* Success with results. */
01437               Q_SUCCESS,                         /* Success but no results. */
01438               Q_FAILURE,                         /* Failure, no results. */
01439        } status;
01440 
01441        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|rb", &query, &len, &sybase_link_index, &store) == FAILURE) {
01442               return;
01443        }
01444 
01445        if (!store && !buffered) {
01446               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Cannot use non-storing mode with buffered queries");
01447               store = 1;
01448        }
01449 
01450        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
01451               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
01452               RETURN_FALSE;
01453        }
01454 
01455        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
01456 
01457        /* Fail if we already marked this connection dead. */
01458        if (sybase_ptr->dead) {
01459               RETURN_FALSE;
01460        }
01461        
01462        /* Check to see if a previous sybase_unbuffered_query has read all rows */
01463        if (sybase_ptr->active_result_index) {
01464               zval *tmp = NULL;
01465               
01466               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Called without first fetching all rows from a previous unbuffered query");
01467               if (sybase_ptr->cmd) {
01468                      ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01469               }
01470               
01471               /* Get the resultset and free it */
01472               ALLOC_ZVAL(tmp);
01473               Z_LVAL_P(tmp)= sybase_ptr->active_result_index;
01474               Z_TYPE_P(tmp)= IS_RESOURCE;
01475               INIT_PZVAL(tmp);
01476               ZEND_FETCH_RESOURCE(result, sybase_result *, &tmp, -1, "Sybase result", le_result);
01477               
01478               if (result) {
01479                      php_sybase_finish_results(result TSRMLS_CC);
01480               }
01481               
01482               zval_ptr_dtor(&tmp);
01483               zend_list_delete(sybase_ptr->active_result_index);
01484               sybase_ptr->active_result_index= 0;
01485        }
01486 
01487        /* Repeat until we don't deadlock. */
01488        deadlock_count= 0;
01489        for (;;) {
01490               result = NULL;
01491               sybase_ptr->deadlock = 0;
01492               sybase_ptr->affected_rows = 0;
01493 
01494               /* On Solaris 11.5, ct_command() can be moved outside the
01495                * loop, but not on Linux 11.0.
01496                */
01497               if (ct_command(sybase_ptr->cmd, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED)!=CS_SUCCEED) {
01498                      /* If this didn't work, the connection is screwed but
01499                       * ct-lib might not set CS_CONSTAT_DEAD.  So set our own
01500                       * flag.  This happens sometimes when the database is restarted
01501                       * and/or its machine is rebooted, and ct_command() returns
01502                       * CS_BUSY for some reason.
01503                       */
01504                      sybase_ptr->dead = 1;
01505                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Connection is dead");
01506                      RETURN_FALSE;
01507               }
01508 
01509               if (ct_send(sybase_ptr->cmd)!=CS_SUCCEED) {
01510                      ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01511                      sybase_ptr->dead = 1;
01512                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot send command");
01513                      RETURN_FALSE;
01514               }
01515 
01516               /* Use the first result set or succeed/fail status and discard the
01517                * others.  Applications really shouldn't be making calls that
01518                * return multiple result sets, but if they do then we need to
01519                * properly read or cancel them or the connection will become
01520                * unusable.
01521                */
01522               if (ct_results(sybase_ptr->cmd, &restype)!=CS_SUCCEED) {
01523                      ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01524                      sybase_ptr->dead = 1;
01525                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cannot read results");
01526                      RETURN_FALSE;
01527               }
01528               switch ((int) restype) {
01529                      case CS_CMD_FAIL:
01530                      default:
01531                             status = Q_FAILURE;
01532                             break;
01533                      case CS_CMD_SUCCEED:
01534                      case CS_CMD_DONE: {
01535                                    CS_INT row_count;
01536                                    if (ct_res_info(sybase_ptr->cmd, CS_ROW_COUNT, &row_count, CS_UNUSED, NULL)==CS_SUCCEED) {
01537                                           sybase_ptr->affected_rows = (long)row_count;
01538                                    }
01539                             }
01540                             /* Fall through */
01541                      case CS_COMPUTEFMT_RESULT:
01542                      case CS_ROWFMT_RESULT:
01543                      case CS_DESCRIBE_RESULT:
01544                      case CS_MSG_RESULT:
01545                             buffered= 0;                       /* These queries have no need for buffering */
01546                             status = Q_SUCCESS;
01547                             break;
01548                      case CS_COMPUTE_RESULT:
01549                      case CS_CURSOR_RESULT:
01550                      case CS_PARAM_RESULT:
01551                      case CS_ROW_RESULT:
01552                      case CS_STATUS_RESULT:
01553                             result = php_sybase_fetch_result_set(sybase_ptr, buffered, store);
01554                             if (result == NULL) {
01555                                    ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01556                                    RETURN_FALSE;
01557                             }
01558                             status = Q_RESULT;
01559                             break;
01560               }
01561               
01562               /* Check for left-over results */
01563               if (!buffered && status != Q_RESULT) {
01564                      while ((retcode = ct_results(sybase_ptr->cmd, &restype))==CS_SUCCEED) {
01565                             switch ((int) restype) {
01566                                    case CS_CMD_SUCCEED:
01567                                    case CS_CMD_DONE:
01568                                           break;
01569 
01570                                    case CS_CMD_FAIL:
01571                                           status = Q_FAILURE;
01572                                           break;
01573 
01574                                    case CS_COMPUTE_RESULT:
01575                                    case CS_CURSOR_RESULT:
01576                                    case CS_PARAM_RESULT:
01577                                    case CS_ROW_RESULT:
01578                                           if (status != Q_RESULT) {
01579                                                  result = php_sybase_fetch_result_set(sybase_ptr, buffered, store);
01580                                                  if (result == NULL) {
01581                                                         ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01582                                                         sybase_ptr->dead = 1;
01583                                                         RETURN_FALSE;
01584                                                  }
01585                                                  status = Q_RESULT;
01586                                                  retcode = result->last_retcode; 
01587                                           } else {
01588                                                  /* Unexpected results, cancel them. */
01589                                                  ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
01590                                           }
01591                                           break;
01592                                    case CS_STATUS_RESULT:
01593                                           /* Unexpected results, cancel them. */
01594                                           ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT);
01595                                           break;
01596 
01597                                    default:
01598                                           status = Q_FAILURE;
01599                                           break;
01600                             }
01601                             if (status == Q_FAILURE) {
01602                                    ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01603                             }
01604                             if (retcode == CS_END_RESULTS) {
01605                                    break;
01606                             }
01607                      }
01608                      switch (retcode) {
01609                             case CS_END_RESULTS:
01610                                    /* Normal. */
01611                                    break;
01612 
01613                             case CS_FAIL:
01614                                    /* Hopefully this either cleans up the connection, or the
01615                                     * connection ends up marked dead so it will be reopened
01616                                     * if it is persistent.  We may want to do
01617                                     * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
01618                                     * doc for ct_results()==CS_FAIL.
01619                                     */
01620                                    ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
01621                                    /* Don't take chances with the vagaries of ct-lib.  Mark it
01622                                     * dead ourselves.
01623                                     */
01624                                    sybase_ptr->dead = 1;
01625                             case CS_CANCELED:
01626                             default:
01627                                    status = Q_FAILURE;
01628                                    break;
01629                      }
01630               }
01631 
01632               /* Retry deadlocks up until deadlock_retry_count times */             
01633               if (sybase_ptr->deadlock && SybCtG(deadlock_retry_count) != -1 && ++deadlock_count > SybCtG(deadlock_retry_count)) {
01634                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Retried deadlock %d times [max: %ld], giving up", deadlock_count- 1, SybCtG(deadlock_retry_count));
01635                      FREE_SYBASE_RESULT(result);
01636                      break;
01637               }
01638 
01639               /* If query completed without deadlock, break out of the loop.
01640                * Sometimes deadlock results in failures and sometimes not,
01641                * it seems to depend on the server flavor.  But we want to
01642                * retry all deadlocks.
01643                */
01644               if (sybase_ptr->dead || sybase_ptr->deadlock == 0) {
01645                      break;
01646               }
01647 
01648               /* Get rid of any results we may have fetched.  This happens:
01649                * e.g., our result set may be a stored procedure status which
01650                * is returned even if the stored procedure deadlocks.  As an
01651                * optimization, we could try not to fetch results in known
01652                * deadlock conditions, but deadlock is (should be) rare.
01653                */
01654               FREE_SYBASE_RESULT(result);
01655        }
01656 
01657        if (status == Q_SUCCESS) {
01658               RETURN_TRUE;
01659        }
01660 
01661        if (status == Q_FAILURE) {
01662               FREE_SYBASE_RESULT(result);
01663               RETURN_FALSE;
01664        }
01665 
01666        /* Indicate we have data in case of buffered queries */
01667        id= ZEND_REGISTER_RESOURCE(return_value, result, le_result);
01668        sybase_ptr->active_result_index= buffered ? id : 0;
01669 }
01670 
01671 /* {{{ proto int sybase_query(string query [, resource link_id])
01672    Send Sybase query */
01673 PHP_FUNCTION(sybase_query)
01674 {
01675        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01676 }
01677 /* }}} */
01678 
01679 /* {{{ proto int sybase_unbuffered_query(string query [, resource link_id])
01680    Send Sybase query */
01681 PHP_FUNCTION(sybase_unbuffered_query)
01682 {
01683        php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01684 }
01685 
01686 /* {{{ proto bool sybase_free_result(resource result)
01687    Free result memory */
01688 PHP_FUNCTION(sybase_free_result)
01689 {
01690        zval *sybase_result_index = NULL;
01691        sybase_result *result;
01692 
01693        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
01694               return;
01695        }
01696        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01697        
01698        /* Did we fetch up until the end? */
01699        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
01700               /* php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Cancelling the rest of the results"); */
01701               ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
01702               php_sybase_finish_results(result TSRMLS_CC);
01703        }
01704        
01705        zend_list_delete(Z_LVAL_P(sybase_result_index));
01706        RETURN_TRUE;
01707 }
01708 
01709 /* }}} */
01710 
01711 /* {{{ proto string sybase_get_last_message(void)
01712    Returns the last message from server (over min_message_severity) */
01713 PHP_FUNCTION(sybase_get_last_message)
01714 {
01715        RETURN_STRING(SybCtG(server_message), 1);
01716 }
01717 /* }}} */
01718 
01719 /* {{{ proto int sybase_num_rows(resource result)
01720    Get number of rows in result */
01721 PHP_FUNCTION(sybase_num_rows)
01722 {
01723        zval *sybase_result_index = NULL;
01724        sybase_result *result;
01725 
01726        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
01727               return;
01728        }
01729        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01730 
01731        Z_LVAL_P(return_value) = result->num_rows;
01732        Z_TYPE_P(return_value) = IS_LONG;
01733 }
01734 
01735 /* }}} */
01736 
01737 /* {{{ proto int sybase_num_fields(resource result)
01738    Get number of fields in result */
01739 PHP_FUNCTION(sybase_num_fields)
01740 {
01741        zval *sybase_result_index = NULL;
01742        sybase_result *result;
01743 
01744        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
01745               return;
01746        }
01747        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01748 
01749        Z_LVAL_P(return_value) = result->num_fields;
01750        Z_TYPE_P(return_value) = IS_LONG;
01751 }
01752 
01753 /* }}} */
01754 
01755 /* {{{ proto array sybase_fetch_row(resource result)
01756    Get row as enumerated array */
01757 PHP_FUNCTION(sybase_fetch_row)
01758 {
01759        zval *sybase_result_index = NULL;
01760        int i;
01761        sybase_result *result;
01762        zval *field_content;
01763 
01764        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
01765               return;
01766        }
01767        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01768 
01769        /* Unbuffered? */
01770        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
01771               php_sybase_fetch_result_row(result, 1);
01772        }
01773        
01774        /* At the end? */
01775        if (result->cur_row >= result->num_rows) {
01776               RETURN_FALSE;
01777        }
01778 
01779        array_init(return_value);
01780        for (i=0; i<result->num_fields; i++) {
01781               ALLOC_ZVAL(field_content);
01782               *field_content = result->data[result->store ? result->cur_row : 0][i];
01783               INIT_PZVAL(field_content);
01784               zval_copy_ctor(field_content);
01785               zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &field_content, sizeof(zval* ), NULL);
01786        }
01787        result->cur_row++;
01788 }
01789 
01790 /* }}} */
01791 
01792 static void php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int numerics)
01793 {
01794        zval *sybase_result_index = NULL;
01795        sybase_result *result;
01796        int i, j;
01797        zval *tmp;
01798        char name[32];
01799 
01800        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &sybase_result_index) == FAILURE) {
01801               return;
01802        }
01803        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01804 
01805        /* Unbuffered ? Fetch next row */
01806        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS) {
01807               php_sybase_fetch_result_row(result, 1);
01808        }
01809 
01810        /* At the end? */
01811        if (result->cur_row >= result->num_rows) {
01812               RETURN_FALSE;
01813        }
01814 
01815        array_init(return_value);
01816        
01817        j= 1;
01818        for (i=0; i<result->num_fields; i++) {
01819               ALLOC_ZVAL(tmp);
01820               *tmp = result->data[result->store ? result->cur_row : 0][i];
01821               INIT_PZVAL(tmp);
01822               if (PG(magic_quotes_runtime) && Z_TYPE_P(tmp) == IS_STRING) {
01823                      Z_STRVAL_P(tmp) = php_addslashes(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &Z_STRLEN_P(tmp), 0 TSRMLS_CC);
01824               } else {
01825                      zval_copy_ctor(tmp);
01826               }
01827               if (numerics) {
01828                      zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &tmp, sizeof(zval *), NULL);
01829                      Z_ADDREF_P(tmp);
01830               }
01831               
01832               if (zend_hash_exists(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1)) {
01833                      snprintf(name, 32, "%s%d", result->fields[i].name, j);
01834                      result->fields[i].name= estrdup(name);
01835                      j++;
01836               }
01837               zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(zval *), NULL);
01838        }
01839        result->cur_row++;
01840 }
01841 
01842 
01843 /* {{{ proto object sybase_fetch_object(resource result [, mixed object])
01844    Fetch row as object */
01845 PHP_FUNCTION(sybase_fetch_object)
01846 {
01847        zval *object = NULL;
01848        zval *sybase_result_index = NULL;
01849        zend_class_entry *ce = NULL;
01850        sybase_result *result;
01851        
01852        /* Was a second parameter given? */
01853        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &sybase_result_index, &object) == FAILURE) {
01854               return;
01855        }
01856        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01857 
01858        ce = ZEND_STANDARD_CLASS_DEF_PTR;
01859        if (NULL != object) {              
01860               switch (Z_TYPE_P(object)) {
01861                      case IS_OBJECT: {
01862                             ce = Z_OBJCE_P(object);
01863                             break;
01864                      }
01865 
01866                      case IS_NULL: {
01867                             /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
01868                             break;
01869                      }
01870 
01871                      default: {
01872                             zend_class_entry **pce = NULL;
01873                             convert_to_string(object);
01874 
01875                             if (zend_lookup_class(Z_STRVAL_P(object), Z_STRLEN_P(object), &pce TSRMLS_CC) == FAILURE) {
01876                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Class %s has not been declared", Z_STRVAL_P(object));
01877                                    /* Use default (ZEND_STANDARD_CLASS_DEF_PTR) */
01878                             } else {
01879                                    ce = *pce;
01880                             }
01881                      }
01882               }
01883        }
01884 
01885        /* Reset no. of arguments to 1 so that we can use INTERNAL_FUNCTION_PARAM_PASSTHRU */
01886        ht= 1;
01887        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01888        if (Z_TYPE_P(return_value) == IS_ARRAY) {
01889               object_and_properties_init(return_value, ce, Z_ARRVAL_P(return_value));
01890        }
01891 }
01892 /* }}} */
01893 
01894 /* {{{ proto array sybase_fetch_array(resource result)
01895    Fetch row as array */
01896 PHP_FUNCTION(sybase_fetch_array)
01897 {
01898        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01899 }
01900 /* }}} */
01901 
01902 /* {{{ proto array sybase_fetch_assoc(resource result)
01903    Fetch row as array without numberic indices */
01904 PHP_FUNCTION(sybase_fetch_assoc)
01905 {
01906        php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01907 }
01908 /* }}} */
01909 
01910 /* {{{ proto bool sybase_data_seek(resource result, int offset)
01911    Move internal row pointer */
01912 PHP_FUNCTION(sybase_data_seek)
01913 {
01914        zval *sybase_result_index = NULL;
01915        long offset;
01916        sybase_result *result;
01917 
01918        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &offset) == FAILURE) {
01919               return;
01920        }
01921        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01922 
01923        /* Unbuffered ? */
01924        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && offset >= result->num_rows) {
01925               php_sybase_fetch_result_row(result, offset+ 1);
01926        }
01927        
01928        if (offset < 0 || offset >= result->num_rows) {
01929               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset %ld, must be betweem 0 and %d", offset, result->num_rows - 1);
01930               RETURN_FALSE;
01931        }
01932 
01933        result->cur_row = offset;
01934        RETURN_TRUE;
01935 }
01936 /* }}} */
01937 
01938 static char *php_sybase_get_field_name(CS_INT type)
01939 {
01940        switch (type) {
01941               case CS_CHAR_TYPE:
01942               case CS_VARCHAR_TYPE:
01943               case CS_TEXT_TYPE:
01944                      return "string";
01945                      break;
01946               case CS_IMAGE_TYPE:
01947                      return "image";
01948                      break;
01949               case CS_BINARY_TYPE:
01950               case CS_VARBINARY_TYPE:
01951                      return "blob";
01952                      break;
01953               case CS_BIT_TYPE:
01954                      return "bit";
01955                      break;
01956               case CS_TINYINT_TYPE:
01957               case CS_SMALLINT_TYPE:
01958               case CS_INT_TYPE:
01959                      return "int";
01960                      break;
01961               case CS_REAL_TYPE:
01962               case CS_FLOAT_TYPE:
01963               case CS_NUMERIC_TYPE:
01964               case CS_DECIMAL_TYPE:
01965                      return "real";
01966                      break;
01967               case CS_MONEY_TYPE:
01968               case CS_MONEY4_TYPE:
01969                      return "money";
01970                      break;
01971               case CS_DATETIME_TYPE:
01972               case CS_DATETIME4_TYPE:
01973                      return "datetime";
01974                      break;
01975               default:
01976                      return "unknown";
01977                      break;
01978        }
01979 }
01980 
01981 
01982 /* {{{ proto object sybase_fetch_field(resource result [, int offset])
01983    Get field information */
01984 PHP_FUNCTION(sybase_fetch_field)
01985 {
01986        zval *sybase_result_index = NULL;
01987        long field_offset = -1;
01988        sybase_result *result;
01989 
01990        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &sybase_result_index, &field_offset) == FAILURE) {
01991               return;
01992        }
01993        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
01994 
01995        if (field_offset == -1) {
01996               field_offset = result->cur_field;
01997               result->cur_field++;
01998        }
01999 
02000        if (field_offset < 0 || field_offset >= result->num_fields) {
02001               if (ZEND_NUM_ARGS() == 2) { /* field specified explicitly */
02002                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
02003               }
02004               RETURN_FALSE;
02005        }
02006 
02007        object_init(return_value);
02008 
02009        add_property_string(return_value, "name", result->fields[field_offset].name, 1);
02010        add_property_long(return_value, "max_length", result->fields[field_offset].max_length);
02011        add_property_string(return_value, "column_source", result->fields[field_offset].column_source, 1);
02012        add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
02013        add_property_string(return_value, "type", php_sybase_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
02014 }
02015 /* }}} */
02016 
02017 
02018 /* {{{ proto bool sybase_field_seek(resource result, int offset)
02019    Set field offset */
02020 PHP_FUNCTION(sybase_field_seek)
02021 {
02022        zval *sybase_result_index = NULL;
02023        long field_offset;
02024        sybase_result *result;
02025 
02026        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &sybase_result_index, &field_offset) == FAILURE) {
02027               return;
02028        }
02029        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
02030 
02031        if (field_offset < 0 || field_offset >= result->num_fields) {
02032               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
02033               RETURN_FALSE;
02034        }
02035 
02036        result->cur_field = field_offset;
02037        RETURN_TRUE;
02038 }
02039 /* }}} */
02040 
02041 
02042 /* {{{ proto string sybase_result(resource result, int row, mixed field)
02043    Get result data */
02044 PHP_FUNCTION(sybase_result)
02045 {
02046        zval *field;
02047        zval *sybase_result_index = NULL;
02048        long row;
02049        int field_offset = 0;
02050        sybase_result *result;
02051 
02052        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &sybase_result_index, &row, &field) == FAILURE) {
02053               return;
02054        }
02055        ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result);
02056        
02057        /* Unbuffered ? */
02058        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && row >= result->num_rows) {
02059               php_sybase_fetch_result_row(result, row);
02060        }
02061 
02062        if (row < 0 || row >= result->num_rows) {
02063               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset (%ld)", row);
02064               RETURN_FALSE;
02065        }
02066 
02067        switch(Z_TYPE_P(field)) {
02068               case IS_STRING: {
02069                      int i;
02070 
02071                      for (i = 0; i < result->num_fields; i++) {
02072                             if (strcasecmp(result->fields[i].name, Z_STRVAL_P(field)) == 0) {
02073                                    field_offset = i;
02074                                    break;
02075                             }
02076                      }
02077                      if (i >= result->num_fields) { /* no match found */
02078                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  %s field not found in result", Z_STRVAL_P(field));
02079                             RETURN_FALSE;
02080                      }
02081                      break;
02082               }
02083               default:
02084                      convert_to_long(field);
02085                      field_offset = Z_LVAL_P(field);
02086                      if (field_offset < 0 || field_offset >= result->num_fields) {
02087                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset specified");
02088                             RETURN_FALSE;
02089                      }
02090                      break;
02091        }
02092 
02093        *return_value = result->data[row][field_offset];
02094        zval_copy_ctor(return_value);
02095 }
02096 /* }}} */
02097 
02098 
02099 /* {{{ proto int sybase_affected_rows([resource link_id])
02100    Get number of affected rows in last query */
02101 PHP_FUNCTION(sybase_affected_rows)
02102 {
02103        zval *sybase_link_index = NULL;
02104        sybase_link *sybase_ptr;
02105        int id;
02106 
02107        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &sybase_link_index) == FAILURE) {
02108               return;
02109        }
02110 
02111        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
02112               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  No connection");
02113               RETURN_FALSE;
02114        }
02115 
02116        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
02117 
02118        Z_LVAL_P(return_value) = sybase_ptr->affected_rows;
02119        Z_TYPE_P(return_value) = IS_LONG;
02120 }
02121 /* }}} */
02122 
02123 
02124 PHP_MINFO_FUNCTION(sybase)
02125 {
02126        char buf[32];
02127 
02128        php_info_print_table_start();
02129        php_info_print_table_header(2, "Sybase_CT Support", "enabled" );
02130        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_persistent));
02131        php_info_print_table_row(2, "Active Persistent Links", buf);
02132        snprintf(buf, sizeof(buf), "%ld", SybCtG(num_links));
02133        php_info_print_table_row(2, "Active Links", buf);
02134        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_server_severity));
02135        php_info_print_table_row(2, "Min server severity", buf);
02136        snprintf(buf, sizeof(buf), "%ld", SybCtG(min_client_severity));
02137        php_info_print_table_row(2, "Min client severity", buf);       
02138        php_info_print_table_row(2, "Application Name", SybCtG(appname));
02139        snprintf(buf, sizeof(buf), "%ld", SybCtG(deadlock_retry_count));
02140        php_info_print_table_row(2, "Deadlock retry count", buf);
02141        php_info_print_table_end();
02142 
02143        DISPLAY_INI_ENTRIES();
02144 }
02145 
02146 
02147 /* {{{ proto void sybase_min_client_severity(int severity)
02148    Sets minimum client severity */
02149 PHP_FUNCTION(sybase_min_client_severity)
02150 {
02151        long severity;
02152 
02153        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
02154               return;
02155        }
02156        
02157        SybCtG(min_client_severity) = severity;
02158 }
02159 /* }}} */
02160 
02161 
02162 /* {{{ proto void sybase_min_server_severity(int severity)
02163    Sets minimum server severity */
02164 PHP_FUNCTION(sybase_min_server_severity)
02165 {
02166        long severity;
02167 
02168        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
02169               return;
02170        }
02171        
02172        SybCtG(min_server_severity) = severity;
02173 }
02174 /* }}} */
02175 
02176 /* {{{ proto void sybase_deadlock_retry_count(int retry_count)
02177    Sets deadlock retry count */
02178 PHP_FUNCTION(sybase_deadlock_retry_count)
02179 {
02180        long retry_count;
02181 
02182        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &retry_count) == FAILURE) {
02183               return;
02184        }
02185        
02186        SybCtG(deadlock_retry_count) = retry_count;
02187 }
02188 /* }}} */
02189 
02190 
02191 /* {{{ proto bool sybase_set_message_handler(mixed error_func [, resource connection])
02192    Set the error handler, to be called when a server message is raised. 
02193    If error_func is NULL the handler will be deleted */
02194 PHP_FUNCTION(sybase_set_message_handler)
02195 {
02196        zend_fcall_info fci = empty_fcall_info;
02197        zend_fcall_info_cache cache = empty_fcall_info_cache;
02198        zval *sybase_link_index= NULL;
02199        sybase_link *sybase_ptr;
02200        zval **callback;
02201        int id;
02202 
02203        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!|r", &fci, &cache, &sybase_link_index) == FAILURE) {
02204               return;
02205        }
02206 
02207        if (php_sybase_connection_id(sybase_link_index, &id TSRMLS_CC) == FAILURE) {
02208 
02209               /* Doesn't matter if we're not connected yet, use default */
02210               callback= &SybCtG(callback_name);
02211        } else if (-1 == id) {
02212 
02213               /* Connection-based message handler */
02214               ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, &sybase_link_index, id, "Sybase-Link", le_link, le_plink);
02215               callback= &sybase_ptr->callback_name;
02216        } else {
02217 
02218               /* Default message handler */
02219               callback= &SybCtG(callback_name);
02220        }
02221 
02222        /* Clean old callback */
02223        if (*callback) {
02224               zval_ptr_dtor(callback);
02225               *callback = NULL;
02226        }
02227 
02228        if (ZEND_FCI_INITIALIZED(fci)) {
02229               ALLOC_ZVAL(*callback);
02230               **callback = *fci.function_name;
02231               INIT_PZVAL(*callback);
02232               zval_copy_ctor(*callback);
02233        } else {
02234               callback= NULL;
02235        }
02236 
02237        RETURN_TRUE;
02238 }
02239 /* }}} */
02240 
02241 
02242 #endif
02243 
02244 /*
02245  * Local variables:
02246  * tab-width: 4
02247  * c-basic-offset: 4
02248  * End:
02249  */