root/ext/odbc/php_odbc.c

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

DEFINITIONS

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

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