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 7                                                        |
   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__); \
  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__); \
  49                 if (S->last_err) {                                                                                              \
  50                         return 0;                                                                                                       \
  51                 }                                                                                                                               \
  52         } while(0)
  53 
  54 static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob);
  55 
  56 #define OCI_TEMPLOB_CLOSE(envhp, svchp, errhp, lob)                             \
  57         do                                                                                                                      \
  58         {                                                                                                                       \
  59                 boolean isTempLOB;                                                                              \
  60                 OCILobIsTemporary(envhp, errhp, lob, &isTempLOB);               \
  61                 if (isTempLOB)                                                                                  \
  62                         OCILobFreeTemporary(svchp, errhp, lob);                         \
  63         } while(0)
  64 
  65 static int oci_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
  66 {
  67         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  68         HashTable *BC = stmt->bound_columns;
  69         HashTable *BP = stmt->bound_params;
  70 
  71         int i;
  72 
  73         if (S->stmt) {
  74                 /* cancel server side resources for the statement if we didn't
  75                  * fetch it all */
  76                 OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
  77 
  78                 /* free the handle */
  79                 OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
  80                 S->stmt = NULL;
  81         }
  82         if (S->err) {
  83                 OCIHandleFree(S->err, OCI_HTYPE_ERROR);
  84                 S->err = NULL;
  85         }
  86 
  87         /* need to ensure these go away now */
  88         if (BC) {
  89                 zend_hash_destroy(BC);
  90                 FREE_HASHTABLE(stmt->bound_columns);
  91                 stmt->bound_columns = NULL;
  92         }
  93 
  94         if (BP) {
  95                 zend_hash_destroy(BP);
  96                 FREE_HASHTABLE(stmt->bound_params);
  97                 stmt->bound_params = NULL;
  98         }
  99 
 100         if (S->einfo.errmsg) {
 101                 pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
 102                 S->einfo.errmsg = NULL;
 103         }
 104 
 105         if (S->cols) {
 106                 for (i = 0; i < stmt->column_count; i++) {
 107                         if (S->cols[i].data) {
 108                                 switch (S->cols[i].dtype) {
 109                                         case SQLT_BLOB:
 110                                         case SQLT_CLOB:
 111                                                 OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err,
 112                                                         (OCILobLocator *) S->cols[i].data);
 113                                                 OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
 114                                                 break;
 115                                         default:
 116                                                 efree(S->cols[i].data);
 117                                 }
 118                         }
 119                 }
 120                 efree(S->cols);
 121                 S->cols = NULL;
 122         }
 123         efree(S);
 124 
 125         stmt->driver_data = NULL;
 126 
 127         return 1;
 128 } /* }}} */
 129 
 130 static int oci_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
 131 {
 132         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
 133         ub4 rowcount;
 134         b4 mode;
 135 
 136         if (!S->stmt_type) {
 137                 STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
 138                                 (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
 139         }
 140 
 141         if (stmt->executed) {
 142                 /* ensure that we cancel the cursor from a previous fetch */
 143                 OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
 144         }
 145 
 146 #ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
 147         if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
 148                 mode = OCI_STMT_SCROLLABLE_READONLY;
 149         } else
 150 #endif
 151         if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
 152                 mode = OCI_COMMIT_ON_SUCCESS;
 153         } else {
 154                 mode = OCI_DEFAULT;
 155         }
 156 
 157         STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
 158                                 (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
 159                                 mode));
 160 
 161         if (!stmt->executed) {
 162                 ub4 colcount;
 163                 /* do first-time-only definition of bind/mapping stuff */
 164 
 165                 /* how many columns do we have ? */
 166                 STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
 167                                 (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
 168 
 169                 stmt->column_count = (int)colcount;
 170 
 171                 if (S->cols) {
 172                         int i;
 173                         for (i = 0; i < stmt->column_count; i++) {
 174                                 if (S->cols[i].data) {
 175                                         switch (S->cols[i].dtype) {
 176                                                 case SQLT_BLOB:
 177                                                 case SQLT_CLOB:
 178                                                         /* do nothing */
 179                                                         break;
 180                                                 default:
 181                                                         efree(S->cols[i].data);
 182                                         }
 183                                 }
 184                         }
 185                         efree(S->cols);
 186                 }
 187 
 188                 S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
 189         }
 190 
 191         STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
 192                         (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
 193         stmt->row_count = (long)rowcount;
 194 
 195         return 1;
 196 } /* }}} */
 197 
 198 static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
 199 {
 200         struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
 201         pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
 202         zval *parameter;
 203 
 204         if (!param) {
 205                 php_error_docref(NULL, E_WARNING, "param is NULL in oci_bind_input_cb; this should not happen");
 206                 return OCI_ERROR;
 207         }
 208 
 209         *indpp = &P->indicator;
 210 
 211     if (Z_ISREF(param->parameter))
 212                 parameter = Z_REFVAL(param->parameter);
 213         else
 214                 parameter = &param->parameter;
 215 
 216         if (P->thing) {
 217                 *bufpp = P->thing;
 218                 *alenp = sizeof(void*);
 219         } else if (ZVAL_IS_NULL(parameter)) {
 220                 /* insert a NULL value into the column */
 221                 P->indicator = -1; /* NULL */
 222                 *bufpp = 0;
 223                 *alenp = -1;
 224         } else if (!P->thing) {
 225                 /* regular string bind */
 226                 convert_to_string(parameter);
 227                 *bufpp = Z_STRVAL_P(parameter);
 228                 *alenp = (ub4) Z_STRLEN_P(parameter);
 229         }
 230 
 231         *piecep = OCI_ONE_PIECE;
 232         return OCI_CONTINUE;
 233 } /* }}} */
 234 
 235 static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
 236 {
 237         struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
 238         pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
 239         zval *parameter;
 240 
 241         if (!param) {
 242                 php_error_docref(NULL, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen");
 243                 return OCI_ERROR;
 244         }
 245 
 246         if (Z_ISREF(param->parameter))
 247         parameter = Z_REFVAL(param->parameter);
 248     else
 249         parameter = &param->parameter;
 250 
 251         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 252                 P->actual_len = sizeof(OCILobLocator*);
 253                 *bufpp = P->thing;
 254                 *alenpp = &P->actual_len;
 255                 *piecep = OCI_ONE_PIECE;
 256                 *rcodepp = &P->retcode;
 257                 *indpp = &P->indicator;
 258                 return OCI_CONTINUE;
 259         }
 260 
 261         if (Z_TYPE_P(parameter) == IS_OBJECT || Z_TYPE_P(parameter) == IS_RESOURCE) {
 262                 return OCI_CONTINUE;
 263         }
 264 
 265         convert_to_string(parameter);
 266         zval_dtor(parameter);
 267 
 268         Z_STR_P(parameter) = zend_string_alloc(param->max_value_len, 1);
 269         P->used_for_output = 1;
 270 
 271         P->actual_len = (ub4) Z_STRLEN_P(parameter);
 272         *alenpp = &P->actual_len;
 273         *bufpp = (Z_STR_P(parameter))->val;
 274         *piecep = OCI_ONE_PIECE;
 275         *rcodepp = &P->retcode;
 276         *indpp = &P->indicator;
 277 
 278         return OCI_CONTINUE;
 279 } /* }}} */
 280 
 281 static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
 282 {
 283         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
 284 
 285         /* we're only interested in parameters for prepared SQL right now */
 286         if (param->is_param) {
 287                 pdo_oci_bound_param *P;
 288                 sb4 value_sz = -1;
 289                 zval *parameter;
 290 
 291                 if (Z_ISREF(param->parameter))
 292                         parameter = Z_REFVAL(param->parameter);
 293                 else
 294                         parameter = &param->parameter;
 295 
 296                 P = (pdo_oci_bound_param*)param->driver_data;
 297 
 298                 switch (event_type) {
 299                         case PDO_PARAM_EVT_FETCH_PRE:
 300                         case PDO_PARAM_EVT_FETCH_POST:
 301                         case PDO_PARAM_EVT_NORMALIZE:
 302                                 /* Do nothing */
 303                                 break;
 304 
 305                         case PDO_PARAM_EVT_FREE:
 306                                 P = param->driver_data;
 307                                 if (P && P->thing) {
 308                                         OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
 309                                         OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
 310                                         P->thing = NULL;
 311                                         efree(P);
 312                                 }
 313                                 else if (P) {
 314                                         efree(P);
 315                                 }
 316                                 break;
 317 
 318                         case PDO_PARAM_EVT_ALLOC:
 319                                 P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
 320                                 param->driver_data = P;
 321 
 322                                 /* figure out what we're doing */
 323                                 switch (PDO_PARAM_TYPE(param->param_type)) {
 324                                         case PDO_PARAM_STMT:
 325                                                 return 0;
 326 
 327                                         case PDO_PARAM_LOB:
 328                                                 /* P->thing is now an OCILobLocator * */
 329                                                 P->oci_type = SQLT_BLOB;
 330                                                 value_sz = (sb4) sizeof(OCILobLocator*);
 331                                                 break;
 332 
 333                                         case PDO_PARAM_STR:
 334                                         default:
 335                                                 P->oci_type = SQLT_CHR;
 336                                                 value_sz = (sb4) param->max_value_len;
 337                                                 if (param->max_value_len == 0) {
 338                                                         value_sz = (sb4) 1332; /* maximum size before value is interpreted as a LONG value */
 339                                                 }
 340 
 341                                 }
 342 
 343                                 if (param->name) {
 344                                         STMT_CALL(OCIBindByName, (S->stmt,
 345                                                         &P->bind, S->err, (text*)param->name->val,
 346                                                         (sb4) param->name->len, 0, value_sz, P->oci_type,
 347                                                         &P->indicator, 0, &P->retcode, 0, 0,
 348                                                         OCI_DATA_AT_EXEC));
 349                                 } else {
 350                                         STMT_CALL(OCIBindByPos, (S->stmt,
 351                                                         &P->bind, S->err, ((ub4)param->paramno)+1,
 352                                                         0, value_sz, P->oci_type,
 353                                                         &P->indicator, 0, &P->retcode, 0, 0,
 354                                                         OCI_DATA_AT_EXEC));
 355                                 }
 356 
 357                                 STMT_CALL(OCIBindDynamic, (P->bind,
 358                                                         S->err,
 359                                                         param, oci_bind_input_cb,
 360                                                         param, oci_bind_output_cb));
 361 
 362                                 return 1;
 363 
 364                         case PDO_PARAM_EVT_EXEC_PRE:
 365                                 P->indicator = 0;
 366                                 P->used_for_output = 0;
 367                                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 368                                         ub4 empty = 0;
 369                                         STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
 370                                         STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
 371                                         S->have_blobs = 1;
 372                                 }
 373                                 return 1;
 374 
 375                         case PDO_PARAM_EVT_EXEC_POST:
 376                                 /* fixup stuff set in motion in oci_bind_output_cb */
 377                                 if (P->used_for_output) {
 378                                         if (P->indicator == -1) {
 379                                                 /* set up a NULL value */
 380                                                 if (Z_TYPE_P(parameter) == IS_STRING) {
 381                                                         /* OCI likes to stick non-terminated strings in things */
 382                                                         *Z_STRVAL_P(parameter) = '\0';
 383                                                 }
 384                                                 zval_dtor(parameter);
 385                                                 ZVAL_UNDEF(parameter);
 386                                         } else if (Z_TYPE_P(parameter) == IS_STRING) {
 387                                                 Z_STR_P(parameter) = zend_string_init(Z_STRVAL_P(parameter), P->actual_len, 1);
 388                                         }
 389                                 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
 390                                         php_stream *stm;
 391 
 392                                         if (Z_TYPE_P(parameter) == IS_NULL) {
 393                                                 /* if the param is NULL, then we assume that they
 394                                                  * wanted to bind a lob locator into it from the query
 395                                                  * */
 396 
 397                                                 stm = oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)P->thing);
 398                                                 if (stm) {
 399                                                         OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
 400                                                         php_stream_to_zval(stm, parameter);
 401                                                 }
 402                                         } else {
 403                                                 /* we're a LOB being used for insert; transfer the data now */
 404                                                 size_t n;
 405                                                 ub4 amt, offset = 1;
 406                                                 char *consume;
 407 
 408                                                 php_stream_from_zval_no_verify(stm, parameter);
 409                                                 if (stm) {
 410                                                         OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
 411                                                         do {
 412                                                                 char buf[8192];
 413                                                                 n = php_stream_read(stm, buf, sizeof(buf));
 414                                                                 if ((int)n <= 0) {
 415                                                                         break;
 416                                                                 }
 417                                                                 consume = buf;
 418                                                                 do {
 419                                                                         amt = (ub4) n;
 420                                                                         OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
 421                                                                                         &amt, offset, consume, (ub4) n,
 422                                                                                         OCI_ONE_PIECE,
 423                                                                                         NULL, NULL, 0, SQLCS_IMPLICIT);
 424                                                                         offset += amt;
 425                                                                         n -= amt;
 426                                                                         consume += amt;
 427                                                                 } while (n);
 428                                                         } while (1);
 429                                                         OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
 430                                                         OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
 431                                                 } else if (Z_TYPE_P(parameter) == IS_STRING) {
 432                                                         /* stick the string into the LOB */
 433                                                         consume = Z_STRVAL_P(parameter);
 434                                                         n = Z_STRLEN_P(parameter);
 435                                                         if (n) {
 436                                                                 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
 437                                                                 while (n) {
 438                                                                         amt = (ub4) n;
 439                                                                         OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
 440                                                                                         &amt, offset, consume, (ub4) n,
 441                                                                                         OCI_ONE_PIECE,
 442                                                                                         NULL, NULL, 0, SQLCS_IMPLICIT);
 443                                                                         consume += amt;
 444                                                                         n -= amt;
 445                                                                 }
 446                                                                 OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
 447                                                         }
 448                                                 }
 449                                                 OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
 450                                                 OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
 451                                                 P->thing = NULL;
 452                                         }
 453                                 }
 454 
 455                                 return 1;
 456                 }
 457         }
 458 
 459         return 1;
 460 } /* }}} */
 461 
 462 static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,     zend_long offset) /* {{{ */
 463 {
 464 #if HAVE_OCISTMTFETCH2
 465         ub4 ociori;
 466 #endif
 467         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
 468 
 469 #if HAVE_OCISTMTFETCH2
 470         switch (ori) {
 471                 case PDO_FETCH_ORI_NEXT:        ociori = OCI_FETCH_NEXT; break;
 472                 case PDO_FETCH_ORI_PRIOR:       ociori = OCI_FETCH_PRIOR; break;
 473                 case PDO_FETCH_ORI_FIRST:       ociori = OCI_FETCH_FIRST; break;
 474                 case PDO_FETCH_ORI_LAST:        ociori = OCI_FETCH_LAST; break;
 475                 case PDO_FETCH_ORI_ABS:         ociori = OCI_FETCH_ABSOLUTE; break;
 476                 case PDO_FETCH_ORI_REL:         ociori = OCI_FETCH_RELATIVE; break;
 477         }
 478         S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, (sb4) offset, OCI_DEFAULT);
 479 #else
 480         S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
 481 #endif
 482 
 483         if (S->last_err == OCI_NO_DATA) {
 484                 /* no (more) data */
 485                 return 0;
 486         }
 487 
 488         if (S->last_err == OCI_NEED_DATA) {
 489                 oci_stmt_error("OCI_NEED_DATA");
 490                 return 0;
 491         }
 492 
 493         if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
 494                 return 1;
 495         }
 496 
 497         oci_stmt_error("OCIStmtFetch");
 498 
 499         return 0;
 500 } /* }}} */
 501 
 502 static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
 503                 ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
 504 {
 505         pdo_oci_column *col = (pdo_oci_column*)octxp;
 506 
 507         switch (col->dtype) {
 508                 case SQLT_BLOB:
 509                 case SQLT_CLOB:
 510                         *piecep = OCI_ONE_PIECE;
 511                         *bufpp = col->data;
 512                         *alenpp = &col->datalen;
 513                         *indpp = (dvoid *)&col->indicator;
 514                         break;
 515 
 516                 default:
 517                         php_error_docref(NULL, E_WARNING,
 518                                 "unhandled datatype in oci_define_callback; this should not happen");
 519                         return OCI_ERROR;
 520         }
 521 
 522         return OCI_CONTINUE;
 523 }
 524 
 525 static int oci_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
 526 {
 527         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
 528         OCIParam *param = NULL;
 529         text *colname;
 530         ub2 dtype, data_size, scale, precis;
 531         ub4 namelen;
 532         struct pdo_column_data *col = &stmt->columns[colno];
 533         zend_bool dyn = FALSE;
 534 
 535         /* describe the column */
 536         STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)&param, colno+1));
 537 
 538         /* what type ? */
 539         STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
 540                         (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
 541 
 542         /* how big ? */
 543         STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
 544                         (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
 545 
 546         /* scale ? */
 547         STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
 548                         (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
 549 
 550         /* precision ? */
 551         STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
 552                         (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
 553 
 554         /* name ? */
 555         STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
 556                         (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
 557 
 558         col->precision = scale;
 559         col->maxlen = data_size;
 560         col->name = zend_string_init((char *)colname, namelen, 0);
 561 
 562         S->cols[colno].dtype = dtype;
 563 
 564         /* how much room do we need to store the field */
 565         switch (dtype) {
 566                 case SQLT_LBI:
 567                 case SQLT_LNG:
 568                         if (dtype == SQLT_LBI) {
 569                                 dtype = SQLT_BIN;
 570                         } else {
 571                                 dtype = SQLT_CHR;
 572                         }
 573                         S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
 574                         S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
 575                         col->param_type = PDO_PARAM_STR;
 576                         break;
 577 
 578                 case SQLT_BLOB:
 579                 case SQLT_CLOB:
 580                         col->param_type = PDO_PARAM_LOB;
 581                         STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
 582                         S->cols[colno].datalen = sizeof(OCILobLocator*);
 583                         dyn = TRUE;
 584                         break;
 585 
 586                 case SQLT_BIN:
 587                 default:
 588                         if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
 589 #ifdef SQLT_TIMESTAMP
 590                                         || dtype == SQLT_TIMESTAMP
 591 #endif
 592 #ifdef SQLT_TIMESTAMP_TZ
 593                                         || dtype == SQLT_TIMESTAMP_TZ
 594 #endif
 595                                         ) {
 596                                 /* should be big enough for most date formats and numbers */
 597                                 S->cols[colno].datalen = 512;
 598 #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
 599                         } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
 600                                 S->cols[colno].datalen = 1024;
 601 #endif
 602                         } else {
 603                                 S->cols[colno].datalen = (ub4) col->maxlen;
 604                         }
 605                         if (dtype == SQLT_BIN) {
 606                                 S->cols[colno].datalen *= 3;
 607                         }
 608                         S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
 609                         dtype = SQLT_CHR;
 610 
 611                         /* returning data as a string */
 612                         col->param_type = PDO_PARAM_STR;
 613         }
 614 
 615         STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
 616                                 S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
 617                                 &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
 618 
 619         if (dyn) {
 620                 STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
 621                                 oci_define_callback));
 622         }
 623 
 624         return 1;
 625 } /* }}} */
 626 
 627 struct _oci_lob_env {
 628         OCISvcCtx *svc;
 629         OCIError  *err;
 630 };
 631 typedef struct _oci_lob_env oci_lob_env;
 632 
 633 struct oci_lob_self {
 634         zval dbh;
 635         pdo_stmt_t *stmt;
 636         pdo_oci_stmt *S;
 637         OCILobLocator *lob;
 638         oci_lob_env   *E;
 639         ub4 offset;
 640 };
 641 
 642 static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count)
 643 {
 644         struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
 645         ub4 amt;
 646         sword r;
 647 
 648         amt = (ub4) count;
 649         r = OCILobWrite(self->E->svc, self->E->err, self->lob,
 650                 &amt, self->offset, (char*)buf, (ub4) count,
 651                 OCI_ONE_PIECE,
 652                 NULL, NULL, 0, SQLCS_IMPLICIT);
 653 
 654         if (r != OCI_SUCCESS) {
 655                 return (size_t)-1;
 656         }
 657 
 658         self->offset += amt;
 659         return amt;
 660 }
 661 
 662 static size_t oci_blob_read(php_stream *stream, char *buf, size_t count)
 663 {
 664         struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
 665         ub4 amt;
 666         sword r;
 667 
 668         amt = (ub4) count;
 669         r = OCILobRead(self->E->svc, self->E->err, self->lob,
 670                 &amt, self->offset, buf, (ub4) count,
 671                 NULL, NULL, 0, SQLCS_IMPLICIT);
 672 
 673         if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
 674                 return (size_t)-1;
 675         }
 676 
 677         self->offset += amt;
 678         if (amt < count) {
 679                 stream->eof = 1;
 680         }
 681         return amt;
 682 }
 683 
 684 static int oci_blob_close(php_stream *stream, int close_handle)
 685 {
 686         struct oci_lob_self *self = (struct oci_lob_self *)stream->abstract;
 687         pdo_stmt_t *stmt = self->stmt;
 688 
 689         if (close_handle) {
 690                 zend_object *obj = &stmt->std;
 691 
 692                 OCILobClose(self->E->svc, self->E->err, self->lob);
 693                 zval_ptr_dtor(&self->dbh);
 694                 GC_REFCOUNT(obj)--;
 695                 efree(self->E);
 696                 efree(self);
 697         }
 698 
 699         /* php_pdo_free_statement(stmt); */
 700         return 0;
 701 }
 702 
 703 static int oci_blob_flush(php_stream *stream)
 704 {
 705         struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
 706         OCILobFlushBuffer(self->E->svc, self->E->err, self->lob, 0);
 707         return 0;
 708 }
 709 
 710 static int oci_blob_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
 711 {
 712         struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
 713 
 714         if (offset >= PDO_OCI_LOBMAXSIZE) {
 715                 return -1;
 716         } else {
 717                 self->offset = (ub4) offset + 1;  /* Oracle LOBS are 1-based, but PHP is 0-based */
 718                 return 0;
 719         }
 720 }
 721 
 722 static php_stream_ops oci_blob_stream_ops = {
 723         oci_blob_write,
 724         oci_blob_read,
 725         oci_blob_close,
 726         oci_blob_flush,
 727         "pdo_oci blob stream",
 728         oci_blob_seek,
 729         NULL,
 730         NULL,
 731         NULL
 732 };
 733 
 734 static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob)
 735 {
 736         php_stream *stm;
 737         struct oci_lob_self *self = ecalloc(1, sizeof(*self));
 738 
 739         ZVAL_COPY_VALUE(&self->dbh, dbh);
 740         self->lob = lob;
 741         self->offset = 1; /* 1-based */
 742         self->stmt = stmt;
 743         self->S = (pdo_oci_stmt*)stmt->driver_data;
 744         self->E = ecalloc(1, sizeof(oci_lob_env));
 745         self->E->svc = self->S->H->svc;
 746         self->E->err = self->S->err;
 747 
 748         stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
 749 
 750         if (stm) {
 751                 zend_object *obj;
 752                 obj = &stmt->std;
 753                 Z_ADDREF(self->dbh);
 754                 GC_REFCOUNT(obj)++;
 755                 return stm;
 756         }
 757 
 758         efree(self);
 759         return NULL;
 760 }
 761 
 762 static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) /* {{{ */
 763 {
 764         pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
 765         pdo_oci_column *C = &S->cols[colno];
 766 
 767         /* check the indicator to ensure that the data is intact */
 768         if (C->indicator == -1) {
 769                 /* A NULL value */
 770                 *ptr = NULL;
 771                 *len = 0;
 772                 return 1;
 773         } else if (C->indicator == 0) {
 774                 /* it was stored perfectly */
 775 
 776                 if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
 777                         if (C->data) {
 778                                 *ptr = (char*)oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)C->data);
 779                                 OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
 780                         }
 781                         *len = (size_t) 0;
 782                         return *ptr ? 1 : 0;
 783                 }
 784 
 785                 *ptr = C->data;
 786                 *len = (size_t) C->fetched_len;
 787                 return 1;
 788         } else {
 789                 /* it was truncated */
 790                 php_error_docref(NULL, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
 791 
 792                 *ptr = C->data;
 793                 *len = (size_t) C->fetched_len;
 794                 return 1;
 795         }
 796 } /* }}} */
 797 
 798 struct pdo_stmt_methods oci_stmt_methods = {
 799         oci_stmt_dtor,
 800         oci_stmt_execute,
 801         oci_stmt_fetch,
 802         oci_stmt_describe,
 803         oci_stmt_get_col,
 804         oci_stmt_param_hook
 805 };
 806 
 807 /*
 808  * Local variables:
 809  * tab-width: 4
 810  * c-basic-offset: 4
 811  * End:
 812  * vim600: noet sw=4 ts=4 fdm=marker
 813  * vim<600: noet sw=4 ts=4
 814  */

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