diff options
| author | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:35:13 -0400 |
|---|---|---|
| committer | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:35:13 -0400 |
| commit | 0a36161e13484a99ccf69bb38f206462d27cc6d6 (patch) | |
| tree | d5107db4b7369603ac7c753829e8972ee74949f7 /ext/pdo_pgsql | |
| parent | ce7edc9b3c7370f32fec0bc7a8ec3e29ed9a5f61 (diff) | |
| download | php-upstream/5.1.2.tar.gz | |
Imported Upstream version 5.1.2upstream/5.1.2
Diffstat (limited to 'ext/pdo_pgsql')
| -rw-r--r-- | ext/pdo_pgsql/package.xml | 63 | ||||
| -rw-r--r-- | ext/pdo_pgsql/package2.xml | 79 | ||||
| -rw-r--r-- | ext/pdo_pgsql/pdo_pgsql.c | 12 | ||||
| -rw-r--r-- | ext/pdo_pgsql/pgsql_driver.c | 223 | ||||
| -rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 124 | ||||
| -rw-r--r-- | ext/pdo_pgsql/php_pdo_pgsql.h | 8 | ||||
| -rw-r--r-- | ext/pdo_pgsql/php_pdo_pgsql_int.h | 30 | ||||
| -rw-r--r-- | ext/pdo_pgsql/tests/bug_33876.phpt | 2 | ||||
| -rw-r--r-- | ext/pdo_pgsql/tests/common.phpt | 1 | ||||
| -rw-r--r-- | ext/pdo_pgsql/tests/config.inc | 14 | ||||
| -rw-r--r-- | ext/pdo_pgsql/tests/large_objects.phpt | 61 |
11 files changed, 506 insertions, 111 deletions
diff --git a/ext/pdo_pgsql/package.xml b/ext/pdo_pgsql/package.xml deleted file mode 100644 index 2f093a9ef..000000000 --- a/ext/pdo_pgsql/package.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE package SYSTEM "../pear/package.dtd">
-<package version="1.0">
- <name>PDO_PGSQL</name>
- <summary>PostgreSQL driver for PDO</summary>
- <maintainers>
- <maintainer>
- <user>edink</user>
- <name>Edin Kadribasic</name>
- <email>edink@php.net</email>
- <role>lead</role>
- </maintainer>
- <maintainer>
- <user>iliaa</user>
- <name>Ilia Alshanetsky</name>
- <email>iliaa@php.net</email>
- <role>lead</role>
- </maintainer>
- <maintainer>
- <user>wez</user>
- <name>Wez Furlong</name>
- <email>wez@php.net</email>
- <role>lead</role>
- </maintainer>
-
- </maintainers>
- <description>
- This extension provides an PostgreSQL driver for PDO.
- </description>
- <license>PHP</license>
- <release>
- <state>stable</state>
- <version>1.0</version>
- <date>2005-11-26</date>
-
- <notes>
-Now features native prepared statements and numerous other improvements.
-
-You need to install the PDO core module before you can make use of this one.
-You also require PostgreSQL client libraries installed on the machine where you
-intend to build and/or use it.
-
-If you are running on windows, you can download the binary from here:
-http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll
- </notes>
-
- <filelist>
- <file role="src" name="config.m4"/>
- <file role="src" name="config.w32"/>
- <file role="src" name="pdo_pgsql.c"/>
- <file role="src" name="pgsql_driver.c"/>
- <file role="src" name="pgsql_statement.c"/>
- <file role="src" name="php_pdo_pgsql.h"/>
- <file role="src" name="php_pdo_pgsql_int.h"/>
-
- <file role="doc" name="CREDITS"/>
- </filelist>
- <deps>
- <dep type="php" rel="ge" version="5.0.3"/>
- <dep type="ext" rel="ge" name="pdo" version="1.0"/>
- </deps>
- </release>
-</package>
diff --git a/ext/pdo_pgsql/package2.xml b/ext/pdo_pgsql/package2.xml new file mode 100644 index 000000000..3508bceb8 --- /dev/null +++ b/ext/pdo_pgsql/package2.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package packagerversion="1.4.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd"> + <name>PDO_PGSQL</name> + <channel>pecl.php.net</channel> + <summary>PostgreSQL driver for PDO</summary> + <description>This extension provides an PostgreSQL driver for PDO. + </description> + <lead> + <name>Edin Kadribasic</name> + <user>edink</user> + <email>edink@php.net</email> + <active>yes</active> + </lead> + <lead> + <name>Ilia Alshanetsky</name> + <user>iliaa</user> + <email>iliaa@php.net</email> + <active>yes</active> + </lead> + <lead> + <name>Wez Furlong</name> + <user>wez</user> + <email>wez@php.net</email> + <active>yes</active> + </lead> + <date>2005-12-04</date> + <version> + <release>1.0.1</release> + <api>1.0.1</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP</license> + <notes> +- repackage with package2.xml +- Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink(). + +You require PostgreSQL client libraries installed on the machine where you +intend to build and/or use this package. + +If you are running on windows, you can download the binary from here: +http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll + </notes> + <contents> + <dir name="/"> + <file name="config.m4" role="src" /> + <file name="config.w32" role="src" /> + <file name="CREDITS" role="doc" /> + <file name="pdo_pgsql.c" role="src" /> + <file name="pgsql_driver.c" role="src" /> + <file name="pgsql_statement.c" role="src" /> + <file name="php_pdo_pgsql.h" role="src" /> + <file name="php_pdo_pgsql_int.h" role="src" /> + </dir> <!-- / --> + </contents> + <dependencies> + <required> + <php> + <min>5.0.3</min> + </php> + <pearinstaller> + <min>1.4.0</min> + </pearinstaller> + <package> + <name>pdo</name> + <channel>pecl.php.net</channel> + <min>1.0.2</min> + <providesextension>PDO</providesextension> + </package> + </required> + </dependencies> + <providesextension>PDO_PGSQL</providesextension> + <extsrcrelease /> +</package> diff --git a/ext/pdo_pgsql/pdo_pgsql.c b/ext/pdo_pgsql/pdo_pgsql.c index 72dfac108..87cfb1b86 100644 --- a/ext/pdo_pgsql/pdo_pgsql.c +++ b/ext/pdo_pgsql/pdo_pgsql.c @@ -2,12 +2,12 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 The PHP Group | + | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: pdo_pgsql.c,v 1.7.2.6 2005/11/26 20:50:08 wez Exp $ */ +/* $Id: pdo_pgsql.c,v 1.7.2.10 2006/01/01 12:50:12 sniper Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -31,7 +31,7 @@ #include "php_pdo_pgsql_int.h" /* {{{ pdo_pgsql_functions[] */ -function_entry pdo_pgsql_functions[] = { +zend_function_entry pdo_pgsql_functions[] = { {NULL, NULL, NULL} }; /* }}} */ @@ -61,7 +61,7 @@ zend_module_entry pdo_pgsql_module_entry = { PHP_RINIT(pdo_pgsql), PHP_RSHUTDOWN(pdo_pgsql), PHP_MINFO(pdo_pgsql), - "1.0", + "1.0.2", STANDARD_MODULE_PROPERTIES }; /* }}} */ diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 99c37d681..8568d3697 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -2,21 +2,23 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 The PHP Group | + | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Edin Kadribasic <edink@emini.dk> | + | Authors: Edin Kadribasic <edink@emini.dk> | + | Ilia Alshanestsky <ilia@prohost.org> | + | Wez Furlong <wez@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: pgsql_driver.c,v 1.53.2.1 2005/11/25 03:35:04 wez Exp $ */ +/* $Id: pgsql_driver.c,v 1.53.2.10 2006/01/01 12:50:12 sniper Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -28,6 +30,11 @@ #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION #include "pg_config.h" /* needed for PG_VERSION */ #include "php_pdo_pgsql.h" #include "php_pdo_pgsql_int.h" @@ -108,6 +115,81 @@ static int pdo_pgsql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *in } /* }}} */ +/* {{{ pdo_pgsql_create_lob_stream */ +static size_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) +{ + struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract; + return lo_write(self->conn, self->lfd, (char*)buf, count); +} + +static size_t pgsql_lob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) +{ + struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract; + return lo_read(self->conn, self->lfd, buf, count); +} + +static int pgsql_lob_close(php_stream *stream, int close_handle TSRMLS_DC) +{ + struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract; + pdo_dbh_t *dbh = self->dbh; + + if (close_handle) { + lo_close(self->conn, self->lfd); + } + efree(self); + php_pdo_dbh_delref(dbh TSRMLS_CC); + return 0; +} + +static int pgsql_lob_flush(php_stream *stream TSRMLS_DC) +{ + return 0; +} + +static int pgsql_lob_seek(php_stream *stream, off_t offset, int whence, + off_t *newoffset TSRMLS_DC) +{ + struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract; + int pos = lo_lseek(self->conn, self->lfd, offset, whence); + *newoffset = pos; + return pos >= 0 ? 0 : -1; +} + +php_stream_ops pdo_pgsql_lob_stream_ops = { + pgsql_lob_write, + pgsql_lob_read, + pgsql_lob_close, + pgsql_lob_flush, + "pdo_pgsql lob stream", + pgsql_lob_seek, + NULL, + NULL, + NULL +}; + +php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *dbh, int lfd, Oid oid TSRMLS_DC) +{ + php_stream *stm; + struct pdo_pgsql_lob_self *self = ecalloc(1, sizeof(*self)); + pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; + + self->dbh = dbh; + self->lfd = lfd; + self->oid = oid; + self->conn = H->server; + + stm = php_stream_alloc(&pdo_pgsql_lob_stream_ops, self, 0, "r+b"); + + if (stm) { + php_pdo_dbh_addref(dbh TSRMLS_CC); + return stm; + } + + efree(self); + return NULL; +} +/* }}} */ + static int pgsql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ { pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; @@ -133,11 +215,9 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt)); int scrollable; #if HAVE_PQPREPARE - PGresult *res; int ret; char *nsql = NULL; int nsql_len = 0; - ExecStatusType status; #endif S->H = H; @@ -397,6 +477,131 @@ static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC); } +/* {{{ proto string PDO::pgsqlLOBCreate() + Creates a new large object, returning its identifier. Must be called inside a transaction. */ +static PHP_METHOD(PDO, pgsqlLOBCreate) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + Oid lfd; + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + lfd = lo_creat(H->server, INV_READ|INV_WRITE); + + if (lfd != InvalidOid) { + char *buf; + spprintf(&buf, 0, "%lu", (long) lfd); + RETURN_STRING(buf, 0); + } + + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto resource PDO::pgsqlLOBOpen(string oid [, string mode = 'rb']) + Opens an existing large object stream. Must be called inside a transaction. */ +static PHP_METHOD(PDO, pgsqlLOBOpen) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + Oid oid; + int lfd; + char *oidstr; + int oidstrlen; + char *modestr = "rb"; + int modestrlen; + int mode = INV_READ; + char *end_ptr; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", + &oidstr, &oidstrlen, &modestr, &modestrlen)) { + RETURN_FALSE; + } + + oid = (Oid)strtoul(oidstr, &end_ptr, 10); + if (oid == 0 && (errno == ERANGE || errno == EINVAL)) { + RETURN_FALSE; + } + + if (strpbrk(modestr, "+w")) { + mode = INV_READ|INV_WRITE; + } + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + lfd = lo_open(H->server, oid, mode); + + if (lfd >= 0) { + php_stream *stream = pdo_pgsql_create_lob_stream(dbh, lfd, oid TSRMLS_CC); + if (stream) { + php_stream_to_zval(stream, return_value); + return; + } + } else { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool PDO::pgsqlLOBUnlink(string oid) + Deletes the large object identified by oid. Must be called inside a transaction. */ +static PHP_METHOD(PDO, pgsqlLOBUnlink) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + Oid oid; + char *oidstr, *end_ptr; + int oidlen; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &oidstr, &oidlen)) { + RETURN_FALSE; + } + + oid = (Oid)strtoul(oidstr, &end_ptr, 10); + if (oid == 0 && (errno == ERANGE || errno == EINVAL)) { + RETURN_FALSE; + } + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + if (1 == lo_unlink(H->server, oid)) { + RETURN_TRUE; + } + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + RETURN_FALSE; +} +/* }}} */ + + +static zend_function_entry dbh_methods[] = { + PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC) +{ + switch (kind) { + case PDO_DBH_DRIVER_METHOD_KIND_DBH: + return dbh_methods; + default: + return NULL; + } +} + static struct pdo_dbh_methods pgsql_methods = { pgsql_handle_closer, pgsql_handle_preparer, @@ -410,7 +615,7 @@ static struct pdo_dbh_methods pgsql_methods = { pdo_pgsql_fetch_error_func, pdo_pgsql_get_attribute, NULL, /* check_liveness */ - NULL /* get_driver_methods */ + pdo_pgsql_get_driver_methods /* get_driver_methods */ }; static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ @@ -462,7 +667,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_ H->pgoid = -1; dbh->methods = &pgsql_methods; - dbh->alloc_own_columns = 1; + dbh->alloc_own_columns = 0; dbh->max_escaped_char_length = 2; ret = 1; diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index f3a1fc8af..1d28d0b71 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -2,21 +2,23 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 The PHP Group | + | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Edin Kadribasic <edink@emini.dk> | + | Authors: Edin Kadribasic <edink@emini.dk> | + | Ilia Alshanestsky <ilia@prohost.org> | + | Wez Furlong <wez@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: pgsql_statement.c,v 1.31.2.4 2005/11/25 03:35:04 wez Exp $ */ +/* $Id: pgsql_statement.c,v 1.31.2.10 2006/01/01 12:50:12 sniper Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -29,6 +31,9 @@ #include "pdo/php_pdo_driver.h" #include "php_pdo_pgsql.h" #include "php_pdo_pgsql_int.h" +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif /* from postgresql/src/include/catalog/pg_type.h */ #define BOOLOID 16 @@ -39,7 +44,6 @@ #define TEXTOID 25 #define OIDOID 26 - static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; @@ -75,7 +79,14 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) efree(S->param_formats); S->param_formats = NULL; } - + if (S->param_types) { + efree(S->param_types); + S->param_types = NULL; + } + if (S->query) { + efree(S->query); + S->query = NULL; + } #endif if (S->cursor_name) { @@ -118,7 +129,8 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) if (S->stmt_name) { /* using a prepared statement */ - if (!stmt->executed) { + if (!S->is_prepared) { +stmt_retry: /* we deferred the prepare until now, because we didn't * know anything about the parameter types; now we do */ S->result = PQprepare(H->server, S->stmt_name, S->query, @@ -129,12 +141,31 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: /* it worked */ + S->is_prepared = 1; PQclear(S->result); break; - default: - pdo_pgsql_error_stmt(stmt, status, - pdo_pgsql_sqlstate(S->result)); - return 0; + default: { + char *sqlstate = pdo_pgsql_sqlstate(S->result); + /* 42P05 means that the prepared statement already existed. this can happen if you use + * a connection pooling software line pgpool which doesn't close the db-connection once + * php disconnects. if php dies (no chanche to run RSHUTDOWN) during execution it has no + * chance to DEALLOCATE the prepared statements it has created. so, if we hit a 42P05 we + * deallocate it and retry ONCE (thies 2005.12.15) + */ + if (!strcmp(sqlstate, "42P05")) { + char buf[100]; /* stmt_name == "pdo_pgsql_cursor_%08x" */ + PGresult *res; + snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name); + res = PQexec(H->server, buf); + if (res) { + PQclear(res); + } + goto stmt_retry; + } else { + pdo_pgsql_error_stmt(stmt, status, sqlstate); + return 0; + } + } } } S->result = PQexecPrepared(H->server, S->stmt_name, @@ -184,6 +215,12 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * #if HAVE_PQPREPARE if (S->stmt_name && param->is_param) { switch (event_type) { + case PDO_PARAM_EVT_FREE: + if (param->driver_data) { + efree(param->driver_data); + } + break; + case PDO_PARAM_EVT_ALLOC: /* decode name from $1, $2 into 0, 1 etc. */ if (param->name) { @@ -224,10 +261,26 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * php_stream *stm; php_stream_from_zval_no_verify(stm, ¶m->parameter); if (stm) { - SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); - Z_TYPE_P(param->parameter) = IS_STRING; - Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm, - &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0); + if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) { + struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract; + pdo_pgsql_bound_param *P = param->driver_data; + + if (P == NULL) { + P = ecalloc(1, sizeof(*P)); + param->driver_data = P; + } + P->oid = htonl(self->oid); + S->param_values[param->paramno] = (char*)&P->oid; + S->param_lengths[param->paramno] = sizeof(P->oid); + S->param_formats[param->paramno] = 1; + S->param_types[param->paramno] = OIDOID; + return 1; + } else { + SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); + Z_TYPE_P(param->parameter) = IS_STRING; + Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm, + &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0); + } } else { /* expected a stream resource */ pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105"); @@ -308,6 +361,7 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; struct pdo_column_data *cols = stmt->columns; + struct pdo_bound_param_data *param; if (!S->result) { return 0; @@ -324,10 +378,25 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) case BOOLOID: cols[colno].param_type = PDO_PARAM_BOOL; break; + + case OIDOID: + /* did the user bind the column as a LOB ? */ + if (stmt->bound_columns && ( + SUCCESS == zend_hash_index_find(stmt->bound_columns, + colno, (void**)¶m) || + SUCCESS == zend_hash_find(stmt->bound_columns, + cols[colno].name, cols[colno].namelen, + (void**)¶m))) { + if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { + cols[colno].param_type = PDO_PARAM_LOB; + break; + } + } + cols[colno].param_type = PDO_PARAM_INT; + break; case INT2OID: case INT4OID: - case OIDOID: cols[colno].param_type = PDO_PARAM_INT; break; @@ -487,9 +556,24 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned break; case PDO_PARAM_LOB: - *ptr = php_pdo_pgsql_unescape_bytea(*ptr, &tmp_len); - *len = tmp_len; - *caller_frees = 1; + if (S->cols[colno].pgsql_type == OIDOID) { + /* ooo, a real large object */ + char *end_ptr; + Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10); + int loid = lo_open(S->H->server, oid, INV_READ); + if (loid >= 0) { + *ptr = (char*)pdo_pgsql_create_lob_stream(stmt->dbh, loid, oid TSRMLS_CC); + *len = 0; + return *ptr ? 1 : 0; + } + *ptr = NULL; + *len = 0; + return 0; + } else { + *ptr = php_pdo_pgsql_unescape_bytea(*ptr, &tmp_len); + *len = tmp_len; + *caller_frees = 1; + } break; case PDO_PARAM_NULL: case PDO_PARAM_STR: diff --git a/ext/pdo_pgsql/php_pdo_pgsql.h b/ext/pdo_pgsql/php_pdo_pgsql.h index eddb7556c..4af13813e 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql.h +++ b/ext/pdo_pgsql/php_pdo_pgsql.h @@ -2,12 +2,12 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 The PHP Group | + | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_pdo_pgsql.h,v 1.3 2005/08/03 14:07:39 sniper Exp $ */ +/* $Id: php_pdo_pgsql.h,v 1.3.2.1 2006/01/01 12:50:12 sniper Exp $ */ #ifndef PHP_PDO_PGSQL_H #define PHP_PDO_PGSQL_H diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index dc2437110..54914042e 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -2,26 +2,29 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2005 The PHP Group | + | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | + | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Edin Kadribasic <edink@emini.dk> | + | Authors: Edin Kadribasic <edink@emini.dk> | + | Ilia Alshanestsky <ilia@prohost.org> | + | Wez Furlong <wez@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: php_pdo_pgsql_int.h,v 1.13.2.1 2005/11/25 03:35:04 wez Exp $ */ +/* $Id: php_pdo_pgsql_int.h,v 1.13.2.4 2006/01/01 12:50:12 sniper Exp $ */ #ifndef PHP_PDO_PGSQL_INT_H #define PHP_PDO_PGSQL_INT_H #include <libpq-fe.h> +#include <libpq/libpq-fs.h> #include <php.h> #define PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE "08006" @@ -62,14 +65,12 @@ typedef struct { int *param_lengths; int *param_formats; Oid *param_types; + zend_bool is_prepared; #endif } pdo_pgsql_stmt; typedef struct { - char *repr; - long repr_len; - int pgsql_type; - void *thing; /* for LOBS, REFCURSORS etc. */ + Oid oid; } pdo_pgsql_bound_param; extern pdo_driver_t pdo_pgsql_driver; @@ -90,6 +91,17 @@ enum { PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT = PDO_ATTR_DRIVER_SPECIFIC, }; +struct pdo_pgsql_lob_self { + pdo_dbh_t *dbh; + PGconn *conn; + int lfd; + Oid oid; +}; + + +php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *stmt, int lfd, Oid oid TSRMLS_DC); +extern php_stream_ops pdo_pgsql_lob_stream_ops; + #endif /* PHP_PDO_PGSQL_INT_H */ /* diff --git a/ext/pdo_pgsql/tests/bug_33876.phpt b/ext/pdo_pgsql/tests/bug_33876.phpt index 1184e7627..fc9d20f69 100644 --- a/ext/pdo_pgsql/tests/bug_33876.phpt +++ b/ext/pdo_pgsql/tests/bug_33876.phpt @@ -3,6 +3,7 @@ PDO PgSQL Bug #33876 --SKIPIF-- <?php if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; PDOTest::skip(); ?> @@ -12,6 +13,7 @@ require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; $db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); +$db->exec("SET LC_MESSAGES='C'"); $db->exec('CREATE TABLE test (foo varchar(5) NOT NULL, bar bool NOT NULL)'); $db->exec("INSERT INTO test VALUES('false','f')"); $db->exec("INSERT INTO test VALUES('true', 't')"); diff --git a/ext/pdo_pgsql/tests/common.phpt b/ext/pdo_pgsql/tests/common.phpt index 383700904..2ecc2025f 100644 --- a/ext/pdo_pgsql/tests/common.phpt +++ b/ext/pdo_pgsql/tests/common.phpt @@ -5,6 +5,7 @@ Postgres if (!extension_loaded('pdo_pgsql')) print 'skip'; ?> --REDIRECTTEST-- # magic auto-configuration +# Also update config.inc if you make changes here... $config = array( 'TESTS' => 'ext/pdo/tests' diff --git a/ext/pdo_pgsql/tests/config.inc b/ext/pdo_pgsql/tests/config.inc new file mode 100644 index 000000000..6d616cddb --- /dev/null +++ b/ext/pdo_pgsql/tests/config.inc @@ -0,0 +1,14 @@ +<?php # vim:se ft=php: +if (false !== getenv('PDO_PGSQL_TEST_DSN')) { + # user set them from their shell + $config['ENV']['PDOTEST_DSN'] = getenv('PDO_PGSQL_TEST_DSN'); + if (false !== getenv('PDO_PGSQL_TEST_ATTR')) { + $config['ENV']['PDOTEST_ATTR'] = getenv('PDO_PGSQL_TEST_ATTR'); + } +} else { + $config['ENV']['PDOTEST_DSN'] = 'pgsql:host=localhost port=5432 dbname=test user=root password='; +} + +foreach ($config['ENV'] as $k => $v) { + putenv("$k=$v"); +} diff --git a/ext/pdo_pgsql/tests/large_objects.phpt b/ext/pdo_pgsql/tests/large_objects.phpt new file mode 100644 index 000000000..f6ee9e29c --- /dev/null +++ b/ext/pdo_pgsql/tests/large_objects.phpt @@ -0,0 +1,61 @@ +--TEST-- +PDO PgSQL Large Objects +--SKIPIF-- +<?php # vim:se ft=php: +if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); +$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); + +$db->exec('CREATE TABLE test (blobid integer not null primary key, bloboid OID)'); + +$db->beginTransaction(); +$oid = $db->pgsqlLOBCreate(); +try { +$stm = $db->pgsqlLOBOpen($oid); +fwrite($stm, "Hello dude\n"); + +$stmt = $db->prepare("INSERT INTO test (blobid, bloboid) values (?, ?)"); +$stmt->bindValue(1, 1); +/* bind as LOB; the oid from the pgsql stream will be inserted instead + * of the stream contents. Binding other streams will attempt to bind + * as bytea, and will most likely lead to an error. + * You can also just bind the $oid in as a string. */ +$stmt->bindParam(2, $stm, PDO::PARAM_LOB); +$stmt->execute(); +$stm = null; + +/* Pull it out */ +$stmt = $db->prepare("SELECT * from test"); +$stmt->execute(); +$stmt->bindColumn('bloboid', $lob, PDO::PARAM_LOB); +echo "Fetching:\n"; +while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) { + var_dump($row['blobid']); + var_dump(stream_get_contents($lob)); +} +echo "Fetched!\n"; +} catch (Exception $e) { + /* catch exceptions so that we can guarantee to clean + * up the LOB */ + echo "Exception! at line ", $e->getLine(), "\n"; + var_dump($e->getMessage()); +} + +/* Now to remove the large object from the database, so it doesn't + * linger and clutter up the storage */ +$db->pgsqlLOBUnlink($oid); + +--EXPECT-- +Fetching: +int(1) +string(11) "Hello dude +" +Fetched! |
