Annotation of embedaddon/php/ext/pdo_pgsql/pgsql_statement.c, revision 1.1.1.3

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.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt                                  |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Authors: Edin Kadribasic <edink@emini.dk>                            |
                     16:   |          Ilia Alshanestsky <ilia@prohost.org>                        |
                     17:   |          Wez Furlong <wez@php.net>                                   |
                     18:   +----------------------------------------------------------------------+
                     19: */
                     20: 
1.1.1.2   misho      21: /* $Id$ */
1.1       misho      22: 
                     23: #ifdef HAVE_CONFIG_H
                     24: #include "config.h"
                     25: #endif
                     26: 
                     27: #include "php.h"
                     28: #include "php_ini.h"
                     29: #include "ext/standard/info.h"
                     30: #include "pdo/php_pdo.h"
                     31: #include "pdo/php_pdo_driver.h"
                     32: #include "php_pdo_pgsql.h"
                     33: #include "php_pdo_pgsql_int.h"
                     34: #if HAVE_NETINET_IN_H
                     35: #include <netinet/in.h>
                     36: #endif
                     37: 
                     38: /* from postgresql/src/include/catalog/pg_type.h */
                     39: #define BOOLOID     16
                     40: #define BYTEAOID    17
                     41: #define INT8OID     20
                     42: #define INT2OID     21
                     43: #define INT4OID     23
                     44: #define TEXTOID     25
                     45: #define OIDOID      26
                     46: 
                     47: static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
                     48: {
                     49:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                     50: 
                     51:        if (S->result) {
                     52:                /* free the resource */
                     53:                PQclear(S->result);
                     54:                S->result = NULL;
                     55:        }
                     56: 
                     57: #if HAVE_PQPREPARE
                     58:        if (S->stmt_name) {
                     59:                pdo_pgsql_db_handle *H = S->H;
                     60:                char *q = NULL;
                     61:                PGresult *res;
                     62: 
                     63:                if (S->is_prepared) {
                     64:                        spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name);
                     65:                        res = PQexec(H->server, q);
                     66:                        efree(q);
                     67:                        if (res) {
                     68:                                PQclear(res);
                     69:                        }
                     70:                }
                     71:                efree(S->stmt_name);
                     72:                S->stmt_name = NULL;
                     73:        }
                     74:        if (S->param_lengths) {
                     75:                efree(S->param_lengths);
                     76:                S->param_lengths = NULL;
                     77:        }
                     78:        if (S->param_values) {
                     79:                efree(S->param_values);
                     80:                S->param_values = NULL;
                     81:        }
                     82:        if (S->param_formats) {
                     83:                efree(S->param_formats);
                     84:                S->param_formats = NULL;
                     85:        }
                     86:        if (S->param_types) {
                     87:                efree(S->param_types);
                     88:                S->param_types = NULL;
                     89:        }
                     90:        if (S->query) {
                     91:                efree(S->query);
                     92:                S->query = NULL;
                     93:        }
                     94: #endif
                     95: 
                     96:        if (S->cursor_name) {
                     97:                pdo_pgsql_db_handle *H = S->H;
                     98:                char *q = NULL;
                     99:                PGresult *res;
                    100: 
                    101:                spprintf(&q, 0, "CLOSE %s", S->cursor_name);
                    102:                res = PQexec(H->server, q);
                    103:                efree(q);
                    104:                if (res) PQclear(res);
                    105:                efree(S->cursor_name);
                    106:                S->cursor_name = NULL;
                    107:        }
                    108:        
                    109:        if(S->cols) {
                    110:                efree(S->cols);
                    111:                S->cols = NULL;
                    112:        }
                    113:        efree(S);
                    114:        stmt->driver_data = NULL;
                    115:        return 1;
                    116: }
                    117: 
                    118: static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
                    119: {
                    120:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    121:        pdo_pgsql_db_handle *H = S->H;
                    122:        ExecStatusType status;
                    123: 
                    124:        /* ensure that we free any previous unfetched results */
                    125:        if(S->result) {
                    126:                PQclear(S->result);
                    127:                S->result = NULL;
                    128:        }
                    129:        
                    130:        S->current_row = 0;
                    131: 
                    132:        if (S->cursor_name) {
                    133:                char *q = NULL;
                    134: 
                    135:                if (S->is_prepared) {
                    136:                        spprintf(&q, 0, "CLOSE %s", S->cursor_name);
                    137:                        S->result = PQexec(H->server, q);
                    138:                        efree(q);
                    139:                }
                    140: 
                    141:                spprintf(&q, 0, "DECLARE %s SCROLL CURSOR WITH HOLD FOR %s", S->cursor_name, stmt->active_query_string);
                    142:                S->result = PQexec(H->server, q);
                    143:                efree(q);
                    144: 
                    145:                /* check if declare failed */
                    146:                status = PQresultStatus(S->result);
                    147:                if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
                    148:                        pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
                    149:                        return 0;
                    150:                }
                    151: 
                    152:                /* the cursor was declared correctly */
                    153:                S->is_prepared = 1;
                    154: 
                    155:                /* fetch to be able to get the number of tuples later, but don't advance the cursor pointer */
                    156:                spprintf(&q, 0, "FETCH FORWARD 0 FROM %s", S->cursor_name);
                    157:                S->result = PQexec(H->server, q);
                    158:                efree(q);
                    159:        } else
                    160: #if HAVE_PQPREPARE
                    161:        if (S->stmt_name) {
                    162:                /* using a prepared statement */
                    163: 
                    164:                if (!S->is_prepared) {
                    165: stmt_retry:
                    166:                        /* we deferred the prepare until now, because we didn't
                    167:                         * know anything about the parameter types; now we do */
                    168:                        S->result = PQprepare(H->server, S->stmt_name, S->query, 
                    169:                                                stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
                    170:                                                S->param_types);
                    171:                        status = PQresultStatus(S->result);
                    172:                        switch (status) {
                    173:                                case PGRES_COMMAND_OK:
                    174:                                case PGRES_TUPLES_OK:
                    175:                                        /* it worked */
                    176:                                        S->is_prepared = 1;
                    177:                                        PQclear(S->result);
                    178:                                        break;
                    179:                                default: {
                    180:                                        char *sqlstate = pdo_pgsql_sqlstate(S->result);
                    181:                                        /* 42P05 means that the prepared statement already existed. this can happen if you use 
                    182:                                         * a connection pooling software line pgpool which doesn't close the db-connection once 
                    183:                                         * php disconnects. if php dies (no chance to run RSHUTDOWN) during execution it has no 
                    184:                                         * chance to DEALLOCATE the prepared statements it has created. so, if we hit a 42P05 we 
                    185:                                         * deallocate it and retry ONCE (thies 2005.12.15)
                    186:                                         */
                    187:                                        if (sqlstate && !strcmp(sqlstate, "42P05")) {
                    188:                                                char buf[100]; /* stmt_name == "pdo_crsr_%08x" */
                    189:                                                PGresult *res;
                    190:                                                snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name);
                    191:                                                res = PQexec(H->server, buf);
                    192:                                                if (res) {
                    193:                                                        PQclear(res);
                    194:                                                }
                    195:                                                goto stmt_retry;
                    196:                                        } else {
                    197:                                                pdo_pgsql_error_stmt(stmt, status, sqlstate);
                    198:                                                return 0;
                    199:                                        }
                    200:                                }
                    201:                        }
                    202:                }
                    203:                S->result = PQexecPrepared(H->server, S->stmt_name,
                    204:                                stmt->bound_params ?
                    205:                                        zend_hash_num_elements(stmt->bound_params) :
                    206:                                        0,
                    207:                                (const char**)S->param_values,
                    208:                                S->param_lengths,
                    209:                                S->param_formats,
                    210:                                0);
                    211:        } else
                    212: #endif
                    213:        {
                    214:                S->result = PQexec(H->server, stmt->active_query_string);
                    215:        }
                    216:        status = PQresultStatus(S->result);
                    217: 
                    218:        if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
                    219:                pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
                    220:                return 0;
                    221:        }
                    222: 
                    223:        if (!stmt->executed && !stmt->column_count) {
                    224:                stmt->column_count = (int) PQnfields(S->result);
                    225:                S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
                    226:        }
                    227: 
                    228:        if (status == PGRES_COMMAND_OK) {
                    229:                stmt->row_count = (long)atoi(PQcmdTuples(S->result));
                    230:                H->pgoid = PQoidValue(S->result);
                    231:        } else {
                    232:                stmt->row_count = (long)PQntuples(S->result);
                    233:        }
                    234: 
                    235:        return 1;
                    236: }
                    237: 
                    238: static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
                    239:                enum pdo_param_event event_type TSRMLS_DC)
                    240: {
                    241: #if HAVE_PQPREPARE
                    242:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    243: 
                    244:        if (S->stmt_name && param->is_param) {
                    245:                switch (event_type) {
                    246:                        case PDO_PARAM_EVT_FREE:
                    247:                                if (param->driver_data) {
                    248:                                        efree(param->driver_data);
                    249:                                }
                    250:                                break;
                    251: 
                    252:                        case PDO_PARAM_EVT_NORMALIZE:
                    253:                                /* decode name from $1, $2 into 0, 1 etc. */
                    254:                                if (param->name) {
                    255:                                        if (param->name[0] == '$') {
                    256:                                                param->paramno = atoi(param->name + 1);
                    257:                                        } else {
                    258:                                                /* resolve parameter name to rewritten name */
                    259:                                                char *nameptr;
                    260:                                                if (stmt->bound_param_map && SUCCESS == zend_hash_find(stmt->bound_param_map,
                    261:                                                                param->name, param->namelen + 1, (void**)&nameptr)) {
                    262:                                                        param->paramno = atoi(nameptr + 1) - 1;
                    263:                                                } else {
                    264:                                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY093", param->name TSRMLS_CC);
                    265:                                                        return 0;
                    266:                                                }
                    267:                                        }
                    268:                                }
                    269:                                break;
                    270: 
                    271:                        case PDO_PARAM_EVT_ALLOC:
                    272:                        case PDO_PARAM_EVT_EXEC_POST:
                    273:                        case PDO_PARAM_EVT_FETCH_PRE:
                    274:                        case PDO_PARAM_EVT_FETCH_POST:
                    275:                                /* work is handled by EVT_NORMALIZE */
                    276:                                return 1;
                    277: 
                    278:                        case PDO_PARAM_EVT_EXEC_PRE:
                    279:                                if (!stmt->bound_param_map) {
                    280:                                        return 0;
                    281:                                }
                    282:                                if (!S->param_values) {
                    283:                                        S->param_values = ecalloc(
                    284:                                                        zend_hash_num_elements(stmt->bound_param_map),
                    285:                                                        sizeof(char*));
                    286:                                        S->param_lengths = ecalloc(
                    287:                                                        zend_hash_num_elements(stmt->bound_param_map),
                    288:                                                        sizeof(int));
                    289:                                        S->param_formats = ecalloc(
                    290:                                                        zend_hash_num_elements(stmt->bound_param_map),
                    291:                                                        sizeof(int));
                    292:                                        S->param_types = ecalloc(
                    293:                                                        zend_hash_num_elements(stmt->bound_param_map),
                    294:                                                        sizeof(Oid));
                    295:                                }
                    296:                                if (param->paramno >= 0) {
                    297:                                        if (param->paramno > zend_hash_num_elements(stmt->bound_param_map)) {
                    298:                                                pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
                    299:                                                return 0;
                    300:                                        }
                    301: 
                    302:                                        if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB &&
                    303:                                                        Z_TYPE_P(param->parameter) == IS_RESOURCE) {
                    304:                                                php_stream *stm;
                    305:                                                php_stream_from_zval_no_verify(stm, &param->parameter);
                    306:                                                if (stm) {
                    307:                                                        if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
                    308:                                                                struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
                    309:                                                                pdo_pgsql_bound_param *P = param->driver_data;
                    310: 
                    311:                                                                if (P == NULL) {
                    312:                                                                        P = ecalloc(1, sizeof(*P));
                    313:                                                                        param->driver_data = P;
                    314:                                                                }
                    315:                                                                P->oid = htonl(self->oid);
                    316:                                                                S->param_values[param->paramno] = (char*)&P->oid;
                    317:                                                                S->param_lengths[param->paramno] = sizeof(P->oid);
                    318:                                                                S->param_formats[param->paramno] = 1;
                    319:                                                                S->param_types[param->paramno] = OIDOID;
                    320:                                                                return 1;
                    321:                                                        } else {
                    322:                                                                int len;
                    323:                                                                
                    324:                                                                SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
                    325:                                                                Z_TYPE_P(param->parameter) = IS_STRING;
                    326:                                                                
                    327:                                                                if ((len = php_stream_copy_to_mem(stm, &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0)) > 0) {
                    328:                                                                        Z_STRLEN_P(param->parameter) = len;
                    329:                                                                } else {
                    330:                                                                        ZVAL_EMPTY_STRING(param->parameter);
                    331:                                                                }
                    332:                                                        }
                    333:                                                } else {
                    334:                                                        /* expected a stream resource */
                    335:                                                        pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
                    336:                                                        return 0;
                    337:                                                }
                    338:                                        }
                    339: 
                    340:                                        if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
                    341:                                                        Z_TYPE_P(param->parameter) == IS_NULL) {
                    342:                                                S->param_values[param->paramno] = NULL;
                    343:                                                S->param_lengths[param->paramno] = 0;
                    344:                                        } else if (Z_TYPE_P(param->parameter) == IS_BOOL) {
                    345:                                                S->param_values[param->paramno] = Z_BVAL_P(param->parameter) ? "t" : "f";
                    346:                                                S->param_lengths[param->paramno] = 1;
                    347:                                                S->param_formats[param->paramno] = 0;
                    348:                                        } else {
                    349:                                                SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
                    350:                                                convert_to_string(param->parameter);
                    351:                                                S->param_values[param->paramno] = Z_STRVAL_P(param->parameter);
                    352:                                                S->param_lengths[param->paramno] = Z_STRLEN_P(param->parameter);
                    353:                                                S->param_formats[param->paramno] = 0;
                    354:                                        }
                    355: 
                    356:                                        if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
                    357:                                                S->param_types[param->paramno] = 0;
                    358:                                                S->param_formats[param->paramno] = 1;
                    359:                                        } else {
                    360:                                                S->param_types[param->paramno] = 0;
                    361:                                        }
                    362:                                }
                    363:                                break;
                    364:                }
