Annotation of embedaddon/php/ext/pdo_pgsql/pgsql_driver.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.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 "ext/standard/file.h"
                     33: 
                     34: #undef PACKAGE_BUGREPORT
                     35: #undef PACKAGE_NAME
                     36: #undef PACKAGE_STRING
                     37: #undef PACKAGE_TARNAME
                     38: #undef PACKAGE_VERSION
                     39: #include "pg_config.h" /* needed for PG_VERSION */
                     40: #include "php_pdo_pgsql.h"
                     41: #include "php_pdo_pgsql_int.h"
                     42: #include "zend_exceptions.h"
                     43: 
                     44: static char * _pdo_pgsql_trim_message(const char *message, int persistent)
                     45: {
                     46:        register int i = strlen(message)-1;
                     47:        char *tmp;
                     48: 
                     49:        if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
                     50:                --i;
                     51:        }
                     52:        while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
                     53:                --i;
                     54:        }
                     55:        ++i;
                     56:        tmp = pemalloc(i + 1, persistent);
                     57:        memcpy(tmp, message, i);
                     58:        tmp[i] = '\0';
                     59:        
                     60:        return tmp;
                     61: }
                     62: 
                     63: int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC) /* {{{ */
                     64: {
                     65:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                     66:        pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
                     67:        pdo_pgsql_error_info *einfo = &H->einfo;
                     68:        char *errmsg = PQerrorMessage(H->server);
                     69: 
                     70:        einfo->errcode = errcode;
                     71:        einfo->file = file;
                     72:        einfo->line = line;
                     73: 
                     74:        if (einfo->errmsg) {
                     75:                pefree(einfo->errmsg, dbh->is_persistent);
                     76:                einfo->errmsg = NULL;
                     77:        }
                     78: 
1.1.1.3   misho      79:        if (sqlstate == NULL || strlen(sqlstate) >= sizeof(pdo_error_type)) {
1.1       misho      80:                strcpy(*pdo_err, "HY000");
                     81:        }
                     82:        else {
                     83:                strcpy(*pdo_err, sqlstate);
                     84:        }
                     85: 
                     86:        if (errmsg) {
                     87:                einfo->errmsg = _pdo_pgsql_trim_message(errmsg, dbh->is_persistent);
                     88:        }
                     89: 
                     90:        if (!dbh->methods) {
                     91:                zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
                     92:                                *pdo_err, einfo->errcode, einfo->errmsg);
                     93:        }
                     94:        
                     95:        return errcode;
                     96: }
                     97: /* }}} */
                     98: 
                     99: static void _pdo_pgsql_notice(pdo_dbh_t *dbh, const char *message) /* {{{ */
                    100: {
                    101: /*     pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */
                    102: }
                    103: /* }}} */
                    104: 
                    105: static int pdo_pgsql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
                    106: {
                    107:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    108:        pdo_pgsql_error_info *einfo = &H->einfo;
                    109: 
                    110:        if (einfo->errcode) {
                    111:                add_next_index_long(info, einfo->errcode);
                    112:                add_next_index_string(info, einfo->errmsg, 1);
                    113:        }
                    114: 
                    115:        return 1;
                    116: }
                    117: /* }}} */
                    118: 
                    119: /* {{{ pdo_pgsql_create_lob_stream */
                    120: static size_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
                    121: {
                    122:        struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
                    123:        return lo_write(self->conn, self->lfd, (char*)buf, count);
                    124: }
                    125: 
                    126: static size_t pgsql_lob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
                    127: {
                    128:        struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
                    129:        return lo_read(self->conn, self->lfd, buf, count);
                    130: }
                    131: 
                    132: static int pgsql_lob_close(php_stream *stream, int close_handle TSRMLS_DC)
                    133: {
                    134:        struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
                    135:        pdo_dbh_t *dbh = self->dbh;
                    136: 
                    137:        if (close_handle) {
                    138:                lo_close(self->conn, self->lfd);
                    139:        }
                    140:        efree(self);
                    141:        php_pdo_dbh_delref(dbh TSRMLS_CC);
                    142:        return 0;
                    143: }
                    144: 
                    145: static int pgsql_lob_flush(php_stream *stream TSRMLS_DC)
                    146: {
                    147:        return 0;
                    148: }
                    149: 
                    150: static int pgsql_lob_seek(php_stream *stream, off_t offset, int whence,
                    151:                off_t *newoffset TSRMLS_DC)
                    152: {
                    153:        struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
                    154:        int pos = lo_lseek(self->conn, self->lfd, offset, whence);
                    155:        *newoffset = pos;
                    156:        return pos >= 0 ? 0 : -1;
                    157: }
                    158: 
                    159: php_stream_ops pdo_pgsql_lob_stream_ops = {
                    160:        pgsql_lob_write,
                    161:        pgsql_lob_read,
                    162:        pgsql_lob_close,
                    163:        pgsql_lob_flush,
                    164:        "pdo_pgsql lob stream",
                    165:        pgsql_lob_seek,
                    166:        NULL,
                    167:        NULL,
                    168:        NULL
                    169: };
                    170: 
                    171: php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *dbh, int lfd, Oid oid TSRMLS_DC)
                    172: {
                    173:        php_stream *stm;
                    174:        struct pdo_pgsql_lob_self *self = ecalloc(1, sizeof(*self));
                    175:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    176: 
                    177:        self->dbh = dbh;
                    178:        self->lfd = lfd;
                    179:        self->oid = oid;
                    180:        self->conn = H->server;
                    181: 
                    182:        stm = php_stream_alloc(&pdo_pgsql_lob_stream_ops, self, 0, "r+b");
                    183: 
                    184:        if (stm) {
                    185:                php_pdo_dbh_addref(dbh TSRMLS_CC);
                    186:                return stm;
                    187:        }
                    188: 
                    189:        efree(self);
                    190:        return NULL;
                    191: }
                    192: /* }}} */
                    193: 
                    194: static int pgsql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
                    195: {
                    196:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    197:        if (H) {
                    198:                if (H->server) {
                    199:                        PQfinish(H->server);
                    200:                        H->server = NULL;
                    201:                }
                    202:                if (H->einfo.errmsg) {
                    203:                        pefree(H->einfo.errmsg, dbh->is_persistent);
                    204:                        H->einfo.errmsg = NULL;
                    205:                }
                    206:                pefree(H, dbh->is_persistent);
                    207:                dbh->driver_data = NULL;
                    208:        }
                    209:        return 0;
                    210: }
                    211: /* }}} */
                    212: 
                    213: static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
                    214: {
                    215:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    216:        pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
                    217:        int scrollable;
                    218: #if HAVE_PQPREPARE
                    219:        int ret;
                    220:        char *nsql = NULL;
                    221:        int nsql_len = 0;
                    222:        int emulate = 0;
                    223: #endif
                    224: 
                    225:        S->H = H;
                    226:        stmt->driver_data = S;
                    227:        stmt->methods = &pgsql_stmt_methods;
                    228: 
                    229:        scrollable = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
                    230:                PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL;
                    231: 
                    232:        if (scrollable) {
                    233:                if (S->cursor_name) {
                    234:                        efree(S->cursor_name);
                    235:                }
                    236:                spprintf(&S->cursor_name, 0, "pdo_crsr_%08x", ++H->stmt_counter);
                    237: #if HAVE_PQPREPARE
                    238:                emulate = 1;
                    239: #endif
                    240:        }
                    241: 
                    242: #if HAVE_PQPREPARE
                    243:        else if (driver_options) {
                    244:                if (pdo_attr_lval(driver_options, PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT, H->disable_native_prepares TSRMLS_CC) == 1 ||
                    245:                        pdo_attr_lval(driver_options, PDO_ATTR_EMULATE_PREPARES, H->emulate_prepares TSRMLS_CC) == 1) {
                    246:                        emulate = 1;
                    247:                }
                    248:        } else {
                    249:                emulate = H->disable_native_prepares || H->emulate_prepares;
                    250:        }
                    251: 
                    252:        if (!emulate && PQprotocolVersion(H->server) > 2) {
                    253:                stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
                    254:                stmt->named_rewrite_template = "$%d";
                    255:                ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
                    256: 
                    257:                if (ret == 1) {
                    258:                        /* query was re-written */
                    259:                        sql = nsql;
                    260:                } else if (ret == -1) {
                    261:                        /* couldn't grok it */
                    262:                        strcpy(dbh->error_code, stmt->error_code);
                    263:                        return 0;
                    264:                }
                    265: 
                    266:                spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter);
                    267:                /* that's all for now; we'll defer the actual prepare until the first execute call */
                    268:        
                    269:                if (nsql) {
                    270:                        S->query = nsql;
                    271:                } else {
                    272:                        S->query = estrdup(sql);
                    273:                }
                    274: 
                    275:                return 1;
                    276:        }
                    277: #endif
                    278: 
                    279:        stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
                    280:        return 1;
                    281: }
                    282: 
                    283: static long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
                    284: {
                    285:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    286:        PGresult *res;
                    287:        long ret = 1;
                    288:        ExecStatusType qs;
                    289:        
                    290:        if (!(res = PQexec(H->server, sql))) {
                    291:                /* fatal error */
                    292:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
                    293:                return -1;
                    294:        }
                    295:        qs = PQresultStatus(res);
                    296:        if (qs != PGRES_COMMAND_OK && qs != PGRES_TUPLES_OK) {
                    297:                pdo_pgsql_error(dbh, qs, pdo_pgsql_sqlstate(res));
                    298:                PQclear(res);
                    299:                return -1;
                    300:        }
                    301:        H->pgoid = PQoidValue(res);
1.1.1.2   misho     302:        ret = (qs == PGRES_COMMAND_OK) ? atol(PQcmdTuples(res)) : 0L;
1.1       misho     303:        PQclear(res);
                    304: 
                    305:        return ret;
                    306: }
                    307: 
                    308: static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
                    309: {
                    310:        unsigned char *escaped;
                    311:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    312:        size_t tmp_len;
                    313:        
                    314:        switch (paramtype) {
                    315:                case PDO_PARAM_LOB:
                    316:                        /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
                    317: #ifdef HAVE_PQESCAPE_BYTEA_CONN
1.1.1.4 ! misho     318:                        escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, (size_t)unquotedlen, &tmp_len);
1.1       misho     319: #else
1.1.1.4 ! misho     320:                        escaped = PQescapeBytea((unsigned char *)unquoted, (size_t)unquotedlen, &tmp_len);
1.1       misho     321: #endif
                    322:                        *quotedlen = (int)tmp_len + 1;
                    323:                        *quoted = emalloc(*quotedlen + 1);
                    324:                        memcpy((*quoted)+1, escaped, *quotedlen-2);
                    325:                        (*quoted)[0] = '\'';
                    326:                        (*quoted)[*quotedlen-1] = '\'';
                    327:                        (*quoted)[*quotedlen] = '\0';
                    328:                        PQfreemem(escaped);
                    329:                        break;
                    330:                default:
                    331:                        *quoted = safe_emalloc(2, unquotedlen, 3);
                    332:                        (*quoted)[0] = '\'';
                    333: #ifndef HAVE_PQESCAPE_CONN
1.1.1.4 ! misho     334:                        *quotedlen = PQescapeString(*quoted + 1, unquoted, (size_t)unquotedlen);
1.1       misho     335: #else
1.1.1.4 ! misho     336:                        *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, (size_t)unquotedlen, NULL);
1.1       misho     337: #endif
                    338:                        (*quoted)[*quotedlen + 1] = '\'';
                    339:                        (*quoted)[*quotedlen + 2] = '\0';
                    340:                        *quotedlen += 2;
                    341:        }
                    342:        return 1;
                    343: }
                    344: 
                    345: static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
                    346: {
                    347:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    348:        char *id = NULL;
                    349: 
                    350:        if (name == NULL) {
                    351:                if (H->pgoid == InvalidOid) {
                    352:                        return NULL;
                    353:                }
                    354:                *len = spprintf(&id, 0, "%ld", (long) H->pgoid);
                    355:        } else {
                    356:                PGresult *res;
                    357:                ExecStatusType status;
                    358:                const char *q[1];
                    359:                q[0] = name;
                    360:                res = PQexecParams(H->server, "SELECT CURRVAL($1)", 1, NULL, q, NULL, NULL, 0);
                    361:                status = PQresultStatus(res);
                    362: 
                    363:                if (res && (status == PGRES_TUPLES_OK)) {
                    364:                        id = estrdup((char *)PQgetvalue(res, 0, 0));
                    365:                        *len = PQgetlength(res, 0, 0);
                    366:                } else {
                    367:                        pdo_pgsql_error(dbh, status, pdo_pgsql_sqlstate(res));
                    368:                }
                    369: 
                    370:                if (res) {
                    371:                        PQclear(res);
                    372:                }
                    373:        }
                    374:        return id;
                    375: }
                    376: 
                    377: static int pdo_pgsql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
                    378: {
                    379:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    380: 
                    381:        switch (attr) {
                    382:                case PDO_ATTR_CLIENT_VERSION:
                    383:                        ZVAL_STRING(return_value, PG_VERSION, 1);
                    384:                        break;
                    385: 
                    386:                case PDO_ATTR_SERVER_VERSION:
                    387:                        if (PQprotocolVersion(H->server) >= 3) { /* PostgreSQL 7.4 or later */
                    388:                                ZVAL_STRING(return_value, (char*)PQparameterStatus(H->server, "server_version"), 1);
                    389:                        } else /* emulate above via a query */
                    390:                        {
                    391:                                PGresult *res = PQexec(H->server, "SELECT VERSION()");
                    392:                                if (res && PQresultStatus(res) == PGRES_TUPLES_OK) {
                    393:                                        ZVAL_STRING(return_value, (char *)PQgetvalue(res, 0, 0), 1);
                    394:                                }
                    395: 
                    396:                                if (res) {
                    397:                                        PQclear(res);
                    398:                                }
                    399:                        }
                    400:                        break;
                    401: 
                    402:                case PDO_ATTR_CONNECTION_STATUS:
                    403:                        switch (PQstatus(H->server)) {
                    404:                                case CONNECTION_STARTED:
                    405:                                        ZVAL_STRINGL(return_value, "Waiting for connection to be made.", sizeof("Waiting for connection to be made.")-1, 1);
                    406:                                        break;
                    407: 
                    408:                                case CONNECTION_MADE:
                    409:                                case CONNECTION_OK:
                    410:                                        ZVAL_STRINGL(return_value, "Connection OK; waiting to send.", sizeof("Connection OK; waiting to send.")-1, 1);
                    411:                                        break;
                    412: 
                    413:                                case CONNECTION_AWAITING_RESPONSE:
                    414:                                        ZVAL_STRINGL(return_value, "Waiting for a response from the server.", sizeof("Waiting for a response from the server.")-1, 1);
                    415:                                        break;
                    416: 
                    417:                                case CONNECTION_AUTH_OK:
                    418:                                        ZVAL_STRINGL(return_value, "Received authentication; waiting for backend start-up to finish.", sizeof("Received authentication; waiting for backend start-up to finish.")-1, 1);
                    419:                                        break;
                    420: #ifdef CONNECTION_SSL_STARTUP
                    421:                                case CONNECTION_SSL_STARTUP:
                    422:                                        ZVAL_STRINGL(return_value, "Negotiating SSL encryption.", sizeof("Negotiating SSL encryption.")-1, 1);
                    423:                                        break;
                    424: #endif
                    425:                                case CONNECTION_SETENV:
                    426:                                        ZVAL_STRINGL(return_value, "Negotiating environment-driven parameter settings.", sizeof("Negotiating environment-driven parameter settings.")-1, 1);
                    427:                                        break;
                    428: 
                    429:                                case CONNECTION_BAD:
                    430:                                default:
                    431:                                        ZVAL_STRINGL(return_value, "Bad connection.", sizeof("Bad connection.")-1, 1);
                    432:                                        break;
                    433:                        }
                    434:                        break;
                    435: 
                    436:                case PDO_ATTR_SERVER_INFO: {
                    437:                        int spid = PQbackendPID(H->server);
                    438:                        char *tmp;
                    439:                        spprintf(&tmp, 0, 
                    440:                                "PID: %d; Client Encoding: %s; Is Superuser: %s; Session Authorization: %s; Date Style: %s", 
                    441:                                spid,
                    442:                                (char*)PQparameterStatus(H->server, "client_encoding"),
                    443:                                (char*)PQparameterStatus(H->server, "is_superuser"),
                    444:                                (char*)PQparameterStatus(H->server, "session_authorization"),
                    445:                                (char*)PQparameterStatus(H->server, "DateStyle"));
                    446:                        ZVAL_STRING(return_value, tmp, 0);
                    447:                }
                    448:                        break;
                    449: 
                    450:                default:
                    451:                        return 0;       
                    452:        }
                    453: 
                    454:        return 1;
                    455: }
                    456: 
                    457: /* {{{ */
                    458: static int pdo_pgsql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC)
                    459: {
                    460:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    461:        if (PQstatus(H->server) == CONNECTION_BAD) {
                    462:                PQreset(H->server);
                    463:        }
                    464:        return (PQstatus(H->server) == CONNECTION_OK) ? SUCCESS : FAILURE;
                    465: }
                    466: /* }}} */
                    467: 
                    468: static int pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC)
                    469: {
                    470:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    471:        PGresult *res;
                    472:        int ret = 1;
                    473: 
                    474:        res = PQexec(H->server, cmd);
                    475: 
                    476:        if (PQresultStatus(res) != PGRES_COMMAND_OK) {
                    477:                pdo_pgsql_error(dbh, PQresultStatus(res), pdo_pgsql_sqlstate(res));
                    478:                ret = 0;
                    479:        }
                    480: 
                    481:        PQclear(res);
                    482:        return ret;
                    483: }
                    484: 
                    485: static int pgsql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
                    486: {
                    487:        return pdo_pgsql_transaction_cmd("BEGIN", dbh TSRMLS_CC);
                    488: }
                    489: 
                    490: static int pgsql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
                    491: {
                    492:        return pdo_pgsql_transaction_cmd("COMMIT", dbh TSRMLS_CC);
                    493: }
                    494: 
                    495: static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
                    496: {
                    497:        return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC);
                    498: }
                    499: 
