Annotation of embedaddon/php/ext/pdo_oci/oci_driver.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_exceptions.h"
                     33: 
                     34: static inline ub4 pdo_oci_sanitize_prefetch(long prefetch);
                     35: 
                     36: static int pdo_oci_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
                     37: {
                     38:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                     39:        pdo_oci_error_info *einfo;
                     40: 
                     41:        einfo = &H->einfo;
                     42: 
                     43:        if (stmt) {
                     44:                pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
                     45: 
                     46:                if (S->einfo.errmsg) {
                     47:                        einfo = &S->einfo;
                     48:                }
                     49:        }
                     50: 
                     51:        if (einfo->errcode) {
                     52:                add_next_index_long(info, einfo->errcode);
                     53:                add_next_index_string(info, einfo->errmsg, 1);
                     54:        }
                     55: 
                     56:        return 1;
                     57: }
                     58: /* }}} */
                     59: 
                     60: ub4 _oci_error(OCIError *err, pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *what, sword status, int isinit, const char *file, int line TSRMLS_DC) /* {{{ */
                     61: {
                     62:        text errbuf[1024] = "<<Unknown>>";
                     63:        char tmp_buf[2048];
                     64:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                     65:        pdo_oci_error_info *einfo;
                     66:        pdo_oci_stmt *S = NULL;
                     67:        pdo_error_type *pdo_err = &dbh->error_code;
                     68: 
                     69:        if (stmt) {
                     70:                S = (pdo_oci_stmt*)stmt->driver_data;
                     71:                einfo = &S->einfo;
                     72:                pdo_err = &stmt->error_code;
                     73:        }
                     74:        else {
                     75:                einfo = &H->einfo;
                     76:        }
                     77: 
                     78:        if (einfo->errmsg) {
                     79:                pefree(einfo->errmsg, dbh->is_persistent);
                     80:        }
                     81: 
                     82:        einfo->errmsg = NULL;
                     83:        einfo->errcode = 0;
                     84:        einfo->file = file;
                     85:        einfo->line = line;
                     86: 
                     87:        if (isinit) { /* Initialization error */
                     88:                strcpy(*pdo_err, "HY000");
                     89:                slprintf(tmp_buf, sizeof(tmp_buf), "%s (%s:%d)", what, file, line);
                     90:                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                     91:        }
                     92:        else {
                     93:                switch (status) {
                     94:                        case OCI_SUCCESS:
                     95:                                strcpy(*pdo_err, "00000");
                     96:                                break;
                     97:                        case OCI_ERROR:
                     98:                                OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
                     99:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: %s (%s:%d)", what, errbuf, file, line);
                    100:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    101:                                break;
                    102:                        case OCI_SUCCESS_WITH_INFO:
                    103:                                OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
                    104:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_SUCCESS_WITH_INFO: %s (%s:%d)", what, errbuf, file, line);
                    105:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    106:                                break;
                    107:                        case OCI_NEED_DATA:
                    108:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NEED_DATA (%s:%d)", what, file, line);
                    109:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    110:                                break;
                    111:                        case OCI_NO_DATA:
                    112:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NO_DATA (%s:%d)", what, file, line);
                    113:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    114:                                break;
                    115:                        case OCI_INVALID_HANDLE:
                    116:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_INVALID_HANDLE (%s:%d)", what, file, line);
                    117:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    118:                                break;
                    119:                        case OCI_STILL_EXECUTING:
                    120:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_STILL_EXECUTING (%s:%d)", what, file, line);
                    121:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    122:                                break;
                    123:                        case OCI_CONTINUE:
                    124:                                slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_CONTINUE (%s:%d)", what, file, line);
                    125:                                einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
                    126:                                break;
                    127:                }
                    128: 
                    129:                if (einfo->errcode) {
                    130:                        switch (einfo->errcode) {
                    131:                                case 1013:      /* user requested cancel of current operation */
                    132:                                        zend_bailout();
                    133:                                        break;
                    134: 
                    135: #if 0
                    136:                                case 955:       /* ORA-00955: name is already used by an existing object */
                    137:                                        *pdo_err = PDO_ERR_ALREADY_EXISTS;
                    138:                                        break;
                    139: #endif
                    140: 
                    141:                                case 12154:     /* ORA-12154: TNS:could not resolve service name */
                    142:                                        strcpy(*pdo_err, "42S02");
                    143:                                        break;
                    144:                                
                    145:                                case    22:     /* ORA-00022: invalid session id */
                    146:                                case   378:
                    147:                                case   602:
                    148:                                case   603:
                    149:                                case   604:
                    150:                                case   609:
                    151:                                case  1012:     /* ORA-01012: */
                    152:                                case  1033:
                    153:                                case  1041:
                    154:                                case  1043:
                    155:                                case  1089:
                    156:                                case  1090:
                    157:                                case  1092:
                    158:                                case  3113:     /* ORA-03133: end of file on communication channel */
                    159:                                case  3114:
                    160:                                case  3122:
                    161:                                case  3135:
                    162:                                case 12153:
                    163:                                case 27146:
                    164:                                case 28511:
                    165:                                        /* consider the connection closed */
                    166:                                        dbh->is_closed = 1;
                    167:                                        H->attached = 0;
                    168:                                        strcpy(*pdo_err, "01002"); /* FIXME */
                    169:                                        break;
                    170: 
                    171:                                default:
                    172:                                        strcpy(*pdo_err, "HY000");
                    173:                        }
                    174:                }
                    175: 
                    176:                if (stmt) {
                    177:                        /* always propogate the error code back up to the dbh,
                    178:                         * so that we can catch the error information when execute
                    179:                         * is called via query.  See Bug #33707 */
                    180:                        if (H->einfo.errmsg) {
                    181:                                pefree(H->einfo.errmsg, dbh->is_persistent);
                    182:                        }
                    183:                        H->einfo = *einfo;
                    184:                        H->einfo.errmsg = einfo->errmsg ? pestrdup(einfo->errmsg, dbh->is_persistent) : NULL;
                    185:                        strcpy(dbh->error_code, stmt->error_code);
                    186:                }
                    187:        }
                    188: 
                    189:        /* little mini hack so that we can use this code from the dbh ctor */
                    190:        if (!dbh->methods) {
                    191:                zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s]: %s", *pdo_err, einfo->errmsg);
                    192:        }
                    193: 
                    194:        return einfo->errcode;
                    195: }
                    196: /* }}} */
                    197: 
                    198: static int oci_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    199: {
                    200:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    201: 
                    202:        if (H->svc) {
                    203:                /* rollback any outstanding work */
                    204:                OCITransRollback(H->svc, H->err, 0);
                    205:        }
                    206: 
                    207:        if (H->session) {
                    208:                OCIHandleFree(H->session, OCI_HTYPE_SESSION);
                    209:                H->session = NULL;
                    210:        }
                    211: 
                    212:        if (H->svc) {
                    213:                OCIHandleFree(H->svc, OCI_HTYPE_SVCCTX);
                    214:                H->svc = NULL;
                    215:        }
                    216: 
                    217:        if (H->server && H->attached) {
                    218:                H->last_err = OCIServerDetach(H->server, H->err, OCI_DEFAULT);
                    219:                if (H->last_err) {
                    220:                        oci_drv_error("OCIServerDetach");
                    221:                }
                    222:                H->attached = 0;
                    223:        }
                    224: 
                    225:        if (H->server) {
                    226:                OCIHandleFree(H->server, OCI_HTYPE_SERVER);
                    227:                H->server = NULL;
                    228:        }
                    229: 
1.1.1.3   misho     230:        if (H->err) {
                    231:                OCIHandleFree(H->err, OCI_HTYPE_ERROR);
                    232:                H->err = NULL;
                    233:        }
1.1       misho     234: 
                    235:        if (H->charset && H->env) {
                    236:                OCIHandleFree(H->env, OCI_HTYPE_ENV);
                    237:                H->env = NULL;
                    238:        }
                    239: 
                    240:        if (H->einfo.errmsg) {
                    241:                pefree(H->einfo.errmsg, dbh->is_persistent);
                    242:                H->einfo.errmsg = NULL;
                    243:        }
                    244: 
                    245:        pefree(H, dbh->is_persistent);
                    246: 
                    247:        return 0;
                    248: }
                    249: /* }}} */
                    250: 
                    251: static int oci_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) /* {{{ */
                    252: {
                    253:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    254:        pdo_oci_stmt *S = ecalloc(1, sizeof(*S));
                    255:        ub4 prefetch;
                    256:        char *nsql = NULL;
                    257:        int nsql_len = 0;
                    258:        int ret;
                    259: 
                    260: #if HAVE_OCISTMTFETCH2
                    261:        S->exec_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
                    262:                PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL ?
                    263:                OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
                    264: #else
                    265:        S->exec_type = OCI_DEFAULT;
                    266: #endif
                    267: 
                    268:        S->H = H;
                    269:        stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
                    270:        ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
                    271: 
                    272:        if (ret == 1) {
                    273:                /* query was re-written */
                    274:                sql = nsql;
                    275:                sql_len = nsql_len;
                    276:        } else if (ret == -1) {
                    277:                /* couldn't grok it */
                    278:                strcpy(dbh->error_code, stmt->error_code);
                    279:                efree(S);
                    280:                return 0;
                    281:        }
                    282: 
                    283:        /* create an OCI statement handle */
                    284:        OCIHandleAlloc(H->env, (dvoid*)&S->stmt, OCI_HTYPE_STMT, 0, NULL);
                    285: 
                    286:        /* and our own private error handle */
                    287:        OCIHandleAlloc(H->env, (dvoid*)&S->err, OCI_HTYPE_ERROR, 0, NULL);
                    288: 
                    289:        if (sql_len) {
                    290:                H->last_err = OCIStmtPrepare(S->stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
                    291:                if (nsql) {
                    292:                        efree(nsql);
                    293:                        nsql = NULL;
                    294:                }
                    295:                if (H->last_err) {
                    296:                        H->last_err = oci_drv_error("OCIStmtPrepare");
                    297:                        OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
                    298:                        OCIHandleFree(S->err, OCI_HTYPE_ERROR);
                    299:                        efree(S);
                    300:                        return 0;
                    301:                }
                    302: 
                    303:        }
                    304: 
                    305:        prefetch = pdo_oci_sanitize_prefetch(pdo_attr_lval(driver_options, PDO_ATTR_PREFETCH, PDO_OCI_PREFETCH_DEFAULT TSRMLS_CC));
                    306:        if (prefetch) {
                    307:                H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
                    308:                        OCI_ATTR_PREFETCH_ROWS, H->err);
                    309:                if (!H->last_err) {
                    310:                        prefetch *= PDO_OCI_PREFETCH_ROWSIZE;
                    311:                        H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
                    312:                                OCI_ATTR_PREFETCH_MEMORY, H->err);
                    313:                }
                    314:        }
                    315: 
                    316:        stmt->driver_data = S;
                    317:        stmt->methods = &oci_stmt_methods;
                    318:        if (nsql) {
                    319:                efree(nsql);
                    320:                nsql = NULL;
                    321:        }
                    322: 
                    323:        return 1;
                    324: }
                    325: /* }}} */
                    326: 
                    327: static long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
                    328: {
                    329:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    330:        OCIStmt         *stmt;
                    331:        ub2 stmt_type;
                    332:        ub4 rowcount;
                    333:        int ret = -1;
                    334: 
                    335:        OCIHandleAlloc(H->env, (dvoid*)&stmt, OCI_HTYPE_STMT, 0, NULL);
                    336: 
                    337:        H->last_err = OCIStmtPrepare(stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
                    338:        if (H->last_err) {
                    339:                H->last_err = oci_drv_error("OCIStmtPrepare");
                    340:                OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    341:                return -1;
                    342:        }
                    343: 
                    344:        H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, H->err);
                    345: 
                    346:        if (stmt_type == OCI_STMT_SELECT) {
                    347:                /* invalid usage; cancel it */
                    348:                OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    349:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "issuing a SELECT query here is invalid");
                    350:                return -1;
                    351:        }
                    352: 
                    353:        /* now we are good to go */
                    354:        H->last_err = OCIStmtExecute(H->svc, stmt, H->err, 1, 0, NULL, NULL,
                    355:                        (dbh->auto_commit && !dbh->in_txn) ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
                    356: 
                    357:        if (H->last_err) {
                    358:                H->last_err = oci_drv_error("OCIStmtExecute");
                    359:        } else {
                    360:                /* return the number of affected rows */
                    361:                H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, H->err);
                    362:                ret = rowcount;
                    363:        }
                    364: 
                    365:        OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    366: 
                    367:        return ret;
                    368: }
                    369: /* }}} */
                    370: 
                    371: static int oci_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype  TSRMLS_DC) /* {{{ */
                    372: {
                    373:        int qcount = 0;
                    374:        char const *cu, *l, *r;
                    375:        char *c;
                    376: 
                    377:        if (!unquotedlen) {
                    378:                *quotedlen = 2;
                    379:                *quoted = emalloc(*quotedlen+1);
                    380:                strcpy(*quoted, "''");
                    381:                return 1;
                    382:        }
                    383: 
                    384:        /* count single quotes */
                    385:        for (cu = unquoted; (cu = strchr(cu,'\'')); qcount++, cu++)
                    386:                ; /* empty loop */
                    387: 
                    388:        *quotedlen = unquotedlen + qcount + 2;
                    389:        *quoted = c = emalloc(*quotedlen+1);
                    390:        *c++ = '\'';
                    391:        
                    392:        /* foreach (chunk that ends in a quote) */
                    393:        for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {
                    394:                strncpy(c, l, r-l+1);
                    395:                c += (r-l+1);           
                    396:                *c++ = '\'';                    /* add second quote */
                    397:        }
                    398: 
                    399:     /* Copy remainder and add enclosing quote */       
                    400:        strncpy(c, l, *quotedlen-(c-*quoted)-1);
                    401:        (*quoted)[*quotedlen-1] = '\''; 
                    402:        (*quoted)[*quotedlen]   = '\0';
                    403:        
                    404:        return 1;
                    405: }
                    406: /* }}} */
                    407: 
                    408: static int oci_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    409: {
                    410:        /* with Oracle, there is nothing special to be done */
                    411:        return 1;
                    412: }
                    413: /* }}} */
                    414: 
                    415: static int oci_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    416: {
                    417:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    418: 
                    419:        H->last_err = OCITransCommit(H->svc, H->err, 0);
                    420: 
                    421:        if (H->last_err) {
                    422:                H->last_err = oci_drv_error("OCITransCommit");
                    423:                return 0;
                    424:        }
                    425:        return 1;
                    426: }
                    427: /* }}} */
                    428: 
                    429: static int oci_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    430: {
                    431:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    432: 
                    433:        H->last_err = OCITransRollback(H->svc, H->err, 0);
                    434: 
                    435:        if (H->last_err) {
                    436:                H->last_err = oci_drv_error("OCITransRollback");
                    437:                return 0;
                    438:        }
                    439:        return 1;
                    440: }
                    441: /* }}} */
                    442: 
                    443: static int oci_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
                    444: {
                    445:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    446: 
                    447:        if (attr == PDO_ATTR_AUTOCOMMIT) {
                    448:                if (dbh->in_txn) {
                    449:                        /* Assume they want to commit whatever is outstanding */
                    450:                        H->last_err = OCITransCommit(H->svc, H->err, 0);
                    451: 
                    452:                        if (H->last_err) {
                    453:                                H->last_err = oci_drv_error("OCITransCommit");
                    454:                                return 0;
                    455:                        }
                    456:                        dbh->in_txn = 0;
                    457:                }
                    458: 
                    459:                convert_to_long(val);
                    460: 
                    461:                dbh->auto_commit = Z_LVAL_P(val);
                    462:                return 1;
                    463:        } else {
                    464:                return 0;
                    465:        }
                    466:        
                    467: }
                    468: /* }}} */
                    469: 
                    470: static int oci_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)  /* {{{ */
                    471: {
                    472:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    473: 
                    474:        switch (attr) {
                    475:                case PDO_ATTR_SERVER_VERSION:
                    476:                case PDO_ATTR_SERVER_INFO:
                    477:                {
                    478:                        text infostr[512];
                    479:                        char verstr[15];
                    480:                        ub4  vernum;
                    481:                        
                    482:                        if (OCIServerRelease(H->svc, H->err, infostr, (ub4)sizeof(infostr), (ub1)OCI_HTYPE_SVCCTX, &vernum))
                    483:                        {
                    484:                                ZVAL_STRING(return_value, "<<Unknown>>", 1);
                    485:                        } else {
                    486:                                if (attr == PDO_ATTR_SERVER_INFO) {
                    487:                                        ZVAL_STRING(return_value, (char *)infostr, 1);
                    488:                                } else {
                    489:                                        slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", 
                    490:                                                         (int)((vernum>>24) & 0xFF),  /* version number */
                    491:                                                         (int)((vernum>>20) & 0x0F),  /* release number*/
                    492:                                                         (int)((vernum>>12) & 0xFF),  /* update number */
                    493:                                                         (int)((vernum>>8)  & 0x0F),  /* port release number */
                    494:                                                         (int)((vernum>>0)  & 0xFF)); /* port update number */
                    495:                                        
                    496:                                        ZVAL_STRING(return_value, verstr, 1);
                    497:                                }
                    498:                        }
                    499:                        return TRUE;
                    500:                }
                    501: 
                    502:                case PDO_ATTR_CLIENT_VERSION:
                    503:                {
                    504: #if OCI_MAJOR_VERSION > 10 || (OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION >= 2)
                    505:                        /* Run time client version */
                    506:                        sword major, minor, update, patch, port_update;
                    507:                        char verstr[15];
                    508: 
                    509:                        OCIClientVersion(&major, &minor, &update, &patch, &port_update);
                    510:                        slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", major, minor, update, patch, port_update);
                    511:                        ZVAL_STRING(return_value, verstr, 1);
                    512: #elif defined(PHP_PDO_OCI_CLIENT_VERSION)
                    513:                        /* Compile time client version */
                    514:                        ZVAL_STRING(return_value, PHP_PDO_OCI_CLIENT_VERSION, 1);
                    515: #else
                    516:                        return FALSE;
                    517: 
                    518: #endif /* Check for OCIClientVersion() support */
                    519: 
                    520:                        return TRUE;
                    521:                }
                    522: 
                    523:                case PDO_ATTR_AUTOCOMMIT:
                    524:                        ZVAL_BOOL(return_value, dbh->auto_commit);
                    525:                        return TRUE;
                    526: 
                    527:                default:
                    528:                        return FALSE;
                    529: 
                    530:        }
                    531:        return FALSE;
                    532: 
                    533: }
                    534: /* }}} */
                    535: 
                    536: static int pdo_oci_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    537: {
                    538:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    539:        sb4 error_code = 0;
1.1.1.4   misho     540: #if (!((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))))
1.1       misho     541:        char version[256];
1.1.1.4   misho     542: #endif
1.1       misho     543: 
                    544:        /* TODO move attached check to PDO level */
                    545:        if (H->attached == 0) {
                    546:                return FAILURE;
                    547:        }
                    548:        /* TODO add persistent_timeout check at PDO level */
                    549: 
                    550: 
                    551:        /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
                    552:         * such as from Pre-10.1 servers, the error is still from the server and we would have
                    553:         * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
                    554:         * Pre-10.2 clients
                    555:         */     
                    556: #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))      /* OCIPing available 10.2 onwards */
                    557:        H->last_err = OCIPing (H->svc, H->err, OCI_DEFAULT);
                    558: #else
                    559:        /* use good old OCIServerVersion() */
                    560:        H->last_err = OCIServerVersion (H->svc, H->err, (text *)version, sizeof(version), OCI_HTYPE_SVCCTX);
                    561: #endif
1.1.1.2   misho     562:        if (H->last_err == OCI_SUCCESS) {
1.1       misho     563:                return SUCCESS;
                    564:        }
                    565: 
                    566:        OCIErrorGet (H->err, (ub4)1, NULL, &error_code, NULL, 0, OCI_HTYPE_ERROR);
1.1.1.2   misho     567:        
1.1       misho     568:        if (error_code == 1010) {
                    569:                return SUCCESS;
                    570:        }
                    571:        return FAILURE;
                    572: }
                    573: /* }}} */
                    574: 
                    575: static struct pdo_dbh_methods oci_methods = {
                    576:        oci_handle_closer,
                    577:        oci_handle_preparer,
                    578:        oci_handle_doer,
                    579:        oci_handle_quoter,
                    580:        oci_handle_begin,
                    581:        oci_handle_commit,
                    582:        oci_handle_rollback,
                    583:        oci_handle_set_attribute,
                    584:        NULL,
                    585:        pdo_oci_fetch_error_func,
                    586:        oci_handle_get_attribute,
                    587:        pdo_oci_check_liveness, /* check_liveness */
                    588:        NULL    /* get_driver_methods */
                    589: };
                    590: 
                    591: static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
                    592: {
                    593:        pdo_oci_db_handle *H;
                    594:        int i, ret = 0;
                    595:        struct pdo_data_src_parser vars[] = {
                    596:                { "charset",  NULL,     0 },
                    597:                { "dbname",   "",       0 }
                    598:        };
                    599: 
                    600:        php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 2);
                    601: 
                    602:        H = pecalloc(1, sizeof(*H), dbh->is_persistent);
                    603:        dbh->driver_data = H;
                    604: 
                    605:        /* allocate an environment */
                    606: #if HAVE_OCIENVNLSCREATE
                    607:        if (vars[0].optval) {
                    608:                H->charset = OCINlsCharSetNameToId(pdo_oci_Env, (const oratext *)vars[0].optval);
                    609:                if (!H->charset) {
                    610:                        oci_init_error("OCINlsCharSetNameToId: unknown character set name");
                    611:                        goto cleanup;
                    612:                } else {
                    613:                        if (OCIEnvNlsCreate(&H->env, PDO_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, H->charset, H->charset) != OCI_SUCCESS) {
                    614:                                oci_init_error("OCIEnvNlsCreate: Check the character set is valid and that PHP has access to Oracle libraries and NLS data");
                    615:                                goto cleanup;
                    616:                        }
                    617:                }
                    618:        }
                    619: #endif
                    620:        if (H->env == NULL) {
                    621:                /* use the global environment */
                    622:                H->env = pdo_oci_Env;
                    623:        }
                    624: 
                    625:        /* something to hold errors */
                    626:        OCIHandleAlloc(H->env, (dvoid **)&H->err, OCI_HTYPE_ERROR, 0, NULL);
                    627: 
                    628:        /* handle for the server */
                    629:        OCIHandleAlloc(H->env, (dvoid **)&H->server, OCI_HTYPE_SERVER, 0, NULL);
                    630: 
                    631:        H->last_err = OCIServerAttach(H->server, H->err, (text*)vars[1].optval,
                    632:                        strlen(vars[1].optval), OCI_DEFAULT);
                    633: 
                    634:        if (H->last_err) {
                    635:                oci_drv_error("pdo_oci_handle_factory");
                    636:                goto cleanup;
                    637:        }
                    638: 
                    639:        H->attached = 1;
                    640: 
                    641:        /* create a service context */
                    642:        H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->svc, OCI_HTYPE_SVCCTX, 0, NULL);
                    643:        if (H->last_err) {
                    644:                oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SVCCTX");
                    645:                goto cleanup;
                    646:        }
                    647: 
                    648:        H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->session, OCI_HTYPE_SESSION, 0, NULL);
                    649:        if (H->last_err) {
                    650:                oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SESSION");
                    651:                goto cleanup;
                    652:        }
                    653: 
                    654:        /* set server handle into service handle */
                    655:        H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->server, 0, OCI_ATTR_SERVER, H->err);
                    656:        if (H->last_err) {
                    657:                oci_drv_error("OCIAttrSet: OCI_ATTR_SERVER");
                    658:                goto cleanup;
                    659:        }
                    660: 
                    661:        /* username */
                    662:        if (dbh->username) {
                    663:                H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
                    664:                                dbh->username, strlen(dbh->username),
                    665:                                OCI_ATTR_USERNAME, H->err);
                    666:                if (H->last_err) {
                    667:                        oci_drv_error("OCIAttrSet: OCI_ATTR_USERNAME");
                    668:                        goto cleanup;
                    669:                }
                    670:        }
                    671: 
                    672:        /* password */
                    673:        if (dbh->password) {
                    674:                H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
                    675:                                dbh->password, strlen(dbh->password),
                    676:                                OCI_ATTR_PASSWORD, H->err);
                    677:                if (H->last_err) {
                    678:                        oci_drv_error("OCIAttrSet: OCI_ATTR_PASSWORD");
                    679:                        goto cleanup;
                    680:                }
                    681:        }
                    682: 
                    683:        /* Now fire up the session */
                    684:        H->last_err = OCISessionBegin(H->svc, H->err, H->session, OCI_CRED_RDBMS, OCI_DEFAULT);
                    685:        if (H->last_err) {
                    686:                oci_drv_error("OCISessionBegin");
                    687:                goto cleanup;
                    688:        }
                    689: 
                    690:        /* set the server handle into service handle */
                    691:        H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->session, 0, OCI_ATTR_SESSION, H->err);
                    692:        if (H->last_err) {
                    693:                oci_drv_error("OCIAttrSet: OCI_ATTR_SESSION");
                    694:                goto cleanup;
                    695:        }
                    696: 
                    697:        dbh->methods = &oci_methods;
                    698:        dbh->alloc_own_columns = 1;
                    699:        dbh->native_case = PDO_CASE_UPPER;
                    700: 
                    701:        ret = 1;
                    702: 
                    703: cleanup:
                    704:        for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
                    705:                if (vars[i].freeme) {
                    706:                        efree(vars[i].optval);
                    707:                }
                    708:        }
                    709: 
                    710:        if (!ret) {
                    711:                oci_handle_closer(dbh TSRMLS_CC);
                    712:        }
                    713: 
                    714:        return ret;
                    715: }
                    716: /* }}} */
                    717: 
                    718: pdo_driver_t pdo_oci_driver = {
                    719:        PDO_DRIVER_HEADER(oci),
                    720:        pdo_oci_handle_factory
                    721: };
                    722: 
                    723: static inline ub4 pdo_oci_sanitize_prefetch(long prefetch) /* {{{ */
                    724: {
                    725:        if (prefetch < 0) {
                    726:                prefetch = 0;
                    727:        } else if (prefetch > UB4MAXVAL / PDO_OCI_PREFETCH_ROWSIZE) {
                    728:                prefetch = PDO_OCI_PREFETCH_DEFAULT;
                    729:        }
                    730:        return ((ub4)prefetch);
                    731: }
                    732: /* }}} */
                    733: 
                    734: 
                    735: /*
                    736:  * Local variables:
                    737:  * tab-width: 4
                    738:  * c-basic-offset: 4
                    739:  * End:
                    740:  * vim600: noet sw=4 ts=4 fdm=marker
                    741:  * vim<600: noet sw=4 ts=4
                    742:  */

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