123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Wez Furlong <wez@php.net> |
- +----------------------------------------------------------------------+
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_ini.h"
- #include "ext/standard/info.h"
- #include "pdo/php_pdo.h"
- #include "pdo/php_pdo_driver.h"
- #include "php_pdo_oci.h"
- #include "php_pdo_oci_int.h"
- #include "Zend/zend_extensions.h"
- #define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
- #define STMT_CALL(name, params) \
- do { \
- S->last_err = name params; \
- S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__); \
- if (S->last_err) { \
- return 0; \
- } \
- } while(0)
- #define STMT_CALL_MSG(name, msg, params) \
- do { \
- S->last_err = name params; \
- S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__); \
- if (S->last_err) { \
- return 0; \
- } \
- } while(0)
- static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob);
- #define OCI_TEMPLOB_CLOSE(envhp, svchp, errhp, lob) \
- do \
- { \
- boolean isTempLOB; \
- OCILobIsTemporary(envhp, errhp, lob, &isTempLOB); \
- if (isTempLOB) \
- OCILobFreeTemporary(svchp, errhp, lob); \
- } while(0)
- static int oci_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- HashTable *BC = stmt->bound_columns;
- HashTable *BP = stmt->bound_params;
- int i;
- if (S->stmt) {
- /* cancel server side resources for the statement if we didn't
- * fetch it all */
- OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
- /* free the handle */
- OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
- S->stmt = NULL;
- }
- if (S->err) {
- OCIHandleFree(S->err, OCI_HTYPE_ERROR);
- S->err = NULL;
- }
- /* need to ensure these go away now */
- if (BC) {
- zend_hash_destroy(BC);
- FREE_HASHTABLE(stmt->bound_columns);
- stmt->bound_columns = NULL;
- }
- if (BP) {
- zend_hash_destroy(BP);
- FREE_HASHTABLE(stmt->bound_params);
- stmt->bound_params = NULL;
- }
- if (S->einfo.errmsg) {
- pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
- S->einfo.errmsg = NULL;
- }
- if (S->cols) {
- for (i = 0; i < stmt->column_count; i++) {
- if (S->cols[i].data) {
- switch (S->cols[i].dtype) {
- case SQLT_BLOB:
- case SQLT_CLOB:
- OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err,
- (OCILobLocator *) S->cols[i].data);
- OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
- break;
- default:
- efree(S->cols[i].data);
- }
- }
- }
- efree(S->cols);
- S->cols = NULL;
- }
- efree(S);
- stmt->driver_data = NULL;
- return 1;
- } /* }}} */
- static int oci_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- ub4 rowcount;
- b4 mode;
- if (!S->stmt_type) {
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
- (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
- }
- if (stmt->executed) {
- /* ensure that we cancel the cursor from a previous fetch */
- OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
- }
- #ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
- if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
- mode = OCI_STMT_SCROLLABLE_READONLY;
- } else
- #endif
- if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
- mode = OCI_COMMIT_ON_SUCCESS;
- } else {
- mode = OCI_DEFAULT;
- }
- STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
- (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
- mode));
- if (!stmt->executed) {
- ub4 colcount;
- /* do first-time-only definition of bind/mapping stuff */
- /* how many columns do we have ? */
- STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
- (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
- stmt->column_count = (int)colcount;
- if (S->cols) {
- int i;
- for (i = 0; i < stmt->column_count; i++) {
- if (S->cols[i].data) {
- switch (S->cols[i].dtype) {
- case SQLT_BLOB:
- case SQLT_CLOB:
- /* do nothing */
- break;
- default:
- efree(S->cols[i].data);
- }
- }
- }
- efree(S->cols);
- }
- S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
- }
- STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
- (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
- stmt->row_count = (long)rowcount;
- return 1;
- } /* }}} */
- static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
- {
- struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
- pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
- zval *parameter;
- ZEND_ASSERT(param);
- *indpp = &P->indicator;
- if (Z_ISREF(param->parameter))
- parameter = Z_REFVAL(param->parameter);
- else
- parameter = ¶m->parameter;
- if (P->thing) {
- *bufpp = P->thing;
- *alenp = sizeof(void*);
- } else if (ZVAL_IS_NULL(parameter)) {
- /* insert a NULL value into the column */
- P->indicator = -1; /* NULL */
- *bufpp = 0;
- *alenp = -1;
- } else if (!P->thing) {
- /* regular string bind */
- if (!try_convert_to_string(parameter)) {
- return OCI_ERROR;
- }
- *bufpp = Z_STRVAL_P(parameter);
- *alenp = (ub4) Z_STRLEN_P(parameter);
- }
- *piecep = OCI_ONE_PIECE;
- return OCI_CONTINUE;
- } /* }}} */
- static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
- {
- struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
- pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
- zval *parameter;
- ZEND_ASSERT(param);
- if (Z_ISREF(param->parameter)) {
- parameter = Z_REFVAL(param->parameter);
- } else {
- parameter = ¶m->parameter;
- }
- if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
- P->actual_len = sizeof(OCILobLocator*);
- *bufpp = P->thing;
- *alenpp = &P->actual_len;
- *piecep = OCI_ONE_PIECE;
- *rcodepp = &P->retcode;
- *indpp = &P->indicator;
- return OCI_CONTINUE;
- }
- if (Z_TYPE_P(parameter) == IS_OBJECT || Z_TYPE_P(parameter) == IS_RESOURCE) {
- return OCI_CONTINUE;
- }
- zval_ptr_dtor(parameter);
- Z_STR_P(parameter) = zend_string_alloc(param->max_value_len, 1);
- P->used_for_output = 1;
- P->actual_len = (ub4) Z_STRLEN_P(parameter);
- *alenpp = &P->actual_len;
- *bufpp = (Z_STR_P(parameter))->val;
- *piecep = OCI_ONE_PIECE;
- *rcodepp = &P->retcode;
- *indpp = &P->indicator;
- return OCI_CONTINUE;
- } /* }}} */
- static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- /* we're only interested in parameters for prepared SQL right now */
- if (param->is_param) {
- pdo_oci_bound_param *P;
- sb4 value_sz = -1;
- zval *parameter;
- if (Z_ISREF(param->parameter))
- parameter = Z_REFVAL(param->parameter);
- else
- parameter = ¶m->parameter;
- P = (pdo_oci_bound_param*)param->driver_data;
- switch (event_type) {
- case PDO_PARAM_EVT_FETCH_PRE:
- case PDO_PARAM_EVT_FETCH_POST:
- case PDO_PARAM_EVT_NORMALIZE:
- /* Do nothing */
- break;
- case PDO_PARAM_EVT_FREE:
- P = param->driver_data;
- if (P && P->thing) {
- OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
- OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
- P->thing = NULL;
- efree(P);
- }
- else if (P) {
- efree(P);
- }
- break;
- case PDO_PARAM_EVT_ALLOC:
- P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
- param->driver_data = P;
- /* figure out what we're doing */
- switch (PDO_PARAM_TYPE(param->param_type)) {
- case PDO_PARAM_STMT:
- return 0;
- case PDO_PARAM_LOB:
- /* P->thing is now an OCILobLocator * */
- P->oci_type = SQLT_BLOB;
- value_sz = (sb4) sizeof(OCILobLocator*);
- break;
- case PDO_PARAM_STR:
- default:
- P->oci_type = SQLT_CHR;
- value_sz = (sb4) param->max_value_len;
- if (param->max_value_len == 0) {
- value_sz = (sb4) 1332; /* maximum size before value is interpreted as a LONG value */
- }
- }
- if (param->name) {
- STMT_CALL(OCIBindByName, (S->stmt,
- &P->bind, S->err, (text*)param->name->val,
- (sb4) param->name->len, 0, value_sz, P->oci_type,
- &P->indicator, 0, &P->retcode, 0, 0,
- OCI_DATA_AT_EXEC));
- } else {
- STMT_CALL(OCIBindByPos, (S->stmt,
- &P->bind, S->err, ((ub4)param->paramno)+1,
- 0, value_sz, P->oci_type,
- &P->indicator, 0, &P->retcode, 0, 0,
- OCI_DATA_AT_EXEC));
- }
- STMT_CALL(OCIBindDynamic, (P->bind,
- S->err,
- param, oci_bind_input_cb,
- param, oci_bind_output_cb));
- return 1;
- case PDO_PARAM_EVT_EXEC_PRE:
- P->indicator = 0;
- P->used_for_output = 0;
- if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
- ub4 empty = 0;
- STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
- STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
- S->have_blobs = 1;
- }
- return 1;
- case PDO_PARAM_EVT_EXEC_POST:
- /* fixup stuff set in motion in oci_bind_output_cb */
- if (P->used_for_output) {
- if (P->indicator == -1) {
- /* set up a NULL value */
- if (Z_TYPE_P(parameter) == IS_STRING) {
- /* OCI likes to stick non-terminated strings in things */
- *Z_STRVAL_P(parameter) = '\0';
- }
- zval_ptr_dtor_str(parameter);
- ZVAL_UNDEF(parameter);
- } else if (Z_TYPE_P(parameter) == IS_STRING) {
- Z_STR_P(parameter) = zend_string_init(Z_STRVAL_P(parameter), P->actual_len, 1);
- }
- } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
- php_stream *stm;
- if (Z_TYPE_P(parameter) == IS_NULL) {
- /* if the param is NULL, then we assume that they
- * wanted to bind a lob locator into it from the query
- * */
- stm = oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)P->thing);
- if (stm) {
- OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
- php_stream_to_zval(stm, parameter);
- }
- } else {
- /* we're a LOB being used for insert; transfer the data now */
- size_t n;
- ub4 amt, offset = 1;
- char *consume;
- php_stream_from_zval_no_verify(stm, parameter);
- if (stm) {
- OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
- do {
- char buf[8192];
- n = php_stream_read(stm, buf, sizeof(buf));
- if ((int)n <= 0) {
- break;
- }
- consume = buf;
- do {
- amt = (ub4) n;
- OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
- &amt, offset, consume, (ub4) n,
- OCI_ONE_PIECE,
- NULL, NULL, 0, SQLCS_IMPLICIT);
- offset += amt;
- n -= amt;
- consume += amt;
- } while (n);
- } while (1);
- OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
- OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
- } else if (Z_TYPE_P(parameter) == IS_STRING) {
- /* stick the string into the LOB */
- consume = Z_STRVAL_P(parameter);
- n = Z_STRLEN_P(parameter);
- if (n) {
- OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
- while (n) {
- amt = (ub4) n;
- OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
- &amt, offset, consume, (ub4) n,
- OCI_ONE_PIECE,
- NULL, NULL, 0, SQLCS_IMPLICIT);
- consume += amt;
- n -= amt;
- }
- OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
- }
- }
- OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
- OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
- P->thing = NULL;
- }
- }
- return 1;
- }
- }
- return 1;
- } /* }}} */
- static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) /* {{{ */
- {
- #ifdef HAVE_OCISTMTFETCH2
- ub4 ociori = OCI_FETCH_NEXT;
- #endif
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- #ifdef HAVE_OCISTMTFETCH2
- switch (ori) {
- case PDO_FETCH_ORI_NEXT: ociori = OCI_FETCH_NEXT; break;
- case PDO_FETCH_ORI_PRIOR: ociori = OCI_FETCH_PRIOR; break;
- case PDO_FETCH_ORI_FIRST: ociori = OCI_FETCH_FIRST; break;
- case PDO_FETCH_ORI_LAST: ociori = OCI_FETCH_LAST; break;
- case PDO_FETCH_ORI_ABS: ociori = OCI_FETCH_ABSOLUTE; break;
- case PDO_FETCH_ORI_REL: ociori = OCI_FETCH_RELATIVE; break;
- }
- S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, (sb4) offset, OCI_DEFAULT);
- #else
- S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
- #endif
- if (S->last_err == OCI_NO_DATA) {
- /* no (more) data */
- return 0;
- }
- if (S->last_err == OCI_NEED_DATA) {
- oci_stmt_error("OCI_NEED_DATA");
- return 0;
- }
- if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
- return 1;
- }
- oci_stmt_error("OCIStmtFetch");
- return 0;
- } /* }}} */
- static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
- ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
- {
- pdo_oci_column *col = (pdo_oci_column*)octxp;
- switch (col->dtype) {
- case SQLT_BLOB:
- case SQLT_CLOB:
- *piecep = OCI_ONE_PIECE;
- *bufpp = col->data;
- *alenpp = &col->datalen;
- *indpp = (dvoid *)&col->indicator;
- break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- return OCI_CONTINUE;
- }
- static int oci_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- OCIParam *param = NULL;
- text *colname;
- ub2 dtype, data_size, precis;
- ub4 namelen;
- struct pdo_column_data *col = &stmt->columns[colno];
- bool dyn = FALSE;
- /* describe the column */
- STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)¶m, colno+1));
- /* what type ? */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
- (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
- /* how big ? */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
- (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
- /* precision ? */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
- (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
- /* name ? */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
- (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
- col->precision = precis;
- col->maxlen = data_size;
- col->name = zend_string_init((char *)colname, namelen, 0);
- S->cols[colno].dtype = dtype;
- /* how much room do we need to store the field */
- switch (dtype) {
- case SQLT_LBI:
- case SQLT_LNG:
- if (dtype == SQLT_LBI) {
- dtype = SQLT_BIN;
- } else {
- dtype = SQLT_CHR;
- }
- S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
- S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
- break;
- case SQLT_BLOB:
- case SQLT_CLOB:
- STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
- S->cols[colno].datalen = sizeof(OCILobLocator*);
- dyn = TRUE;
- break;
- case SQLT_BIN:
- default:
- if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
- #ifdef SQLT_TIMESTAMP
- || dtype == SQLT_TIMESTAMP
- #endif
- #ifdef SQLT_TIMESTAMP_TZ
- || dtype == SQLT_TIMESTAMP_TZ
- #endif
- ) {
- /* should be big enough for most date formats and numbers */
- S->cols[colno].datalen = 512;
- #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
- } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
- S->cols[colno].datalen = 1024;
- #endif
- } else if (dtype == SQLT_BIN) {
- S->cols[colno].datalen = (ub4) col->maxlen * 2; /* raw characters to hex digits */
- } else {
- S->cols[colno].datalen = (ub4) (col->maxlen * S->H->max_char_width);
- }
- S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
- dtype = SQLT_CHR;
- }
- STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
- S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
- &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
- if (dyn) {
- STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
- oci_define_callback));
- }
- return 1;
- } /* }}} */
- struct _oci_lob_env {
- OCISvcCtx *svc;
- OCIError *err;
- };
- typedef struct _oci_lob_env oci_lob_env;
- struct oci_lob_self {
- zval dbh;
- pdo_stmt_t *stmt;
- pdo_oci_stmt *S;
- OCILobLocator *lob;
- oci_lob_env *E;
- ub4 offset;
- };
- static ssize_t oci_blob_write(php_stream *stream, const char *buf, size_t count)
- {
- struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
- ub4 amt;
- sword r;
- amt = (ub4) count;
- r = OCILobWrite(self->E->svc, self->E->err, self->lob,
- &amt, self->offset, (char*)buf, (ub4) count,
- OCI_ONE_PIECE,
- NULL, NULL, 0, SQLCS_IMPLICIT);
- if (r != OCI_SUCCESS) {
- return (ssize_t)-1;
- }
- self->offset += amt;
- return amt;
- }
- static ssize_t oci_blob_read(php_stream *stream, char *buf, size_t count)
- {
- struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
- ub4 amt;
- sword r;
- amt = (ub4) count;
- r = OCILobRead(self->E->svc, self->E->err, self->lob,
- &amt, self->offset, buf, (ub4) count,
- NULL, NULL, 0, SQLCS_IMPLICIT);
- if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
- return (size_t)-1;
- }
- self->offset += amt;
- if (amt < count) {
- stream->eof = 1;
- }
- return amt;
- }
- static int oci_blob_close(php_stream *stream, int close_handle)
- {
- struct oci_lob_self *self = (struct oci_lob_self *)stream->abstract;
- pdo_stmt_t *stmt = self->stmt;
- if (close_handle) {
- zend_object *obj = &stmt->std;
- OCILobClose(self->E->svc, self->E->err, self->lob);
- zval_ptr_dtor(&self->dbh);
- GC_DELREF(obj);
- efree(self->E);
- efree(self);
- }
- /* php_pdo_free_statement(stmt); */
- return 0;
- }
- static int oci_blob_flush(php_stream *stream)
- {
- struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
- OCILobFlushBuffer(self->E->svc, self->E->err, self->lob, 0);
- return 0;
- }
- static int oci_blob_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
- {
- struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
- if (offset >= PDO_OCI_LOBMAXSIZE) {
- return -1;
- } else {
- self->offset = (ub4) offset + 1; /* Oracle LOBS are 1-based, but PHP is 0-based */
- return 0;
- }
- }
- static const php_stream_ops oci_blob_stream_ops = {
- oci_blob_write,
- oci_blob_read,
- oci_blob_close,
- oci_blob_flush,
- "pdo_oci blob stream",
- oci_blob_seek,
- NULL,
- NULL,
- NULL
- };
- static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob)
- {
- php_stream *stm;
- struct oci_lob_self *self = ecalloc(1, sizeof(*self));
- ZVAL_COPY_VALUE(&self->dbh, dbh);
- self->lob = lob;
- self->offset = 1; /* 1-based */
- self->stmt = stmt;
- self->S = (pdo_oci_stmt*)stmt->driver_data;
- self->E = ecalloc(1, sizeof(oci_lob_env));
- self->E->svc = self->S->H->svc;
- self->E->err = self->S->err;
- stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
- if (stm) {
- zend_object *obj;
- obj = &stmt->std;
- Z_ADDREF(self->dbh);
- GC_ADDREF(obj);
- return stm;
- }
- efree(self);
- return NULL;
- }
- static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- pdo_oci_column *C = &S->cols[colno];
- /* check the indicator to ensure that the data is intact */
- if (C->indicator == -1) {
- /* A NULL value */
- ZVAL_NULL(result);
- return 1;
- } else if (C->indicator == 0) {
- /* it was stored perfectly */
- if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
- if (C->data) {
- php_stream *stream = oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)C->data);
- OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
- php_stream_to_zval(stream, result);
- return 1;
- }
- return 0;
- }
- ZVAL_STRINGL_FAST(result, C->data, C->fetched_len);
- return 1;
- } else {
- /* it was truncated */
- php_error_docref(NULL, E_WARNING, "Column %d data was too large for buffer and was truncated to fit it", colno);
- ZVAL_STRINGL(result, C->data, C->fetched_len);
- return 1;
- }
- } /* }}} */
- static int oci_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) /* {{{ */
- {
- pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
- OCIParam *param = NULL;
- ub2 dtype, precis;
- sb1 scale;
- zval flags;
- ub1 isnull, charset_form;
- if (!S->stmt) {
- return FAILURE;
- }
- if (colno >= stmt->column_count) {
- /* error invalid column */
- return FAILURE;
- }
- array_init(return_value);
- array_init(&flags);
- /* describe the column */
- STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)¶m, colno+1));
- /* column data type */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
- (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
- /* column precision */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
- (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
- /* column scale */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
- (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
- /* string column charset form */
- if (dtype == SQLT_CHR || dtype == SQLT_VCS || dtype == SQLT_AFC || dtype == SQLT_CLOB) {
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_CHARSET_FORM",
- (param, OCI_DTYPE_PARAM, &charset_form, 0, OCI_ATTR_CHARSET_FORM, S->err));
- }
- if (dtype) {
- /* if there is a declared type */
- switch (dtype) {
- #ifdef SQLT_TIMESTAMP
- case SQLT_TIMESTAMP:
- add_assoc_string(return_value, "oci:decl_type", "TIMESTAMP");
- add_assoc_string(return_value, "native_type", "TIMESTAMP");
- break;
- #endif
- #ifdef SQLT_TIMESTAMP_TZ
- case SQLT_TIMESTAMP_TZ:
- add_assoc_string(return_value, "oci:decl_type", "TIMESTAMP WITH TIMEZONE");
- add_assoc_string(return_value, "native_type", "TIMESTAMP WITH TIMEZONE");
- break;
- #endif
- #ifdef SQLT_TIMESTAMP_LTZ
- case SQLT_TIMESTAMP_LTZ:
- add_assoc_string(return_value, "oci:decl_type", "TIMESTAMP WITH LOCAL TIMEZONE");
- add_assoc_string(return_value, "native_type", "TIMESTAMP WITH LOCAL TIMEZONE");
- break;
- #endif
- #ifdef SQLT_INTERVAL_YM
- case SQLT_INTERVAL_YM:
- add_assoc_string(return_value, "oci:decl_type", "INTERVAL YEAR TO MONTH");
- add_assoc_string(return_value, "native_type", "INTERVAL YEAR TO MONTH");
- break;
- #endif
- #ifdef SQLT_INTERVAL_DS
- case SQLT_INTERVAL_DS:
- add_assoc_string(return_value, "oci:decl_type", "INTERVAL DAY TO SECOND");
- add_assoc_string(return_value, "native_type", "INTERVAL DAY TO SECOND");
- break;
- #endif
- case SQLT_DAT:
- add_assoc_string(return_value, "oci:decl_type", "DATE");
- add_assoc_string(return_value, "native_type", "DATE");
- break;
- case SQLT_FLT :
- case SQLT_NUM:
- /* if the precision is nonzero and scale is -127 then it is a FLOAT */
- if (scale == -127 && precis != 0) {
- add_assoc_string(return_value, "oci:decl_type", "FLOAT");
- add_assoc_string(return_value, "native_type", "FLOAT");
- } else {
- add_assoc_string(return_value, "oci:decl_type", "NUMBER");
- add_assoc_string(return_value, "native_type", "NUMBER");
- }
- break;
- case SQLT_LNG:
- add_assoc_string(return_value, "oci:decl_type", "LONG");
- add_assoc_string(return_value, "native_type", "LONG");
- break;
- case SQLT_BIN:
- add_assoc_string(return_value, "oci:decl_type", "RAW");
- add_assoc_string(return_value, "native_type", "RAW");
- break;
- case SQLT_LBI:
- add_assoc_string(return_value, "oci:decl_type", "LONG RAW");
- add_assoc_string(return_value, "native_type", "LONG RAW");
- break;
- case SQLT_CHR:
- case SQLT_VCS:
- if (charset_form == SQLCS_NCHAR) {
- add_assoc_string(return_value, "oci:decl_type", "NVARCHAR2");
- add_assoc_string(return_value, "native_type", "NVARCHAR2");
- } else {
- add_assoc_string(return_value, "oci:decl_type", "VARCHAR2");
- add_assoc_string(return_value, "native_type", "VARCHAR2");
- }
- break;
- case SQLT_AFC:
- if (charset_form == SQLCS_NCHAR) {
- add_assoc_string(return_value, "oci:decl_type", "NCHAR");
- add_assoc_string(return_value, "native_type", "NCHAR");
- } else {
- add_assoc_string(return_value, "oci:decl_type", "CHAR");
- add_assoc_string(return_value, "native_type", "CHAR");
- }
- break;
- case SQLT_BLOB:
- add_assoc_string(return_value, "oci:decl_type", "BLOB");
- add_next_index_string(&flags, "blob");
- add_assoc_string(return_value, "native_type", "BLOB");
- break;
- case SQLT_CLOB:
- if (charset_form == SQLCS_NCHAR) {
- add_assoc_string(return_value, "oci:decl_type", "NCLOB");
- add_assoc_string(return_value, "native_type", "NCLOB");
- } else {
- add_assoc_string(return_value, "oci:decl_type", "CLOB");
- add_assoc_string(return_value, "native_type", "CLOB");
- }
- add_next_index_string(&flags, "blob");
- break;
- case SQLT_BFILE:
- add_assoc_string(return_value, "oci:decl_type", "BFILE");
- add_next_index_string(&flags, "blob");
- add_assoc_string(return_value, "native_type", "BFILE");
- break;
- case SQLT_RDD:
- add_assoc_string(return_value, "oci:decl_type", "ROWID");
- add_assoc_string(return_value, "native_type", "ROWID");
- break;
- case SQLT_BFLOAT:
- case SQLT_IBFLOAT:
- add_assoc_string(return_value, "oci:decl_type", "BINARY_FLOAT");
- add_assoc_string(return_value, "native_type", "BINARY_FLOAT");
- break;
- case SQLT_BDOUBLE:
- case SQLT_IBDOUBLE:
- add_assoc_string(return_value, "oci:decl_type", "BINARY_DOUBLE");
- add_assoc_string(return_value, "native_type", "BINARY_DOUBLE");
- break;
- default:
- add_assoc_long(return_value, "oci:decl_type", dtype);
- add_assoc_string(return_value, "native_type", "UNKNOWN");
- }
- } else {
- /* if the column is NULL */
- add_assoc_long(return_value, "oci:decl_type", 0);
- add_assoc_string(return_value, "native_type", "NULL");
- }
- switch (dtype) {
- case SQLT_BLOB:
- case SQLT_CLOB:
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_LOB);
- break;
- default:
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
- break;
- }
- /* column can be null */
- STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_IS_NULL",
- (param, OCI_DTYPE_PARAM, &isnull, 0, OCI_ATTR_IS_NULL, S->err));
- if (isnull) {
- add_next_index_string(&flags, "nullable");
- } else {
- add_next_index_string(&flags, "not_null");
- }
- /* PDO type */
- switch (dtype) {
- case SQLT_BFILE:
- case SQLT_BLOB:
- case SQLT_CLOB:
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_LOB);
- break;
- default:
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
- }
- add_assoc_long(return_value, "scale", scale);
- add_assoc_zval(return_value, "flags", &flags);
- OCIDescriptorFree(param, OCI_DTYPE_PARAM);
- return SUCCESS;
- } /* }}} */
- const struct pdo_stmt_methods oci_stmt_methods = {
- oci_stmt_dtor,
- oci_stmt_execute,
- oci_stmt_fetch,
- oci_stmt_describe,
- oci_stmt_get_col,
- oci_stmt_param_hook,
- NULL, /* set_attr */
- NULL, /* get_attr */
- oci_stmt_col_meta,
- NULL,
- NULL
- };
|