Back to index

php5  5.3.10
php_odbc.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
00016    |          Andreas Karajannis <Andreas.Karajannis@gmd.de>              |
00017    |          Frank M. Kromann <frank@kromann.info>  Support for DB/2 CLI |
00018    |          Kevin N. Shallow <kshallow@tampabay.rr.com> Birdstep Support|
00019    |          Daniel R. Kalowsky <kalowsky@php.net>                       |
00020    +----------------------------------------------------------------------+
00021 */
00022 
00023 /* $Id: php_odbc.c 321634 2012-01-01 13:15:04Z felipe $ */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028  
00029 #include "php.h"
00030 #include "php_globals.h"
00031 
00032 #include "ext/standard/info.h"
00033 #include "ext/standard/php_string.h"
00034 #include "ext/standard/php_standard.h"
00035 
00036 #include "php_odbc.h"
00037 #include "php_odbc_includes.h"
00038 #include "php_globals.h"
00039 
00040 #if HAVE_UODBC
00041 
00042 #include <fcntl.h>
00043 #include "ext/standard/head.h"
00044 #include "php_ini.h"
00045 
00046 #ifdef PHP_WIN32
00047 #include <winsock2.h>
00048 
00049 #define ODBC_TYPE "Win32"
00050 #define PHP_ODBC_TYPE ODBC_TYPE
00051 
00052 #endif
00053 
00054 /*
00055  * not defined elsewhere
00056  */
00057 
00058 #ifndef TRUE
00059 #define TRUE 1
00060 #define FALSE 0
00061 #endif
00062 
00063 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent);
00064 
00065 static int le_result, le_conn, le_pconn;
00066 
00067 #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0))
00068 
00069 /* {{{ arginfo */
00070 ZEND_BEGIN_ARG_INFO(arginfo_odbc_close_all, 0)
00071 ZEND_END_ARG_INFO()
00072 
00073 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_binmode, 0, 0, 2)
00074        ZEND_ARG_INFO(0, result_id)
00075        ZEND_ARG_INFO(0, mode)
00076 ZEND_END_ARG_INFO()
00077 
00078 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_longreadlen, 0, 0, 2)
00079        ZEND_ARG_INFO(0, result_id)
00080        ZEND_ARG_INFO(0, length)
00081 ZEND_END_ARG_INFO()
00082 
00083 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_prepare, 0, 0, 2)
00084        ZEND_ARG_INFO(0, connection_id)
00085        ZEND_ARG_INFO(0, query)
00086 ZEND_END_ARG_INFO()
00087 
00088 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_execute, 0, 0, 1)
00089        ZEND_ARG_INFO(0, result_id)
00090        ZEND_ARG_INFO(0, parameters_array)
00091 ZEND_END_ARG_INFO()
00092 
00093 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_cursor, 0, 0, 1)
00094        ZEND_ARG_INFO(0, result_id)
00095 ZEND_END_ARG_INFO()
00096 
00097 #ifdef HAVE_SQLDATASOURCES
00098 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_data_source, 0, 0, 2)
00099        ZEND_ARG_INFO(0, connection_id)
00100        ZEND_ARG_INFO(0, fetch_type)
00101 ZEND_END_ARG_INFO()
00102 #endif
00103 
00104 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_exec, 0, 0, 2)
00105        ZEND_ARG_INFO(0, connection_id)
00106        ZEND_ARG_INFO(0, query)
00107        ZEND_ARG_INFO(0, flags)
00108 ZEND_END_ARG_INFO()
00109 
00110 #ifdef PHP_ODBC_HAVE_FETCH_HASH
00111 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_object, 0, 0, 1)
00112        ZEND_ARG_INFO(0, result)
00113        ZEND_ARG_INFO(0, rownumber)
00114 ZEND_END_ARG_INFO()
00115 
00116 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_array, 0, 0, 1)
00117        ZEND_ARG_INFO(0, result)
00118        ZEND_ARG_INFO(0, rownumber)
00119 ZEND_END_ARG_INFO()
00120 #endif
00121 
00122 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_into, 0, 0, 2)
00123        ZEND_ARG_INFO(0, result_id)
00124        ZEND_ARG_INFO(1, result_array)
00125        ZEND_ARG_INFO(0, rownumber)
00126 ZEND_END_ARG_INFO()
00127 
00128 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_fetch_row, 0, 0, 1)
00129        ZEND_ARG_INFO(0, result_id)
00130        ZEND_ARG_INFO(0, row_number)
00131 ZEND_END_ARG_INFO()
00132 
00133 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result, 0, 0, 2)
00134        ZEND_ARG_INFO(0, result_id)
00135        ZEND_ARG_INFO(0, field)
00136 ZEND_END_ARG_INFO()
00137 
00138 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_result_all, 0, 0, 1)
00139        ZEND_ARG_INFO(0, result_id)
00140        ZEND_ARG_INFO(0, format)
00141 ZEND_END_ARG_INFO()
00142 
00143 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_free_result, 0, 0, 1)
00144        ZEND_ARG_INFO(0, result_id)
00145 ZEND_END_ARG_INFO()
00146 
00147 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_connect, 0, 0, 3)
00148        ZEND_ARG_INFO(0, dsn)
00149        ZEND_ARG_INFO(0, user)
00150        ZEND_ARG_INFO(0, password)
00151        ZEND_ARG_INFO(0, cursor_option)
00152 ZEND_END_ARG_INFO()
00153 
00154 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_pconnect, 0, 0, 3)
00155        ZEND_ARG_INFO(0, dsn)
00156        ZEND_ARG_INFO(0, user)
00157        ZEND_ARG_INFO(0, password)
00158        ZEND_ARG_INFO(0, cursor_option)
00159 ZEND_END_ARG_INFO()
00160 
00161 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_close, 0, 0, 1)
00162        ZEND_ARG_INFO(0, connection_id)
00163 ZEND_END_ARG_INFO()
00164 
00165 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_rows, 0, 0, 1)
00166        ZEND_ARG_INFO(0, result_id)
00167 ZEND_END_ARG_INFO()
00168 
00169 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
00170 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_next_result, 0, 0, 1)
00171        ZEND_ARG_INFO(0, result_id)
00172 ZEND_END_ARG_INFO()
00173 #endif
00174 
00175 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_num_fields, 0, 0, 1)
00176        ZEND_ARG_INFO(0, result_id)
00177 ZEND_END_ARG_INFO()
00178 
00179 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_name, 0, 0, 2)
00180        ZEND_ARG_INFO(0, result_id)
00181        ZEND_ARG_INFO(0, field_number)
00182 ZEND_END_ARG_INFO()
00183 
00184 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_type, 0, 0, 2)
00185        ZEND_ARG_INFO(0, result_id)
00186        ZEND_ARG_INFO(0, field_number)
00187 ZEND_END_ARG_INFO()
00188 
00189 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_len, 0, 0, 2)
00190        ZEND_ARG_INFO(0, result_id)
00191        ZEND_ARG_INFO(0, field_number)
00192 ZEND_END_ARG_INFO()
00193 
00194 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_scale, 0, 0, 2)
00195        ZEND_ARG_INFO(0, result_id)
00196        ZEND_ARG_INFO(0, field_number)
00197 ZEND_END_ARG_INFO()
00198 
00199 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_field_num, 0, 0, 2)
00200        ZEND_ARG_INFO(0, result_id)
00201        ZEND_ARG_INFO(0, field_name)
00202 ZEND_END_ARG_INFO()
00203 
00204 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_autocommit, 0, 0, 1)
00205        ZEND_ARG_INFO(0, connection_id)
00206        ZEND_ARG_INFO(0, onoff)
00207 ZEND_END_ARG_INFO()
00208 
00209 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_commit, 0, 0, 1)
00210        ZEND_ARG_INFO(0, connection_id)
00211 ZEND_END_ARG_INFO()
00212 
00213 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_rollback, 0, 0, 1)
00214        ZEND_ARG_INFO(0, connection_id)
00215 ZEND_END_ARG_INFO()
00216 
00217 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_error, 0, 0, 0)
00218        ZEND_ARG_INFO(0, connection_id)
00219 ZEND_END_ARG_INFO()
00220 
00221 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_errormsg, 0, 0, 0)
00222        ZEND_ARG_INFO(0, connection_id)
00223 ZEND_END_ARG_INFO()
00224 
00225 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_setoption, 0, 0, 4)
00226        ZEND_ARG_INFO(0, conn_id)
00227        ZEND_ARG_INFO(0, which)
00228        ZEND_ARG_INFO(0, option)
00229        ZEND_ARG_INFO(0, value)
00230 ZEND_END_ARG_INFO()
00231 
00232 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tables, 0, 0, 1)
00233        ZEND_ARG_INFO(0, connection_id)
00234        ZEND_ARG_INFO(0, qualifier)
00235        ZEND_ARG_INFO(0, owner)
00236        ZEND_ARG_INFO(0, name)
00237        ZEND_ARG_INFO(0, table_types)
00238 ZEND_END_ARG_INFO()
00239 
00240 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columns, 0, 0, 1)
00241        ZEND_ARG_INFO(0, connection_id)
00242        ZEND_ARG_INFO(0, qualifier)
00243        ZEND_ARG_INFO(0, owner)
00244        ZEND_ARG_INFO(0, table_name)
00245        ZEND_ARG_INFO(0, column_name)
00246 ZEND_END_ARG_INFO()
00247 
00248 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_gettypeinfo, 0, 0, 1)
00249        ZEND_ARG_INFO(0, connection_id)
00250        ZEND_ARG_INFO(0, data_type)
00251 ZEND_END_ARG_INFO()
00252 
00253 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_primarykeys, 0, 0, 4)
00254        ZEND_ARG_INFO(0, connection_id)
00255        ZEND_ARG_INFO(0, qualifier)
00256        ZEND_ARG_INFO(0, owner)
00257        ZEND_ARG_INFO(0, table)
00258 ZEND_END_ARG_INFO()
00259 
00260 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
00261 #if !defined(HAVE_BIRDSTEP)
00262 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedurecolumns, 0, 0, 1)
00263        ZEND_ARG_INFO(0, connection_id)
00264        ZEND_ARG_INFO(0, qualifier)
00265        ZEND_ARG_INFO(0, owner)
00266        ZEND_ARG_INFO(0, proc)
00267        ZEND_ARG_INFO(0, column)
00268 ZEND_END_ARG_INFO()
00269 #endif
00270 
00271 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedures, 0, 0, 1)
00272        ZEND_ARG_INFO(0, connection_id)
00273        ZEND_ARG_INFO(0, qualifier)
00274        ZEND_ARG_INFO(0, owner)
00275        ZEND_ARG_INFO(0, name)
00276 ZEND_END_ARG_INFO()
00277 
00278 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7)
00279        ZEND_ARG_INFO(0, connection_id)
00280        ZEND_ARG_INFO(0, pk_qualifier)
00281        ZEND_ARG_INFO(0, pk_owner)
00282        ZEND_ARG_INFO(0, pk_table)
00283        ZEND_ARG_INFO(0, fk_qualifier)
00284        ZEND_ARG_INFO(0, fk_owner)
00285        ZEND_ARG_INFO(0, fk_table)
00286 ZEND_END_ARG_INFO()
00287 #endif
00288 
00289 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7)
00290        ZEND_ARG_INFO(0, connection_id)
00291        ZEND_ARG_INFO(0, type)
00292        ZEND_ARG_INFO(0, qualifier)
00293        ZEND_ARG_INFO(0, owner)
00294        ZEND_ARG_INFO(0, table)
00295        ZEND_ARG_INFO(0, scope)
00296        ZEND_ARG_INFO(0, nullable)
00297 ZEND_END_ARG_INFO()
00298 
00299 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6)
00300        ZEND_ARG_INFO(0, connection_id)
00301        ZEND_ARG_INFO(0, qualifier)
00302        ZEND_ARG_INFO(0, owner)
00303        ZEND_ARG_INFO(0, name)
00304        ZEND_ARG_INFO(0, unique)
00305        ZEND_ARG_INFO(0, accuracy)
00306 ZEND_END_ARG_INFO()
00307 
00308 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
00309 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tableprivileges, 0, 0, 4)
00310        ZEND_ARG_INFO(0, connection_id)
00311        ZEND_ARG_INFO(0, qualifier)
00312        ZEND_ARG_INFO(0, owner)
00313        ZEND_ARG_INFO(0, name)
00314 ZEND_END_ARG_INFO()
00315 
00316 ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5)
00317        ZEND_ARG_INFO(0, connection_id)
00318        ZEND_ARG_INFO(0, catalog)
00319        ZEND_ARG_INFO(0, schema)
00320        ZEND_ARG_INFO(0, table)
00321        ZEND_ARG_INFO(0, column)
00322 ZEND_END_ARG_INFO()
00323 #endif
00324 /* }}} */
00325 
00326 /* {{{ odbc_functions[]
00327  */
00328 const zend_function_entry odbc_functions[] = {
00329        PHP_FE(odbc_autocommit, arginfo_odbc_autocommit)
00330        PHP_FE(odbc_binmode, arginfo_odbc_binmode)
00331        PHP_FE(odbc_close, arginfo_odbc_close)
00332        PHP_FE(odbc_close_all, arginfo_odbc_close_all)
00333        PHP_FE(odbc_columns, arginfo_odbc_columns)
00334        PHP_FE(odbc_commit, arginfo_odbc_commit)
00335        PHP_FE(odbc_connect, arginfo_odbc_connect)
00336        PHP_FE(odbc_cursor, arginfo_odbc_cursor)
00337 #ifdef HAVE_SQLDATASOURCES
00338        PHP_FE(odbc_data_source, arginfo_odbc_data_source)
00339 #endif
00340        PHP_FE(odbc_execute, arginfo_odbc_execute)
00341        PHP_FE(odbc_error, arginfo_odbc_error)
00342        PHP_FE(odbc_errormsg, arginfo_odbc_errormsg)
00343        PHP_FE(odbc_exec, arginfo_odbc_exec)
00344 #ifdef PHP_ODBC_HAVE_FETCH_HASH
00345        PHP_FE(odbc_fetch_array, arginfo_odbc_fetch_array)
00346        PHP_FE(odbc_fetch_object, arginfo_odbc_fetch_object)
00347 #endif
00348        PHP_FE(odbc_fetch_row, arginfo_odbc_fetch_row)
00349        PHP_FE(odbc_fetch_into, arginfo_odbc_fetch_into)
00350        PHP_FE(odbc_field_len, arginfo_odbc_field_len)
00351        PHP_FE(odbc_field_scale, arginfo_odbc_field_scale)
00352        PHP_FE(odbc_field_name, arginfo_odbc_field_name)
00353        PHP_FE(odbc_field_type, arginfo_odbc_field_type)
00354        PHP_FE(odbc_field_num, arginfo_odbc_field_num)
00355        PHP_FE(odbc_free_result, arginfo_odbc_free_result)
00356        PHP_FE(odbc_gettypeinfo, arginfo_odbc_gettypeinfo)
00357        PHP_FE(odbc_longreadlen, arginfo_odbc_longreadlen)
00358 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
00359        PHP_FE(odbc_next_result, arginfo_odbc_next_result)
00360 #endif
00361        PHP_FE(odbc_num_fields, arginfo_odbc_num_fields)
00362        PHP_FE(odbc_num_rows, arginfo_odbc_num_rows)
00363        PHP_FE(odbc_pconnect, arginfo_odbc_pconnect)
00364        PHP_FE(odbc_prepare, arginfo_odbc_prepare)
00365        PHP_FE(odbc_result, arginfo_odbc_result)
00366        PHP_FE(odbc_result_all, arginfo_odbc_result_all)
00367        PHP_FE(odbc_rollback, arginfo_odbc_rollback)
00368        PHP_FE(odbc_setoption, arginfo_odbc_setoption)
00369        PHP_FE(odbc_specialcolumns, arginfo_odbc_specialcolumns)
00370        PHP_FE(odbc_statistics, arginfo_odbc_statistics)
00371        PHP_FE(odbc_tables, arginfo_odbc_tables)
00372        PHP_FE(odbc_primarykeys, arginfo_odbc_primarykeys)
00373 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)    /* not supported now */
00374        PHP_FE(odbc_columnprivileges, arginfo_odbc_columnprivileges)
00375        PHP_FE(odbc_tableprivileges, arginfo_odbc_tableprivileges)
00376 #endif
00377 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) /* not supported */
00378        PHP_FE(odbc_foreignkeys, arginfo_odbc_foreignkeys)
00379        PHP_FE(odbc_procedures, arginfo_odbc_procedures)
00380 #if !defined(HAVE_BIRDSTEP)
00381        PHP_FE(odbc_procedurecolumns, arginfo_odbc_procedurecolumns)
00382 #endif
00383 #endif
00384        PHP_FALIAS(odbc_do, odbc_exec, arginfo_odbc_exec)
00385        PHP_FALIAS(odbc_field_precision, odbc_field_len, arginfo_odbc_field_len)
00386        PHP_FE_END
00387 };
00388 /* }}} */
00389 
00390 ZEND_DECLARE_MODULE_GLOBALS(odbc);
00391 static PHP_GINIT_FUNCTION(odbc);
00392 
00393 /* {{{ odbc_module_entry
00394  */
00395 zend_module_entry odbc_module_entry = {
00396        STANDARD_MODULE_HEADER,
00397        "odbc", 
00398        odbc_functions, 
00399        PHP_MINIT(odbc), 
00400        PHP_MSHUTDOWN(odbc),
00401        PHP_RINIT(odbc), 
00402        PHP_RSHUTDOWN(odbc), 
00403        PHP_MINFO(odbc), 
00404        "1.0",
00405        PHP_MODULE_GLOBALS(odbc),
00406        PHP_GINIT(odbc),
00407        NULL,
00408        NULL,
00409        STANDARD_MODULE_PROPERTIES_EX
00410 };
00411 /* }}} */
00412 
00413 #ifdef COMPILE_DL_ODBC
00414 ZEND_GET_MODULE(odbc)
00415 #endif
00416 
00417 /* {{{ _free_odbc_result
00418  */
00419 static void _free_odbc_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00420 {
00421        odbc_result *res = (odbc_result *)rsrc->ptr;
00422        int i;
00423        RETCODE rc;
00424        
00425        if (res) {
00426               if (res->values) {
00427                      for(i = 0; i < res->numcols; i++) {
00428                             if (res->values[i].value)
00429                                    efree(res->values[i].value);
00430                      }
00431                      efree(res->values);
00432                      res->values = NULL;
00433               }
00434               if (res->stmt) {
00435 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
00436                      SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc,
00437                                           (SQLUSMALLINT) SQL_COMMIT);
00438 #endif
00439                      rc = SQLFreeStmt(res->stmt,SQL_DROP);
00440                      /* We don't want the connection to be closed after the last statment has been closed
00441                       * Connections will be closed on shutdown
00442                       * zend_list_delete(res->conn_ptr->id);
00443                       */
00444               }
00445               efree(res);
00446        }
00447 }
00448 /* }}} */
00449 
00450 /* {{{ safe_odbc_disconnect
00451  * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher)
00452  */
00453 static void safe_odbc_disconnect( void *handle )
00454 {
00455        int ret;
00456 
00457        ret = SQLDisconnect( handle );
00458        if ( ret == SQL_ERROR )
00459        {
00460               SQLTransact( NULL, handle, SQL_ROLLBACK );
00461               SQLDisconnect( handle );
00462        }
00463 }
00464 /* }}} */
00465 
00466 /* {{{ _close_odbc_conn
00467  */
00468 static void _close_odbc_conn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00469 {
00470        int i, nument, type;
00471        void *ptr;
00472        odbc_result *res;
00473 
00474        odbc_connection *conn = (odbc_connection *)rsrc->ptr;
00475 
00476        nument = zend_hash_next_free_element(&EG(regular_list));
00477        for(i = 1; i < nument; i++) {
00478               ptr = zend_list_find(i, &type);
00479               if (ptr && (type == le_result)) {
00480                      res = (odbc_result *)ptr;
00481                      if (res->conn_ptr == conn) {
00482                             zend_list_delete(i);
00483                      }
00484               }
00485        }
00486 
00487        safe_odbc_disconnect(conn->hdbc);
00488        SQLFreeConnect(conn->hdbc);
00489        SQLFreeEnv(conn->henv);
00490        efree(conn);
00491        ODBCG(num_links)--;
00492 }
00493 /* }}} */
00494 
00495 /* {{{ void _close_odbc_pconn
00496  */
00497 static void _close_odbc_pconn(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00498 {
00499        int i, nument, type;
00500        void *ptr;
00501        odbc_result *res;
00502        odbc_connection *conn = (odbc_connection *)rsrc->ptr;
00503 
00504        nument = zend_hash_next_free_element(&EG(persistent_list));
00505        for(i = 1; i < nument; i++) {
00506               ptr = zend_list_find(i, &type);
00507               if (ptr && (type == le_result)) {
00508                      res = (odbc_result *)ptr;
00509                      if (res->conn_ptr == conn) {
00510                             zend_list_delete(i);
00511                      }
00512               }
00513        }
00514        
00515        safe_odbc_disconnect(conn->hdbc);
00516        SQLFreeConnect(conn->hdbc);
00517        SQLFreeEnv(conn->henv);
00518        free(conn);
00519 
00520        ODBCG(num_links)--;
00521        ODBCG(num_persistent)--;
00522 }
00523 /* }}} */
00524 
00525 /* {{{ PHP_INI_DISP(display_link_nums)
00526  */
00527 static PHP_INI_DISP(display_link_nums)
00528 {
00529        char *value;
00530        TSRMLS_FETCH();
00531 
00532        if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
00533               value = ini_entry->orig_value;
00534        } else if (ini_entry->value) {
00535               value = ini_entry->value;
00536        } else {
00537               value = NULL;
00538        }
00539 
00540        if (value) {
00541               if (atoi(value) == -1) {
00542                      PUTS("Unlimited");
00543               } else {
00544                      php_printf("%s", value);
00545               }
00546        }
00547 }
00548 /* }}} */
00549 
00550 /* {{{ PHP_INI_DISP(display_defPW)
00551  */
00552 static PHP_INI_DISP(display_defPW)
00553 {
00554        char *value;
00555        TSRMLS_FETCH();
00556 
00557        if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
00558               value = ini_entry->orig_value;
00559        } else if (ini_entry->value) {
00560               value = ini_entry->value;
00561        } else {
00562               value = NULL;
00563        }
00564 
00565        if (value) {
00566 #if PHP_DEBUG
00567               php_printf("%s", value);
00568 #else
00569               PUTS("********");
00570 #endif
00571        } else {
00572               if (PG(html_errors)) {
00573                      PUTS("<i>no value</i>");
00574               } else {
00575                      PUTS("no value");
00576               }
00577        }
00578 }
00579 /* }}} */
00580 
00581 /* {{{ PHP_INI_DISP(display_binmode)
00582  */
00583 static PHP_INI_DISP(display_binmode)
00584 {
00585        char *value;
00586        TSRMLS_FETCH();
00587        
00588        if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
00589               value = ini_entry->orig_value;
00590        } else if (ini_entry->value) {
00591               value = ini_entry->value;
00592        } else {
00593               value = NULL;
00594        }
00595 
00596        if (value) {
00597               switch(atoi(value)) {
00598                      case 0:
00599                             PUTS("passthru");
00600                             break;
00601                      case 1:
00602                             PUTS("return as is");
00603                             break;
00604                      case 2:
00605                             PUTS("return as char");
00606                             break;
00607               }
00608        }
00609 }
00610 /* }}} */
00611 
00612 /* {{{ PHP_INI_DISP(display_lrl)
00613  */
00614 static PHP_INI_DISP(display_lrl)
00615 {
00616        char *value;
00617        TSRMLS_FETCH();
00618 
00619        if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
00620               value = ini_entry->orig_value;
00621        } else if (ini_entry->value) {
00622               value = ini_entry->value;
00623        } else {
00624               value = NULL;
00625        }
00626 
00627        if (value) {
00628               if (atoi(value) <= 0) {
00629                      PUTS("Passthru");
00630               } else {
00631                      php_printf("return up to %s bytes", value);
00632               }
00633        }
00634 }
00635 /* }}} */
00636 
00637 
00638 /* {{{ PHP_INI_DISP(display_cursortype)
00639  */
00640 static PHP_INI_DISP(display_cursortype)
00641 {
00642        char *value;
00643        TSRMLS_FETCH();
00644 
00645        if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
00646               value = ini_entry->orig_value;
00647        } else if (ini_entry->value) {
00648               value = ini_entry->value;
00649        } else {
00650               value = NULL;
00651        }
00652 
00653        if (value) {
00654               switch (atoi (value))
00655                 {
00656                   case SQL_CURSOR_FORWARD_ONLY:
00657                             PUTS ("Forward Only cursor");
00658                             break;
00659 
00660                      case SQL_CURSOR_STATIC:
00661                          PUTS ("Static cursor");
00662                             break;
00663 
00664                      case SQL_CURSOR_KEYSET_DRIVEN:
00665                             PUTS ("Keyset driven cursor");
00666                             break;
00667 
00668                      case SQL_CURSOR_DYNAMIC:
00669                             PUTS ("Dynamic cursor");
00670                             break;
00671 
00672                      default:
00673                             php_printf("Unknown cursor model %s", value);
00674                             break;
00675                 }
00676        }
00677 }
00678 
00679 /* }}} */
00680 
00681 /* {{{ PHP_INI_BEGIN 
00682  */
00683 PHP_INI_BEGIN()
00684        STD_PHP_INI_BOOLEAN("odbc.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
00685                      allow_persistent, zend_odbc_globals, odbc_globals)
00686        STD_PHP_INI_ENTRY_EX("odbc.max_persistent",  "-1", PHP_INI_SYSTEM, OnUpdateLong,
00687                      max_persistent, zend_odbc_globals, odbc_globals, display_link_nums)
00688        STD_PHP_INI_ENTRY_EX("odbc.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong,
00689                      max_links, zend_odbc_globals, odbc_globals, display_link_nums)
00690        STD_PHP_INI_ENTRY("odbc.default_db", NULL, PHP_INI_ALL, OnUpdateString,
00691                      defDB, zend_odbc_globals, odbc_globals)
00692        STD_PHP_INI_ENTRY("odbc.default_user", NULL, PHP_INI_ALL, OnUpdateString,
00693                      defUser, zend_odbc_globals, odbc_globals)
00694        STD_PHP_INI_ENTRY_EX("odbc.default_pw", NULL, PHP_INI_ALL, OnUpdateString,
00695                      defPW, zend_odbc_globals, odbc_globals, display_defPW)
00696        STD_PHP_INI_ENTRY_EX("odbc.defaultlrl", "4096", PHP_INI_ALL, OnUpdateLong,
00697                      defaultlrl, zend_odbc_globals, odbc_globals, display_lrl)
00698        STD_PHP_INI_ENTRY_EX("odbc.defaultbinmode", "1", PHP_INI_ALL, OnUpdateLong,
00699                      defaultbinmode, zend_odbc_globals, odbc_globals, display_binmode)
00700        STD_PHP_INI_BOOLEAN("odbc.check_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong,
00701                      check_persistent, zend_odbc_globals, odbc_globals)
00702        STD_PHP_INI_ENTRY_EX("odbc.default_cursortype", "3", PHP_INI_ALL, OnUpdateLong, 
00703                      default_cursortype, zend_odbc_globals, odbc_globals, display_cursortype)
00704 PHP_INI_END()
00705 /* }}} */
00706 
00707 static PHP_GINIT_FUNCTION(odbc)
00708 {
00709        odbc_globals->num_persistent = 0;
00710 }
00711 
00712 /* {{{ PHP_MINIT_FUNCTION */
00713 PHP_MINIT_FUNCTION(odbc)
00714 {
00715 #ifdef SQLANY_BUG
00716        ODBC_SQL_CONN_T foobar;
00717        RETCODE rc;
00718 #endif
00719 
00720        REGISTER_INI_ENTRIES();
00721        le_result = zend_register_list_destructors_ex(_free_odbc_result, NULL, "odbc result", module_number);
00722        le_conn = zend_register_list_destructors_ex(_close_odbc_conn, NULL, "odbc link", module_number);
00723        le_pconn = zend_register_list_destructors_ex(NULL, _close_odbc_pconn, "odbc link persistent", module_number);
00724        Z_TYPE(odbc_module_entry) = type;
00725        
00726        REGISTER_STRING_CONSTANT("ODBC_TYPE", PHP_ODBC_TYPE, CONST_CS | CONST_PERSISTENT);
00727        REGISTER_LONG_CONSTANT("ODBC_BINMODE_PASSTHRU", 0, CONST_CS | CONST_PERSISTENT);
00728        REGISTER_LONG_CONSTANT("ODBC_BINMODE_RETURN", 1, CONST_CS | CONST_PERSISTENT);
00729        REGISTER_LONG_CONSTANT("ODBC_BINMODE_CONVERT", 2, CONST_CS | CONST_PERSISTENT);
00730        /* Define Constants for options
00731           these Constants are defined in <sqlext.h>
00732        */
00733        REGISTER_LONG_CONSTANT("SQL_ODBC_CURSORS", SQL_ODBC_CURSORS, CONST_PERSISTENT | CONST_CS);
00734        REGISTER_LONG_CONSTANT("SQL_CUR_USE_DRIVER", SQL_CUR_USE_DRIVER, CONST_PERSISTENT | CONST_CS);
00735        REGISTER_LONG_CONSTANT("SQL_CUR_USE_IF_NEEDED", SQL_CUR_USE_IF_NEEDED, CONST_PERSISTENT | CONST_CS);
00736        REGISTER_LONG_CONSTANT("SQL_CUR_USE_ODBC", SQL_CUR_USE_ODBC, CONST_PERSISTENT | CONST_CS);
00737 
00738 
00739        REGISTER_LONG_CONSTANT("SQL_CONCURRENCY", SQL_CONCURRENCY, CONST_PERSISTENT | CONST_CS);
00740        REGISTER_LONG_CONSTANT("SQL_CONCUR_READ_ONLY", SQL_CONCUR_READ_ONLY, CONST_PERSISTENT | CONST_CS);
00741        REGISTER_LONG_CONSTANT("SQL_CONCUR_LOCK", SQL_CONCUR_LOCK, CONST_PERSISTENT | CONST_CS);
00742        REGISTER_LONG_CONSTANT("SQL_CONCUR_ROWVER", SQL_CONCUR_ROWVER, CONST_PERSISTENT | CONST_CS);
00743        REGISTER_LONG_CONSTANT("SQL_CONCUR_VALUES", SQL_CONCUR_VALUES, CONST_PERSISTENT | CONST_CS);
00744 
00745        REGISTER_LONG_CONSTANT("SQL_CURSOR_TYPE", SQL_CURSOR_TYPE, CONST_PERSISTENT | CONST_CS);
00746        REGISTER_LONG_CONSTANT("SQL_CURSOR_FORWARD_ONLY", SQL_CURSOR_FORWARD_ONLY, CONST_PERSISTENT | CONST_CS);
00747        REGISTER_LONG_CONSTANT("SQL_CURSOR_KEYSET_DRIVEN", SQL_CURSOR_KEYSET_DRIVEN, CONST_PERSISTENT | CONST_CS);
00748        REGISTER_LONG_CONSTANT("SQL_CURSOR_DYNAMIC", SQL_CURSOR_DYNAMIC, CONST_PERSISTENT | CONST_CS);
00749        REGISTER_LONG_CONSTANT("SQL_CURSOR_STATIC", SQL_CURSOR_STATIC, CONST_PERSISTENT | CONST_CS);
00750        
00751        REGISTER_LONG_CONSTANT("SQL_KEYSET_SIZE", SQL_KEYSET_SIZE, CONST_PERSISTENT | CONST_CS);
00752 
00753        /* these are for the Data Source type */
00754        REGISTER_LONG_CONSTANT("SQL_FETCH_FIRST", SQL_FETCH_FIRST, CONST_PERSISTENT | CONST_CS);
00755        REGISTER_LONG_CONSTANT("SQL_FETCH_NEXT", SQL_FETCH_NEXT, CONST_PERSISTENT | CONST_CS);
00756 
00757        /*
00758         * register the standard data types
00759         */
00760        REGISTER_LONG_CONSTANT("SQL_CHAR", SQL_CHAR, CONST_PERSISTENT | CONST_CS);
00761        REGISTER_LONG_CONSTANT("SQL_VARCHAR", SQL_VARCHAR, CONST_PERSISTENT | CONST_CS);
00762        REGISTER_LONG_CONSTANT("SQL_LONGVARCHAR", SQL_LONGVARCHAR, CONST_PERSISTENT | CONST_CS);
00763        REGISTER_LONG_CONSTANT("SQL_DECIMAL", SQL_DECIMAL, CONST_PERSISTENT | CONST_CS);
00764        REGISTER_LONG_CONSTANT("SQL_NUMERIC", SQL_NUMERIC, CONST_PERSISTENT | CONST_CS);
00765        REGISTER_LONG_CONSTANT("SQL_BIT", SQL_BIT, CONST_PERSISTENT | CONST_CS);
00766        REGISTER_LONG_CONSTANT("SQL_TINYINT", SQL_TINYINT, CONST_PERSISTENT | CONST_CS);
00767        REGISTER_LONG_CONSTANT("SQL_SMALLINT", SQL_SMALLINT, CONST_PERSISTENT | CONST_CS);
00768        REGISTER_LONG_CONSTANT("SQL_INTEGER", SQL_INTEGER, CONST_PERSISTENT | CONST_CS);
00769        REGISTER_LONG_CONSTANT("SQL_BIGINT", SQL_BIGINT, CONST_PERSISTENT | CONST_CS);
00770        REGISTER_LONG_CONSTANT("SQL_REAL", SQL_REAL, CONST_PERSISTENT | CONST_CS);
00771        REGISTER_LONG_CONSTANT("SQL_FLOAT", SQL_FLOAT, CONST_PERSISTENT | CONST_CS);
00772        REGISTER_LONG_CONSTANT("SQL_DOUBLE", SQL_DOUBLE, CONST_PERSISTENT | CONST_CS);
00773        REGISTER_LONG_CONSTANT("SQL_BINARY", SQL_BINARY, CONST_PERSISTENT | CONST_CS);
00774        REGISTER_LONG_CONSTANT("SQL_VARBINARY", SQL_VARBINARY, CONST_PERSISTENT | CONST_CS);
00775        REGISTER_LONG_CONSTANT("SQL_LONGVARBINARY", SQL_LONGVARBINARY, CONST_PERSISTENT | CONST_CS);
00776        REGISTER_LONG_CONSTANT("SQL_DATE", SQL_DATE, CONST_PERSISTENT | CONST_CS);
00777        REGISTER_LONG_CONSTANT("SQL_TIME", SQL_TIME, CONST_PERSISTENT | CONST_CS);
00778        REGISTER_LONG_CONSTANT("SQL_TIMESTAMP", SQL_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
00779 #if defined(ODBCVER) && (ODBCVER >= 0x0300)
00780        REGISTER_LONG_CONSTANT("SQL_TYPE_DATE", SQL_TYPE_DATE, CONST_PERSISTENT | CONST_CS);
00781        REGISTER_LONG_CONSTANT("SQL_TYPE_TIME", SQL_TYPE_TIME, CONST_PERSISTENT | CONST_CS);
00782        REGISTER_LONG_CONSTANT("SQL_TYPE_TIMESTAMP", SQL_TYPE_TIMESTAMP, CONST_PERSISTENT | CONST_CS);
00783 
00784        /*
00785         * SQLSpecialColumns values
00786         */
00787        REGISTER_LONG_CONSTANT("SQL_BEST_ROWID", SQL_BEST_ROWID, CONST_PERSISTENT | CONST_CS);
00788        REGISTER_LONG_CONSTANT("SQL_ROWVER", SQL_ROWVER, CONST_PERSISTENT | CONST_CS);
00789        REGISTER_LONG_CONSTANT("SQL_SCOPE_CURROW", SQL_SCOPE_CURROW, CONST_PERSISTENT | CONST_CS);
00790        REGISTER_LONG_CONSTANT("SQL_SCOPE_TRANSACTION", SQL_SCOPE_TRANSACTION, CONST_PERSISTENT | CONST_CS);
00791        REGISTER_LONG_CONSTANT("SQL_SCOPE_SESSION", SQL_SCOPE_SESSION, CONST_PERSISTENT | CONST_CS);
00792        REGISTER_LONG_CONSTANT("SQL_NO_NULLS", SQL_NO_NULLS, CONST_PERSISTENT | CONST_CS);
00793        REGISTER_LONG_CONSTANT("SQL_NULLABLE", SQL_NULLABLE, CONST_PERSISTENT | CONST_CS);
00794 
00795        /*
00796         * SQLStatistics values
00797         */
00798        REGISTER_LONG_CONSTANT("SQL_INDEX_UNIQUE", SQL_INDEX_UNIQUE, CONST_PERSISTENT | CONST_CS);
00799        REGISTER_LONG_CONSTANT("SQL_INDEX_ALL", SQL_INDEX_ALL, CONST_PERSISTENT | CONST_CS);
00800        REGISTER_LONG_CONSTANT("SQL_ENSURE", SQL_ENSURE, CONST_PERSISTENT | CONST_CS);
00801        REGISTER_LONG_CONSTANT("SQL_QUICK", SQL_QUICK, CONST_PERSISTENT | CONST_CS);
00802 #endif
00803 
00804 #if defined(HAVE_IBMDB2) && defined(_AIX)
00805        /* atexit() handler in the DB2/AIX library segfaults in PHP CLI */
00806        /* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */
00807        putenv("DB2NOEXITLIST=TRUE");
00808 #endif
00809 
00810        return SUCCESS;
00811 }
00812 /* }}} */
00813 
00814 /* {{{ PHP_RINIT_FUNCTION */
00815 PHP_RINIT_FUNCTION(odbc)
00816 {
00817        ODBCG(defConn) = -1;
00818        ODBCG(num_links) = ODBCG(num_persistent);
00819        memset(ODBCG(laststate), '\0', 6);
00820        memset(ODBCG(lasterrormsg), '\0', SQL_MAX_MESSAGE_LENGTH);
00821        return SUCCESS;
00822 }
00823 /* }}} */
00824 
00825 /* {{{ PHP_RSHUTDOWN_FUNCTION */
00826 PHP_RSHUTDOWN_FUNCTION(odbc)
00827 {
00828        return SUCCESS;
00829 }
00830 /* }}} */
00831 
00832 /* {{{ PHP_MSHUTDOWN_FUNCTION */
00833 PHP_MSHUTDOWN_FUNCTION(odbc)
00834 {
00835        UNREGISTER_INI_ENTRIES();
00836        return SUCCESS;
00837 }
00838 /* }}} */
00839 
00840 /* {{{ PHP_MINFO_FUNCTION */
00841 PHP_MINFO_FUNCTION(odbc)
00842 {
00843        char buf[32];
00844 
00845        php_info_print_table_start();
00846        php_info_print_table_header(2, "ODBC Support", "enabled");
00847        snprintf(buf, sizeof(buf), "%ld", ODBCG(num_persistent));
00848        php_info_print_table_row(2, "Active Persistent Links", buf);
00849        snprintf(buf, sizeof(buf), "%ld", ODBCG(num_links));
00850        php_info_print_table_row(2, "Active Links", buf);
00851        php_info_print_table_row(2, "ODBC library", PHP_ODBC_TYPE);
00852 #ifndef PHP_WIN32
00853        php_info_print_table_row(2, "ODBC_INCLUDE", PHP_ODBC_INCLUDE);
00854        php_info_print_table_row(2, "ODBC_LFLAGS", PHP_ODBC_LFLAGS);
00855        php_info_print_table_row(2, "ODBC_LIBS", PHP_ODBC_LIBS);
00856 #endif
00857        php_info_print_table_end();
00858 
00859        DISPLAY_INI_ENTRIES();
00860 
00861 }       
00862 /* }}} */
00863 
00864 /* {{{ odbc_sql_error */
00865 void odbc_sql_error(ODBC_SQL_ERROR_PARAMS)
00866 {
00867        char              state[6];
00868        SQLINTEGER    error;        /* Not used */
00869        char              errormsg[SQL_MAX_MESSAGE_LENGTH];
00870        SQLSMALLINT   errormsgsize; /* Not used */
00871        RETCODE rc;
00872        ODBC_SQL_ENV_T henv;
00873        ODBC_SQL_CONN_T conn;
00874        TSRMLS_FETCH();
00875 
00876        if (conn_resource) {
00877               henv = conn_resource->henv;
00878               conn = conn_resource->hdbc;
00879        } else {
00880               henv = SQL_NULL_HENV;
00881               conn = SQL_NULL_HDBC;
00882        }
00883 
00884        /* This leads to an endless loop in many drivers! 
00885         *
00886           while(henv != SQL_NULL_HENV){
00887               do {
00888         */
00889        rc = SQLError(henv, conn, stmt, state, &error, errormsg, sizeof(errormsg)-1, &errormsgsize);
00890        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00891               snprintf(state, sizeof(state), "HY000");
00892               snprintf(errormsg, sizeof(errormsg), "Failed to fetch error message");
00893        }
00894        if (conn_resource) {
00895               memcpy(conn_resource->laststate, state, sizeof(state));
00896               memcpy(conn_resource->lasterrormsg, errormsg, sizeof(errormsg));
00897        }
00898        memcpy(ODBCG(laststate), state, sizeof(state));
00899        memcpy(ODBCG(lasterrormsg), errormsg, sizeof(errormsg));
00900        if (func) {
00901               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s in %s", errormsg, state, func);
00902        } else {
00903               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
00904        }
00905        /*            
00906               } while (SQL_SUCCEEDED(rc));
00907        }
00908        */
00909 }
00910 /* }}} */
00911 
00912 /* {{{ php_odbc_fetch_attribs */
00913 void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode)
00914 {
00915        odbc_result *result;
00916        zval *pv_res;
00917        long flag;
00918 
00919        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &flag) == FAILURE) {
00920               return;
00921        }
00922        
00923        if (Z_LVAL_P(pv_res)) {
00924               ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
00925         if (mode) {
00926             result->longreadlen = flag;
00927         } else {
00928             result->binmode = flag;
00929               }
00930        } else {
00931         if (mode) {
00932             ODBCG(defaultlrl) = flag;
00933         } else {
00934             ODBCG(defaultbinmode) = flag;
00935               }
00936        }
00937        RETURN_TRUE;
00938 }
00939 /* }}} */
00940 
00941 /* {{{ odbc_bindcols */
00942 int odbc_bindcols(odbc_result *result TSRMLS_DC)
00943 {
00944        RETCODE rc;
00945        int i;
00946        SQLSMALLINT colnamelen; /* Not used */
00947        SQLLEN      displaysize;
00948 
00949        result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0);
00950 
00951        result->longreadlen = ODBCG(defaultlrl);
00952        result->binmode = ODBCG(defaultbinmode);
00953 
00954        for(i = 0; i < result->numcols; i++) {
00955               rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_NAME, 
00956                             result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0);
00957               rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_TYPE, 
00958                             NULL, 0, NULL, &result->values[i].coltype);
00959               
00960               /* Don't bind LONG / BINARY columns, so that fetch behaviour can
00961                * be controlled by odbc_binmode() / odbc_longreadlen()
00962                */
00963               
00964               switch(result->values[i].coltype) {
00965                      case SQL_BINARY:
00966                      case SQL_VARBINARY:
00967                      case SQL_LONGVARBINARY:
00968                      case SQL_LONGVARCHAR:
00969                             result->values[i].value = NULL;
00970                             break;
00971                             
00972 #ifdef HAVE_ADABAS
00973                      case SQL_TIMESTAMP:
00974                             result->values[i].value = (char *)emalloc(27);
00975                             SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
00976                                                  27, &result->values[i].vallen);
00977                             break;
00978 #endif /* HAVE_ADABAS */
00979                      default:
00980                             rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE,
00981                                                                NULL, 0, NULL, &displaysize);
00982                             displaysize = displaysize <= result->longreadlen ? displaysize : 
00983                                                         result->longreadlen;
00984                             /* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */
00985                             if (result->values[i].coltype == SQL_TIMESTAMP) {
00986                                    displaysize += 3;
00987                             }
00988                             result->values[i].value = (char *)emalloc(displaysize + 1);
00989                             rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value,
00990                                                  displaysize + 1, &result->values[i].vallen);
00991                             break;
00992               }
00993        }
00994        return 1;
00995 }
00996 /* }}} */
00997 
00998 /* {{{ odbc_transact */
00999 void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type)
01000 {
01001        odbc_connection *conn;
01002        RETCODE rc;
01003        zval *pv_conn;
01004        
01005        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
01006               return;
01007        }
01008 
01009        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
01010        
01011        rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK));
01012        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01013               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTransact");
01014               RETURN_FALSE;
01015        }
01016 
01017        RETURN_TRUE;
01018 }
01019 /* }}} */
01020 
01021 /* {{{ _close_pconn_with_id */
01022 static int _close_pconn_with_id(zend_rsrc_list_entry *le, int *id TSRMLS_DC)
01023 {
01024        if(Z_TYPE_P(le) == le_pconn && (((odbc_connection *)(le->ptr))->id == *id)){
01025               return 1;
01026        }else{
01027               return 0;
01028        }
01029 }
01030 /* }}} */
01031 
01032 /* {{{ odbc_column_lengths */
01033 void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
01034 {
01035        odbc_result *result;
01036 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
01037        /* this seems to be necessary for Solid2.3 ( tested by 
01038         * tammy@synchronis.com) and Solid 3.0 (tested by eric@terra.telemediair.nl)
01039         * Solid does not seem to declare a SQLINTEGER, but it does declare a
01040         * SQL_INTEGER which does not work (despite being the same type as a SDWORD.
01041         * Solid 3.5 does not have this issue.
01042         */
01043        SDWORD len;
01044 #else
01045        SQLLEN len;
01046 #endif
01047        zval *pv_res;
01048        long pv_num;
01049 
01050        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
01051               return;
01052        }
01053 
01054        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01055 
01056        if (result->numcols == 0) {
01057               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
01058               RETURN_FALSE;
01059        }
01060 
01061        if (pv_num > result->numcols) {
01062               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
01063               RETURN_FALSE;
01064        }
01065 
01066        if (pv_num < 1) {
01067               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
01068               RETURN_FALSE;
01069        }
01070 
01071        SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT) (type?SQL_COLUMN_SCALE:SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
01072 
01073        RETURN_LONG(len);
01074 }
01075 /* }}} */
01076 
01077 /* Main User Functions */
01078 
01079 /* {{{ proto void odbc_close_all(void)
01080    Close all ODBC connections */
01081 PHP_FUNCTION(odbc_close_all)
01082 {
01083        void *ptr;
01084        int type;
01085        int i;
01086        int nument;
01087 
01088        if (zend_parse_parameters_none() == FAILURE) {
01089               return;
01090        }
01091 
01092        nument = zend_hash_next_free_element(&EG(regular_list));
01093        
01094        /* Loop through list and close all statements */
01095        for(i = 1; i < nument; i++) {
01096               ptr = zend_list_find(i, &type);
01097               if (ptr && (type == le_result)){
01098                      zend_list_delete(i);
01099               }
01100        }
01101 
01102        /* Second loop through list, now close all connections */
01103        nument = zend_hash_next_free_element(&EG(regular_list));
01104        
01105        for(i = 1; i < nument; i++) {
01106               ptr = zend_list_find(i, &type);
01107               if (ptr){
01108                      if(type == le_conn){
01109                             zend_list_delete(i);
01110                      }else if(type == le_pconn){
01111                             zend_list_delete(i);
01112                             /* Delete the persistent connection */
01113                             zend_hash_apply_with_argument(&EG(persistent_list), 
01114                                    (apply_func_arg_t) _close_pconn_with_id, (void *) &i TSRMLS_CC);
01115                      }
01116               }
01117        }
01118 }
01119 /* }}} */
01120 
01121 /* {{{ proto bool odbc_binmode(int result_id, int mode)
01122    Handle binary column data */
01123 PHP_FUNCTION(odbc_binmode)
01124 {
01125        php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01126 }
01127 /* }}} */
01128 
01129 /* {{{ proto bool odbc_longreadlen(int result_id, int length)
01130    Handle LONG columns */
01131 PHP_FUNCTION(odbc_longreadlen)
01132 {
01133        php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01134 }
01135 /* }}} */
01136 
01137 /* {{{ proto resource odbc_prepare(resource connection_id, string query)
01138    Prepares a statement for execution */
01139 PHP_FUNCTION(odbc_prepare)
01140 {
01141        zval *pv_conn;
01142        char *query;
01143        int query_len;
01144        odbc_result *result = NULL;
01145        odbc_connection *conn;
01146        RETCODE rc;
01147 #ifdef HAVE_SQL_EXTENDED_FETCH
01148        SQLUINTEGER      scrollopts;
01149 #endif
01150 
01151        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_conn, &query, &query_len) == FAILURE) {
01152               return;
01153        }
01154 
01155        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
01156 
01157        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
01158        
01159        result->numparams = 0;
01160        
01161        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
01162        if (rc == SQL_INVALID_HANDLE) {
01163               efree(result);
01164               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
01165               RETURN_FALSE;
01166        }
01167 
01168        if (rc == SQL_ERROR) {
01169               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
01170               efree(result);
01171               RETURN_FALSE;
01172        }
01173 
01174 #ifdef HAVE_SQL_EXTENDED_FETCH
01175        /* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
01176           whether Driver supports ExtendedFetch */
01177        rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
01178        if (rc == SQL_SUCCESS) {
01179               if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
01180                      /* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
01181                         type if not possible.
01182                      */
01183                      SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
01184               }
01185        } else {
01186               result->fetch_abs = 0;
01187        }
01188 #endif
01189 
01190        rc = SQLPrepare(result->stmt, query, SQL_NTS);
01191        switch (rc) {
01192               case SQL_SUCCESS:
01193                      break;
01194               case SQL_SUCCESS_WITH_INFO:
01195                      odbc_sql_error(conn, result->stmt, "SQLPrepare");
01196                      break;
01197               default:
01198                      odbc_sql_error(conn, result->stmt, "SQLPrepare");
01199                      RETURN_FALSE;
01200        }
01201        
01202        SQLNumParams(result->stmt, &(result->numparams));
01203        SQLNumResultCols(result->stmt, &(result->numcols));
01204 
01205        if (result->numcols > 0) {
01206               if (!odbc_bindcols(result TSRMLS_CC)) {
01207                      efree(result);
01208                      RETURN_FALSE;
01209               }
01210        } else {
01211               result->values = NULL;
01212        }
01213        zend_list_addref(conn->id);
01214        result->conn_ptr = conn;
01215        result->fetched = 0;
01216        ZEND_REGISTER_RESOURCE(return_value, result, le_result);  
01217 }
01218 /* }}} */
01219 
01220 /*
01221  * Execute prepared SQL statement. Supports only input parameters.
01222  */
01223 
01224 /* {{{ proto bool odbc_execute(resource result_id [, array parameters_array])
01225    Execute a prepared statement */
01226 PHP_FUNCTION(odbc_execute)
01227 { 
01228        zval *pv_res, *pv_param_arr, **tmp;
01229        typedef struct params_t {
01230               SQLLEN vallen;
01231               int fp;
01232        } params_t;
01233        params_t *params = NULL;
01234        char *filename;
01235        unsigned char otype;
01236        SQLSMALLINT sqltype, ctype, scale;
01237        SQLSMALLINT nullable;
01238        SQLULEN precision;
01239        odbc_result *result;
01240        int numArgs, i, ne;
01241        RETCODE rc;
01242        
01243        numArgs = ZEND_NUM_ARGS();
01244        
01245        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|a", &pv_res, &pv_param_arr) == FAILURE) {
01246               return;
01247        }
01248 
01249        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01250        
01251        /* XXX check for already bound parameters*/
01252        if (result->numparams > 0 && numArgs == 1) {
01253               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No parameters to SQL statement given");
01254               RETURN_FALSE;
01255        }
01256 
01257        if (result->numparams > 0) {
01258               if ((ne = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr))) < result->numparams) {
01259                      php_error_docref(NULL TSRMLS_CC, E_WARNING,"Not enough parameters (%d should be %d) given", ne, result->numparams);
01260                      RETURN_FALSE;
01261               }
01262 
01263               zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
01264               params = (params_t *)safe_emalloc(sizeof(params_t), result->numparams, 0);
01265               for(i = 0; i < result->numparams; i++) {
01266                      params[i].fp = -1;
01267               }
01268               
01269               for(i = 1; i <= result->numparams; i++) {
01270                      if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
01271                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
01272                             SQLFreeStmt(result->stmt,SQL_RESET_PARAMS);
01273                             for (i = 0; i < result->numparams; i++) {
01274                                    if (params[i].fp != -1) {
01275                                           close(params[i].fp);
01276                                    }
01277                             }
01278                             efree(params);
01279                             RETURN_FALSE;
01280                      }
01281 
01282                      otype = (*tmp)->type;
01283                      convert_to_string_ex(tmp);
01284                      if (Z_TYPE_PP(tmp) != IS_STRING) {
01285                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
01286                             SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01287                             for (i = 0; i < result->numparams; i++) {
01288                                    if (params[i].fp != -1) {
01289                                           close(params[i].fp);
01290                                    }
01291                             }
01292                             efree(params);
01293                             RETURN_FALSE;
01294                      }
01295                      
01296                      rc = SQLDescribeParam(result->stmt, (SQLUSMALLINT)i, &sqltype, &precision, &scale, &nullable);
01297                      params[i-1].vallen = Z_STRLEN_PP(tmp);
01298                      params[i-1].fp = -1;
01299                      if (rc == SQL_ERROR) {
01300                             odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter");      
01301                             SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01302                             for (i = 0; i < result->numparams; i++) {
01303                                    if (params[i].fp != -1) {
01304                                           close(params[i].fp);
01305                                    }
01306                             }
01307                             efree(params);
01308                             RETURN_FALSE;
01309                      }
01310 
01311                      if (IS_SQL_BINARY(sqltype)) {
01312                             ctype = SQL_C_BINARY;
01313                      } else {
01314                             ctype = SQL_C_CHAR;
01315                      }
01316 
01317                      if (Z_STRLEN_PP(tmp) > 2 &&
01318                             Z_STRVAL_PP(tmp)[0] == '\'' &&
01319                             Z_STRVAL_PP(tmp)[Z_STRLEN_PP(tmp) - 1] == '\'') {
01320                             if (strlen(tmp) != Z_STRLEN_PP(tmp)) {
01321                                    RETURN_FALSE;
01322                             }
01323 
01324                             filename = estrndup(&Z_STRVAL_PP(tmp)[1], Z_STRLEN_PP(tmp) - 2);
01325 
01326                             /* Check for safe mode. */
01327                             if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
01328                                    efree(filename);
01329                                    efree(params);
01330                                    RETURN_FALSE;
01331                             }
01332 
01333                             /* Check the basedir */
01334                             if (php_check_open_basedir(filename TSRMLS_CC)) {
01335                                    efree(filename);
01336                                    SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01337                                    for (i = 0; i < result->numparams; i++) {
01338                                           if (params[i].fp != -1) {
01339                                                  close(params[i].fp);
01340                                           }
01341                                    }
01342                                    efree(params);
01343                                    RETURN_FALSE;
01344                             }
01345 
01346                             if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
01347                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Can't open file %s", filename);
01348                                    SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01349                                    for (i = 0; i < result->numparams; i++) {
01350                                           if (params[i].fp != -1) {
01351                                                  close(params[i].fp);
01352                                           }
01353                                    }
01354                                    efree(params);
01355                                    efree(filename);
01356                                    RETURN_FALSE;
01357                             }
01358 
01359                             efree(filename);
01360 
01361                             params[i-1].vallen = SQL_LEN_DATA_AT_EXEC(0);
01362 
01363                             rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
01364                                                                  ctype, sqltype, precision, scale,
01365                                                                  (void *)params[i-1].fp, 0,
01366                                                                  &params[i-1].vallen);
01367                      } else {
01368 #ifdef HAVE_DBMAKER
01369                             precision = params[i-1].vallen;
01370 #endif
01371                             if (otype == IS_NULL) {
01372                                    params[i-1].vallen = SQL_NULL_DATA;
01373                             }
01374 
01375                             rc = SQLBindParameter(result->stmt, (SQLUSMALLINT)i, SQL_PARAM_INPUT,
01376                                                                  ctype, sqltype, precision, scale,
01377                                                                  Z_STRVAL_PP(tmp), 0,
01378                                                                  &params[i-1].vallen);
01379                      }
01380                      if (rc == SQL_ERROR) {
01381                             odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");   
01382                             SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01383                             for (i = 0; i < result->numparams; i++) {
01384                                    if (params[i].fp != -1) {
01385                                           close(params[i].fp);
01386                                    }
01387                             }
01388                             efree(params);
01389                             RETURN_FALSE;
01390                      }
01391                      zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
01392               }
01393        }
01394        /* Close cursor, needed for doing multiple selects */
01395        rc = SQLFreeStmt(result->stmt, SQL_CLOSE);
01396 
01397        if (rc == SQL_ERROR) {
01398               odbc_sql_error(result->conn_ptr, result->stmt, "SQLFreeStmt"); 
01399        }
01400 
01401        rc = SQLExecute(result->stmt);
01402 
01403        result->fetched = 0;
01404        if (rc == SQL_NEED_DATA) {
01405               char buf[4096];
01406               int fp, nbytes;
01407               while (rc == SQL_NEED_DATA) {
01408                      rc = SQLParamData(result->stmt, (void*)&fp);
01409                      if (rc == SQL_NEED_DATA) {
01410                             while ((nbytes = read(fp, &buf, 4096)) > 0) {
01411                                    SQLPutData(result->stmt, (void*)&buf, nbytes);
01412                             }
01413                      }
01414               }
01415        } else {
01416               switch (rc) {
01417                      case SQL_SUCCESS:
01418                             break;
01419                      case SQL_NO_DATA_FOUND:
01420                      case SQL_SUCCESS_WITH_INFO:
01421                             odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
01422                             break;
01423                      default:
01424                             odbc_sql_error(result->conn_ptr, result->stmt, "SQLExecute");
01425                             RETVAL_FALSE;
01426               }
01427        }      
01428        
01429        if (result->numparams > 0) {
01430               SQLFreeStmt(result->stmt, SQL_RESET_PARAMS);
01431               for(i = 0; i < result->numparams; i++) {
01432                      if (params[i].fp != -1) {
01433                             close(params[i].fp);
01434                      }
01435               }
01436               efree(params);
01437        }
01438 
01439        if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO || rc == SQL_NO_DATA_FOUND) {
01440               RETVAL_TRUE;
01441        }
01442 
01443        if (result->numcols == 0) {
01444               SQLNumResultCols(result->stmt, &(result->numcols));
01445 
01446               if (result->numcols > 0) {
01447                      if (!odbc_bindcols(result TSRMLS_CC)) {
01448                             efree(result);
01449                             RETVAL_FALSE;
01450                      }
01451               } else {
01452                      result->values = NULL;
01453               }
01454        }
01455 }
01456 /* }}} */
01457 
01458 /* {{{ proto string odbc_cursor(resource result_id)
01459    Get cursor name */
01460 PHP_FUNCTION(odbc_cursor)
01461 {
01462        zval *pv_res;
01463        SQLUSMALLINT max_len;
01464        SQLSMALLINT len;
01465        char *cursorname;
01466        odbc_result *result;
01467        RETCODE rc;
01468        
01469        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
01470               return;
01471        }
01472 
01473        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01474 
01475        rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len);
01476        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01477               RETURN_FALSE;
01478        }
01479        
01480        if (max_len > 0) {
01481               cursorname = emalloc(max_len + 1);
01482               rc = SQLGetCursorName(result->stmt,cursorname,(SQLSMALLINT)max_len,&len);
01483               if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01484                      char        state[6];     /* Not used */
01485                      SQLINTEGER  error;        /* Not used */
01486                      char        errormsg[SQL_MAX_MESSAGE_LENGTH];
01487                      SQLSMALLINT errormsgsize; /* Not used */
01488 
01489                      SQLError( result->conn_ptr->henv, result->conn_ptr->hdbc,
01490                                           result->stmt, state, &error, errormsg,
01491                                           sizeof(errormsg)-1, &errormsgsize);
01492                      if (!strncmp(state,"S1015",5)) {
01493                             snprintf(cursorname, max_len+1, "php_curs_%d", (int)result->stmt);
01494                             if (SQLSetCursorName(result->stmt,cursorname,SQL_NTS) != SQL_SUCCESS) {
01495                                    odbc_sql_error(result->conn_ptr, result->stmt, "SQLSetCursorName");
01496                                    RETVAL_FALSE;
01497                             } else {
01498                                    RETVAL_STRING(cursorname,1);
01499                             }
01500                      } else {
01501                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQL error: %s, SQL state %s", errormsg, state);
01502                             RETVAL_FALSE;
01503                      }
01504               } else {
01505                      RETVAL_STRING(cursorname,1);
01506               }
01507               efree(cursorname);
01508        } else {
01509               RETVAL_FALSE;
01510        }
01511 }
01512 /* }}} */
01513 
01514 #ifdef HAVE_SQLDATASOURCES
01515 /* {{{ proto array odbc_data_source(resource connection_id, int fetch_type)
01516    Return information about the currently connected data source */
01517 PHP_FUNCTION(odbc_data_source)
01518 {
01519        zval *zv_conn;
01520        long zv_fetch_type;
01521        RETCODE rc = 0; /* assume all is good */
01522        odbc_connection *conn;
01523        UCHAR server_name[100], desc[200];
01524        SQLSMALLINT len1=0, len2=0, fetch_type;
01525 
01526        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zv_conn, &zv_fetch_type) == FAILURE) {
01527               return;
01528        }
01529 
01530        fetch_type = (SQLSMALLINT) zv_fetch_type;
01531 
01532        if (!(fetch_type == SQL_FETCH_FIRST || fetch_type == SQL_FETCH_NEXT)) {
01533               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fetch type (%d)", fetch_type);
01534               RETURN_FALSE;
01535        }
01536 
01537        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &zv_conn, -1, "ODBC-Link", le_conn, le_pconn);
01538 
01539        /* now we have the "connection" lets call the DataSource object */
01540        rc = SQLDataSources(conn->henv, 
01541                      fetch_type,
01542                      server_name,
01543                      (SQLSMALLINT)sizeof(server_name),
01544                      &len1,
01545                      desc, 
01546                      (SQLSMALLINT)sizeof(desc),
01547                      &len2);
01548 
01549        if (rc != SQL_SUCCESS) {
01550               /* ummm.... he did it */
01551               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLDataSources");
01552               RETURN_FALSE;
01553        }
01554 
01555        if (len1 == 0 || len2 == 0) {
01556               /* we have a non-valid entry... so stop the looping */
01557               RETURN_FALSE;
01558        }
01559 
01560        array_init(return_value);
01561 
01562        add_assoc_string_ex(return_value, "server", sizeof("server"), server_name, 1);
01563        add_assoc_string_ex(return_value, "description", sizeof("description"), desc, 1);
01564 
01565 }
01566 /* }}} */
01567 #endif /* HAVE_SQLDATASOURCES */
01568 
01569 /* {{{ proto resource odbc_exec(resource connection_id, string query [, int flags])
01570    Prepare and execute an SQL statement */
01571 /* XXX Use flags */
01572 PHP_FUNCTION(odbc_exec)
01573 {
01574        zval *pv_conn;
01575        long pv_flags;
01576        char *query;
01577        int numArgs, query_len;
01578        odbc_result *result = NULL;
01579        odbc_connection *conn;
01580        RETCODE rc;
01581 #ifdef HAVE_SQL_EXTENDED_FETCH
01582        SQLUINTEGER      scrollopts;
01583 #endif
01584 
01585        numArgs = ZEND_NUM_ARGS();
01586        
01587        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &pv_conn, &query, &query_len, &pv_flags) == FAILURE) {
01588               return;
01589        }
01590 
01591        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
01592               
01593        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
01594 
01595        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
01596        if (rc == SQL_INVALID_HANDLE) {
01597               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
01598               efree(result);
01599               RETURN_FALSE;
01600        }
01601 
01602        if (rc == SQL_ERROR) {
01603               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
01604               efree(result);
01605               RETURN_FALSE;
01606        }
01607        
01608 #ifdef HAVE_SQL_EXTENDED_FETCH
01609        /* Solid doesn't have ExtendedFetch, if DriverManager is used, get Info,
01610           whether Driver supports ExtendedFetch */
01611        rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts, sizeof(scrollopts), NULL);
01612        if (rc == SQL_SUCCESS) {
01613               if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
01614                      /* Try to set CURSOR_TYPE to dynamic. Driver will replace this with other
01615                         type if not possible.
01616                       */
01617                      SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
01618               }
01619        } else {
01620               result->fetch_abs = 0;
01621        }
01622 #endif
01623 
01624        rc = SQLExecDirect(result->stmt, query, SQL_NTS);
01625        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) { 
01626               /* XXX FIXME we should really check out SQLSTATE with SQLError
01627                * in case rc is SQL_SUCCESS_WITH_INFO here.
01628                */
01629               odbc_sql_error(conn, result->stmt, "SQLExecDirect"); 
01630               SQLFreeStmt(result->stmt, SQL_DROP);
01631               efree(result);
01632               RETURN_FALSE;
01633        }
01634 
01635        SQLNumResultCols(result->stmt, &(result->numcols));
01636        
01637        /* For insert, update etc. cols == 0 */
01638        if (result->numcols > 0) {
01639               if (!odbc_bindcols(result TSRMLS_CC)) {
01640                      efree(result);
01641                      RETURN_FALSE;
01642               }
01643        } else {
01644               result->values = NULL;
01645        }
01646        zend_list_addref(conn->id);
01647        result->conn_ptr = conn;
01648        result->fetched = 0;
01649        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
01650 }
01651 /* }}} */
01652 
01653 #ifdef PHP_ODBC_HAVE_FETCH_HASH
01654 #define ODBC_NUM  1
01655 #define ODBC_OBJECT  2
01656 
01657 /* {{{ php_odbc_fetch_hash */
01658 static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
01659 {
01660        int i;
01661        odbc_result *result;
01662        RETCODE rc;
01663        SQLSMALLINT sql_c_type;
01664        char *buf = NULL;
01665 #ifdef HAVE_SQL_EXTENDED_FETCH
01666        SQLULEN crow;
01667        SQLUSMALLINT RowStatus[1];
01668        SQLLEN rownum;
01669        zval *pv_res, *tmp;
01670        long pv_row = -1;
01671 
01672        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
01673               return;
01674        }
01675        
01676        rownum = pv_row;
01677 #else
01678        zval *pv_res, *tmp;
01679 
01680        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
01681               return;
01682        }
01683 #endif
01684 
01685        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01686 
01687        if (result->numcols == 0) {
01688               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
01689               RETURN_FALSE;
01690        }
01691 
01692 #ifdef HAVE_SQL_EXTENDED_FETCH
01693        if (result->fetch_abs) {
01694               if (rownum > 0) {
01695                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
01696               } else {
01697                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
01698               }
01699        } else
01700 #endif
01701        rc = SQLFetch(result->stmt);
01702 
01703        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01704               RETURN_FALSE;
01705        }
01706        
01707        array_init(return_value);
01708        
01709 #ifdef HAVE_SQL_EXTENDED_FETCH
01710        if (rownum > 0 && result->fetch_abs)
01711               result->fetched = rownum;
01712        else
01713 #endif
01714               result->fetched++;
01715 
01716        for(i = 0; i < result->numcols; i++) {
01717               ALLOC_INIT_ZVAL(tmp);
01718               Z_TYPE_P(tmp) = IS_STRING;
01719               Z_STRLEN_P(tmp) = 0;
01720               sql_c_type = SQL_C_CHAR;
01721 
01722               switch(result->values[i].coltype) {
01723                      case SQL_BINARY:
01724                      case SQL_VARBINARY:
01725                      case SQL_LONGVARBINARY:
01726                             if (result->binmode <= 0) {
01727                                    Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
01728                                    break;
01729                             }
01730                             if (result->binmode == 1) {
01731                                    sql_c_type = SQL_C_BINARY;
01732                             }
01733                      case SQL_LONGVARCHAR:
01734                             if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
01735                                    Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
01736                                    break;
01737                             }                           
01738                             if (buf == NULL) {
01739                                    buf = emalloc(result->longreadlen + 1);
01740                             }
01741                             
01742                             rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1), sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
01743 
01744                             if (rc == SQL_ERROR) {
01745                                    odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
01746                                    efree(buf);
01747                                    RETURN_FALSE;
01748                             }
01749 
01750                             if (rc == SQL_SUCCESS_WITH_INFO) {
01751                                    Z_STRLEN_P(tmp) = result->longreadlen;
01752                             } else if (result->values[i].vallen == SQL_NULL_DATA) {
01753                                    ZVAL_NULL(tmp);
01754                                    break;
01755                             } else {
01756                                    Z_STRLEN_P(tmp) = result->values[i].vallen;
01757                             }
01758                             Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
01759                             break;
01760 
01761                      default:
01762                             if (result->values[i].vallen == SQL_NULL_DATA) {
01763                                    ZVAL_NULL(tmp);
01764                                    break;
01765                             }
01766                             Z_STRLEN_P(tmp) = result->values[i].vallen;
01767                             Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
01768                             break;
01769               }
01770 
01771               if (result_type & ODBC_NUM) {
01772                      zend_hash_index_update(Z_ARRVAL_P(return_value), i, &tmp, sizeof(zval *), NULL);
01773               } else {
01774                      if (!*(result->values[i].name)) {
01775                             zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(tmp),    Z_STRLEN_P(tmp)+1, &tmp, sizeof(zval *), NULL);
01776                      } else {
01777                             zend_hash_update(Z_ARRVAL_P(return_value), result->values[i].name, strlen(result->values[i].name)+1, &tmp, sizeof(zval *), NULL);
01778                      }
01779               }
01780        }
01781        if (buf) {
01782               efree(buf);
01783        }
01784 }
01785 /* }}} */
01786 
01787 
01788 /* {{{ proto object odbc_fetch_object(int result [, int rownumber])
01789    Fetch a result row as an object */
01790 PHP_FUNCTION(odbc_fetch_object)
01791 {
01792        php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
01793        if (Z_TYPE_P(return_value) == IS_ARRAY) {
01794               object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
01795        }
01796 }
01797 /* }}} */
01798 
01799 /* {{{ proto array odbc_fetch_array(int result [, int rownumber])
01800    Fetch a result row as an associative array */
01801 PHP_FUNCTION(odbc_fetch_array)
01802 {
01803        php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, ODBC_OBJECT);
01804 }
01805 /* }}} */
01806 #endif
01807 
01808 /* {{{ proto int odbc_fetch_into(resource result_id, array &result_array, [, int rownumber])
01809    Fetch one result row into an array */ 
01810 PHP_FUNCTION(odbc_fetch_into)
01811 {
01812        int i;
01813        odbc_result *result;
01814        RETCODE rc;
01815        SQLSMALLINT sql_c_type;
01816        char *buf = NULL;
01817        zval *pv_res, **pv_res_arr, *tmp;
01818 #ifdef HAVE_SQL_EXTENDED_FETCH
01819        long pv_row = 0;
01820        SQLULEN crow;
01821        SQLUSMALLINT RowStatus[1];
01822        SQLLEN rownum = -1;
01823 #endif /* HAVE_SQL_EXTENDED_FETCH */
01824 
01825 #ifdef HAVE_SQL_EXTENDED_FETCH
01826        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) {
01827               return;
01828        }
01829        
01830        rownum = pv_row;
01831 #else
01832        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_res_arr) == FAILURE) {
01833               return;
01834        }
01835 #endif /* HAVE_SQL_EXTENDED_FETCH */
01836 
01837        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01838        
01839        if (result->numcols == 0) {
01840               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
01841               RETURN_FALSE;
01842        }
01843        
01844        if (Z_TYPE_PP(pv_res_arr) != IS_ARRAY) {
01845               array_init(*pv_res_arr);
01846        }
01847 
01848 #ifdef HAVE_SQL_EXTENDED_FETCH
01849        if (result->fetch_abs) {
01850               if (rownum > 0) {
01851                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
01852               } else {
01853                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
01854               }
01855        } else
01856 #endif
01857               rc = SQLFetch(result->stmt);
01858 
01859        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01860               RETURN_FALSE;
01861        }
01862 
01863 #ifdef HAVE_SQL_EXTENDED_FETCH
01864        if (rownum > 0 && result->fetch_abs)
01865               result->fetched = rownum;
01866        else
01867 #endif
01868               result->fetched++;
01869 
01870        for(i = 0; i < result->numcols; i++) {
01871               MAKE_STD_ZVAL(tmp);
01872               Z_TYPE_P(tmp) = IS_STRING;
01873               Z_STRLEN_P(tmp) = 0;
01874               sql_c_type = SQL_C_CHAR;
01875 
01876               switch(result->values[i].coltype) {
01877                      case SQL_BINARY:
01878                      case SQL_VARBINARY:
01879                      case SQL_LONGVARBINARY:
01880                             if (result->binmode <= 0) {
01881                                    Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
01882                                    break;
01883                             }
01884                             if (result->binmode == 1) sql_c_type = SQL_C_BINARY; 
01885                      case SQL_LONGVARCHAR:
01886                             if (IS_SQL_LONG(result->values[i].coltype) && result->longreadlen <= 0) {
01887                                    Z_STRVAL_P(tmp) = STR_EMPTY_ALLOC();
01888                                    break;
01889                             }
01890 
01891                             if (buf == NULL) {
01892                                    buf = emalloc(result->longreadlen + 1);
01893                             }
01894                             rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen + 1, &result->values[i].vallen);
01895 
01896                             if (rc == SQL_ERROR) {
01897                                    odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
01898                                    efree(buf);
01899                                    RETURN_FALSE;
01900                             }
01901                             if (rc == SQL_SUCCESS_WITH_INFO) {
01902                                    Z_STRLEN_P(tmp) = result->longreadlen;
01903                             } else if (result->values[i].vallen == SQL_NULL_DATA) {
01904                                    ZVAL_NULL(tmp);
01905                                    break;
01906                             } else {
01907                                    Z_STRLEN_P(tmp) = result->values[i].vallen;
01908                             }
01909                             Z_STRVAL_P(tmp) = estrndup(buf, Z_STRLEN_P(tmp));
01910                             break;
01911 
01912                      default:
01913                             if (result->values[i].vallen == SQL_NULL_DATA) {
01914                                    ZVAL_NULL(tmp);
01915                                    break;
01916                             }
01917                             Z_STRLEN_P(tmp) = result->values[i].vallen;
01918                             Z_STRVAL_P(tmp) = estrndup(result->values[i].value,Z_STRLEN_P(tmp));
01919                             break;
01920               }
01921               zend_hash_index_update(Z_ARRVAL_PP(pv_res_arr), i, &tmp, sizeof(zval *), NULL);
01922        }
01923        if (buf) efree(buf);
01924        RETURN_LONG(result->numcols);      
01925 }
01926 /* }}} */
01927 
01928 /* {{{ proto bool solid_fetch_prev(resource result_id)
01929    */ 
01930 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35)
01931 PHP_FUNCTION(solid_fetch_prev)
01932 {
01933        odbc_result *result;
01934        RETCODE rc;
01935        zval *pv_res;
01936        
01937        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
01938               return;
01939        }
01940        
01941        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01942        if (result->numcols == 0) {
01943               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
01944               RETURN_FALSE;
01945        }
01946        rc = SQLFetchPrev(result->stmt);
01947 
01948        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01949               RETURN_FALSE;
01950        }
01951 
01952        if (result->fetched > 1) {
01953               result->fetched--;
01954        }
01955 
01956        RETURN_TRUE;
01957 }
01958 #endif
01959 /* }}} */
01960 
01961 /* {{{ proto bool odbc_fetch_row(resource result_id [, int row_number])
01962    Fetch a row */
01963 PHP_FUNCTION(odbc_fetch_row)
01964 {
01965        SQLLEN rownum;
01966        odbc_result *result;
01967        RETCODE rc;
01968        zval *pv_res;
01969        long pv_row = 1;
01970 #ifdef HAVE_SQL_EXTENDED_FETCH
01971        SQLULEN crow;
01972        SQLUSMALLINT RowStatus[1];
01973 #endif
01974 
01975        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_res, &pv_row) == FAILURE) {
01976               return;
01977        }
01978        
01979        rownum = pv_row;
01980        
01981        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
01982        
01983        if (result->numcols == 0) {
01984               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
01985               RETURN_FALSE;
01986        }
01987 
01988 #ifdef HAVE_SQL_EXTENDED_FETCH
01989        if (result->fetch_abs) {
01990               if (ZEND_NUM_ARGS() > 1) {
01991                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus);
01992               } else {
01993                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
01994               }
01995        } else
01996 #endif
01997               rc = SQLFetch(result->stmt);
01998 
01999        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02000               RETURN_FALSE;
02001        }
02002        
02003        if (ZEND_NUM_ARGS() > 1) {
02004               result->fetched = rownum;
02005        } else {
02006               result->fetched++;
02007        }
02008        
02009        RETURN_TRUE;
02010 }      
02011 /* }}} */
02012 
02013 /* {{{ proto mixed odbc_result(resource result_id, mixed field)
02014    Get result data */ 
02015 PHP_FUNCTION(odbc_result)
02016 {
02017        char *field;
02018        int field_ind;
02019        SQLSMALLINT sql_c_type = SQL_C_CHAR;
02020        odbc_result *result;
02021        int i = 0;
02022        RETCODE rc;
02023        SQLLEN fieldsize;
02024        zval *pv_res, **pv_field;
02025 #ifdef HAVE_SQL_EXTENDED_FETCH
02026        SQLULEN crow;
02027        SQLUSMALLINT RowStatus[1];
02028 #endif
02029 
02030        field_ind = -1;
02031        field = NULL;
02032 
02033        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &pv_res, &pv_field) == FAILURE) {
02034               return;
02035        }
02036        
02037        if (Z_TYPE_PP(pv_field) == IS_STRING) {
02038               field = Z_STRVAL_PP(pv_field);
02039        } else {
02040               convert_to_long_ex(pv_field);
02041               field_ind = Z_LVAL_PP(pv_field) - 1;
02042        }
02043        
02044        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02045        
02046        if ((result->numcols == 0)) {
02047               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
02048               RETURN_FALSE;
02049        }
02050        
02051        /* get field index if the field parameter was a string */
02052        if (field != NULL) {
02053               if (result->values == NULL) {
02054                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set contains no data");
02055                      RETURN_FALSE;
02056               }
02057 
02058               for(i = 0; i < result->numcols; i++) {
02059                      if (!strcasecmp(result->values[i].name, field)) {
02060                             field_ind = i;
02061                             break;
02062                      }
02063               }
02064 
02065               if (field_ind < 0) {
02066                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field %s not found", field);
02067                      RETURN_FALSE;
02068               }
02069        } else {
02070               /* check for limits of field_ind if the field parameter was an int */
02071               if (field_ind >= result->numcols || field_ind < 0) {
02072                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index is larger than the number of fields");
02073                      RETURN_FALSE;
02074               }
02075        }
02076 
02077        if (result->fetched == 0) {
02078               /* User forgot to call odbc_fetch_row(), or wants to reload the results, do it now */
02079 #ifdef HAVE_SQL_EXTENDED_FETCH
02080               if (result->fetch_abs)
02081                      rc = SQLExtendedFetch(result->stmt, SQL_FETCH_NEXT, 1, &crow,RowStatus);
02082               else
02083 #endif
02084                      rc = SQLFetch(result->stmt);
02085 
02086               if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02087                      RETURN_FALSE;
02088               }
02089               
02090               result->fetched++;
02091        }
02092 
02093        switch(result->values[field_ind].coltype) {
02094               case SQL_BINARY:
02095               case SQL_VARBINARY:
02096               case SQL_LONGVARBINARY:
02097                      if (result->binmode <= 1) {
02098                             sql_c_type = SQL_C_BINARY;
02099                      }
02100                      if (result->binmode <= 0) {
02101                             break; 
02102                      }
02103               case SQL_LONGVARCHAR:
02104                      if (IS_SQL_LONG(result->values[field_ind].coltype)) {
02105                             if (result->longreadlen <= 0) {
02106                                break;
02107                             } else {
02108                                fieldsize = result->longreadlen;
02109                             }
02110                      } else {
02111                         SQLColAttributes(result->stmt, (SQLUSMALLINT)(field_ind + 1), 
02112                                                         (SQLUSMALLINT)((sql_c_type == SQL_C_BINARY) ? SQL_COLUMN_LENGTH :
02113                                                         SQL_COLUMN_DISPLAY_SIZE),
02114                                                         NULL, 0, NULL, &fieldsize);
02115                      }
02116                      /* For char data, the length of the returned string will be longreadlen - 1 */
02117                      fieldsize = (result->longreadlen <= 0) ? 4096 : result->longreadlen;
02118                      field = emalloc(fieldsize);
02119 
02120               /* SQLGetData will truncate CHAR data to fieldsize - 1 bytes and append \0.
02121                * For binary data it is truncated to fieldsize bytes. 
02122                */
02123                      rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1), sql_c_type,
02124                                                  field, fieldsize, &result->values[field_ind].vallen);
02125 
02126                      if (rc == SQL_ERROR) {
02127                             odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
02128                             efree(field);
02129                             RETURN_FALSE;
02130                      }
02131 
02132                      if (result->values[field_ind].vallen == SQL_NULL_DATA) {
02133                             efree(field);
02134                             RETURN_NULL();
02135                      } else if (rc == SQL_NO_DATA_FOUND) {
02136                             efree(field);
02137                             RETURN_FALSE;
02138                      }
02139                      /* Reduce fieldlen by 1 if we have char data. One day we might 
02140                         have binary strings... */
02141                      if (result->values[field_ind].coltype == SQL_LONGVARCHAR) {
02142                             fieldsize -= 1;
02143                      }
02144                      /* Don't duplicate result, saves one emalloc.
02145                         For SQL_SUCCESS, the length is in vallen.
02146                       */
02147                      RETURN_STRINGL(field, (rc == SQL_SUCCESS_WITH_INFO) ? fieldsize : result->values[field_ind].vallen, 0);
02148                      break;
02149                      
02150               default:
02151                      if (result->values[field_ind].vallen == SQL_NULL_DATA) {
02152                             RETURN_NULL();
02153                      } else {
02154                             RETURN_STRINGL(result->values[field_ind].value, result->values[field_ind].vallen, 1);
02155                      }
02156                      break;
02157        }
02158 
02159 /* If we come here, output unbound LONG and/or BINARY column data to the client */
02160        
02161        /* We emalloc 1 byte more for SQL_C_CHAR (trailing \0) */
02162        fieldsize = (sql_c_type == SQL_C_CHAR) ? 4096 : 4095;
02163        field = emalloc(fieldsize);
02164        
02165        /* Call SQLGetData() until SQL_SUCCESS is returned */
02166        while(1) {
02167               rc = SQLGetData(result->stmt, (SQLUSMALLINT)(field_ind + 1),sql_c_type, field, fieldsize, &result->values[field_ind].vallen);
02168 
02169               if (rc == SQL_ERROR) {
02170                      odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
02171                      efree(field);
02172                      RETURN_FALSE;
02173               }
02174               
02175               if (result->values[field_ind].vallen == SQL_NULL_DATA) {
02176                      efree(field);
02177                      RETURN_NULL();
02178               }
02179               /* chop the trailing \0 by outputing only 4095 bytes */
02180               PHPWRITE(field,(rc == SQL_SUCCESS_WITH_INFO) ? 4095 : result->values[field_ind].vallen);
02181 
02182               if (rc == SQL_SUCCESS) { /* no more data avail */
02183                      efree(field);
02184                      RETURN_TRUE;
02185               }
02186        }
02187        RETURN_TRUE;
02188 }
02189 /* }}} */
02190 
02191 /* {{{ proto int odbc_result_all(resource result_id [, string format])
02192    Print result as HTML table */
02193 PHP_FUNCTION(odbc_result_all)
02194 {
02195        char *buf = NULL;
02196        odbc_result *result;
02197        RETCODE rc;
02198        zval *pv_res;
02199        char *pv_format = NULL;
02200        int i, pv_format_len = 0;
02201        SQLSMALLINT sql_c_type;
02202 #ifdef HAVE_SQL_EXTENDED_FETCH
02203        SQLULEN crow;
02204        SQLUSMALLINT RowStatus[1];
02205 #endif
02206 
02207        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) {
02208               return;
02209        }
02210                             
02211        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02212        
02213        if (result->numcols == 0) {
02214               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
02215               RETURN_FALSE;
02216        }
02217 #ifdef HAVE_SQL_EXTENDED_FETCH
02218        if (result->fetch_abs)
02219               rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
02220        else
02221 #endif 
02222               rc = SQLFetch(result->stmt);
02223 
02224        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02225               php_printf("<h2>No rows found</h2>\n");
02226               RETURN_LONG(0);
02227        }
02228        
02229        /* Start table tag */
02230        if (ZEND_NUM_ARGS() == 1) {
02231               php_printf("<table><tr>");
02232        } else {
02233               php_printf("<table %s ><tr>", pv_format);
02234        }
02235        
02236        for (i = 0; i < result->numcols; i++) {
02237               php_printf("<th>%s</th>", result->values[i].name);
02238        }
02239 
02240        php_printf("</tr>\n");
02241 
02242        while(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
02243               result->fetched++;
02244               php_printf("<tr>");
02245               for(i = 0; i < result->numcols; i++) {
02246                      sql_c_type = SQL_C_CHAR;
02247                      switch(result->values[i].coltype) {
02248                             case SQL_BINARY:
02249                             case SQL_VARBINARY:
02250                             case SQL_LONGVARBINARY:
02251                                    if (result->binmode <= 0) {
02252                                           php_printf("<td>Not printable</td>");
02253                                           break;
02254                                    }
02255                                    if (result->binmode <= 1) sql_c_type = SQL_C_BINARY; 
02256                             case SQL_LONGVARCHAR:
02257                                    if (IS_SQL_LONG(result->values[i].coltype) && 
02258                                           result->longreadlen <= 0) {
02259                                           php_printf("<td>Not printable</td>"); 
02260                                           break;
02261                                    }
02262 
02263                                    if (buf == NULL) {
02264                                           buf = emalloc(result->longreadlen);
02265                                    }
02266 
02267                                    rc = SQLGetData(result->stmt, (SQLUSMALLINT)(i + 1),sql_c_type, buf, result->longreadlen, &result->values[i].vallen);
02268  
02269                                    php_printf("<td>");
02270 
02271                                    if (rc == SQL_ERROR) {
02272                                           odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData");
02273                                           php_printf("</td></tr></table>");
02274                                           efree(buf);
02275                                           RETURN_FALSE;
02276                                    }
02277                                    if (rc == SQL_SUCCESS_WITH_INFO) {
02278                                           PHPWRITE(buf, result->longreadlen);
02279                                    } else if (result->values[i].vallen == SQL_NULL_DATA) {
02280                                           php_printf("<td>NULL</td>");
02281                                           break;
02282                                    } else {
02283                                           PHPWRITE(buf, result->values[i].vallen);
02284                                    }
02285                                    php_printf("</td>");
02286                                    break;
02287                             default:
02288                                    if (result->values[i].vallen == SQL_NULL_DATA) {
02289                                           php_printf("<td>NULL</td>");
02290                                    } else {
02291                                           php_printf("<td>%s</td>", result->values[i].value);
02292                                    }
02293                                    break;
02294                      }
02295               }
02296               php_printf("</tr>\n");
02297 
02298 #ifdef HAVE_SQL_EXTENDED_FETCH
02299               if (result->fetch_abs)
02300                      rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus);
02301               else
02302 #endif
02303                      rc = SQLFetch(result->stmt);              
02304        }
02305        php_printf("</table>\n");
02306        if (buf) efree(buf);
02307        RETURN_LONG(result->fetched);
02308 }
02309 /* }}} */
02310 
02311 /* {{{ proto bool odbc_free_result(resource result_id)
02312    Free resources associated with a result */
02313 PHP_FUNCTION(odbc_free_result)
02314 {
02315        zval *pv_res;
02316        odbc_result *result;
02317        int i;
02318 
02319        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
02320               return;
02321        }
02322 
02323        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02324        if (result->values) {
02325               for (i = 0; i < result->numcols; i++) {
02326                      if (result->values[i].value) {
02327                             efree(result->values[i].value);
02328                      }
02329               }
02330               efree(result->values);
02331               result->values = NULL;
02332        }
02333                      
02334        zend_list_delete(Z_LVAL_P(pv_res));
02335        
02336        RETURN_TRUE;
02337 }
02338 /* }}} */
02339 
02340 /* {{{ proto resource odbc_connect(string DSN, string user, string password [, int cursor_option])
02341    Connect to a datasource */
02342 PHP_FUNCTION(odbc_connect)
02343 {
02344        odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
02345 }
02346 /* }}} */
02347 
02348 /* {{{ proto resource odbc_pconnect(string DSN, string user, string password [, int cursor_option])
02349    Establish a persistent connection to a datasource */
02350 PHP_FUNCTION(odbc_pconnect)
02351 {
02352        odbc_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
02353 }
02354 /* }}} */
02355 
02356 /* {{{ odbc_sqlconnect */
02357 int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent TSRMLS_DC)
02358 {
02359        RETCODE rc;
02360        
02361        *conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent);
02362        (*conn)->persistent = persistent;
02363        SQLAllocEnv(&((*conn)->henv));
02364        SQLAllocConnect((*conn)->henv, &((*conn)->hdbc));
02365        
02366 #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) 
02367        SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION,
02368                      SQL_SOLID_XLATOPT_NOCNV);
02369 #endif
02370 #ifdef HAVE_ODBC_ROUTER
02371        {
02372 #define CONNSTRSIZE 2048
02373         char *lpszConnStr = emalloc(CONNSTRSIZE);
02374         if (lpszConnStr && db) {
02375                short cbszConnStr;
02376                if (strstr(db, ";")) {
02377                       /* the caller has apparently passed a connection-string */
02378                       if (strstr(db, "uid") || strstr(db, "UID")) {
02379                              uid = NULL;
02380                       }
02381                       if (strstr(db, "pwd") || strstr(db, "PWD")) {
02382                              pwd = NULL;
02383                       }
02384                       strlcpy( lpszConnStr, db, CONNSTRSIZE);
02385                }
02386                else {
02387                       strcpy(lpszConnStr, "DSN=");
02388                       strlcat(lpszConnStr, db, CONNSTRSIZE);
02389                }
02390                if (uid) {
02391                       if (uid[0]) {
02392                              strlcat(lpszConnStr, ";UID=", CONNSTRSIZE);
02393                              strlcat(lpszConnStr, uid, CONNSTRSIZE);
02394                              strlcat(lpszConnStr, ";", CONNSTRSIZE);
02395                       }
02396                       if (pwd) {
02397                              if (pwd[0]) {
02398                                     strlcat(lpszConnStr, "PWD=", CONNSTRSIZE);
02399                                     strlcat(lpszConnStr, pwd, CONNSTRSIZE);
02400                                     strlcat(lpszConnStr, ";", CONNSTRSIZE);
02401                              }
02402                       }
02403                }
02404                rc = SQLDriverConnect((*conn)->hdbc, NULL, lpszConnStr, SQL_NTS, lpszConnStr, CONNSTRSIZE, &cbszConnStr, SQL_DRIVER_NOPROMPT);
02405                efree(lpszConnStr);
02406         }
02407        }
02408 #else
02409 #ifdef HAVE_OPENLINK
02410        {
02411               char dsnbuf[1024];
02412               short dsnbuflen;
02413 
02414               rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
02415        }
02416 #else
02417        if (cur_opt != SQL_CUR_DEFAULT) {
02418               rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt);
02419               if (rc != SQL_SUCCESS) {  /* && rc != SQL_SUCCESS_WITH_INFO ? */
02420                      odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption");
02421                      SQLFreeConnect((*conn)->hdbc);
02422                      pefree(*conn, persistent);
02423                      return FALSE;
02424               }
02425        }
02426 /*  Possible fix for bug #10250
02427  *  Needs testing on UnixODBC < 2.0.5 though. */
02428 #if defined(HAVE_EMPRESS) || defined(HAVE_UNIXODBC) || defined(PHP_WIN32) || defined (HAVE_IODBC)
02429 /* *  Uncomment the line above, and comment line below to fully test 
02430  * #ifdef HAVE_EMPRESS */
02431        {
02432               int     direct = 0;
02433               char    dsnbuf[1024];
02434               short   dsnbuflen;
02435               char    *ldb = 0;
02436               int           ldb_len = 0;
02437 
02438               if (strstr((char*)db, ";")) {
02439                      direct = 1;
02440                      if (uid && !strstr ((char*)db, "uid") && !strstr((char*)db, "UID")) {
02441                             spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid, pwd);
02442                      } else {
02443                             ldb_len = strlen(db)+1;
02444                             ldb = (char*) emalloc(ldb_len);
02445                             memcpy(ldb, db, ldb_len);
02446                      }
02447               }
02448 
02449               if (direct) {
02450                      rc = SQLDriverConnect((*conn)->hdbc, NULL, ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
02451               } else {
02452                      rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
02453               }
02454 
02455               if (ldb) {
02456                      efree(ldb);
02457               }
02458        }
02459 #else
02460        rc = SQLConnect((*conn)->hdbc, db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
02461 #endif
02462 #endif
02463 #endif
02464        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02465               odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect");
02466               SQLFreeConnect((*conn)->hdbc);
02467               pefree((*conn), persistent);
02468               return FALSE;
02469        }
02470 /*     (*conn)->open = 1;*/
02471        return TRUE;
02472 }
02473 /* }}} */
02474 
02475 /* Persistent connections: two list-types le_pconn, le_conn and a plist
02476  * where hashed connection info is stored together with index pointer to
02477  * the actual link of type le_pconn in the list. Only persistent 
02478  * connections get hashed up. Normal connections use existing pconnections.
02479  * Maybe this has to change with regard to transactions on pconnections?
02480  * Possibly set autocommit to on on request shutdown.
02481  *
02482  * We do have to hash non-persistent connections, and reuse connections.
02483  * In the case where two connects were being made, without closing the first
02484  * connect, access violations were occuring.  This is because some of the
02485  * "globals" in this module should actualy be per-connection variables.  I
02486  * simply fixed things to get them working for now.  Shane
02487  */
02488 /* {{{ odbc_do_connect */
02489 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
02490 {
02491        char *db, *uid, *pwd;
02492        int db_len, uid_len, pwd_len;
02493        long pv_opt = SQL_CUR_DEFAULT;
02494        odbc_connection *db_conn;
02495        char *hashed_details;
02496        int hashed_len, cur_opt;
02497 
02498        /*  Now an optional 4th parameter specifying the cursor type
02499         *  defaulting to the cursors default
02500         */
02501        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) {
02502               return;
02503        }
02504        
02505        cur_opt = pv_opt;
02506        
02507        if (ZEND_NUM_ARGS() > 3) {
02508               /* Confirm the cur_opt range */
02509               if (! (cur_opt == SQL_CUR_USE_IF_NEEDED || 
02510                      cur_opt == SQL_CUR_USE_ODBC || 
02511                      cur_opt == SQL_CUR_USE_DRIVER || 
02512                      cur_opt == SQL_CUR_DEFAULT) ) {
02513                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Cursor type (%d)", cur_opt);
02514                      RETURN_FALSE;
02515               }
02516        }
02517 
02518        if (ODBCG(allow_persistent) <= 0) {
02519               persistent = 0;
02520        }
02521 
02522        hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt);
02523 
02524        /* FIXME the idea of checking to see if our connection is already persistent
02525               is good, but it adds a lot of overhead to non-persistent connections.  We
02526               should look and see if we can fix that somehow */
02527        /* try to find if we already have this link in our persistent list,
02528         * no matter if it is to be persistent or not
02529         */
02530 
02531 try_and_get_another_connection:
02532 
02533        if (persistent) {
02534               zend_rsrc_list_entry *le;
02535               
02536               /* the link is not in the persistent list */
02537               if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_len + 1, (void **) &le)    == FAILURE) {
02538                      zend_rsrc_list_entry new_le;
02539                      
02540                      if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
02541                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", ODBCG(num_links));
02542                             efree(hashed_details);
02543                             RETURN_FALSE;
02544                      }
02545                      if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) {
02546                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open persistent links (%ld)", ODBCG(num_persistent));
02547                             efree(hashed_details);
02548                             RETURN_FALSE;
02549                      }
02550                      
02551                      if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1 TSRMLS_CC)) {
02552                             efree(hashed_details);
02553                             RETURN_FALSE;
02554                      }
02555                      
02556                      Z_TYPE(new_le) = le_pconn;
02557                      new_le.ptr = db_conn;
02558                      if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_len + 1, &new_le,
02559                                           sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
02560                             free(db_conn);
02561                             efree(hashed_details);
02562                             RETURN_FALSE;
02563                      }
02564                      ODBCG(num_persistent)++;
02565                      ODBCG(num_links)++;
02566                      db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
02567               } else { /* found connection */
02568                      if (Z_TYPE_P(le) != le_pconn) {
02569                             RETURN_FALSE;
02570                      }
02571                      /*
02572                       * check to see if the connection is still valid
02573                       */
02574                      db_conn = (odbc_connection *)le->ptr;
02575 
02576                      /*
02577                       * check to see if the connection is still in place (lurcher)
02578                       */
02579                      if(ODBCG(check_persistent)){
02580                             RETCODE ret;
02581                             UCHAR d_name[32];
02582                             SQLSMALLINT len;
02583 
02584                             ret = SQLGetInfo(db_conn->hdbc, 
02585                                    SQL_DATA_SOURCE_READ_ONLY, 
02586                                    d_name, sizeof(d_name), &len);
02587 
02588                             if(ret != SQL_SUCCESS || len == 0) {
02589                                    zend_hash_del(&EG(persistent_list), hashed_details, hashed_len + 1);
02590                                    /* Commented out to fix a possible double closure error 
02591                                     * when working with persistent connections as submitted by
02592                                     * bug #15758
02593                                     *
02594                                     * safe_odbc_disconnect(db_conn->hdbc);
02595                                     * SQLFreeConnect(db_conn->hdbc);
02596                                     */
02597                                    goto try_and_get_another_connection;
02598                             }
02599                      }
02600               }
02601               db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_pconn);
02602        } else { /* non persistent */
02603               zend_rsrc_list_entry *index_ptr, new_index_ptr;
02604               
02605               if (zend_hash_find(&EG(regular_list), hashed_details, hashed_len + 1, (void **) &index_ptr) == SUCCESS) {
02606                      int type, conn_id;
02607                      void *ptr;
02608 
02609                      if (Z_TYPE_P(index_ptr) != le_index_ptr) {
02610                             RETURN_FALSE;
02611                      }
02612                      conn_id = (int)index_ptr->ptr;
02613                      ptr = zend_list_find(conn_id, &type);   /* check if the connection is still there */
02614 
02615                      if (ptr && (type == le_conn || type == le_pconn)) {
02616                             zend_list_addref(conn_id);
02617                             Z_LVAL_P(return_value) = conn_id;
02618                             Z_TYPE_P(return_value) = IS_RESOURCE;
02619                             efree(hashed_details);
02620                             return;
02621                      } else {
02622                             zend_hash_del(&EG(regular_list), hashed_details, hashed_len + 1);
02623                      }
02624               }
02625               if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) {
02626                      php_error_docref(NULL TSRMLS_CC, E_WARNING,"Too many open connections (%ld)",ODBCG(num_links));
02627                      efree(hashed_details);
02628                      RETURN_FALSE;
02629               }
02630 
02631               if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0 TSRMLS_CC)) {
02632                      efree(hashed_details);
02633                      RETURN_FALSE;
02634               }
02635               db_conn->id = ZEND_REGISTER_RESOURCE(return_value, db_conn, le_conn);
02636               new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
02637               Z_TYPE(new_index_ptr) = le_index_ptr;
02638 
02639               if (zend_hash_update(&EG(regular_list), hashed_details, hashed_len + 1, (void *) &new_index_ptr,
02640                                sizeof(zend_rsrc_list_entry), NULL) == FAILURE) {
02641                      efree(hashed_details);
02642                      RETURN_FALSE;
02643                      /* XXX Free Connection */
02644               }
02645               ODBCG(num_links)++;
02646        }
02647        efree(hashed_details);
02648 }
02649 /* }}} */
02650 
02651 /* {{{ proto void odbc_close(resource connection_id)
02652    Close an ODBC connection */
02653 PHP_FUNCTION(odbc_close)
02654 {
02655        zval *pv_conn;
02656        void *ptr;
02657        odbc_connection *conn;
02658        odbc_result *res;
02659        int nument;
02660        int i;
02661        int type;
02662        int is_pconn = 0;
02663        int found_resource_type = le_conn;
02664 
02665        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_conn) == FAILURE) {
02666               return;
02667        }
02668 
02669        conn = (odbc_connection *) zend_fetch_resource(&pv_conn TSRMLS_CC, -1, "ODBC-Link", &found_resource_type, 2, le_conn, le_pconn);
02670        if (found_resource_type==le_pconn) {
02671               is_pconn = 1;
02672        }
02673 
02674        nument = zend_hash_next_free_element(&EG(regular_list));
02675 
02676        for(i = 1; i < nument; i++){
02677               ptr = zend_list_find(i, &type);
02678               if(ptr && (type == le_result)){
02679                      res = (odbc_result *)ptr;
02680                      if(res->conn_ptr == conn){
02681                             zend_list_delete(i);
02682                      }
02683               }
02684        }
02685        
02686        zend_list_delete(Z_LVAL_P(pv_conn));
02687        
02688        if(is_pconn){
02689               zend_hash_apply_with_argument(&EG(persistent_list),     (apply_func_arg_t) _close_pconn_with_id, (void *) &(Z_LVAL_P(pv_conn)) TSRMLS_CC);  
02690        }
02691 }
02692 /* }}} */
02693 
02694 /* {{{ proto int odbc_num_rows(resource result_id)
02695    Get number of rows in a result */
02696 PHP_FUNCTION(odbc_num_rows)
02697 {
02698        odbc_result *result;
02699        SQLLEN rows;
02700        zval *pv_res;
02701        
02702        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
02703               return;
02704        }
02705        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02706        SQLRowCount(result->stmt, &rows);
02707        RETURN_LONG(rows);
02708 }
02709 /* }}} */
02710 
02711 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30)
02712 /* {{{ proto bool odbc_next_result(resource result_id)
02713    Checks if multiple results are avaiable */
02714 PHP_FUNCTION(odbc_next_result)
02715 {
02716        odbc_result *result;
02717        zval *pv_res;
02718        int rc, i;
02719 
02720        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
02721               return;
02722        }
02723        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result); 
02724 
02725        if (result->values) {
02726               for(i = 0; i < result->numcols; i++) {
02727                      if (result->values[i].value) {
02728                             efree(result->values[i].value);
02729                      }
02730               }
02731               efree(result->values);
02732               result->values = NULL;
02733        }
02734 
02735        result->fetched = 0;
02736        rc = SQLMoreResults(result->stmt);
02737        if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS) {
02738               rc = SQLFreeStmt(result->stmt, SQL_UNBIND);
02739               SQLNumParams(result->stmt, &(result->numparams));
02740               SQLNumResultCols(result->stmt, &(result->numcols));
02741 
02742               if (result->numcols > 0) {
02743                      if (!odbc_bindcols(result TSRMLS_CC)) {
02744                             efree(result);
02745                             RETVAL_FALSE;
02746                      }
02747               } else {
02748                      result->values = NULL;
02749               }
02750               RETURN_TRUE;
02751        } else if (rc == SQL_NO_DATA_FOUND) {
02752               RETURN_FALSE;
02753        } else {
02754               odbc_sql_error(result->conn_ptr, result->stmt, "SQLMoreResults");
02755               RETURN_FALSE;
02756        }
02757 }
02758 /* }}} */
02759 #endif
02760 
02761 /* {{{ proto int odbc_num_fields(resource result_id)
02762    Get number of columns in a result */
02763 PHP_FUNCTION(odbc_num_fields)
02764 {
02765        odbc_result *result;
02766        zval *pv_res;
02767 
02768        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pv_res) == FAILURE) {
02769               return;
02770        }
02771        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02772        RETURN_LONG(result->numcols);
02773 }
02774 /* }}} */
02775 
02776 /* {{{ proto string odbc_field_name(resource result_id, int field_number)
02777    Get a column name */
02778 PHP_FUNCTION(odbc_field_name)
02779 {
02780        odbc_result *result;
02781        zval *pv_res;
02782        long pv_num;
02783        
02784        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
02785               return;
02786        }
02787        
02788        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02789        
02790        if (result->numcols == 0) {
02791               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
02792               RETURN_FALSE;
02793        }
02794        
02795        if (pv_num > result->numcols) {
02796               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
02797               RETURN_FALSE;
02798        }
02799        
02800        if (pv_num < 1) {
02801               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
02802               RETURN_FALSE;
02803        }
02804        
02805        RETURN_STRING(result->values[pv_num - 1].name, 1);
02806 }
02807 /* }}} */
02808 
02809 /* {{{ proto string odbc_field_type(resource result_id, int field_number)
02810    Get the datatype of a column */
02811 PHP_FUNCTION(odbc_field_type)
02812 {
02813        odbc_result   *result;
02814        char          tmp[32];
02815        SQLSMALLINT   tmplen;
02816        zval          *pv_res;
02817        long          pv_num;
02818 
02819        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &pv_res, &pv_num) == FAILURE) {
02820               return;
02821        }
02822 
02823        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02824 
02825        if (result->numcols == 0) {
02826               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
02827               RETURN_FALSE;
02828        }
02829        
02830        if (pv_num > result->numcols) {
02831               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field index larger than number of fields");
02832               RETURN_FALSE;
02833        }
02834 
02835        if (pv_num < 1) {
02836               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field numbering starts at 1");
02837               RETURN_FALSE;
02838        }
02839 
02840        SQLColAttributes(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, 31, &tmplen, NULL);
02841        RETURN_STRING(tmp,1)
02842 }
02843 /* }}} */
02844 
02845 /* {{{ proto int odbc_field_len(resource result_id, int field_number)
02846    Get the length (precision) of a column */
02847 PHP_FUNCTION(odbc_field_len)
02848 {
02849        odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
02850 }
02851 /* }}} */
02852 
02853 /* {{{ proto int odbc_field_scale(resource result_id, int field_number)
02854    Get the scale of a column */
02855 PHP_FUNCTION(odbc_field_scale)
02856 {
02857        odbc_column_lengths(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);      
02858 }
02859 /* }}} */
02860 
02861 /* {{{ proto int odbc_field_num(resource result_id, string field_name)
02862    Return column number */
02863 PHP_FUNCTION(odbc_field_num)
02864 {
02865        char *fname;
02866        int i, field_ind, fname_len;
02867        odbc_result *result;
02868        zval *pv_res;
02869 
02870        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pv_res, &fname, &fname_len) == FAILURE) {
02871               return;
02872        }
02873        
02874        ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_res, -1, "ODBC result", le_result);
02875        
02876        if (result->numcols == 0) {
02877               php_error_docref(NULL TSRMLS_CC, E_WARNING, "No tuples available at this result index");
02878               RETURN_FALSE;
02879        }
02880 
02881        field_ind = -1;
02882        for(i = 0; i < result->numcols; i++) {
02883               if (strcasecmp(result->values[i].name, fname) == 0) {
02884                      field_ind = i + 1;
02885               }
02886        }
02887 
02888        if (field_ind == -1) {
02889               RETURN_FALSE;
02890        }
02891        RETURN_LONG(field_ind);
02892 }
02893 /* }}} */
02894 
02895 /* {{{ proto mixed odbc_autocommit(resource connection_id [, int OnOff])
02896    Toggle autocommit mode or get status */
02897 /* There can be problems with pconnections!*/
02898 PHP_FUNCTION(odbc_autocommit)
02899 {
02900        odbc_connection *conn;
02901        RETCODE rc;
02902        zval *pv_conn;
02903        long pv_onoff = 0;
02904 
02905        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_onoff) == FAILURE) {
02906               return;
02907        }
02908 
02909        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
02910        
02911        if (ZEND_NUM_ARGS() > 1) {
02912               rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (pv_onoff) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
02913               if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02914                      odbc_sql_error(conn, SQL_NULL_HSTMT, "Set autocommit");
02915                      RETURN_FALSE;
02916               }
02917               RETVAL_TRUE;
02918        } else {
02919               SQLINTEGER status;
02920 
02921               rc = SQLGetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, (PTR)&status);
02922               if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
02923                      odbc_sql_error(conn, SQL_NULL_HSTMT, "Get commit status");
02924                      RETURN_FALSE;
02925               }
02926               RETVAL_LONG((long)status);
02927        }
02928 }
02929 /* }}} */
02930 
02931 /* {{{ proto bool odbc_commit(resource connection_id)
02932    Commit an ODBC transaction */
02933 PHP_FUNCTION(odbc_commit)
02934 {
02935        odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
02936 }
02937 /* }}} */
02938 
02939 /* {{{ proto bool odbc_rollback(resource connection_id)
02940    Rollback a transaction */
02941 PHP_FUNCTION(odbc_rollback)
02942 {
02943        odbc_transact(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
02944 }
02945 /* }}} */
02946 
02947 /* {{{ php_odbc_lasterror */
02948 static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode)
02949 {
02950        odbc_connection *conn;
02951        zval *pv_handle;
02952        char *ptr;
02953        int len;
02954 
02955        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &pv_handle) == FAILURE) {
02956               return;
02957        }
02958 
02959        if (mode == 0) {  /* last state */
02960               len = 6;
02961        } else { /* last error message */
02962               len = SQL_MAX_MESSAGE_LENGTH;
02963        }
02964 
02965        if (ZEND_NUM_ARGS() == 1) {
02966               ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
02967               ptr = ecalloc(len + 1, 1);
02968               if (mode == 0) {
02969                      strlcpy(ptr, conn->laststate, len+1);
02970               } else {
02971                      strlcpy(ptr, conn->lasterrormsg, len+1);
02972               }
02973        } else {
02974               ptr = ecalloc(len + 1, 1);
02975               if (mode == 0) {
02976                      strlcpy(ptr, ODBCG(laststate), len+1);
02977               } else {
02978                      strlcpy(ptr, ODBCG(lasterrormsg), len+1);
02979               }
02980        }
02981        RETVAL_STRING(ptr, 0);
02982 }
02983 /* }}} */
02984 
02985 /* {{{ proto string odbc_error([resource connection_id])
02986    Get the last error code */
02987 PHP_FUNCTION(odbc_error)
02988 {
02989        php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
02990 }
02991 /* }}} */
02992 
02993 /* {{{ proto string odbc_errormsg([resource connection_id])
02994    Get the last error message */
02995 PHP_FUNCTION(odbc_errormsg)
02996 {
02997        php_odbc_lasterror(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
02998 }
02999 /* }}} */
03000 
03001 /* {{{ proto bool odbc_setoption(resource conn_id|result_id, int which, int option, int value)
03002    Sets connection or statement options */
03003 /* This one has to be used carefully. We can't allow to set connection options for
03004    persistent connections. I think that SetStmtOption is of little use, since most
03005    of those can only be specified before preparing/executing statements.
03006    On the other hand, they can be made connection wide default through SetConnectOption
03007    - but will be overidden by calls to SetStmtOption() in odbc_prepare/odbc_do
03008 */
03009 PHP_FUNCTION(odbc_setoption)
03010 {
03011        odbc_connection *conn;
03012        odbc_result   *result;
03013        RETCODE rc;
03014        zval *pv_handle;
03015        long pv_which, pv_opt, pv_val;
03016 
03017        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) {
03018               return;
03019        }
03020 
03021        switch (pv_which) {
03022               case 1:              /* SQLSetConnectOption */
03023                      ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_handle, -1, "ODBC-Link", le_conn, le_pconn);
03024 
03025                      if (conn->persistent) {
03026                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set option for persistent connection");
03027                             RETURN_FALSE;
03028                      }
03029                      rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val);
03030                      if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
03031                             odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption");
03032                             RETURN_FALSE;
03033                      }
03034                      break;
03035               case 2:              /* SQLSetStmtOption */
03036                      ZEND_FETCH_RESOURCE(result, odbc_result *, &pv_handle, -1, "ODBC result", le_result);
03037                      
03038                      rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val);
03039 
03040                      if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
03041                             odbc_sql_error(result->conn_ptr, result->stmt, "SetStmtOption");
03042                             RETURN_FALSE;
03043                      }
03044                      break;
03045               default:
03046                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option type");
03047                      RETURN_FALSE;
03048                      break;
03049        }
03050 
03051        RETURN_TRUE;
03052 }
03053 /* }}} */
03054 
03055 /*
03056  * metadata functions
03057  */
03058 
03059 /* {{{ proto resource odbc_tables(resource connection_id [, string qualifier [, string owner [, string name [, string table_types]]]])
03060    Call the SQLTables function */
03061 PHP_FUNCTION(odbc_tables)
03062 {
03063        zval *pv_conn;
03064        odbc_result   *result = NULL;
03065        odbc_connection *conn;
03066        char *cat = NULL, *schema = NULL, *table = NULL, *type = NULL;
03067        int cat_len = 0, schema_len = 0, table_len = 0, type_len = 0;
03068        RETCODE rc;
03069 
03070        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, 
03071               &table, &table_len, &type, &type_len) == FAILURE) {
03072               return;
03073        }
03074 
03075        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03076 
03077        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03078        
03079        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03080        if (rc == SQL_INVALID_HANDLE) {
03081               efree(result);
03082               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03083               RETURN_FALSE;
03084        }
03085 
03086        if (rc == SQL_ERROR) {
03087               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03088               efree(result);
03089               RETURN_FALSE;
03090        }
03091 
03092        /* This hack is needed to access table information in Access databases (fmk) */
03093        if (table && table_len && schema && schema_len == 0) {
03094               schema = NULL;
03095        }
03096 
03097        rc = SQLTables(result->stmt, 
03098                      cat, SAFE_SQL_NTS(cat), 
03099                      schema,       SAFE_SQL_NTS(schema), 
03100                      table, SAFE_SQL_NTS(table),
03101                      type, SAFE_SQL_NTS(type));
03102 
03103        if (rc == SQL_ERROR) {
03104               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTables");
03105               efree(result);
03106               RETURN_FALSE;
03107        }
03108 
03109        result->numparams = 0;
03110        SQLNumResultCols(result->stmt, &(result->numcols));
03111 
03112        if (result->numcols > 0) {
03113               if (!odbc_bindcols(result TSRMLS_CC)) {
03114                      efree(result);
03115                      RETURN_FALSE;
03116               }
03117        } else {
03118               result->values = NULL;
03119        }
03120        result->conn_ptr = conn;
03121        result->fetched = 0;
03122        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03123 }
03124 /* }}} */
03125 
03126 /* {{{ proto resource odbc_columns(resource connection_id [, string qualifier [, string owner [, string table_name [, string column_name]]]])
03127    Returns a result identifier that can be used to fetch a list of column names in specified tables */
03128 PHP_FUNCTION(odbc_columns)
03129 {
03130        zval *pv_conn;
03131        odbc_result *result = NULL;
03132        odbc_connection *conn;
03133        char *cat = NULL, *schema = NULL, *table = NULL, *column = NULL;
03134        int cat_len = 0, schema_len = 0, table_len = 0, column_len = 0;
03135        RETCODE rc;
03136 
03137        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
03138               &table, &table_len, &column, &column_len) == FAILURE) {
03139               return;
03140        }
03141 
03142        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03143 
03144        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03145        
03146        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03147        if (rc == SQL_INVALID_HANDLE) {
03148               efree(result);
03149               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03150               RETURN_FALSE;
03151        }
03152 
03153        if (rc == SQL_ERROR) {
03154               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03155               efree(result);
03156               RETURN_FALSE;
03157        }
03158 
03159        /* 
03160         * Needed to make MS Access happy
03161         */
03162        if (table && table_len && schema && schema_len == 0) {
03163               schema = NULL;
03164        }
03165 
03166        rc = SQLColumns(result->stmt, 
03167                      cat, (SQLSMALLINT) cat_len,
03168                      schema, (SQLSMALLINT) schema_len,
03169                      table, (SQLSMALLINT) table_len,
03170                      column, (SQLSMALLINT) column_len);
03171 
03172        if (rc == SQL_ERROR) {
03173               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumns");
03174               efree(result);
03175               RETURN_FALSE;
03176        }
03177 
03178        result->numparams = 0;
03179        SQLNumResultCols(result->stmt, &(result->numcols));
03180 
03181        if (result->numcols > 0) {
03182               if (!odbc_bindcols(result TSRMLS_CC)) {
03183                      efree(result);
03184                      RETURN_FALSE;
03185               }
03186        } else {
03187               result->values = NULL;
03188        }
03189        result->conn_ptr = conn;
03190        result->fetched = 0;
03191        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03192 }
03193 /* }}} */
03194 
03195 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
03196 /* {{{ proto resource odbc_columnprivileges(resource connection_id, string catalog, string schema, string table, string column)
03197    Returns a result identifier that can be used to fetch a list of columns and associated privileges for the specified table */
03198 PHP_FUNCTION(odbc_columnprivileges)
03199 {
03200        zval *pv_conn;
03201        odbc_result *result = NULL;
03202        odbc_connection *conn;
03203        char *cat = NULL, *schema, *table, *column;
03204        int cat_len = 0, schema_len, table_len, column_len;
03205        RETCODE rc;
03206        
03207        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len,
03208               &table, &table_len, &column, &column_len) == FAILURE) {
03209               return;
03210        }
03211 
03212        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03213 
03214        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03215        
03216        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03217        if (rc == SQL_INVALID_HANDLE) {
03218               efree(result);
03219               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03220               RETURN_FALSE;
03221        }
03222 
03223        if (rc == SQL_ERROR) {
03224               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03225               efree(result);
03226               RETURN_FALSE;
03227        }
03228 
03229        rc = SQLColumnPrivileges(result->stmt, 
03230                      cat, SAFE_SQL_NTS(cat),
03231                      schema, SAFE_SQL_NTS(schema),
03232                      table, SAFE_SQL_NTS(table),
03233                      column, SAFE_SQL_NTS(column));
03234 
03235        if (rc == SQL_ERROR) {
03236               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLColumnPrivileges");
03237               efree(result);
03238               RETURN_FALSE;
03239        }
03240 
03241        result->numparams = 0;
03242        SQLNumResultCols(result->stmt, &(result->numcols));
03243 
03244        if (result->numcols > 0) {
03245               if (!odbc_bindcols(result TSRMLS_CC)) {
03246                      efree(result);
03247                      RETURN_FALSE;
03248               }
03249        } else {
03250               result->values = NULL;
03251        }
03252        result->conn_ptr = conn;
03253        result->fetched = 0;
03254        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03255 }
03256 /* }}} */
03257 #endif /* HAVE_DBMAKER || HAVE_SOLID*/
03258 
03259 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
03260 /* {{{ 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)
03261    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 */
03262 PHP_FUNCTION(odbc_foreignkeys)
03263 {
03264        zval *pv_conn;
03265        odbc_result *result = NULL;
03266        odbc_connection *conn;
03267        char *pcat = NULL, *pschema, *ptable, *fcat, *fschema, *ftable;
03268        int pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len;
03269        RETCODE rc;
03270 
03271        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len, 
03272               &ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) {
03273               return;
03274        }
03275 
03276 #if defined(HAVE_DBMAKER) || defined(HAVE_IBMDB2)
03277 #define EMPTY_TO_NULL(xstr) \
03278        if ((int)strlen((xstr)) == 0) (xstr) = NULL
03279 
03280               EMPTY_TO_NULL(pcat);
03281               EMPTY_TO_NULL(pschema);
03282               EMPTY_TO_NULL(ptable);
03283               EMPTY_TO_NULL(fcat);
03284               EMPTY_TO_NULL(fschema);
03285               EMPTY_TO_NULL(ftable);
03286 #endif
03287 
03288        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03289 
03290        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03291        
03292        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03293        if (rc == SQL_INVALID_HANDLE) {
03294               efree(result);
03295               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03296               RETURN_FALSE;
03297        }
03298 
03299        if (rc == SQL_ERROR) {
03300               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03301               efree(result);
03302               RETURN_FALSE;
03303        }
03304 
03305        rc = SQLForeignKeys(result->stmt, 
03306                      pcat, SAFE_SQL_NTS(pcat), 
03307                      pschema, SAFE_SQL_NTS(pschema), 
03308                      ptable, SAFE_SQL_NTS(ptable), 
03309                      fcat, SAFE_SQL_NTS(fcat), 
03310                      fschema, SAFE_SQL_NTS(fschema), 
03311                      ftable, SAFE_SQL_NTS(ftable) );
03312 
03313        if (rc == SQL_ERROR) {
03314               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLForeignKeys");
03315               efree(result);
03316               RETURN_FALSE;
03317        }
03318 
03319        result->numparams = 0;
03320        SQLNumResultCols(result->stmt, &(result->numcols));
03321 
03322        if (result->numcols > 0) {
03323               if (!odbc_bindcols(result TSRMLS_CC)) {
03324                      efree(result);
03325                      RETURN_FALSE;
03326               }
03327        } else {
03328               result->values = NULL;
03329        }
03330        result->conn_ptr = conn;
03331        result->fetched = 0;
03332        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03333 }
03334 /* }}} */
03335 #endif /* HAVE_SOLID */
03336 
03337 /* {{{ proto resource odbc_gettypeinfo(resource connection_id [, int data_type])
03338    Returns a result identifier containing information about data types supported by the data source */
03339 PHP_FUNCTION(odbc_gettypeinfo)
03340 {
03341        zval *pv_conn;
03342        long pv_data_type = SQL_ALL_TYPES;
03343        odbc_result *result = NULL;
03344        odbc_connection *conn;
03345        RETCODE rc;
03346        SQLSMALLINT data_type;
03347 
03348        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &pv_conn, &pv_data_type) == FAILURE) {
03349               return;
03350        }
03351        
03352        data_type = (SQLSMALLINT) pv_data_type;
03353 
03354        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03355 
03356        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03357        
03358        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03359        if (rc == SQL_INVALID_HANDLE) {
03360               efree(result);
03361               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03362               RETURN_FALSE;
03363        }
03364 
03365        if (rc == SQL_ERROR) {
03366               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03367               efree(result);
03368               RETURN_FALSE;
03369        }
03370 
03371        rc = SQLGetTypeInfo(result->stmt, data_type );
03372 
03373        if (rc == SQL_ERROR) {
03374               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLGetTypeInfo");
03375               efree(result);
03376               RETURN_FALSE;
03377        }
03378 
03379        result->numparams = 0;
03380        SQLNumResultCols(result->stmt, &(result->numcols));
03381 
03382        if (result->numcols > 0) {
03383               if (!odbc_bindcols(result TSRMLS_CC)) {
03384                      efree(result);
03385                      RETURN_FALSE;
03386               }
03387        } else {
03388               result->values = NULL;
03389        }
03390        result->conn_ptr = conn;
03391        result->fetched = 0;
03392        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03393 }
03394 /* }}} */
03395 
03396 /* {{{ proto resource odbc_primarykeys(resource connection_id, string qualifier, string owner, string table)
03397    Returns a result identifier listing the column names that comprise the primary key for a table */
03398 PHP_FUNCTION(odbc_primarykeys)
03399 {
03400        zval *pv_conn;
03401        odbc_result   *result = NULL;
03402        odbc_connection *conn;
03403        char *cat = NULL, *schema = NULL, *table = NULL;
03404        int cat_len = 0, schema_len, table_len;
03405        RETCODE rc;
03406 
03407        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
03408               return;
03409        }
03410 
03411        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03412 
03413        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03414        
03415        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03416        if (rc == SQL_INVALID_HANDLE) {
03417               efree(result);
03418               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03419               RETURN_FALSE;
03420        }
03421 
03422        if (rc == SQL_ERROR) {
03423               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03424               efree(result);
03425               RETURN_FALSE;
03426        }
03427 
03428        rc = SQLPrimaryKeys(result->stmt, 
03429                      cat, SAFE_SQL_NTS(cat), 
03430                      schema, SAFE_SQL_NTS(schema), 
03431                      table, SAFE_SQL_NTS(table) );
03432 
03433        if (rc == SQL_ERROR) {
03434               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLPrimaryKeys");
03435               efree(result);
03436               RETURN_FALSE;
03437        }
03438 
03439        result->numparams = 0;
03440        SQLNumResultCols(result->stmt, &(result->numcols));
03441 
03442        if (result->numcols > 0) {
03443               if (!odbc_bindcols(result TSRMLS_CC)) {
03444                      efree(result);
03445                      RETURN_FALSE;
03446               }
03447        } else {
03448               result->values = NULL;
03449        }
03450        result->conn_ptr = conn;
03451        result->fetched = 0;
03452        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03453 }
03454 /* }}} */
03455 
03456 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
03457 /* {{{ proto resource odbc_procedurecolumns(resource connection_id [, string qualifier, string owner, string proc, string column])
03458    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 */
03459 PHP_FUNCTION(odbc_procedurecolumns)
03460 {
03461        zval *pv_conn;
03462        odbc_result *result = NULL;
03463        odbc_connection *conn;
03464        char *cat = NULL, *schema = NULL, *proc = NULL, *col = NULL;
03465        int cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0;
03466        RETCODE rc;
03467        
03468        if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 5) {
03469               WRONG_PARAM_COUNT;
03470        }
03471 
03472        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, 
03473               &proc, &proc_len, &col, &col_len) == FAILURE) {
03474               return;
03475        }
03476 
03477        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03478 
03479        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03480        
03481        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03482        if (rc == SQL_INVALID_HANDLE) {
03483               efree(result);
03484               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03485               RETURN_FALSE;
03486        }
03487 
03488        if (rc == SQL_ERROR) {
03489               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03490               efree(result);
03491               RETURN_FALSE;
03492        }
03493 
03494        rc = SQLProcedureColumns(result->stmt, 
03495                      cat, SAFE_SQL_NTS(cat), 
03496                      schema, SAFE_SQL_NTS(schema), 
03497                      proc, SAFE_SQL_NTS(proc), 
03498                      col, SAFE_SQL_NTS(col) );
03499 
03500        if (rc == SQL_ERROR) {
03501               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedureColumns");
03502               efree(result);
03503               RETURN_FALSE;
03504        }
03505 
03506        result->numparams = 0;
03507        SQLNumResultCols(result->stmt, &(result->numcols));
03508 
03509        if (result->numcols > 0) {
03510               if (!odbc_bindcols(result TSRMLS_CC)) {
03511                      efree(result);
03512                      RETURN_FALSE;
03513               }
03514        } else {
03515               result->values = NULL;
03516        }
03517        result->conn_ptr = conn;
03518        result->fetched = 0;
03519        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03520 }
03521 /* }}} */
03522 #endif /* HAVE_SOLID */
03523 
03524 #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
03525 /* {{{ proto resource odbc_procedures(resource connection_id [, string qualifier, string owner, string name])
03526    Returns a result identifier containg the list of procedure names in a datasource */
03527 PHP_FUNCTION(odbc_procedures)
03528 {
03529        zval *pv_conn;
03530        odbc_result   *result = NULL;
03531        odbc_connection *conn;
03532        char *cat = NULL, *schema = NULL, *proc = NULL;
03533        int cat_len = 0, schema_len = 0, proc_len = 0;
03534        RETCODE rc;
03535 
03536        if (ZEND_NUM_ARGS() != 1 && ZEND_NUM_ARGS() != 4) {
03537               WRONG_PARAM_COUNT;
03538        }
03539        
03540        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) {
03541               return;
03542        }
03543 
03544        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03545 
03546        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03547        
03548        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03549        if (rc == SQL_INVALID_HANDLE) {
03550               efree(result);
03551               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03552               RETURN_FALSE;
03553        }
03554 
03555        if (rc == SQL_ERROR) {
03556               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03557               efree(result);
03558               RETURN_FALSE;
03559        }
03560 
03561        rc = SQLProcedures(result->stmt, 
03562                      cat, SAFE_SQL_NTS(cat), 
03563                      schema, SAFE_SQL_NTS(schema), 
03564                      proc, SAFE_SQL_NTS(proc) );
03565 
03566        if (rc == SQL_ERROR) {
03567               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLProcedures");
03568               efree(result);
03569               RETURN_FALSE;
03570        }
03571 
03572        result->numparams = 0;
03573        SQLNumResultCols(result->stmt, &(result->numcols));
03574 
03575        if (result->numcols > 0) {
03576               if (!odbc_bindcols(result TSRMLS_CC)) {
03577                      efree(result);
03578                      RETURN_FALSE;
03579               }
03580        } else {
03581               result->values = NULL;
03582        }
03583        result->conn_ptr = conn;
03584        result->fetched = 0;
03585        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03586 }
03587 /* }}} */
03588 #endif /* HAVE_SOLID */
03589 
03590 /* {{{ proto resource odbc_specialcolumns(resource connection_id, int type, string qualifier, string owner, string table, int scope, int nullable)
03591    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 */
03592 PHP_FUNCTION(odbc_specialcolumns)
03593 {
03594        zval *pv_conn;
03595        long vtype, vscope, vnullable;
03596        odbc_result *result = NULL;
03597        odbc_connection *conn;
03598        char *cat = NULL, *schema = NULL, *name = NULL;
03599        int cat_len = 0, schema_len, name_len;
03600        SQLUSMALLINT type, scope, nullable;
03601        RETCODE rc;
03602 
03603        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len,
03604               &name, &name_len, &vscope, &vnullable) == FAILURE) {
03605               return;
03606        }
03607        
03608        type = (SQLUSMALLINT) vtype;
03609        scope = (SQLUSMALLINT) vscope;
03610        nullable = (SQLUSMALLINT) vnullable;
03611 
03612        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03613 
03614        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03615        
03616        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03617        if (rc == SQL_INVALID_HANDLE) {
03618               efree(result);
03619               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03620               RETURN_FALSE;
03621        }
03622 
03623        if (rc == SQL_ERROR) {
03624               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03625               efree(result);
03626               RETURN_FALSE;
03627        }
03628 
03629        rc = SQLSpecialColumns(result->stmt, 
03630                      type,
03631                      cat, SAFE_SQL_NTS(cat), 
03632                      schema, SAFE_SQL_NTS(schema), 
03633                      name, SAFE_SQL_NTS(name),
03634                      scope,
03635                      nullable);
03636 
03637        if (rc == SQL_ERROR) {
03638               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLSpecialColumns");
03639               efree(result);
03640               RETURN_FALSE;
03641        }
03642 
03643        result->numparams = 0;
03644        SQLNumResultCols(result->stmt, &(result->numcols));
03645 
03646        if (result->numcols > 0) {
03647               if (!odbc_bindcols(result TSRMLS_CC)) {
03648                      efree(result);
03649                      RETURN_FALSE;
03650               }
03651        } else {
03652               result->values = NULL;
03653        }
03654        result->conn_ptr = conn;
03655        result->fetched = 0;
03656        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03657 }
03658 /* }}} */
03659 
03660 /* {{{ proto resource odbc_statistics(resource connection_id, string qualifier, string owner, string name, int unique, int accuracy)
03661    Returns a result identifier that contains statistics about a single table and the indexes associated with the table */
03662 PHP_FUNCTION(odbc_statistics)
03663 {
03664        zval *pv_conn;
03665        long vunique, vreserved;
03666        odbc_result *result = NULL;
03667        odbc_connection *conn;
03668        char *cat = NULL, *schema, *name;
03669        int cat_len = 0, schema_len, name_len;
03670        SQLUSMALLINT unique, reserved;
03671        RETCODE rc;
03672 
03673        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len,
03674               &name, &name_len, &vunique, &vreserved) == FAILURE) {
03675               return;
03676        }
03677        
03678        unique = (SQLUSMALLINT) vunique;
03679        reserved = (SQLUSMALLINT) vreserved;
03680 
03681        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03682 
03683        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03684        
03685        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03686        if (rc == SQL_INVALID_HANDLE) {
03687               efree(result);
03688               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03689               RETURN_FALSE;
03690        }
03691 
03692        if (rc == SQL_ERROR) {
03693               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03694               efree(result);
03695               RETURN_FALSE;
03696        }
03697 
03698        rc = SQLStatistics(result->stmt, 
03699                      cat, SAFE_SQL_NTS(cat),
03700                      schema, SAFE_SQL_NTS(schema), 
03701                      name, SAFE_SQL_NTS(name),
03702                      unique,
03703                      reserved);
03704 
03705        if (rc == SQL_ERROR) {
03706               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLStatistics");
03707               efree(result);
03708               RETURN_FALSE;
03709        }
03710 
03711        result->numparams = 0;
03712        SQLNumResultCols(result->stmt, &(result->numcols));
03713 
03714        if (result->numcols > 0) {
03715               if (!odbc_bindcols(result TSRMLS_CC)) {
03716                      efree(result);
03717                      RETURN_FALSE;
03718               }
03719        } else {
03720               result->values = NULL;
03721        }
03722        result->conn_ptr = conn;
03723        result->fetched = 0;
03724        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03725 }
03726 /* }}} */
03727 
03728 #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) && !defined(HAVE_BIRDSTEP)
03729 /* {{{ proto resource odbc_tableprivileges(resource connection_id, string qualifier, string owner, string name)
03730    Returns a result identifier containing a list of tables and the privileges associated with each table */
03731 PHP_FUNCTION(odbc_tableprivileges)
03732 {
03733        zval *pv_conn;
03734        odbc_result   *result = NULL;
03735        odbc_connection *conn;
03736        char *cat = NULL, *schema = NULL, *table = NULL;
03737        int cat_len = 0, schema_len, table_len;
03738        RETCODE rc;
03739 
03740        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) {
03741               return;
03742        }
03743 
03744        ZEND_FETCH_RESOURCE2(conn, odbc_connection *, &pv_conn, -1, "ODBC-Link", le_conn, le_pconn);
03745 
03746        result = (odbc_result *)ecalloc(1, sizeof(odbc_result));
03747        
03748        rc = SQLAllocStmt(conn->hdbc, &(result->stmt));
03749        if (rc == SQL_INVALID_HANDLE) {
03750               efree(result);
03751               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLAllocStmt error 'Invalid Handle'");
03752               RETURN_FALSE;
03753        }
03754 
03755        if (rc == SQL_ERROR) {
03756               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt");
03757               efree(result);
03758               RETURN_FALSE;
03759        }
03760 
03761        rc = SQLTablePrivileges(result->stmt, 
03762                      cat, SAFE_SQL_NTS(cat), 
03763                      schema, SAFE_SQL_NTS(schema), 
03764                      table, SAFE_SQL_NTS(table));
03765 
03766        if (rc == SQL_ERROR) {
03767               odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLTablePrivileges");
03768               efree(result);
03769               RETURN_FALSE;
03770        }
03771 
03772        result->numparams = 0;
03773        SQLNumResultCols(result->stmt, &(result->numcols));
03774 
03775        if (result->numcols > 0) {
03776               if (!odbc_bindcols(result TSRMLS_CC)) {
03777                      efree(result);
03778                      RETURN_FALSE;
03779               }
03780        } else {
03781               result->values = NULL;
03782        }
03783        result->conn_ptr = conn;
03784        result->fetched = 0;
03785        ZEND_REGISTER_RESOURCE(return_value, result, le_result);
03786 }
03787 /* }}} */
03788 #endif /* HAVE_DBMAKER */
03789 
03790 #endif /* HAVE_UODBC */
03791 
03792 /*
03793  * Local variables:
03794  * tab-width: 4
03795  * c-basic-offset: 4
03796  * End:
03797  * vim600: sw=4 ts=4 fdm=marker
03798  * vim<600: sw=4 ts=4
03799  */