root/ext/pdo_oci/oci_statement.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oci_stmt_dtor
  2. oci_stmt_execute
  3. oci_bind_input_cb
  4. oci_bind_output_cb
  5. oci_stmt_param_hook
  6. oci_stmt_fetch
  7. oci_define_callback
  8. oci_stmt_describe
  9. oci_blob_write
  10. oci_blob_read
  11. oci_blob_close
  12. oci_blob_flush
  13. oci_blob_seek
  14. oci_create_lob_stream
  15. oci_stmt_get_col

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Author: Wez Furlong <wez@php.net>                                    |
  16   +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 #include "php_ini.h"
  27 #include "ext/standard/info.h"
  28 #include "pdo/php_pdo.h"
  29 #include "pdo/php_pdo_driver.h"
  30 #include "php_pdo_oci.h"
  31 #include "php_pdo_oci_int.h"
  32 #include "Zend/zend_extensions.h"
  33 
  34 #define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
  35 
  36 #define STMT_CALL(name, params)                                                                                 \
  37         do {                                                                                                                            \
  38                 S->last_err = name params;                                                                              \
  39                 S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
  40                 if (S->last_err) {                                                                                              \
  41                         return 0;                                                                                                       \
  42                 }                                                                                                                               \
  43         } while(0)
  44 
  45 #define STMT_CALL_MSG(name, msg, params)                                                                \
  46         do {                                                                                                                            \
  47                 S->last_err = name params;                                                                              \
  48                 S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__ TSRMLS_CC); \
  49                 if (S->last_err) {                                                                                              \
  50                         return 0;                                                                                                       \
  51                 }                                                                                                                               \
  52         } while(0)
  53 
  54 static php_stream *oci_create_lob_stream(pdo_stmt_t *stmt, OCILobLocator *lob TSRMLS_DC);
  55 
  56 static int oci_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
  57 {
  58         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  59         HashTable *BC = stmt->bound_columns;
  60         HashTable *BP = stmt->bound_params;
  61 
  62         int i;
  63 
  64         if (S->stmt) {
  65                 /* cancel server side resources for the statement if we didn't
  66                  * fetch it all */
  67                 OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
  68 
  69                 /* free the handle */
  70                 OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
  71                 S->stmt = NULL;
  72         }
  73         if (S->err) {
  74                 OCIHandleFree(S->err, OCI_HTYPE_ERROR);
  75                 S->err = NULL;
  76         }
  77 
  78         /* need to ensure these go away now */
  79         if (BC) {
  80                 zend_hash_destroy(BC);
  81                 FREE_HASHTABLE(stmt->bound_columns);
  82                 stmt->bound_columns = NULL;
  83         }
  84 
  85         if (BP) {
  86                 zend_hash_destroy(BP);
  87                 FREE_HASHTABLE(stmt->bound_params);
  88                 stmt->bound_params = NULL;
  89         }
  90 
  91         if (S->einfo.errmsg) {
  92                 pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
  93                 S->einfo.errmsg = NULL;
  94         }
  95 
  96         if (S->cols) {
  97                 for (i = 0; i < stmt->column_count; i++) {
  98                         if (S->cols[i].data) {
  99                                 switch (S->cols[i].dtype) {
 100                                         case SQLT_BLOB:
 101                                         case SQLT_CLOB:
 102                                                 OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
 103                                                 break;
 104                                         default:
 105                                                 efree(S->cols[i].data);
 106                                 }
 107                         }
 108                 }
 109                 efree(S->cols);
 110                 S->cols = NULL;
 111         }
 112         efree(S);
 113 
 114         stmt->driver_data = NULL;
 115 
 116         return 1;
 117 } /* }}} */
 118 
 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) {
 273                         case PDO_PARAM_EVT_FETCH_PRE:
 274                         case PDO_PARAM_EVT_FETCH_POST:
 275                         case PDO_PARAM_EVT_NORMALIZE:
 276                                 /* Do nothing */
 277                                 break;
 278 
 279                         case PDO_PARAM_EVT_FREE:
 280                                 P = param->driver_data;
 281                                 if (P) {
 282                                         efree(P);
 283                                 }
 284                                 break;
 285 
 286                         case PDO_PARAM_EVT_ALLOC:
 287                                 P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
 288                                 param->driver_data = P;
 289 
 290                                 /* figure out what we're doing */
 291                                 switch (PDO_PARAM_TYPE(param->param_type)) {
 292                                         case PDO_PARAM_STMT:
 293                                                 return 0;
 294 
 295                                         case PDO_PARAM_LOB:
 296                                                 /* P->thing is now an OCILobLocator * */
 297                                                 P->oci_type = SQLT_BLOB;
 298                                                 value_sz = sizeof(OCILobLocator*);
 299                                                 break;
 300 
 301                                         case PDO_PARAM_STR:
 302                                         default:
 303                                                 P->oci_type = SQLT_CHR;
 304                                                 value_sz = param->max_value_len;
 305                                                 if (param->max_value_len == 0) {
 306                                                         value_sz = 1332; /* maximum size before value is interpreted as a LONG value */
 307                                                 }
 308 
 309                                 }
 310 
 311                                 if (param->name) {
 312                                         STMT_CALL(OCIBindByName, (S->stmt,
 313                                                         &P->bind, S->err, (text*)param->name,
 314                                                         param->namelen, 0, value_sz, P->oci_type,
 315                                                         &P->indicator, 0, &P->retcode, 0, 0,
 316                                                         OCI_DATA_AT_EXEC));
 317                                 } else {
 318                                         STMT_CALL(OCIBindByPos, (S->stmt,
 319                                                         &P->bind, S->err, param->paramno+1,
 320                                                         0, value_sz, P->oci_type,
 321                                                         &P->indicator, 0, &P->retcode, 0, 0,
 322                                                         OCI_DATA_AT_EXEC));
 323                                 }
 324 
 325                                 STMT_CALL(OCIBindDynamic, (P->bind,
 326                                                         S->err,
 327                                                         param, oci_bind_input_cb,
 328                                                         param, oci_bind_output_cb));
 329 
 330                                 return 1;
 331 
 332                         case PDO_PARAM_EVT_EXEC_PRE:
 333                                 P->indicator = 0;
 334                                 P->used_for_output = 0;
 335                                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 336                                         ub4 empty = 0;
 337                                         STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
 338                                         STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
 339                                         S->have_blobs = 1;
 340                                 }
 341                                 return 1;
 342 
 343                         case PDO_PARAM_EVT_EXEC_POST:
 344                                 /* fixup stuff set in motion in oci_bind_output_cb */
 345                                 if (P->used_for_output) {
 346                                         if (P->indicator == -1) {
 347                                                 /* set up a NULL value */
 348                                                 if (Z_TYPE_P(param->parameter) == IS_STRING
 349 #if ZEND_EXTENSION_API_NO < 220040718
 350                                                                 && Z_STRVAL_P(param->parameter) != empty_string
 351 #endif
 352                                                    ) {
 353                                                         /* OCI likes to stick non-terminated strings in things */
 354                                                         *Z_STRVAL_P(param->parameter) = '\0';
 355                                                 }
 356                                                 zval_dtor(param->parameter);
 357                                                 ZVAL_NULL(param->parameter);
 358                                         } else if (Z_TYPE_P(param->parameter) == IS_STRING
 359 #if ZEND_EXTENSION_API_NO < 220040718
 360                                                         && Z_STRVAL_P(param->parameter) != empty_string
 361 #endif
 362                                                         ) {
 363                                                 Z_STRLEN_P(param->parameter) = P->actual_len;
 364                                                 Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->actual_len+1);
 365                                                 Z_STRVAL_P(param->parameter)[P->actual_len] = '\0';
 366                                         }
 367                                 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
 368                                         php_stream *stm;
 369 
 370                                         if (Z_TYPE_P(param->parameter) == IS_NULL) {
 371                                                 /* if the param is NULL, then we assume that they
 372                                                  * wanted to bind a lob locator into it from the query
 373                                                  * */
 374 
 375                                                 stm = oci_create_lob_stream(stmt, (OCILobLocator*)P->thing TSRMLS_CC);
 376                                                 if (stm) {
 377                                                         OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
 378                                                         php_stream_to_zval(stm, param->parameter);
 379                                                         P->thing = NULL;
 380                                                 }
 381                                         } else {
 382                                                 /* we're a LOB being used for insert; transfer the data now */
 383                                                 size_t n;
 384                                                 ub4 amt, offset = 1;
 385                                                 char *consume;
 386 
 387                                                 php_stream_from_zval_no_verify(stm, &param->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*)&param, 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  */

/* [<][>][^][v][top][bottom][index][help] */