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 | 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 OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
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_FETCH_PRE:
274 case PDO_PARAM_EVT_FETCH_POST:
275 case PDO_PARAM_EVT_NORMALIZE:
276 /* Do nothing */
277 break;
278
279 case PDO_PARAM_EVT_FREE:
280 P = param->driver_data;
281 if (P) {
282 efree(P);
283 }
284 break;
285
286 case PDO_PARAM_EVT_ALLOC:
287 P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
288 param->driver_data = P;
289
290 /* figure out what we're doing */
291 switch (PDO_PARAM_TYPE(param->param_type)) {
292 case PDO_PARAM_STMT:
293 return 0;
294
295 case PDO_PARAM_LOB:
296 /* P->thing is now an OCILobLocator * */
297 P->oci_type = SQLT_BLOB;
298 value_sz = sizeof(OCILobLocator*);
299 break;
300
301 case PDO_PARAM_STR:
302 default:
303 P->oci_type = SQLT_CHR;
304 value_sz = param->max_value_len;
305 if (param->max_value_len == 0) {
306 value_sz = 1332; /* maximum size before value is interpreted as a LONG value */
307 }
308
309 }
310
311 if (param->name) {
312 STMT_CALL(OCIBindByName, (S->stmt,
313 &P->bind, S->err, (text*)param->name,
314 param->namelen, 0, value_sz, P->oci_type,
315 &P->indicator, 0, &P->retcode, 0, 0,
316 OCI_DATA_AT_EXEC));
317 } else {
318 STMT_CALL(OCIBindByPos, (S->stmt,
319 &P->bind, S->err, param->paramno+1,
320 0, value_sz, P->oci_type,
321 &P->indicator, 0, &P->retcode, 0, 0,
322 OCI_DATA_AT_EXEC));
323 }
324
325 STMT_CALL(OCIBindDynamic, (P->bind,
326 S->err,
327 param, oci_bind_input_cb,
328 param, oci_bind_output_cb));
329
330 return 1;
331
332 case PDO_PARAM_EVT_EXEC_PRE:
333 P->indicator = 0;
334 P->used_for_output = 0;
335 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
336 ub4 empty = 0;
337 STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
338 STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
339 S->have_blobs = 1;
340 }
341 return 1;
342
343 case PDO_PARAM_EVT_EXEC_POST:
344 /* fixup stuff set in motion in oci_bind_output_cb */
345 if (P->used_for_output) {
346 if (P->indicator == -1) {
347 /* set up a NULL value */
348 if (Z_TYPE_P(param->parameter) == IS_STRING
349 #if ZEND_EXTENSION_API_NO < 220040718
350 && Z_STRVAL_P(param->parameter) != empty_string
351 #endif
352 ) {
353 /* OCI likes to stick non-terminated strings in things */
354 *Z_STRVAL_P(param->parameter) = '\0';
355 }
356 zval_dtor(param->parameter);
357 ZVAL_NULL(param->parameter);
358 } else if (Z_TYPE_P(param->parameter) == IS_STRING
359 #if ZEND_EXTENSION_API_NO < 220040718
360 && Z_STRVAL_P(param->parameter) != empty_string
361 #endif
362 ) {
363 Z_STRLEN_P(param->parameter) = P->actual_len;
364 Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1);
365 Z_STRVAL_P(param->parameter)[P->actual_len] = '\0';
366 }
367 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
368 php_stream *stm;
369
370 if (Z_TYPE_P(param->parameter) == IS_NULL) {
371 /* if the param is NULL, then we assume that they
372 * wanted to bind a lob locator into it from the query
373 * */
374
375 stm = oci_create_lob_stream(stmt, (OCILobLocator*)P->thing TSRMLS_CC);
376 if (stm) {
377 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
378 php_stream_to_zval(stm, param->parameter);
379 P->thing = NULL;
380 }
381 } else {
382 /* we're a LOB being used for insert; transfer the data now */
383 size_t n;
384 ub4 amt, offset = 1;
385 char *consume;
386
387 php_stream_from_zval_no_verify(stm, ¶m->parameter);
388 if (stm) {
389 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
390 do {
391 char buf[8192];
392 n = php_stream_read(stm, buf, sizeof(buf));
393 if ((int)n <= 0) {
394 break;
395 }
396 consume = buf;
397 do {
398 amt = n;
399 OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
400 &amt, offset, consume, n,
401 OCI_ONE_PIECE,
402 NULL, NULL, 0, SQLCS_IMPLICIT);
403 offset += amt;
404 n -= amt;
405 consume += amt;
406 } while (n);
407 } while (1);
408 OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
409 OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
410 } else if (Z_TYPE_P(param->parameter) == IS_STRING) {
411 /* stick the string into the LOB */
412 consume = Z_STRVAL_P(param->parameter);
413 n = Z_STRLEN_P(param->parameter);
414 if (n) {
415 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
416 while (n) {
417 amt = n;
418 OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
419 &amt, offset, consume, n,
420 OCI_ONE_PIECE,
421 NULL, NULL, 0, SQLCS_IMPLICIT);
422 consume += amt;
423 n -= amt;
424 }
425 OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
426 }
427 }
428 OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
429 P->thing = NULL;
430 }
431 }
432
433 return 1;
434 }
435 }
436
437 return 1;
438 } /* }}} */
439
oci_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)440 static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC) /* {{{ */
441 {
442 #if HAVE_OCISTMTFETCH2
443 ub4 ociori;
444 #endif
445 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
446
447 #if HAVE_OCISTMTFETCH2
448 switch (ori) {
449 case PDO_FETCH_ORI_NEXT: ociori = OCI_FETCH_NEXT; break;
450 case PDO_FETCH_ORI_PRIOR: ociori = OCI_FETCH_PRIOR; break;
451 case PDO_FETCH_ORI_FIRST: ociori = OCI_FETCH_FIRST; break;
452 case PDO_FETCH_ORI_LAST: ociori = OCI_FETCH_LAST; break;
453 case PDO_FETCH_ORI_ABS: ociori = OCI_FETCH_ABSOLUTE; break;
454 case PDO_FETCH_ORI_REL: ociori = OCI_FETCH_RELATIVE; break;
455 }
456 S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, offset, OCI_DEFAULT);
457 #else
458 S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
459 #endif
460
461 if (S->last_err == OCI_NO_DATA) {
462 /* no (more) data */
463 return 0;
464 }
465
466 if (S->last_err == OCI_NEED_DATA) {
467 oci_stmt_error("OCI_NEED_DATA");
468 return 0;
469 }
470
471 if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
472 return 1;
473 }
474
475 oci_stmt_error("OCIStmtFetch");
476
477 return 0;
478 } /* }}} */
479
oci_define_callback(dvoid * octxp,OCIDefine * define,ub4 iter,dvoid ** bufpp,ub4 ** alenpp,ub1 * piecep,dvoid ** indpp,ub2 ** rcodepp)480 static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
481 ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
482 {
483 pdo_oci_column *col = (pdo_oci_column*)octxp;
484 TSRMLS_FETCH();
485
486 switch (col->dtype) {
487 case SQLT_BLOB:
488 case SQLT_CLOB:
489 *piecep = OCI_ONE_PIECE;
490 *bufpp = col->data;
491 *alenpp = &col->datalen;
492 *indpp = (dvoid *)&col->indicator;
493 break;
494
495 default:
496 php_error_docref(NULL TSRMLS_CC, E_WARNING,
497 "unhandled datatype in oci_define_callback; this should not happen");
498 return OCI_ERROR;
499 }
500
501 return OCI_CONTINUE;
502 }
503
oci_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)504 static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
505 {
506 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
507 OCIParam *param = NULL;
508 text *colname;
509 ub2 dtype, data_size, scale, precis;
510 ub4 namelen;
511 struct pdo_column_data *col = &stmt->columns[colno];
512 zend_bool dyn = FALSE;
513
514 /* describe the column */
515 STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)¶m, colno+1));
516
517 /* what type ? */
518 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
519 (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
520
521 /* how big ? */
522 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
523 (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
524
525 /* scale ? */
526 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
527 (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
528
529 /* precision ? */
530 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
531 (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
532
533 /* name ? */
534 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
535 (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
536
537 col->precision = scale;
538 col->maxlen = data_size;
539 col->namelen = namelen;
540 col->name = estrndup((char *)colname, namelen);
541
542 S->cols[colno].dtype = dtype;
543
544 /* how much room do we need to store the field */
545 switch (dtype) {
546 case SQLT_LBI:
547 case SQLT_LNG:
548 if (dtype == SQLT_LBI) {
549 dtype = SQLT_BIN;
550 } else {
551 dtype = SQLT_CHR;
552 }
553 S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
554 S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
555 col->param_type = PDO_PARAM_STR;
556 break;
557
558 case SQLT_BLOB:
559 case SQLT_CLOB:
560 col->param_type = PDO_PARAM_LOB;
561 STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
562 S->cols[colno].datalen = sizeof(OCILobLocator*);
563 dyn = TRUE;
564 break;
565
566 case SQLT_BIN:
567 default:
568 if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
569 #ifdef SQLT_TIMESTAMP
570 || dtype == SQLT_TIMESTAMP
571 #endif
572 #ifdef SQLT_TIMESTAMP_TZ
573 || dtype == SQLT_TIMESTAMP_TZ
574 #endif
575 ) {
576 /* should be big enough for most date formats and numbers */
577 S->cols[colno].datalen = 512;
578 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
579 } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
580 S->cols[colno].datalen = 1024;
581 #endif
582 } else {
583 S->cols[colno].datalen = col->maxlen;
584 }
585 if (dtype == SQLT_BIN) {
586 S->cols[colno].datalen *= 3;
587 }
588 S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
589 dtype = SQLT_CHR;
590
591 /* returning data as a string */
592 col->param_type = PDO_PARAM_STR;
593 }
594
595 STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
596 S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
597 &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
598
599 if (dyn) {
600 STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
601 oci_define_callback));
602 }
603
604 return 1;
605 } /* }}} */
606
607 struct oci_lob_self {
608 pdo_stmt_t *stmt;
609 pdo_oci_stmt *S;
610 OCILobLocator *lob;
611 ub4 offset;
612 };
613
oci_blob_write(php_stream * stream,const char * buf,size_t count TSRMLS_DC)614 static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
615 {
616 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
617 ub4 amt;
618 sword r;
619
620 amt = count;
621 r = OCILobWrite(self->S->H->svc, self->S->err, self->lob,
622 &amt, self->offset, (char*)buf, count,
623 OCI_ONE_PIECE,
624 NULL, NULL, 0, SQLCS_IMPLICIT);
625
626 if (r != OCI_SUCCESS) {
627 return (size_t)-1;
628 }
629
630 self->offset += amt;
631 return amt;
632 }
633
oci_blob_read(php_stream * stream,char * buf,size_t count TSRMLS_DC)634 static size_t oci_blob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
635 {
636 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
637 ub4 amt;
638 sword r;
639
640 amt = count;
641 r = OCILobRead(self->S->H->svc, self->S->err, self->lob,
642 &amt, self->offset, buf, count,
643 NULL, NULL, 0, SQLCS_IMPLICIT);
644
645 if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
646 return (size_t)-1;
647 }
648
649 self->offset += amt;
650 if (amt < count) {
651 stream->eof = 1;
652 }
653 return amt;
654 }
655
oci_blob_close(php_stream * stream,int close_handle TSRMLS_DC)656 static int oci_blob_close(php_stream *stream, int close_handle TSRMLS_DC)
657 {
658 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
659 pdo_stmt_t *stmt = self->stmt;
660
661 if (close_handle) {
662 OCILobClose(self->S->H->svc, self->S->err, self->lob);
663 efree(self);
664 }
665
666 php_pdo_stmt_delref(stmt TSRMLS_CC);
667 return 0;
668 }
669
oci_blob_flush(php_stream * stream TSRMLS_DC)670 static int oci_blob_flush(php_stream *stream TSRMLS_DC)
671 {
672 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
673 OCILobFlushBuffer(self->S->H->svc, self->S->err, self->lob, 0);
674 return 0;
675 }
676
oci_blob_seek(php_stream * stream,off_t offset,int whence,off_t * newoffset TSRMLS_DC)677 static int oci_blob_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
678 {
679 struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
680
681 if (offset >= PDO_OCI_LOBMAXSIZE) {
682 return -1;
683 } else {
684 self->offset = offset + 1; /* Oracle LOBS are 1-based, but PHP is 0-based */
685 return 0;
686 }
687 }
688
689 static php_stream_ops oci_blob_stream_ops = {
690 oci_blob_write,
691 oci_blob_read,
692 oci_blob_close,
693 oci_blob_flush,
694 "pdo_oci blob stream",
695 oci_blob_seek,
696 NULL,
697 NULL,
698 NULL
699 };
700
oci_create_lob_stream(pdo_stmt_t * stmt,OCILobLocator * lob TSRMLS_DC)701 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC)
702 {
703 php_stream *stm;
704 struct oci_lob_self *self = ecalloc(1, sizeof(*self));
705 self->lob = lob;
706 self->offset = 1; /* 1-based */
707 self->stmt = stmt;
708 self->S = (pdo_oci_stmt*)stmt->driver_data;
709
710 stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
711
712 if (stm) {
713 php_pdo_stmt_addref(stmt TSRMLS_CC);
714 return stm;
715 }
716
717 efree(self);
718 return NULL;
719 }
720
oci_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)721 static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
722 {
723 pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
724 pdo_oci_column *C = &S->cols[colno];
725
726 /* check the indicator to ensure that the data is intact */
727 if (C->indicator == -1) {
728 /* A NULL value */
729 *ptr = NULL;
730 *len = 0;
731 return 1;
732 } else if (C->indicator == 0) {
733 /* it was stored perfectly */
734
735 if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
736 if (C->data) {
737 *ptr = (char*)oci_create_lob_stream(stmt, (OCILobLocator*)C->data TSRMLS_CC);
738 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
739 }
740 *len = 0;
741 return *ptr ? 1 : 0;
742 }
743
744 *ptr = C->data;
745 *len = C->fetched_len;
746 return 1;
747 } else {
748 /* it was truncated */
749 php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
750
751 *ptr = C->data;
752 *len = C->fetched_len;
753 return 1;
754 }
755 } /* }}} */
756
757 struct pdo_stmt_methods oci_stmt_methods = {
758 oci_stmt_dtor,
759 oci_stmt_execute,
760 oci_stmt_fetch,
761 oci_stmt_describe,
762 oci_stmt_get_col,
763 oci_stmt_param_hook
764 };
765
766 /*
767 * Local variables:
768 * tab-width: 4
769 * c-basic-offset: 4
770 * End:
771 * vim600: noet sw=4 ts=4 fdm=marker
772 * vim<600: noet sw=4 ts=4
773 */
774