Annotation of embedaddon/php/ext/pdo_oci/oci_driver.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 1997-2012 The PHP Group                                |
                      6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt                                  |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Author: Wez Furlong <wez@php.net>                                    |
                     16:   +----------------------------------------------------------------------+
                     17: */
                     18: 
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: 
                    230:        OCIHandleFree(H->err, OCI_HTYPE_ERROR);
                    231:        H->err = NULL;
                    232: 
                    233:        if (H->charset && H->env) {
                    234:                OCIHandleFree(H->env, OCI_HTYPE_ENV);
                    235:                H->env = NULL;
                    236:        }
                    237: 
                    238:        if (H->einfo.errmsg) {
                    239:                pefree(H->einfo.errmsg, dbh->is_persistent);
                    240:                H->einfo.errmsg = NULL;
                    241:        }
                    242: 
                    243:        pefree(H, dbh->is_persistent);
                    244: 
                    245:        return 0;
                    246: }
                    247: /* }}} */
                    248: 
                    249: static int oci_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) /* {{{ */
                    250: {
                    251:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    252:        pdo_oci_stmt *S = ecalloc(1, sizeof(*S));
                    253:        ub4 prefetch;
                    254:        char *nsql = NULL;
                    255:        int nsql_len = 0;
                    256:        int ret;
                    257: 
                    258: #if HAVE_OCISTMTFETCH2
                    259:        S->exec_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
                    260:                PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL ?
                    261:                OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
                    262: #else
                    263:        S->exec_type = OCI_DEFAULT;
                    264: #endif
                    265: 
                    266:        S->H = H;
                    267:        stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
                    268:        ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
                    269: 
                    270:        if (ret == 1) {
                    271:                /* query was re-written */
                    272:                sql = nsql;
                    273:                sql_len = nsql_len;
                    274:        } else if (ret == -1) {
                    275:                /* couldn't grok it */
                    276:                strcpy(dbh->error_code, stmt->error_code);
                    277:                efree(S);
                    278:                return 0;
                    279:        }
                    280: 
                    281:        /* create an OCI statement handle */
                    282:        OCIHandleAlloc(H->env, (dvoid*)&S->stmt, OCI_HTYPE_STMT, 0, NULL);
                    283: 
                    284:        /* and our own private error handle */
                    285:        OCIHandleAlloc(H->env, (dvoid*)&S->err, OCI_HTYPE_ERROR, 0, NULL);
                    286: 
                    287:        if (sql_len) {
                    288:                H->last_err = OCIStmtPrepare(S->stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
                    289:                if (nsql) {
                    290:                        efree(nsql);
                    291:                        nsql = NULL;
                    292:                }
                    293:                if (H->last_err) {
                    294:                        H->last_err = oci_drv_error("OCIStmtPrepare");
                    295:                        OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
                    296:                        OCIHandleFree(S->err, OCI_HTYPE_ERROR);
                    297:                        efree(S);
                    298:                        return 0;
                    299:                }
                    300: 
                    301:        }
                    302: 
                    303:        prefetch = pdo_oci_sanitize_prefetch(pdo_attr_lval(driver_options, PDO_ATTR_PREFETCH, PDO_OCI_PREFETCH_DEFAULT TSRMLS_CC));
                    304:        if (prefetch) {
                    305:                H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
                    306:                        OCI_ATTR_PREFETCH_ROWS, H->err);
                    307:                if (!H->last_err) {
                    308:                        prefetch *= PDO_OCI_PREFETCH_ROWSIZE;
                    309:                        H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
                    310:                                OCI_ATTR_PREFETCH_MEMORY, H->err);
                    311:                }
                    312:        }
                    313: 
                    314:        stmt->driver_data = S;
                    315:        stmt->methods = &oci_stmt_methods;
                    316:        if (nsql) {
                    317:                efree(nsql);
                    318:                nsql = NULL;
                    319:        }
                    320: 
                    321:        return 1;
                    322: }
                    323: /* }}} */
                    324: 
                    325: static long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
                    326: {
                    327:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    328:        OCIStmt         *stmt;
                    329:        ub2 stmt_type;
                    330:        ub4 rowcount;
                    331:        int ret = -1;
                    332: 
                    333:        OCIHandleAlloc(H->env, (dvoid*)&stmt, OCI_HTYPE_STMT, 0, NULL);
                    334: 
                    335:        H->last_err = OCIStmtPrepare(stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
                    336:        if (H->last_err) {
                    337:                H->last_err = oci_drv_error("OCIStmtPrepare");
                    338:                OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    339:                return -1;
                    340:        }
                    341: 
                    342:        H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, H->err);
                    343: 
                    344:        if (stmt_type == OCI_STMT_SELECT) {
                    345:                /* invalid usage; cancel it */
                    346:                OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    347:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "issuing a SELECT query here is invalid");
                    348:                return -1;
                    349:        }
                    350: 
                    351:        /* now we are good to go */
                    352:        H->last_err = OCIStmtExecute(H->svc, stmt, H->err, 1, 0, NULL, NULL,
                    353:                        (dbh->auto_commit && !dbh->in_txn) ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
                    354: 
                    355:        if (H->last_err) {
                    356:                H->last_err = oci_drv_error("OCIStmtExecute");
                    357:        } else {
                    358:                /* return the number of affected rows */
                    359:                H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, H->err);
                    360:                ret = rowcount;
                    361:        }
                    362: 
                    363:        OCIHandleFree(stmt, OCI_HTYPE_STMT);
                    364: 
                    365:        return ret;
                    366: }
                    367: /* }}} */
                    368: 
                    369: 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) /* {{{ */
                    370: {
                    371:        int qcount = 0;
                    372:        char const *cu, *l, *r;
                    373:        char *c;
                    374: 
                    375:        if (!unquotedlen) {
                    376:                *quotedlen = 2;
                    377:                *quoted = emalloc(*quotedlen+1);
                    378:                strcpy(*quoted, "''");
                    379:                return 1;
                    380:        }
                    381: 
                    382:        /* count single quotes */
                    383:        for (cu = unquoted; (cu = strchr(cu,'\'')); qcount++, cu++)
                    384:                ; /* empty loop */
                    385: 
                    386:        *quotedlen = unquotedlen + qcount + 2;
                    387:        *quoted = c = emalloc(*quotedlen+1);
                    388:        *c++ = '\'';
                    389:        
                    390:        /* foreach (chunk that ends in a quote) */
                    391:        for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {
                    392:                strncpy(c, l, r-l+1);
                    393:                c += (r-l+1);           
                    394:                *c++ = '\'';                    /* add second quote */
                    395:        }
                    396: 
                    397:     /* Copy remainder and add enclosing quote */       
                    398:        strncpy(c, l, *quotedlen-(c-*quoted)-1);
                    399:        (*quoted)[*quotedlen-1] = '\''; 
                    400:        (*quoted)[*quotedlen]   = '\0';
                    401:        
                    402:        return 1;
                    403: }
                    404: /* }}} */
                    405: 
                    406: static int oci_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    407: {
                    408:        /* with Oracle, there is nothing special to be done */
                    409:        return 1;
                    410: }
                    411: /* }}} */
                    412: 
                    413: static int oci_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    414: {
                    415:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    416: 
                    417:        H->last_err = OCITransCommit(H->svc, H->err, 0);
                    418: 
                    419:        if (H->last_err) {
                    420:                H->last_err = oci_drv_error("OCITransCommit");
                    421:                return 0;
                    422:        }
                    423:        return 1;
                    424: }
                    425: /* }}} */
                    426: 
                    427: static int oci_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    428: {
                    429:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    430: 
                    431:        H->last_err = OCITransRollback(H->svc, H->err, 0);
                    432: 
                    433:        if (H->last_err) {
                    434:                H->last_err = oci_drv_error("OCITransRollback");
                    435:                return 0;
                    436:        }
                    437:        return 1;
                    438: }
                    439: /* }}} */
                    440: 
                    441: static int oci_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
                    442: {
                    443:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    444: 
                    445:        if (attr == PDO_ATTR_AUTOCOMMIT) {
                    446:                if (dbh->in_txn) {
                    447:                        /* Assume they want to commit whatever is outstanding */
                    448:                        H->last_err = OCITransCommit(H->svc, H->err, 0);
                    449: 
                    450:                        if (H->last_err) {
                    451:                                H->last_err = oci_drv_error("OCITransCommit");
                    452:                                return 0;
                    453:                        }
                    454:                        dbh->in_txn = 0;
                    455:                }
                    456: 
                    457:                convert_to_long(val);
                    458: 
                    459:                dbh->auto_commit = Z_LVAL_P(val);
                    460:                return 1;
                    461:        } else {
                    462:                return 0;
                    463:        }
                    464:        
                    465: }
                    466: /* }}} */
                    467: 
                    468: static int oci_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)  /* {{{ */
                    469: {
                    470:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    471: 
                    472:        switch (attr) {
                    473:                case PDO_ATTR_SERVER_VERSION:
                    474:                case PDO_ATTR_SERVER_INFO:
                    475:                {
                    476:                        text infostr[512];
                    477:                        char verstr[15];
                    478:                        ub4  vernum;
                    479:                        
                    480:                        if (OCIServerRelease(H->svc, H->err, infostr, (ub4)sizeof(infostr), (ub1)OCI_HTYPE_SVCCTX, &vernum))
                    481:                        {
                    482:                                ZVAL_STRING(return_value, "<<Unknown>>", 1);
                    483:                        } else {
                    484:                                if (attr == PDO_ATTR_SERVER_INFO) {
                    485:                                        ZVAL_STRING(return_value, (char *)infostr, 1);
                    486:                                } else {
                    487:                                        slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", 
                    488:                                                         (int)((vernum>>24) & 0xFF),  /* version number */
                    489:                                                         (int)((vernum>>20) & 0x0F),  /* release number*/
                    490:                                                         (int)((vernum>>12) & 0xFF),  /* update number */
                    491:                                                         (int)((vernum>>8)  & 0x0F),  /* port release number */
                    492:                                                         (int)((vernum>>0)  & 0xFF)); /* port update number */
                    493:                                        
                    494:                                        ZVAL_STRING(return_value, verstr, 1);
                    495:                                }
                    496:                        }
                    497:                        return TRUE;
                    498:                }
                    499: 
                    500:                case PDO_ATTR_CLIENT_VERSION:
                    501:                {
                    502: #if OCI_MAJOR_VERSION > 10 || (OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION >= 2)
                    503:                        /* Run time client version */
                    504:                        sword major, minor, update, patch, port_update;
                    505:                        char verstr[15];
                    506: 
                    507:                        OCIClientVersion(&major, &minor, &update, &patch, &port_update);
                    508:                        slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", major, minor, update, patch, port_update);
                    509:                        ZVAL_STRING(return_value, verstr, 1);
                    510: #elif defined(PHP_PDO_OCI_CLIENT_VERSION)
                    511:                        /* Compile time client version */
                    512:                        ZVAL_STRING(return_value, PHP_PDO_OCI_CLIENT_VERSION, 1);
                    513: #else
                    514:                        return FALSE;
                    515: 
                    516: #endif /* Check for OCIClientVersion() support */
                    517: 
                    518:                        return TRUE;
                    519:                }
                    520: 
                    521:                case PDO_ATTR_AUTOCOMMIT:
                    522:                        ZVAL_BOOL(return_value, dbh->auto_commit);
                    523:                        return TRUE;
                    524: 
                    525:                default:
                    526:                        return FALSE;
                    527: 
                    528:        }
                    529:        return FALSE;
                    530: 
                    531: }
                    532: /* }}} */
                    533: 
                    534: static int pdo_oci_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    535: {
                    536:        pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
                    537:        sb4 error_code = 0;
                    538:        char version[256];
                    539: 
                    540:        /* TODO move attached check to PDO level */
                    541:        if (H->attached == 0) {
                    542:                return FAILURE;
                    543:        }
                    544:        /* TODO add persistent_timeout check at PDO level */
                    545: 
                    546: 
                    547:        /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
                    548:         * such as from Pre-10.1 servers, the error is still from the server and we would have
                    549:         * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
                    550:         * Pre-10.2 clients
                    551:         */     
                    552: #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))      /* OCIPing available 10.2 onwards */
                    553:        H->last_err = OCIPing (H->svc, H->err, OCI_DEFAULT);
                    554: #else
                    555:        /* use good old OCIServerVersion() */
                    556:        H->last_err = OCIServerVersion (H->svc, H->err, (text *)version, sizeof(version), OCI_HTYPE_SVCCTX);
                    557: #endif
1.1.1.2 ! misho     558:        if (H->last_err == OCI_SUCCESS) {
1.1       misho     559:                return SUCCESS;
                    560:        }
                    561: 
                    562:        OCIErrorGet (H->err, (ub4)1, NULL, &error_code, NULL, 0, OCI_HTYPE_ERROR);
1.1.1.2 ! misho     563:        
1.1       misho     564:        if (error_code == 1010) {
                    565:                return SUCCESS;
                    566:        }
                    567:        return FAILURE;
                    568: }
                    569: /* }}} */
                    570: 
                    571: static struct pdo_dbh_methods oci_methods = {
                    572:        oci_handle_closer,
                    573:        oci_handle_preparer,
                    574:        oci_handle_doer,
                    575:        oci_handle_quoter,
                    576:        oci_handle_begin,
                    577:        oci_handle_commit,
                    578:        oci_handle_rollback,
                    579:        oci_handle_set_attribute,
                    580:        NULL,
                    581:        pdo_oci_fetch_error_func,
                    582:        oci_handle_get_attribute,
                    583:        pdo_oci_check_liveness, /* check_liveness */
                    584:        NULL    /* get_driver_methods */
                    585: };
                    586: 
                    587: static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
                    588: {
                    589:        pdo_oci_db_handle *H;
                    590:        int i, ret = 0;
                    591:        struct pdo_data_src_parser vars[] = {
                    592:                { "charset",  NULL,     0 },
                    593:                { "dbname",   "",       0 }
                    594:        };
                    595: 
                    596:        php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 2);
                    597: 
                    598:        H = pecalloc(1, sizeof(*H), dbh->is_persistent);
                    599:        dbh->driver_data = H;
                    600: 
                    601:        /* allocate an environment */
                    602: #if HAVE_OCIENVNLSCREATE
                    603:        if (vars[0].optval) {
                    604:                H->charset = OCINlsCharSetNameToId(pdo_oci_Env, (const oratext *)vars[0].optval);
                    605:                if (!H->charset) {
                    606:                        oci_init_error("OCINlsCharSetNameToId: unknown character set name");
                    607:                        goto cleanup;
                    608:                } else {
                    609:                        if (OCIEnvNlsCreate(&H->env, PDO_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, H->charset, H->charset) != OCI_SUCCESS) {
                    610:                                oci_init_error("OCIEnvNlsCreate: Check the character set is valid and that PHP has access to Oracle libraries and NLS data");
                    611:                                goto cleanup;
                    612:                        }
                    613:                }
                    614:        }
                    615: #endif
                    616:        if (H->env == NULL) {
                    617:                /* use the global environment */
                    618:                H->env = pdo_oci_Env;
                    619:        }
                    620: 
                    621:        /* something to hold errors */
                    622:        OCIHandleAlloc(H->env, (dvoid **)&H->err, OCI_HTYPE_ERROR, 0, NULL);
                    623: 
                    624:        /* handle for the server */
                    625:        OCIHandleAlloc(H->env, (dvoid **)&H->server, OCI_HTYPE_SERVER, 0, NULL);
                    626: 
                    627:        H->last_err = OCIServerAttach(H->server, H->err, (text*)vars[1].optval,
                    628:                        strlen(vars[1].optval), OCI_DEFAULT);
                    629: 
                    630:        if (H->last_err) {
                    631:                oci_drv_error("pdo_oci_handle_factory");
                    632:                goto cleanup;
                    633:        }
                    634: 
                    635:        H->attached = 1;
                    636: 
                    637:        /* create a service context */
                    638:        H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->svc, OCI_HTYPE_SVCCTX, 0, NULL);
                    639:        if (H->last_err) {
                    640:                oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SVCCTX");
                    641:                goto cleanup;
                    642:        }
                    643: 
                    644:        H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->session, OCI_HTYPE_SESSION, 0, NULL);
                    645:        if (H->last_err) {
                    646:                oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SESSION");
                    647:                goto cleanup;
                    648:        }
                    649: 
                    650:        /* set server handle into service handle */
                    651:        H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->server, 0, OCI_ATTR_SERVER, H->err);
                    652:        if (H->last_err) {
                    653:                oci_drv_error("OCIAttrSet: OCI_ATTR_SERVER");
                    654:                goto cleanup;
                    655:        }
                    656: 
                    657:        /* username */
                    658:        if (dbh->username) {
                    659:                H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
                    660:                                dbh->username, strlen(dbh->username),
                    661:                                OCI_ATTR_USERNAME, H->err);
                    662:                if (H->last_err) {
                    663:                        oci_drv_error("OCIAttrSet: OCI_ATTR_USERNAME");
                    664:                        goto cleanup;
                    665:                }
                    666:        }
                    667: 
                    668:        /* password */
                    669:        if (dbh->password) {
                    670:                H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
                    671:                                dbh->password, strlen(dbh->password),
                    672:                                OCI_ATTR_PASSWORD, H->err);
                    673:                if (H->last_err) {
                    674:                        oci_drv_error("OCIAttrSet: OCI_ATTR_PASSWORD");
                    675:                        goto cleanup;
                    676:                }
                    677:        }
                    678: 
                    679:        /* Now fire up the session */
                    680:        H->last_err = OCISessionBegin(H->svc, H->err, H->session, OCI_CRED_RDBMS, OCI_DEFAULT);
                    681:        if (H->last_err) {
                    682:                oci_drv_error("OCISessionBegin");
                    683:                goto cleanup;
                    684:        }
                    685: 
                    686:        /* set the server handle into service handle */
                    687:        H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->session, 0, OCI_ATTR_SESSION, H->err);
                    688:        if (H->last_err) {
                    689:                oci_drv_error("OCIAttrSet: OCI_ATTR_SESSION");
                    690:                goto cleanup;
                    691:        }
                    692: 
                    693:        dbh->methods = &oci_methods;
                    694:        dbh->alloc_own_columns = 1;
                    695:        dbh->native_case = PDO_CASE_UPPER;
                    696: 
                    697:        ret = 1;
                    698: 
                    699: cleanup:
                    700:        for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
                    701:                if (vars[i].freeme) {
                    702:                        efree(vars[i].optval);
                    703:                }
                    704:        }
                    705: 
                    706:        if (!ret) {
                    707:                oci_handle_closer(dbh TSRMLS_CC);
                    708:        }
                    709: 
                    710:        return ret;
                    711: }
                    712: /* }}} */
                    713: 
                    714: pdo_driver_t pdo_oci_driver = {
                    715:        PDO_DRIVER_HEADER(oci),
                    716:        pdo_oci_handle_factory
                    717: };
                    718: 
                    719: static inline ub4 pdo_oci_sanitize_prefetch(long prefetch) /* {{{ */
                    720: {
                    721:        if (prefetch < 0) {
                    722:                prefetch = 0;
                    723:        } else if (prefetch > UB4MAXVAL / PDO_OCI_PREFETCH_ROWSIZE) {
                    724:                prefetch = PDO_OCI_PREFETCH_DEFAULT;
                    725:        }
                    726:        return ((ub4)prefetch);
                    727: }
                    728: /* }}} */
                    729: 
                    730: 
                    731: /*
                    732:  * Local variables:
                    733:  * tab-width: 4
                    734:  * c-basic-offset: 4
                    735:  * End:
                    736:  * vim600: noet sw=4 ts=4 fdm=marker
                    737:  * vim<600: noet sw=4 ts=4
                    738:  */

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