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

Generated by: LCOV version 1.10

Generated at Wed, 23 Jul 2014 19:58:42 +0000 (39 hours ago)

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