Annotation of embedaddon/php/ext/pdo_oci/oci_statement.c, revision 1.1.1.5

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.5 ! misho       5:   | Copyright (c) 1997-2014 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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:
1.1.1.3   misho     102:                                                OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
1.1       misho     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) {
1.1.1.4   misho     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: 
1.1       misho     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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>