Back to index

php5  5.3.10
oci_statement.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Wez Furlong <wez@php.net>                                    |
00016   +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: oci_statement.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "pdo/php_pdo.h"
00029 #include "pdo/php_pdo_driver.h"
00030 #include "php_pdo_oci.h"
00031 #include "php_pdo_oci_int.h"
00032 #include "Zend/zend_extensions.h"
00033 
00034 #define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
00035 
00036 #define STMT_CALL(name, params)                                                                          \
00037        do {                                                                                                            \
00038               S->last_err = name params;                                                                 \
00039               S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
00040               if (S->last_err) {                                                                                \
00041                      return 0;                                                                                         \
00042               }                                                                                                               \
00043        } while(0)
00044 
00045 #define STMT_CALL_MSG(name, msg, params)                                                   \
00046        do {                                                                                                            \
00047               S->last_err = name params;                                                                 \
00048               S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
00049               if (S->last_err) {                                                                                \
00050                      return 0;                                                                                         \
00051               }                                                                                                               \
00052        } while(0)
00053 
00054 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC);
00055 
00056 static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00057 {
00058        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00059        HashTable *BC = stmt->bound_columns;
00060        HashTable *BP = stmt->bound_params;
00061 
00062        int i;
00063 
00064        if (S->stmt) {
00065               /* cancel server side resources for the statement if we didn't
00066                * fetch it all */
00067               OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
00068 
00069               /* free the handle */
00070               OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
00071               S->stmt = NULL;
00072        }
00073        if (S->err) {
00074               OCIHandleFree(S->err, OCI_HTYPE_ERROR);
00075               S->err = NULL;
00076        }
00077 
00078        /* need to ensure these go away now */
00079        if (BC) {
00080               zend_hash_destroy(BC);
00081               FREE_HASHTABLE(stmt->bound_columns);
00082               stmt->bound_columns = NULL;
00083        }
00084 
00085        if (BP) {
00086               zend_hash_destroy(BP);
00087               FREE_HASHTABLE(stmt->bound_params);
00088               stmt->bound_params = NULL;
00089        }
00090 
00091        if (S->einfo.errmsg) {
00092               pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
00093               S->einfo.errmsg = NULL;
00094        }
00095 
00096        if (S->cols) {
00097               for (i = 0; i < stmt->column_count; i++) {
00098                      if (S->cols[i].data) {
00099                             switch (S->cols[i].dtype) {
00100                                    case SQLT_BLOB:
00101                                    case SQLT_CLOB:
00102                                           /* do nothing */
00103                                           break;
00104                                    default:
00105                                           efree(S->cols[i].data);
00106                             }
00107                      }
00108               }
00109               efree(S->cols);
00110               S->cols = NULL;
00111        }
00112        efree(S);
00113 
00114        stmt->driver_data = NULL;
00115 
00116        return 1;
00117 } /* }}} */
00118 
00119 static int oci_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
00120 {
00121        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00122        ub4 rowcount;
00123        b4 mode;
00124 
00125        if (!S->stmt_type) {
00126               STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
00127                             (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
00128        }
00129 
00130        if (stmt->executed) {
00131               /* ensure that we cancel the cursor from a previous fetch */
00132               OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
00133        }
00134 
00135 #ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
00136        if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
00137               mode = OCI_STMT_SCROLLABLE_READONLY;
00138        } else
00139 #endif
00140        if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
00141               mode = OCI_COMMIT_ON_SUCCESS;
00142        } else {
00143               mode = OCI_DEFAULT;
00144        }
00145 
00146        STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
00147                             (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
00148                             mode));
00149 
00150        if (!stmt->executed) {
00151               ub4 colcount;
00152               /* do first-time-only definition of bind/mapping stuff */
00153 
00154               /* how many columns do we have ? */
00155               STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
00156                             (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
00157 
00158               stmt->column_count = (int)colcount;
00159 
00160               if (S->cols) {
00161                      int i;
00162                      for (i = 0; i < stmt->column_count; i++) {
00163                             if (S->cols[i].data) {
00164                                    switch (S->cols[i].dtype) {
00165                                           case SQLT_BLOB:
00166                                           case SQLT_CLOB:
00167                                                  /* do nothing */
00168                                                  break;
00169                                           default:
00170                                                  efree(S->cols[i].data);
00171                                    }
00172                             }
00173                      }
00174                      efree(S->cols);
00175               }
00176 
00177               S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
00178        }
00179 
00180        STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
00181                      (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
00182        stmt->row_count = (long)rowcount;
00183 
00184        return 1;
00185 } /* }}} */
00186 
00187 static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
00188 {
00189        struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
00190        pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
00191        TSRMLS_FETCH();
00192 
00193        if (!param || !param->parameter) {
00194               php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_input_cb; this should not happen");
00195               return OCI_ERROR;
00196        }
00197 
00198        *indpp = &P->indicator;
00199 
00200        if (P->thing) {
00201               *bufpp = P->thing;
00202               *alenp = sizeof(void*);
00203        } else if (ZVAL_IS_NULL(param->parameter)) {
00204               /* insert a NULL value into the column */
00205               P->indicator = -1; /* NULL */
00206               *bufpp = 0;
00207               *alenp = -1;
00208        } else if (!P->thing) {
00209               /* regular string bind */
00210               convert_to_string(param->parameter);
00211               *bufpp = Z_STRVAL_P(param->parameter);
00212               *alenp = Z_STRLEN_P(param->parameter);
00213        }
00214 
00215        *piecep = OCI_ONE_PIECE;
00216        return OCI_CONTINUE;
00217 } /* }}} */
00218 
00219 static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
00220 {
00221        struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
00222        pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
00223        TSRMLS_FETCH();
00224 
00225        if (!param || !param->parameter) {
00226               php_error_docref(NULL TSRMLS_CC, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen");
00227               return OCI_ERROR;
00228        }
00229 
00230        if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
00231               P->actual_len = sizeof(OCILobLocator*);
00232               *bufpp = P->thing;
00233               *alenpp = &P->actual_len;
00234               *piecep = OCI_ONE_PIECE;
00235               *rcodepp = &P->retcode;
00236               *indpp = &P->indicator;
00237               return OCI_CONTINUE;
00238        }
00239 
00240        if (Z_TYPE_P(param->parameter) == IS_OBJECT || Z_TYPE_P(param->parameter) == IS_RESOURCE) {
00241               return OCI_CONTINUE;
00242        }
00243 
00244        convert_to_string(param->parameter);
00245        zval_dtor(param->parameter);
00246 
00247        Z_STRLEN_P(param->parameter) = param->max_value_len;
00248        Z_STRVAL_P(param->parameter) = ecalloc(1, Z_STRLEN_P(param->parameter)+1);
00249        P->used_for_output = 1;
00250 
00251        P->actual_len = Z_STRLEN_P(param->parameter);
00252        *alenpp = &P->actual_len;
00253        *bufpp = Z_STRVAL_P(param->parameter);
00254        *piecep = OCI_ONE_PIECE;
00255        *rcodepp = &P->retcode;
00256        *indpp = &P->indicator;
00257 
00258        return OCI_CONTINUE;
00259 } /* }}} */
00260 
00261 static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
00262 {
00263        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00264 
00265        /* we're only interested in parameters for prepared SQL right now */
00266        if (param->is_param) {
00267               pdo_oci_bound_param *P;
00268               sb4 value_sz = -1;
00269 
00270               P = (pdo_oci_bound_param*)param->driver_data;
00271 
00272               switch (event_type) {
00273                      case PDO_PARAM_EVT_FREE:
00274                             P = param->driver_data;
00275                             if (P) {
00276                                    efree(P);
00277                             }
00278                             break;
00279 
00280                      case PDO_PARAM_EVT_ALLOC:
00281                             P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
00282                             param->driver_data = P;
00283 
00284                             /* figure out what we're doing */
00285                             switch (PDO_PARAM_TYPE(param->param_type)) {
00286                                    case PDO_PARAM_STMT:
00287                                           return 0;
00288 
00289                                    case PDO_PARAM_LOB:
00290                                           /* P->thing is now an OCILobLocator * */
00291                                           P->oci_type = SQLT_BLOB;
00292                                           value_sz = sizeof(OCILobLocator*);
00293                                           break;
00294 
00295                                    case PDO_PARAM_STR:
00296                                    default:
00297                                           P->oci_type = SQLT_CHR;
00298                                           value_sz = param->max_value_len;
00299                                           if (param->max_value_len == 0) {
00300                                                  value_sz = 1332; /* maximum size before value is interpreted as a LONG value */
00301                                           }
00302 
00303                             }
00304 
00305                             if (param->name) {
00306                                    STMT_CALL(OCIBindByName, (S->stmt,
00307                                                  &P->bind, S->err, (text*)param->name,
00308                                                  param->namelen, 0, value_sz, P->oci_type,
00309                                                  &P->indicator, 0, &P->retcode, 0, 0,
00310                                                  OCI_DATA_AT_EXEC));
00311                             } else {
00312                                    STMT_CALL(OCIBindByPos, (S->stmt,
00313                                                  &P->bind, S->err, param->paramno+1,
00314                                                  0, value_sz, P->oci_type,
00315                                                  &P->indicator, 0, &P->retcode, 0, 0,
00316                                                  OCI_DATA_AT_EXEC));
00317                             }
00318 
00319                             STMT_CALL(OCIBindDynamic, (P->bind,
00320                                                  S->err,
00321                                                  param, oci_bind_input_cb,
00322                                                  param, oci_bind_output_cb));
00323 
00324                             return 1;
00325 
00326                      case PDO_PARAM_EVT_EXEC_PRE:
00327                             P->indicator = 0;
00328                             P->used_for_output = 0;
00329                             if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
00330                                    ub4 empty = 0;
00331                                    STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
00332                                    STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
00333                                    S->have_blobs = 1;
00334                             }
00335                             return 1;
00336 
00337                      case PDO_PARAM_EVT_EXEC_POST:
00338                             /* fixup stuff set in motion in oci_bind_output_cb */
00339                             if (P->used_for_output) {
00340                                    if (P->indicator == -1) {
00341                                           /* set up a NULL value */
00342                                           if (Z_TYPE_P(param->parameter) == IS_STRING
00343 #if ZEND_EXTENSION_API_NO < 220040718
00344                                                         && Z_STRVAL_P(param->parameter) != empty_string
00345 #endif
00346                                              ) {
00347                                                  /* OCI likes to stick non-terminated strings in things */
00348                                                  *Z_STRVAL_P(param->parameter) = '\0';
00349                                           }
00350                                           zval_dtor(param->parameter);
00351                                           ZVAL_NULL(param->parameter);
00352                                    } else if (Z_TYPE_P(param->parameter) == IS_STRING
00353 #if ZEND_EXTENSION_API_NO < 220040718
00354                                                  && Z_STRVAL_P(param->parameter) != empty_string
00355 #endif
00356                                                  ) {
00357                                           Z_STRLEN_P(param->parameter) = P->actual_len;
00358                                           Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1);
00359                                           Z_STRVAL_P(param->parameter)[P->actual_len] = '\0';
00360                                    }
00361                             } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
00362                                    php_stream *stm;
00363 
00364                                    if (Z_TYPE_P(param->parameter) == IS_NULL) {
00365                                           /* if the param is NULL, then we assume that they
00366                                            * wanted to bind a lob locator into it from the query
00367                                            * */
00368 
00369                                           stm = oci_create_lob_stream(stmt, (OCILobLocator*)P->thing TSRMLS_CC);
00370                                           if (stm) {
00371                                                  OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
00372                                                  php_stream_to_zval(stm, param->parameter);
00373                                                  P->thing = NULL;
00374                                           }
00375                                    } else {
00376                                           /* we're a LOB being used for insert; transfer the data now */
00377                                           size_t n;
00378                                           ub4 amt, offset = 1;
00379                                           char *consume;
00380 
00381                                           php_stream_from_zval_no_verify(stm, &param->parameter);
00382                                           if (stm) {
00383                                                  OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
00384                                                  do {
00385                                                         char buf[8192];
00386                                                         n = php_stream_read(stm, buf, sizeof(buf));
00387                                                         if ((int)n <= 0) {
00388                                                                break;
00389                                                         }
00390                                                         consume = buf;
00391                                                         do {
00392                                                                amt = n;
00393                                                                OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
00394                                                                              &amt, offset, consume, n,
00395                                                                              OCI_ONE_PIECE,
00396                                                                              NULL, NULL, 0, SQLCS_IMPLICIT);
00397                                                                offset += amt;
00398                                                                n -= amt;
00399                                                                consume += amt;
00400                                                         } while (n);
00401                                                  } while (1);
00402                                                  OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
00403                                                  OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
00404                                           } else if (Z_TYPE_P(param->parameter) == IS_STRING) {
00405                                                  /* stick the string into the LOB */
00406                                                  consume = Z_STRVAL_P(param->parameter);
00407                                                  n = Z_STRLEN_P(param->parameter);
00408                                                  if (n) {
00409                                                         OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
00410                                                         while (n) {
00411                                                                amt = n;
00412                                                                OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
00413                                                                              &amt, offset, consume, n,
00414                                                                              OCI_ONE_PIECE,
00415                                                                              NULL, NULL, 0, SQLCS_IMPLICIT);
00416                                                                consume += amt;
00417                                                                n -= amt;
00418                                                         }
00419                                                         OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
00420                                                  }
00421                                           }
00422                                           OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
00423                                           P->thing = NULL;
00424                                    }
00425                             }
00426 
00427                             return 1;
00428               }
00429        }
00430 
00431        return 1;
00432 } /* }}} */
00433 
00434 static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,  long offset TSRMLS_DC) /* {{{ */
00435 {
00436 #if HAVE_OCISTMTFETCH2
00437        ub4 ociori;
00438 #endif
00439        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00440 
00441 #if HAVE_OCISTMTFETCH2
00442        switch (ori) {
00443               case PDO_FETCH_ORI_NEXT:    ociori = OCI_FETCH_NEXT; break;
00444               case PDO_FETCH_ORI_PRIOR:   ociori = OCI_FETCH_PRIOR; break;
00445               case PDO_FETCH_ORI_FIRST:   ociori = OCI_FETCH_FIRST; break;
00446               case PDO_FETCH_ORI_LAST:    ociori = OCI_FETCH_LAST; break;
00447               case PDO_FETCH_ORI_ABS:            ociori = OCI_FETCH_ABSOLUTE; break;
00448               case PDO_FETCH_ORI_REL:            ociori = OCI_FETCH_RELATIVE; break;
00449        }
00450        S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, offset, OCI_DEFAULT);
00451 #else
00452        S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
00453 #endif
00454 
00455        if (S->last_err == OCI_NO_DATA) {
00456               /* no (more) data */
00457               return 0;
00458        }
00459 
00460        if (S->last_err == OCI_NEED_DATA) {
00461               oci_stmt_error("OCI_NEED_DATA");
00462               return 0;
00463        }
00464 
00465        if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
00466               return 1;
00467        }
00468 
00469        oci_stmt_error("OCIStmtFetch");
00470 
00471        return 0;
00472 } /* }}} */
00473 
00474 static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
00475               ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
00476 {
00477        pdo_oci_column *col = (pdo_oci_column*)octxp;
00478        TSRMLS_FETCH();
00479 
00480        switch (col->dtype) {
00481               case SQLT_BLOB:
00482               case SQLT_CLOB:
00483                      *piecep = OCI_ONE_PIECE;
00484                      *bufpp = col->data;
00485                      *alenpp = &col->datalen;
00486                      *indpp = (dvoid *)&col->indicator;
00487                      break;
00488 
00489               default:
00490                      php_error_docref(NULL TSRMLS_CC, E_WARNING,
00491                             "unhandled datatype in oci_define_callback; this should not happen");
00492                      return OCI_ERROR;
00493        }
00494 
00495        return OCI_CONTINUE;
00496 }
00497 
00498 static int oci_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
00499 {
00500        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00501        OCIParam *param = NULL;
00502        text *colname;
00503        ub2 dtype, data_size, scale, precis;
00504        ub4 namelen;
00505        struct pdo_column_data *col = &stmt->columns[colno];
00506        zend_bool dyn = FALSE;
00507 
00508        /* describe the column */
00509        STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)&param, colno+1));
00510 
00511        /* what type ? */
00512        STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
00513                      (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
00514 
00515        /* how big ? */
00516        STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
00517                      (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
00518 
00519        /* scale ? */
00520        STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
00521                      (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
00522 
00523        /* precision ? */
00524        STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
00525                      (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
00526 
00527        /* name ? */
00528        STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
00529                      (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
00530 
00531        col->precision = scale;
00532        col->maxlen = data_size;
00533        col->namelen = namelen;
00534        col->name = estrndup((char *)colname, namelen);
00535 
00536        S->cols[colno].dtype = dtype;
00537 
00538        /* how much room do we need to store the field */
00539        switch (dtype) {
00540               case SQLT_LBI:
00541               case SQLT_LNG:
00542                      if (dtype == SQLT_LBI) {
00543                             dtype = SQLT_BIN;
00544                      } else {
00545                             dtype = SQLT_CHR;
00546                      }
00547                      S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
00548                      S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
00549                      col->param_type = PDO_PARAM_STR;
00550                      break;
00551 
00552               case SQLT_BLOB:
00553               case SQLT_CLOB:
00554                      col->param_type = PDO_PARAM_LOB;
00555                      STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
00556                      S->cols[colno].datalen = sizeof(OCILobLocator*);
00557                      dyn = TRUE;
00558                      break;
00559 
00560               case SQLT_BIN:
00561               default:
00562                      if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
00563 #ifdef SQLT_TIMESTAMP
00564                                    || dtype == SQLT_TIMESTAMP
00565 #endif
00566 #ifdef SQLT_TIMESTAMP_TZ
00567                                    || dtype == SQLT_TIMESTAMP_TZ
00568 #endif
00569                                    ) {
00570                             /* should be big enough for most date formats and numbers */
00571                             S->cols[colno].datalen = 512;
00572 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
00573                      } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
00574                             S->cols[colno].datalen = 1024;
00575 #endif
00576                      } else {
00577                             S->cols[colno].datalen = col->maxlen;
00578                      }
00579                      if (dtype == SQLT_BIN) {
00580                             S->cols[colno].datalen *= 3;
00581                      }
00582                      S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
00583                      dtype = SQLT_CHR;
00584 
00585                      /* returning data as a string */
00586                      col->param_type = PDO_PARAM_STR;
00587        }
00588 
00589        STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
00590                             S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
00591                             &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
00592 
00593        if (dyn) {
00594               STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
00595                             oci_define_callback));
00596        }
00597 
00598        return 1;
00599 } /* }}} */
00600 
00601 struct oci_lob_self {
00602        pdo_stmt_t *stmt;
00603        pdo_oci_stmt *S;
00604        OCILobLocator *lob;
00605        ub4 offset;
00606 };
00607 
00608 static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
00609 {
00610        struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
00611        ub4 amt;
00612        sword r;
00613 
00614        amt = count;
00615        r = OCILobWrite(self->S->H->svc, self->S->err, self->lob,
00616               &amt, self->offset, (char*)buf, count,
00617               OCI_ONE_PIECE,
00618               NULL, NULL, 0, SQLCS_IMPLICIT);
00619 
00620        if (r != OCI_SUCCESS) {
00621               return (size_t)-1;
00622        }
00623 
00624        self->offset += amt;
00625        return amt;
00626 }
00627 
00628 static size_t oci_blob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
00629 {
00630        struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
00631        ub4 amt;
00632        sword r;
00633 
00634        amt = count;
00635        r = OCILobRead(self->S->H->svc, self->S->err, self->lob,
00636               &amt, self->offset, buf, count,
00637               NULL, NULL, 0, SQLCS_IMPLICIT);
00638 
00639        if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
00640               return (size_t)-1;
00641        }
00642 
00643        self->offset += amt;
00644        if (amt < count) {
00645               stream->eof = 1;
00646        }
00647        return amt;
00648 }
00649 
00650 static int oci_blob_close(php_stream *stream, int close_handle TSRMLS_DC)
00651 {
00652        struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
00653        pdo_stmt_t *stmt = self->stmt;
00654 
00655        if (close_handle) {
00656               OCILobClose(self->S->H->svc, self->S->err, self->lob);
00657               OCIDescriptorFree(self->lob, OCI_DTYPE_LOB);
00658               efree(self);
00659        }
00660 
00661        php_pdo_stmt_delref(stmt TSRMLS_CC);
00662        return 0;
00663 }
00664 
00665 static int oci_blob_flush(php_stream *stream TSRMLS_DC)
00666 {
00667        struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
00668        OCILobFlushBuffer(self->S->H->svc, self->S->err, self->lob, 0);
00669        return 0;
00670 }
00671 
00672 static int oci_blob_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
00673 {
00674        struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
00675 
00676        if (offset >= PDO_OCI_LOBMAXSIZE) {
00677               return -1;
00678        } else {
00679               self->offset = offset + 1;  /* Oracle LOBS are 1-based, but PHP is 0-based */
00680               return 0;
00681        }
00682 }
00683 
00684 static php_stream_ops oci_blob_stream_ops = {
00685        oci_blob_write,
00686        oci_blob_read,
00687        oci_blob_close,
00688        oci_blob_flush,
00689        "pdo_oci blob stream",
00690        oci_blob_seek,
00691        NULL,
00692        NULL,
00693        NULL
00694 };
00695 
00696 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC)
00697 {
00698        php_stream *stm;
00699        struct oci_lob_self *self = ecalloc(1, sizeof(*self));
00700        self->lob = lob;
00701        self->offset = 1; /* 1-based */
00702        self->stmt = stmt;
00703        self->S = (pdo_oci_stmt*)stmt->driver_data;
00704 
00705        stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
00706 
00707        if (stm) {
00708               php_pdo_stmt_addref(stmt TSRMLS_CC);
00709               return stm;
00710        }
00711 
00712        efree(self);
00713        return NULL;
00714 }
00715 
00716 static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) /* {{{ */
00717 {
00718        pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
00719        pdo_oci_column *C = &S->cols[colno];
00720 
00721        /* check the indicator to ensure that the data is intact */
00722        if (C->indicator == -1) {
00723               /* A NULL value */
00724               *ptr = NULL;
00725               *len = 0;
00726               return 1;
00727        } else if (C->indicator == 0) {
00728               /* it was stored perfectly */
00729 
00730               if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
00731                      if (C->data) {
00732                             *ptr = (char*)oci_create_lob_stream(stmt, (OCILobLocator*)C->data TSRMLS_CC);
00733                             OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
00734                      }
00735                      *len = 0;
00736                      return *ptr ? 1 : 0;
00737               }
00738 
00739               *ptr = C->data;
00740               *len = C->fetched_len;
00741               return 1;
00742        } else {
00743               /* it was truncated */
00744               php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
00745 
00746               *ptr = C->data;
00747               *len = C->fetched_len;
00748               return 1;
00749        }
00750 } /* }}} */
00751 
00752 struct pdo_stmt_methods oci_stmt_methods = {
00753        oci_stmt_dtor,
00754        oci_stmt_execute,
00755        oci_stmt_fetch,
00756        oci_stmt_describe,
00757        oci_stmt_get_col,
00758        oci_stmt_param_hook
00759 };
00760 
00761 /*
00762  * Local variables:
00763  * tab-width: 4
00764  * c-basic-offset: 4
00765  * End:
00766  * vim600: noet sw=4 ts=4 fdm=marker
00767  * vim<600: noet sw=4 ts=4
00768  */