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