diff options
author | Wez Furlong <wez@php.net> | 2005-10-31 02:11:27 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2005-10-31 02:11:27 +0000 |
commit | 2baf1500e0a649235b0f2243176ad2fd2c9e2d54 (patch) | |
tree | 9ff49dd57bf76b1516a35ac63727a4f671af6d05 /ext/pdo_oci | |
parent | 40c24a65c474d3a87500bf338b96bcb8b6185ee1 (diff) | |
download | php-git-2baf1500e0a649235b0f2243176ad2fd2c9e2d54.tar.gz |
Closes PECL Bug #5722; BLOB support was half-baked.
Diffstat (limited to 'ext/pdo_oci')
-rwxr-xr-x | ext/pdo_oci/oci_statement.c | 281 | ||||
-rwxr-xr-x | ext/pdo_oci/php_pdo_oci_int.h | 5 |
2 files changed, 258 insertions, 28 deletions
diff --git a/ext/pdo_oci/oci_statement.c b/ext/pdo_oci/oci_statement.c index b5a53dede5..102249e699 100755 --- a/ext/pdo_oci/oci_statement.c +++ b/ext/pdo_oci/oci_statement.c @@ -45,6 +45,7 @@ return 0; \ } +static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC); static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ { @@ -89,7 +90,14 @@ static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ if (S->cols) { for (i = 0; i < stmt->column_count; i++) { if (S->cols[i].data) { - efree(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); @@ -130,7 +138,7 @@ static int oci_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ } STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err, - S->stmt_type == OCI_STMT_SELECT ? 0 : 1, 0, NULL, NULL, + (S->stmt_type == OCI_STMT_SELECT || S->have_blobs) : 1, 0, NULL, NULL, mode)); if (!stmt->executed) { @@ -166,7 +174,10 @@ static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dv *indpp = &P->indicator; - if (ZVAL_IS_NULL(param->parameter)) { + if (P->thing) { + *bufpp = P->thing; + *alenp = sizeof(void*); + } else if (ZVAL_IS_NULL(param->parameter)) { /* insert a NULL value into the column */ P->indicator = -1; /* NULL */ *bufpp = 0; @@ -176,9 +187,6 @@ static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dv convert_to_string(param->parameter); *bufpp = Z_STRVAL_P(param->parameter); *alenp = Z_STRLEN_P(param->parameter); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "P->thing should not be set??"); - return OCI_ERROR; } *piecep = OCI_ONE_PIECE; @@ -195,6 +203,16 @@ static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, d php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen"); return OCI_ERROR; } + + 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(param->parameter) == IS_OBJECT || Z_TYPE_P(param->parameter) == IS_RESOURCE) { return OCI_CONTINUE; @@ -246,21 +264,10 @@ static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *pa return 0; case PDO_PARAM_LOB: - /* fake lobs for now */ - if (Z_TYPE_P(param->parameter) == IS_RESOURCE) { - php_stream *stm; - php_stream_from_zval_no_verify(stm, ¶m->parameter); - if (stm) { - SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); - Z_TYPE_P(param->parameter) = IS_STRING; - Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm, - &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0); - } else { - pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC); - return 0; - } - } - /* fall through */ + /* P->thing is now an OCILobLocator * */ + P->oci_type = SQLT_BLOB; + value_sz = sizeof(OCILobLocator*); + break; case PDO_PARAM_STR: default: @@ -296,6 +303,12 @@ static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *pa 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: @@ -322,6 +335,70 @@ static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *pa Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1); Z_STRVAL_P(param->parameter)[P->actual_len] = '\0'; } + } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) { + php_stream *stm; + + if (Z_TYPE_P(param->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, (OCILobLocator*)P->thing TSRMLS_CC); + if (stm) { + OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE); + php_stream_to_zval(stm, param->parameter); + P->thing = NULL; + } + } 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, ¶m->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 = n; + OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing, + &amt, offset, consume, 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(param->parameter) == IS_STRING) { + /* stick the string into the LOB */ + consume = Z_STRVAL_P(param->parameter); + n = Z_STRLEN_P(param->parameter); + if (n) { + OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE); + while (n) { + amt = n; + OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing, + &amt, offset, consume, n, + OCI_ONE_PIECE, + NULL, NULL, 0, SQLCS_IMPLICIT); + consume += amt; + n -= amt; + } + OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing); + } + } + OCIDescriptorFree(P->thing, OCI_DTYPE_LOB); + P->thing = NULL; + } } return 1; @@ -371,6 +448,28 @@ static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long 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; + break; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "unhandled datatype in oci_define_callback; this should not happen"); + return OCI_ERROR; + } + + return OCI_CONTINUE; +} + static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */ { pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data; @@ -409,11 +508,12 @@ static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */ col->namelen = namelen; col->name = estrndup(colname, namelen); + S->cols[colno].dtype = dtype; + /* how much room do we need to store the field */ switch (dtype) { case SQLT_LBI: case SQLT_LNG: - dyn = FALSE; if (dtype == SQLT_LBI) { dtype = SQLT_BIN; } else { @@ -423,10 +523,17 @@ static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */ S->cols[colno].data = emalloc(S->cols[colno].datalen + 1); col->param_type = PDO_PARAM_STR; break; + + case SQLT_BLOB: + case SQLT_CLOB: + col->param_type = PDO_PARAM_LOB; + 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: - dyn = FALSE; if (dtype == SQLT_DAT || dtype == SQLT_NUM #ifdef SQLT_TIMESTAMP || dtype == SQLT_TIMESTAMP @@ -450,15 +557,125 @@ static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */ col->param_type = PDO_PARAM_STR; } - if (!dyn) { - 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, OCI_DEFAULT)); + 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_self { + pdo_stmt_t *stmt; + pdo_oci_stmt *S; + OCILobLocator *lob; + ub4 offset; +}; + +static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) +{ + struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; + ub4 amt; + sword r; + + amt = count; + r = OCILobWrite(self->S->H->svc, self->S->err, self->lob, + &amt, self->offset, (char*)buf, count, + OCI_ONE_PIECE, + NULL, NULL, 0, SQLCS_IMPLICIT); + + if (r != OCI_SUCCESS) { + return (size_t)-1; + } + + self->offset += amt; + return amt; +} + +static size_t oci_blob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) +{ + struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; + ub4 amt; + sword r; + + amt = count; + r = OCILobRead(self->S->H->svc, self->S->err, self->lob, + &amt, self->offset, buf, count, + NULL, NULL, 0, SQLCS_IMPLICIT); + + if (r != OCI_SUCCESS) { + return (size_t)-1; + } + + self->offset += amt; + return amt; +} + +static int oci_blob_close(php_stream *stream, int close_handle TSRMLS_DC) +{ + struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; + pdo_stmt_t *stmt = self->stmt; + + if (close_handle) { + OCILobClose(self->S->H->svc, self->S->err, self->lob); + OCIDescriptorFree(self->lob, OCI_DTYPE_LOB); + efree(self); + } + + php_pdo_stmt_delref(stmt TSRMLS_CC); + return 0; +} + +static int oci_blob_flush(php_stream *stream TSRMLS_DC) +{ + struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; + OCILobFlushBuffer(self->S->H->svc, self->S->err, self->lob, 0); + return 0; +} + +static int oci_blob_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) +{ + struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; + /* TODO: implement */ + return -1; +} + +static php_stream_ops oci_blob_stream_ops = { + oci_blob_write, + oci_blob_read, + oci_blob_close, + oci_blob_flush, + "pdo_oci blob stream", + NULL, /*oci_blob_seek,*/ + NULL, + NULL, + NULL +}; + +static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC) +{ + php_stream *stm; + struct oci_lob_self *self = ecalloc(1, sizeof(*self)); + self->lob = lob; + self->offset = 1; /* 1-based */ + self->stmt = stmt; + self->S = (pdo_oci_stmt*)stmt->driver_data; + + stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b"); + + if (stm) { + php_pdo_stmt_addref(stmt TSRMLS_CC); + return stm; + } + + efree(self); + return NULL; +} + static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */ { pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data; @@ -472,6 +689,16 @@ static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned lo return 1; } else if (C->indicator == 0) { /* it was stored perfectly */ + + if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) { + if (C->data) { + *ptr = (char*)oci_create_lob_stream(stmt, (OCILobLocator*)C->data TSRMLS_CC); + OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY); + } + *len = 0; + return *ptr ? 1 : 0; + } + *ptr = C->data; *len = C->fetched_len; return 1; diff --git a/ext/pdo_oci/php_pdo_oci_int.h b/ext/pdo_oci/php_pdo_oci_int.h index a28d466eac..45d52a620b 100755 --- a/ext/pdo_oci/php_pdo_oci_int.h +++ b/ext/pdo_oci/php_pdo_oci_int.h @@ -51,7 +51,9 @@ typedef struct { sb2 indicator; char *data; - unsigned long datalen; + ub4 datalen; + + ub2 dtype; } pdo_oci_column; @@ -64,6 +66,7 @@ typedef struct { ub4 exec_type; pdo_oci_column *cols; pdo_oci_error_info einfo; + unsigned int have_blobs:1; } pdo_oci_stmt; typedef struct { |