1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Wez Furlong <wez@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "pdo/php_pdo.h"
29 #include "pdo/php_pdo_driver.h"
30 #include "php_pdo_oci.h"
31 #include "php_pdo_oci_int.h"
32 #include "Zend/zend_extensions.h"
33
34 #define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
35
36 #define STMT_CALL(name, params) \
37 do { \
38 S->last_err = name params; \
39 S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
40 if (S->last_err) { \
41 return 0; \
42 } \
43 } while(0)
44
45 #define STMT_CALL_MSG(name, msg, params) \
46 do { \
47 S->last_err = name params; \
48 S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
49 if (S->last_err) { \
50 return 0; \
51 } \
52 } while(0)
53
54 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC);
55
oci_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)56 static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
57 {
58 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
59 HashTable *BC = stmt->bound_columns;
60 HashTable *BP = stmt->bound_params;
61
62 int i;
63
64 if (S->stmt) {
65 /* cancel server side resources for the statement if we didn't
66 * fetch it all */
67 OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
68
69 /* free the handle */
70 OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
71 S->stmt = NULL;
72 }
73 if (S->err) {
74 OCIHandleFree(S->err, OCI_HTYPE_ERROR);
75 S->err = NULL;
76 }
77
78 /* need to ensure these go away now */
79 if (BC) {
80 zend_hash_destroy(BC);
81 FREE_HASHTABLE(stmt->bound_columns);
82 stmt->bound_columns = NULL;
83 }
84
85 if (BP) {
86 zend_hash_destroy(BP);
87 FREE_HASHTABLE(stmt->bound_params);
88 stmt->bound_params = NULL;
89 }
90
91 if (S->einfo.errmsg) {
92 pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
93 S->einfo.errmsg = NULL;
94 }
95
96 if (S->cols) {
97 for (i = 0; i < stmt->column_count; i++) {
98 if (S->cols[i].data) {
99 switch (S->cols[i].dtype) {
100 case SQLT_BLOB:
101 case SQLT_CLOB:
102 /* do nothing */
103 break;
104 default:
105 efree(S->cols[i].data);
106 }
107 }
108 }
109 efree(S->cols);
110 S->cols = NULL;
111 }
112 efree(S);
113
114 stmt->driver_data = NULL;
115
116 return 1;
117 } /* }}} */
118
oci_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)119 static int oci_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
120 {
121 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
122 ub4 rowcount;
123 b4 mode;
124
125 if (!S->stmt_type) {
126 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
127 (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
128 }
129
130 if (stmt->executed) {
131 /* ensure that we cancel the cursor from a previous fetch */
132 OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
133 }
134
135 #ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
136 if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
137 mode = OCI_STMT_SCROLLABLE_READONLY;
138 } else
139 #endif
140 if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
141 mode = OCI_COMMIT_ON_SUCCESS;
142 } else {
143 mode = OCI_DEFAULT;
144 }
145
146 STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
147 (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
148 mode));
149
150 if (!stmt->executed) {
151 ub4 colcount;
152 /* do first-time-only definition of bind/mapping stuff */
153
154 /* how many columns do we have ? */
155 STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
156 (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
157
158 stmt->column_count = (int)colcount;
159
160 if (S->cols) {
161 int i;
162 for (i = 0; i < stmt->column_count; i++) {
163 if (S->cols[i].data) {
164 switch (S->cols[i].dtype) {
165 case SQLT_BLOB:
166 case SQLT_CLOB:
167 /* do nothing */
168 break;
169 default:
170 efree(S->cols[i].data);
171 }
172 }
173 }
174 efree(S->cols);
175 }
176
177 S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
178 }
179
180 STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
181 (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
182 stmt->row_count = (long)rowcount;
183
184 return 1;
185 } /* }}} */
186
oci_bind_input_cb(dvoid * ctx,OCIBind * bindp,ub4 iter,ub4 index,dvoid ** bufpp,ub4 * alenp,ub1 * piecep,dvoid ** indpp)187 static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
188 {
189 struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
190 pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
191 TSRMLS_FETCH();
192
193 if (!param || !param->parameter) {
194 php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_input_cb; this should not happen");
195 return OCI_ERROR;
196 }
197
198 *indpp = &P->indicator;
199
200 if (P->thing) {
201 *bufpp = P->thing;
202 *alenp = sizeof(void*);
203 } else if (ZVAL_IS_NULL(param->parameter)) {
204 /* insert a NULL value into the column */
205 P->indicator = -1; /* NULL */
206 *bufpp = 0;
207 *alenp = -1;
208 } else if (!P->thing) {
209 /* regular string bind */
210 convert_to_string(param->parameter);
211 *bufpp = Z_STRVAL_P(param->parameter);
212 *alenp = Z_STRLEN_P(param->parameter);
213 }
214
215 *piecep = OCI_ONE_PIECE;
216 return OCI_CONTINUE;
217 } /* }}} */
218
oci_bind_output_cb(dvoid * ctx,OCIBind * bindp,ub4 iter,ub4 index,dvoid ** bufpp,ub4 ** alenpp,ub1 * piecep,dvoid ** indpp,ub2 ** rcodepp)219 static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
220 {
221 struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
222 pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
223 TSRMLS_FETCH();
224
225 if (!param || !param->parameter) {
226 php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen");
227 return OCI_ERROR;
228 }
229
230 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
231 P->actual_len = sizeof(OCILobLocator*);
232 *bufpp = P->thing;
233 *alenpp = &P->actual_len;
234 *piecep = OCI_ONE_PIECE;
235 *rcodepp = &P->retcode;
236 *indpp = &P->indicator;
237 return OCI_CONTINUE;
238 }
239
240 if (Z_TYPE_P(param->parameter) == IS_OBJECT || Z_TYPE_P(param->parameter) == IS_RESOURCE) {
241 return OCI_CONTINUE;
242 }
243
244 convert_to_string(param->parameter);
245 zval_dtor(param->parameter);
246
247 Z_STRLEN_P(param->parameter) = param->max_value_len;
248 Z_STRVAL_P(param->parameter) = ecalloc(1, Z_STRLEN_P(param->parameter)+1);
249 P->used_for_output = 1;
250
251 P->actual_len = Z_STRLEN_P(param->parameter);
252 *alenpp = &P->actual_len;
253 *bufpp = Z_STRVAL_P(param->parameter);
254 *piecep = OCI_ONE_PIECE;
255 *rcodepp = &P->retcode;
256 *indpp = &P->indicator;
257
258 return OCI_CONTINUE;
259 } /* }}} */
260
oci_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type TSRMLS_DC)261 static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
262 {
263 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
264
265 /* we're only interested in parameters for prepared SQL right now */
266 if (param->is_param) {
267 pdo_oci_bound_param *P;
268 sb4 value_sz = -1;
269
270 P = (pdo_oci_bound_param*)param->driver_data;
271
272 switch (event_type) {
273 case PDO_PARAM_EVT_FREE:
274 P = param->driver_data;
275 if (P) {
276 efree(P);
277 }
278 break;
279
280 case PDO_PARAM_EVT_ALLOC:
281 P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
282 param->driver_data = P;
283
284 /* figure out what we're doing */
285 switch (PDO_PARAM_TYPE(param->param_type)) {
286 case PDO_PARAM_STMT:
287 return 0;
288
289 case PDO_PARAM_LOB:
290 /* P->thing is now an OCILobLocator * */
291 P->oci_type = SQLT_BLOB;
292 value_sz = sizeof(OCILobLocator*);
293 break;
294
295 case PDO_PARAM_STR:
296 default:
297 P->oci_type = SQLT_CHR;
298 value_sz = param->max_value_len;
299 if (param->max_value_len == 0) {
300 value_sz = 1332; /* maximum size before value is interpreted as a LONG value */
301 }
302
303 }
304
305 if (param->name) {
306 STMT_CALL(OCIBindByName, (S->stmt,
307 &P->bind, S->err, (text*)param->name,
308 param->namelen, 0, value_sz, P->oci_type,
309 &P->indicator, 0, &P->retcode, 0, 0,
310 OCI_DATA_AT_EXEC));
311 } else {
312 STMT_CALL(OCIBindByPos, (S->stmt,
313 &P->bind, S->err, param->paramno+1,
314 0, value_sz, P->oci_type,
315 &P->indicator, 0, &P->retcode, 0, 0,
316 OCI_DATA_AT_EXEC));
317 }
318
319 STMT_CALL(OCIBindDynamic, (P->bind,
320 S->err,
321 param, oci_bind_input_cb,
322 param, oci_bind_output_cb));
323
324 return 1;
325
326 case PDO_PARAM_EVT_EXEC_PRE:
327 P->indicator = 0;
328 P->used_for_output = 0;
329 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
330 ub4 empty = 0;
331 STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
332 STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
333 S->have_blobs = 1;
334 }
335 return 1;
336
337 case PDO_PARAM_EVT_EXEC_POST:
338 /* fixup stuff set in motion in oci_bind_output_cb */
339 if (P->used_for_output) {
340 if (P->indicator == -1) {
341 /* set up a NULL value */
342 if (Z_TYPE_P(param->parameter) == IS_STRING
343 #if ZEND_EXTENSION_API_NO < 220040718
344 && Z_STRVAL_P(param->parameter) != empty_string
345 #endif
346 ) {
347 /* OCI likes to stick non-terminated strings in things */
348 *Z_STRVAL_P(param->parameter) = '\0';
349 }
350 zval_dtor(param->parameter);
351 ZVAL_NULL(param->parameter);
352 } else if (Z_TYPE_P(param->parameter) == IS_STRING
353 #if ZEND_EXTENSION_API_NO < 220040718
354 && Z_STRVAL_P(param->parameter) != empty_string
355 #endif
356 ) {
357 Z_STRLEN_P(param->parameter) = P->actual_len;
358 Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1);
359 Z_STRVAL_P(param->parameter)[P->actual_len] = '\0';
360 }
361 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
362 php_stream *stm;
363
364 if (Z_TYPE_P(param->parameter) == IS_NULL) {
365 /* if the param is NULL, then we assume that they
366 * wanted to bind a lob locator into it from the query
367 * */
368
369 stm = oci_create_lob_stream(stmt, (OCILobLocator*)P->thing TSRMLS_CC);
370 if (stm) {
371 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
372 php_stream_to_zval(stm, param->parameter);
373 P->thing = NULL;
374 }
375 } else {
376 /* we're a LOB being used for insert; transfer the data now */
377 size_t n;
378 ub4 amt, offset = 1;
379 char *consume;
380
381 php_stream_from_zval_no_verify(stm, ¶m->parameter);
382 if (stm) {
383 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
384 do {
385 char buf[8192];
386 n = php_stream_read(stm, buf, sizeof(buf));
387 if ((int)n <= 0) {
388 break;
389 }
390 consume = buf;
391 do {
392 amt = n;
393 OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
394 &amt, offset, consume, n,
395 OCI_ONE_PIECE,
396 NULL, NULL, 0, SQLCS_IMPLICIT);
397 offset += amt;
398 n -= amt;
399 consume += amt;
400 } while (n);
401 } while (1);
402 OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
403 OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
404 } else if (Z_TYPE_P(param->parameter) == IS_STRING) {
405 /* stick the string into the LOB */
406 consume = Z_STRVAL_P(param->parameter);
407 n = Z_STRLEN_P(param->parameter);
408 if (n) {
409 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
410 while (n) {
411 amt = n;
412 OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
413 &amt, offset, consume, n,
414 OCI_ONE_PIECE,
415 NULL, NULL, 0, SQLCS_IMPLICIT);
416 consume += amt;
417 n -= amt;
418 }
419 OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
420 }
421 }
422 OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
423 P->thing = NULL;
424 }
425 }
426
427 return 1;
428 }
429 }
430
431 return 1;
432 } /* }}} */
433
oci_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)434 static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) /* {{{ */
435 {
436 #if HAVE_OCISTMTFETCH2
437 ub4 ociori;
438 #endif
439 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
440
441 #if HAVE_OCISTMTFETCH2
442 switch (ori) {
443 case PDO_FETCH_ORI_NEXT: ociori = OCI_FETCH_NEXT; break;
444 case PDO_FETCH_ORI_PRIOR: ociori = OCI_FETCH_PRIOR; break;
445 case PDO_FETCH_ORI_FIRST: ociori = OCI_FETCH_FIRST; break;
446 case PDO_FETCH_ORI_LAST: ociori = OCI_FETCH_LAST; break;
447 case PDO_FETCH_ORI_ABS: ociori = OCI_FETCH_ABSOLUTE; break;
448 case PDO_FETCH_ORI_REL: ociori = OCI_FETCH_RELATIVE; break;
449 }
450 S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, offset, OCI_DEFAULT);
451 #else
452 S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
453 #endif
454
455 if (S->last_err == OCI_NO_DATA) {
456 /* no (more) data */
457 return 0;
458 }
459
460 if (S->last_err == OCI_NEED_DATA) {
461 oci_stmt_error("OCI_NEED_DATA");
462 return 0;
463 }
464
465 if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
466 return 1;
467 }
468
469 oci_stmt_error("OCIStmtFetch");
470
471 return 0;
472 } /* }}} */
473
oci_define_callback(dvoid * octxp,OCIDefine * define,ub4 iter,dvoid ** bufpp,ub4 ** alenpp,ub1 * piecep,dvoid ** indpp,ub2 ** rcodepp)474 static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
475 ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
476 {
477 pdo_oci_column *col = (pdo_oci_column*)octxp;
478 TSRMLS_FETCH();
479
480 switch (col->dtype) {
481 case SQLT_BLOB:
482 case SQLT_CLOB:
483 *piecep = OCI_ONE_PIECE;
484 *bufpp = col->data;
485 *alenpp = &col->datalen;
486 *indpp = (dvoid *)&col->indicator;
487 break;
488
489 default:
490 php_error_docref(NULL TSRMLS_CC, E_WARNING,
491 "unhandled datatype in oci_define_callback; this should not happen");
492 return OCI_ERROR;
493 }
494
495 return OCI_CONTINUE;
496 }
497
oci_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)498 static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
499 {
500 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
501 OCIParam *param = NULL;
502 text *colname;
503 ub2 dtype, data_size, scale, precis;
504 ub4 namelen;
505 struct pdo_column_data *col = &stmt->columns[colno];
506 zend_bool dyn = FALSE;
507
508 /* describe the column */
509 STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)¶m, colno+1));
510
511 /* what type ? */
512 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
513 (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
514
515 /* how big ? */
516 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
517 (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
518
519 /* scale ? */
520 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
521 (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
522
523 /* precision ? */
524 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
525 (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
526
527 /* name ? */
528 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
529 (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
530
531 col->precision = scale;
532 col->maxlen = data_size;
533 col->namelen = namelen;
534 col->name = estrndup((char *)colname, namelen);
535
536 S->cols[colno].dtype = dtype;
537
538 /* how much room do we need to store the field */
539 switch (dtype) {
540 case SQLT_LBI:
541 case SQLT_LNG:
542 if (dtype == SQLT_LBI) {
543 dtype = SQLT_BIN;
544 } else {
545 dtype = SQLT_CHR;
546 }
547 S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
548 S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
549 col->param_type = PDO_PARAM_STR;
550 break;
551
552 case SQLT_BLOB:
553 case SQLT_CLOB:
554 col->param_type = PDO_PARAM_LOB;
555 STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
556 S->cols[colno].datalen = sizeof(OCILobLocator*);
557 dyn = TRUE;
558 break;
559
560 case SQLT_BIN:
561 default:
562 if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
563 #ifdef SQLT_TIMESTAMP
564 || dtype == SQLT_TIMESTAMP
565 #endif
566 #ifdef SQLT_TIMESTAMP_TZ
567 || dtype == SQLT_TIMESTAMP_TZ
568 #endif
569 ) {
570 /* should be big enough for most date formats and numbers */
571 S->cols[colno].datalen = 512;
572 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
573 } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
574 S->cols[colno].datalen = 1024;
575 #endif
576 } else {
577 S->cols[colno].datalen = col->maxlen;
578 }
579 if (dtype == SQLT_BIN) {
580 S->cols[colno].datalen *= 3;
581 }
582 S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
583 dtype = SQLT_CHR;
584
585 /* returning data as a string */
586 col->param_type = PDO_PARAM_STR;
587 }
588
589 STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
590 S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
591 &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
592
593 if (dyn) {
594 STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
595 oci_define_callback));
596 }
597
598 return 1;
599 } /* }}} */
600
601 struct oci_lob_self {
602 pdo_stmt_t *stmt;
603 pdo_oci_stmt *S;
604 OCILobLocator *lob;
605 ub4 offset;
606 };
607
oci_blob_write(php_stream * stream,const char * buf,size_t count TSRMLS_DC)608 static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
609 {
610 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
611 ub4 amt;
612 sword r;
613
614 amt = count;
615 r = OCILobWrite(self->S->H->svc, self->S->err, self->lob,
616 &amt, self->offset, (char*)buf, count,
617 OCI_ONE_PIECE,
618 NULL, NULL, 0, SQLCS_IMPLICIT);
619
620 if (r != OCI_SUCCESS) {
621 return (size_t)-1;
622 }
623
624 self->offset += amt;
625 return amt;
626 }
627
oci_blob_read(php_stream * stream,char * buf,size_t count TSRMLS_DC)628 static size_t oci_blob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
629 {
630 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
631 ub4 amt;
632 sword r;
633
634 amt = count;
635 r = OCILobRead(self->S->H->svc, self->S->err, self->lob,
636 &amt, self->offset, buf, count,
637 NULL, NULL, 0, SQLCS_IMPLICIT);
638
639 if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
640 return (size_t)-1;
641 }
642
643 self->offset += amt;
644 if (amt < count) {
645 stream->eof = 1;
646 }
647 return amt;
648 }
649
oci_blob_close(php_stream * stream,int close_handle TSRMLS_DC)650 static int oci_blob_close(php_stream *stream, int close_handle TSRMLS_DC)
651 {
652 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
653 pdo_stmt_t *stmt = self->stmt;
654
655 if (close_handle) {
656 OCILobClose(self->S->H->svc, self->S->err, self->lob);
657 OCIDescriptorFree(self->lob, OCI_DTYPE_LOB);
658 efree(self);
659 }
660
661 php_pdo_stmt_delref(stmt TSRMLS_CC);
662 return 0;
663 }
664
oci_blob_flush(php_stream * stream TSRMLS_DC)665 static int oci_blob_flush(php_stream *stream TSRMLS_DC)
666 {
667 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
668 OCILobFlushBuffer(self->S->H->svc, self->S->err, self->lob, 0);
669 return 0;
670 }
671
oci_blob_seek(php_stream * stream,off_t offset,int whence,off_t * newoffset TSRMLS_DC)672 static int oci_blob_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
673 {
674 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
675
676 if (offset >= PDO_OCI_LOBMAXSIZE) {
677 return -1;
678 } else {
679 self->offset = offset + 1; /* Oracle LOBS are 1-based, but PHP is 0-based */
680 return 0;
681 }
682 }
683
684 static php_stream_ops oci_blob_stream_ops = {
685 oci_blob_write,
686 oci_blob_read,
687 oci_blob_close,
688 oci_blob_flush,
689 "pdo_oci blob stream",
690 oci_blob_seek,
691 NULL,
692 NULL,
693 NULL
694 };
695
oci_create_lob_stream(pdo_stmt_t * stmt,OCILobLocator * lob TSRMLS_DC)696 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC)
697 {
698 php_stream *stm;
699 struct oci_lob_self *self = ecalloc(1, sizeof(*self));
700 self->lob = lob;
701 self->offset = 1; /* 1-based */
702 self->stmt = stmt;
703 self->S = (pdo_oci_stmt*)stmt->driver_data;
704
705 stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
706
707 if (stm) {
708 php_pdo_stmt_addref(stmt TSRMLS_CC);
709 return stm;
710 }
711
712 efree(self);
713 return NULL;
714 }
715
oci_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)716 static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
717 {
718 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
719 pdo_oci_column *C = &S->cols[colno];
720
721 /* check the indicator to ensure that the data is intact */
722 if (C->indicator == -1) {
723 /* A NULL value */
724 *ptr = NULL;
725 *len = 0;
726 return 1;
727 } else if (C->indicator == 0) {
728 /* it was stored perfectly */
729
730 if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
731 if (C->data) {
732 *ptr = (char*)oci_create_lob_stream(stmt, (OCILobLocator*)C->data TSRMLS_CC);
733 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
734 }
735 *len = 0;
736 return *ptr ? 1 : 0;
737 }
738
739 *ptr = C->data;
740 *len = C->fetched_len;
741 return 1;
742 } else {
743 /* it was truncated */
744 php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
745
746 *ptr = C->data;
747 *len = C->fetched_len;
748 return 1;
749 }
750 } /* }}} */
751
752 struct pdo_stmt_methods oci_stmt_methods = {
753 oci_stmt_dtor,
754 oci_stmt_execute,
755 oci_stmt_fetch,
756 oci_stmt_describe,
757 oci_stmt_get_col,
758 oci_stmt_param_hook
759 };
760
761 /*
762 * Local variables:
763 * tab-width: 4
764 * c-basic-offset: 4
765 * End:
766 * vim600: noet sw=4 ts=4 fdm=marker
767 * vim<600: noet sw=4 ts=4
768 */
769