root/ext/odbc/php_odbc.c

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

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. safe_odbc_disconnect
  3. _close_odbc_conn
  4. _close_odbc_pconn
  5. PHP_INI_DISP
  6. PHP_INI_DISP
  7. PHP_INI_DISP
  8. PHP_INI_DISP
  9. PHP_INI_DISP
  10. PHP_INI_BEGIN
  11. PHP_MINIT_FUNCTION
  12. PHP_RINIT_FUNCTION
  13. PHP_RSHUTDOWN_FUNCTION
  14. PHP_MSHUTDOWN_FUNCTION
  15. PHP_MINFO_FUNCTION
  16. odbc_sql_error
  17. php_odbc_fetch_attribs
  18. odbc_bindcols
  19. odbc_transact
  20. _close_pconn_with_id
  21. odbc_column_lengths
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. php_odbc_fetch_hash
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. odbc_sqlconnect
  42. odbc_do_connect
  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_odbc_lasterror
  56. PHP_FUNCTION
  57. PHP_FUNCTION
  58. PHP_FUNCTION
  59. PHP_FUNCTION
  60. PHP_FUNCTION
  61. PHP_FUNCTION
  62. PHP_FUNCTION
  63. PHP_FUNCTION
  64. PHP_FUNCTION
  65. PHP_FUNCTION
  66. PHP_FUNCTION
  67. PHP_FUNCTION
  68. PHP_FUNCTION
  69. 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    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
  16    |          Andreas Karajannis <Andreas.Karajannis@gmd.de>              |
  17    |          Frank M. Kromann <frank@kromann.info>  Support for DB/2 CLI |
  18    |          Kevin N. Shallow <kshallow@tampabay.rr.com> Birdstep Support|
  19    |          Daniel R. Kalowsky <kalowsky@php.net>                       |
  20    +----------------------------------------------------------------------+
  21 */
  22 
  23 /* $Id$ */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include "config.h"
  27 #endif
  28  
  29 #include "php.h"
  30 #include "php_globals.h"
  31 
  32 #include "ext/standard/info.h"
  33 #include "ext/standard/php_string.h"
  34 #include "ext/standard/php_standard.h"
  35 
  36 #include "php_odbc.h"
  37 #include "php_odbc_includes.h"
  38 #include "php_globals.h"
  39 
  40 #if HAVE_UODBC
  41 
  42 #include <fcntl.h>
  43 #include "ext/standard/head.h"
  44 #include "php_ini.h"
  45 
  46 #ifdef PHP_WIN32
  47 #include <winsock2.h>
  48 
  49 #define ODBC_TYPE "Win32"
  50 #define PHP_ODBC_TYPE ODBC_TYPE
  51 
  52 #endif
  53 
  54 /*
  55  * not defined elsewhere
  56  */
  57 
  58 #ifndef TRUE
  59 #define TRUE 1
  60 #define FALSE 0
  61 #endif
  62 
  63 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent);
  64 
  65 static int le_result, le_conn, le_pconn;
  66 
  67 #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0))
  68 
  69 /* {{{ arginfo */
  70 ZEND_BEGIN_ARG_INFO(arginfo_odbc_close_all, 0)
  71 ZEND_END_ARG_INFO()
  72 
  73 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_binmode, 0, 0, 2)
  74         ZEND_ARG_INFO(0, result_id)
  75         ZEND_ARG_INFO(0, mode)
  76 ZEND_END_ARG_INFO()
  77 
  78 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_longreadlen, 0, 0, 2)
  79         ZEND_ARG_INFO(0, result_id)
  80         ZEND_ARG_INFO(0, length)
  81 ZEND_END_ARG_INFO()
  82 
  83 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_prepare, 0, 0, 2)
  84         ZEND_ARG_INFO(0, connection_id)
  85         ZEND_ARG_INFO(0, query)
  86 ZEND_END_ARG_INFO()
  87 
  88 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_execute, 0, 0, 1)
  89         ZEND_ARG_INFO(0, result_id)
  90         ZEND_ARG_INFO(0, parameters_array)
  91 ZEND_END_ARG_INFO()
  92 
  93 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_cursor, 0, 0, 1)
  94         ZEND_ARG_INFO(0, result_id)
  95 ZEND_END_ARG_INFO()
  96 
  97 #ifdef HAVE_SQLDATASOURCES
  98 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_data_source, 0, 0, 2)
  99         ZEND_ARG_INFO(0, connection_id)
 100         ZEND_ARG_INFO(0, fetch_type)
 101 ZEND_END_ARG_INFO()
 102 #endif
 103 
 104 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_exec, 0, 0, 2)
 105         ZEND_ARG_INFO(0, connection_id)
 106         ZEND_ARG_INFO(0, query)
 107         ZEND_ARG_INFO(0, flags)
 108 ZEND_END_ARG_INFO()
 109 
 110 #ifdef PHP_ODBC_HAVE_FETCH_HASH
 111 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_object, 0, 0, 1)
 112         ZEND_ARG_INFO(0, result)
 113         ZEND_ARG_INFO(0, rownumber)
 114 ZEND_END_ARG_INFO()
 115 
 116 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_array, 0, 0, 1)
 117         ZEND_ARG_INFO(0, result)
 118         ZEND_ARG_INFO(0, rownumber)
 119 ZEND_END_ARG_INFO()
 120 #endif
 121 
 122 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_into, 0, 0, 2)
 123         ZEND_ARG_INFO(0, result_id)
 124         ZEND_ARG_INFO(1, result_array)
 125         ZEND_ARG_INFO(0, rownumber)
 126 ZEND_END_ARG_INFO()
 127 
 128 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_row, 0, 0, 1)
 129         ZEND_ARG_INFO(0, result_id)
 130         ZEND_ARG_INFO(0, row_number)
 131 ZEND_END_ARG_INFO()
 132 
 133 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result, 0, 0, 2)
 134         ZEND_ARG_INFO(0, result_id)
 135         ZEND_ARG_INFO(0, field)
 136 ZEND_END_ARG_INFO()
 137 
 138 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result_all, 0, 0, 1)
 139         ZEND_ARG_INFO(0, result_id)
 140         ZEND_ARG_INFO(0, format)
 141 ZEND_END_ARG_INFO()
 142 
 143 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_free_result, 0, 0, 1)
 144         ZEND_ARG_INFO(0, result_id)
 145 ZEND_END_ARG_INFO()
 146 
 147 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_connect, 0, 0, 3)
 148         ZEND_ARG_INFO(0, dsn)
 149         ZEND_ARG_INFO(0, user)
 150         ZEND_ARG_INFO(0, password)
 151         ZEND_ARG_INFO(0, cursor_option)
 152 ZEND_END_ARG_INFO()
 153 
 154 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_pconnect, 0, 0, 3)
 155         ZEND_ARG_INFO(0, dsn)
 156         ZEND_ARG_INFO(0, user)
 157         ZEND_ARG_INFO(0, password)
 158         ZEND_ARG_INFO(0, cursor_option)
 159 ZEND_END_ARG_INFO()
 160 
 161 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_close, 0, 0, 1)
 162         ZEND_ARG_INFO(0, connection_id)
 163 ZEND_END_ARG_INFO()
 164 
 165 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_rows, 0, 0, 1)
 166         ZEND_ARG_INFO(0, result_id)
 167 ZEND_END_ARG_INFO()
 168 
 169 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
 170 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_next_result, 0, 0, 1)
 171         ZEND_ARG_INFO(0, result_id)
 172 ZEND_END_ARG_INFO()
 173 #endif
 174 
 175 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_fields, 0, 0, 1)
 176         ZEND_ARG_INFO(0, result_id)
 177 ZEND_END_ARG_INFO()
 178 
 179 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_name, 0, 0, 2)
 180         ZEND_ARG_INFO(0, result_id)
 181         ZEND_ARG_INFO(0, field_number)
 182 ZEND_END_ARG_INFO()
 183 
 184 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_type, 0, 0, 2)
 185         ZEND_ARG_INFO(0, result_id)
 186         ZEND_ARG_INFO(0, field_number)
 187 ZEND_END_ARG_INFO()
 188 
 189 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_len, 0, 0, 2)
 190         ZEND_ARG_INFO(0, result_id)
 191         ZEND_ARG_INFO(0, field_number)
 192 ZEND_END_ARG_INFO()
 193 
 194 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_scale, 0, 0, 2)
 195         ZEND_ARG_INFO(0, result_id)
 196         ZEND_ARG_INFO(0, field_number)
 197 ZEND_END_ARG_INFO()
 198 
 199 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_num, 0, 0, 2)
 200         ZEND_ARG_INFO(0, result_id)
 201         ZEND_ARG_INFO(0, field_name)
 202 ZEND_END_ARG_INFO()
 203 
 204 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_autocommit, 0, 0, 1)
 205         ZEND_ARG_INFO(0, connection_id)
 206         ZEND_ARG_INFO(0, onoff)
 207 ZEND_END_ARG_INFO()
 208 
 209 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_commit, 0, 0, 1)
 210         ZEND_ARG_INFO(0, connection_id)
 211 ZEND_END_ARG_INFO()
 212 
 213 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_rollback, 0, 0, 1)
 214         ZEND_ARG_INFO(0, connection_id)
 215 ZEND_END_ARG_INFO()
 216 
 217 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_error, 0, 0, 0)
 218         ZEND_ARG_INFO(0, connection_id)
 219 ZEND_END_ARG_INFO()
 220 
 221 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_errormsg, 0, 0, 0)
 222         ZEND_ARG_INFO(0, connection_id)
 223 ZEND_END_ARG_INFO()
 224 
 225 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_setoption, 0, 0, 4)
 226         ZEND_ARG_INFO(0, conn_id)
 227         ZEND_ARG_INFO(0, which)
 228         ZEND_ARG_INFO(0, option)
 229         ZEND_ARG_INFO(0, value)
 230 ZEND_END_ARG_INFO()
 231 
 232 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tables, 0, 0, 1)
 233         ZEND_ARG_INFO(0, connection_id)
 234         ZEND_ARG_INFO(0, qualifier)
 235         ZEND_ARG_INFO(0, owner)
 236         ZEND_ARG_INFO(0, name)
 237         ZEND_ARG_INFO(0, table_types)
 238 ZEND_END_ARG_INFO()
 239 
 240 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columns, 0, 0, 1)
 241         ZEND_ARG_INFO(0, connection_id)
 242         ZEND_ARG_INFO(0, qualifier)
 243         ZEND_ARG_INFO(0, owner)
 244         ZEND_ARG_INFO(0, table_name)
 245         ZEND_ARG_INFO(0, column_name)
 246 ZEND_END_ARG_INFO()
 247 
 248 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_gettypeinfo, 0, 0, 1)
 249         ZEND_ARG_INFO(0, connection_id)
 250         ZEND_ARG_INFO(0, data_type)
 251 ZEND_END_ARG_INFO()
 252 
 253 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_primarykeys, 0, 0, 4)
 254         ZEND_ARG_INFO(0, connection_id)
 255         ZEND_ARG_INFO(0, qualifier)
 256         ZEND_ARG_INFO(0, owner)
 257         ZEND_ARG_INFO(0, table)
 258 ZEND_END_ARG_INFO()
 259 
 260 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
 261 #if !defined(HAVE_BIRDSTEP)
 262 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedurecolumns, 0, 0, 1)
 263         ZEND_ARG_INFO(0, connection_id)
 264         ZEND_ARG_INFO(0, qualifier)
 265         ZEND_ARG_INFO(0, owner)
 266         ZEND_ARG_INFO(0, proc)
 267         ZEND_ARG_INFO(0, column)
 268 ZEND_END_ARG_INFO()
 269 #endif
 270 
 271 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedures, 0, 0, 1)
 272         ZEND_ARG_INFO(0, connection_id)
 273         ZEND_ARG_INFO(0, qualifier)
 274         ZEND_ARG_INFO(0, owner)
 275         ZEND_ARG_INFO(0, name)
 276 ZEND_END_ARG_INFO()
 277 
 278 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7)
 279         ZEND_ARG_INFO(0, connection_id)
 280         ZEND_ARG_INFO(0, pk_qualifier)
 281         ZEND_ARG_INFO(0, pk_owner)
 282         ZEND_ARG_INFO(0, pk_table)
 283         ZEND_ARG_INFO(0, fk_qualifier)
 284         ZEND_ARG_INFO(0, fk_owner)
 285         ZEND_ARG_INFO(0, fk_table)
 286 ZEND_END_ARG_INFO()
 287 #endif
 288 
 289 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7)
 290         ZEND_ARG_INFO(0, connection_id)
 291         ZEND_ARG_INFO(0, type)
 292         ZEND_ARG_INFO(0, qualifier)
 293         ZEND_ARG_INFO(0, owner)
 294         ZEND_ARG_INFO(0, table)
 295         ZEND_ARG_INFO(0, scope)
 296         ZEND_ARG_INFO(0, nullable)
 297 ZEND_END_ARG_INFO()
 298 
 299 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6)
 300         ZEND_ARG_INFO(0, connection_id)
 301         ZEND_ARG_INFO(0, qualifier)
 302         ZEND_ARG_INFO(0, owner)
 303         ZEND_ARG_INFO(0, name)
 304         ZEND_ARG_INFO(0, unique)
 305         ZEND_ARG_INFO(0, accuracy)
 306 ZEND_END_ARG_INFO()
 307 
 308 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
 309 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tableprivileges, 0, 0, 4)
 310         ZEND_ARG_INFO(0, connection_id)
 311         ZEND_ARG_INFO(0, qualifier)
 312         ZEND_ARG_INFO(0, owner)
 313         ZEND_ARG_INFO(0, name)
 314 ZEND_END_ARG_INFO()
 315 
 316 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5)
 317         ZEND_ARG_INFO(0, connection_id)
 318         ZEND_ARG_INFO(0, catalog)
 319         ZEND_ARG_INFO(0, schema)
 320         ZEND_ARG_INFO(0, table)
 321         ZEND_ARG_INFO(0, column)
 322 ZEND_END_ARG_INFO()
 323 #endif
 324 /* }}} */
 325 
 326 /* {{{ odbc_functions[]
 327  */
 328 const zend_function_entry odbc_functions[] = {
 329         PHP_FE(odbc_autocommit, arginfo_odbc_autocommit)
 330         PHP_FE(odbc_binmode, arginfo_odbc_binmode)
 331         PHP_FE(odbc_close, arginfo_odbc_close)
 332         PHP_FE(odbc_close_all, arginfo_odbc_close_all)
 333         PHP_FE(odbc_columns, arginfo_odbc_columns)
 334         PHP_FE(odbc_commit, arginfo_odbc_commit)
 335         PHP_FE(odbc_connect, arginfo_odbc_connect)
 336         PHP_FE(odbc_cursor, arginfo_odbc_cursor)
 337 #ifdef HAVE_SQLDATASOURCES
 338         PHP_FE(odbc_data_source, arginfo_odbc_data_source)
 339 #endif
 340         PHP_FE(odbc_execute, arginfo_odbc_execute)
 341         PHP_FE(odbc_error, arginfo_odbc_error)
 342         PHP_FE(odbc_errormsg, arginfo_odbc_errormsg)
 343         PHP_FE(odbc_exec, arginfo_odbc_exec)
 344 #ifdef PHP_ODBC_HAVE_FETCH_HASH
 345         PHP_FE(odbc_fetch_array, arginfo_odbc_fetch_array)
 346         PHP_FE(odbc_fetch_object, arginfo_odbc_fetch_object)
 347 #endif
 348         PHP_FE(odbc_fetch_row, arginfo_odbc_fetch_row)
 349         PHP_FE(odbc_fetch_into, arginfo_odbc_fetch_into)
 350         PHP_FE(odbc_field_len, arginfo_odbc_field_len)
 351         PHP_FE(odbc_field_scale, arginfo_odbc_field_scale)
 352         PHP_FE(odbc_field_name, arginfo_odbc_field_name)
 353         PHP_FE(odbc_field_type, arginfo_odbc_field_type)
 354         PHP_FE(odbc_field_num, arginfo_odbc_field_num)
 355         PHP_FE(odbc_free_result, arginfo_odbc_free_result)
 356         PHP_FE(odbc_gettypeinfo, arginfo_odbc_gettypeinfo)
 357         PHP_FE(odbc_longreadlen, arginfo_odbc_longreadlen)
 358 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
 359         PHP_FE(odbc_next_result, arginfo_odbc_next_result)
 360 #endif
 361         PHP_FE(odbc_num_fields, arginfo_odbc_num_fields)
 362         PHP_FE(odbc_num_rows, arginfo_odbc_num_rows)
 363         PHP_FE(odbc_pconnect, arginfo_odbc_pconnect)
 364         PHP_FE(odbc_prepare, arginfo_odbc_prepare)
 365         PHP_FE(odbc_result, arginfo_odbc_result)
 366         PHP_FE(odbc_result_all, arginfo_odbc_result_all)
 367         PHP_FE(odbc_rollback, arginfo_odbc_rollback)
 368         PHP_FE(odbc_setoption, arginfo_odbc_setoption)
 369         PHP_FE(odbc_specialcolumns, arginfo_odbc_specialcolumns)
 370         PHP_FE(odbc_statistics, arginfo_odbc_statistics)
 371         PHP_FE(odbc_tables, arginfo_odbc_tables)
 372         PHP_FE(odbc_primarykeys, arginfo_odbc_primarykeys)
 373 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)    /* not supported now */
 374         PHP_FE(odbc_columnprivileges, arginfo_odbc_columnprivileges)
 375         PHP_FE(odbc_tableprivileges, arginfo_odbc_tableprivileges)
 376 #endif
 377 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) /* not supported */
 378         PHP_FE(odbc_foreignkeys, arginfo_odbc_foreignkeys)
 379         PHP_FE(odbc_procedures, arginfo_odbc_procedures)
 380 #if !defined(HAVE_BIRDSTEP)
 381         PHP_FE(odbc_procedurecolumns, arginfo_odbc_procedurecolumns)
 382 #endif
 383 #endif
 384         PHP_FALIAS(odbc_do, odbc_exec, arginfo_odbc_exec)
 385         PHP_FALIAS(odbc_field_precision, odbc_field_len, arginfo_odbc_field_len)
 386         PHP_FE_END
 387 };
 388 /* }}} */
 389 
 390 ZEND_DECLARE_MODULE_GLOBALS(odbc)
 391 static PHP_GINIT_FUNCTION(odbc);
 392 
 393 /* {{{ odbc_module_entry
 394  */
 395 zend_module_entry odbc_module_entry = {
 396         STANDARD_MODULE_HEADER,
 397         "odbc", 
 398         odbc_functions, 
 399         PHP_MINIT(odbc), 
 400         PHP_MSHUTDOWN(odbc),
 401         PHP_RINIT(odbc), 
 402         PHP_RSHUTDOWN(odbc), 
 403         PHP_MINFO(odbc), 
 404         "1.0",
 405         PHP_MODULE_GLOBALS(odbc),
 406         PHP_GINIT(odbc),
 407         NULL,
 408         NULL,
 409         STANDARD_MODULE_PROPERTIES_EX
 410 };
 411 /* }}} */
 412 
 413 #ifdef COMPILE_DL_ODBC
 414 ZEND_GET_MODULE(odbc)
 415 #endif
 416 
 417 /* {{{ _free_odbc_result
 418  */
 419 static void _free_odbc_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 420 {
 421         odbc_result *res = (odbc_result *)rsrc->ptr;
 422         int i;
 423         RETCODE rc;
 424         
 425         if (res) {
 426                 if (res->values) {
 427                         for(i = 0; i < res->numcols; i++) {
 428                                 if (res->values[i].value)
 429                                         efree(res->values[i].value);
 430                         }
 431                         efree(res->values);
 432                         res->values = NULL;
 433                 }
 434                 if (res->stmt) {
 435 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
 436                         SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc,
 437                                                 (SQLUSMALLINT) SQL_COMMIT);
 438 #endif
 439                         rc = SQLFreeStmt(res->stmt,SQL_DROP);
 440                         /* We don't want the connection to be closed after the last statment has been closed
 441                          * Connections will be closed on shutdown
 442                          * zend_list_delete(res->conn_ptr->id);
 443                          */
 444                 }
 445                 if (res->param_info) {
 446                         efree(res->param_info);
 447                 }
 448                 efree(res);
 449         }
 450 }
 451 /* }}} */
 452 
 453 /* {{{ safe_odbc_disconnect
 454  * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher)
 455  */
 456 static void safe_odbc_disconnect( void *handle )
 457 {
 458         int ret;
 459 
 460         ret = SQLDisconnect( handle );
 461         if ( ret == SQL_ERROR )
 462         {
 463                 SQLTransact( NULL, handle, SQL_ROLLBACK );
 464                 SQLDisconnect( handle );
 465         }
 466 }
 467 /* }}} */
 468 
 469 /* {{{ _close_odbc_conn
 470  */
 471 static void _close_odbc_conn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 472 {
 473         int i, nument, type;
 474         void *ptr;
 475         odbc_result *res;
 476 
 477         odbc_connection *conn = (odbc_connection *)rsrc->ptr;
 478 
 479         nument = zend_hash_next_free_element(&EG(regular_list));
 480         for(i = 1; i < nument; i++) {
 481                 ptr = zend_list_find(i, &type);
 482                 if (ptr && (type == le_result)) {
 483                         res = (odbc_result *)ptr;
 484                         if (res->conn_ptr == conn) {
 485                                 zend_list_delete(i);
 486                         }
 487                 }
 488         }
 489 
 490         safe_odbc_disconnect(conn->hdbc);
 491         SQLFreeConnect(conn->hdbc);
 492         SQLFreeEnv(conn->henv);
 493         efree(conn);
 494         ODBCG(num_links)--;
 495 }
 496 /* }}} */
 497 
 498 /* {{{ void _close_odbc_pconn
 499  */
 500 static void _close_odbc_pconn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 501 {
 502         int i, nument, type;
 503         void *ptr;
 504         odbc_result *res;
 505         odbc_connection *conn = (odbc_connection *)rsrc->ptr;
 506 
 507         nument = zend_hash_next_free_element(&EG(persistent_list));
 508         for(i = 1; i < nument; i++) {
 509                 ptr = zend_list_find(i, &type);
 510                 if (ptr && (type == le_result)) {
 511                         res = (odbc_result *)ptr;
 512                         if (res->conn_ptr == conn) {
 513                                 zend_list_delete(i);
 514                         }
 515                 }
 516         }
 517         
 518         safe_odbc_disconnect(conn->hdbc);
 519         SQLFreeConnect(conn->hdbc);
 520         SQLFreeEnv(conn->henv);
 521         free(conn);
 522 
 523         ODBCG(num_links)--;
 524         ODBCG(num_persistent)--;
 525 }
 526 /* }}} */
 527 
 528 /* {{{ PHP_INI_DISP(display_link_nums)
 529  */
 530 static PHP_INI_DISP(display_link_nums)
 531 {
 532         char *value;
 533         TSRMLS_FETCH();
 534 
 535         if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 536                 value = ini_entry->orig_value;
 537         } else if (ini_entry->value) {
 538                 value = ini_entry->value;
 539         } else {
 540                 value = NULL;
 541         }
 542 
 543         if (value) {
 544                 if (atoi(value) == -1) {
 545                         PUTS("Unlimited");
 546                 } else {
 547                         php_printf("%s", value);
 548                 }
 549         }
 550 }
 551 /* }}} */
 552 
 553 /* {{{ PHP_INI_DISP(display_defPW)
 554  */
 555 static PHP_INI_DISP(display_defPW)
 556 {
 557         char *value;
 558         TSRMLS_FETCH();
 559 
 560         if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 561                 value = ini_entry->orig_value;
 562         } else if (ini_entry->value) {
 563                 value = ini_entry->value;
 564         } else {
 565                 value = NULL;
 566         }
 567 
 568         if (value) {
 569 #if PHP_DEBUG
 570                 php_printf("%s", value);
 571 #else
 572                 PUTS("********");
 573 #endif
 574         } else {
 575                 if (PG(html_errors)) {
 576                         PUTS("<i>no value</i>");
 577                 } else {
 578                         PUTS("no value");
 579                 }
 580         }
 581 }
 582 /* }}} */
 583 
 584 /* {{{ PHP_INI_DISP(display_binmode)
 585  */
 586 static PHP_INI_DISP(display_binmode)
 587 {
 588         char *value;
 589         TSRMLS_FETCH();
 590         
 591         if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 592                 value = ini_entry->orig_value;
 593         } else if (ini_entry->value) {
 594                 value = ini_entry->value;
 595         } else {
 596                 value = NULL;
 597         }
 598 
 599         if (value) {
 600                 switch(atoi(value)) {
 601                         case 0:
 602                                 PUTS("passthru");
 603                                 break;
 604                         case 1:
 605                                 PUTS("return as is");
 606                                 break;
 607                         case 2:
 608                                 PUTS("return as char");
 609                                 break;
 610                 }
 611         }
 612 }
 613 /* }}} */
 614 
 615 /* {{{ PHP_INI_DISP(display_lrl)
 616  */
 617 static PHP_INI_DISP(display_lrl)
 618 {
 619         char *value;
 620         TSRMLS_FETCH();
 621 
 622         if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 623                 value = ini_entry->orig_value;
 624         } else if (ini_entry->value) {
 625                 value = ini_entry->value;
 626         } else {
 627                 value = NULL;
 628         }
 629 
 630         if (value) {
 631                 if (atoi(value) <= 0) {
 632                         PUTS("Passthru");
 633                 } else {
 634                         php_printf("return up to %s bytes", value);
 635                 }
 636         }
 637 }
 638 /* }}} */
 639 
 640 
 641 /* {{{ PHP_INI_DISP(display_cursortype)
 642  */
 643 static PHP_INI_DISP(display_cursortype)
 644 {
 645         char *value;
 646         TSRMLS_FETCH();
 647 
 648         if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
 649                 value = ini_entry->orig_value;
 650         } else if (ini_entry->value) {
 651                 value = ini_entry->value;
 652         } else {
 653                 value = NULL;
 654         }
 655 
 656         if (value) {
 657                 switch (atoi (value))
 658                   {
 659                     case SQL_CURSOR_FORWARD_ONLY:
 660                                 PUTS ("Forward Only cursor");
 661                                 break;
 662 
 663                         case SQL_CURSOR_STATIC:
 664                             PUTS ("Static cursor");
 665                                 break;
 666 
 667                         case SQL_CURSOR_KEYSET_DRIVEN:
 668                                 PUTS ("Keyset driven cursor");
 669                                 break;
 670 
 671                         case SQL_CURSOR_DYNAMIC:
 672                                 PUTS ("Dynamic cursor");
 673                                 break;
 674 
 675                         default:
 676                                 php_printf("Unknown cursor model %s", value);
 677                                 break;
 678                   }
 679         }
 680 }
 681 
 682 /* }}} */
 683 
 684 /* {{{ PHP_INI_BEGIN 
 685  */
 686 PHP_INI_BEGIN()
 687         STD_PHP_INI_BOOLEAN("odbc.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
 688                         allow_persistent, zend_odbc_globals, odbc_globals)
 689         STD_PHP_INI_ENTRY_EX("odbc.max_persistent",  "-1", PHP_INI_SYSTEM, OnUpdateLong,
 690                         max_persistent, zend_odbc_globals, odbc_globals, display_link_nums)
 691         STD_PHP_INI_ENTRY_EX("odbc.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong,
 692                         max_links, zend_odbc_globals, odbc_globals, display_link_nums)
 693         STD_PHP_INI_ENTRY("odbc.default_db", NULL, PHP_INI_ALL, OnUpdateString,
 694                         defDB, zend_odbc_globals, odbc_globals)
 695         STD_PHP_INI_ENTRY("odbc.default_user", NULL, PHP_INI_ALL, OnUpdateString,
 696                         defUser, zend_odbc_globals, odbc_globals)
 697         STD_PHP_INI_ENTRY_EX("odbc.default_pw", NULL, PHP_INI_ALL, OnUpdateString,
 698                         defPW, zend_odbc_globals, odbc_globals, display_defPW)
 699         STD_PHP_INI_ENTRY_EX("odbc.defaultlrl", "4096", PHP_INI_ALL, OnUpdateLong,
 700                         defaultlrl, zend_odbc_globals, odbc_globals, display_lrl)
 701         STD_PHP_INI_ENTRY_EX("odbc.defaultbinmode", "1", PHP_INI_ALL, OnUpdateLong,
 702                         defaultbinmode, zend_odbc_globals, odbc_globals, display_binmode)
 703         STD_PHP_INI_BOOLEAN("odbc.check_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
 704                         check_persistent, zend_odbc_globals, odbc_globals)
 705         STD_PHP_INI_ENTRY_EX("odbc.default_cursortype", "3", PHP_INI_ALL, OnUpdateLong, 
 706                         default_cursortype, zend_odbc_globals, odbc_globals, display_cursortype)
 707 PHP_INI_END()
 708 /* }}} */
 709 
 710 static PHP_GINIT_FUNCTION(odbc)
 711 {
 712         odbc_globals->num_persistent = 0;
 713 }
 714 
 715 /* {{{ PHP_MINIT_FUNCTION */
 716 PHP_MINIT_FUNCTION(odbc)
 717 {
 718 #ifdef SQLANY_BUG
 719         ODBC_SQL_CONN_T foobar;
 720         RETCODE rc;
 721 #endif
 722 
 723         REGISTER_INI_ENTRIES();
 724         le_result = zend_register_list_destructors_ex(_free_odbc_result, NULL, "odbc result", module_number);
 725         le_conn = zend_register_list_destructors_ex(_close_odbc_conn, NULL, "odbc link", module_number);
 726         le_pconn = zend_register_list_destructors_ex(NULL, _close_odbc_pconn, "odbc link persistent", module_number);
 727         Z_TYPE(odbc_module_entry) = type;
 728         
 729         REGISTER_STRING_CONSTANT("ODBC_TYPE", PHP_ODBC_TYPE, CONST_CS | CONST_PERSISTENT);
 730         REGISTER_LONG_CONSTANT("ODBC_BINMODE_PASSTHRU", 0, CONST_CS | CONST_PERSISTENT);
 731         REGISTER_LONG_CONSTANT("ODBC_BINMODE_RETURN", 1, CONST_CS | CONST_PERSISTENT);
 732         REGISTER_LONG_CONSTANT("ODBC_BINMODE_CONVERT", 2, CONST_CS | CONST_PERSISTENT);
 733         /* Define Constants for options
 734            these Constants are defined in <sqlext.h>
 735         */
 736         REGISTER_LONG_CONSTANT("SQL_ODBC_CURSORS", SQL_ODBC_CURSORS, CONST_PERSISTENT | CONST_CS);
 737         REGISTER_LONG_CONSTANT("SQL_CUR_USE_DRIVER", SQL_CUR_USE_DRIVER, CONST_PERSISTENT | CONST_CS);
 738         REGISTER_LONG_CONSTANT("SQL_CUR_USE_IF_NEEDED", SQL_CUR_USE_IF_NEEDED, CONST_PERSISTENT | CONST_CS);
 739         REGISTER_LONG_CONSTANT("SQL_CUR_USE_ODBC", SQL_CUR_USE_ODBC, CONST_PERSISTENT | CONST_CS);
 740 
 741 
 742         REGISTER_LONG_CONSTANT("SQL_CONCURRENCY", SQL_CONCURRENCY, CONST_PERSISTENT | CONST_CS);
 743         REGISTER_LONG_CONSTANT("SQL_CONCUR_READ_ONLY", SQL_CONCUR_READ_ONLY, CONST_PERSISTENT | CONST_CS);
 744         REGISTER_LONG_CONSTANT("SQL_CONCUR_LOCK", SQL_CONCUR_LOCK, CONST_PERSISTENT | CONST_CS);
 745         REGISTER_LONG_CONSTANT("SQL_CONCUR_ROWVER", SQL_CONCUR_ROWVER, CONST_PERSISTENT | CONST_CS);
 746         REGISTER_LONG_CONSTANT("SQL_CONCUR_VALUES", SQL_CONCUR_VALUES, CONST_PERSISTENT | CONST_CS);
 747 
 748         REGISTER_LONG_CONSTANT("SQL_CURSOR_TYPE", SQL_CURSOR_TYPE, CONST_PERSISTENT | CONST_CS);
 749         REGISTER_LONG_CONSTANT("SQL_CURSOR_FORWARD_ONLY", SQL_CURSOR_FORWARD_ONLY, CONST_PERSISTENT | CONST_CS);
 750         REGISTER_LONG_CONSTANT("SQL_CURSOR_KEYSET_DRIVEN", SQL_CURSOR_KEYSET_DRIVEN, CONST_PERSISTENT | CONST_CS);
 751         REGISTER_LONG_CONSTANT("SQL_CURSOR_DYNAMIC", SQL_CURSOR_DYNAMIC, CONST_PERSISTENT | CONST_CS);
 752         REGISTER_LONG_CONSTANT("SQL_CURSOR_STATIC", SQL_CURSOR_STATIC, CONST_PERSISTENT | CONST_CS);
 753         
 754         REGISTER_LONG_CONSTANT("SQL_KEYSET_SIZE", SQL_KEYSET_SIZE, CONST_PERSISTENT | CONST_CS);
 755 
 756         /* these are for the Data Source type */
 757         REGISTER_LONG_CONSTANT("SQL_FETCH_FIRST", SQL_FETCH_FIRST, CONST_PERSISTENT | CONST_CS);
 758         REGISTER_LONG_CONSTANT("SQL_FETCH_NEXT", SQL_FETCH_NEXT, CONST_PERSISTENT | CONST_CS);
 759 
 760         /*
 761          * register the standard data types
 762          */
 763         REGISTER_LONG_CONSTANT("SQL_CHAR", SQL_CHAR, CONST_PERSISTENT | CONST_CS);
 764         REGISTER_LONG_CONSTANT("SQL_VARCHAR", SQL_VARCHAR, CONST_PERSISTENT | CONST_CS);
 765         REGISTER_LONG_CONSTANT("SQL_LONGVARCHAR", SQL_LONGVARCHAR, CONST_PERSISTENT | CONST_CS);
 766         REGISTER_LONG_CONSTANT("SQL_DECIMAL", SQL_DECIMAL, CONST_PERSISTENT | CONST_CS);
 767         REGISTER_LONG_CONSTANT("SQL_NUMERIC", SQL_NUMERIC, CONST_PERSISTENT | CONST_CS);
 768         REGISTER_LONG_CONSTANT("SQL_BIT", SQL_BIT, CONST_PERSISTENT | CONST_CS);
 769         REGISTER_LONG_CONSTANT("SQL_TINYINT", SQL_TINYINT, CONST_PERSISTENT | CONST_CS);
 770         REGISTER_LONG_CONSTANT("SQL_SMALLINT", SQL_SMALLINT, CONST_PERSISTENT | CONST_CS);
 771         REGISTER_LONG_CONSTANT("SQL_INTEGER", SQL_INTEGER, CONST_PERSISTENT | CONST_CS);
 772         REGISTER_LONG_CONSTANT("SQL_BIGINT", SQL_BIGINT, CONST_PERSISTENT | CONST_CS);
 773         REGISTER_LONG_CONSTANT("SQL_REAL", SQL_REAL, CONST_PERSISTENT | CONST_CS);
 774         REGISTER_LONG_CONSTANT("SQL_FLOAT", SQL_FLOAT, CONST_PERSISTENT | CONST_CS);
 775         REGISTER_LONG_CONSTANT("SQL_DOUBLE", SQL_DOUBLE, CONST_PERSISTENT | CONST_CS);
 776         REGISTER_LONG_CONSTANT("SQL_BINARY", SQL_BINARY, CONST_PERSISTENT | CONST_CS);
 777         REGISTER_LONG_CONSTANT("SQL_VARBINARY", SQL_VARBINARY, CONST_PERSISTENT | CONST_CS);
 778         REGISTER_LONG_CONSTANT("SQL_LONGVARBINARY", SQL_LONGVARBINARY, CONST_PERSISTENT | CONST_CS);
 779         REGISTER_LONG_CONSTANT("SQL_DATE", SQL_DATE, CONST_PERSISTENT | CONST_CS);
 780         REGISTER_LONG_CONSTANT("SQL_TIME", SQL_TIME, CONST_PERSISTENT | CONST_CS);
 781         REGISTER_LONG_CONSTANT("SQL_TIMESTAMP", SQL_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
 782 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
 783         REGISTER_LONG_CONSTANT("SQL_TYPE_DATE", SQL_TYPE_DATE, CONST_PERSISTENT | CONST_CS);
 784         REGISTER_LONG_CONSTANT("SQL_TYPE_TIME", SQL_TYPE_TIME, CONST_PERSISTENT | CONST_CS);
 785         REGISTER_LONG_CONSTANT("SQL_TYPE_TIMESTAMP", SQL_TYPE_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
 786         REGISTER_LONG_CONSTANT("SQL_WCHAR", SQL_WCHAR, CONST_PERSISTENT | CONST_CS);
 787         REGISTER_LONG_CONSTANT("SQL_WVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT | CONST_CS);
 788         REGISTER_LONG_CONSTANT("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR, CONST_PERSISTENT | CONST_CS);
 789 
 790         /*
 791          * SQLSpecialColumns values
 792          */
 793         REGISTER_LONG_CONSTANT("SQL_BEST_ROWID", SQL_BEST_ROWID, CONST_PERSISTENT | CONST_CS);
 794         REGISTER_LONG_CONSTANT("SQL_ROWVER", SQL_ROWVER, CONST_PERSISTENT | CONST_CS);
 795         REGISTER_LONG_CONSTANT("SQL_SCOPE_CURROW", SQL_SCOPE_CURROW, CONST_PERSISTENT | CONST_CS);
 796         REGISTER_LONG_CONSTANT("SQL_SCOPE_TRANSACTION", SQL_SCOPE_TRANSACTION, CONST_PERSISTENT | CONST_CS);
 797         REGISTER_LONG_CONSTANT("SQL_SCOPE_SESSION", SQL_SCOPE_SESSION, CONST_PERSISTENT | CONST_CS);
 798         REGISTER_LONG_CONSTANT("SQL_NO_NULLS", SQL_NO_NULLS, CONST_PERSISTENT | CONST_CS);
 799         REGISTER_LONG_CONSTANT("SQL_NULLABLE", SQL_NULLABLE, CONST_PERSISTENT | CONST_CS);
 800 
 801         /*
 802          * SQLStatistics values
 803          */
 804         REGISTER_LONG_CONSTANT("SQL_INDEX_UNIQUE", SQL_INDEX_UNIQUE, CONST_PERSISTENT | CONST_CS);
 805         REGISTER_LONG_CONSTANT("SQL_INDEX_ALL", SQL_INDEX_ALL, CONST_PERSISTENT | CONST_CS);
 806         REGISTER_LONG_CONSTANT("SQL_ENSURE", SQL_ENSURE, CONST_PERSISTENT | CONST_CS);
 807         REGISTER_LONG_CONSTANT("SQL_QUICK", SQL_QUICK, CONST_PERSISTENT | CONST_CS);
 808 #endif
 809 
 810 #if defined(HAVE_IBMDB2) && defined(_AIX)
 811         /* atexit() handler in the DB2/AIX library segfaults in PHP CLI */
 812         /* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */
 813         putenv("DB2NOEXITLIST=TRUE");
 814 #endif
 815 
 816         return SUCCESS;
 817 }
 818 /* }}} */
 819 
 820 /* {{{ PHP_RINIT_FUNCTION */
 821 PHP_RINIT_FUNCTION(odbc)
 822 {
 823         ODBCG(defConn) = -1;
 824         ODBCG(num_links) = ODBCG(num_persistent);
 825         memset(ODBCG(laststate), '\0', 6);
 826         memset(ODBCG(lasterrormsg), '\0', SQL_MAX_MESSAGE_LENGTH);
 827         return SUCCESS;
 828 }
 829 /* }}} */
 830 
 831 /* {{{ PHP_RSHUTDOWN_FUNCTION */
 832 PHP_RSHUTDOWN_FUNCTION(odbc)
 833 {
 834         return SUCCESS;
 835 }
 836 /* }}} */
 837 
 838 /* {{{ PHP_MSHUTDOWN_FUNCTION */
 839 PHP_MSHUTDOWN_FUNCTION(odbc)
 840 {
 841         UNREGISTER_INI_ENTRIES();
 842         return SUCCESS;
 843 }
 844 /* }}} */
 845 
 846 /* {{{ PHP_MINFO_FUNCTION */
 847 PHP_MINFO_FUNCTION(odbc)
 848 {
 849         char buf[32];
 850 
 851         php_info_print_table_start();
 852         php_info_print_table_header(2, "ODBC Support", "enabled");
 853         snprintf(buf, sizeof(buf), "%ld", ODBCG(num_persistent));
 854         php_info_print_table_row(2, "Active Persistent Links", buf);
 855         snprintf(buf, sizeof(buf), "%ld", ODBCG(num_links));
 856         php_info_print_table_row(2, "Active Links", buf);
 857         php_info_print_table_row(2, "ODBC library", PHP_ODBC_TYPE);
 858 #ifndef PHP_WIN32
 859         php_info_print_table_row(2, "ODBC_INCLUDE", PHP_ODBC_INCLUDE);
 860         php_info_print_table_row(2, "ODBC_LFLAGS", PHP_ODBC_LFLAGS);
 861         php_info_print_table_row(2, "ODBC_LIBS", PHP_ODBC_LIBS);
 862 #endif
 863         php_info_print_table_end();
 864 
 865         DISPLAY_INI_ENTRIES();
 866 
 867 }        
 868 /* }}} */
 869 
 870 /* {{{ odbc_sql_error */
 871 void odbc_sql_error(ODBC_SQL_ERROR_PARAMS)
 872 {
 873         char        state[6];
 874         SQLINTEGER      error;        /* Not used */
 875         char        errormsg[SQL_MAX_MESSAGE_LENGTH];
 876         SQLSMALLINT     errormsgsize; /* Not used */
 877         RETCODE rc;
 878         ODBC_SQL_ENV_T henv;
 879         ODBC_SQL_CONN_T conn;
 880         TSRMLS_FETCH();
 881 
 882         if (conn_resource) {
 883                 henv = conn_resource->henv;
 884                 conn = conn_resource->hdbc;
 885         } else {
 886                 henv = SQL_NULL_HENV;
 887                 conn = SQL_NULL_HDBC;
 888         }
 889 
 890         /* This leads to an endless loop in many drivers! 
 891          *
 892            while(henv != SQL_NULL_HENV){
 893                 do {
 894          */
 895         rc = SQLError(henv, conn, stmt, state, &error, errormsg, sizeof(errormsg)-1, &errormsgsize);
 896         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
 897                 snprintf(state, sizeof(state), "HY000");
 898                 snprintf(errormsg, sizeof(errormsg), "Failed to fetch error message");
 899         }
 900         if (conn_resource) {
 901                 memcpy(conn_resource->laststate, state, sizeof(state));
 902                 memcpy(conn_resource->lasterrormsg, errormsg, sizeof(errormsg));
 903         }
 904         memcpy(ODBCG(laststate), state, sizeof(state));
 905         memcpy(ODBCG(lasterrormsg), errormsg, sizeof(errormsg));
 906         if (func) {
 907                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s in %s", errormsg, state, func);
 908         } else {
 909                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
 910         }
 911         /*              
 912                 } while (SQL_SUCCEEDED(rc));
 913         }
 914         */
 915 }
 916 /* }}} */
 917 
 918 /* {{{ php_odbc_fetch_attribs */
 919 void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode)
 920 {
 921         odbc_result *result;
 922         zval *pv_res;
 923         long flag;
 924 
 925         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &flag) == FAILURE) {
 926                 return;
 927         }
 928         
 929         if (Z_LVAL_P(pv_res)) {
 930                 ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
 931         if (mode) {
 932             result->longreadlen = flag;
 933         } else {
 934             result->binmode = flag;
 935                 }
 936         } else {
 937         if (mode) {
 938             ODBCG(defaultlrl) = flag;
 939         } else {
 940             ODBCG(defaultbinmode) = flag;
 941                 }
 942         }
 943         RETURN_TRUE;
 944 }
 945 /* }}} */
 946 
 947 /* {{{ odbc_bindcols */
 948 int odbc_bindcols(odbc_result *result TSRMLS_DC)
 949 {
 950         RETCODE rc;
 951         int i;
 952         SQLSMALLINT     colnamelen; /* Not used */
 953         SQLLEN          displaysize;
 954         SQLUSMALLINT    colfieldid;
 955         int             charextraalloc;
 956 
 957         result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0);
 958 
 959         result->longreadlen = ODBCG(defaultlrl);
 960         result->binmode = ODBCG(defaultbinmode);
 961 
 962         for(i = 0; i < result->numcols; i++) {
 963                 charextraalloc = 0;
 964                 colfieldid = SQL_COLUMN_DISPLAY_SIZE;
 965 
 966                 rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(i+1), PHP_ODBC_SQL_DESC_NAME,
 967                                 result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0);
 968                 rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_TYPE, 
 969                                 NULL, 0, NULL, &result->values[i].coltype);
 970                 
 971                 /* Don't bind LONG / BINARY columns, so that fetch behaviour can
 972                  * be controlled by odbc_binmode() / odbc_longreadlen()
 973                  */
 974                 
 975                 switch(result->values[i].coltype) {
 976                         case SQL_BINARY:
 977                         case SQL_VARBINARY:
 978                         case SQL_LONGVARBINARY:
 979                         case SQL_LONGVARCHAR:
 980 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
 981                         case SQL_WLONGVARCHAR:
 982 #endif
 983                                 result->values[i].value = NULL;
 984                                 break;
 985                                 
 986 #ifdef HAVE_ADABAS
 987                         case SQL_TIMESTAMP:
 988                                 result->values[i].value = (char *)emalloc(27);
 989                                 SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
 990                                                         27, &result->values[i].vallen);
 991                                 break;
 992 #endif /* HAVE_ADABAS */
 993                         case SQL_CHAR:
 994                         case SQL_VARCHAR:
 995 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
 996                         case SQL_WCHAR:
 997                         case SQL_WVARCHAR:
 998                                 colfieldid = SQL_DESC_OCTET_LENGTH;
 999 #else
