![]() ![]() | ![]() |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.5 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 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:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 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:
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:
1.1.1.3 misho 102: OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
1.1 misho 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:
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:
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:
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:
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) {
1.1.1.4 misho 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:
1.1 misho 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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: */