Annotation of embedaddon/php/ext/pdo_pgsql/pgsql_driver.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | PHP Version 5                                                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:   +----------------------------------------------------------------------+
        !             7:   | This source file is subject to version 3.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: 
        !            21: /* $Id: pgsql_driver.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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: 
        !            79:        if (sqlstate == NULL) {
        !            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);
        !           302:        ret = atol(PQcmdTuples(res));
        !           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
        !           318:                        escaped = PQescapeByteaConn(H->server, unquoted, unquotedlen, &tmp_len);
        !           319: #else
        !           320:                        escaped = PQescapeBytea(unquoted, unquotedlen, &tmp_len);
        !           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
        !           334:                        *quotedlen = PQescapeString(*quoted + 1, unquoted, unquotedlen);
        !           335: #else
        !           336:                        *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, NULL);
        !           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: 
        !           500: /* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields])
        !           501:    Returns true if the copy worked fine or false if error */
        !           502: static PHP_METHOD(PDO, pgsqlCopyFromArray)
        !           503: {
        !           504:        pdo_dbh_t *dbh;
        !           505:        pdo_pgsql_db_handle *H;
        !           506: 
        !           507:        zval *pg_rows;
        !           508: 
        !           509:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
        !           510:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
        !           511:        char *query;
        !           512: 
        !           513:        PGresult *pgsql_result;
        !           514:        ExecStatusType status;
        !           515: 
        !           516:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s/a|sss",
        !           517:                                        &table_name, &table_name_len, &pg_rows,
        !           518:                                        &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
        !           519:                return;
        !           520:        }
        !           521: 
        !           522:        if (!zend_hash_num_elements(Z_ARRVAL_P(pg_rows))) {
        !           523:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot copy from an empty array");
        !           524:                RETURN_FALSE;
        !           525:        }
        !           526: 
        !           527:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           528:        PDO_CONSTRUCT_CHECK;
        !           529: 
        !           530:        if (pg_fields) {
        !           531:                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"));
        !           532:        } else {
        !           533:                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"));
        !           534:        }
        !           535: 
        !           536:        /* Obtain db Handle */
        !           537:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           538: 
        !           539:        while ((pgsql_result = PQgetResult(H->server))) {
        !           540:                PQclear(pgsql_result);
        !           541:        }
        !           542:        pgsql_result = PQexec(H->server, query);
        !           543: 
        !           544:        efree(query);
        !           545:        query = NULL;
        !           546: 
        !           547:        if (pgsql_result) {
        !           548:                status = PQresultStatus(pgsql_result);
        !           549:        } else {
        !           550:                status = (ExecStatusType) PQstatus(H->server);
        !           551:        }
        !           552: 
        !           553:        if (status == PGRES_COPY_IN && pgsql_result) {
        !           554:                int command_failed = 0;
        !           555:                int buffer_len = 0;
        !           556:                zval **tmp;
        !           557:                HashPosition pos;
        !           558: 
        !           559:                PQclear(pgsql_result);
        !           560:                zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
        !           561:                while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
        !           562:                        int query_len;
        !           563:                        convert_to_string_ex(tmp);
        !           564:                
        !           565:                        if (buffer_len < Z_STRLEN_PP(tmp)) {
        !           566:                                buffer_len = Z_STRLEN_PP(tmp);
        !           567:                                query = erealloc(query, buffer_len + 2); /* room for \n\0 */
        !           568:                        }
        !           569:                        memcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
        !           570:                        query_len = Z_STRLEN_PP(tmp);
        !           571:                        if (query[query_len - 1] != '\n') {
        !           572:                                query[query_len++] = '\n';
        !           573:                        }
        !           574:                        query[query_len] = '\0';
        !           575:                        if (PQputCopyData(H->server, query, query_len) != 1) {
        !           576:                                efree(query);
        !           577:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed");
        !           578:                                RETURN_FALSE;
        !           579:                        }
        !           580:                        zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
        !           581:                 }
        !           582:                if (query) {
        !           583:                        efree(query);
        !           584:                }
        !           585: 
        !           586:                if (PQputCopyEnd(H->server, NULL) != 1) {
        !           587:                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed");
        !           588:                        RETURN_FALSE;
        !           589:                }
        !           590: 
        !           591:                while ((pgsql_result = PQgetResult(H->server))) {
        !           592:                        if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
        !           593:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           594:                                command_failed = 1;
        !           595:                        }
        !           596:                        PQclear(pgsql_result);
        !           597:                }
        !           598: 
        !           599:                RETURN_BOOL(!command_failed);
        !           600:        } else {
        !           601:                PQclear(pgsql_result);
        !           602:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           603:                RETURN_FALSE;
        !           604:        }
        !           605: }
        !           606: /* }}} */
        !           607: 
        !           608: /* {{{ proto string PDO::pgsqlCopyFromFile(string $table_name , string $filename [, string $delimiter [, string $null_as ] [, string $fields])
        !           609:    Returns true if the copy worked fine or false if error */
        !           610: static PHP_METHOD(PDO, pgsqlCopyFromFile)
        !           611: {
        !           612:        pdo_dbh_t *dbh;
        !           613:        pdo_pgsql_db_handle *H;
        !           614: 
        !           615:        char *table_name, *filename, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
        !           616:        int  table_name_len, filename_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
        !           617:        char *query;
        !           618:        PGresult *pgsql_result;
        !           619:        ExecStatusType status;
        !           620:        php_stream *stream;
        !           621: 
        !           622:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss",
        !           623:                                &table_name, &table_name_len, &filename, &filename_len,
        !           624:                                &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
        !           625:                return;
        !           626:        }
        !           627: 
        !           628:        /* Obtain db Handler */
        !           629:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           630:        PDO_CONSTRUCT_CHECK;
        !           631: 
        !           632:        stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context));
        !           633:        if (!stream) {
        !           634:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file");
        !           635:                RETURN_FALSE;
        !           636:        }
        !           637: 
        !           638:        if (pg_fields) {
        !           639:                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"));
        !           640:        } else {
        !           641:                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"));
        !           642:        }
        !           643: 
        !           644:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           645: 
        !           646:        while ((pgsql_result = PQgetResult(H->server))) {
        !           647:                PQclear(pgsql_result);
        !           648:        }
        !           649:        pgsql_result = PQexec(H->server, query);
        !           650: 
        !           651:        efree(query);
        !           652: 
        !           653:        if (pgsql_result) {
        !           654:                status = PQresultStatus(pgsql_result);
        !           655:        } else {
        !           656:                status = (ExecStatusType) PQstatus(H->server);
        !           657:        }
        !           658: 
        !           659:        if (status == PGRES_COPY_IN && pgsql_result) {
        !           660:                char *buf;
        !           661:                int command_failed = 0;
        !           662:                size_t line_len = 0;
        !           663: 
        !           664:                PQclear(pgsql_result);
        !           665:                while ((buf = php_stream_get_line(stream, NULL, 0, &line_len)) != NULL) {
        !           666:                        if (PQputCopyData(H->server, buf, line_len) != 1) {
        !           667:                                efree(buf);
        !           668:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed");
        !           669:                                php_stream_close(stream);
        !           670:                                RETURN_FALSE;
        !           671:                        }
        !           672:                        efree(buf);
        !           673:                }
        !           674:                php_stream_close(stream);
        !           675: 
        !           676:                if (PQputCopyEnd(H->server, NULL) != 1) {
        !           677:                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed");
        !           678:                        RETURN_FALSE;
        !           679:                }
        !           680: 
        !           681:                while ((pgsql_result = PQgetResult(H->server))) {
        !           682:                        if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
        !           683:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           684:                                command_failed = 1;
        !           685:                        }
        !           686:                        PQclear(pgsql_result);
        !           687:                }
        !           688: 
        !           689:                RETURN_BOOL(!command_failed);
        !           690:        } else {
        !           691:                PQclear(pgsql_result);
        !           692:                php_stream_close(stream);
        !           693:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           694:                RETURN_FALSE;
        !           695:        }
        !           696: }
        !           697: /* }}} */
        !           698: 
        !           699: 
        !           700: /* {{{ proto string PDO::pgsqlCopyToFile(string $table_name , $filename, [string $delimiter [, string $null_as [, string $fields]]])
        !           701:    Returns true if the copy worked fine or false if error */
        !           702: static PHP_METHOD(PDO, pgsqlCopyToFile)
        !           703: {
        !           704:        pdo_dbh_t *dbh;
        !           705:        pdo_pgsql_db_handle *H;
        !           706: 
        !           707:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL, *filename = NULL;
        !           708:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len, filename_len;
        !           709:        char *query;
        !           710: 
        !           711:        PGresult *pgsql_result;
        !           712:        ExecStatusType status;
        !           713: 
        !           714:        php_stream *stream;
        !           715: 
        !           716:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss",
        !           717:                                        &table_name, &table_name_len, &filename, &filename_len,
        !           718:                                        &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
        !           719:                return;
        !           720:        }
        !           721: 
        !           722:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           723:        PDO_CONSTRUCT_CHECK;
        !           724: 
        !           725:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           726: 
        !           727:        stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context));
        !           728:        if (!stream) {
        !           729:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing");
        !           730:                RETURN_FALSE;
        !           731:        }
        !           732: 
        !           733:        while ((pgsql_result = PQgetResult(H->server))) {
        !           734:                PQclear(pgsql_result);
        !           735:        }
        !           736: 
        !           737:        if (pg_fields) {
        !           738:                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"));
        !           739:        } else {
        !           740:                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"));
        !           741:        }
        !           742:        pgsql_result = PQexec(H->server, query);
        !           743:        efree(query);
        !           744: 
        !           745:        if (pgsql_result) {
        !           746:                status = PQresultStatus(pgsql_result);
        !           747:        } else {
        !           748:                status = (ExecStatusType) PQstatus(H->server);
        !           749:        }
        !           750: 
        !           751:        if (status == PGRES_COPY_OUT && pgsql_result) {
        !           752:                PQclear(pgsql_result);
        !           753:                while (1) {
        !           754:                        char *csv = NULL;
        !           755:                        int ret = PQgetCopyData(H->server, &csv, 0);
        !           756: 
        !           757:                        if (ret == -1) {
        !           758:                                break; /* done */
        !           759:                        } else if (ret > 0) {
        !           760:                                if (php_stream_write(stream, csv, ret) != ret) {
        !           761:                                        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to write to file");
        !           762:                                        PQfreemem(csv);
        !           763:                                        php_stream_close(stream);
        !           764:                                        RETURN_FALSE;
        !           765:                                } else {
        !           766:                                        PQfreemem(csv);
        !           767:                                }
        !           768:                        } else {
        !           769:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed");
        !           770:                                php_stream_close(stream);
        !           771:                                RETURN_FALSE;
        !           772:                        }
        !           773:                }
        !           774:                php_stream_close(stream);
        !           775: 
        !           776:                while ((pgsql_result = PQgetResult(H->server))) {
        !           777:                        PQclear(pgsql_result);
        !           778:                }
        !           779:                RETURN_TRUE;
        !           780:        } else {
        !           781:                php_stream_close(stream);
        !           782:                PQclear(pgsql_result);
        !           783:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           784:                RETURN_FALSE;
        !           785:        }
        !           786: }
        !           787: /* }}} */
        !           788: 
        !           789: /* {{{ proto string PDO::pgsqlCopyToArray(string $table_name , [string $delimiter [, string $null_as [, string $fields]]])
        !           790:    Returns true if the copy worked fine or false if error */
        !           791: static PHP_METHOD(PDO, pgsqlCopyToArray)
        !           792: {
        !           793:        pdo_dbh_t *dbh;
        !           794:        pdo_pgsql_db_handle *H;
        !           795: 
        !           796:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
        !           797:        int table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
        !           798:        char *query;
        !           799: 
        !           800:        PGresult *pgsql_result;
        !           801:        ExecStatusType status;
        !           802: 
        !           803:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss",
        !           804:                &table_name, &table_name_len,
        !           805:                &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
        !           806:                return;
        !           807:        }
        !           808: 
        !           809:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           810:        PDO_CONSTRUCT_CHECK;
        !           811: 
        !           812:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           813: 
        !           814:        while ((pgsql_result = PQgetResult(H->server))) {
        !           815:                PQclear(pgsql_result);
        !           816:        }
        !           817: 
        !           818:        if (pg_fields) {
        !           819:                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"));
        !           820:        } else {
        !           821:                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"));
        !           822:        }
        !           823:        pgsql_result = PQexec(H->server, query);
        !           824:        efree(query);
        !           825: 
        !           826:        if (pgsql_result) {
        !           827:                status = PQresultStatus(pgsql_result);
        !           828:        } else {
        !           829:                status = (ExecStatusType) PQstatus(H->server);
        !           830:        }
        !           831: 
        !           832:        if (status == PGRES_COPY_OUT && pgsql_result) {
        !           833:                PQclear(pgsql_result);
        !           834:                 array_init(return_value);
        !           835: 
        !           836:                while (1) {
        !           837:                        char *csv = NULL;
        !           838:                        int ret = PQgetCopyData(H->server, &csv, 0);
        !           839:                        if (ret == -1) {
        !           840:                                break; /* copy done */
        !           841:                        } else if (ret > 0) { 
        !           842:                                add_next_index_stringl(return_value, csv, ret, 1);
        !           843:                                PQfreemem(csv);
        !           844:                        } else {
        !           845:                                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed");
        !           846:                                RETURN_FALSE;
        !           847:                        }
        !           848:                }
        !           849: 
        !           850:                while ((pgsql_result = PQgetResult(H->server))) {
        !           851:                        PQclear(pgsql_result);
        !           852:                }
        !           853:        } else {
        !           854:                PQclear(pgsql_result);
        !           855:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed");
        !           856:                RETURN_FALSE;
        !           857:        }
        !           858: }
        !           859: /* }}} */
        !           860: 
        !           861: 
        !           862: /* {{{ proto string PDO::pgsqlLOBCreate()
        !           863:    Creates a new large object, returning its identifier.  Must be called inside a transaction. */
        !           864: static PHP_METHOD(PDO, pgsqlLOBCreate)
        !           865: {
        !           866:        pdo_dbh_t *dbh;
        !           867:        pdo_pgsql_db_handle *H;
        !           868:        Oid lfd;
        !           869: 
        !           870:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           871:        PDO_CONSTRUCT_CHECK;
        !           872: 
        !           873:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           874:        lfd = lo_creat(H->server, INV_READ|INV_WRITE);
        !           875: 
        !           876:        if (lfd != InvalidOid) {
        !           877:                char *buf;
        !           878:                spprintf(&buf, 0, "%lu", (long) lfd);
        !           879:                RETURN_STRING(buf, 0);
        !           880:        }
        !           881:        
        !           882:        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
        !           883:        RETURN_FALSE;
        !           884: }
        !           885: /* }}} */
        !           886: 
        !           887: /* {{{ proto resource PDO::pgsqlLOBOpen(string oid [, string mode = 'rb'])
        !           888:    Opens an existing large object stream.  Must be called inside a transaction. */
        !           889: static PHP_METHOD(PDO, pgsqlLOBOpen)
        !           890: {
        !           891:        pdo_dbh_t *dbh;
        !           892:        pdo_pgsql_db_handle *H;
        !           893:        Oid oid;
        !           894:        int lfd;
        !           895:        char *oidstr;
        !           896:        int oidstrlen;
        !           897:        char *modestr = "rb";
        !           898:        int modestrlen;
        !           899:        int mode = INV_READ;
        !           900:        char *end_ptr;
        !           901: 
        !           902:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
        !           903:                                &oidstr, &oidstrlen, &modestr, &modestrlen)) {
        !           904:                RETURN_FALSE;
        !           905:        }
        !           906: 
        !           907:        oid = (Oid)strtoul(oidstr, &end_ptr, 10);
        !           908:        if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
        !           909:                RETURN_FALSE;
        !           910:        }
        !           911: 
        !           912:        if (strpbrk(modestr, "+w")) {
        !           913:                mode = INV_READ|INV_WRITE;
        !           914:        }
        !           915:        
        !           916:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           917:        PDO_CONSTRUCT_CHECK;
        !           918: 
        !           919:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           920: 
        !           921:        lfd = lo_open(H->server, oid, mode);
        !           922: 
        !           923:        if (lfd >= 0) {
        !           924:                php_stream *stream = pdo_pgsql_create_lob_stream(dbh, lfd, oid TSRMLS_CC);
        !           925:                if (stream) {
        !           926:                        php_stream_to_zval(stream, return_value);
        !           927:                        return;
        !           928:                }
        !           929:        } else {
        !           930:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
        !           931:        }
        !           932:        RETURN_FALSE;
        !           933: }
        !           934: /* }}} */
        !           935: 
        !           936: /* {{{ proto bool PDO::pgsqlLOBUnlink(string oid)
        !           937:    Deletes the large object identified by oid.  Must be called inside a transaction. */
        !           938: static PHP_METHOD(PDO, pgsqlLOBUnlink)
        !           939: {
        !           940:        pdo_dbh_t *dbh;
        !           941:        pdo_pgsql_db_handle *H;
        !           942:        Oid oid;
        !           943:        char *oidstr, *end_ptr;
        !           944:        int oidlen;
        !           945: 
        !           946:        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
        !           947:                                &oidstr, &oidlen)) {
        !           948:                RETURN_FALSE;
        !           949:        }
        !           950: 
        !           951:        oid = (Oid)strtoul(oidstr, &end_ptr, 10);
        !           952:        if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
        !           953:                RETURN_FALSE;
        !           954:        }
        !           955: 
        !           956:        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
        !           957:        PDO_CONSTRUCT_CHECK;
        !           958: 
        !           959:        H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           960:        
        !           961:        if (1 == lo_unlink(H->server, oid)) {
        !           962:                RETURN_TRUE;
        !           963:        }
        !           964:        pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
        !           965:        RETURN_FALSE;
        !           966: }
        !           967: /* }}} */
        !           968: 
        !           969: 
        !           970: static const zend_function_entry dbh_methods[] = {
        !           971:        PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
        !           972:        PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
        !           973:        PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
        !           974:        PHP_ME(PDO, pgsqlCopyFromArray, NULL, ZEND_ACC_PUBLIC)
        !           975:        PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC)
        !           976:        PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC)
        !           977:        PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC)
        !           978:        PHP_FE_END
        !           979: };
        !           980: 
        !           981: static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
        !           982: {
        !           983:        switch (kind) {
        !           984:                case PDO_DBH_DRIVER_METHOD_KIND_DBH:
        !           985:                        return dbh_methods;
        !           986:                default:
        !           987:                        return NULL;
        !           988:        }
        !           989: }
        !           990: 
        !           991: static int pdo_pgsql_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
        !           992: {
        !           993:        pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
        !           994: 
        !           995:        switch (attr) {
        !           996: #if HAVE_PQPREPARE
        !           997:                case PDO_ATTR_EMULATE_PREPARES:
        !           998:                        H->emulate_prepares = Z_LVAL_P(val);
        !           999:                        return 1;
        !          1000:                case PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT:
        !          1001:                        H->disable_native_prepares = Z_LVAL_P(val);
        !          1002:                        return 1;
        !          1003: #endif
        !          1004: 
        !          1005:                default:
        !          1006:                        return 0;
        !          1007:        }
        !          1008: }
        !          1009: 
        !          1010: static struct pdo_dbh_methods pgsql_methods = {
        !          1011:        pgsql_handle_closer,
        !          1012:        pgsql_handle_preparer,
        !          1013:        pgsql_handle_doer,
        !          1014:        pgsql_handle_quoter,
        !          1015:        pgsql_handle_begin,
        !          1016:        pgsql_handle_commit,
        !          1017:        pgsql_handle_rollback,
        !          1018:        pdo_pgsql_set_attr,
        !          1019:        pdo_pgsql_last_insert_id,
        !          1020:        pdo_pgsql_fetch_error_func,
        !          1021:        pdo_pgsql_get_attribute,
        !          1022:        pdo_pgsql_check_liveness,       /* check_liveness */
        !          1023:        pdo_pgsql_get_driver_methods,  /* get_driver_methods */
        !          1024:        NULL,
        !          1025: };
        !          1026: 
        !          1027: static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
        !          1028: {
        !          1029:        pdo_pgsql_db_handle *H;
        !          1030:        int ret = 0;
        !          1031:        char *conn_str, *p, *e;
        !          1032:        long connect_timeout = 30;
        !          1033: 
        !          1034:        H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
        !          1035:        dbh->driver_data = H;
        !          1036: 
        !          1037:        H->einfo.errcode = 0;
        !          1038:        H->einfo.errmsg = NULL;
        !          1039:        
        !          1040:        /* PostgreSQL wants params in the connect string to be separated by spaces,
        !          1041:         * if the PDO standard semicolons are used, we convert them to spaces
        !          1042:         */
        !          1043:        e = (char *) dbh->data_source + strlen(dbh->data_source);
        !          1044:        p = (char *) dbh->data_source;
        !          1045:        while ((p = memchr(p, ';', (e - p)))) {
        !          1046:                *p = ' ';
        !          1047:        }
        !          1048: 
        !          1049:        if (driver_options) {
        !          1050:                connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
        !          1051:        }
        !          1052: 
        !          1053:        /* support both full connection string & connection string + login and/or password */
        !          1054:        if (dbh->username && dbh->password) {
        !          1055:                spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, dbh->password, connect_timeout);
        !          1056:        } else if (dbh->username) {
        !          1057:                spprintf(&conn_str, 0, "%s user=%s connect_timeout=%ld", dbh->data_source, dbh->username, connect_timeout);
        !          1058:        } else if (dbh->password) {
        !          1059:                spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, dbh->password, connect_timeout);
        !          1060:        } else {
        !          1061:                spprintf(&conn_str, 0, "%s connect_timeout=%ld", (char *) dbh->data_source, connect_timeout);
        !          1062:        }
        !          1063: 
        !          1064:        H->server = PQconnectdb(conn_str);
        !          1065: 
        !          1066:        efree(conn_str);
        !          1067: 
        !          1068:        if (PQstatus(H->server) != CONNECTION_OK) {
        !          1069:                pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE);
        !          1070:                goto cleanup;
        !          1071:        }
        !          1072: 
        !          1073:        PQsetNoticeProcessor(H->server, (void(*)(void*,const char*))_pdo_pgsql_notice, (void *)&dbh);
        !          1074: 
        !          1075:        H->attached = 1;
        !          1076:        H->pgoid = -1;
        !          1077: 
        !          1078:        dbh->methods = &pgsql_methods;
        !          1079:        dbh->alloc_own_columns = 1;
        !          1080:        dbh->max_escaped_char_length = 2;
        !          1081: 
        !          1082:        ret = 1;
        !          1083:        
        !          1084: cleanup:
        !          1085:        dbh->methods = &pgsql_methods;
        !          1086:        if (!ret) {
        !          1087:                pgsql_handle_closer(dbh TSRMLS_CC);
        !          1088:        }
        !          1089: 
        !          1090:        return ret;
        !          1091: }
        !          1092: /* }}} */
        !          1093: 
        !          1094: pdo_driver_t pdo_pgsql_driver = {
        !          1095:        PDO_DRIVER_HEADER(pgsql),
        !          1096:        pdo_pgsql_handle_factory
        !          1097: };
        !          1098: 
        !          1099: /*
        !          1100:  * Local variables:
        !          1101:  * tab-width: 4
        !          1102:  * c-basic-offset: 4
        !          1103:  * End:
        !          1104:  * vim600: noet sw=4 ts=4 fdm=marker
        !          1105:  * vim<600: noet sw=4 ts=4
        !          1106:  */

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