1000                                 charextraalloc = 1;
1001 #endif
1002                         default:
1003                                 rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(i+1), colfieldid,
1004                                                                 NULL, 0, NULL, &displaysize);
1005 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
1006                                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && colfieldid == SQL_DESC_OCTET_LENGTH) {
1007                                          /* This is  a quirk for ODBC 2.0 compatibility for broken driver implementations.
1008                                           */
1009                                         charextraalloc = 1;
1010                                         rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE,
1011                                                                 NULL, 0, NULL, &displaysize);
1012                                 }
1013 
1014                                 /* Workaround for drivers that report NVARCHAR(MAX) columns as SQL_WVARCHAR with size 0 (bug #69975) */
1015                                 if (result->values[i].coltype == SQL_WVARCHAR && displaysize == 0) {
1016                                         result->values[i].coltype = SQL_WLONGVARCHAR;
1017                                         result->values[i].value = NULL;
1018                                         break;
1019                                 }
1020 #endif
1021                                 /* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */
1022                                 if (result->values[i].coltype == SQL_TIMESTAMP) {
1023                                         displaysize += 3;
1024                                 }
1025 
1026                                 if (charextraalloc) {
1027                                         /* Since we don't know the exact # of bytes, allocate extra */
1028                                         displaysize *= 4;
1029                                 }
1030                                 result->values[i].value = (char *)emalloc(displaysize + 1);
1031                                 rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
1032                                                         displaysize + 1, &result->values[i].vallen);
1033                                 break;
1034                 }
1035         }
1036         return 1;
1037 }
1038 /* }}} */
1039 
1040 /* {{{ odbc_transact */
1041 void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type)
1042 {
1043         odbc_connection *conn;
1044         RETCODE rc;
1045         zval *pv_conn;
1046         
1047         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
1048                 return;
1049         }
1050 
1051         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1052         
1053         rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK));
1054         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1055                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTransact");
1056                 RETURN_FALSE;
1057         }
1058 
1059         RETURN_TRUE;
1060 }
1061 /* }}} */
1062 
1063 /* {{{ _close_pconn_with_id */
1064 static int _close_pconn_with_id(zend_rsrc_list_entry *le, int *id TSRMLS_DC)
1065 {
1066         if(Z_TYPE_P(le) == le_pconn && (((odbc_connection *)(le->ptr))->id == *id)){
1067                 return 1;
1068         }else{
1069                 return 0;
1070         }
1071 }
1072 /* }}} */
1073 
1074 /* {{{ odbc_column_lengths */
1075 void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
1076 {
1077         odbc_result *result;
1078 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
1079         /* this seems to be necessary for Solid2.3 ( tested by 
1080          * tammy@synchronis.com) and Solid 3.0 (tested by eric@terra.telemediair.nl)
1081          * Solid does not seem to declare a SQLINTEGER, but it does declare a
1082          * SQL_INTEGER which does not work (despite being the same type as a SDWORD.
1083          * Solid 3.5 does not have this issue.
1084          */
1085         SDWORD len;
1086 #else
1087         SQLLEN len;
1088 #endif
1089         zval *pv_res;
1090         long pv_num;
1091 
1092         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
1093                 return;
1094         }
1095 
1096         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1097 
1098         if (result->numcols == 0) {
1099                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1100                 RETURN_FALSE;
1101         }
1102 
1103         if (pv_num > result->numcols) {
1104                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
1105                 RETURN_FALSE;
1106         }
1107 
1108         if (pv_num < 1) {
1109                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
1110                 RETURN_FALSE;
1111         }
1112 
1113         PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT) (type?SQL_COLUMN_SCALE:SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
1114 
1115         RETURN_LONG(len);
1116 }
1117 /* }}} */
1118 
1119 /* Main User Functions */
1120 
1121 /* {{{ proto void odbc_close_all(void)
1122    Close all ODBC connections */
1123 PHP_FUNCTION(odbc_close_all)
1124 {
1125         void *ptr;
1126         int type;
1127         int i;
1128         int nument;
1129 
1130         if (zend_parse_parameters_none() == FAILURE) {
1131                 return;
1132         }
1133 
1134         nument = zend_hash_next_free_element(&EG(regular_list));
1135         
1136         /* Loop through list and close all statements */
1137         for(i = 1; i < nument; i++) {
1138                 ptr = zend_list_find(i, &type);
1139                 if (ptr && (type == le_result)){
1140                         zend_list_delete(i);
1141                 }
1142         }
1143 
1144         /* Second loop through list, now close all connections */
1145         nument = zend_hash_next_free_element(&EG(regular_list));
1146         
1147         for(i = 1; i < nument; i++) {
1148                 ptr = zend_list_find(i, &type);
1149                 if (ptr){
1150                         if(type == le_conn){
1151                                 zend_list_delete(i);
1152                         }else if(type == le_pconn){
1153                                 zend_list_delete(i);
1154                                 /* Delete the persistent connection */
1155                                 zend_hash_apply_with_argument(&EG(persistent_list), 
1156                                         (apply_func_arg_t) _close_pconn_with_id, (void *) &i TSRMLS_CC);
1157                         }
1158                 }
1159         }
1160 }
1161 /* }}} */
1162 
1163 /* {{{ proto bool odbc_binmode(int result_id, int mode)
1164    Handle binary column data */
1165 PHP_FUNCTION(odbc_binmode)
1166 {
1167         php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1168 }
1169 /* }}} */
1170 
1171 /* {{{ proto bool odbc_longreadlen(int result_id, int length)
1172    Handle LONG columns */
1173 PHP_FUNCTION(odbc_longreadlen)
1174 {
1175         php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1176 }
1177 /* }}} */
1178 
1179 /* {{{ proto resource odbc_prepare(resource connection_id, string query)
1180    Prepares a statement for execution */
1181 PHP_FUNCTION(odbc_prepare)
1182 {
1183         zval *pv_conn;
1184         char *query;
1185         int query_len;
1186         odbc_result *result = NULL;
1187         odbc_connection *conn;
1188         RETCODE rc;
1189         int i;
1190 #ifdef HAVE_SQL_EXTENDED_FETCH
1191         SQLUINTEGER      scrollopts;
1192 #endif
1193 
1194         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_conn, &query, &query_len) == FAILURE) {
1195                 return;
1196         }
1197 
1198         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1199 
1200         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1201         
1202         result->numparams = 0;
1203         result->param_info = NULL;
1204         
1205         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
1206         if (rc == SQL_INVALID_HANDLE) {
1207                 efree(result);
1208                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1209                 RETURN_FALSE;
1210         }
1211 
1212         if (rc == SQL_ERROR) {
1213                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1214                 efree(result);
1215                 RETURN_FALSE;
1216         }
1217 
1218 #ifdef HAVE_SQL_EXTENDED_FETCH
1219         /* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1220            whether Driver supports ExtendedFetch */
1221         rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1222         if (rc == SQL_SUCCESS) {
1223                 if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1224                         /* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1225                            type if not possible.
1226                         */
1227                         SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1228                 }
1229         } else {
1230                 result->fetch_abs = 0;
1231         }
1232 #endif
1233 
1234         rc = SQLPrepare(result->stmt, query, SQL_NTS);
1235         switch (rc) {
1236                 case SQL_SUCCESS:
1237                         break;
1238                 case SQL_SUCCESS_WITH_INFO:
1239                         odbc_sql_error(conn, result->stmt, "SQLPrepare");
1240                         break;
1241                 default:
1242                         odbc_sql_error(conn, result->stmt, "SQLPrepare");
1243                         RETURN_FALSE;
1244         }
1245         
1246         SQLNumParams(result->stmt, &(result->numparams));
1247         SQLNumResultCols(result->stmt, &(result->numcols));
1248 
1249         if (result->numcols > 0) {
1250                 if (!odbc_bindcols(result TSRMLS_CC)) {
1251                         efree(result);
1252                         RETURN_FALSE;
1253                 }
1254         } else {
1255                 result->values = NULL;
1256         }
1257         zend_list_addref(conn->id);
1258         result->conn_ptr = conn;
1259         result->fetched = 0;
1260 
1261         result->param_info = (odbc_param_info *) safe_emalloc(sizeof(odbc_param_info), result->numparams, 0);
1262         for (i=0;i<result->numparams;i++) {
1263                 rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)(i+1), &result->param_info[i].sqltype, &result->param_info[i].precision,
1264                                                                                                         &result->param_info[i].scale, &result->param_info[i].nullable);
1265                 if (rc == SQL_ERROR) {
1266                         odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter");
1267                         SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1268                         efree(result->param_info);
1269                         efree(result);
1270                         RETURN_FALSE;
1271                 }
1272         }
1273         ZEND_REGISTER_RESOURCE(return_value, result, le_result);  
1274 }
1275 /* }}} */
1276 
1277 /*
1278  * Execute prepared SQL statement. Supports only input parameters.
1279  */
1280 
1281 /* {{{ proto bool odbc_execute(resource result_id [, array parameters_array])
1282    Execute a prepared statement */
1283 PHP_FUNCTION(odbc_execute)
1284 { 
1285         zval *pv_res, *pv_param_arr, **tmp;
1286         typedef struct params_t {
1287                 SQLLEN vallen;
1288                 int fp;
1289         } params_t;
1290         params_t *params = NULL;
1291         char *filename;
1292         unsigned char otype;
1293         SQLSMALLINT ctype;
1294         odbc_result *result;
1295         int numArgs, i, ne;
1296         RETCODE rc;
1297         
1298         numArgs = ZEND_NUM_ARGS();
1299         
1300         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|a", &pv_res, &pv_param_arr) == FAILURE) {
1301                 return;
1302         }
1303 
1304         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1305         
1306         /* XXX check for already bound parameters*/
1307         if (result->numparams > 0 && numArgs == 1) {
1308                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No parameters to SQL statement given");
1309                 RETURN_FALSE;
1310         }
1311 
1312         if (result->numparams > 0) {
1313                 if ((ne = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr))) < result->numparams) {
1314                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"Not enough parameters (%d should be %d) given", ne, result->numparams);
1315                         RETURN_FALSE;
1316                 }
1317 
1318                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
1319                 params = (params_t *)safe_emalloc(sizeof(params_t), result->numparams, 0);
1320                 for(i = 0; i < result->numparams; i++) {
1321                         params[i].fp = -1;
1322                 }
1323                 
1324                 for(i = 1; i <= result->numparams; i++) {
1325                         if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
1326                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
1327                                 SQLFreeStmt(result->stmt,SQL_RESET_PARAMS);
1328                                 for (i = 0; i < result->numparams; i++) {
1329                                         if (params[i].fp != -1) {
1330                                                 close(params[i].fp);
1331                                         }
1332                                 }
1333                                 efree(params);
1334                                 RETURN_FALSE;
1335                         }
1336 
1337                         otype = (*tmp)->type;
1338                         convert_to_string_ex(tmp);
1339                         if (Z_TYPE_PP(tmp) != IS_STRING) {
1340                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
1341                                 SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1342                                 for (i = 0; i < result->numparams; i++) {
1343                                         if (params[i].fp != -1) {
1344                                                 close(params[i].fp);
1345                                         }
1346                                 }
1347                                 efree(params);
1348                                 RETURN_FALSE;
1349                         }
1350                         
1351                         params[i-1].vallen = Z_STRLEN_PP(tmp);
1352                         params[i-1].fp = -1;
1353 
1354                         if (IS_SQL_BINARY(result->param_info[i-1].sqltype)) {
1355                                 ctype = SQL_C_BINARY;
1356                         } else {
1357                                 ctype = SQL_C_CHAR;
1358                         }
1359 
1360                         if (Z_STRLEN_PP(tmp) > 2 &&
1361                                 Z_STRVAL_PP(tmp)[0] == '\'' &&
1362                                 Z_STRVAL_PP(tmp)[Z_STRLEN_PP(tmp) - 1] == '\'') {
1363                                         
1364                                 if (CHECK_ZVAL_NULL_PATH(*tmp)) {
1365                                         RETURN_FALSE;
1366                                 }
1367                                 filename = estrndup(&Z_STRVAL_PP(tmp)[1], Z_STRLEN_PP(tmp) - 2);
1368                                 filename[strlen(filename)] = '\0';
1369 
1370                                 /* Check the basedir */
1371                                 if (php_check_open_basedir(filename TSRMLS_CC)) {
1372                                         efree(filename);
1373                                         SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1374                                         for (i = 0; i < result->numparams; i++) {
1375                                                 if (params[i].fp != -1) {
1376                                                         close(params[i].fp);
1377                                                 }
1378                                         }
1379                                         efree(params);
1380                                         RETURN_FALSE;
1381                                 }
1382 
1383                                 if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
1384                                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"Can't open file %s", filename);
1385                                         SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1386                                         for (i = 0; i < result->numparams; i++) {
1387                                                 if (params[i].fp != -1) {
1388                                                         close(params[i].fp);
1389                                                 }
1390                                         }
1391                                         efree(params);
1392                                         efree(filename);
1393                                         RETURN_FALSE;
1394                                 }
1395 
1396                                 efree(filename);
1397 
1398                                 params[i-1].vallen = SQL_LEN_DATA_AT_EXEC(0);
1399 
1400                                 rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1401                                                                           ctype, result->param_info[i-1].sqltype, result->param_info[i-1].precision, result->param_info[i-1].scale,
1402                                                                           (void *)params[i-1].fp, 0,
1403                                                                           &params[i-1].vallen);
1404                         } else {
1405 #ifdef HAVE_DBMAKER
1406                                 precision = params[i-1].vallen;
1407 #endif
1408                                 if (otype == IS_NULL) {
1409                                         params[i-1].vallen = SQL_NULL_DATA;
1410                                 }
1411 
1412                                 rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
1413                                                                           ctype, result->param_info[i-1].sqltype, result->param_info[i-1].precision, result->param_info[i-1].scale,
1414                                                                           Z_STRVAL_PP(tmp), 0,
1415                                                                           &params[i-1].vallen);
1416                         }
1417                         if (rc == SQL_ERROR) {
1418                                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");     
1419                                 SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1420                                 for (i = 0; i < result->numparams; i++) {
1421                                         if (params[i].fp != -1) {
1422                                                 close(params[i].fp);
1423                                         }
1424                                 }
1425                                 efree(params);
1426                                 RETURN_FALSE;
1427                         }
1428                         zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
1429                 }
1430         }
1431         /* Close cursor, needed for doing multiple selects */
1432         rc = SQLFreeStmt(result->stmt, SQL_CLOSE);
1433 
1434         if (rc == SQL_ERROR) {
1435                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLFreeStmt");  
1436         }
1437 
1438         rc = SQLExecute(result->stmt);
1439 
1440         result->fetched = 0;
1441         if (rc == SQL_NEED_DATA) {
1442                 char buf[4096];
1443                 int fp, nbytes;
1444                 while (rc == SQL_NEED_DATA) {
1445                         rc = SQLParamData(result->stmt, (void*)&fp);
1446                         if (rc == SQL_NEED_DATA) {
1447                                 while ((nbytes = read(fp, &buf, 4096)) > 0) {
1448                                         SQLPutData(result->stmt, (void*)&buf, nbytes);
1449                                 }
1450                         }
1451                 }
1452         } else {
1453                 switch (rc) {
1454                         case SQL_SUCCESS:
1455                                 break;
1456                         case SQL_NO_DATA_FOUND:
1457                         case SQL_SUCCESS_WITH_INFO:
1458                                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1459                                 break;
1460                         default:
1461                                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
1462                                 RETVAL_FALSE;
1463                 }
1464         }       
1465         
1466         if (result->numparams > 0) {
1467                 SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
1468                 for(i = 0; i < result->numparams; i++) {
1469                         if (params[i].fp != -1) {
1470                                 close(params[i].fp);
1471                         }
1472                 }
1473                 efree(params);
1474         }
1475 
1476         if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO || rc == SQL_NO_DATA_FOUND) {
1477                 RETVAL_TRUE;
1478         }
1479 
1480         if (result->numcols == 0) {
1481                 SQLNumResultCols(result->stmt, &(result->numcols));
1482 
1483                 if (result->numcols > 0) {
1484                         if (!odbc_bindcols(result TSRMLS_CC)) {
1485                                 efree(result);
1486                                 RETVAL_FALSE;
1487                         }
1488                 } else {
1489                         result->values = NULL;
1490                 }
1491         }
1492 }
1493 /* }}} */
1494 
1495 /* {{{ proto string odbc_cursor(resource result_id)
1496    Get cursor name */
1497 PHP_FUNCTION(odbc_cursor)
1498 {
1499         zval *pv_res;
1500         SQLUSMALLINT max_len;
1501         SQLSMALLINT len;
1502         char *cursorname;
1503         odbc_result *result;
1504         RETCODE rc;
1505         
1506         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1507                 return;
1508         }
1509 
1510         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1511 
1512         rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len);
1513         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1514                 RETURN_FALSE;
1515         }
1516         
1517         if (max_len > 0) {
1518                 cursorname = emalloc(max_len + 1);
1519                 rc = SQLGetCursorName(result->stmt,cursorname,(SQLSMALLINT)max_len,&len);
1520                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1521                         char        state[6];     /* Not used */
1522                         SQLINTEGER  error;        /* Not used */
1523                         char        errormsg[SQL_MAX_MESSAGE_LENGTH];
1524                         SQLSMALLINT errormsgsize; /* Not used */
1525 
1526                         SQLError( result->conn_ptr->henv, result->conn_ptr->hdbc,
1527                                                 result->stmt, state, &error, errormsg,
1528                                                 sizeof(errormsg)-1, &errormsgsize);
1529                         if (!strncmp(state,"S1015",5)) {
1530                                 snprintf(cursorname, max_len+1, "php_curs_%d", (int)result->stmt);
1531                                 if (SQLSetCursorName(result->stmt,cursorname,SQL_NTS) != SQL_SUCCESS) {
1532                                         odbc_sql_error(result->conn_ptr, result->stmt, "SQLSetCursorName");
1533                                         RETVAL_FALSE;
1534                                 } else {
1535                                         RETVAL_STRING(cursorname,1);
1536                                 }
1537                         } else {
1538                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
1539                                 RETVAL_FALSE;
1540                         }
1541                 } else {
1542                         RETVAL_STRING(cursorname,1);
1543                 }
1544                 efree(cursorname);
1545         } else {
1546                 RETVAL_FALSE;
1547         }
1548 }
1549 /* }}} */
1550 
1551 #ifdef HAVE_SQLDATASOURCES
1552 /* {{{ proto array odbc_data_source(resource connection_id, int fetch_type)
1553    Return information about the currently connected data source */
1554 PHP_FUNCTION(odbc_data_source)
1555 {
1556         zval *zv_conn;
1557         long zv_fetch_type;
1558         RETCODE rc = 0; /* assume all is good */
1559         odbc_connection *conn;
1560         UCHAR server_name[100], desc[200];
1561         SQLSMALLINT len1=0, len2=0, fetch_type;
1562 
1563         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zv_conn, &zv_fetch_type) == FAILURE) {
1564                 return;
1565         }
1566 
1567         fetch_type = (SQLSMALLINT) zv_fetch_type;
1568 
1569         if (!(fetch_type == SQL_FETCH_FIRST || fetch_type == SQL_FETCH_NEXT)) {
1570                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fetch type (%d)", fetch_type);
1571                 RETURN_FALSE;
1572         }
1573 
1574         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &zv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1575 
1576         /* now we have the "connection" lets call the DataSource object */
1577         rc = SQLDataSources(conn->henv, 
1578                         fetch_type,
1579                         server_name,
1580                         (SQLSMALLINT)sizeof(server_name),
1581                         &len1,
1582                         desc, 
1583                         (SQLSMALLINT)sizeof(desc),
1584                         &len2);
1585 
1586         if (rc != SQL_SUCCESS) {
1587                 /* ummm.... he did it */
1588                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLDataSources");
1589                 RETURN_FALSE;
1590         }
1591 
1592         if (len1 == 0 || len2 == 0) {
1593                 /* we have a non-valid entry... so stop the looping */
1594                 RETURN_FALSE;
1595         }
1596 
1597         array_init(return_value);
1598 
1599         add_assoc_string_ex(return_value, "server", sizeof("server"), server_name, 1);
1600         add_assoc_string_ex(return_value, "description", sizeof("description"), desc, 1);
1601 
1602 }
1603 /* }}} */
1604 #endif /* HAVE_SQLDATASOURCES */
1605 
1606 /* {{{ proto resource odbc_exec(resource connection_id, string query [, int flags])
1607    Prepare and execute an SQL statement */
1608 /* XXX Use flags */
1609 PHP_FUNCTION(odbc_exec)
1610 {
1611         zval *pv_conn;
1612         long pv_flags;
1613         char *query;
1614         int numArgs, query_len;
1615         odbc_result *result = NULL;
1616         odbc_connection *conn;
1617         RETCODE rc;
1618 #ifdef HAVE_SQL_EXTENDED_FETCH
1619         SQLUINTEGER      scrollopts;
1620 #endif
1621 
1622         numArgs = ZEND_NUM_ARGS();
1623         
1624         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &pv_conn, &query, &query_len, &pv_flags) == FAILURE) {
1625                 return;
1626         }
1627 
1628         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
1629                 
1630         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
1631 
1632         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
1633         if (rc == SQL_INVALID_HANDLE) {
1634                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
1635                 efree(result);
1636                 RETURN_FALSE;
1637         }
1638 
1639         if (rc == SQL_ERROR) {
1640                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
1641                 efree(result);
1642                 RETURN_FALSE;
1643         }
1644         
1645 #ifdef HAVE_SQL_EXTENDED_FETCH
1646         /* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
1647            whether Driver supports ExtendedFetch */
1648         rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
1649         if (rc == SQL_SUCCESS) {
1650                 if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
1651                         /* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
1652                            type if not possible.
1653                          */
1654                         SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
1655                 }
1656         } else {
1657                 result->fetch_abs = 0;
1658         }
1659 #endif
1660 
1661         rc = SQLExecDirect(result->stmt, query, SQL_NTS);
1662         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) { 
1663                 /* XXX FIXME we should really check out SQLSTATE with SQLError
1664                  * in case rc is SQL_SUCCESS_WITH_INFO here.
1665                  */
1666                 odbc_sql_error(conn, result->stmt, "SQLExecDirect"); 
1667                 SQLFreeStmt(result->stmt, SQL_DROP);
1668                 efree(result);
1669                 RETURN_FALSE;
1670         }
1671 
1672         SQLNumResultCols(result->stmt, &(result->numcols));
1673         
1674         /* For insert, update etc. cols == 0 */
1675         if (result->numcols > 0) {
1676                 if (!odbc_bindcols(result TSRMLS_CC)) {
1677                         efree(result);
1678                         RETURN_FALSE;
1679                 }
1680         } else {
1681                 result->values = NULL;
1682         }
1683         zend_list_addref(conn->id);
1684         result->conn_ptr = conn;
1685         result->fetched = 0;
1686         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1687 }
1688 /* }}} */
1689 
1690 #ifdef PHP_ODBC_HAVE_FETCH_HASH
1691 #define ODBC_NUM  1
1692 #define ODBC_OBJECT  2
1693 
1694 /* {{{ php_odbc_fetch_hash */
1695 static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1696 {
1697         int i;
1698         odbc_result *result;
1699         RETCODE rc;
1700         SQLSMALLINT sql_c_type;
1701         char *buf = NULL;
1702 #ifdef HAVE_SQL_EXTENDED_FETCH
1703         SQLULEN crow;
1704         SQLUSMALLINT RowStatus[1];
1705         SQLLEN rownum;
1706         zval *pv_res, *tmp;
1707         long pv_row = -1;
1708 
1709         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
1710                 return;
1711         }
1712         
1713         rownum = pv_row;
1714 #else
1715         zval *pv_res, *tmp;
1716 
1717         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1718                 return;
1719         }
1720 #endif
1721 
1722         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1723 
1724         if (result->numcols == 0) {
1725                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1726                 RETURN_FALSE;
1727         }
1728 
1729 #ifdef HAVE_SQL_EXTENDED_FETCH
1730         if (result->fetch_abs) {
1731                 if (rownum > 0) {
1732                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1733                 } else {
1734                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1735                 }
1736         } else
1737 #endif
1738         rc = SQLFetch(result->stmt);
1739 
1740         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1741                 RETURN_FALSE;
1742         }
1743         
1744         array_init(return_value);
1745         
1746 #ifdef HAVE_SQL_EXTENDED_FETCH
1747         if (rownum > 0 && result->fetch_abs)
1748                 result->fetched = rownum;
1749         else
1750 #endif
1751                 result->fetched++;
1752 
1753         for(i = 0; i < result->numcols; i++) {
1754                 ALLOC_INIT_ZVAL(tmp);
1755                 Z_TYPE_P(tmp) = IS_STRING;
1756                 Z_STRLEN_P(tmp) = 0;
1757                 sql_c_type = SQL_C_CHAR;
1758 
1759                 switch(result->values[i].coltype) {
1760                         case SQL_BINARY:
1761                         case SQL_VARBINARY:
1762                         case SQL_LONGVARBINARY:
1763                                 if (result->binmode <= 0) {
1764                                         Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1765                                         break;
1766                                 }
1767                                 if (result->binmode == 1) {
1768                                         sql_c_type = SQL_C_BINARY;
1769                                 }
1770                         case SQL_LONGVARCHAR:
1771 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
1772                         case SQL_WLONGVARCHAR:
1773 #endif
1774                                 if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1775                                         Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1776                                         break;
1777                                 }                               
1778                                 if (buf == NULL) {
1779                                         buf = emalloc(result->longreadlen + 1);
1780                                 }
1781                                 
1782                                 rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1), sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1783 
1784                                 if (rc == SQL_ERROR) {
1785                                         odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1786                                         efree(buf);
1787                                         RETURN_FALSE;
1788                                 }
1789 
1790                                 if (rc == SQL_SUCCESS_WITH_INFO) {
1791                                         Z_STRLEN_P(tmp) = result->longreadlen;
1792                                 } else if (result->values[i].vallen == SQL_NULL_DATA) {
1793                                         ZVAL_NULL(tmp);
1794                                         break;
1795                                 } else {
1796                                         Z_STRLEN_P(tmp) = result->values[i].vallen;
1797                                 }
1798                                 Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1799                                 break;
1800 
1801                         default:
1802                                 if (result->values[i].vallen == SQL_NULL_DATA) {
1803                                         ZVAL_NULL(tmp);
1804                                         break;
1805                                 }
1806                                 Z_STRLEN_P(tmp) = result->values[i].vallen;
1807                                 Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1808                                 break;
1809                 }
1810 
1811                 if (result_type & ODBC_NUM) {
1812                         zend_hash_index_update(Z_ARRVAL_P(return_value), i, &tmp, sizeof(zval *), NULL);
1813                 } else {
1814                         if (!*(result->values[i].name) && Z_TYPE_P(tmp) == IS_STRING) {
1815                                 zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(tmp),     Z_STRLEN_P(tmp)+1, &tmp, sizeof(zval *), NULL);
1816                         } else {
1817                                 zend_hash_update(Z_ARRVAL_P(return_value), result->values[i].name, strlen(result->values[i].name)+1, &tmp, sizeof(zval *), NULL);
1818                         }
1819                 }
1820         }
1821         if (buf) {
1822                 efree(buf);
1823         }
1824 }
1825 /* }}} */
1826 
1827 
1828 /* {{{ proto object odbc_fetch_object(int result [, int rownumber])
1829    Fetch a result row as an object */
1830 PHP_FUNCTION(odbc_fetch_object)
1831 {
1832         php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1833         if (Z_TYPE_P(return_value) == IS_ARRAY) {
1834                 object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1835         }
1836 }
1837 /* }}} */
1838 
1839 /* {{{ proto array odbc_fetch_array(int result [, int rownumber])
1840    Fetch a result row as an associative array */
1841 PHP_FUNCTION(odbc_fetch_array)
1842 {
1843         php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
1844 }
1845 /* }}} */
1846 #endif
1847 
1848 /* {{{ proto int odbc_fetch_into(resource result_id, array &result_array, [, int rownumber])
1849    Fetch one result row into an array */ 
1850 PHP_FUNCTION(odbc_fetch_into)
1851 {
1852         int i;
1853         odbc_result *result;
1854         RETCODE rc;
1855         SQLSMALLINT sql_c_type;
1856         char *buf = NULL;
1857         zval *pv_res, **pv_res_arr, *tmp;
1858 #ifdef HAVE_SQL_EXTENDED_FETCH
1859         long pv_row = 0;
1860         SQLULEN crow;
1861         SQLUSMALLINT RowStatus[1];
1862         SQLLEN rownum = -1;
1863 #endif /* HAVE_SQL_EXTENDED_FETCH */
1864 
1865 #ifdef HAVE_SQL_EXTENDED_FETCH
1866         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) {
1867                 return;
1868         }
1869         
1870         rownum = pv_row;
1871 #else
1872         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_res_arr) == FAILURE) {
1873                 return;
1874         }
1875 #endif /* HAVE_SQL_EXTENDED_FETCH */
1876 
1877         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1878         
1879         if (result->numcols == 0) {
1880                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1881                 RETURN_FALSE;
1882         }
1883         
1884         if (Z_TYPE_PP(pv_res_arr) != IS_ARRAY) {
1885                 array_init(*pv_res_arr);
1886         }
1887 
1888 #ifdef HAVE_SQL_EXTENDED_FETCH
1889         if (result->fetch_abs) {
1890                 if (rownum > 0) {
1891                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
1892                 } else {
1893                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
1894                 }
1895         } else
1896 #endif
1897                 rc = SQLFetch(result->stmt);
1898 
1899         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1900                 RETURN_FALSE;
1901         }
1902 
1903 #ifdef HAVE_SQL_EXTENDED_FETCH
1904         if (rownum > 0 && result->fetch_abs)
1905                 result->fetched = rownum;
1906         else
1907 #endif
1908                 result->fetched++;
1909 
1910         for(i = 0; i < result->numcols; i++) {
1911                 MAKE_STD_ZVAL(tmp);
1912                 Z_TYPE_P(tmp) = IS_STRING;
1913                 Z_STRLEN_P(tmp) = 0;
1914                 sql_c_type = SQL_C_CHAR;
1915 
1916                 switch(result->values[i].coltype) {
1917                         case SQL_BINARY:
1918                         case SQL_VARBINARY:
1919                         case SQL_LONGVARBINARY:
1920                                 if (result->binmode <= 0) {
1921                                         Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1922                                         break;
1923                                 }
1924                                 if (result->binmode == 1) sql_c_type = SQL_C_BINARY; 
1925 
1926                         case SQL_LONGVARCHAR:
1927 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
1928                         case SQL_WLONGVARCHAR:
1929 #endif
1930                                 if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
1931                                         Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
1932                                         break;
1933                                 }
1934 
1935                                 if (buf == NULL) {
1936                                         buf = emalloc(result->longreadlen + 1);
1937                                 }
1938                                 rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
1939 
1940                                 if (rc == SQL_ERROR) {
1941                                         odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
1942                                         efree(buf);
1943                                         RETURN_FALSE;
1944                                 }
1945                                 if (rc == SQL_SUCCESS_WITH_INFO) {
1946                                         Z_STRLEN_P(tmp) = result->longreadlen;
1947                                 } else if (result->values[i].vallen == SQL_NULL_DATA) {
1948                                         ZVAL_NULL(tmp);
1949                                         break;
1950                                 } else {
1951                                         Z_STRLEN_P(tmp) = result->values[i].vallen;
1952                                 }
1953                                 Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
1954                                 break;
1955 
1956                         default:
1957                                 if (result->values[i].vallen == SQL_NULL_DATA) {
1958                                         ZVAL_NULL(tmp);
1959                                         break;
1960                                 }
1961                                 Z_STRLEN_P(tmp) = result->values[i].vallen;
1962                                 Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
1963                                 break;
1964                 }
1965                 zend_hash_index_update(Z_ARRVAL_PP(pv_res_arr), i, &tmp, sizeof(zval *), NULL);
1966         }
1967         if (buf) efree(buf);
1968         RETURN_LONG(result->numcols);   
1969 }
1970 /* }}} */
1971 
1972 /* {{{ proto bool solid_fetch_prev(resource result_id)
1973    */ 
1974 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
1975 PHP_FUNCTION(solid_fetch_prev)
1976 {
1977         odbc_result *result;
1978         RETCODE rc;
1979         zval *pv_res;
1980         
1981         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
1982                 return;
1983         }
1984         
1985         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
1986         if (result->numcols == 0) {
1987                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
1988                 RETURN_FALSE;
1989         }
1990         rc = SQLFetchPrev(result->stmt);
1991 
1992         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
1993                 RETURN_FALSE;
1994         }
1995 
1996         if (result->fetched > 1) {
1997                 result->fetched--;
1998         }
1999 
2000         RETURN_TRUE;
2001 }
2002 #endif
2003 /* }}} */
2004 
2005 /* {{{ proto bool odbc_fetch_row(resource result_id [, int row_number])
2006    Fetch a row */
2007 PHP_FUNCTION(odbc_fetch_row)
2008 {
2009         SQLLEN rownum;
2010         odbc_result *result;
2011         RETCODE rc;
2012         zval *pv_res;
2013         long pv_row = 1;
2014 #ifdef HAVE_SQL_EXTENDED_FETCH
2015         SQLULEN crow;
2016         SQLUSMALLINT RowStatus[1];
2017 #endif
2018 
2019         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
2020                 return;
2021         }
2022         
2023         rownum = pv_row;
2024         
2025         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2026         
2027         if (result->numcols == 0) {
2028                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2029                 RETURN_FALSE;
2030         }
2031 
2032 #ifdef HAVE_SQL_EXTENDED_FETCH
2033         if (result->fetch_abs) {
2034                 if (ZEND_NUM_ARGS() > 1) {
2035                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
2036                 } else {
2037                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2038                 }
2039         } else
2040 #endif
2041                 rc = SQLFetch(result->stmt);
2042 
2043         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2044                 RETURN_FALSE;
2045         }
2046         
2047         if (ZEND_NUM_ARGS() > 1) {
2048                 result->fetched = rownum;
2049         } else {
2050                 result->fetched++;
2051         }
2052         
2053         RETURN_TRUE;
2054 }       
2055 /* }}} */
2056 
2057 /* {{{ proto mixed odbc_result(resource result_id, mixed field)
2058    Get result data */ 
2059 PHP_FUNCTION(odbc_result)
2060 {
2061         char *field;
2062         int field_ind;
2063         SQLSMALLINT sql_c_type = SQL_C_CHAR;
2064         odbc_result *result;
2065         int i = 0;
2066         RETCODE rc;
2067         SQLLEN  fieldsize;
2068         zval *pv_res, **pv_field;
2069 #ifdef HAVE_SQL_EXTENDED_FETCH
2070         SQLULEN crow;
2071         SQLUSMALLINT RowStatus[1];
2072 #endif
2073 
2074         field_ind = -1;
2075         field = NULL;
2076 
2077         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_field) == FAILURE) {
2078                 return;
2079         }
2080         
2081         if (Z_TYPE_PP(pv_field) == IS_STRING) {
2082                 field = Z_STRVAL_PP(pv_field);
2083         } else {
2084                 convert_to_long_ex(pv_field);
2085                 field_ind = Z_LVAL_PP(pv_field) - 1;
2086         }
2087         
2088         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2089         
2090         if ((result->numcols == 0)) {
2091                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2092                 RETURN_FALSE;
2093         }
2094         
2095         /* get field index if the field parameter was a string */
2096         if (field != NULL) {
2097                 if (result->values == NULL) {
2098                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set contains no data");
2099                         RETURN_FALSE;
2100                 }
2101 
2102                 for(i = 0; i < result->numcols; i++) {
2103                         if (!strcasecmp(result->values[i].name, field)) {
2104                                 field_ind = i;
2105                                 break;
2106                         }
2107                 }
2108 
2109                 if (field_ind < 0) {
2110                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field %s not found", field);
2111                         RETURN_FALSE;
2112                 }
2113         } else {
2114                 /* check for limits of field_ind if the field parameter was an int */
2115                 if (field_ind >= result->numcols || field_ind < 0) {
2116                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index is larger than the number of fields");
2117                         RETURN_FALSE;
2118                 }
2119         }
2120 
2121         if (result->fetched == 0) {
2122                 /* User forgot to call odbc_fetch_row(), or wants to reload the results, do it now */
2123 #ifdef HAVE_SQL_EXTENDED_FETCH
2124                 if (result->fetch_abs)
2125                         rc = SQLExtendedFetch(result->stmt, SQL_FETCH_NEXT, 1, &crow,RowStatus);
2126                 else
2127 #endif
2128                         rc = SQLFetch(result->stmt);
2129 
2130                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2131                         RETURN_FALSE;
2132                 }
2133                 
2134                 result->fetched++;
2135         }
2136 
2137         switch(result->values[field_ind].coltype) {
2138                 case SQL_BINARY:
2139                 case SQL_VARBINARY:
2140                 case SQL_LONGVARBINARY:
2141                         if (result->binmode <= 1) {
2142                                 sql_c_type = SQL_C_BINARY;
2143                         }
2144                         if (result->binmode <= 0) {
2145                                 break; 
2146                         }
2147                 case SQL_LONGVARCHAR:
2148 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2149                 case SQL_WLONGVARCHAR:
2150 #endif
2151                         if (IS_SQL_LONG(result->values[field_ind].coltype)) {
2152                                 if (result->longreadlen <= 0) {
2153                                    break;
2154                                 } else {
2155                                    fieldsize = result->longreadlen;
2156                                 }
2157                         } else {
2158                            PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(field_ind + 1), 
2159                                                                 (SQLUSMALLINT)((sql_c_type == SQL_C_BINARY) ? SQL_COLUMN_LENGTH :
2160                                                                 SQL_COLUMN_DISPLAY_SIZE),
2161                                                                 NULL, 0, NULL, &fieldsize);
2162                         }
2163                         /* For char data, the length of the returned string will be longreadlen - 1 */
2164                         fieldsize = (result->longreadlen <= 0) ? 4096 : result->longreadlen;
2165                         field = emalloc(fieldsize);
2166 
2167                 /* SQLGetData will truncate CHAR data to fieldsize - 1 bytes and append \0.
2168                  * For binary data it is truncated to fieldsize bytes. 
2169                  */
2170                         rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1), sql_c_type,
2171                                                         field, fieldsize, &result->values[field_ind].vallen);
2172 
2173                         if (rc == SQL_ERROR) {
2174                                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2175                                 efree(field);
2176                                 RETURN_FALSE;
2177                         }
2178 
2179                         if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2180                                 efree(field);
2181                                 RETURN_NULL();
2182                         } else if (rc == SQL_NO_DATA_FOUND) {
2183                                 efree(field);
2184                                 RETURN_FALSE;
2185                         }
2186                         /* Reduce fieldlen by 1 if we have char data. One day we might 
2187                            have binary strings... */
2188                         if ((result->values[field_ind].coltype == SQL_LONGVARCHAR)
2189 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2190                             || (result->values[field_ind].coltype == SQL_WLONGVARCHAR)
2191 #endif
2192                         ) {
2193                                 fieldsize -= 1;
2194                         }
2195                         /* Don't duplicate result, saves one emalloc.
2196                            For SQL_SUCCESS, the length is in vallen.
2197                          */
2198                         RETURN_STRINGL(field, (rc == SQL_SUCCESS_WITH_INFO) ? fieldsize : result->values[field_ind].vallen, 0);
2199                         break;
2200                         
2201                 default:
2202                         if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2203                                 RETURN_NULL();
2204                         } else {
2205                                 RETURN_STRINGL(result->values[field_ind].value, result->values[field_ind].vallen, 1);
2206                         }
2207                         break;
2208         }
2209 
2210 /* If we come here, output unbound LONG and/or BINARY column data to the client */
2211         
2212         /* We emalloc 1 byte more for SQL_C_CHAR (trailing \0) */
2213         fieldsize = (sql_c_type == SQL_C_CHAR) ? 4096 : 4095;
2214         field = emalloc(fieldsize);
2215         
2216         /* Call SQLGetData() until SQL_SUCCESS is returned */
2217         while(1) {
2218                 rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1),sql_c_type, field, fieldsize, &result->values[field_ind].vallen);
2219 
2220                 if (rc == SQL_ERROR) {
2221                         odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2222                         efree(field);
2223                         RETURN_FALSE;
2224                 }
2225                 
2226                 if (result->values[field_ind].vallen == SQL_NULL_DATA) {
2227                         efree(field);
2228                         RETURN_NULL();
2229                 }
2230                 /* chop the trailing \0 by outputing only 4095 bytes */
2231                 PHPWRITE(field,(rc == SQL_SUCCESS_WITH_INFO) ? 4095 : result->values[field_ind].vallen);
2232 
2233                 if (rc == SQL_SUCCESS) { /* no more data avail */
2234                         efree(field);
2235                         RETURN_TRUE;
2236                 }
2237         }
2238         RETURN_TRUE;
2239 }
2240 /* }}} */
2241 
2242 /* {{{ proto int odbc_result_all(resource result_id [, string format])
2243    Print result as HTML table */
2244 PHP_FUNCTION(odbc_result_all)
2245 {
2246         char *buf = NULL;
2247         odbc_result *result;
2248         RETCODE rc;
2249         zval *pv_res;
2250         char *pv_format = NULL;
2251         int i, pv_format_len = 0;
2252         SQLSMALLINT sql_c_type;
2253 #ifdef HAVE_SQL_EXTENDED_FETCH
2254         SQLULEN crow;
2255         SQLUSMALLINT RowStatus[1];
2256 #endif
2257 
2258         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) {
2259                 return;
2260         }
2261                                 
2262         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2263         
2264         if (result->numcols == 0) {
2265                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2266                 RETURN_FALSE;
2267         }
2268 #ifdef HAVE_SQL_EXTENDED_FETCH
2269         if (result->fetch_abs)
2270                 rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2271         else
2272 #endif  
2273                 rc = SQLFetch(result->stmt);
2274 
2275         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2276                 php_printf("<h2>No rows found</h2>\n");
2277                 RETURN_LONG(0);
2278         }
2279         
2280         /* Start table tag */
2281         if (ZEND_NUM_ARGS() == 1) {
2282                 php_printf("<table><tr>");
2283         } else {
2284                 php_printf("<table %s ><tr>", pv_format);
2285         }
2286         
2287         for (i = 0; i < result->numcols; i++) {
2288                 php_printf("<th>%s</th>", result->values[i].name);
2289         }
2290 
2291         php_printf("</tr>\n");
2292 
2293         while(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
2294                 result->fetched++;
2295                 php_printf("<tr>");
2296                 for(i = 0; i < result->numcols; i++) {
2297                         sql_c_type = SQL_C_CHAR;
2298                         switch(result->values[i].coltype) {
2299                                 case SQL_BINARY:
2300                                 case SQL_VARBINARY:
2301                                 case SQL_LONGVARBINARY:
2302                                         if (result->binmode <= 0) {
2303                                                 php_printf("<td>Not printable</td>");
2304                                                 break;
2305                                         }
2306                                         if (result->binmode <= 1) sql_c_type = SQL_C_BINARY; 
2307                                 case SQL_LONGVARCHAR:
2308 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
2309                                 case SQL_WLONGVARCHAR:
2310 #endif
2311                                         if (IS_SQL_LONG(result->values[i].coltype) && 
2312                                                 result->longreadlen <= 0) {
2313                                                 php_printf("<td>Not printable</td>"); 
2314                                                 break;
2315                                         }
2316 
2317                                         if (buf == NULL) {
2318                                                 buf = emalloc(result->longreadlen);
2319                                         }
2320 
2321                                         rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen, &result->values[i].vallen);
2322  
2323                                         php_printf("<td>");
2324 
2325                                         if (rc == SQL_ERROR) {
2326                                                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
2327                                                 php_printf("</td></tr></table>");
2328                                                 efree(buf);
2329                                                 RETURN_FALSE;
2330                                         }
2331                                         if (rc == SQL_SUCCESS_WITH_INFO) {
2332                                                 PHPWRITE(buf, result->longreadlen);
2333                                         } else if (result->values[i].vallen == SQL_NULL_DATA) {
2334                                                 php_printf("<td>NULL</td>");
2335                                                 break;
2336                                         } else {
2337                                                 PHPWRITE(buf, result->values[i].vallen);
2338                                         }
2339                                         php_printf("</td>");
2340                                         break;
2341                                 default:
2342                                         if (result->values[i].vallen == SQL_NULL_DATA) {
2343                                                 php_printf("<td>NULL</td>");
2344                                         } else {
2345                                                 php_printf("<td>%s</td>", result->values[i].value);
2346                                         }
2347                                         break;
2348                         }
2349                 }
2350                 php_printf("</tr>\n");
2351 
2352 #ifdef HAVE_SQL_EXTENDED_FETCH
2353                 if (result->fetch_abs)
2354                         rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
2355                 else
2356 #endif
2357                         rc = SQLFetch(result->stmt);            
2358         }
2359         php_printf("</table>\n");
2360         if (buf) efree(buf);
2361         RETURN_LONG(result->fetched);
2362 }
2363 /* }}} */
2364 
2365 /* {{{ proto bool odbc_free_result(resource result_id)
2366    Free resources associated with a result */
2367 PHP_FUNCTION(odbc_free_result)
2368 {
2369         zval *pv_res;
2370         odbc_result *result;
2371         int i;
2372 
2373         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2374                 return;
2375         }
2376 
2377         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2378         if (result->values) {
2379                 for (i = 0; i < result->numcols; i++) {
2380                         if (result->values[i].value) {
2381                                 efree(result->values[i].value);
2382                         }
2383                 }
2384                 efree(result->values);
2385                 result->values = NULL;
2386         }
2387                         
2388         zend_list_delete(Z_LVAL_P(pv_res));
2389         
2390         RETURN_TRUE;
2391 }
2392 /* }}} */
2393 
2394 /* {{{ proto resource odbc_connect(string DSN, string user, string password [, int cursor_option])
2395    Connect to a datasource */
2396 PHP_FUNCTION(odbc_connect)
2397 {
2398         odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2399 }
2400 /* }}} */
2401 
2402 /* {{{ proto resource odbc_pconnect(string DSN, string user, string password [, int cursor_option])
2403    Establish a persistent connection to a datasource */
2404 PHP_FUNCTION(odbc_pconnect)
2405 {
2406         odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2407 }
2408 /* }}} */
2409 
2410 /* {{{ odbc_sqlconnect */
2411 int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent TSRMLS_DC)
2412 {
2413         RETCODE rc;
2414         
2415         *conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent);
2416         (*conn)->persistent = persistent;
2417         SQLAllocEnv(&((*conn)->henv));
2418         SQLAllocConnect((*conn)->henv, &((*conn)->hdbc));
2419         
2420 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) 
2421         SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION,
2422                         SQL_SOLID_XLATOPT_NOCNV);
2423 #endif
2424 #ifdef HAVE_ODBC_ROUTER
2425         {
2426 #define CONNSTRSIZE 2048
2427          char *lpszConnStr = emalloc(CONNSTRSIZE);
2428          if (lpszConnStr && db) {
2429                  short cbszConnStr;
2430                  if (strstr(db, ";")) {
2431                          /* the caller has apparently passed a connection-string */
2432                          if (strstr(db, "uid") || strstr(db, "UID")) {
2433                                  uid = NULL;
2434                          }
2435                          if (strstr(db, "pwd") || strstr(db, "PWD")) {
2436                                  pwd = NULL;
2437                          }
2438                          strlcpy( lpszConnStr, db, CONNSTRSIZE);
2439                  }
2440                  else {
2441                          strcpy(lpszConnStr, "DSN=");
2442                          strlcat(lpszConnStr, db, CONNSTRSIZE);
2443                  }
2444                  if (uid) {
2445                          if (uid[0]) {
2446                                  strlcat(lpszConnStr, ";UID=", CONNSTRSIZE);
2447                                  strlcat(lpszConnStr, uid, CONNSTRSIZE);
2448                                  strlcat(lpszConnStr, ";", CONNSTRSIZE);
2449                          }
2450                          if (pwd) {
2451                                  if (pwd[0]) {
2452                                          strlcat(lpszConnStr, "PWD=", CONNSTRSIZE);
2453                                          strlcat(lpszConnStr, pwd, CONNSTRSIZE);
2454                                          strlcat(lpszConnStr, ";", CONNSTRSIZE);
2455                                  }
2456                          }
2457                  }
2458                  rc = SQLDriverConnect((*conn)->hdbc, NULL, lpszConnStr, SQL_NTS, lpszConnStr, CONNSTRSIZE, &cbszConnStr, SQL_DRIVER_NOPROMPT);
2459                  efree(lpszConnStr);
2460          }
2461         }
2462 #else
2463 #ifdef HAVE_OPENLINK
2464         {
2465                 char dsnbuf[1024];
2466                 short dsnbuflen;
2467 
2468                 rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2469         }
2470 #else
2471         if (cur_opt != SQL_CUR_DEFAULT) {
2472                 rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt);
2473                 if (rc != SQL_SUCCESS) {  /* && rc != SQL_SUCCESS_WITH_INFO ? */
2474                         odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption");
2475                         SQLFreeConnect((*conn)->hdbc);
2476                         pefree(*conn, persistent);
2477                         return FALSE;
2478                 }
2479         }
2480 /*  Possible fix for bug #10250
2481  *  Needs testing on UnixODBC < 2.0.5 though. */
2482 #if defined(HAVE_EMPRESS) || defined(HAVE_UNIXODBC) || defined(PHP_WIN32) || defined (HAVE_IODBC)
2483 /* *  Uncomment the line above, and comment line below to fully test 
2484  * #ifdef HAVE_EMPRESS */
2485         {
2486                 int     direct = 0;
2487                 char    dsnbuf[1024];
2488                 short   dsnbuflen;
2489                 char    *ldb = 0;
2490                 int             ldb_len = 0;
2491 
2492                 if (strstr((char*)db, ";")) {
2493                         direct = 1;
2494                         if (uid && !strstr ((char*)db, "uid") && !strstr((char*)db, "UID")) {
2495                                 spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid, pwd);
2496                         } else {
2497                                 ldb_len = strlen(db)+1;
2498                                 ldb = (char*) emalloc(ldb_len);
2499                                 memcpy(ldb, db, ldb_len);
2500                         }
2501                 }
2502 
2503                 if (direct) {
2504                         rc = SQLDriverConnect((*conn)->hdbc, NULL, ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
2505                 } else {
2506                         rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2507                 }
2508 
2509                 if (ldb) {
2510                         efree(ldb);
2511                 }
2512         }
2513 #else
2514         rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
2515 #endif
2516 #endif
2517 #endif
2518         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2519                 odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect");
2520                 SQLFreeConnect((*conn)->hdbc);
2521                 pefree((*conn), persistent);
2522                 return FALSE;
2523         }
2524 /*      (*conn)->open = 1;*/
2525         return TRUE;
2526 }
2527 /* }}} */
2528 
2529 /* Persistent connections: two list-types le_pconn, le_conn and a plist
2530  * where hashed connection info is stored together with index pointer to
2531  * the actual link of type le_pconn in the list. Only persistent 
2532  * connections get hashed up. Normal connections use existing pconnections.
2533  * Maybe this has to change with regard to transactions on pconnections?
2534  * Possibly set autocommit to on on request shutdown.
2535  *
2536  * We do have to hash non-persistent connections, and reuse connections.
2537  * In the case where two connects were being made, without closing the first
2538  * connect, access violations were occuring.  This is because some of the
2539  * "globals" in this module should actualy be per-connection variables.  I
2540  * simply fixed things to get them working for now.  Shane
2541  */
2542 /* {{{ odbc_do_connect */
2543 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
2544 {
2545         char *db, *uid, *pwd;
2546         int db_len, uid_len, pwd_len;
2547         long pv_opt = SQL_CUR_DEFAULT;
2548         odbc_connection *db_conn;
2549         char *hashed_details;
2550         int hashed_len, cur_opt;
2551 
2552         /*  Now an optional 4th parameter specifying the cursor type
2553          *  defaulting to the cursors default
2554          */
2555         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) {
2556                 return;
2557         }
2558         
2559         cur_opt = pv_opt;
2560         
2561         if (ZEND_NUM_ARGS() > 3) {
2562                 /* Confirm the cur_opt range */
2563                 if (! (cur_opt == SQL_CUR_USE_IF_NEEDED || 
2564                         cur_opt == SQL_CUR_USE_ODBC || 
2565                         cur_opt == SQL_CUR_USE_DRIVER || 
2566                         cur_opt == SQL_CUR_DEFAULT) ) {
2567                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Cursor type (%d)", cur_opt);
2568                         RETURN_FALSE;
2569                 }
2570         }
2571 
2572         if (ODBCG(allow_persistent) <= 0) {
2573                 persistent = 0;
2574         }
2575 
2576         hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt);
2577 
2578         /* FIXME the idea of checking to see if our connection is already persistent
2579                 is good, but it adds a lot of overhead to non-persistent connections.  We
2580                 should look and see if we can fix that somehow */
2581         /* try to find if we already have this link in our persistent list,
2582          * no matter if it is to be persistent or not
2583          */
2584 
2585 try_and_get_another_connection:
2586 
2587         if (persistent) {
2588                 zend_rsrc_list_entry *le;
2589                 
2590                 /* the link is not in the persistent list */
2591                 if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_len + 1, (void **) &le) == FAILURE) {
2592                         zend_rsrc_list_entry new_le;
2593                         
2594                         if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2595                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", ODBCG(num_links));
2596                                 efree(hashed_details);
2597                                 RETURN_FALSE;
2598                         }
2599                         if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) {
2600                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open persistent links (%ld)", ODBCG(num_persistent));
2601                                 efree(hashed_details);
2602                                 RETURN_FALSE;
2603                         }
2604                         
2605                         if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1 TSRMLS_CC)) {
2606                                 efree(hashed_details);
2607                                 RETURN_FALSE;
2608                         }
2609                         
2610                         Z_TYPE(new_le) = le_pconn;
2611                         new_le.ptr = db_conn;
2612                         if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_len + 1, &new_le,
2613                                                 sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2614                                 free(db_conn);
2615                                 efree(hashed_details);
2616                                 RETURN_FALSE;
2617                         }
2618                         ODBCG(num_persistent)++;
2619                         ODBCG(num_links)++;
2620                         db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2621                 } else { /* found connection */
2622                         if (Z_TYPE_P(le) != le_pconn) {
2623                                 RETURN_FALSE;
2624                         }
2625                         /*
2626                          * check to see if the connection is still valid
2627                          */
2628                         db_conn = (odbc_connection *)le->ptr;
2629 
2630                         /*
2631                          * check to see if the connection is still in place (lurcher)
2632                          */
2633                         if(ODBCG(check_persistent)){
2634                                 RETCODE ret;
2635                                 UCHAR d_name[32];
2636                                 SQLSMALLINT len;
2637 
2638                                 ret = SQLGetInfo(db_conn->hdbc, 
2639                                         SQL_DATA_SOURCE_READ_ONLY, 
2640                                         d_name, sizeof(d_name), &len);
2641 
2642                                 if(ret != SQL_SUCCESS || len == 0) {
2643                                         zend_hash_del(&EG(persistent_list), hashed_details, hashed_len + 1);
2644                                         /* Commented out to fix a possible double closure error 
2645                                          * when working with persistent connections as submitted by
2646                                          * bug #15758
2647                                          *
2648                                          * safe_odbc_disconnect(db_conn->hdbc);
2649                                          * SQLFreeConnect(db_conn->hdbc);
2650                                          */
2651                                         goto try_and_get_another_connection;
2652                                 }
2653                         }
2654                 }
2655                 db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
2656         } else { /* non persistent */
2657                 zend_rsrc_list_entry *index_ptr, new_index_ptr;
2658                 
2659                 if (zend_hash_find(&EG(regular_list), hashed_details, hashed_len + 1, (void **) &index_ptr) == SUCCESS) {
2660                         int type, conn_id;
2661                         void *ptr;
2662 
2663                         if (Z_TYPE_P(index_ptr) != le_index_ptr) {
2664                                 RETURN_FALSE;
2665                         }
2666                         conn_id = (int)index_ptr->ptr;
2667                         ptr = zend_list_find(conn_id, &type);   /* check if the connection is still there */
2668 
2669                         if (ptr && (type == le_conn || type == le_pconn)) {
2670                                 zend_list_addref(conn_id);
2671                                 Z_LVAL_P(return_value) = conn_id;
2672                                 Z_TYPE_P(return_value) = IS_RESOURCE;
2673                                 efree(hashed_details);
2674                                 return;
2675                         } else {
2676                                 zend_hash_del(&EG(regular_list), hashed_details, hashed_len + 1);
2677                         }
2678                 }
2679                 if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
2680                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open connections (%ld)",ODBCG(num_links));
2681                         efree(hashed_details);
2682                         RETURN_FALSE;
2683                 }
2684 
2685                 if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0 TSRMLS_CC)) {
2686                         efree(hashed_details);
2687                         RETURN_FALSE;
2688                 }
2689                 db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_conn);
2690                 new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
2691                 Z_TYPE(new_index_ptr) = le_index_ptr;
2692 
2693                 if (zend_hash_update(&EG(regular_list), hashed_details, hashed_len + 1, (void *) &new_index_ptr,
2694                                    sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
2695                         efree(hashed_details);
2696                         RETURN_FALSE;
2697                         /* XXX Free Connection */
2698                 }
2699                 ODBCG(num_links)++;
2700         }
2701         efree(hashed_details);
2702 }
2703 /* }}} */
2704 
2705 /* {{{ proto void odbc_close(resource connection_id)
2706    Close an ODBC connection */
2707 PHP_FUNCTION(odbc_close)
2708 {
2709         zval *pv_conn;
2710         void *ptr;
2711         odbc_connection *conn;
2712         odbc_result *res;
2713         int nument;
2714         int i;
2715         int type;
2716         int is_pconn = 0;
2717         int found_resource_type = le_conn;
2718 
2719         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
2720                 return;
2721         }
2722 
2723         conn = (odbc_connection *) zend_fetch_resource(&pv_conn TSRMLS_CC, -1, "ODBC-Link", &found_resource_type, 2, le_conn, le_pconn);
2724         if (found_resource_type==le_pconn) {
2725                 is_pconn = 1;
2726         }
2727 
2728         nument = zend_hash_next_free_element(&EG(regular_list));
2729 
2730         for(i = 1; i < nument; i++){
2731                 ptr = zend_list_find(i, &type);
2732                 if(ptr && (type == le_result)){
2733                         res = (odbc_result *)ptr;
2734                         if(res->conn_ptr == conn){
2735                                 zend_list_delete(i);
2736                         }
2737                 }
2738         }
2739         
2740         zend_list_delete(Z_LVAL_P(pv_conn));
2741         
2742         if(is_pconn){
2743                 zend_hash_apply_with_argument(&EG(persistent_list),     (apply_func_arg_t) _close_pconn_with_id, (void *) &(Z_LVAL_P(pv_conn)) TSRMLS_CC);      
2744         }
2745 }
2746 /* }}} */
2747 
2748 /* {{{ proto int odbc_num_rows(resource result_id)
2749    Get number of rows in a result */
2750 PHP_FUNCTION(odbc_num_rows)
2751 {
2752         odbc_result *result;
2753         SQLLEN rows;
2754         zval *pv_res;
2755         
2756         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2757                 return;
2758         }
2759         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2760         SQLRowCount(result->stmt, &rows);
2761         RETURN_LONG(rows);
2762 }
2763 /* }}} */
2764 
2765 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
2766 /* {{{ proto bool odbc_next_result(resource result_id)
2767    Checks if multiple results are available */
2768 PHP_FUNCTION(odbc_next_result)
2769 {
2770         odbc_result *result;
2771         zval *pv_res;
2772         int rc, i;
2773 
2774         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2775                 return;
2776         }
2777         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result); 
2778 
2779         if (result->values) {
2780                 for(i = 0; i < result->numcols; i++) {
2781                         if (result->values[i].value) {
2782                                 efree(result->values[i].value);
2783                         }
2784                 }
2785                 efree(result->values);
2786                 result->values = NULL;
2787         }
2788 
2789         result->fetched = 0;
2790         rc = SQLMoreResults(result->stmt);
2791         if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
2792                 rc = SQLFreeStmt(result->stmt, SQL_UNBIND);
2793                 SQLNumParams(result->stmt, &(result->numparams));
2794                 SQLNumResultCols(result->stmt, &(result->numcols));
2795 
2796                 if (result->numcols > 0) {
2797                         if (!odbc_bindcols(result TSRMLS_CC)) {
2798                                 efree(result);
2799                                 RETVAL_FALSE;
2800                         }
2801                 } else {
2802                         result->values = NULL;
2803                 }
2804                 RETURN_TRUE;
2805         } else if (rc == SQL_NO_DATA_FOUND) {
2806                 RETURN_FALSE;
2807         } else {
2808                 odbc_sql_error(result->conn_ptr, result->stmt, "SQLMoreResults");
2809                 RETURN_FALSE;
2810         }
2811 }
2812 /* }}} */
2813 #endif
2814 
2815 /* {{{ proto int odbc_num_fields(resource result_id)
2816    Get number of columns in a result */
2817 PHP_FUNCTION(odbc_num_fields)
2818 {
2819         odbc_result *result;
2820         zval *pv_res;
2821 
2822         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
2823                 return;
2824         }
2825         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2826         RETURN_LONG(result->numcols);
2827 }
2828 /* }}} */
2829 
2830 /* {{{ proto string odbc_field_name(resource result_id, int field_number)
2831    Get a column name */
2832 PHP_FUNCTION(odbc_field_name)
2833 {
2834         odbc_result *result;
2835         zval *pv_res;
2836         long pv_num;
2837         
2838         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2839                 return;
2840         }
2841         
2842         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2843         
2844         if (result->numcols == 0) {
2845                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2846                 RETURN_FALSE;
2847         }
2848         
2849         if (pv_num > result->numcols) {
2850                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2851                 RETURN_FALSE;
2852         }
2853         
2854         if (pv_num < 1) {
2855                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2856                 RETURN_FALSE;
2857         }
2858         
2859         RETURN_STRING(result->values[pv_num - 1].name, 1);
2860 }
2861 /* }}} */
2862 
2863 /* {{{ proto string odbc_field_type(resource result_id, int field_number)
2864    Get the datatype of a column */
2865 PHP_FUNCTION(odbc_field_type)
2866 {
2867         odbc_result     *result;
2868         char            tmp[32];
2869         SQLSMALLINT     tmplen;
2870         zval            *pv_res;
2871         long            pv_num;
2872 
2873         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
2874                 return;
2875         }
2876 
2877         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2878 
2879         if (result->numcols == 0) {
2880                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2881                 RETURN_FALSE;
2882         }
2883         
2884         if (pv_num > result->numcols) {
2885                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
2886                 RETURN_FALSE;
2887         }
2888 
2889         if (pv_num < 1) {
2890                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
2891                 RETURN_FALSE;
2892         }
2893 
2894         PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, 31, &tmplen, NULL);
2895         RETURN_STRING(tmp,1)
2896 }
2897 /* }}} */
2898 
2899 /* {{{ proto int odbc_field_len(resource result_id, int field_number)
2900    Get the length (precision) of a column */
2901 PHP_FUNCTION(odbc_field_len)
2902 {
2903         odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2904 }
2905 /* }}} */
2906 
2907 /* {{{ proto int odbc_field_scale(resource result_id, int field_number)
2908    Get the scale of a column */
2909 PHP_FUNCTION(odbc_field_scale)
2910 {
2911         odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);       
2912 }
2913 /* }}} */
2914 
2915 /* {{{ proto int odbc_field_num(resource result_id, string field_name)
2916    Return column number */
2917 PHP_FUNCTION(odbc_field_num)
2918 {
2919         char *fname;
2920         int i, field_ind, fname_len;
2921         odbc_result *result;
2922         zval *pv_res;
2923 
2924         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_res, &fname, &fname_len) == FAILURE) {
2925                 return;
2926         }
2927         
2928         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
2929         
2930         if (result->numcols == 0) {
2931                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
2932                 RETURN_FALSE;
2933         }
2934 
2935         field_ind = -1;
2936         for(i = 0; i < result->numcols; i++) {
2937                 if (strcasecmp(result->values[i].name, fname) == 0) {
2938                         field_ind = i + 1;
2939                 }
2940         }
2941 
2942         if (field_ind == -1) {
2943                 RETURN_FALSE;
2944         }
2945         RETURN_LONG(field_ind);
2946 }
2947 /* }}} */
2948 
2949 /* {{{ proto mixed odbc_autocommit(resource connection_id [, int OnOff])
2950    Toggle autocommit mode or get status */
2951 /* There can be problems with pconnections!*/
2952 PHP_FUNCTION(odbc_autocommit)
2953 {
2954         odbc_connection *conn;
2955         RETCODE rc;
2956         zval *pv_conn;
2957         long pv_onoff = 0;
2958 
2959         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_onoff) == FAILURE) {
2960                 return;
2961         }
2962 
2963         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
2964         
2965         if (ZEND_NUM_ARGS() > 1) {
2966                 rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (pv_onoff) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
2967                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2968                         odbc_sql_error(conn, SQL_NULL_HSTMT, "Set autocommit");
2969                         RETURN_FALSE;
2970                 }
2971                 RETVAL_TRUE;
2972         } else {
2973                 SQLINTEGER status;
2974 
2975                 rc = SQLGetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (PTR)&status);
2976                 if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
2977                         odbc_sql_error(conn, SQL_NULL_HSTMT, "Get commit status");
2978                         RETURN_FALSE;
2979                 }
2980                 RETVAL_LONG((long)status);
2981         }
2982 }
2983 /* }}} */
2984 
2985 /* {{{ proto bool odbc_commit(resource connection_id)
2986    Commit an ODBC transaction */
2987 PHP_FUNCTION(odbc_commit)
2988 {
2989         odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2990 }
2991 /* }}} */
2992 
2993 /* {{{ proto bool odbc_rollback(resource connection_id)
2994    Rollback a transaction */
2995 PHP_FUNCTION(odbc_rollback)
2996 {
2997         odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2998 }
2999 /* }}} */
3000 
3001 /* {{{ php_odbc_lasterror */
3002 static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode)
3003 {
3004         odbc_connection *conn;
3005         zval *pv_handle;
3006         char *ptr;
3007         int len;
3008 
3009         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &pv_handle) == FAILURE) {
3010                 return;
3011         }
3012 
3013         if (mode == 0) {  /* last state */
3014                 len = 6;
3015         } else { /* last error message */
3016                 len = SQL_MAX_MESSAGE_LENGTH;
3017         }
3018 
3019         if (ZEND_NUM_ARGS() == 1) {
3020                 ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
3021                 ptr = ecalloc(len + 1, 1);
3022                 if (mode == 0) {
3023                         strlcpy(ptr, conn->laststate, len+1);
3024                 } else {
3025                         strlcpy(ptr, conn->lasterrormsg, len+1);
3026                 }
3027         } else {
3028                 ptr = ecalloc(len + 1, 1);
3029                 if (mode == 0) {
3030                         strlcpy(ptr, ODBCG(laststate), len+1);
3031                 } else {
3032                         strlcpy(ptr, ODBCG(lasterrormsg), len+1);
3033                 }
3034         }
3035         RETVAL_STRING(ptr, 0);
3036 }
3037 /* }}} */
3038 
3039 /* {{{ proto string odbc_error([resource connection_id])
3040    Get the last error code */
3041 PHP_FUNCTION(odbc_error)
3042 {
3043         php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3044 }
3045 /* }}} */
3046 
3047 /* {{{ proto string odbc_errormsg([resource connection_id])
3048    Get the last error message */
3049 PHP_FUNCTION(odbc_errormsg)
3050 {
3051         php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3052 }
3053 /* }}} */
3054 
3055 /* {{{ proto bool odbc_setoption(resource conn_id|result_id, int which, int option, int value)
3056    Sets connection or statement options */
3057 /* This one has to be used carefully. We can't allow to set connection options for
3058    persistent connections. I think that SetStmtOption is of little use, since most
3059    of those can only be specified before preparing/executing statements.
3060    On the other hand, they can be made connection wide default through SetConnectOption
3061    - but will be overidden by calls to SetStmtOption() in odbc_prepare/odbc_do
3062 */
3063 PHP_FUNCTION(odbc_setoption)
3064 {
3065         odbc_connection *conn;
3066         odbc_result     *result;
3067         RETCODE rc;
3068         zval *pv_handle;
3069         long pv_which, pv_opt, pv_val;
3070 
3071         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) {
3072                 return;
3073         }
3074 
3075         switch (pv_which) {
3076                 case 1:         /* SQLSetConnectOption */
3077                         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
3078 
3079                         if (conn->persistent) {
3080                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set option for persistent connection");
3081                                 RETURN_FALSE;
3082                         }
3083                         rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val);
3084                         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3085                                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption");
3086                                 RETURN_FALSE;
3087                         }
3088                         break;
3089                 case 2:         /* SQLSetStmtOption */
3090                         ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_handle, -1, "ODBC result", le_result);
3091                         
3092                         rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val);
3093 
3094                         if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
3095                                 odbc_sql_error(result->conn_ptr, result->stmt, "SetStmtOption");
3096                                 RETURN_FALSE;
3097                         }
3098                         break;
3099                 default:
3100                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option type");
3101                         RETURN_FALSE;
3102                         break;
3103         }
3104 
3105         RETURN_TRUE;
3106 }
3107 /* }}} */
3108 
3109 /*
3110  * metadata functions
3111  */
3112 
3113 /* {{{ proto resource odbc_tables(resource connection_id [, string qualifier [, string owner [, string name [, string table_types]]]])
3114    Call the SQLTables function */
3115 PHP_FUNCTION(odbc_tables)
3116 {
3117         zval *pv_conn;
3118         odbc_result   *result = NULL;
3119         odbc_connection *conn;
3120         char *cat = NULL, *schema = NULL, *table = NULL, *type = NULL;
3121         int cat_len = 0, schema_len = 0, table_len = 0, type_len = 0;
3122         RETCODE rc;
3123 
3124         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, 
3125                 &table, &table_len, &type, &type_len) == FAILURE) {
3126                 return;
3127         }
3128 
3129         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3130 
3131         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3132         
3133         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3134         if (rc == SQL_INVALID_HANDLE) {
3135                 efree(result);
3136                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3137                 RETURN_FALSE;
3138         }
3139 
3140         if (rc == SQL_ERROR) {
3141                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3142                 efree(result);
3143                 RETURN_FALSE;
3144         }
3145 
3146         /* This hack is needed to access table information in Access databases (fmk) */
3147         if (table && table_len && schema && schema_len == 0) {
3148                 schema = NULL;
3149         }
3150 
3151         rc = SQLTables(result->stmt, 
3152                         cat, SAFE_SQL_NTS(cat), 
3153                         schema, SAFE_SQL_NTS(schema), 
3154                         table, SAFE_SQL_NTS(table),
3155                         type, SAFE_SQL_NTS(type));
3156 
3157         if (rc == SQL_ERROR) {
3158                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTables");
3159                 efree(result);
3160                 RETURN_FALSE;
3161         }
3162 
3163         result->numparams = 0;
3164         SQLNumResultCols(result->stmt, &(result->numcols));
3165 
3166         if (result->numcols > 0) {
3167                 if (!odbc_bindcols(result TSRMLS_CC)) {
3168                         efree(result);
3169                         RETURN_FALSE;
3170                 }
3171         } else {
3172                 result->values = NULL;
3173         }
3174         result->conn_ptr = conn;
3175         result->fetched = 0;
3176         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3177 }
3178 /* }}} */
3179 
3180 /* {{{ proto resource odbc_columns(resource connection_id [, string qualifier [, string owner [, string table_name [, string column_name]]]])
3181    Returns a result identifier that can be used to fetch a list of column names in specified tables */
3182 PHP_FUNCTION(odbc_columns)
3183 {
3184         zval *pv_conn;
3185         odbc_result *result = NULL;
3186         odbc_connection *conn;
3187         char *cat = NULL, *schema = NULL, *table = NULL, *column = NULL;
3188         int cat_len = 0, schema_len = 0, table_len = 0, column_len = 0;
3189         RETCODE rc;
3190 
3191         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3192                 &table, &table_len, &column, &column_len) == FAILURE) {
3193                 return;
3194         }
3195 
3196         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3197 
3198         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3199         
3200         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3201         if (rc == SQL_INVALID_HANDLE) {
3202                 efree(result);
3203                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3204                 RETURN_FALSE;
3205         }
3206 
3207         if (rc == SQL_ERROR) {
3208                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3209                 efree(result);
3210                 RETURN_FALSE;
3211         }
3212 
3213         /* 
3214          * Needed to make MS Access happy
3215          */
3216         if (table && table_len && schema && schema_len == 0) {
3217                 schema = NULL;
3218         }
3219 
3220         rc = SQLColumns(result->stmt, 
3221                         cat, (SQLSMALLINT) cat_len,
3222                         schema, (SQLSMALLINT) schema_len,
3223                         table, (SQLSMALLINT) table_len,
3224                         column, (SQLSMALLINT) column_len);
3225 
3226         if (rc == SQL_ERROR) {
3227                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumns");
3228                 efree(result);
3229                 RETURN_FALSE;
3230         }
3231 
3232         result->numparams = 0;
3233         SQLNumResultCols(result->stmt, &(result->numcols));
3234 
3235         if (result->numcols > 0) {
3236                 if (!odbc_bindcols(result TSRMLS_CC)) {
3237                         efree(result);
3238                         RETURN_FALSE;
3239                 }
3240         } else {
3241                 result->values = NULL;
3242         }
3243         result->conn_ptr = conn;
3244         result->fetched = 0;
3245         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3246 }
3247 /* }}} */
3248 
3249 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3250 /* {{{ proto resource odbc_columnprivileges(resource connection_id, string catalog, string schema, string table, string column)
3251    Returns a result identifier that can be used to fetch a list of columns and associated privileges for the specified table */
3252 PHP_FUNCTION(odbc_columnprivileges)
3253 {
3254         zval *pv_conn;
3255         odbc_result *result = NULL;
3256         odbc_connection *conn;
3257         char *cat = NULL, *schema, *table, *column;
3258         int cat_len = 0, schema_len, table_len, column_len;
3259         RETCODE rc;
3260         
3261         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3262                 &table, &table_len, &column, &column_len) == FAILURE) {
3263                 return;
3264         }
3265 
3266         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3267 
3268         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3269         
3270         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3271         if (rc == SQL_INVALID_HANDLE) {
3272                 efree(result);
3273                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3274                 RETURN_FALSE;
3275         }
3276 
3277         if (rc == SQL_ERROR) {
3278                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3279                 efree(result);
3280                 RETURN_FALSE;
3281         }
3282 
3283         rc = SQLColumnPrivileges(result->stmt, 
3284                         cat, SAFE_SQL_NTS(cat),
3285                         schema, SAFE_SQL_NTS(schema),
3286                         table, SAFE_SQL_NTS(table),
3287                         column, SAFE_SQL_NTS(column));
3288 
3289         if (rc == SQL_ERROR) {
3290                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumnPrivileges");
3291                 efree(result);
3292                 RETURN_FALSE;
3293         }
3294 
3295         result->numparams = 0;
3296         SQLNumResultCols(result->stmt, &(result->numcols));
3297 
3298         if (result->numcols > 0) {
3299                 if (!odbc_bindcols(result TSRMLS_CC)) {
3300                         efree(result);
3301                         RETURN_FALSE;
3302                 }
3303         } else {
3304                 result->values = NULL;
3305         }
3306         result->conn_ptr = conn;
3307         result->fetched = 0;
3308         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3309 }
3310 /* }}} */
3311 #endif /* HAVE_DBMAKER || HAVE_SOLID*/
3312 
3313 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3314 /* {{{ proto resource odbc_foreignkeys(resource connection_id, string pk_qualifier, string pk_owner, string pk_table, string fk_qualifier, string fk_owner, string fk_table)
3315    Returns a result identifier to either a list of foreign keys in the specified table or a list of foreign keys in other tables that refer to the primary key in the specified table */
3316 PHP_FUNCTION(odbc_foreignkeys)
3317 {
3318         zval *pv_conn;
3319         odbc_result *result = NULL;
3320         odbc_connection *conn;
3321         char *pcat = NULL, *pschema, *ptable, *fcat, *fschema, *ftable;
3322         int pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len;
3323         RETCODE rc;
3324 
3325         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len, 
3326                 &ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) {
3327                 return;
3328         }
3329 
3330 #if defined(HAVE_DBMAKER) || defined(HAVE_IBMDB2)
3331 #define EMPTY_TO_NULL(xstr) \
3332         if ((int)strlen((xstr)) == 0) (xstr) = NULL
3333 
3334                 EMPTY_TO_NULL(pcat);
3335                 EMPTY_TO_NULL(pschema);
3336                 EMPTY_TO_NULL(ptable);
3337                 EMPTY_TO_NULL(fcat);
3338                 EMPTY_TO_NULL(fschema);
3339                 EMPTY_TO_NULL(ftable);
3340 #endif
3341 
3342         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3343 
3344         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3345         
3346         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3347         if (rc == SQL_INVALID_HANDLE) {
3348                 efree(result);
3349                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3350                 RETURN_FALSE;
3351         }
3352 
3353         if (rc == SQL_ERROR) {
3354                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3355                 efree(result);
3356                 RETURN_FALSE;
3357         }
3358 
3359         rc = SQLForeignKeys(result->stmt, 
3360                         pcat, SAFE_SQL_NTS(pcat), 
3361                         pschema, SAFE_SQL_NTS(pschema), 
3362                         ptable, SAFE_SQL_NTS(ptable), 
3363                         fcat, SAFE_SQL_NTS(fcat), 
3364                         fschema, SAFE_SQL_NTS(fschema), 
3365                         ftable, SAFE_SQL_NTS(ftable) );
3366 
3367         if (rc == SQL_ERROR) {
3368                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLForeignKeys");
3369                 efree(result);
3370                 RETURN_FALSE;
3371         }
3372 
3373         result->numparams = 0;
3374         SQLNumResultCols(result->stmt, &(result->numcols));
3375 
3376         if (result->numcols > 0) {
3377                 if (!odbc_bindcols(result TSRMLS_CC)) {
3378                         efree(result);
3379                         RETURN_FALSE;
3380                 }
3381         } else {
3382                 result->values = NULL;
3383         }
3384         result->conn_ptr = conn;
3385         result->fetched = 0;
3386         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3387 }
3388 /* }}} */
3389 #endif /* HAVE_SOLID */
3390 
3391 /* {{{ proto resource odbc_gettypeinfo(resource connection_id [, int data_type])
3392    Returns a result identifier containing information about data types supported by the data source */
3393 PHP_FUNCTION(odbc_gettypeinfo)
3394 {
3395         zval *pv_conn;
3396         long pv_data_type = SQL_ALL_TYPES;
3397         odbc_result *result = NULL;
3398         odbc_connection *conn;
3399         RETCODE rc;
3400         SQLSMALLINT data_type;
3401 
3402         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_data_type) == FAILURE) {
3403                 return;
3404         }
3405         
3406         data_type = (SQLSMALLINT) pv_data_type;
3407 
3408         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3409 
3410         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3411         
3412         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3413         if (rc == SQL_INVALID_HANDLE) {
3414                 efree(result);
3415                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3416                 RETURN_FALSE;
3417         }
3418 
3419         if (rc == SQL_ERROR) {
3420                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3421                 efree(result);
3422                 RETURN_FALSE;
3423         }
3424 
3425         rc = SQLGetTypeInfo(result->stmt, data_type );
3426 
3427         if (rc == SQL_ERROR) {
3428                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLGetTypeInfo");
3429                 efree(result);
3430                 RETURN_FALSE;
3431         }
3432 
3433         result->numparams = 0;
3434         SQLNumResultCols(result->stmt, &(result->numcols));
3435 
3436         if (result->numcols > 0) {
3437                 if (!odbc_bindcols(result TSRMLS_CC)) {
3438                         efree(result);
3439                         RETURN_FALSE;
3440                 }
3441         } else {
3442                 result->values = NULL;
3443         }
3444         result->conn_ptr = conn;
3445         result->fetched = 0;
3446         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3447 }
3448 /* }}} */
3449 
3450 /* {{{ proto resource odbc_primarykeys(resource connection_id, string qualifier, string owner, string table)
3451    Returns a result identifier listing the column names that comprise the primary key for a table */
3452 PHP_FUNCTION(odbc_primarykeys)
3453 {
3454         zval *pv_conn;
3455         odbc_result   *result = NULL;
3456         odbc_connection *conn;
3457         char *cat = NULL, *schema = NULL, *table = NULL;
3458         int cat_len = 0, schema_len, table_len;
3459         RETCODE rc;
3460 
3461         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3462                 return;
3463         }
3464 
3465         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3466 
3467         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3468         
3469         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3470         if (rc == SQL_INVALID_HANDLE) {
3471                 efree(result);
3472                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3473                 RETURN_FALSE;
3474         }
3475 
3476         if (rc == SQL_ERROR) {
3477                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3478                 efree(result);
3479                 RETURN_FALSE;
3480         }
3481 
3482         rc = SQLPrimaryKeys(result->stmt, 
3483                         cat, SAFE_SQL_NTS(cat), 
3484                         schema, SAFE_SQL_NTS(schema), 
3485                         table, SAFE_SQL_NTS(table) );
3486 
3487         if (rc == SQL_ERROR) {
3488                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLPrimaryKeys");
3489                 efree(result);
3490                 RETURN_FALSE;
3491         }
3492 
3493         result->numparams = 0;
3494         SQLNumResultCols(result->stmt, &(result->numcols));
3495 
3496         if (result->numcols > 0) {
3497                 if (!odbc_bindcols(result TSRMLS_CC)) {
3498                         efree(result);
3499                         RETURN_FALSE;
3500                 }
3501         } else {
3502                 result->values = NULL;
3503         }
3504         result->conn_ptr = conn;
3505         result->fetched = 0;
3506         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3507 }
3508 /* }}} */
3509 
3510 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3511 /* {{{ proto resource odbc_procedurecolumns(resource connection_id [, string qualifier, string owner, string proc, string column])
3512    Returns a result identifier containing the list of input and output parameters, as well as the columns that make up the result set for the specified procedures */
3513 PHP_FUNCTION(odbc_procedurecolumns)
3514 {
3515         zval *pv_conn;
3516         odbc_result *result = NULL;
3517         odbc_connection *conn;
3518         char *cat = NULL, *schema = NULL, *proc = NULL, *col = NULL;
3519         int cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0;
3520         RETCODE rc;
3521         
3522         if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 5) {
3523                 WRONG_PARAM_COUNT;
3524         }
3525 
3526         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, 
3527                 &proc, &proc_len, &col, &col_len) == FAILURE) {
3528                 return;
3529         }
3530 
3531         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3532 
3533         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3534         
3535         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3536         if (rc == SQL_INVALID_HANDLE) {
3537                 efree(result);
3538                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3539                 RETURN_FALSE;
3540         }
3541 
3542         if (rc == SQL_ERROR) {
3543                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3544                 efree(result);
3545                 RETURN_FALSE;
3546         }
3547 
3548         rc = SQLProcedureColumns(result->stmt, 
3549                         cat, SAFE_SQL_NTS(cat), 
3550                         schema, SAFE_SQL_NTS(schema), 
3551                         proc, SAFE_SQL_NTS(proc), 
3552                         col, SAFE_SQL_NTS(col) );
3553 
3554         if (rc == SQL_ERROR) {
3555                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedureColumns");
3556                 efree(result);
3557                 RETURN_FALSE;
3558         }
3559 
3560         result->numparams = 0;
3561         SQLNumResultCols(result->stmt, &(result->numcols));
3562 
3563         if (result->numcols > 0) {
3564                 if (!odbc_bindcols(result TSRMLS_CC)) {
3565                         efree(result);
3566                         RETURN_FALSE;
3567                 }
3568         } else {
3569                 result->values = NULL;
3570         }
3571         result->conn_ptr = conn;
3572         result->fetched = 0;
3573         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3574 }
3575 /* }}} */
3576 #endif /* HAVE_SOLID */
3577 
3578 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
3579 /* {{{ proto resource odbc_procedures(resource connection_id [, string qualifier, string owner, string name])
3580    Returns a result identifier containg the list of procedure names in a datasource */
3581 PHP_FUNCTION(odbc_procedures)
3582 {
3583         zval *pv_conn;
3584         odbc_result   *result = NULL;
3585         odbc_connection *conn;
3586         char *cat = NULL, *schema = NULL, *proc = NULL;
3587         int cat_len = 0, schema_len = 0, proc_len = 0;
3588         RETCODE rc;
3589 
3590         if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 4) {
3591                 WRONG_PARAM_COUNT;
3592         }
3593         
3594         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) {
3595                 return;
3596         }
3597 
3598         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3599 
3600         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3601         
3602         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3603         if (rc == SQL_INVALID_HANDLE) {
3604                 efree(result);
3605                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3606                 RETURN_FALSE;
3607         }
3608 
3609         if (rc == SQL_ERROR) {
3610                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3611                 efree(result);
3612                 RETURN_FALSE;
3613         }
3614 
3615         rc = SQLProcedures(result->stmt, 
3616                         cat, SAFE_SQL_NTS(cat), 
3617                         schema, SAFE_SQL_NTS(schema), 
3618                         proc, SAFE_SQL_NTS(proc) );
3619 
3620         if (rc == SQL_ERROR) {
3621                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedures");
3622                 efree(result);
3623                 RETURN_FALSE;
3624         }
3625 
3626         result->numparams = 0;
3627         SQLNumResultCols(result->stmt, &(result->numcols));
3628 
3629         if (result->numcols > 0) {
3630                 if (!odbc_bindcols(result TSRMLS_CC)) {
3631                         efree(result);
3632                         RETURN_FALSE;
3633                 }
3634         } else {
3635                 result->values = NULL;
3636         }
3637         result->conn_ptr = conn;
3638         result->fetched = 0;
3639         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3640 }
3641 /* }}} */
3642 #endif /* HAVE_SOLID */
3643 
3644 /* {{{ proto resource odbc_specialcolumns(resource connection_id, int type, string qualifier, string owner, string table, int scope, int nullable)
3645    Returns a result identifier containing either the optimal set of columns that uniquely identifies a row in the table or columns that are automatically updated when any value in the row is updated by a transaction */
3646 PHP_FUNCTION(odbc_specialcolumns)
3647 {
3648         zval *pv_conn;
3649         long vtype, vscope, vnullable;
3650         odbc_result *result = NULL;
3651         odbc_connection *conn;
3652         char *cat = NULL, *schema = NULL, *name = NULL;
3653         int cat_len = 0, schema_len, name_len;
3654         SQLUSMALLINT type, scope, nullable;
3655         RETCODE rc;
3656 
3657         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len,
3658                 &name, &name_len, &vscope, &vnullable) == FAILURE) {
3659                 return;
3660         }
3661         
3662         type = (SQLUSMALLINT) vtype;
3663         scope = (SQLUSMALLINT) vscope;
3664         nullable = (SQLUSMALLINT) vnullable;
3665 
3666         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3667 
3668         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3669         
3670         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3671         if (rc == SQL_INVALID_HANDLE) {
3672                 efree(result);
3673                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3674                 RETURN_FALSE;
3675         }
3676 
3677         if (rc == SQL_ERROR) {
3678                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3679                 efree(result);
3680                 RETURN_FALSE;
3681         }
3682 
3683         rc = SQLSpecialColumns(result->stmt, 
3684                         type,
3685                         cat, SAFE_SQL_NTS(cat), 
3686                         schema, SAFE_SQL_NTS(schema), 
3687                         name, SAFE_SQL_NTS(name),
3688                         scope,
3689                         nullable);
3690 
3691         if (rc == SQL_ERROR) {
3692                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLSpecialColumns");
3693                 efree(result);
3694                 RETURN_FALSE;
3695         }
3696 
3697         result->numparams = 0;
3698         SQLNumResultCols(result->stmt, &(result->numcols));
3699 
3700         if (result->numcols > 0) {
3701                 if (!odbc_bindcols(result TSRMLS_CC)) {
3702                         efree(result);
3703                         RETURN_FALSE;
3704                 }
3705         } else {
3706                 result->values = NULL;
3707         }
3708         result->conn_ptr = conn;
3709         result->fetched = 0;
3710         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3711 }
3712 /* }}} */
3713 
3714 /* {{{ proto resource odbc_statistics(resource connection_id, string qualifier, string owner, string name, int unique, int accuracy)
3715    Returns a result identifier that contains statistics about a single table and the indexes associated with the table */
3716 PHP_FUNCTION(odbc_statistics)
3717 {
3718         zval *pv_conn;
3719         long vunique, vreserved;
3720         odbc_result *result = NULL;
3721         odbc_connection *conn;
3722         char *cat = NULL, *schema, *name;
3723         int cat_len = 0, schema_len, name_len;
3724         SQLUSMALLINT unique, reserved;
3725         RETCODE rc;
3726 
3727         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len,
3728                 &name, &name_len, &vunique, &vreserved) == FAILURE) {
3729                 return;
3730         }
3731         
3732         unique = (SQLUSMALLINT) vunique;
3733         reserved = (SQLUSMALLINT) vreserved;
3734 
3735         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3736 
3737         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3738         
3739         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3740         if (rc == SQL_INVALID_HANDLE) {
3741                 efree(result);
3742                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3743                 RETURN_FALSE;
3744         }
3745 
3746         if (rc == SQL_ERROR) {
3747                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3748                 efree(result);
3749                 RETURN_FALSE;
3750         }
3751 
3752         rc = SQLStatistics(result->stmt, 
3753                         cat, SAFE_SQL_NTS(cat),
3754                         schema, SAFE_SQL_NTS(schema), 
3755                         name, SAFE_SQL_NTS(name),
3756                         unique,
3757                         reserved);
3758 
3759         if (rc == SQL_ERROR) {
3760                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLStatistics");
3761                 efree(result);
3762                 RETURN_FALSE;
3763         }
3764 
3765         result->numparams = 0;
3766         SQLNumResultCols(result->stmt, &(result->numcols));
3767 
3768         if (result->numcols > 0) {
3769                 if (!odbc_bindcols(result TSRMLS_CC)) {
3770                         efree(result);
3771                         RETURN_FALSE;
3772                 }
3773         } else {
3774                 result->values = NULL;
3775         }
3776         result->conn_ptr = conn;
3777         result->fetched = 0;
3778         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3779 }
3780 /* }}} */
3781 
3782 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
3783 /* {{{ proto resource odbc_tableprivileges(resource connection_id, string qualifier, string owner, string name)
3784    Returns a result identifier containing a list of tables and the privileges associated with each table */
3785 PHP_FUNCTION(odbc_tableprivileges)
3786 {
3787         zval *pv_conn;
3788         odbc_result   *result = NULL;
3789         odbc_connection *conn;
3790         char *cat = NULL, *schema = NULL, *table = NULL;
3791         int cat_len = 0, schema_len, table_len;
3792         RETCODE rc;
3793 
3794         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
3795                 return;
3796         }
3797 
3798         ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
3799 
3800         result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
3801         
3802         rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt));
3803         if (rc == SQL_INVALID_HANDLE) {
3804                 efree(result);
3805                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
3806                 RETURN_FALSE;
3807         }
3808 
3809         if (rc == SQL_ERROR) {
3810                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
3811                 efree(result);
3812                 RETURN_FALSE;
3813         }
3814 
3815         rc = SQLTablePrivileges(result->stmt, 
3816                         cat, SAFE_SQL_NTS(cat), 
3817                         schema, SAFE_SQL_NTS(schema), 
3818                         table, SAFE_SQL_NTS(table));
3819 
3820         if (rc == SQL_ERROR) {
3821                 odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTablePrivileges");
3822                 efree(result);
3823                 RETURN_FALSE;
3824         }
3825 
3826         result->numparams = 0;
3827         SQLNumResultCols(result->stmt, &(result->numcols));
3828 
3829         if (result->numcols > 0) {
3830                 if (!odbc_bindcols(result TSRMLS_CC)) {
3831                         efree(result);
3832                         RETURN_FALSE;
3833                 }
3834         } else {
3835                 result->values = NULL;
3836         }
3837         result->conn_ptr = conn;
3838         result->fetched = 0;
3839         ZEND_REGISTER_RESOURCE(return_value, result, le_result);
3840 }
3841 /* }}} */
3842 #endif /* HAVE_DBMAKER */
3843 
3844 #endif /* HAVE_UODBC */
3845 
3846 /*
3847  * Local variables:
3848  * tab-width: 4
3849  * c-basic-offset: 4
3850  * End:
3851  * vim600: sw=4 ts=4 fdm=marker
3852  * vim<600: sw=4 ts=4
3853  */

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