root/ext/mssql/php_mssql.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_INI_DISP
  2. PHP_INI_BEGIN
  3. php_mssql_message_handler
  4. _clean_invalid_results
  5. _free_result
  6. _free_mssql_statement
  7. _free_mssql_result
  8. php_mssql_set_default_link
  9. _close_mssql_link
  10. _close_mssql_plink
  11. _mssql_bind_hash_dtor
  12. PHP_GINIT_FUNCTION
  13. PHP_MINIT_FUNCTION
  14. PHP_MSHUTDOWN_FUNCTION
  15. PHP_RINIT_FUNCTION
  16. PHP_RSHUTDOWN_FUNCTION
  17. PHP_MINFO_FUNCTION
  18. php_mssql_do_connect
  19. php_mssql_get_default_link
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. php_mssql_get_column_content_with_type
  25. php_mssql_get_column_content_without_type
  26. _mssql_get_sp_result
  27. _mssql_fetch_batch
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. php_mssql_fetch_hash
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. php_mssql_get_field_name
  42. PHP_FUNCTION
  43. PHP_FUNCTION
  44. PHP_FUNCTION
  45. PHP_FUNCTION
  46. PHP_FUNCTION
  47. PHP_FUNCTION
  48. PHP_FUNCTION
  49. PHP_FUNCTION
  50. PHP_FUNCTION
  51. PHP_FUNCTION
  52. PHP_FUNCTION
  53. PHP_FUNCTION
  54. PHP_FUNCTION
  55. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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    | Author: Frank M. Kromann <frank@kromann.info>                        |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef COMPILE_DL_MSSQL
  22 #define HAVE_MSSQL 1
  23 #endif
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include "config.h"
  27 #endif
  28 
  29 #include "php.h"
  30 #include "php_globals.h"
  31 #include "ext/standard/php_standard.h"
  32 #include "ext/standard/info.h"
  33 #include "php_mssql.h"
  34 #include "php_ini.h"
  35 
  36 #if HAVE_MSSQL
  37 #define SAFE_STRING(s) ((s)?(s):"")
  38 
  39 #define MSSQL_ASSOC             1<<0
  40 #define MSSQL_NUM               1<<1
  41 #define MSSQL_BOTH              (MSSQL_ASSOC|MSSQL_NUM)
  42 
  43 static int le_result, le_link, le_plink, le_statement;
  44 
  45 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC);
  46 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC);
  47 
  48 static void _mssql_bind_hash_dtor(void *data);
  49 
  50 /* {{{ arginfo */
  51 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_connect, 0, 0, 0)
  52         ZEND_ARG_INFO(0, servername)
  53         ZEND_ARG_INFO(0, username)
  54         ZEND_ARG_INFO(0, password)
  55         ZEND_ARG_INFO(0, newlink)
  56 ZEND_END_ARG_INFO()
  57 
  58 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_close, 0, 0, 0)
  59         ZEND_ARG_INFO(0, link_identifier)
  60 ZEND_END_ARG_INFO()
  61 
  62 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_select_db, 0, 0, 1)
  63         ZEND_ARG_INFO(0, database_name)
  64         ZEND_ARG_INFO(0, link_identifier)
  65 ZEND_END_ARG_INFO()
  66 
  67 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_query, 0, 0, 1)
  68         ZEND_ARG_INFO(0, query)
  69         ZEND_ARG_INFO(0, link_identifier)
  70         ZEND_ARG_INFO(0, batch_size)
  71 ZEND_END_ARG_INFO()
  72 
  73 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_batch, 0, 0, 1)
  74         ZEND_ARG_INFO(0, result)
  75 ZEND_END_ARG_INFO()
  76 
  77 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_rows_affected, 0, 0, 1)
  78         ZEND_ARG_INFO(0, link_identifier)
  79 ZEND_END_ARG_INFO()
  80 
  81 ZEND_BEGIN_ARG_INFO(arginfo_mssql_get_last_message, 0)
  82 ZEND_END_ARG_INFO()
  83 
  84 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_field, 0, 0, 1)
  85         ZEND_ARG_INFO(0, result)
  86         ZEND_ARG_INFO(0, field_offset)
  87 ZEND_END_ARG_INFO()
  88 
  89 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_array, 0, 0, 1)
  90         ZEND_ARG_INFO(0, result)
  91         ZEND_ARG_INFO(0, result_type)
  92 ZEND_END_ARG_INFO()
  93 
  94 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_assoc, 0, 0, 1)
  95         ZEND_ARG_INFO(0, result_id)
  96 ZEND_END_ARG_INFO()
  97 
  98 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_field_length, 0, 0, 1)
  99         ZEND_ARG_INFO(0, result)
 100         ZEND_ARG_INFO(0, offset)
 101 ZEND_END_ARG_INFO()
 102 
 103 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_data_seek, 0, 0, 2)
 104         ZEND_ARG_INFO(0, result_identifier)
 105         ZEND_ARG_INFO(0, row_number)
 106 ZEND_END_ARG_INFO()
 107 
 108 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_result, 0, 0, 3)
 109         ZEND_ARG_INFO(0, result)
 110         ZEND_ARG_INFO(0, row)
 111         ZEND_ARG_INFO(0, field)
 112 ZEND_END_ARG_INFO()
 113 
 114 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_min_error_severity, 0, 0, 1)
 115         ZEND_ARG_INFO(0, severity)
 116 ZEND_END_ARG_INFO()
 117 
 118 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_init, 0, 0, 1)
 119         ZEND_ARG_INFO(0, sp_name)
 120         ZEND_ARG_INFO(0, link_identifier)
 121 ZEND_END_ARG_INFO()
 122 
 123 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_bind, 0, 0, 4)
 124         ZEND_ARG_INFO(0, stmt)
 125         ZEND_ARG_INFO(0, param_name)
 126         ZEND_ARG_INFO(1, var)
 127         ZEND_ARG_INFO(0, type)
 128         ZEND_ARG_INFO(0, is_output)
 129         ZEND_ARG_INFO(0, is_null)
 130         ZEND_ARG_INFO(0, maxlen)
 131 ZEND_END_ARG_INFO()
 132 
 133 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_execute, 0, 0, 1)
 134         ZEND_ARG_INFO(0, stmt)
 135         ZEND_ARG_INFO(0, skip_results)
 136 ZEND_END_ARG_INFO()
 137 
 138 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_free_statement, 0, 0, 1)
 139         ZEND_ARG_INFO(0, stmt)
 140 ZEND_END_ARG_INFO()
 141 
 142 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_guid_string, 0, 0, 1)
 143         ZEND_ARG_INFO(0, binary)
 144         ZEND_ARG_INFO(0, short_format)
 145 ZEND_END_ARG_INFO()
 146 /* }}} */
 147 
 148 /* {{{ mssql_functions
 149 */
 150 const zend_function_entry mssql_functions[] = {
 151         PHP_FE(mssql_connect,                           arginfo_mssql_connect)
 152         PHP_FE(mssql_pconnect,                          arginfo_mssql_connect)
 153         PHP_FE(mssql_close,                                     arginfo_mssql_close)
 154         PHP_FE(mssql_select_db,                         arginfo_mssql_select_db)
 155         PHP_FE(mssql_query,                                     arginfo_mssql_query)
 156         PHP_FE(mssql_fetch_batch,                       arginfo_mssql_fetch_batch)
 157         PHP_FE(mssql_rows_affected,                     arginfo_mssql_rows_affected)
 158         PHP_FE(mssql_free_result,                       arginfo_mssql_fetch_batch)
 159         PHP_FE(mssql_get_last_message,          arginfo_mssql_get_last_message)
 160         PHP_FE(mssql_num_rows,                          arginfo_mssql_fetch_batch)
 161         PHP_FE(mssql_num_fields,                        arginfo_mssql_fetch_batch)
 162         PHP_FE(mssql_fetch_field,                       arginfo_mssql_fetch_field)
 163         PHP_FE(mssql_fetch_row,                         arginfo_mssql_fetch_batch)
 164         PHP_FE(mssql_fetch_array,                       arginfo_mssql_fetch_array)
 165         PHP_FE(mssql_fetch_assoc,                       arginfo_mssql_fetch_assoc)
 166         PHP_FE(mssql_fetch_object,                      arginfo_mssql_fetch_batch)
 167         PHP_FE(mssql_field_length,                      arginfo_mssql_field_length)
 168         PHP_FE(mssql_field_name,                        arginfo_mssql_field_length)
 169         PHP_FE(mssql_field_type,                        arginfo_mssql_field_length)
 170         PHP_FE(mssql_data_seek,                         arginfo_mssql_data_seek)
 171         PHP_FE(mssql_field_seek,                        arginfo_mssql_fetch_field)
 172         PHP_FE(mssql_result,                            arginfo_mssql_result)
 173         PHP_FE(mssql_next_result,                       arginfo_mssql_fetch_assoc)
 174         PHP_FE(mssql_min_error_severity,        arginfo_mssql_min_error_severity)
 175         PHP_FE(mssql_min_message_severity,      arginfo_mssql_min_error_severity)
 176         PHP_FE(mssql_init,                                      arginfo_mssql_init)
 177         PHP_FE(mssql_bind,                                      arginfo_mssql_bind)
 178         PHP_FE(mssql_execute,                           arginfo_mssql_execute)
 179         PHP_FE(mssql_free_statement,            arginfo_mssql_free_statement)
 180         PHP_FE(mssql_guid_string,                       arginfo_mssql_guid_string)
 181         PHP_FE_END
 182 };
 183 /* }}} */
 184 
 185 ZEND_DECLARE_MODULE_GLOBALS(mssql)
 186 static PHP_GINIT_FUNCTION(mssql);
 187 
 188 /* {{{ mssql_module_entry
 189 */
 190 zend_module_entry mssql_module_entry = 
 191 {
 192         STANDARD_MODULE_HEADER,
 193         "mssql", 
 194         mssql_functions, 
 195         PHP_MINIT(mssql), 
 196         PHP_MSHUTDOWN(mssql), 
 197         PHP_RINIT(mssql), 
 198         PHP_RSHUTDOWN(mssql), 
 199         PHP_MINFO(mssql), 
 200         NO_VERSION_YET,
 201         PHP_MODULE_GLOBALS(mssql),
 202         PHP_GINIT(mssql),
 203         NULL,
 204         NULL,
 205         STANDARD_MODULE_PROPERTIES_EX
 206 };
 207 /* }}} */
 208 
 209 #ifdef COMPILE_DL_MSSQL
 210 ZEND_GET_MODULE(mssql)
 211 #endif
 212 
 213 #define CHECK_LINK(link) { if (link==-1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "A link to the server could not be established"); RETURN_FALSE; } }
 214 
 215 /* {{{ PHP_INI_DISP
 216 */
 217 static PHP_INI_DISP(display_text_size)
 218 {
 219         char *value;
 220         TSRMLS_FETCH();
 221         
 222     if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 223                 value = ini_entry->orig_value;
 224         } else if (ini_entry->value) {
 225                 value = ini_entry->value;
 226         } else {
 227                 value = NULL;
 228         }
 229 
 230         if (atoi(value) == -1) {
 231                 PUTS("Server default");
 232         } else {
 233                 php_printf("%s", value);
 234         }
 235 }
 236 /* }}} */
 237 
 238 /* {{{ PHP_INI
 239 */
 240 PHP_INI_BEGIN()
 241         STD_PHP_INI_BOOLEAN("mssql.allow_persistent",           "1",    PHP_INI_SYSTEM, OnUpdateBool,   allow_persistent,                       zend_mssql_globals,             mssql_globals)
 242         STD_PHP_INI_ENTRY_EX("mssql.max_persistent",            "-1",   PHP_INI_SYSTEM, OnUpdateLong,   max_persistent,                         zend_mssql_globals,             mssql_globals,  display_link_numbers)
 243         STD_PHP_INI_ENTRY_EX("mssql.max_links",                         "-1",   PHP_INI_SYSTEM, OnUpdateLong,   max_links,                                      zend_mssql_globals,             mssql_globals,  display_link_numbers)
 244         STD_PHP_INI_ENTRY_EX("mssql.min_error_severity",        "10",   PHP_INI_ALL,    OnUpdateLong,   cfg_min_error_severity,         zend_mssql_globals,             mssql_globals,  display_link_numbers)
 245         STD_PHP_INI_ENTRY_EX("mssql.min_message_severity",      "10",   PHP_INI_ALL,    OnUpdateLong,   cfg_min_message_severity,       zend_mssql_globals,             mssql_globals,  display_link_numbers)
 246         /*
 247           mssql.compatAbility_mode (with typo) was used for relatively long time.
 248           Unless it is fixed the old version is also kept for compatibility reasons.
 249         */
 250         STD_PHP_INI_BOOLEAN("mssql.compatability_mode",         "0",    PHP_INI_ALL,    OnUpdateBool,   compatibility_mode,                     zend_mssql_globals,             mssql_globals)
 251         STD_PHP_INI_BOOLEAN("mssql.compatibility_mode",         "0",    PHP_INI_ALL,    OnUpdateBool,   compatibility_mode,                     zend_mssql_globals,             mssql_globals)
 252         STD_PHP_INI_ENTRY_EX("mssql.connect_timeout",           "5",    PHP_INI_ALL,    OnUpdateLong,   connect_timeout,                        zend_mssql_globals,             mssql_globals,  display_link_numbers)
 253         STD_PHP_INI_ENTRY_EX("mssql.timeout",                           "60",   PHP_INI_ALL,    OnUpdateLong,   timeout,                                        zend_mssql_globals,             mssql_globals,  display_link_numbers)
 254         STD_PHP_INI_ENTRY_EX("mssql.textsize",                          "-1",   PHP_INI_ALL,    OnUpdateLong,   textsize,                                       zend_mssql_globals,             mssql_globals,  display_text_size)
 255         STD_PHP_INI_ENTRY_EX("mssql.textlimit",                         "-1",   PHP_INI_ALL,    OnUpdateLong,   textlimit,                                      zend_mssql_globals,             mssql_globals,  display_text_size)
 256         STD_PHP_INI_ENTRY_EX("mssql.batchsize",                         "0",    PHP_INI_ALL,    OnUpdateLong,   batchsize,                                      zend_mssql_globals,             mssql_globals,  display_link_numbers)
 257         STD_PHP_INI_BOOLEAN("mssql.datetimeconvert",            "1",    PHP_INI_ALL,    OnUpdateBool,   datetimeconvert,                        zend_mssql_globals,             mssql_globals)
 258         STD_PHP_INI_BOOLEAN("mssql.secure_connection",          "0",    PHP_INI_SYSTEM, OnUpdateBool,   secure_connection,                      zend_mssql_globals,             mssql_globals)
 259         STD_PHP_INI_ENTRY_EX("mssql.max_procs",                         "-1",   PHP_INI_ALL,    OnUpdateLong,   max_procs,                                      zend_mssql_globals,             mssql_globals,  display_link_numbers)
 260 #ifdef HAVE_FREETDS
 261         STD_PHP_INI_ENTRY("mssql.charset",                                      "",             PHP_INI_ALL,    OnUpdateString, charset,                                        zend_mssql_globals,             mssql_globals)
 262 #endif
 263 PHP_INI_END()
 264 /* }}} */
 265 
 266 /* error handler */
 267 static int php_mssql_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
 268 {
 269         TSRMLS_FETCH();
 270 
 271         if (severity >= MS_SQL_G(min_error_severity)) {
 272                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (severity %d)", dberrstr, severity);
 273         }
 274         return INT_CANCEL;  
 275 }
 276 
 277 /* {{{ php_mssql_message_handler
 278 */
 279 /* message handler */
 280 static int php_mssql_message_handler(DBPROCESS *dbproc, DBINT msgno,int msgstate, int severity,char *msgtext,char *srvname, char *procname,DBUSMALLINT line)
 281 {
 282         TSRMLS_FETCH();
 283 
 284         if (severity >= MS_SQL_G(min_message_severity)) {
 285                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "message: %s (severity %d)", msgtext, severity);
 286         }
 287         if (MS_SQL_G(server_message)) {
 288                 STR_FREE(MS_SQL_G(server_message));
 289                 MS_SQL_G(server_message) = NULL;
 290         }
 291         MS_SQL_G(server_message) = estrdup(msgtext);
 292         return 0;
 293 }
 294 /* }}} */
 295 
 296 /* {{{ _clean_invalid_results
 297 */
 298 static int _clean_invalid_results(zend_rsrc_list_entry *le TSRMLS_DC)
 299 {
 300         if (Z_TYPE_P(le) == le_result) {
 301                 mssql_link *mssql_ptr = ((mssql_result *) le->ptr)->mssql_ptr;
 302                 
 303                 if (!mssql_ptr->valid) {
 304                         return 1;
 305                 }
 306         }
 307         return 0;
 308 }
 309 /* }}} */
 310 
 311 /* {{{ _free_result
 312 */
 313 static void _free_result(mssql_result *result, int free_fields) 
 314 {
 315         int i,j;
 316 
 317         if (result->data) {
 318                 for (i=0; i<result->num_rows; i++) {
 319                         if (result->data[i]) {
 320                                 for (j=0; j<result->num_fields; j++) {
 321                                         zval_dtor(&result->data[i][j]);
 322                                 }
 323                                 efree(result->data[i]);
 324                         }
 325                 }
 326                 efree(result->data);
 327                 result->data = NULL;
 328                 result->blocks_initialized = 0;
 329         }
 330         
 331         if (free_fields && result->fields) {
 332                 for (i=0; i<result->num_fields; i++) {
 333                         STR_FREE(result->fields[i].name);
 334                         STR_FREE(result->fields[i].column_source);
 335                 }
 336                 efree(result->fields);
 337         }
 338 }
 339 /* }}} */
 340 
 341 /* {{{ _free_mssql_statement
 342 */
 343 static void _free_mssql_statement(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 344 {
 345         mssql_statement *statement = (mssql_statement *)rsrc->ptr;
 346 
 347         if (statement->binds) {
 348                 zend_hash_destroy(statement->binds);
 349                 efree(statement->binds);
 350         }
 351         
 352         efree(statement);
 353 }
 354 /* }}} */
 355 
 356 /* {{{ _free_mssql_result
 357 */
 358 static void _free_mssql_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 359 {
 360         mssql_result *result = (mssql_result *)rsrc->ptr;
 361 
 362         _free_result(result, 1);
 363         dbcancel(result->mssql_ptr->link);
 364         efree(result);
 365 }
 366 /* }}} */
 367 
 368 /* {{{ php_mssql_set_defaullt_link
 369 */
 370 static void php_mssql_set_default_link(int id TSRMLS_DC)
 371 {
 372         if (MS_SQL_G(default_link)!=-1) {
 373                 zend_list_delete(MS_SQL_G(default_link));
 374         }
 375         MS_SQL_G(default_link) = id;
 376         zend_list_addref(id);
 377 }
 378 /* }}} */
 379 
 380 /* {{{ _close_mssql_link
 381 */
 382 static void _close_mssql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 383 {
 384         mssql_link *mssql_ptr = (mssql_link *)rsrc->ptr;
 385 
 386         mssql_ptr->valid = 0;
 387         zend_hash_apply(&EG(regular_list),(apply_func_t) _clean_invalid_results TSRMLS_CC);
 388         dbclose(mssql_ptr->link);
 389         dbfreelogin(mssql_ptr->login);
 390         efree(mssql_ptr);
 391         MS_SQL_G(num_links)--;
 392 }
 393 /* }}} */
 394 
 395 /* {{{ _close_mssql_plink
 396 */
 397 static void _close_mssql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 398 {
 399         mssql_link *mssql_ptr = (mssql_link *)rsrc->ptr;
 400 
 401         dbclose(mssql_ptr->link);
 402         dbfreelogin(mssql_ptr->login);
 403         free(mssql_ptr);
 404         MS_SQL_G(num_persistent)--;
 405         MS_SQL_G(num_links)--;
 406 }
 407 /* }}} */
 408 
 409 /* {{{ _mssql_bind_hash_dtor
 410 */
 411 static void _mssql_bind_hash_dtor(void *data)
 412 {
 413         mssql_bind *bind= (mssql_bind *) data;
 414 
 415         zval_ptr_dtor(&(bind->zval));
 416 }
 417 /* }}} */
 418 
 419 /* {{{ PHP_GINIT_FUNCTION
 420 */
 421 static PHP_GINIT_FUNCTION(mssql)
 422 {
 423         long compatibility_mode;
 424 
 425         mssql_globals->num_persistent = 0;
 426         mssql_globals->get_column_content = php_mssql_get_column_content_with_type;
 427         if (cfg_get_long("mssql.compatibility_mode", &compatibility_mode) == SUCCESS) {
 428                 if (compatibility_mode) {
 429                         mssql_globals->get_column_content = php_mssql_get_column_content_without_type;  
 430                 }
 431         }
 432 }
 433 /* }}} */
 434 
 435 /* {{{ PHP_MINIT_FUNCTION
 436 */
 437 PHP_MINIT_FUNCTION(mssql)
 438 {
 439         REGISTER_INI_ENTRIES();
 440 
 441         le_statement = zend_register_list_destructors_ex(_free_mssql_statement, NULL, "mssql statement", module_number);
 442         le_result = zend_register_list_destructors_ex(_free_mssql_result, NULL, "mssql result", module_number);
 443         le_link = zend_register_list_destructors_ex(_close_mssql_link, NULL, "mssql link", module_number);
 444         le_plink = zend_register_list_destructors_ex(NULL, _close_mssql_plink, "mssql link persistent", module_number);
 445         Z_TYPE(mssql_module_entry) = type;
 446 
 447         if (dbinit()==FAIL) {
 448                 return FAILURE;
 449         }
 450 
 451         /* BEGIN MSSQL data types for mssql_bind */
 452         REGISTER_LONG_CONSTANT("MSSQL_ASSOC", MSSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
 453         REGISTER_LONG_CONSTANT("MSSQL_NUM", MSSQL_NUM, CONST_CS | CONST_PERSISTENT);
 454         REGISTER_LONG_CONSTANT("MSSQL_BOTH", MSSQL_BOTH, CONST_CS | CONST_PERSISTENT);
 455 
 456         REGISTER_LONG_CONSTANT("SQLTEXT",SQLTEXT, CONST_CS | CONST_PERSISTENT);
 457         REGISTER_LONG_CONSTANT("SQLVARCHAR",SQLVARCHAR, CONST_CS | CONST_PERSISTENT);
 458         REGISTER_LONG_CONSTANT("SQLCHAR",SQLCHAR, CONST_CS | CONST_PERSISTENT);
 459         REGISTER_LONG_CONSTANT("SQLINT1",SQLINT1, CONST_CS | CONST_PERSISTENT);
 460         REGISTER_LONG_CONSTANT("SQLINT2",SQLINT2, CONST_CS | CONST_PERSISTENT);
 461         REGISTER_LONG_CONSTANT("SQLINT4",SQLINT4, CONST_CS | CONST_PERSISTENT);
 462         REGISTER_LONG_CONSTANT("SQLBIT",SQLBIT, CONST_CS | CONST_PERSISTENT);
 463         REGISTER_LONG_CONSTANT("SQLFLT4",SQLFLT4, CONST_CS | CONST_PERSISTENT);
 464         REGISTER_LONG_CONSTANT("SQLFLT8",SQLFLT8, CONST_CS | CONST_PERSISTENT);
 465         REGISTER_LONG_CONSTANT("SQLFLTN",SQLFLTN, CONST_CS | CONST_PERSISTENT);
 466         /* END MSSQL data types for mssql_bind */
 467 
 468         return SUCCESS;
 469 }
 470 /* }}} */
 471 
 472 /* {{{ PHP_MSHUTDOWN_FUNCTION
 473 */
 474 PHP_MSHUTDOWN_FUNCTION(mssql)
 475 {
 476         UNREGISTER_INI_ENTRIES();
 477 #ifndef HAVE_FREETDS
 478         dbwinexit();
 479 #else
 480         dbexit();
 481 #endif
 482         return SUCCESS;
 483 }
 484 /* }}} */
 485 
 486 /* {{{ PHP_RINIT_FUNCTION
 487 */
 488 PHP_RINIT_FUNCTION(mssql)
 489 {
 490         MS_SQL_G(default_link) = -1;
 491         MS_SQL_G(num_links) = MS_SQL_G(num_persistent);
 492         MS_SQL_G(appname) = estrndup("PHP 5", 5);
 493         MS_SQL_G(server_message) = NULL;
 494         MS_SQL_G(min_error_severity) = MS_SQL_G(cfg_min_error_severity);
 495         MS_SQL_G(min_message_severity) = MS_SQL_G(cfg_min_message_severity);
 496         if (MS_SQL_G(connect_timeout) < 1) MS_SQL_G(connect_timeout) = 1;
 497         if (MS_SQL_G(timeout) < 0) MS_SQL_G(timeout) = 60;
 498         if (MS_SQL_G(max_procs) != -1) {
 499                 dbsetmaxprocs((TDS_SHORT)MS_SQL_G(max_procs));
 500         }
 501 
 502         return SUCCESS;
 503 }
 504 /* }}} */
 505 
 506 /* {{{ PHP_RSHUTDOWN_FUNCTION
 507 */
 508 PHP_RSHUTDOWN_FUNCTION(mssql)
 509 {
 510         STR_FREE(MS_SQL_G(appname));
 511         MS_SQL_G(appname) = NULL;
 512         if (MS_SQL_G(server_message)) {
 513                 STR_FREE(MS_SQL_G(server_message));
 514                 MS_SQL_G(server_message) = NULL;
 515         }
 516         return SUCCESS;
 517 }
 518 /* }}} */
 519 
 520 /* {{{ PHP_MINFO_FUNCTION
 521 */
 522 PHP_MINFO_FUNCTION(mssql)
 523 {
 524         char buf[32];
 525 
 526         php_info_print_table_start();
 527         php_info_print_table_header(2, "MSSQL Support", "enabled");
 528 
 529         snprintf(buf, sizeof(buf), "%ld", MS_SQL_G(num_persistent));
 530         php_info_print_table_row(2, "Active Persistent Links", buf);
 531         snprintf(buf, sizeof(buf), "%ld", MS_SQL_G(num_links));
 532         php_info_print_table_row(2, "Active Links", buf);
 533 
 534         php_info_print_table_row(2, "Library version", MSSQL_VERSION);
 535         php_info_print_table_end();
 536 
 537         DISPLAY_INI_ENTRIES();
 538 
 539 }
 540 /* }}} */
 541 
 542 /* {{{ php_mssql_do_connect
 543 */
 544 static void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
 545 {
 546         char *host = NULL, *user = NULL, *passwd = NULL;
 547         int host_len = 0, user_len = 0, passwd_len = 0;
 548         zend_bool new_link = 0;
 549         char *hashed_details;
 550         int hashed_details_length;
 551         mssql_link mssql, *mssql_ptr;
 552         char buffer[40];
 553 
 554         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sssb", &host, &host_len, &user, &user_len, &passwd, &passwd_len, &new_link) == FAILURE) {
 555                 return;
 556         }
 557 
 558         /* Limit strings to 255 chars to prevent overflow issues in underlying libraries */
 559         if(host_len>255) {
 560                 host[255] = '\0';
 561         }
 562         if(user_len>255) {
 563                 user[255] = '\0';
 564         }
 565         if(passwd_len>255) {
 566                 passwd[255] = '\0';
 567         }
 568 
 569         switch(ZEND_NUM_ARGS())
 570         {
 571                 case 0:
 572                         /* defaults */
 573                         hashed_details_length=5+3;
 574                         hashed_details = (char *) emalloc(hashed_details_length+1);
 575                         strcpy(hashed_details, "mssql___");
 576                         break;
 577                 case 1:
 578                         hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s__", host);
 579                         break;
 580                 case 2:
 581                         hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s_%s_", host, user);
 582                         break;
 583                 case 3:
 584                 case 4:
 585                         hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s_%s_%s", host, user, passwd);
 586                         break;
 587         }
 588 
 589         if (hashed_details == NULL) {
 590                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Out of memory");
 591                 RETURN_FALSE;
 592         }
 593 
 594         dbsetlogintime(MS_SQL_G(connect_timeout));
 595         dbsettime(MS_SQL_G(timeout));
 596 
 597         /* set a DBLOGIN record */      
 598         if ((mssql.login = dblogin()) == NULL) {
 599                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to allocate login record");
 600                 RETURN_FALSE;
 601         }
 602         
 603         DBERRHANDLE(mssql.login, (EHANDLEFUNC) php_mssql_error_handler);
 604         DBMSGHANDLE(mssql.login, (MHANDLEFUNC) php_mssql_message_handler);
 605 
 606 #ifndef HAVE_FREETDS
 607         if (MS_SQL_G(secure_connection)){
 608                 DBSETLSECURE(mssql.login);
 609         }
 610         else {
 611 #endif
 612                 if (user) {
 613                         DBSETLUSER(mssql.login,user);
 614                 }
 615                 if (passwd) {
 616                         DBSETLPWD(mssql.login,passwd);
 617                 }
 618 #ifndef HAVE_FREETDS
 619         }
 620 #endif
 621 
 622 #ifdef HAVE_FREETDS
 623                 if (MS_SQL_G(charset) && strlen(MS_SQL_G(charset))) {
 624                         DBSETLCHARSET(mssql.login, MS_SQL_G(charset));
 625                 }
 626 #endif
 627 
 628         DBSETLAPP(mssql.login,MS_SQL_G(appname));
 629         mssql.valid = 1;
 630 
 631 #ifndef HAVE_FREETDS
 632         DBSETLVERSION(mssql.login, DBVER60);
 633 #endif
 634 /*      DBSETLTIME(mssql.login, TIMEOUT_INFINITE); */
 635 
 636         if (!MS_SQL_G(allow_persistent)) {
 637                 persistent=0;
 638         }
 639         if (persistent) {
 640                 zend_rsrc_list_entry *le;
 641 
 642                 /* try to find if we already have this link in our persistent list */
 643                 if (new_link || zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length + 1, (void **) &le)==FAILURE) {  /* we don't */
 644                         zend_rsrc_list_entry new_le;
 645 
 646                         if (MS_SQL_G(max_links) != -1 && MS_SQL_G(num_links) >= MS_SQL_G(max_links)) {
 647                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MS_SQL_G(num_links));
 648                                 efree(hashed_details);
 649                                 dbfreelogin(mssql.login);
 650                                 RETURN_FALSE;
 651                         }
 652                         if (MS_SQL_G(max_persistent) != -1 && MS_SQL_G(num_persistent) >= MS_SQL_G(max_persistent)) {
 653                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)", MS_SQL_G(num_persistent));
 654                                 efree(hashed_details);
 655                                 dbfreelogin(mssql.login);
 656                                 RETURN_FALSE;
 657                         }
 658                         /* create the link */
 659                         if ((mssql.link = dbopen(mssql.login, host)) == FAIL) {
 660                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to server: %s", (host == NULL ? "" : host));
 661                                 efree(hashed_details);
 662                                 dbfreelogin(mssql.login);
 663                                 RETURN_FALSE;
 664                         }
 665 
 666                         if (DBSETOPT(mssql.link, DBBUFFER, "2")==FAIL) {
 667                                 efree(hashed_details);
 668                                 dbfreelogin(mssql.login);
 669                                 dbclose(mssql.link);
 670                                 RETURN_FALSE;
 671                         }
 672 
 673 #ifndef HAVE_FREETDS
 674                         if (MS_SQL_G(textlimit) != -1) {
 675                                 snprintf(buffer, sizeof(buffer), "%li", MS_SQL_G(textlimit));
 676                                 if (DBSETOPT(mssql.link, DBTEXTLIMIT, buffer)==FAIL) {
 677                                         efree(hashed_details);
 678                                         dbfreelogin(mssql.login);
 679                                         dbclose(mssql.link);
 680                                         RETURN_FALSE;
 681                                 }
 682                         }
 683 #endif
 684                         if (MS_SQL_G(textsize) != -1) {
 685                                 snprintf(buffer, sizeof(buffer), "SET TEXTSIZE %li", MS_SQL_G(textsize));
 686                                 dbcmd(mssql.link, buffer);
 687                                 dbsqlexec(mssql.link);
 688                                 dbresults(mssql.link);
 689                         }
 690 
 691                         /* hash it up */
 692                         mssql_ptr = (mssql_link *) malloc(sizeof(mssql_link));
 693                         if (!mssql_ptr) {
 694                                 efree(hashed_details);
 695                                 dbfreelogin(mssql.login);
 696                                 dbclose(mssql.link);
 697                                 RETURN_FALSE;
 698                         }
 699 
 700                         memcpy(mssql_ptr, &mssql, sizeof(mssql_link));
 701                         Z_TYPE(new_le) = le_plink;
 702                         new_le.ptr = mssql_ptr;
 703                         if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length + 1, &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
 704                                 free(mssql_ptr);
 705                                 efree(hashed_details);
 706                                 dbfreelogin(mssql.login);
 707                                 dbclose(mssql.link);
 708                                 RETURN_FALSE;
 709                         }
 710                         MS_SQL_G(num_persistent)++;
 711                         MS_SQL_G(num_links)++;
 712                 } else {  /* we do */
 713                         if (Z_TYPE_P(le) != le_plink) {
 714 #if BROKEN_MSSQL_PCONNECTS
 715                                 log_error("PHP/MS SQL: Hashed persistent link is not a MS SQL link!",php_rqst->server);
 716 #endif
 717                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hashed persistent link is not a MS SQL link!");
 718                                 efree(hashed_details);
 719                                 RETURN_FALSE;
 720                         }
 721                         
 722                         mssql_ptr = (mssql_link *) le->ptr;
 723                         /* test that the link hasn't died */
 724                         if (DBDEAD(mssql_ptr->link) == TRUE) {
 725                                 dbclose(mssql_ptr->link);
 726 #if BROKEN_MSSQL_PCONNECTS
 727                                 log_error("PHP/MS SQL: Persistent link died, trying to reconnect...",php_rqst->server);
 728 #endif
 729                                 if ((mssql_ptr->link=dbopen(mssql_ptr->login,host))==NULL) {
 730 #if BROKEN_MSSQL_PCONNECTS
 731                                         log_error("PHP/MS SQL: Unable to reconnect!",php_rqst->server);
 732 #endif
 733                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link to server lost, unable to reconnect");
 734                                         zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_length+1);
 735                                         efree(hashed_details);
 736                                         dbfreelogin(mssql_ptr->login);
 737                                         RETURN_FALSE;
 738                                 }
 739 #if BROKEN_MSSQL_PCONNECTS
 740                                 log_error("PHP/MS SQL: Reconnect successful!",php_rqst->server);
 741 #endif
 742                                 if (DBSETOPT(mssql_ptr->link, DBBUFFER, "2")==FAIL) {
 743 #if BROKEN_MSSQL_PCONNECTS
 744                                         log_error("PHP/MS SQL: Unable to set required options",php_rqst->server);
 745 #endif
 746                                         zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_length + 1);
 747                                         efree(hashed_details);
 748                                         dbfreelogin(mssql_ptr->login);
 749                                         dbclose(mssql_ptr->link);
 750                                         RETURN_FALSE;
 751                                 }
 752                         }
 753                 }
 754                 ZEND_REGISTER_RESOURCE(return_value, mssql_ptr, le_plink);
 755         } else { /* non persistent */
 756                 zend_rsrc_list_entry *index_ptr, new_index_ptr;
 757                 
 758                 /* first we check the hash for the hashed_details key.  if it exists,
 759                  * it should point us to the right offset where the actual mssql link sits.
 760                  * if it doesn't, open a new mssql link, add it to the resource list,
 761                  * and add a pointer to it with hashed_details as the key.
 762                  */
 763                 if (!new_link && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length + 1,(void **) &index_ptr)==SUCCESS) {
 764                         int type,link;
 765                         void *ptr;
 766 
 767                         if (Z_TYPE_P(index_ptr) != le_index_ptr) {
 768                                 efree(hashed_details);
 769                                 dbfreelogin(mssql.login);
 770                                 RETURN_FALSE;
 771                         }
 772                         link = (int) index_ptr->ptr;
 773                         ptr = zend_list_find(link,&type);   /* check if the link is still there */
 774                         if (ptr && (type==le_link || type==le_plink)) {
 775                                 zend_list_addref(link);
 776                                 Z_LVAL_P(return_value) = link;
 777                                 php_mssql_set_default_link(link TSRMLS_CC);
 778                                 Z_TYPE_P(return_value) = IS_RESOURCE;
 779                                 dbfreelogin(mssql.login);
 780                                 efree(hashed_details);
 781                                 return;
 782                         } else {
 783                                 zend_hash_del(&EG(regular_list), hashed_details, hashed_details_length + 1);
 784                         }
 785                 }
 786                 if (MS_SQL_G(max_links) != -1 && MS_SQL_G(num_links) >= MS_SQL_G(max_links)) {
 787                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MS_SQL_G(num_links));
 788                         efree(hashed_details);
 789                         dbfreelogin(mssql.login);
 790                         RETURN_FALSE;
 791                 }
 792                 
 793                 if ((mssql.link=dbopen(mssql.login, host))==NULL) {
 794                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to server: %s", (host == NULL ? "" : host));
 795                         efree(hashed_details);
 796                         dbfreelogin(mssql.login);
 797                         RETURN_FALSE;
 798                 }
 799 
 800                 if (DBSETOPT(mssql.link, DBBUFFER,"2")==FAIL) {
 801                         efree(hashed_details);
 802                         dbfreelogin(mssql.login);
 803                         dbclose(mssql.link);
 804                         RETURN_FALSE;
 805                 }
 806 
 807 #ifndef HAVE_FREETDS
 808                 if (MS_SQL_G(textlimit) != -1) {
 809                         snprintf(buffer, sizeof(buffer), "%li", MS_SQL_G(textlimit));
 810                         if (DBSETOPT(mssql.link, DBTEXTLIMIT, buffer)==FAIL) {
 811                                 efree(hashed_details);
 812                                 dbfreelogin(mssql.login);
 813                                 dbclose(mssql.link);
 814                                 RETURN_FALSE;
 815                         }
 816                 }
 817 #endif
 818                 if (MS_SQL_G(textsize) != -1) {
 819                         snprintf(buffer, sizeof(buffer), "SET TEXTSIZE %li", MS_SQL_G(textsize));
 820                         dbcmd(mssql.link, buffer);
 821                         dbsqlexec(mssql.link);
 822                         dbresults(mssql.link);
 823                 }
 824 
 825                 /* add it to the list */
 826                 mssql_ptr = (mssql_link *) emalloc(sizeof(mssql_link));
 827                 memcpy(mssql_ptr, &mssql, sizeof(mssql_link));
 828                 ZEND_REGISTER_RESOURCE(return_value, mssql_ptr, le_link);
 829                 
 830                 /* add it to the hash */
 831                 new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
 832                 Z_TYPE(new_index_ptr) = le_index_ptr;
 833                 if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length + 1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry),NULL)==FAILURE) {
 834                         efree(hashed_details);
 835                         RETURN_FALSE;
 836                 }
 837                 MS_SQL_G(num_links)++;
 838         }
 839         efree(hashed_details);
 840         php_mssql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
 841 }
 842 /* }}} */
 843 
 844 /* {{{ php_mssql_get_default_link
 845 */
 846 static int php_mssql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
 847 {
 848         if (MS_SQL_G(default_link)==-1) { /* no link opened yet, implicitly open one */
 849                 ht = 0;
 850                 php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
 851         }
 852         return MS_SQL_G(default_link);
 853 }
 854 /* }}} */
 855 
 856 /* {{{ proto int mssql_connect([string servername [, string username [, string password [, bool new_link]]]])
 857    Establishes a connection to a MS-SQL server */
 858 PHP_FUNCTION(mssql_connect)
 859 {
 860         php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
 861 }
 862 /* }}} */
 863 
 864 /* {{{ proto int mssql_pconnect([string servername [, string username [, string password [, bool new_link]]]])
 865    Establishes a persistent connection to a MS-SQL server */
 866 PHP_FUNCTION(mssql_pconnect)
 867 {
 868         php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
 869 }
 870 /* }}} */
 871 
 872 /* {{{ proto bool mssql_close([resource conn_id])
 873    Closes a connection to a MS-SQL server */
 874 PHP_FUNCTION(mssql_close)
 875 {
 876         zval *mssql_link_index = NULL;
 877         int id = -1;
 878         mssql_link *mssql_ptr;
 879         
 880         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &mssql_link_index) == FAILURE) {
 881                 return;
 882         }
 883 
 884         if (mssql_link_index == NULL) {
 885                 id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
 886                 CHECK_LINK(id);
 887         }
 888 
 889         ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
 890 
 891         if (mssql_link_index) {
 892                 zend_list_delete(Z_RESVAL_P(mssql_link_index));
 893         } else {
 894                 zend_list_delete(id);
 895         }
 896 
 897         RETURN_TRUE;
 898 }
 899 /* }}} */
 900 
 901 /* {{{ proto bool mssql_select_db(string database_name [, resource conn_id])
 902    Select a MS-SQL database */
 903 PHP_FUNCTION(mssql_select_db)
 904 {
 905         char *db;
 906         zval *mssql_link_index = NULL;
 907         int db_len;
 908         int id = -1;
 909         mssql_link  *mssql_ptr;
 910 
 911         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &db, &db_len, &mssql_link_index) == FAILURE) {
 912                 return;
 913         }
 914 
 915         if (mssql_link_index == NULL) {
 916                 id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
 917                 CHECK_LINK(id);
 918         }
 919 
 920         ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
 921         
 922         if (dbuse(mssql_ptr->link, db)==FAIL) {
 923                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to select database:  %s", db);
 924                 RETURN_FALSE;
 925         } else {
 926                 RETURN_TRUE;
 927         }
 928 }
 929 /* }}} */
 930 
 931 /* {{{ php_mssql_get_column_content_with_type
 932 */
 933 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type  TSRMLS_DC)
 934 {
 935         if (dbdata(mssql_ptr->link,offset) == NULL && dbdatlen(mssql_ptr->link,offset) == 0) {
 936                 ZVAL_NULL(result);
 937                 return;
 938         }
 939 
 940         switch (column_type)
 941         {
 942                 case SQLBIT:
 943                 case SQLINT1:
 944                 case SQLINT2:
 945                 case SQLINT4:
 946                 case SQLINTN: { 
 947                         ZVAL_LONG(result, (long) anyintcol(offset));
 948                         break;
 949                 } 
 950                 case SQLCHAR:
 951                 case SQLVARCHAR:
 952                 case SQLTEXT: {
 953                         int length;
 954                         char *data = charcol(offset);
 955 
 956                         length=dbdatlen(mssql_ptr->link,offset);
 957 #if ilia_0
 958                         while (length>0 && data[length-1] == ' ') { /* nuke trailing whitespace */
 959                                 length--;
 960                         }
 961 #endif
 962                         ZVAL_STRINGL(result, data, length, 1); 
 963                         break;
 964                 }
 965                 case SQLFLT4:
 966                         ZVAL_DOUBLE(result, (double) floatcol4(offset));
 967                         break;
 968                 case SQLMONEY:
 969                 case SQLMONEY4:
 970                 case SQLMONEYN: {
 971                         DBFLT8 res_buf;
 972                         dbconvert(NULL, column_type, dbdata(mssql_ptr->link,offset), 8, SQLFLT8, (LPBYTE)&res_buf, -1);
 973                         ZVAL_DOUBLE(result, res_buf);
 974                         }
 975                         break;
 976                 case SQLFLT8:
 977                         ZVAL_DOUBLE(result, (double) floatcol8(offset));
 978                         break;
 979 #ifdef SQLUNIQUE
 980                 case SQLUNIQUE: {
 981 #else
 982                 case 36: {                      /* FreeTDS hack */
 983 #endif
 984                         char *data = charcol(offset);
 985 
 986                         /* uniqueidentifier is a 16-byte binary number */
 987                         ZVAL_STRINGL(result, data, 16, 1);
 988                         }
 989                         break;
 990                 case SQLVARBINARY:
 991                 case SQLBINARY:
 992                 case SQLIMAGE: {
 993                         int res_length = dbdatlen(mssql_ptr->link, offset);
 994 
 995                         if (!res_length) {
 996                                 ZVAL_NULL(result);
 997                         } else {
 998                                 ZVAL_STRINGL(result, (char *)dbdata(mssql_ptr->link, offset), res_length, 1);
 999                         }
1000                 }
1001                         break;
1002                 case SQLNUMERIC:
1003                 default: {
1004                         if (dbwillconvert(column_type,SQLCHAR)) {
1005                                 char *res_buf;
1006                                 DBDATEREC dateinfo;     
1007                                 int res_length = dbdatlen(mssql_ptr->link,offset);
1008 
1009                                 if (res_length == -1) {
1010                                         res_length = 255;
1011                                 }
1012 
1013                                 if ((column_type != SQLDATETIME && column_type != SQLDATETIM4) || MS_SQL_G(datetimeconvert)) {
1014 
1015                                         switch (column_type) {
1016                                                 case SQLDATETIME :
1017                                                 case SQLDATETIM4 :
1018                                                         res_length += 20;
1019                                                         break;
1020                                                 case SQLMONEY :
1021                                                 case SQLMONEY4 :
1022                                                 case SQLMONEYN :
1023                                                 case SQLDECIMAL :
1024                                                 case SQLNUMERIC :
1025                                                         res_length += 5;
1026                                                 case 127 :
1027                                                         res_length += 20;
1028                                                         break;
1029                                         }
1030 
1031                                         res_buf = (unsigned char *) emalloc(res_length+1);
1032                                         res_length = dbconvert(NULL,coltype(offset),dbdata(mssql_ptr->link,offset), res_length, SQLCHAR,res_buf,-1);
1033                                         res_buf[res_length] = '\0';
1034                                 } else {
1035                                         if (column_type == SQLDATETIM4) {
1036                                                 DBDATETIME temp;
1037 
1038                                                 dbconvert(NULL, SQLDATETIM4, dbdata(mssql_ptr->link,offset), -1, SQLDATETIME, (LPBYTE) &temp, -1);
1039                                                 dbdatecrack(mssql_ptr->link, &dateinfo, &temp);
1040                                         } else {
1041                                                 dbdatecrack(mssql_ptr->link, &dateinfo, (DBDATETIME *) dbdata(mssql_ptr->link,offset));
1042                                         }
1043                         
1044                                         res_length = 19;
1045                                         spprintf(&res_buf, 0, "%d-%02d-%02d %02d:%02d:%02d" , dateinfo.year, dateinfo.month, dateinfo.day, dateinfo.hour, dateinfo.minute, dateinfo.second);
1046                                 }
1047                 
1048                                 ZVAL_STRINGL(result, res_buf, res_length, 0);
1049                         } else {
1050                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d has unknown data type (%d)", offset, coltype(offset));
1051                                 ZVAL_FALSE(result);
1052                         }
1053                 }
1054         }
1055 }
1056 /* }}} */
1057 
1058 /* {{{ php_mssql_get_column_content_without_type
1059 */
1060 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC)
1061 {
1062         if (dbdatlen(mssql_ptr->link,offset) == 0) {
1063                 ZVAL_NULL(result);
1064                 return;
1065         }
1066 
1067         if (column_type == SQLVARBINARY ||
1068                 column_type == SQLBINARY ||
1069                 column_type == SQLIMAGE) {
1070                 DBBINARY *bin;
1071                 unsigned char *res_buf;
1072                 int res_length = dbdatlen(mssql_ptr->link, offset);
1073 
1074                 if (res_length == 0) {
1075                         ZVAL_NULL(result);
1076                         return;
1077                 } else if (res_length < 0) {
1078                         ZVAL_FALSE(result);
1079                         return;
1080                 }
1081 
1082                 res_buf = (unsigned char *) emalloc(res_length+1);
1083                 bin = ((DBBINARY *)dbdata(mssql_ptr->link, offset));
1084                 res_buf[res_length] = '\0';
1085                 memcpy(res_buf, bin, res_length);
1086                 ZVAL_STRINGL(result, res_buf, res_length, 0);
1087         }
1088         else if  (dbwillconvert(coltype(offset),SQLCHAR)) {
1089                 unsigned char *res_buf;
1090                 DBDATEREC dateinfo;     
1091                 int res_length = dbdatlen(mssql_ptr->link,offset);
1092 
1093                 if ((column_type != SQLDATETIME && column_type != SQLDATETIM4) || MS_SQL_G(datetimeconvert)) {
1094 
1095                         switch (column_type) {
1096                                 case SQLDATETIME :
1097                                 case SQLDATETIM4 :
1098                                         res_length += 20;
1099                                         break;
1100                                 case SQLMONEY :
1101                                 case SQLMONEY4 :
1102                                 case SQLMONEYN :
1103                                 case SQLDECIMAL :
1104                                 case SQLNUMERIC :
1105                                         res_length += 5;
1106                                 case 127 :
1107                                         res_length += 20;
1108                                         break;
1109                         }
1110                         
1111                         res_buf = (unsigned char *) emalloc(res_length+1);
1112                         res_length = dbconvert(NULL,coltype(offset),dbdata(mssql_ptr->link,offset), res_length, SQLCHAR, res_buf, -1);
1113                         res_buf[res_length] = '\0';
1114                 } else {
1115                         if (column_type == SQLDATETIM4) {
1116                                 DBDATETIME temp;
1117 
1118                                 dbconvert(NULL, SQLDATETIM4, dbdata(mssql_ptr->link,offset), -1, SQLDATETIME, (LPBYTE) &temp, -1);
1119                                 dbdatecrack(mssql_ptr->link, &dateinfo, &temp);
1120                         } else {
1121                                 dbdatecrack(mssql_ptr->link, &dateinfo, (DBDATETIME *) dbdata(mssql_ptr->link,offset));
1122                         }
1123                         
1124                         res_length = 19;
1125                         spprintf(&res_buf, 0, "%d-%02d-%02d %02d:%02d:%02d" , dateinfo.year, dateinfo.month, dateinfo.day, dateinfo.hour, dateinfo.minute, dateinfo.second);
1126                 }
1127 
1128                 ZVAL_STRINGL(result, res_buf, res_length, 0);
1129         } else {
1130                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d has unknown data type (%d)", offset, coltype(offset));
1131                 ZVAL_FALSE(result);
1132         }
1133 }
1134 /* }}} */
1135 
1136 /* {{{ _mssql_get_sp_result
1137 */
1138 static void _mssql_get_sp_result(mssql_link *mssql_ptr, mssql_statement *statement TSRMLS_DC) 
1139 {
1140         int i, num_rets, type;
1141         char *parameter;
1142         mssql_bind *bind;
1143 
1144         /* Now to fetch RETVAL and OUTPUT values*/
1145         num_rets = dbnumrets(mssql_ptr->link);
1146 
1147         if (num_rets!=0) {
1148                 for (i = 1; i <= num_rets; i++) {
1149                         parameter = (char*)dbretname(mssql_ptr->link, i);
1150                         type = dbrettype(mssql_ptr->link, i);
1151                                                 
1152                         if (statement->binds != NULL) { /*      Maybe a non-parameter sp        */
1153                                 if (zend_hash_find(statement->binds, parameter, strlen(parameter), (void**)&bind)==SUCCESS) {
1154                                         if (!dbretlen(mssql_ptr->link,i)) {
1155                                                 ZVAL_NULL(bind->zval);
1156                                         }
1157                                         else {
1158                                                 switch (type) {
1159                                                         case SQLBIT:
1160                                                         case SQLINT1:
1161                                                         case SQLINT2:
1162                                                         case SQLINT4:
1163                                                                 convert_to_long_ex(&bind->zval);
1164                                                                 /* FIXME this works only on little endian machine !!! */
1165                                                                 Z_LVAL_P(bind->zval) = *((int *)(dbretdata(mssql_ptr->link,i)));
1166                                                                 break;
1167                                 
1168                                                         case SQLFLT4:
1169                                                         case SQLFLT8:
1170                                                         case SQLFLTN:
1171                                                         case SQLMONEY4:
1172                                                         case SQLMONEY:
1173                                                         case SQLMONEYN:
1174                                                                 convert_to_double_ex(&bind->zval);
1175                                                                 Z_DVAL_P(bind->zval) = *((double *)(dbretdata(mssql_ptr->link,i)));
1176                                                                 break;
1177         
1178                                                         case SQLCHAR:
1179                                                         case SQLVARCHAR:
1180                                                         case SQLTEXT:
1181                                                                 convert_to_string_ex(&bind->zval);
1182                                                                 Z_STRLEN_P(bind->zval) = dbretlen(mssql_ptr->link,i);
1183                                                                 Z_STRVAL_P(bind->zval) = estrndup(dbretdata(mssql_ptr->link,i),Z_STRLEN_P(bind->zval));
1184                                                                 break;
1185                                                         /* TODO binary */
1186                                                 }
1187                                         }
1188                                 }
1189                                 else {
1190                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "An output parameter variable was not provided");
1191                                 }
1192                         }
1193                 }
1194         }
1195         if (statement->binds != NULL) { /*      Maybe a non-parameter sp        */
1196                 if (zend_hash_find(statement->binds, "RETVAL", 6, (void**)&bind)==SUCCESS) {
1197                         if (dbhasretstat(mssql_ptr->link)) {
1198                                 convert_to_long_ex(&bind->zval);
1199                                 Z_LVAL_P(bind->zval)=dbretstatus(mssql_ptr->link);
1200                         }
1201                         else {
1202                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "stored procedure has no return value. Nothing was returned into RETVAL");
1203                         }
1204                 }
1205         }
1206 }
1207 /* }}} */
1208 
1209 /* {{{ _mssql_fetch_batch
1210 */
1211 static int _mssql_fetch_batch(mssql_link *mssql_ptr, mssql_result *result, int retvalue TSRMLS_DC) 
1212 {
1213         int i, j = 0;
1214         char computed_buf[16];
1215 
1216         if (!result->have_fields) {
1217                 for (i=0; i<result->num_fields; i++) {
1218                         char *source = NULL;
1219                         char *fname = (char *)dbcolname(mssql_ptr->link,i+1);
1220         
1221                         if (*fname) {
1222                                 result->fields[i].name = estrdup(fname);
1223                         } else {
1224                                 if (j>0) {
1225                                         snprintf(computed_buf,16,"computed%d",j);
1226                                 } else {
1227                                         strcpy(computed_buf,"computed");
1228                                 }
1229                                 result->fields[i].name = estrdup(computed_buf);
1230                                 j++;
1231                         }
1232                         result->fields[i].max_length = dbcollen(mssql_ptr->link,i+1);
1233                         source = (char *)dbcolsource(mssql_ptr->link,i+1);
1234                         if (source) {
1235                                 result->fields[i].column_source = estrdup(source);
1236                         }
1237                         else {
1238                                 result->fields[i].column_source = STR_EMPTY_ALLOC();
1239                         }
1240         
1241                         result->fields[i].type = coltype(i+1);
1242                         /* set numeric flag */
1243                         switch (result->fields[i].type) {
1244                                 case SQLINT1:
1245                                 case SQLINT2:
1246                                 case SQLINT4:
1247                                 case SQLINTN:
1248                                 case SQLFLT4:
1249                                 case SQLFLT8:
1250                                 case SQLNUMERIC:
1251                                 case SQLDECIMAL:
1252                                         result->fields[i].numeric = 1;
1253                                         break;
1254                                 case SQLCHAR:
1255                                 case SQLVARCHAR:
1256                                 case SQLTEXT:
1257                                 default:
1258                                         result->fields[i].numeric = 0;
1259                                         break;
1260                         }
1261                 }
1262                 result->have_fields = 1;
1263         }
1264 
1265         i=0;
1266         if (!result->data) {
1267                 result->data = (zval **) safe_emalloc(sizeof(zval *), MSSQL_ROWS_BLOCK*(++result->blocks_initialized), 0);
1268         }
1269         while (retvalue!=FAIL && retvalue!=NO_MORE_ROWS) {
1270                 result->num_rows++;
1271                 if (result->num_rows > result->blocks_initialized*MSSQL_ROWS_BLOCK) {
1272                         result->data = (zval **) erealloc(result->data,sizeof(zval *)*MSSQL_ROWS_BLOCK*(++result->blocks_initialized));
1273                 }
1274                 result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
1275                 for (j=0; j<result->num_fields; j++) {
1276                         INIT_ZVAL(result->data[i][j]);
1277                         MS_SQL_G(get_column_content(mssql_ptr, j+1, &result->data[i][j], result->fields[j].type TSRMLS_CC));
1278                 }
1279                 if (i<result->batchsize || result->batchsize==0) {
1280                         i++;
1281                         dbclrbuf(mssql_ptr->link,DBLASTROW(mssql_ptr->link)); 
1282                         retvalue=dbnextrow(mssql_ptr->link);
1283                 }
1284                 else
1285                         break;
1286                 result->lastresult = retvalue;
1287         }
1288         if (result->statement && (retvalue == NO_MORE_RESULTS || retvalue == NO_MORE_RPC_RESULTS)) {
1289                 _mssql_get_sp_result(mssql_ptr, result->statement TSRMLS_CC);
1290         }
1291         return i;
1292 }
1293 /* }}} */
1294 
1295 /* {{{ proto int mssql_fetch_batch(resource result_index)
1296    Returns the next batch of records */
1297 PHP_FUNCTION(mssql_fetch_batch)
1298 {
1299         zval *mssql_result_index;
1300         mssql_result *result;
1301         mssql_link *mssql_ptr;
1302 
1303         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1304                 return;
1305         }
1306         
1307         if (Z_RESVAL_P(mssql_result_index) == 0) {
1308                 RETURN_FALSE;
1309         }
1310 
1311         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1312 
1313         mssql_ptr = result->mssql_ptr;
1314         _free_result(result, 0);
1315         result->cur_row=result->num_rows=0;
1316         result->num_rows = _mssql_fetch_batch(mssql_ptr, result, result->lastresult TSRMLS_CC);
1317 
1318         RETURN_LONG(result->num_rows);
1319 }
1320 /* }}} */
1321 
1322 /* {{{ proto resource mssql_query(string query [, resource conn_id [, int batch_size]])
1323    Perform an SQL query on a MS-SQL server database */
1324 PHP_FUNCTION(mssql_query)
1325 {
1326         char *query;
1327         zval *mssql_link_index = NULL;
1328         int query_len, retvalue, batchsize, num_fields;
1329         long zbatchsize = 0;
1330         mssql_link *mssql_ptr;
1331         mssql_result *result;
1332         int id = -1;
1333 
1334         dbsettime(MS_SQL_G(timeout));
1335         batchsize = MS_SQL_G(batchsize);
1336 
1337         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|rl", &query, &query_len, &mssql_link_index, &zbatchsize) == FAILURE) {
1338                 return;
1339         }
1340 
1341         switch(ZEND_NUM_ARGS()) {
1342                 case 1:
1343                         id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1344                         CHECK_LINK(id);
1345                         break;
1346                 case 3:
1347                         batchsize = (int) zbatchsize;
1348                         break;
1349         }
1350 
1351         ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
1352         
1353         if (dbcmd(mssql_ptr->link, query)==FAIL) {
1354                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set query");
1355                 RETURN_FALSE;
1356         }
1357         if (dbsqlexec(mssql_ptr->link)==FAIL || (retvalue = dbresults(mssql_ptr->link))==FAIL) {
1358                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed");
1359                 dbcancel(mssql_ptr->link);
1360                 RETURN_FALSE;
1361         }
1362         
1363         /* Skip results not returning any columns */
1364         while ((num_fields = dbnumcols(mssql_ptr->link)) <= 0 && retvalue == SUCCEED) {
1365                 retvalue = dbresults(mssql_ptr->link);
1366         }
1367 
1368         if (num_fields <= 0) {
1369                 RETURN_TRUE;
1370         }
1371 
1372         retvalue=dbnextrow(mssql_ptr->link);    
1373         if (retvalue==FAIL) {
1374                 dbcancel(mssql_ptr->link);
1375                 RETURN_FALSE;
1376         }
1377 
1378         result = (mssql_result *) emalloc(sizeof(mssql_result));
1379         result->statement = NULL;
1380         result->num_fields = num_fields;
1381         result->blocks_initialized = 1;
1382         
1383         result->batchsize = batchsize;
1384         result->data = NULL;
1385         result->blocks_initialized = 0;
1386         result->mssql_ptr = mssql_ptr;
1387         result->cur_field=result->cur_row=result->num_rows=0;
1388         result->have_fields = 0;
1389 
1390         result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), result->num_fields, 0);
1391         result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
1392         
1393         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1394 }
1395 /* }}} */
1396 
1397 /* {{{ proto int mssql_rows_affected(resource conn_id)
1398    Returns the number of records affected by the query */
1399 PHP_FUNCTION(mssql_rows_affected)
1400 {
1401         zval *mssql_link_index;
1402         mssql_link *mssql_ptr;
1403 
1404         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_link_index) == FAILURE) {
1405                 return;
1406         }
1407         
1408         ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, -1, "MS SQL-Link", le_link, le_plink);
1409 
1410         RETURN_LONG(DBCOUNT(mssql_ptr->link));
1411 }
1412 /* }}} */
1413 
1414 /* {{{ proto bool mssql_free_result(resource result_index)
1415    Free a MS-SQL result index */
1416 PHP_FUNCTION(mssql_free_result)
1417 {
1418         zval *mssql_result_index;
1419         mssql_result *result;
1420         int retvalue;
1421         
1422         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1423                 return;
1424         }
1425         
1426         if (Z_RESVAL_P(mssql_result_index) == 0) {
1427                 RETURN_FALSE;
1428         }
1429 
1430         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1431         /* Release remaining results */
1432         do {
1433                 dbcanquery(result->mssql_ptr->link);
1434                 retvalue = dbresults(result->mssql_ptr->link);
1435         } while (retvalue == SUCCEED);
1436 
1437         zend_list_delete(Z_RESVAL_P(mssql_result_index));
1438         RETURN_TRUE;
1439 }
1440 /* }}} */
1441 
1442 /* {{{ proto string mssql_get_last_message(void)
1443    Gets the last message from the MS-SQL server */
1444 PHP_FUNCTION(mssql_get_last_message)
1445 {
1446         if (zend_parse_parameters_none() == FAILURE) {
1447                 return;
1448         }
1449 
1450         if (MS_SQL_G(server_message)) {
1451                 RETURN_STRING(MS_SQL_G(server_message),1);
1452         } else {
1453                 RETURN_STRING("",1);
1454         }
1455 }
1456 /* }}} */
1457 
1458 /* {{{ proto int mssql_num_rows(resource mssql_result_index)
1459    Returns the number of rows fetched in from the result id specified */
1460 PHP_FUNCTION(mssql_num_rows)
1461 {
1462         zval *mssql_result_index;
1463         mssql_result *result;
1464 
1465         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1466                 return;
1467         }
1468 
1469         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1470 
1471         RETURN_LONG(result->num_rows);
1472 }
1473 /* }}} */
1474 
1475 /* {{{ proto int mssql_num_fields(resource mssql_result_index)
1476    Returns the number of fields fetched in from the result id specified */
1477 PHP_FUNCTION(mssql_num_fields)
1478 {
1479         zval *mssql_result_index;
1480         mssql_result *result;
1481         
1482         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1483                 return;
1484         }
1485         
1486         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1487 
1488         RETURN_LONG(result->num_fields);
1489 }
1490 /* }}} */
1491 
1492 /* {{{ php_mssql_fetch_hash
1493 */
1494 static void php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1495 {
1496         zval *mssql_result_index;
1497         mssql_result *result;
1498         int i;
1499         long resulttype = 0;
1500 
1501         switch (result_type) {
1502                 case MSSQL_NUM:
1503                 case MSSQL_ASSOC:
1504                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1505                                 return;
1506                         }
1507                         break;
1508                 case MSSQL_BOTH:
1509                         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &resulttype) == FAILURE) {
1510                                 return;
1511                         }
1512                         result_type = (resulttype > 0 && (resulttype & MSSQL_BOTH)) ? resulttype : result_type;
1513                         break;
1514                 default:
1515                         return;
1516         }
1517 
1518         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1519 
1520         if (MS_SQL_G(server_message)) {
1521                 STR_FREE(MS_SQL_G(server_message));
1522                 MS_SQL_G(server_message) = NULL;
1523         }
1524 
1525         if (result->cur_row >= result->num_rows) {
1526                 RETURN_FALSE;
1527         }
1528         
1529         array_init(return_value);
1530         
1531         for (i=0; i<result->num_fields; i++) {
1532                 if (Z_TYPE(result->data[result->cur_row][i]) != IS_NULL) {
1533                         char *data;
1534                         int data_len;
1535 
1536                         if (Z_TYPE(result->data[result->cur_row][i]) == IS_STRING) {
1537                                 data = Z_STRVAL(result->data[result->cur_row][i]);
1538                                 data_len = Z_STRLEN(result->data[result->cur_row][i]);
1539 
1540                                 if (result_type & MSSQL_NUM) {
1541                                         add_index_stringl(return_value, i, data, data_len, 1);
1542                                 }
1543                                 
1544                                 if (result_type & MSSQL_ASSOC) {
1545                                         add_assoc_stringl(return_value, result->fields[i].name, data, data_len, 1);
1546                                 }
1547                         }
1548                         else if (Z_TYPE(result->data[result->cur_row][i]) == IS_LONG) {
1549                                 if (result_type & MSSQL_NUM)
1550                                         add_index_long(return_value, i, Z_LVAL(result->data[result->cur_row][i]));
1551                                 
1552                                 if (result_type & MSSQL_ASSOC)
1553                                         add_assoc_long(return_value, result->fields[i].name, Z_LVAL(result->data[result->cur_row][i]));
1554                         }
1555                         else if (Z_TYPE(result->data[result->cur_row][i]) == IS_DOUBLE) {
1556                                 if (result_type & MSSQL_NUM)
1557                                         add_index_double(return_value, i, Z_DVAL(result->data[result->cur_row][i]));
1558                                 
1559                                 if (result_type & MSSQL_ASSOC)
1560                                         add_assoc_double(return_value, result->fields[i].name, Z_DVAL(result->data[result->cur_row][i]));
1561                         }
1562                 }
1563                 else
1564                 {
1565                         if (result_type & MSSQL_NUM)
1566                                 add_index_null(return_value, i);
1567                         if (result_type & MSSQL_ASSOC)
1568                                 add_assoc_null(return_value, result->fields[i].name);
1569                 }
1570         }
1571         result->cur_row++;
1572 }
1573 /* }}} */
1574 
1575 /* {{{ proto array mssql_fetch_row(resource result_id)
1576    Returns an array of the current row in the result set specified by result_id */
1577 PHP_FUNCTION(mssql_fetch_row)
1578 {
1579         php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_NUM);
1580 }
1581 /* }}} */
1582 
1583 /* {{{ proto object mssql_fetch_object(resource result_id)
1584    Returns a pseudo-object of the current row in the result set specified by result_id */
1585 PHP_FUNCTION(mssql_fetch_object)
1586 {
1587         php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1588         if (Z_TYPE_P(return_value)==IS_ARRAY) {
1589                 object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1590         }
1591 }
1592 /* }}} */
1593 
1594 /* {{{ proto array mssql_fetch_array(resource result_id [, int result_type])
1595    Returns an associative array of the current row in the result set specified by result_id */
1596 PHP_FUNCTION(mssql_fetch_array)
1597 {
1598         php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_BOTH);
1599 }
1600 /* }}} */
1601 
1602 /* {{{ proto array mssql_fetch_assoc(resource result_id)
1603    Returns an associative array of the current row in the result set specified by result_id */
1604 PHP_FUNCTION(mssql_fetch_assoc)
1605 {
1606         php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1607 }
1608 /* }}} */
1609 
1610 /* {{{ proto bool mssql_data_seek(resource result_id, int offset)
1611    Moves the internal row pointer of the MS-SQL result associated with the specified result identifier to pointer to the specified row number */
1612 PHP_FUNCTION(mssql_data_seek)
1613 {
1614         zval *mssql_result_index;
1615         long offset;
1616         mssql_result *result;
1617 
1618         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &offset) == FAILURE) {
1619                 return;
1620         }
1621         
1622         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1623 
1624         if (offset < 0 || offset >= result->num_rows) {
1625                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset");
1626                 RETURN_FALSE;
1627         }
1628         
1629         result->cur_row = offset;
1630         RETURN_TRUE;
1631 }
1632 /* }}} */
1633 
1634 /* {{{ php_mssql_get_field_name
1635 */
1636 static char *php_mssql_get_field_name(int type)
1637 {
1638         switch (type) {
1639                 case SQLBINARY:
1640                 case SQLVARBINARY:
1641                         return "blob";
1642                         break;
1643                 case SQLCHAR:
1644                 case SQLVARCHAR:
1645                         return "char";
1646                         break;
1647                 case SQLTEXT:
1648                         return "text";
1649                         break;
1650                 case SQLDATETIME:
1651                 case SQLDATETIM4:
1652                 case SQLDATETIMN:
1653                         return "datetime";
1654                         break;
1655                 case SQLDECIMAL:
1656                 case SQLFLT4:
1657                 case SQLFLT8:
1658                 case SQLFLTN:
1659                         return "real";
1660                         break;
1661                 case SQLINT1:
1662                 case SQLINT2:
1663                 case SQLINT4:
1664                 case SQLINTN:
1665                         return "int";
1666                         break;
1667                 case SQLNUMERIC:
1668                         return "numeric";
1669                         break;
1670                 case SQLMONEY:
1671                 case SQLMONEY4:
1672                 case SQLMONEYN:
1673                         return "money";
1674                         break;
1675                 case SQLBIT:
1676                         return "bit";
1677                         break;
1678                 case SQLIMAGE:
1679                         return "image";
1680                         break;
1681 #ifdef SQLUNIQUE
1682                 case SQLUNIQUE:
1683                         return "uniqueidentifier";
1684                         break;
1685 #endif
1686                 default:
1687                         return "unknown";
1688                         break;
1689         }
1690 }
1691 /* }}} */
1692 
1693 /* {{{ proto object mssql_fetch_field(resource result_id [, int offset])
1694    Gets information about certain fields in a query result */
1695 PHP_FUNCTION(mssql_fetch_field)
1696 {
1697         zval *mssql_result_index;
1698         long field_offset = -1;
1699         mssql_result *result;
1700 
1701         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1702                 return;
1703         }
1704 
1705         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1706         
1707         if (field_offset==-1) {
1708                 field_offset = result->cur_field;
1709                 result->cur_field++;
1710         }
1711         
1712         if (field_offset<0 || field_offset >= result->num_fields) {
1713                 if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1714                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1715                 }
1716                 RETURN_FALSE;
1717         }
1718 
1719         object_init(return_value);
1720 
1721         add_property_string(return_value, "name",result->fields[field_offset].name, 1);
1722         add_property_long(return_value, "max_length",result->fields[field_offset].max_length);
1723         add_property_string(return_value, "column_source",result->fields[field_offset].column_source, 1);
1724         add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
1725         add_property_string(return_value, "type", php_mssql_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
1726 }
1727 /* }}} */
1728 
1729 /* {{{ proto int mssql_field_length(resource result_id [, int offset])
1730    Get the length of a MS-SQL field */
1731 PHP_FUNCTION(mssql_field_length)
1732 {
1733         zval *mssql_result_index;
1734         long field_offset = -1;
1735         mssql_result *result;
1736 
1737         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1738                 return;
1739         }
1740         
1741         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1742         
1743         if (field_offset==-1) {
1744                 field_offset = result->cur_field;
1745                 result->cur_field++;
1746         }
1747         
1748         if (field_offset<0 || field_offset >= result->num_fields) {
1749                 if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1750                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1751                 }
1752                 RETURN_FALSE;
1753         }
1754 
1755         RETURN_LONG(result->fields[field_offset].max_length);
1756 }
1757 /* }}} */
1758 
1759 /* {{{ proto string mssql_field_name(resource result_id [, int offset])
1760    Returns the name of the field given by offset in the result set given by result_id */
1761 PHP_FUNCTION(mssql_field_name)
1762 {
1763         zval *mssql_result_index;
1764         long field_offset = -1;
1765         mssql_result *result;
1766 
1767         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1768                 return;
1769         }
1770         
1771         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1772         
1773         if (field_offset==-1) {
1774                 field_offset = result->cur_field;
1775                 result->cur_field++;
1776         }
1777         
1778         if (field_offset<0 || field_offset >= result->num_fields) {
1779                 if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1780                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1781                 }
1782                 RETURN_FALSE;
1783         }
1784 
1785         RETURN_STRINGL(result->fields[field_offset].name, strlen(result->fields[field_offset].name), 1);
1786 }
1787 /* }}} */
1788 
1789 /* {{{ proto string mssql_field_type(resource result_id [, int offset])
1790    Returns the type of a field */
1791 PHP_FUNCTION(mssql_field_type)
1792 {
1793         zval *mssql_result_index;
1794         long field_offset = -1;
1795         mssql_result *result;
1796 
1797         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1798                 return;
1799         }
1800         
1801         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1802         
1803         if (field_offset==-1) {
1804                 field_offset = result->cur_field;
1805                 result->cur_field++;
1806         }
1807         
1808         if (field_offset<0 || field_offset >= result->num_fields) {
1809                 if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1810                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1811                 }
1812                 RETURN_FALSE;
1813         }
1814 
1815         RETURN_STRINGL(php_mssql_get_field_name(Z_TYPE(result->fields[field_offset])), strlen(php_mssql_get_field_name(Z_TYPE(result->fields[field_offset]))), 1);
1816 }
1817 /* }}} */
1818 
1819 /* {{{ proto bool mssql_field_seek(resource result_id, int offset)
1820    Seeks to the specified field offset */
1821 PHP_FUNCTION(mssql_field_seek)
1822 {
1823         zval *mssql_result_index;
1824         long field_offset;
1825         mssql_result *result;
1826 
1827         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &field_offset) == FAILURE) {
1828                 return;
1829         }
1830         
1831         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1832         
1833         if (field_offset<0 || field_offset >= result->num_fields) {
1834                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1835                 RETURN_FALSE;
1836         }
1837 
1838         result->cur_field = field_offset;
1839         RETURN_TRUE;
1840 }
1841 /* }}} */
1842 
1843 /* {{{ proto string mssql_result(resource result_id, int row, mixed field)
1844    Returns the contents of one cell from a MS-SQL result set */
1845 PHP_FUNCTION(mssql_result)
1846 {
1847         zval **field, *mssql_result_index;
1848         long row;
1849         int field_offset=0;
1850         mssql_result *result;
1851 
1852         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &mssql_result_index, &row, &field) == FAILURE) {
1853                 return;
1854         }
1855 
1856         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1857 
1858         if (row < 0 || row >= result->num_rows) {
1859                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset (%ld)", row);
1860                 RETURN_FALSE;
1861         }
1862 
1863         switch(Z_TYPE_PP(field)) {
1864                 case IS_STRING: {
1865                         int i;
1866 
1867                         for (i=0; i<result->num_fields; i++) {
1868                                 if (!strcasecmp(result->fields[i].name, Z_STRVAL_PP(field))) {
1869                                         field_offset = i;
1870                                         break;
1871                                 }
1872                         }
1873                         if (i>=result->num_fields) { /* no match found */
1874                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s field not found in result", Z_STRVAL_PP(field));
1875                                 RETURN_FALSE;
1876                         }
1877                         break;
1878                 }
1879                 default:
1880                         convert_to_long_ex(field);
1881                         field_offset = Z_LVAL_PP(field);
1882                         if (field_offset<0 || field_offset>=result->num_fields) {
1883                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
1884                                 RETURN_FALSE;
1885                         }
1886                         break;
1887         }
1888 
1889         *return_value = result->data[row][field_offset];
1890         zval_copy_ctor(return_value);
1891 }
1892 /* }}} */
1893 
1894 /* {{{ proto bool mssql_next_result(resource result_id)
1895    Move the internal result pointer to the next result */
1896 PHP_FUNCTION(mssql_next_result)
1897 {
1898         zval *mssql_result_index;
1899         int retvalue;
1900         mssql_result *result;
1901         mssql_link *mssql_ptr;
1902 
1903         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1904                 return;
1905         }
1906 
1907         ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);       
1908 
1909         mssql_ptr = result->mssql_ptr;
1910         retvalue = dbresults(mssql_ptr->link);
1911 
1912         while (dbnumcols(mssql_ptr->link) <= 0 && retvalue == SUCCEED) {
1913                 retvalue = dbresults(mssql_ptr->link);
1914         }
1915 
1916         if (retvalue == FAIL) {
1917                 RETURN_FALSE;
1918         }
1919         else if (retvalue == NO_MORE_RESULTS || retvalue == NO_MORE_RPC_RESULTS) {
1920                 if (result->statement) {
1921                         _mssql_get_sp_result(mssql_ptr, result->statement TSRMLS_CC);
1922                 }
1923                 RETURN_FALSE;
1924         }
1925         else {
1926                 _free_result(result, 1);
1927                 result->cur_row=result->num_fields=result->num_rows=0;
1928                 dbclrbuf(mssql_ptr->link,DBLASTROW(mssql_ptr->link));
1929                 retvalue = dbnextrow(mssql_ptr->link);
1930 
1931                 result->num_fields = dbnumcols(mssql_ptr->link);
1932                 result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), result->num_fields, 0);
1933                 result->have_fields = 0;
1934                 result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
1935                 RETURN_TRUE;
1936         }
1937 
1938 }
1939 /* }}} */
1940 
1941 
1942 /* {{{ proto void mssql_min_error_severity(int severity)
1943    Sets the lower error severity */
1944 PHP_FUNCTION(mssql_min_error_severity)
1945 {
1946         long severity;
1947 
1948         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1949                 return;
1950         }
1951 
1952         MS_SQL_G(min_error_severity) = severity;
1953 }
1954 
1955 /* }}} */
1956 
1957 /* {{{ proto void mssql_min_message_severity(int severity)
1958    Sets the lower message severity */
1959 PHP_FUNCTION(mssql_min_message_severity)
1960 {
1961         long severity;
1962         
1963         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1964                 return;
1965         }
1966 
1967         MS_SQL_G(min_message_severity) = severity;
1968 }
1969 /* }}} */
1970 
1971 /* {{{ proto int mssql_init(string sp_name [, resource conn_id])
1972    Initializes a stored procedure or a remote stored procedure  */
1973 PHP_FUNCTION(mssql_init)
1974 {
1975         char *sp_name;
1976         int sp_name_len;
1977         zval *mssql_link_index = NULL;
1978         mssql_link *mssql_ptr;
1979         mssql_statement *statement;
1980         int id = -1;
1981         
1982         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &sp_name, &sp_name_len, &mssql_link_index) == FAILURE) {
1983                 return;
1984         }
1985 
1986         if (mssql_link_index == NULL) {
1987                 id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1988                 CHECK_LINK(id);
1989         }
1990 
1991         ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
1992         
1993         if (dbrpcinit(mssql_ptr->link, sp_name,0)==FAIL) {
1994                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to init stored procedure");
1995                 RETURN_FALSE;
1996         }
1997 
1998         statement=NULL;
1999         statement = ecalloc(1,sizeof(mssql_statement));
2000         statement->link = mssql_ptr;
2001         statement->executed=FALSE;
2002 
2003         statement->id = zend_list_insert(statement,le_statement TSRMLS_CC);
2004         
2005         RETURN_RESOURCE(statement->id);
2006 }
2007 /* }}} */
2008 
2009 /* {{{ proto bool mssql_bind(resource stmt, string param_name, mixed var, int type [, bool is_output [, bool is_null [, int maxlen]]])
2010    Adds a parameter to a stored procedure or a remote stored procedure  */
2011 PHP_FUNCTION(mssql_bind)
2012 {
2013         char *param_name;
2014         int param_name_len, datalen;
2015         int status = 0;
2016         long type = 0, maxlen = -1;
2017         zval *stmt, **var;
2018         zend_bool is_output = 0, is_null = 0;
2019         mssql_link *mssql_ptr;
2020         mssql_statement *statement;
2021         mssql_bind bind,*bindp;
2022         LPBYTE value = NULL;
2023 
2024         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZl|bbl", &stmt, &param_name, &param_name_len, &var, &type, &is_output, &is_null, &maxlen) == FAILURE) {
2025                 return;
2026         }
2027 
2028         if (ZEND_NUM_ARGS() == 7 && !is_output) {
2029                 maxlen = -1;
2030         }
2031         
2032         ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2033 
2034         if (statement==NULL) {
2035                 RETURN_FALSE;
2036         }
2037         mssql_ptr=statement->link;
2038 
2039         /* modify datalen and maxlen according to dbrpcparam documentation */
2040         if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) ) {       /* variable-length type */
2041                 if (is_null) {
2042                         maxlen=0;
2043                         datalen=0;
2044                 } else {
2045                         convert_to_string_ex(var);
2046                         datalen=Z_STRLEN_PP(var);
2047                         value=(LPBYTE)Z_STRVAL_PP(var);
2048                 }
2049         } else {
2050                 /* fixed-length type */
2051                 if (is_null)    {
2052                         datalen=0;
2053                 } else {
2054                         datalen=-1;
2055                 }
2056                 maxlen=-1;
2057 
2058                 switch (type) {
2059                         case SQLFLT4:
2060                         case SQLFLT8:
2061                         case SQLFLTN:
2062                                 convert_to_double_ex(var);
2063                                 value=(LPBYTE)(&Z_DVAL_PP(var));
2064                                 break;
2065 
2066                         case SQLBIT:
2067                         case SQLINT1:
2068                         case SQLINT2:
2069                         case SQLINT4:
2070                                 convert_to_long_ex(var);
2071                                 value=(LPBYTE)(&Z_LVAL_PP(var));
2072                                 break;
2073 
2074                         default:
2075                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported type");
2076                                 RETURN_FALSE;
2077                                 break;
2078                 }
2079         }
2080         
2081         if (is_output) {
2082                 status=DBRPCRETURN;
2083         }
2084         
2085         /* hashtable of binds */
2086         if (! statement->binds) {
2087                 ALLOC_HASHTABLE(statement->binds);
2088                 zend_hash_init(statement->binds, 13, NULL, _mssql_bind_hash_dtor, 0);
2089         }
2090 
2091         if (zend_hash_exists(statement->binds, param_name, param_name_len)) {
2092                 RETURN_FALSE;
2093         }
2094         else {
2095                 memset((void*)&bind,0,sizeof(mssql_bind));
2096                 zend_hash_add(statement->binds, param_name, param_name_len, &bind, sizeof(mssql_bind), (void **)&bindp);
2097                 if( NULL == bindp ) RETURN_FALSE;
2098                 bindp->zval=*var;
2099                 zval_add_ref(var);
2100         
2101                 /* no call to dbrpcparam if RETVAL */
2102                 if ( strcmp("RETVAL", param_name)!=0 ) {                                                
2103                         if (dbrpcparam(mssql_ptr->link, param_name, (BYTE)status, type, maxlen, datalen, (LPBYTE)value)==FAIL) {
2104                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set parameter");
2105                                 RETURN_FALSE;
2106                         }
2107                 }
2108         }
2109 
2110         RETURN_TRUE;
2111 }
2112 /* }}} */
2113 
2114 /* {{{ proto mixed mssql_execute(resource stmt [, bool skip_results = false])
2115    Executes a stored procedure on a MS-SQL server database */
2116 PHP_FUNCTION(mssql_execute)
2117 {
2118         zval *stmt;
2119         zend_bool skip_results = 0;
2120         int retvalue, retval_results;
2121         mssql_link *mssql_ptr;
2122         mssql_statement *statement;
2123         mssql_result *result;
2124         int num_fields;
2125         int batchsize;
2126         int exec_retval;
2127 
2128         batchsize = MS_SQL_G(batchsize);
2129 
2130         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &stmt, &skip_results) == FAILURE) {
2131                 return;
2132         }
2133 
2134         ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2135 
2136         mssql_ptr=statement->link;
2137         exec_retval = dbrpcexec(mssql_ptr->link);
2138 
2139         if (exec_retval == FAIL || dbsqlok(mssql_ptr->link) == FAIL) {
2140                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "stored procedure execution failed");
2141 
2142                 if (exec_retval == FAIL) {
2143                         dbcancel(mssql_ptr->link);
2144                 }
2145 
2146                 RETURN_FALSE;
2147         }
2148 
2149         retval_results=dbresults(mssql_ptr->link);
2150 
2151         if (retval_results==FAIL) {
2152                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not retrieve results");
2153                 dbcancel(mssql_ptr->link);
2154                 RETURN_FALSE;
2155         }
2156 
2157         /* The following is just like mssql_query, fetch all rows from the first result 
2158          *      set into the row buffer. 
2159          */
2160         result=NULL;
2161         if (retval_results == SUCCEED) {
2162                 if (skip_results) {
2163                         do {
2164                                 dbcanquery(mssql_ptr->link);
2165                                 retval_results = dbresults(mssql_ptr->link);
2166                         } while (retval_results == SUCCEED);
2167                 }
2168                 else {
2169                         /* Skip results not returning any columns */
2170                         while ((num_fields = dbnumcols(mssql_ptr->link)) <= 0 && retval_results == SUCCEED) {
2171                                 retval_results = dbresults(mssql_ptr->link);
2172                         }
2173                         if ((num_fields = dbnumcols(mssql_ptr->link)) > 0) {
2174                                 retvalue = dbnextrow(mssql_ptr->link);
2175                                 result = (mssql_result *) emalloc(sizeof(mssql_result));
2176                                 result->batchsize = batchsize;
2177                                 result->blocks_initialized = 1;
2178                                 result->data = (zval **) safe_emalloc(sizeof(zval *), MSSQL_ROWS_BLOCK, 0);
2179                                 result->mssql_ptr = mssql_ptr;
2180                                 result->cur_field=result->cur_row=result->num_rows=0;
2181                                 result->num_fields = num_fields;
2182                                 result->have_fields = 0;
2183 
2184                                 result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), num_fields, 0);
2185                                 result->statement = statement;
2186                                 result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
2187                         }
2188                 }
2189         }
2190         if (retval_results == NO_MORE_RESULTS || retval_results == NO_MORE_RPC_RESULTS) {
2191                 _mssql_get_sp_result(mssql_ptr, statement TSRMLS_CC);
2192         }
2193         
2194         if (result==NULL) {
2195                 RETURN_TRUE;    /* no recordset returned ...*/
2196         }
2197         else {
2198                 ZEND_REGISTER_RESOURCE(return_value, result, le_result);
2199         }
2200 }
2201 /* }}} */
2202 
2203 /* {{{ proto bool mssql_free_statement(resource result_index)
2204    Free a MS-SQL statement index */
2205 PHP_FUNCTION(mssql_free_statement)
2206 {
2207         zval *mssql_statement_index;
2208         mssql_statement *statement;
2209         int retvalue;
2210 
2211         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_statement_index) == FAILURE) {
2212                 return;
2213         }
2214         
2215         if (Z_RESVAL_P(mssql_statement_index) == 0) {
2216                 RETURN_FALSE;
2217         }
2218 
2219         ZEND_FETCH_RESOURCE(statement, mssql_statement *, &mssql_statement_index, -1, "MS SQL-statement", le_statement);        
2220         /* Release remaining results */
2221         do {
2222                 dbcanquery(statement->link->link);
2223                 retvalue = dbresults(statement->link->link);
2224         } while (retvalue == SUCCEED);
2225 
2226         zend_list_delete(Z_RESVAL_P(mssql_statement_index));
2227         RETURN_TRUE;
2228 }
2229 /* }}} */
2230 
2231 /* {{{ proto string mssql_guid_string(string binary [,bool short_format])
2232    Converts a 16 byte binary GUID to a string  */
2233 PHP_FUNCTION(mssql_guid_string)
2234 {
2235         char *binary;
2236         int binary_len;
2237         zend_bool sf = 0;
2238         char buffer[32+1];
2239         char buffer2[36+1];
2240 
2241         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &binary, &binary_len, &sf) == FAILURE) {
2242                 return;
2243         }
2244 
2245         dbconvert(NULL, SQLBINARY, (BYTE*) binary, MIN(16, binary_len), SQLCHAR, buffer, -1);
2246 
2247         if (sf) {
2248                 php_strtoupper(buffer, 32);
2249                 RETURN_STRING(buffer, 1);
2250         }
2251         else {
2252                 int i;
2253                 /* FIXME this works only on little endian machine */
2254                 for (i=0; i<4; i++) {
2255                         buffer2[2*i] = buffer[6-2*i];
2256                         buffer2[2*i+1] = buffer[7-2*i];
2257                 }
2258                 buffer2[8] = '-';
2259                 for (i=0; i<2; i++) {
2260                         buffer2[9+2*i] = buffer[10-2*i];
2261                         buffer2[10+2*i] = buffer[11-2*i];
2262                 }
2263                 buffer2[13] = '-';
2264                 for (i=0; i<2; i++) {
2265                         buffer2[14+2*i] = buffer[14-2*i];
2266                         buffer2[15+2*i] = buffer[15-2*i];
2267                 }
2268                 buffer2[18] = '-';
2269                 for (i=0; i<4; i++) {
2270                         buffer2[19+i] = buffer[16+i];
2271                 }
2272                 buffer2[23] = '-';
2273                 for (i=0; i<12; i++) {
2274                         buffer2[24+i] = buffer[20+i];
2275                 }
2276                 buffer2[36] = 0;
2277 
2278                 php_strtoupper(buffer2, 36);
2279                 RETURN_STRING(buffer2, 1);
2280         }
2281 }
2282 /* }}} */
2283 
2284 #endif

/* [<][>][^][v][top][bottom][index][help] */