1.1.1.3 ! misho     365:        } else {
        !           366: #endif
        !           367:        if (param->is_param) {
        !           368:         /* We need to manually convert to a pg native boolean value */
        !           369:         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL &&
        !           370:             ((param->param_type & PDO_PARAM_INPUT_OUTPUT) != PDO_PARAM_INPUT_OUTPUT)) {
        !           371:             SEPARATE_ZVAL(&param->parameter);
        !           372:             param->param_type = PDO_PARAM_STR;
        !           373:             ZVAL_STRINGL(param->parameter, Z_BVAL_P(param->parameter) ? "t" : "f", 1, 1);
        !           374:         }
        !           375:     }
        !           376: #if HAVE_PQPREPARE
1.1       misho     377:        }
1.1.1.3 ! misho     378: #endif
1.1       misho     379:        return 1;
                    380: }
                    381: 
                    382: static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
                    383:        enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
                    384: {
                    385:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    386: 
                    387:        if (S->cursor_name) {
                    388:                char *ori_str = NULL;
                    389:                char *q = NULL;
                    390:                ExecStatusType status;
                    391: 
                    392:                switch (ori) {
                    393:                        case PDO_FETCH_ORI_NEXT:        spprintf(&ori_str, 0, "NEXT"); break;
                    394:                        case PDO_FETCH_ORI_PRIOR:       spprintf(&ori_str, 0, "BACKWARD"); break;
                    395:                        case PDO_FETCH_ORI_FIRST:       spprintf(&ori_str, 0, "FIRST"); break;
                    396:                        case PDO_FETCH_ORI_LAST:        spprintf(&ori_str, 0, "LAST"); break;
                    397:                        case PDO_FETCH_ORI_ABS:         spprintf(&ori_str, 0, "ABSOLUTE %ld", offset); break;
                    398:                        case PDO_FETCH_ORI_REL:         spprintf(&ori_str, 0, "RELATIVE %ld", offset); break;
                    399:                        default:
                    400:                                return 0;
                    401:                }
                    402:                
                    403:                spprintf(&q, 0, "FETCH %s FROM %s", ori_str, S->cursor_name);
                    404:                efree(ori_str);
                    405:                S->result = PQexec(S->H->server, q);
                    406:                efree(q);
                    407:                status = PQresultStatus(S->result);
                    408: 
                    409:                if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
                    410:                        pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
                    411:                        return 0;
                    412:                }
                    413: 
                    414:                if (PQntuples(S->result)) {
                    415:                        S->current_row = 1;
                    416:                        return 1;
                    417:                } else {
                    418:                        return 0;
                    419:                }
                    420:        } else {
                    421:                if (S->current_row < stmt->row_count) {
                    422:                        S->current_row++;
                    423:                        return 1;
                    424:                } else {
                    425:                        return 0;
                    426:                }
                    427:        }
                    428: }
                    429: 
                    430: static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
                    431: {
                    432:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    433:        struct pdo_column_data *cols = stmt->columns;
                    434:        struct pdo_bound_param_data *param;
                    435:        
                    436:        if (!S->result) {
                    437:                return 0;
                    438:        }
                    439: 
                    440:        cols[colno].name = estrdup(PQfname(S->result, colno));
                    441:        cols[colno].namelen = strlen(cols[colno].name);
                    442:        cols[colno].maxlen = PQfsize(S->result, colno);
                    443:        cols[colno].precision = PQfmod(S->result, colno);
                    444:        S->cols[colno].pgsql_type = PQftype(S->result, colno);
                    445:        
                    446:        switch(S->cols[colno].pgsql_type) {
                    447: 
                    448:                case BOOLOID:
                    449:                        cols[colno].param_type = PDO_PARAM_BOOL;
                    450:                        break;
                    451:        
                    452:                case OIDOID:
                    453:                        /* did the user bind the column as a LOB ? */
                    454:                        if (stmt->bound_columns && (
                    455:                                        SUCCESS == zend_hash_index_find(stmt->bound_columns,
                    456:                                                colno, (void**)&param) ||
                    457:                                        SUCCESS == zend_hash_find(stmt->bound_columns,
                    458:                                                cols[colno].name, cols[colno].namelen,
                    459:                                                (void**)&param))) {
                    460:                                if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
                    461:                                        cols[colno].param_type = PDO_PARAM_LOB;
                    462:                                        break;
                    463:                                }
                    464:                        }
                    465:                        cols[colno].param_type = PDO_PARAM_INT;
                    466:                        break;
                    467: 
                    468:                case INT2OID:
                    469:                case INT4OID:
                    470:                        cols[colno].param_type = PDO_PARAM_INT;
                    471:                        break;
                    472: 
                    473:                case INT8OID:
                    474:                        if (sizeof(long)>=8) {
                    475:                                cols[colno].param_type = PDO_PARAM_INT;
                    476:                        } else {
                    477:                                cols[colno].param_type = PDO_PARAM_STR;
                    478:                        }
                    479:                        break;
                    480: 
                    481:                case BYTEAOID:
                    482:                        cols[colno].param_type = PDO_PARAM_LOB;
                    483:                        break;
                    484: 
                    485:                default:
                    486:                        cols[colno].param_type = PDO_PARAM_STR;
                    487:        }
                    488: 
                    489:        return 1;
                    490: }
                    491: 
                    492: static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees  TSRMLS_DC)
                    493: {
                    494:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    495:        struct pdo_column_data *cols = stmt->columns;
                    496:        size_t tmp_len;
                    497: 
                    498:        if (!S->result) {
                    499:                return 0;
                    500:        }
                    501: 
                    502:        /* We have already increased count by 1 in pgsql_stmt_fetch() */
                    503:        if (PQgetisnull(S->result, S->current_row - 1, colno)) { /* Check if we got NULL */
                    504:                *ptr = NULL;
                    505:                *len = 0;
                    506:        } else {
                    507:                *ptr = PQgetvalue(S->result, S->current_row - 1, colno);
                    508:                *len = PQgetlength(S->result, S->current_row - 1, colno);
                    509:                
                    510:                switch(cols[colno].param_type) {
                    511: 
                    512:                        case PDO_PARAM_INT:
                    513:                                S->cols[colno].intval = atol(*ptr);
                    514:                                *ptr = (char *) &(S->cols[colno].intval);
                    515:                                *len = sizeof(long);
                    516:                                break;
                    517: 
                    518:                        case PDO_PARAM_BOOL:
                    519:                                S->cols[colno].boolval = **ptr == 't' ? 1: 0;
                    520:                                *ptr = (char *) &(S->cols[colno].boolval);
                    521:                                *len = sizeof(zend_bool);
                    522:                                break;
                    523:                                
                    524:                        case PDO_PARAM_LOB:
                    525:                                if (S->cols[colno].pgsql_type == OIDOID) {
                    526:                                        /* ooo, a real large object */
                    527:                                        char *end_ptr;
                    528:                                        Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10);
                    529:                                        int loid = lo_open(S->H->server, oid, INV_READ);
                    530:                                        if (loid >= 0) {
                    531:                                                *ptr = (char*)pdo_pgsql_create_lob_stream(stmt->dbh, loid, oid TSRMLS_CC);
                    532:                                                *len = 0;
                    533:                                                return *ptr ? 1 : 0;
                    534:                                        }
                    535:                                        *ptr = NULL;
                    536:                                        *len = 0;
                    537:                                        return 0;
                    538:                                } else {
                    539:                                        char *tmp_ptr = PQunescapeBytea(*ptr, &tmp_len);
                    540:                                        if (!tmp_ptr) {
                    541:                                                /* PQunescapeBytea returned an error */
                    542:                                                *len = 0;
                    543:                                                return 0;
                    544:                                        }
                    545:                                        if (!tmp_len) {
                    546:                                                /* Empty string, return as empty stream */
                    547:                                                *ptr = (char *)php_stream_memory_open(TEMP_STREAM_READONLY, "", 0);
                    548:                                                PQfreemem(tmp_ptr);
                    549:                                                *len = 0;
                    550:                                        } else {
                    551:                                                *ptr = estrndup(tmp_ptr, tmp_len);
                    552:                                                PQfreemem(tmp_ptr);
                    553:                                                *len = tmp_len;
                    554:                                                *caller_frees = 1;
                    555:                                        }
                    556:                                }
                    557:                                break;
                    558:                        case PDO_PARAM_NULL:
                    559:                        case PDO_PARAM_STR:
                    560:                        case PDO_PARAM_STMT:
                    561:                        case PDO_PARAM_INPUT_OUTPUT:
                    562:                        case PDO_PARAM_ZVAL:
                    563:                        default:
                    564:                                break;
                    565:                }
                    566:        }
                    567: 
                    568:        return 1;
                    569: }
                    570: 
                    571: static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
                    572: {
                    573:        pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
                    574:        PGresult *res;
                    575:        char *q=NULL;
                    576:        ExecStatusType status;
                    577:        
                    578:        if (!S->result) {
                    579:                return FAILURE;
                    580:        }
                    581:        
                    582:        if (colno >= stmt->column_count) {
                    583:                return FAILURE;
                    584:        }
                    585:        
                    586:        array_init(return_value);
                    587:        add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type);
                    588: 
                    589:        /* Fetch metadata from Postgres system catalogue */
                    590:        spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%d", S->cols[colno].pgsql_type);
                    591:        res = PQexec(S->H->server, q);
                    592:        efree(q);
                    593:        
                    594:        status = PQresultStatus(res);
                    595:        
                    596:        if (status != PGRES_TUPLES_OK) {
                    597:                /* Failed to get system catalogue, but return success
                    598:                 * with the data we have collected so far
                    599:                 */
                    600:                goto done;
                    601:        }
                    602: 
                    603:        /* We want exactly one row returned */
                    604:        if (1 != PQntuples(res)) {
                    605:                goto done;
                    606:        }
                    607: 
                    608:        add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0), 1);
                    609: done:
                    610:        PQclear(res);           
                    611:        return 1;
                    612: }
                    613: 
                    614: static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
                    615: {
                    616:        return 1;
                    617: }
                    618: 
                    619: struct pdo_stmt_methods pgsql_stmt_methods = {
                    620:        pgsql_stmt_dtor,
                    621:        pgsql_stmt_execute,
                    622:        pgsql_stmt_fetch,
                    623:        pgsql_stmt_describe,
                    624:        pgsql_stmt_get_col,
                    625:        pgsql_stmt_param_hook,
                    626:        NULL, /* set_attr */
                    627:        NULL, /* get_attr */
                    628:        pgsql_stmt_get_column_meta,
                    629:        NULL,  /* next_rowset */
                    630:        pdo_pgsql_stmt_cursor_closer
                    631: };
                    632: 
                    633: /*
                    634:  * Local variables:
                    635:  * tab-width: 4
                    636:  * c-basic-offset: 4
                    637:  * End:
                    638:  * vim600: noet sw=4 ts=4 fdm=marker
                    639:  * vim<600: noet sw=4 ts=4
                    640:  */

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