Annotation of embedaddon/php/ext/pdo_odbc/odbc_stmt.c, revision 1.1

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.0 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_0.txt.                                  |
        !            11:   | If you did not receive a copy of the PHP license and are unable to   |
        !            12:   | obtain it through the world-wide-web, please send a note to          |
        !            13:   | license@php.net so we can mail you a copy immediately.               |
        !            14:   +----------------------------------------------------------------------+
        !            15:   | Author: Wez Furlong <wez@php.net>                                    |
        !            16:   +----------------------------------------------------------------------+
        !            17: */
        !            18: 
        !            19: /* $Id: odbc_stmt.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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_odbc.h"
        !            31: #include "php_pdo_odbc_int.h"
        !            32: 
        !            33: enum pdo_odbc_conv_result {
        !            34:        PDO_ODBC_CONV_NOT_REQUIRED,
        !            35:        PDO_ODBC_CONV_OK,
        !            36:        PDO_ODBC_CONV_FAIL
        !            37: };
        !            38: 
        !            39: static int pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt *S, SWORD sqltype)
        !            40: {
        !            41:        if (!S->assume_utf8) return 0;
        !            42:        switch (sqltype) {
        !            43: #ifdef SQL_WCHAR
        !            44:                case SQL_WCHAR:
        !            45:                        return 1;
        !            46: #endif
        !            47: #ifdef SQL_WLONGVARCHAR
        !            48:                case SQL_WLONGVARCHAR:
        !            49:                        return 1;
        !            50: #endif
        !            51: #ifdef SQL_WVARCHAR
        !            52:                case SQL_WVARCHAR:
        !            53:                        return 1;
        !            54: #endif
        !            55:                default:
        !            56:                        return 0;
        !            57:        }
        !            58: }
        !            59: 
        !            60: static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf, 
        !            61:        unsigned long buflen, unsigned long *outlen)
        !            62: {
        !            63: #ifdef PHP_WIN32
        !            64:        if (is_unicode && buflen) {
        !            65:                pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !            66:                DWORD ret;
        !            67: 
        !            68:                ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, NULL, 0);
        !            69:                if (ret == 0) {
        !            70:                        /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
        !            71:                        return PDO_ODBC_CONV_FAIL;
        !            72:                }
        !            73: 
        !            74:                ret *= sizeof(WCHAR);
        !            75: 
        !            76:                if (S->convbufsize <= ret) {
        !            77:                        S->convbufsize = ret + sizeof(WCHAR);
        !            78:                        S->convbuf = erealloc(S->convbuf, S->convbufsize);
        !            79:                }
        !            80:                
        !            81:                ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, (LPWSTR)S->convbuf, S->convbufsize / sizeof(WCHAR));
        !            82:                if (ret == 0) {
        !            83:                        /*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
        !            84:                        return PDO_ODBC_CONV_FAIL;
        !            85:                }
        !            86: 
        !            87:                ret *= sizeof(WCHAR);
        !            88:                *outlen = ret;
        !            89:                return PDO_ODBC_CONV_OK;
        !            90:        }
        !            91: #endif
        !            92:        return PDO_ODBC_CONV_NOT_REQUIRED;
        !            93: }
        !            94: 
        !            95: static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf, 
        !            96:        unsigned long buflen, unsigned long *outlen)
        !            97: {
        !            98: #ifdef PHP_WIN32
        !            99:        if (is_unicode && buflen) {
        !           100:                pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           101:                DWORD ret;
        !           102: 
        !           103:                ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL);
        !           104:                if (ret == 0) {
        !           105:                        return PDO_ODBC_CONV_FAIL;
        !           106:                }
        !           107: 
        !           108:                if (S->convbufsize <= ret) {
        !           109:                        S->convbufsize = ret + 1;
        !           110:                        S->convbuf = erealloc(S->convbuf, S->convbufsize);
        !           111:                }
        !           112:                
        !           113:                ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL);
        !           114:                if (ret == 0) {
        !           115:                        return PDO_ODBC_CONV_FAIL;
        !           116:                }
        !           117: 
        !           118:                *outlen = ret;
        !           119:                S->convbuf[*outlen] = '\0';
        !           120:                return PDO_ODBC_CONV_OK;
        !           121:        }
        !           122: #endif
        !           123:        return PDO_ODBC_CONV_NOT_REQUIRED;
        !           124: }
        !           125: 
        !           126: static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC)
        !           127: {
        !           128:        if (S->cols) {
        !           129:                int i;
        !           130: 
        !           131:                for (i = 0; i < stmt->column_count; i++) {
        !           132:                        if (S->cols[i].data) {
        !           133:                                efree(S->cols[i].data);
        !           134:                        }
        !           135:                }
        !           136:                efree(S->cols);
        !           137:                S->cols = NULL;
        !           138:        }
        !           139: }
        !           140: 
        !           141: static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
        !           142: {
        !           143:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           144: 
        !           145:        if (S->stmt != SQL_NULL_HANDLE) {
        !           146:                if (stmt->executed) {
        !           147:                        SQLCloseCursor(S->stmt);
        !           148:                }
        !           149:                SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
        !           150:                S->stmt = SQL_NULL_HANDLE;
        !           151:        }
        !           152: 
        !           153:        free_cols(stmt, S TSRMLS_CC);
        !           154:        if (S->convbuf) {
        !           155:                efree(S->convbuf);
        !           156:        }
        !           157:        efree(S);
        !           158: 
        !           159:        return 1;
        !           160: }
        !           161: 
        !           162: static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
        !           163: {
        !           164:        RETCODE rc;
        !           165:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           166:        char *buf = NULL;
        !           167:        SQLLEN row_count = -1;
        !           168: 
        !           169:        if (stmt->executed) {
        !           170:                SQLCloseCursor(S->stmt);
        !           171:        }
        !           172:        
        !           173:        rc = SQLExecute(S->stmt);       
        !           174: 
        !           175:        while (rc == SQL_NEED_DATA) {
        !           176:                struct pdo_bound_param_data *param;
        !           177: 
        !           178:                rc = SQLParamData(S->stmt, (SQLPOINTER*)&param);
        !           179:                if (rc == SQL_NEED_DATA) {
        !           180:                        php_stream *stm;
        !           181:                        int len;
        !           182:                        pdo_odbc_param *P;
        !           183:        
        !           184:                        P = (pdo_odbc_param*)param->driver_data;
        !           185:                        if (Z_TYPE_P(param->parameter) != IS_RESOURCE) {
        !           186:                                /* they passed in a string */
        !           187:                                unsigned long ulen;
        !           188:                                convert_to_string(param->parameter);
        !           189: 
        !           190:                                switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode, 
        !           191:                                                        Z_STRVAL_P(param->parameter),
        !           192:                                                        Z_STRLEN_P(param->parameter),
        !           193:                                                        &ulen)) {
        !           194:                                        case PDO_ODBC_CONV_NOT_REQUIRED:
        !           195:                                                SQLPutData(S->stmt, Z_STRVAL_P(param->parameter),
        !           196:                                                        Z_STRLEN_P(param->parameter));
        !           197:                                                break;
        !           198:                                        case PDO_ODBC_CONV_OK:
        !           199:                                                SQLPutData(S->stmt, S->convbuf, ulen);
        !           200:                                                break;
        !           201:                                        case PDO_ODBC_CONV_FAIL:
        !           202:                                                pdo_odbc_stmt_error("error converting input string");
        !           203:                                                SQLCloseCursor(S->stmt);
        !           204:                                                if (buf) {
        !           205:                                                        efree(buf);
        !           206:                                                }
        !           207:                                                return 0;
        !           208:                                }
        !           209:                                continue;
        !           210:                        }
        !           211: 
        !           212:                        /* we assume that LOBs are binary and don't need charset
        !           213:                         * conversion */
        !           214: 
        !           215:                        php_stream_from_zval_no_verify(stm, &param->parameter);
        !           216:                        if (!stm) {
        !           217:                                /* shouldn't happen either */
        !           218:                                pdo_odbc_stmt_error("input LOB is no longer a stream");
        !           219:                                SQLCloseCursor(S->stmt);
        !           220:                                if (buf) {
        !           221:                                        efree(buf);
        !           222:                                }
        !           223:                                return 0;
        !           224:                        }
        !           225: 
        !           226:                        /* now suck data from the stream and stick it into the database */
        !           227:                        if (buf == NULL) {
        !           228:                                buf = emalloc(8192);
        !           229:                        }
        !           230: 
        !           231:                        do {
        !           232:                                len = php_stream_read(stm, buf, 8192);
        !           233:                                if (len == 0) {
        !           234:                                        break;
        !           235:                                }
        !           236:                                SQLPutData(S->stmt, buf, len);
        !           237:                        } while (1);
        !           238:                }
        !           239:        }
        !           240: 
        !           241:        if (buf) {
        !           242:                efree(buf);
        !           243:        }
        !           244: 
        !           245:        switch (rc) {
        !           246:                case SQL_SUCCESS:
        !           247:                        break;
        !           248:                case SQL_NO_DATA_FOUND:
        !           249:                case SQL_SUCCESS_WITH_INFO:
        !           250:                        pdo_odbc_stmt_error("SQLExecute");
        !           251:                        break;
        !           252: 
        !           253:                default:
        !           254:                        pdo_odbc_stmt_error("SQLExecute");
        !           255:                        return 0;
        !           256:        }
        !           257: 
        !           258:        SQLRowCount(S->stmt, &row_count);
        !           259:        stmt->row_count = row_count;
        !           260: 
        !           261:        if (!stmt->executed) {
        !           262:                /* do first-time-only definition of bind/mapping stuff */
        !           263:                SQLSMALLINT colcount;
        !           264: 
        !           265:                /* how many columns do we have ? */
        !           266:                SQLNumResultCols(S->stmt, &colcount);
        !           267: 
        !           268:                stmt->column_count = (int)colcount;
        !           269:                S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
        !           270:                S->going_long = 0;
        !           271:        }
        !           272: 
        !           273:        return 1;
        !           274: }
        !           275: 
        !           276: static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
        !           277:                enum pdo_param_event event_type TSRMLS_DC)
        !           278: {
        !           279:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           280:        RETCODE rc;
        !           281:        SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
        !           282:        UDWORD precision = 0;
        !           283:        pdo_odbc_param *P;
        !           284:        
        !           285:        /* we're only interested in parameters for prepared SQL right now */
        !           286:        if (param->is_param) {
        !           287: 
        !           288:                switch (event_type) {
        !           289:                        case PDO_PARAM_EVT_FREE:
        !           290:                                P = param->driver_data;
        !           291:                                if (P) {
        !           292:                                        efree(P);
        !           293:                                }
        !           294:                                break;
        !           295: 
        !           296:                        case PDO_PARAM_EVT_ALLOC:
        !           297:                        {
        !           298:                                /* figure out what we're doing */
        !           299:                                switch (PDO_PARAM_TYPE(param->param_type)) {
        !           300:                                        case PDO_PARAM_LOB:
        !           301:                                                break;
        !           302: 
        !           303:                                        case PDO_PARAM_STMT:
        !           304:                                                return 0;
        !           305:                                        
        !           306:                                        default:
        !           307:                                                break;
        !           308:                                }
        !           309: 
        !           310:                                rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
        !           311:                                if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
        !           312:                                        /* MS Access, for instance, doesn't support SQLDescribeParam,
        !           313:                                         * so we need to guess */
        !           314:                                        sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
        !           315:                                                                        SQL_LONGVARBINARY :
        !           316:                                                                        SQL_LONGVARCHAR;
        !           317:                                        precision = 4000;
        !           318:                                        scale = 5;
        !           319:                                        nullable = 1;
        !           320: 
        !           321:                                        if (param->max_value_len > 0) {
        !           322:                                                precision = param->max_value_len;
        !           323:                                        }
        !           324:                                }
        !           325:                                if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
        !           326:                                        ctype = SQL_C_BINARY;
        !           327:                                } else {
        !           328:                                        ctype = SQL_C_CHAR;
        !           329:                                }
        !           330: 
        !           331:                                P = emalloc(sizeof(*P));
        !           332:                                param->driver_data = P;
        !           333: 
        !           334:                                P->len = 0; /* is re-populated each EXEC_PRE */
        !           335:                                P->outbuf = NULL;
        !           336: 
        !           337:                                P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
        !           338:                                if (P->is_unicode) {
        !           339:                                        /* avoid driver auto-translation: we'll do it ourselves */
        !           340:                                        ctype = SQL_C_BINARY;
        !           341:                                }
        !           342: 
        !           343:                                if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
        !           344:                                        P->paramtype = SQL_PARAM_INPUT_OUTPUT;
        !           345:                                } else if (param->max_value_len <= 0) {
        !           346:                                        P->paramtype = SQL_PARAM_INPUT;
        !           347:                                } else {
        !           348:                                        P->paramtype = SQL_PARAM_OUTPUT;
        !           349:                                }
        !           350:                                
        !           351:                                if (P->paramtype != SQL_PARAM_INPUT) {
        !           352:                                        if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
        !           353:                                                /* need an explicit buffer to hold result */
        !           354:                                                P->len = param->max_value_len > 0 ? param->max_value_len : precision;
        !           355:                                                if (P->is_unicode) {
        !           356:                                                        P->len *= 2;
        !           357:                                                }
        !           358:                                                P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
        !           359:                                        }
        !           360:                                }
        !           361:                                
        !           362:                                if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
        !           363:                                        pdo_odbc_stmt_error("Can't bind a lob for output");
        !           364:                                        return 0;
        !           365:                                }
        !           366: 
        !           367:                                rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
        !           368:                                                P->paramtype, ctype, sqltype, precision, scale,
        !           369:                                                P->paramtype == SQL_PARAM_INPUT ? 
        !           370:                                                        (SQLPOINTER)param :
        !           371:                                                        P->outbuf,
        !           372:                                                P->len,
        !           373:                                                &P->len
        !           374:                                                );
        !           375:        
        !           376:                                if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
        !           377:                                        return 1;
        !           378:                                }
        !           379:                                pdo_odbc_stmt_error("SQLBindParameter");
        !           380:                                return 0;
        !           381:                        }
        !           382: 
        !           383:                        case PDO_PARAM_EVT_EXEC_PRE:
        !           384:                                P = param->driver_data;
        !           385:                                if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
        !           386:                                        if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
        !           387:                                                php_stream *stm;
        !           388:                                                php_stream_statbuf sb;
        !           389: 
        !           390:                                                php_stream_from_zval_no_verify(stm, &param->parameter);
        !           391: 
        !           392:                                                if (!stm) {
        !           393:                                                        return 0;
        !           394:                                                }
        !           395: 
        !           396:                                                if (0 == php_stream_stat(stm, &sb)) {
        !           397:                                                        if (P->outbuf) {
        !           398:                                                                int len, amount;
        !           399:                                                                char *ptr = P->outbuf;
        !           400:                                                                char *end = P->outbuf + P->len;
        !           401: 
        !           402:                                                                P->len = 0;
        !           403:                                                                do {
        !           404:                                                                        amount = end - ptr;
        !           405:                                                                        if (amount == 0) {
        !           406:                                                                                break;
        !           407:                                                                        }
        !           408:                                                                        if (amount > 8192)
        !           409:                                                                                amount = 8192;
        !           410:                                                                        len = php_stream_read(stm, ptr, amount);
        !           411:                                                                        if (len == 0) {
        !           412:                                                                                break;
        !           413:                                                                        }
        !           414:                                                                        ptr += len;
        !           415:                                                                        P->len += len;
        !           416:                                                                } while (1);
        !           417: 
        !           418:                                                        } else {
        !           419:                                                                P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
        !           420:                                                        }
        !           421:                                                } else {
        !           422:                                                        if (P->outbuf) {
        !           423:                                                                P->len = 0;
        !           424:                                                        } else {
        !           425:                                                                P->len = SQL_LEN_DATA_AT_EXEC(0);
        !           426:                                                        }
        !           427:                                                }
        !           428:                                        } else {
        !           429:                                                convert_to_string(param->parameter);
        !           430:                                                if (P->outbuf) {
        !           431:                                                        P->len = Z_STRLEN_P(param->parameter);
        !           432:                                                        memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
        !           433:                                                } else {
        !           434:                                                        P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
        !           435:                                                }
        !           436:                                        }
        !           437:                                } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
        !           438:                                        P->len = SQL_NULL_DATA;
        !           439:                                } else {
        !           440:                                        convert_to_string(param->parameter);
        !           441:                                        if (P->outbuf) {
        !           442:                                                unsigned long ulen;
        !           443:                                                switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
        !           444:                                                                Z_STRVAL_P(param->parameter),
        !           445:                                                                Z_STRLEN_P(param->parameter),
        !           446:                                                                &ulen)) {
        !           447:                                                        case PDO_ODBC_CONV_FAIL:
        !           448:                                                        case PDO_ODBC_CONV_NOT_REQUIRED:
        !           449:                                                                P->len = Z_STRLEN_P(param->parameter);
        !           450:                                                                memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
        !           451:                                                                break;
        !           452:                                                        case PDO_ODBC_CONV_OK:
        !           453:                                                                P->len = ulen;
        !           454:                                                                memcpy(P->outbuf, S->convbuf, P->len);
        !           455:                                                                break;
        !           456:                                                }
        !           457:                                        } else {
        !           458:                                                P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
        !           459:                                        }
        !           460:                                }
        !           461:                                return 1;
        !           462:                        
        !           463:                        case PDO_PARAM_EVT_EXEC_POST:
        !           464:                                P = param->driver_data;
        !           465:                                if (P->outbuf) {
        !           466:                                        if (P->outbuf) {
        !           467:                                                unsigned long ulen;
        !           468:                                                char *srcbuf;
        !           469:                                                unsigned long srclen;
        !           470: 
        !           471:                                                switch (P->len) {
        !           472:                                                        case SQL_NULL_DATA:
        !           473:                                                                zval_dtor(param->parameter);
        !           474:                                                                ZVAL_NULL(param->parameter);
        !           475:                                                                break;
        !           476:                                                        default:
        !           477:                                                                convert_to_string(param->parameter);
        !           478:                                                                switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
        !           479:                                                                        case PDO_ODBC_CONV_FAIL:
        !           480:                                                                                /* something fishy, but allow it to come back as binary */
        !           481:                                                                        case PDO_ODBC_CONV_NOT_REQUIRED:
        !           482:                                                                                srcbuf = P->outbuf;
        !           483:                                                                                srclen = P->len;
        !           484:                                                                                break;
        !           485:                                                                        case PDO_ODBC_CONV_OK:
        !           486:                                                                                srcbuf = S->convbuf;
        !           487:                                                                                srclen = ulen;
        !           488:                                                                                break;
        !           489:                                                                }
        !           490:                                                                                
        !           491:                                                                Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1);
        !           492:                                                                memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen);
        !           493:                                                                Z_STRLEN_P(param->parameter) = srclen;
        !           494:                                                                Z_STRVAL_P(param->parameter)[srclen] = '\0';
        !           495:                                                }
        !           496:                                        }
        !           497:                                }
        !           498:                                return 1;
        !           499:                }
        !           500:        }
        !           501:        return 1;
        !           502: }
        !           503: 
        !           504: static int odbc_stmt_fetch(pdo_stmt_t *stmt,
        !           505:        enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
        !           506: {
        !           507:        RETCODE rc;
        !           508:        SQLSMALLINT odbcori;
        !           509:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           510: 
        !           511:        switch (ori) {
        !           512:                case PDO_FETCH_ORI_NEXT:        odbcori = SQL_FETCH_NEXT; break;
        !           513:                case PDO_FETCH_ORI_PRIOR:       odbcori = SQL_FETCH_PRIOR; break;
        !           514:                case PDO_FETCH_ORI_FIRST:       odbcori = SQL_FETCH_FIRST; break;
        !           515:                case PDO_FETCH_ORI_LAST:        odbcori = SQL_FETCH_LAST; break;
        !           516:                case PDO_FETCH_ORI_ABS:         odbcori = SQL_FETCH_ABSOLUTE; break;
        !           517:                case PDO_FETCH_ORI_REL:         odbcori = SQL_FETCH_RELATIVE; break;
        !           518:                default: 
        !           519:                        strcpy(stmt->error_code, "HY106");
        !           520:                        return 0;
        !           521:        }
        !           522:        rc = SQLFetchScroll(S->stmt, odbcori, offset);
        !           523: 
        !           524:        if (rc == SQL_SUCCESS) {
        !           525:                return 1;
        !           526:        }
        !           527:        if (rc == SQL_SUCCESS_WITH_INFO) {
        !           528:                pdo_odbc_stmt_error("SQLFetchScroll");
        !           529:                return 1;
        !           530:        }
        !           531: 
        !           532:        if (rc == SQL_NO_DATA) {
        !           533:                /* pdo_odbc_stmt_error("SQLFetchScroll"); */
        !           534:                return 0;
        !           535:        }
        !           536: 
        !           537:        pdo_odbc_stmt_error("SQLFetchScroll");
        !           538: 
        !           539:        return 0;
        !           540: }
        !           541: 
        !           542: static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
        !           543: {
        !           544:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           545:        struct pdo_column_data *col = &stmt->columns[colno];
        !           546:        zend_bool dyn = FALSE;
        !           547:        RETCODE rc;
        !           548:        SWORD   colnamelen;
        !           549:        SDWORD  colsize, displaysize;
        !           550: 
        !           551:        rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
        !           552:                        sizeof(S->cols[colno].colname)-1, &colnamelen,
        !           553:                        &S->cols[colno].coltype, &colsize, NULL, NULL);
        !           554: 
        !           555:        if (rc != SQL_SUCCESS) {
        !           556:                pdo_odbc_stmt_error("SQLDescribeCol");
        !           557:                if (rc != SQL_SUCCESS_WITH_INFO) {
        !           558:                        return 0;
        !           559:                }
        !           560:        }
        !           561: 
        !           562:        rc = SQLColAttribute(S->stmt, colno+1,
        !           563:                        SQL_DESC_DISPLAY_SIZE,
        !           564:                        NULL, 0, NULL, &displaysize);
        !           565: 
        !           566:        if (rc != SQL_SUCCESS) {
        !           567:                pdo_odbc_stmt_error("SQLColAttribute");
        !           568:                if (rc != SQL_SUCCESS_WITH_INFO) {
        !           569:                        return 0;
        !           570:                }
        !           571:        }
        !           572:        colsize = displaysize;
        !           573: 
        !           574:        col->maxlen = S->cols[colno].datalen = colsize;
        !           575:        col->namelen = colnamelen;
        !           576:        col->name = estrdup(S->cols[colno].colname);
        !           577:        S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
        !           578: 
        !           579:        /* returning data as a string */
        !           580:        col->param_type = PDO_PARAM_STR;
        !           581: 
        !           582:        /* tell ODBC to put it straight into our buffer, but only if it
        !           583:         * isn't "long" data, and only if we haven't already bound a long
        !           584:         * column. */
        !           585:        if (colsize < 256 && !S->going_long) {
        !           586:                S->cols[colno].data = emalloc(colsize+1);
        !           587:                S->cols[colno].is_long = 0;
        !           588: 
        !           589:                rc = SQLBindCol(S->stmt, colno+1,
        !           590:                        S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
        !           591:                        S->cols[colno].data,
        !           592:                        S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
        !           593: 
        !           594:                if (rc != SQL_SUCCESS) {
        !           595:                        pdo_odbc_stmt_error("SQLBindCol");
        !           596:                        return 0;
        !           597:                }
        !           598:        } else {
        !           599:                /* allocate a smaller buffer to keep around for smaller
        !           600:                 * "long" columns */
        !           601:                S->cols[colno].data = emalloc(256);
        !           602:                S->going_long = 1;
        !           603:                S->cols[colno].is_long = 1;
        !           604:        }
        !           605: 
        !           606:        return 1;
        !           607: }
        !           608: 
        !           609: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
        !           610: {
        !           611:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           612:        pdo_odbc_column *C = &S->cols[colno];
        !           613:        unsigned long ulen;
        !           614: 
        !           615:        /* if it is a column containing "long" data, perform late binding now */
        !           616:        if (C->is_long) {
        !           617:                unsigned long alloced = 4096;
        !           618:                unsigned long used = 0;
        !           619:                char *buf;
        !           620:                RETCODE rc;
        !           621: 
        !           622:                /* fetch it into C->data, which is allocated with a length
        !           623:                 * of 256 bytes; if there is more to be had, we then allocate
        !           624:                 * bigger buffer for the caller to free */
        !           625: 
        !           626:                rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
        !           627:                        256, &C->fetched_len);
        !           628: 
        !           629:                if (rc == SQL_SUCCESS) {
        !           630:                        /* all the data fit into our little buffer;
        !           631:                         * jump down to the generic bound data case */
        !           632:                        goto in_data;
        !           633:                }
        !           634: 
        !           635:                if (rc == SQL_SUCCESS_WITH_INFO) {
        !           636:                        /* promote up to a bigger buffer */
        !           637: 
        !           638:                        if (C->fetched_len != SQL_NO_TOTAL) {
        !           639:                                /* use size suggested by the driver, if it knows it */
        !           640:                                alloced = C->fetched_len + 1;
        !           641:                        }
        !           642:                        
        !           643:                        buf = emalloc(alloced);
        !           644:                        memcpy(buf, C->data, 256);
        !           645:                        used = 255; /* not 256; the driver NUL terminated the buffer */
        !           646: 
        !           647:                        do {
        !           648:                                C->fetched_len = 0;
        !           649:                                rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR,
        !           650:                                        buf + used, alloced - used,
        !           651:                                        &C->fetched_len);
        !           652: 
        !           653:                                if (rc == SQL_NO_DATA) {
        !           654:                                        /* we got the lot */
        !           655:                                        break;
        !           656:                                } else if (rc != SQL_SUCCESS) {
        !           657:                                        pdo_odbc_stmt_error("SQLGetData");
        !           658:                                        if (rc != SQL_SUCCESS_WITH_INFO) {
        !           659:                                                break;
        !           660:                                        }
        !           661:                                }
        !           662: 
        !           663:                                if (C->fetched_len == SQL_NO_TOTAL) {
        !           664:                                        used += alloced - used;
        !           665:                                } else {
        !           666:                                        used += C->fetched_len;
        !           667:                                }
        !           668: 
        !           669:                                if (rc == SQL_SUCCESS) {
        !           670:                                        /* this was the final fetch */
        !           671:                                        break;
        !           672:                                }
        !           673: 
        !           674:                                /* we need to fetch another chunk; resize the
        !           675:                                 * buffer */
        !           676:                                alloced *= 2;
        !           677:                                buf = erealloc(buf, alloced);
        !           678:                        } while (1);
        !           679: 
        !           680:                        /* size down */
        !           681:                        if (used < alloced - 1024) {
        !           682:                                alloced = used+1;
        !           683:                                buf = erealloc(buf, used+1);
        !           684:                        }
        !           685:                        buf[used] = '\0';
        !           686:                        *ptr = buf;
        !           687:                        *caller_frees = 1;
        !           688:                        *len = used;
        !           689:                        if (C->is_unicode) {
        !           690:                                goto unicode_conv;
        !           691:                        }
        !           692:                        return 1;
        !           693:                }
        !           694: 
        !           695:                /* something went caca */
        !           696:                *ptr = NULL;
        !           697:                *len = 0;
        !           698:                return 1;
        !           699:        }
        !           700: 
        !           701: in_data:
        !           702:        /* check the indicator to ensure that the data is intact */
        !           703:        if (C->fetched_len == SQL_NULL_DATA) {
        !           704:                /* A NULL value */
        !           705:                *ptr = NULL;
        !           706:                *len = 0;
        !           707:                return 1;
        !           708:        } else if (C->fetched_len >= 0) {
        !           709:                /* it was stored perfectly */
        !           710:                *ptr = C->data;
        !           711:                *len = C->fetched_len;
        !           712:                if (C->is_unicode) {
        !           713:                        goto unicode_conv;
        !           714:                }
        !           715:                return 1;
        !           716:        } else {
        !           717:                /* no data? */
        !           718:                *ptr = NULL;
        !           719:                *len = 0;
        !           720:                return 1;
        !           721:        }
        !           722: 
        !           723:        unicode_conv:
        !           724:        switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
        !           725:                case PDO_ODBC_CONV_FAIL:
        !           726:                        /* oh well.  They can have the binary version of it */
        !           727:                case PDO_ODBC_CONV_NOT_REQUIRED:
        !           728:                        /* shouldn't happen... */
        !           729:                        return 1;
        !           730: 
        !           731:                case PDO_ODBC_CONV_OK:
        !           732:                        if (*caller_frees) {
        !           733:                                efree(*ptr);
        !           734:                        }
        !           735:                        *ptr = emalloc(ulen + 1);
        !           736:                        *len = ulen;
        !           737:                        memcpy(*ptr, S->convbuf, ulen+1);
        !           738:                        *caller_frees = 1;
        !           739:                        return 1;
        !           740:        }
        !           741:        return 1;
        !           742: }
        !           743: 
        !           744: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
        !           745: {
        !           746:        SQLRETURN rc;
        !           747:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           748: 
        !           749:        switch (attr) {
        !           750:                case PDO_ATTR_CURSOR_NAME:
        !           751:                        convert_to_string(val);
        !           752:                        rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
        !           753: 
        !           754:                        if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
        !           755:                                return 1;
        !           756:                        }
        !           757:                        pdo_odbc_stmt_error("SQLSetCursorName");
        !           758:                        return 0;
        !           759: 
        !           760:                case PDO_ODBC_ATTR_ASSUME_UTF8:
        !           761:                        S->assume_utf8 = zval_is_true(val);
        !           762:                        return 0;
        !           763:                default:
        !           764:                        strcpy(S->einfo.last_err_msg, "Unknown Attribute");
        !           765:                        S->einfo.what = "setAttribute";
        !           766:                        strcpy(S->einfo.last_state, "IM001");
        !           767:                        return -1;
        !           768:        }
        !           769: }
        !           770: 
        !           771: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
        !           772: {
        !           773:        SQLRETURN rc;
        !           774:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           775: 
        !           776:        switch (attr) {
        !           777:                case PDO_ATTR_CURSOR_NAME:
        !           778:                {
        !           779:                        char buf[256];
        !           780:                        SQLSMALLINT len = 0;
        !           781:                        rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
        !           782: 
        !           783:                        if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
        !           784:                                ZVAL_STRINGL(val, buf, len, 1);
        !           785:                                return 1;
        !           786:                        }
        !           787:                        pdo_odbc_stmt_error("SQLGetCursorName");
        !           788:                        return 0;
        !           789:                }
        !           790: 
        !           791:                case PDO_ODBC_ATTR_ASSUME_UTF8:
        !           792:                        ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
        !           793:                        return 0;
        !           794: 
        !           795:                default:
        !           796:                        strcpy(S->einfo.last_err_msg, "Unknown Attribute");
        !           797:                        S->einfo.what = "getAttribute";
        !           798:                        strcpy(S->einfo.last_state, "IM001");
        !           799:                        return -1;
        !           800:        }
        !           801: }
        !           802: 
        !           803: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
        !           804: {
        !           805:        SQLRETURN rc;
        !           806:        SQLSMALLINT colcount;
        !           807:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
        !           808: 
        !           809:        /* NOTE: can't guarantee that output or input/output parameters
        !           810:         * are set until this fella returns SQL_NO_DATA, according to
        !           811:         * MSDN ODBC docs */
        !           812:        rc = SQLMoreResults(S->stmt);
        !           813: 
        !           814:        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
        !           815:                return 0;
        !           816:        }
        !           817: 
        !           818:        free_cols(stmt, S TSRMLS_CC);
        !           819:        /* how many columns do we have ? */
        !           820:        SQLNumResultCols(S->stmt, &colcount);
        !           821:        stmt->column_count = (int)colcount;
        !           822:        S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
        !           823:        S->going_long = 0;
        !           824: 
        !           825:        return 1;
        !           826: }
        !           827: 
        !           828: struct pdo_stmt_methods odbc_stmt_methods = {
        !           829:        odbc_stmt_dtor,
        !           830:        odbc_stmt_execute,
        !           831:        odbc_stmt_fetch,
        !           832:        odbc_stmt_describe,
        !           833:        odbc_stmt_get_col,
        !           834:        odbc_stmt_param_hook,
        !           835:        odbc_stmt_set_param,
        !           836:        odbc_stmt_get_attr, /* get attr */
        !           837:        NULL, /* get column meta */
        !           838:        odbc_stmt_next_rowset
        !           839: };
        !           840: 
        !           841: /*
        !           842:  * Local variables:
        !           843:  * tab-width: 4
        !           844:  * c-basic-offset: 4
        !           845:  * End:
        !           846:  * vim600: noet sw=4 ts=4 fdm=marker
        !           847:  * vim<600: noet sw=4 ts=4
        !           848:  */

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