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

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.3   misho       5:   | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
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_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) {
1.1.1.4 ! misho     289:                        case PDO_PARAM_EVT_FETCH_PRE:
        !           290:                        case PDO_PARAM_EVT_FETCH_POST:
        !           291:                        case PDO_PARAM_EVT_NORMALIZE:
        !           292:                                /* Do nothing */
        !           293:                                break;
        !           294: 
1.1       misho     295:                        case PDO_PARAM_EVT_FREE:
                    296:                                P = param->driver_data;
                    297:                                if (P) {
                    298:                                        efree(P);
                    299:                                }
                    300:                                break;
                    301: 
                    302:                        case PDO_PARAM_EVT_ALLOC:
                    303:                        {
                    304:                                /* figure out what we're doing */
                    305:                                switch (PDO_PARAM_TYPE(param->param_type)) {
                    306:                                        case PDO_PARAM_LOB:
                    307:                                                break;
                    308: 
                    309:                                        case PDO_PARAM_STMT:
                    310:                                                return 0;
                    311:                                        
                    312:                                        default:
                    313:                                                break;
                    314:                                }
                    315: 
                    316:                                rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
                    317:                                if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
                    318:                                        /* MS Access, for instance, doesn't support SQLDescribeParam,
                    319:                                         * so we need to guess */
                    320:                                        sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
                    321:                                                                        SQL_LONGVARBINARY :
                    322:                                                                        SQL_LONGVARCHAR;
                    323:                                        precision = 4000;
                    324:                                        scale = 5;
                    325:                                        nullable = 1;
                    326: 
                    327:                                        if (param->max_value_len > 0) {
                    328:                                                precision = param->max_value_len;
                    329:                                        }
                    330:                                }
                    331:                                if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
                    332:                                        ctype = SQL_C_BINARY;
                    333:                                } else {
                    334:                                        ctype = SQL_C_CHAR;
                    335:                                }
                    336: 
                    337:                                P = emalloc(sizeof(*P));
                    338:                                param->driver_data = P;
                    339: 
                    340:                                P->len = 0; /* is re-populated each EXEC_PRE */
                    341:                                P->outbuf = NULL;
                    342: 
                    343:                                P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
                    344:                                if (P->is_unicode) {
                    345:                                        /* avoid driver auto-translation: we'll do it ourselves */
                    346:                                        ctype = SQL_C_BINARY;
                    347:                                }
                    348: 
                    349:                                if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
                    350:                                        P->paramtype = SQL_PARAM_INPUT_OUTPUT;
                    351:                                } else if (param->max_value_len <= 0) {
                    352:                                        P->paramtype = SQL_PARAM_INPUT;
                    353:                                } else {
                    354:                                        P->paramtype = SQL_PARAM_OUTPUT;
                    355:                                }
                    356:                                
                    357:                                if (P->paramtype != SQL_PARAM_INPUT) {
                    358:                                        if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
                    359:                                                /* need an explicit buffer to hold result */
                    360:                                                P->len = param->max_value_len > 0 ? param->max_value_len : precision;
                    361:                                                if (P->is_unicode) {
                    362:                                                        P->len *= 2;
                    363:                                                }
                    364:                                                P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
                    365:                                        }
                    366:                                }
                    367:                                
                    368:                                if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
                    369:                                        pdo_odbc_stmt_error("Can't bind a lob for output");
                    370:                                        return 0;
                    371:                                }
                    372: 
                    373:                                rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
                    374:                                                P->paramtype, ctype, sqltype, precision, scale,
                    375:                                                P->paramtype == SQL_PARAM_INPUT ? 
                    376:                                                        (SQLPOINTER)param :
                    377:                                                        P->outbuf,
                    378:                                                P->len,
                    379:                                                &P->len
                    380:                                                );
                    381:        
                    382:                                if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
                    383:                                        return 1;
                    384:                                }
                    385:                                pdo_odbc_stmt_error("SQLBindParameter");
                    386:                                return 0;
                    387:                        }
                    388: 
                    389:                        case PDO_PARAM_EVT_EXEC_PRE:
                    390:                                P = param->driver_data;
                    391:                                if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
                    392:                                        if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
                    393:                                                php_stream *stm;
                    394:                                                php_stream_statbuf sb;
                    395: 
                    396:                                                php_stream_from_zval_no_verify(stm, &param->parameter);
                    397: 
                    398:                                                if (!stm) {
                    399:                                                        return 0;
                    400:                                                }
                    401: 
                    402:                                                if (0 == php_stream_stat(stm, &sb)) {
                    403:                                                        if (P->outbuf) {
                    404:                                                                int len, amount;
                    405:                                                                char *ptr = P->outbuf;
                    406:                                                                char *end = P->outbuf + P->len;
                    407: 
                    408:                                                                P->len = 0;
                    409:                                                                do {
                    410:                                                                        amount = end - ptr;
                    411:                                                                        if (amount == 0) {
                    412:                                                                                break;
                    413:                                                                        }
                    414:                                                                        if (amount > 8192)
                    415:                                                                                amount = 8192;
                    416:                                                                        len = php_stream_read(stm, ptr, amount);
                    417:                                                                        if (len == 0) {
                    418:                                                                                break;
                    419:                                                                        }
                    420:                                                                        ptr += len;
                    421:                                                                        P->len += len;
                    422:                                                                } while (1);
                    423: 
                    424:                                                        } else {
                    425:                                                                P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
                    426:                                                        }
                    427:                                                } else {
                    428:                                                        if (P->outbuf) {
                    429:                                                                P->len = 0;
                    430:                                                        } else {
                    431:                                                                P->len = SQL_LEN_DATA_AT_EXEC(0);
                    432:                                                        }
                    433:                                                }
                    434:                                        } else {
                    435:                                                convert_to_string(param->parameter);
                    436:                                                if (P->outbuf) {
                    437:                                                        P->len = Z_STRLEN_P(param->parameter);
                    438:                                                        memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
                    439:                                                } else {
                    440:                                                        P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
                    441:                                                }
                    442:                                        }
                    443:                                } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
                    444:                                        P->len = SQL_NULL_DATA;
                    445:                                } else {
                    446:                                        convert_to_string(param->parameter);
                    447:                                        if (P->outbuf) {
                    448:                                                unsigned long ulen;
                    449:                                                switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
                    450:                                                                Z_STRVAL_P(param->parameter),
                    451:                                                                Z_STRLEN_P(param->parameter),
                    452:                                                                &ulen)) {
                    453:                                                        case PDO_ODBC_CONV_FAIL:
                    454:                                                        case PDO_ODBC_CONV_NOT_REQUIRED:
                    455:                                                                P->len = Z_STRLEN_P(param->parameter);
                    456:                                                                memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
                    457:                                                                break;
                    458:                                                        case PDO_ODBC_CONV_OK:
                    459:                                                                P->len = ulen;
                    460:                                                                memcpy(P->outbuf, S->convbuf, P->len);
                    461:                                                                break;
                    462:                                                }
                    463:                                        } else {
                    464:                                                P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
                    465:                                        }
                    466:                                }
                    467:                                return 1;
                    468:                        
                    469:                        case PDO_PARAM_EVT_EXEC_POST:
                    470:                                P = param->driver_data;
                    471:                                if (P->outbuf) {
                    472:                                        if (P->outbuf) {
                    473:                                                unsigned long ulen;
                    474:                                                char *srcbuf;
                    475:                                                unsigned long srclen;
                    476: 
                    477:                                                switch (P->len) {
                    478:                                                        case SQL_NULL_DATA:
                    479:                                                                zval_dtor(param->parameter);
                    480:                                                                ZVAL_NULL(param->parameter);
                    481:                                                                break;
                    482:                                                        default:
                    483:                                                                convert_to_string(param->parameter);
                    484:                                                                switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
                    485:                                                                        case PDO_ODBC_CONV_FAIL:
                    486:                                                                                /* something fishy, but allow it to come back as binary */
                    487:                                                                        case PDO_ODBC_CONV_NOT_REQUIRED:
                    488:                                                                                srcbuf = P->outbuf;
                    489:                                                                                srclen = P->len;
                    490:                                                                                break;
                    491:                                                                        case PDO_ODBC_CONV_OK:
                    492:                                                                                srcbuf = S->convbuf;
                    493:                                                                                srclen = ulen;
                    494:                                                                                break;
                    495:                                                                }
                    496:                                                                                
                    497:                                                                Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1);
                    498:                                                                memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen);
                    499:                                                                Z_STRLEN_P(param->parameter) = srclen;
                    500:                                                                Z_STRVAL_P(param->parameter)[srclen] = '\0';
                    501:                                                }
                    502:                                        }
                    503:                                }
                    504:                                return 1;
                    505:                }
                    506:        }
                    507:        return 1;
                    508: }
                    509: 
                    510: static int odbc_stmt_fetch(pdo_stmt_t *stmt,
                    511:        enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
                    512: {
                    513:        RETCODE rc;
                    514:        SQLSMALLINT odbcori;
                    515:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    516: 
                    517:        switch (ori) {
                    518:                case PDO_FETCH_ORI_NEXT:        odbcori = SQL_FETCH_NEXT; break;
                    519:                case PDO_FETCH_ORI_PRIOR:       odbcori = SQL_FETCH_PRIOR; break;
                    520:                case PDO_FETCH_ORI_FIRST:       odbcori = SQL_FETCH_FIRST; break;
                    521:                case PDO_FETCH_ORI_LAST:        odbcori = SQL_FETCH_LAST; break;
                    522:                case PDO_FETCH_ORI_ABS:         odbcori = SQL_FETCH_ABSOLUTE; break;
                    523:                case PDO_FETCH_ORI_REL:         odbcori = SQL_FETCH_RELATIVE; break;
                    524:                default: 
                    525:                        strcpy(stmt->error_code, "HY106");
                    526:                        return 0;
                    527:        }
                    528:        rc = SQLFetchScroll(S->stmt, odbcori, offset);
                    529: 
                    530:        if (rc == SQL_SUCCESS) {
                    531:                return 1;
                    532:        }
                    533:        if (rc == SQL_SUCCESS_WITH_INFO) {
                    534:                pdo_odbc_stmt_error("SQLFetchScroll");
                    535:                return 1;
                    536:        }
                    537: 
                    538:        if (rc == SQL_NO_DATA) {
                    539:                /* pdo_odbc_stmt_error("SQLFetchScroll"); */
                    540:                return 0;
                    541:        }
                    542: 
                    543:        pdo_odbc_stmt_error("SQLFetchScroll");
                    544: 
                    545:        return 0;
                    546: }
                    547: 
                    548: static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
                    549: {
                    550:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    551:        struct pdo_column_data *col = &stmt->columns[colno];
                    552:        RETCODE rc;
                    553:        SWORD   colnamelen;
                    554:        SDWORD  colsize, displaysize;
                    555: 
                    556:        rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
                    557:                        sizeof(S->cols[colno].colname)-1, &colnamelen,
                    558:                        &S->cols[colno].coltype, &colsize, NULL, NULL);
                    559: 
                    560:        if (rc != SQL_SUCCESS) {
                    561:                pdo_odbc_stmt_error("SQLDescribeCol");
                    562:                if (rc != SQL_SUCCESS_WITH_INFO) {
                    563:                        return 0;
                    564:                }
                    565:        }
                    566: 
                    567:        rc = SQLColAttribute(S->stmt, colno+1,
                    568:                        SQL_DESC_DISPLAY_SIZE,
                    569:                        NULL, 0, NULL, &displaysize);
                    570: 
                    571:        if (rc != SQL_SUCCESS) {
                    572:                pdo_odbc_stmt_error("SQLColAttribute");
                    573:                if (rc != SQL_SUCCESS_WITH_INFO) {
                    574:                        return 0;
                    575:                }
                    576:        }
                    577:        colsize = displaysize;
                    578: 
                    579:        col->maxlen = S->cols[colno].datalen = colsize;
                    580:        col->namelen = colnamelen;
                    581:        col->name = estrdup(S->cols[colno].colname);
                    582:        S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
                    583: 
                    584:        /* returning data as a string */
                    585:        col->param_type = PDO_PARAM_STR;
                    586: 
                    587:        /* tell ODBC to put it straight into our buffer, but only if it
                    588:         * isn't "long" data, and only if we haven't already bound a long
                    589:         * column. */
                    590:        if (colsize < 256 && !S->going_long) {
                    591:                S->cols[colno].data = emalloc(colsize+1);
                    592:                S->cols[colno].is_long = 0;
                    593: 
                    594:                rc = SQLBindCol(S->stmt, colno+1,
                    595:                        S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
                    596:                        S->cols[colno].data,
                    597:                        S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
                    598: 
                    599:                if (rc != SQL_SUCCESS) {
                    600:                        pdo_odbc_stmt_error("SQLBindCol");
                    601:                        return 0;
                    602:                }
                    603:        } else {
                    604:                /* allocate a smaller buffer to keep around for smaller
                    605:                 * "long" columns */
                    606:                S->cols[colno].data = emalloc(256);
                    607:                S->going_long = 1;
                    608:                S->cols[colno].is_long = 1;
                    609:        }
                    610: 
                    611:        return 1;
                    612: }
                    613: 
                    614: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
                    615: {
                    616:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    617:        pdo_odbc_column *C = &S->cols[colno];
                    618:        unsigned long ulen;
                    619: 
                    620:        /* if it is a column containing "long" data, perform late binding now */
                    621:        if (C->is_long) {
                    622:                unsigned long used = 0;
                    623:                char *buf;
                    624:                RETCODE rc;
                    625: 
                    626:                /* fetch it into C->data, which is allocated with a length
                    627:                 * of 256 bytes; if there is more to be had, we then allocate
                    628:                 * bigger buffer for the caller to free */
                    629: 
                    630:                rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
                    631:                        256, &C->fetched_len);
                    632: 
                    633:                if (rc == SQL_SUCCESS) {
                    634:                        /* all the data fit into our little buffer;
                    635:                         * jump down to the generic bound data case */
                    636:                        goto in_data;
                    637:                }
                    638: 
                    639:                if (rc == SQL_SUCCESS_WITH_INFO) {
1.1.1.3   misho     640:                        /* this is a 'long column'
                    641:                        
                    642:                         read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
                    643:                         in order into the output buffer
                    644:                        
                    645:                         this loop has to work whether or not SQLGetData() provides the total column length.
                    646:                         calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
                    647:                         for that size would be slower except maybe for extremely long columns.*/
                    648:                        char *buf2;
                    649: 
                    650:                        buf2 = emalloc(256);
                    651:                        buf = estrndup(C->data, 256);
                    652:                        used = 255; /* not 256; the driver NUL terminated the buffer */
                    653:                        
1.1       misho     654:                        do {
                    655:                                C->fetched_len = 0;
1.1.1.3   misho     656:                                /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
                    657:                                rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, buf2, 256, &C->fetched_len);
                    658:                                
                    659:                                /* resize output buffer and reassemble block */
                    660:                                if (rc==SQL_SUCCESS_WITH_INFO) {
                    661:                                        /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
                    662:                                         states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
                    663:                                         (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
                    664:                                        buf = erealloc(buf, used + 255+1);
                    665:                                        memcpy(buf + used, buf2, 255);
                    666:                                        used = used + 255;
                    667:                                } else if (rc==SQL_SUCCESS) {
                    668:                                        buf = erealloc(buf, used + C->fetched_len+1);
                    669:                                        memcpy(buf + used, buf2, C->fetched_len);
                    670:                                        used = used + C->fetched_len;
1.1       misho     671:                                } else {
1.1.1.3   misho     672:                                        /* includes SQL_NO_DATA */
1.1       misho     673:                                        break;
                    674:                                }
1.1.1.3   misho     675:                                
1.1       misho     676:                        } while (1);
1.1.1.3   misho     677:                        
                    678:                        efree(buf2);
                    679:                        
                    680:                        /* NULL terminate the buffer once, when finished, for use with the rest of PHP */
1.1       misho     681:                        buf[used] = '\0';
1.1.1.3   misho     682: 
1.1       misho     683:                        *ptr = buf;
                    684:                        *caller_frees = 1;
                    685:                        *len = used;
                    686:                        if (C->is_unicode) {
                    687:                                goto unicode_conv;
                    688:                        }
                    689:                        return 1;
                    690:                }
                    691: 
                    692:                /* something went caca */
                    693:                *ptr = NULL;
                    694:                *len = 0;
                    695:                return 1;
                    696:        }
                    697: 
                    698: in_data:
                    699:        /* check the indicator to ensure that the data is intact */
                    700:        if (C->fetched_len == SQL_NULL_DATA) {
                    701:                /* A NULL value */
                    702:                *ptr = NULL;
                    703:                *len = 0;
                    704:                return 1;
                    705:        } else if (C->fetched_len >= 0) {
                    706:                /* it was stored perfectly */
                    707:                *ptr = C->data;
                    708:                *len = C->fetched_len;
                    709:                if (C->is_unicode) {
                    710:                        goto unicode_conv;
                    711:                }
                    712:                return 1;
                    713:        } else {
                    714:                /* no data? */
                    715:                *ptr = NULL;
                    716:                *len = 0;
                    717:                return 1;
                    718:        }
                    719: 
                    720:        unicode_conv:
                    721:        switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
                    722:                case PDO_ODBC_CONV_FAIL:
                    723:                        /* oh well.  They can have the binary version of it */
                    724:                case PDO_ODBC_CONV_NOT_REQUIRED:
                    725:                        /* shouldn't happen... */
                    726:                        return 1;
                    727: 
                    728:                case PDO_ODBC_CONV_OK:
                    729:                        if (*caller_frees) {
                    730:                                efree(*ptr);
                    731:                        }
                    732:                        *ptr = emalloc(ulen + 1);
                    733:                        *len = ulen;
                    734:                        memcpy(*ptr, S->convbuf, ulen+1);
                    735:                        *caller_frees = 1;
                    736:                        return 1;
                    737:        }
                    738:        return 1;
                    739: }
                    740: 
                    741: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
                    742: {
                    743:        SQLRETURN rc;
                    744:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    745: 
                    746:        switch (attr) {
                    747:                case PDO_ATTR_CURSOR_NAME:
                    748:                        convert_to_string(val);
                    749:                        rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
                    750: 
                    751:                        if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
                    752:                                return 1;
                    753:                        }
                    754:                        pdo_odbc_stmt_error("SQLSetCursorName");
                    755:                        return 0;
                    756: 
                    757:                case PDO_ODBC_ATTR_ASSUME_UTF8:
                    758:                        S->assume_utf8 = zval_is_true(val);
                    759:                        return 0;
                    760:                default:
                    761:                        strcpy(S->einfo.last_err_msg, "Unknown Attribute");
                    762:                        S->einfo.what = "setAttribute";
                    763:                        strcpy(S->einfo.last_state, "IM001");
                    764:                        return -1;
                    765:        }
                    766: }
                    767: 
                    768: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
                    769: {
                    770:        SQLRETURN rc;
                    771:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    772: 
                    773:        switch (attr) {
                    774:                case PDO_ATTR_CURSOR_NAME:
                    775:                {
                    776:                        char buf[256];
                    777:                        SQLSMALLINT len = 0;
                    778:                        rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
                    779: 
                    780:                        if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
                    781:                                ZVAL_STRINGL(val, buf, len, 1);
                    782:                                return 1;
                    783:                        }
                    784:                        pdo_odbc_stmt_error("SQLGetCursorName");
                    785:                        return 0;
                    786:                }
                    787: 
                    788:                case PDO_ODBC_ATTR_ASSUME_UTF8:
                    789:                        ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
                    790:                        return 0;
                    791: 
                    792:                default:
                    793:                        strcpy(S->einfo.last_err_msg, "Unknown Attribute");
                    794:                        S->einfo.what = "getAttribute";
                    795:                        strcpy(S->einfo.last_state, "IM001");
                    796:                        return -1;
                    797:        }
                    798: }
                    799: 
                    800: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
                    801: {
                    802:        SQLRETURN rc;
                    803:        SQLSMALLINT colcount;
                    804:        pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
                    805: 
                    806:        /* NOTE: can't guarantee that output or input/output parameters
                    807:         * are set until this fella returns SQL_NO_DATA, according to
                    808:         * MSDN ODBC docs */
                    809:        rc = SQLMoreResults(S->stmt);
                    810: 
                    811:        if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
                    812:                return 0;
                    813:        }
                    814: 
                    815:        free_cols(stmt, S TSRMLS_CC);
                    816:        /* how many columns do we have ? */
                    817:        SQLNumResultCols(S->stmt, &colcount);
                    818:        stmt->column_count = (int)colcount;
                    819:        S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
                    820:        S->going_long = 0;
                    821: 
                    822:        return 1;
                    823: }
                    824: 
                    825: struct pdo_stmt_methods odbc_stmt_methods = {
                    826:        odbc_stmt_dtor,
                    827:        odbc_stmt_execute,
                    828:        odbc_stmt_fetch,
                    829:        odbc_stmt_describe,
                    830:        odbc_stmt_get_col,
                    831:        odbc_stmt_param_hook,
                    832:        odbc_stmt_set_param,
                    833:        odbc_stmt_get_attr, /* get attr */
                    834:        NULL, /* get column meta */
                    835:        odbc_stmt_next_rowset
                    836: };
                    837: 
                    838: /*
                    839:  * Local variables:
                    840:  * tab-width: 4
                    841:  * c-basic-offset: 4
                    842:  * End:
                    843:  * vim600: noet sw=4 ts=4 fdm=marker
                    844:  * vim<600: noet sw=4 ts=4
                    845:  */

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