1.1.1.2   misho     500: static int pgsql_handle_in_transaction(pdo_dbh_t *dbh TSRMLS_DC)
                    501: {
                    502:        pdo_pgsql_db_handle *H;
                    503: 
                    504:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    505: 
                    506:        return PQtransactionStatus(H->server);
                    507: }
                    508: 
1.1       misho     509: /* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields])
                    510:    Returns true if the copy worked fine or false if error */
                    511: static PHP_METHOD(PDO, pgsqlCopyFromArray)
                    512: {
                    513:        pdo_dbh_t *dbh;
                    514:        pdo_pgsql_db_handle *H;
                    515: 
                    516:        zval *pg_rows;
                    517: 
                    518:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
                    519:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
                    520:        char *query;
                    521: 
                    522:        PGresult *pgsql_result;
                    523:        ExecStatusType status;
                    524: 
                    525:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s/a|sss",
                    526:                                        &table_name, &table_name_len, &pg_rows,
                    527:                                        &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
                    528:                return;
                    529:        }
                    530: 
                    531:        if (!zend_hash_num_elements(Z_ARRVAL_P(pg_rows))) {
                    532:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot copy from an empty array");
                    533:                RETURN_FALSE;
                    534:        }
                    535: 
                    536:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    537:        PDO_CONSTRUCT_CHECK;
                    538: 
                    539:        if (pg_fields) {
                    540:                spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    541:        } else {
                    542:                spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    543:        }
                    544: 
                    545:        /* Obtain db Handle */
                    546:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    547: 
                    548:        while ((pgsql_result = PQgetResult(H->server))) {
                    549:                PQclear(pgsql_result);
                    550:        }
                    551:        pgsql_result = PQexec(H->server, query);
                    552: 
                    553:        efree(query);
                    554:        query = NULL;
                    555: 
                    556:        if (pgsql_result) {
                    557:                status = PQresultStatus(pgsql_result);
                    558:        } else {
                    559:                status = (ExecStatusType) PQstatus(H->server);
                    560:        }
                    561: 
                    562:        if (status == PGRES_COPY_IN && pgsql_result) {
                    563:                int command_failed = 0;
                    564:                int buffer_len = 0;
                    565:                zval **tmp;
                    566:                HashPosition pos;
                    567: 
                    568:                PQclear(pgsql_result);
                    569:                zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
                    570:                while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
                    571:                        int query_len;
                    572:                        convert_to_string_ex(tmp);
                    573:                
                    574:                        if (buffer_len < Z_STRLEN_PP(tmp)) {
                    575:                                buffer_len = Z_STRLEN_PP(tmp);
                    576:                                query = erealloc(query, buffer_len + 2); /* room for \n\0 */
                    577:                        }
                    578:                        memcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
                    579:                        query_len = Z_STRLEN_PP(tmp);
                    580:                        if (query[query_len - 1] != '\n') {
                    581:                                query[query_len++] = '\n';
                    582:                        }
                    583:                        query[query_len] = '\0';
                    584:                        if (PQputCopyData(H->server, query, query_len) != 1) {
                    585:                                efree(query);
                    586:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed");
                    587:                                RETURN_FALSE;
                    588:                        }
                    589:                        zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
                    590:                 }
                    591:                if (query) {
                    592:                        efree(query);
                    593:                }
                    594: 
                    595:                if (PQputCopyEnd(H->server, NULL) != 1) {
                    596:                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed");
                    597:                        RETURN_FALSE;
                    598:                }
                    599: 
                    600:                while ((pgsql_result = PQgetResult(H->server))) {
                    601:                        if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
                    602:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    603:                                command_failed = 1;
                    604:                        }
                    605:                        PQclear(pgsql_result);
                    606:                }
                    607: 
                    608:                RETURN_BOOL(!command_failed);
                    609:        } else {
                    610:                PQclear(pgsql_result);
                    611:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    612:                RETURN_FALSE;
                    613:        }
                    614: }
                    615: /* }}} */
                    616: 
                    617: /* {{{ proto string PDO::pgsqlCopyFromFile(string $table_name , string $filename [, string $delimiter [, string $null_as ] [, string $fields])
                    618:    Returns true if the copy worked fine or false if error */
                    619: static PHP_METHOD(PDO, pgsqlCopyFromFile)
                    620: {
                    621:        pdo_dbh_t *dbh;
                    622:        pdo_pgsql_db_handle *H;
                    623: 
                    624:        char *table_name, *filename, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
                    625:        int  table_name_len, filename_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
                    626:        char *query;
                    627:        PGresult *pgsql_result;
                    628:        ExecStatusType status;
                    629:        php_stream *stream;
                    630: 
1.1.1.2   misho     631:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sp|sss",
1.1       misho     632:                                &table_name, &table_name_len, &filename, &filename_len,
                    633:                                &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
                    634:                return;
                    635:        }
                    636: 
                    637:        /* Obtain db Handler */
                    638:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    639:        PDO_CONSTRUCT_CHECK;
                    640: 
                    641:        stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context));
                    642:        if (!stream) {
                    643:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file");
                    644:                RETURN_FALSE;
                    645:        }
                    646: 
                    647:        if (pg_fields) {
                    648:                spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    649:        } else {
                    650:                spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    651:        }
                    652: 
                    653:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    654: 
                    655:        while ((pgsql_result = PQgetResult(H->server))) {
                    656:                PQclear(pgsql_result);
                    657:        }
                    658:        pgsql_result = PQexec(H->server, query);
                    659: 
                    660:        efree(query);
                    661: 
                    662:        if (pgsql_result) {
                    663:                status = PQresultStatus(pgsql_result);
                    664:        } else {
                    665:                status = (ExecStatusType) PQstatus(H->server);
                    666:        }
                    667: 
                    668:        if (status == PGRES_COPY_IN && pgsql_result) {
                    669:                char *buf;
                    670:                int command_failed = 0;
                    671:                size_t line_len = 0;
                    672: 
                    673:                PQclear(pgsql_result);
                    674:                while ((buf = php_stream_get_line(stream, NULL, 0, &line_len)) != NULL) {
                    675:                        if (PQputCopyData(H->server, buf, line_len) != 1) {
                    676:                                efree(buf);
                    677:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed");
                    678:                                php_stream_close(stream);
                    679:                                RETURN_FALSE;
                    680:                        }
                    681:                        efree(buf);
                    682:                }
                    683:                php_stream_close(stream);
                    684: 
                    685:                if (PQputCopyEnd(H->server, NULL) != 1) {
                    686:                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed");
                    687:                        RETURN_FALSE;
                    688:                }
                    689: 
                    690:                while ((pgsql_result = PQgetResult(H->server))) {
                    691:                        if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
                    692:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    693:                                command_failed = 1;
                    694:                        }
                    695:                        PQclear(pgsql_result);
                    696:                }
                    697: 
                    698:                RETURN_BOOL(!command_failed);
                    699:        } else {
                    700:                PQclear(pgsql_result);
                    701:                php_stream_close(stream);
                    702:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    703:                RETURN_FALSE;
                    704:        }
                    705: }
                    706: /* }}} */
                    707: 
                    708: 
                    709: /* {{{ proto string PDO::pgsqlCopyToFile(string $table_name , $filename, [string $delimiter [, string $null_as [, string $fields]]])
                    710:    Returns true if the copy worked fine or false if error */
                    711: static PHP_METHOD(PDO, pgsqlCopyToFile)
                    712: {
                    713:        pdo_dbh_t *dbh;
                    714:        pdo_pgsql_db_handle *H;
                    715: 
                    716:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL, *filename = NULL;
                    717:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len, filename_len;
                    718:        char *query;
                    719: 
                    720:        PGresult *pgsql_result;
                    721:        ExecStatusType status;
                    722: 
                    723:        php_stream *stream;
                    724: 
1.1.1.2   misho     725:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sp|sss",
1.1       misho     726:                                        &table_name, &table_name_len, &filename, &filename_len,
                    727:                                        &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
                    728:                return;
                    729:        }
                    730: 
                    731:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    732:        PDO_CONSTRUCT_CHECK;
                    733: 
                    734:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    735: 
                    736:        stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context));
                    737:        if (!stream) {
                    738:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing");
                    739:                RETURN_FALSE;
                    740:        }
                    741: 
                    742:        while ((pgsql_result = PQgetResult(H->server))) {
                    743:                PQclear(pgsql_result);
                    744:        }
                    745: 
                    746:        if (pg_fields) {
                    747:                spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    748:        } else {
                    749:                spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    750:        }
                    751:        pgsql_result = PQexec(H->server, query);
                    752:        efree(query);
                    753: 
                    754:        if (pgsql_result) {
                    755:                status = PQresultStatus(pgsql_result);
                    756:        } else {
                    757:                status = (ExecStatusType) PQstatus(H->server);
                    758:        }
                    759: 
                    760:        if (status == PGRES_COPY_OUT && pgsql_result) {
                    761:                PQclear(pgsql_result);
                    762:                while (1) {
                    763:                        char *csv = NULL;
                    764:                        int ret = PQgetCopyData(H->server, &csv, 0);
                    765: 
                    766:                        if (ret == -1) {
                    767:                                break; /* done */
                    768:                        } else if (ret > 0) {
                    769:                                if (php_stream_write(stream, csv, ret) != ret) {
                    770:                                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to write to file");
                    771:                                        PQfreemem(csv);
                    772:                                        php_stream_close(stream);
                    773:                                        RETURN_FALSE;
                    774:                                } else {
                    775:                                        PQfreemem(csv);
                    776:                                }
                    777:                        } else {
                    778:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed");
                    779:                                php_stream_close(stream);
                    780:                                RETURN_FALSE;
                    781:                        }
                    782:                }
                    783:                php_stream_close(stream);
                    784: 
                    785:                while ((pgsql_result = PQgetResult(H->server))) {
                    786:                        PQclear(pgsql_result);
                    787:                }
                    788:                RETURN_TRUE;
                    789:        } else {
                    790:                php_stream_close(stream);
                    791:                PQclear(pgsql_result);
                    792:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    793:                RETURN_FALSE;
                    794:        }
                    795: }
                    796: /* }}} */
                    797: 
                    798: /* {{{ proto string PDO::pgsqlCopyToArray(string $table_name , [string $delimiter [, string $null_as [, string $fields]]])
                    799:    Returns true if the copy worked fine or false if error */
                    800: static PHP_METHOD(PDO, pgsqlCopyToArray)
                    801: {
                    802:        pdo_dbh_t *dbh;
                    803:        pdo_pgsql_db_handle *H;
                    804: 
                    805:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
                    806:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
                    807:        char *query;
                    808: 
                    809:        PGresult *pgsql_result;
                    810:        ExecStatusType status;
                    811: 
                    812:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss",
                    813:                &table_name, &table_name_len,
                    814:                &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
                    815:                return;
                    816:        }
                    817: 
                    818:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    819:        PDO_CONSTRUCT_CHECK;
                    820: 
                    821:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    822: 
                    823:        while ((pgsql_result = PQgetResult(H->server))) {
                    824:                PQclear(pgsql_result);
                    825:        }
                    826: 
                    827:        if (pg_fields) {
                    828:                spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    829:        } else {
                    830:                spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
                    831:        }
                    832:        pgsql_result = PQexec(H->server, query);
                    833:        efree(query);
                    834: 
                    835:        if (pgsql_result) {
                    836:                status = PQresultStatus(pgsql_result);
                    837:        } else {
                    838:                status = (ExecStatusType) PQstatus(H->server);
                    839:        }
                    840: 
                    841:        if (status == PGRES_COPY_OUT && pgsql_result) {
                    842:                PQclear(pgsql_result);
                    843:                 array_init(return_value);
                    844: 
                    845:                while (1) {
                    846:                        char *csv = NULL;
                    847:                        int ret = PQgetCopyData(H->server, &csv, 0);
                    848:                        if (ret == -1) {
                    849:                                break; /* copy done */
                    850:                        } else if (ret > 0) { 
                    851:                                add_next_index_stringl(return_value, csv, ret, 1);
                    852:                                PQfreemem(csv);
                    853:                        } else {
                    854:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed");
                    855:                                RETURN_FALSE;
                    856:                        }
                    857:                }
                    858: 
                    859:                while ((pgsql_result = PQgetResult(H->server))) {
                    860:                        PQclear(pgsql_result);
                    861:                }
                    862:        } else {
                    863:                PQclear(pgsql_result);
                    864:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
                    865:                RETURN_FALSE;
                    866:        }
                    867: }
                    868: /* }}} */
                    869: 
                    870: 
                    871: /* {{{ proto string PDO::pgsqlLOBCreate()
                    872:    Creates a new large object, returning its identifier.  Must be called inside a transaction. */
                    873: static PHP_METHOD(PDO, pgsqlLOBCreate)
                    874: {
                    875:        pdo_dbh_t *dbh;
                    876:        pdo_pgsql_db_handle *H;
                    877:        Oid lfd;
                    878: 
                    879:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    880:        PDO_CONSTRUCT_CHECK;
                    881: 
                    882:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    883:        lfd = lo_creat(H->server, INV_READ|INV_WRITE);
                    884: 
                    885:        if (lfd != InvalidOid) {
                    886:                char *buf;
                    887:                spprintf(&buf, 0, "%lu", (long) lfd);
                    888:                RETURN_STRING(buf, 0);
                    889:        }
                    890:        
                    891:        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
                    892:        RETURN_FALSE;
                    893: }
                    894: /* }}} */
                    895: 
                    896: /* {{{ proto resource PDO::pgsqlLOBOpen(string oid [, string mode = 'rb'])
                    897:    Opens an existing large object stream.  Must be called inside a transaction. */
                    898: static PHP_METHOD(PDO, pgsqlLOBOpen)
                    899: {
                    900:        pdo_dbh_t *dbh;
                    901:        pdo_pgsql_db_handle *H;
                    902:        Oid oid;
                    903:        int lfd;
                    904:        char *oidstr;
                    905:        int oidstrlen;
                    906:        char *modestr = "rb";
                    907:        int modestrlen;
                    908:        int mode = INV_READ;
                    909:        char *end_ptr;
                    910: 
                    911:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
                    912:                                &oidstr, &oidstrlen, &modestr, &modestrlen)) {
                    913:                RETURN_FALSE;
                    914:        }
                    915: 
                    916:        oid = (Oid)strtoul(oidstr, &end_ptr, 10);
                    917:        if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
                    918:                RETURN_FALSE;
                    919:        }
                    920: 
                    921:        if (strpbrk(modestr, "+w")) {
                    922:                mode = INV_READ|INV_WRITE;
                    923:        }
                    924:        
                    925:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    926:        PDO_CONSTRUCT_CHECK;
                    927: 
                    928:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    929: 
                    930:        lfd = lo_open(H->server, oid, mode);
                    931: 
                    932:        if (lfd >= 0) {
                    933:                php_stream *stream = pdo_pgsql_create_lob_stream(dbh, lfd, oid TSRMLS_CC);
                    934:                if (stream) {
                    935:                        php_stream_to_zval(stream, return_value);
                    936:                        return;
                    937:                }
                    938:        } else {
                    939:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
                    940:        }
                    941:        RETURN_FALSE;
                    942: }
                    943: /* }}} */
                    944: 
                    945: /* {{{ proto bool PDO::pgsqlLOBUnlink(string oid)
                    946:    Deletes the large object identified by oid.  Must be called inside a transaction. */
                    947: static PHP_METHOD(PDO, pgsqlLOBUnlink)
                    948: {
                    949:        pdo_dbh_t *dbh;
                    950:        pdo_pgsql_db_handle *H;
                    951:        Oid oid;
                    952:        char *oidstr, *end_ptr;
                    953:        int oidlen;
                    954: 
                    955:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
                    956:                                &oidstr, &oidlen)) {
                    957:                RETURN_FALSE;
                    958:        }
                    959: 
                    960:        oid = (Oid)strtoul(oidstr, &end_ptr, 10);
                    961:        if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
                    962:                RETURN_FALSE;
                    963:        }
                    964: 
                    965:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
                    966:        PDO_CONSTRUCT_CHECK;
                    967: 
                    968:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
                    969:        
                    970:        if (1 == lo_unlink(H->server, oid)) {
                    971:                RETURN_TRUE;
                    972:        }
                    973:        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
                    974:        RETURN_FALSE;
                    975: }
                    976: /* }}} */
                    977: 
                    978: 
                    979: static const zend_function_entry dbh_methods[] = {
                    980:        PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
                    981:        PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
                    982:        PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
                    983:        PHP_ME(PDO, pgsqlCopyFromArray, NULL, ZEND_ACC_PUBLIC)
                    984:        PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC)
                    985:        PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC)
                    986:        PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC)
                    987:        PHP_FE_END
                    988: };
                    989: 
                    990: static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
                    991: {
                    992:        switch (kind) {
                    993:                case PDO_DBH_DRIVER_METHOD_KIND_DBH:
                    994:                        return dbh_methods;
                    995:                default:
                    996:                        return NULL;
                    997:        }
                    998: }
                    999: 
                   1000: static int pdo_pgsql_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
                   1001: {
                   1002:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
                   1003: 
                   1004:        switch (attr) {
                   1005: #if HAVE_PQPREPARE
                   1006:                case PDO_ATTR_EMULATE_PREPARES:
                   1007:                        H->emulate_prepares = Z_LVAL_P(val);
                   1008:                        return 1;
                   1009:                case PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT:
                   1010:                        H->disable_native_prepares = Z_LVAL_P(val);
                   1011:                        return 1;
                   1012: #endif
                   1013: 
                   1014:                default:
                   1015:                        return 0;
                   1016:        }
                   1017: }
                   1018: 
                   1019: static struct pdo_dbh_methods pgsql_methods = {
                   1020:        pgsql_handle_closer,
                   1021:        pgsql_handle_preparer,
                   1022:        pgsql_handle_doer,
                   1023:        pgsql_handle_quoter,
                   1024:        pgsql_handle_begin,
                   1025:        pgsql_handle_commit,
                   1026:        pgsql_handle_rollback,
                   1027:        pdo_pgsql_set_attr,
                   1028:        pdo_pgsql_last_insert_id,
                   1029:        pdo_pgsql_fetch_error_func,
                   1030:        pdo_pgsql_get_attribute,
                   1031:        pdo_pgsql_check_liveness,       /* check_liveness */
                   1032:        pdo_pgsql_get_driver_methods,  /* get_driver_methods */
                   1033:        NULL,
1.1.1.2   misho    1034:        pgsql_handle_in_transaction,
1.1       misho    1035: };
                   1036: 
                   1037: static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
                   1038: {
                   1039:        pdo_pgsql_db_handle *H;
                   1040:        int ret = 0;
                   1041:        char *conn_str, *p, *e;
                   1042:        long connect_timeout = 30;
                   1043: 
                   1044:        H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
                   1045:        dbh->driver_data = H;
                   1046: 
                   1047:        H->einfo.errcode = 0;
                   1048:        H->einfo.errmsg = NULL;
                   1049:        
                   1050:        /* PostgreSQL wants params in the connect string to be separated by spaces,
                   1051:         * if the PDO standard semicolons are used, we convert them to spaces
                   1052:         */
                   1053:        e = (char *) dbh->data_source + strlen(dbh->data_source);
                   1054:        p = (char *) dbh->data_source;
                   1055:        while ((p = memchr(p, ';', (e - p)))) {
                   1056:                *p = ' ';
                   1057:        }
                   1058: 
                   1059:        if (driver_options) {
                   1060:                connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
                   1061:        }
                   1062: 
                   1063:        /* support both full connection string & connection string + login and/or password */
                   1064:        if (dbh->username && dbh->password) {
                   1065:                spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, dbh->password, connect_timeout);
                   1066:        } else if (dbh->username) {
                   1067:                spprintf(&conn_str, 0, "%s user=%s connect_timeout=%ld", dbh->data_source, dbh->username, connect_timeout);
                   1068:        } else if (dbh->password) {
                   1069:                spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, dbh->password, connect_timeout);
                   1070:        } else {
                   1071:                spprintf(&conn_str, 0, "%s connect_timeout=%ld", (char *) dbh->data_source, connect_timeout);
                   1072:        }
                   1073: 
                   1074:        H->server = PQconnectdb(conn_str);
                   1075: 
                   1076:        efree(conn_str);
                   1077: 
                   1078:        if (PQstatus(H->server) != CONNECTION_OK) {
                   1079:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE);
                   1080:                goto cleanup;
                   1081:        }
                   1082: 
                   1083:        PQsetNoticeProcessor(H->server, (void(*)(void*,const char*))_pdo_pgsql_notice, (void *)&dbh);
                   1084: 
                   1085:        H->attached = 1;
                   1086:        H->pgoid = -1;
                   1087: 
                   1088:        dbh->methods = &pgsql_methods;
                   1089:        dbh->alloc_own_columns = 1;
                   1090:        dbh->max_escaped_char_length = 2;
                   1091: 
                   1092:        ret = 1;
                   1093:        
                   1094: cleanup:
                   1095:        dbh->methods = &pgsql_methods;
                   1096:        if (!ret) {
                   1097:                pgsql_handle_closer(dbh TSRMLS_CC);
                   1098:        }
                   1099: 
                   1100:        return ret;
                   1101: }
                   1102: /* }}} */
                   1103: 
                   1104: pdo_driver_t pdo_pgsql_driver = {
                   1105:        PDO_DRIVER_HEADER(pgsql),
                   1106:        pdo_pgsql_handle_factory
                   1107: };
                   1108: 
                   1109: /*
                   1110:  * Local variables:
                   1111:  * tab-width: 4
                   1112:  * c-basic-offset: 4
                   1113:  * End:
                   1114:  * vim600: noet sw=4 ts=4 fdm=marker
                   1115:  * vim<600: noet sw=4 ts=4
                   1116:  */

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