PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/sybase_ct - php_sybase_ct.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 107 886 12.1 %
Date: 2014-10-16 Functions: 12 49 24.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Thu, 16 Oct 2014 05:27:12 +0000 (4 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.