PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/pdo_pgsql - pgsql_driver.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 484 598 80.9 %
Date: 2016-08-24 Functions: 33 35 94.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:27 +0000 (33 hours ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.