]> granicus.if.org Git - php/commitdiff
Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink().
authorWez Furlong <wez@php.net>
Tue, 29 Nov 2005 02:11:39 +0000 (02:11 +0000)
committerWez Furlong <wez@php.net>
Tue, 29 Nov 2005 02:11:39 +0000 (02:11 +0000)
ext/pdo_pgsql/package.xml
ext/pdo_pgsql/pdo_pgsql.c
ext/pdo_pgsql/pgsql_driver.c
ext/pdo_pgsql/pgsql_statement.c
ext/pdo_pgsql/php_pdo_pgsql_int.h
ext/pdo_pgsql/tests/bug_33876.phpt
ext/pdo_pgsql/tests/common.phpt
ext/pdo_pgsql/tests/config.inc [new file with mode: 0644]
ext/pdo_pgsql/tests/large_objects.phpt [new file with mode: 0644]

index 2f093a9efa3d9f86955d5bd5403fccfcabe2f7ac..d5086be5f93a3997dd28e754723ad753f82d4b33 100644 (file)
@@ -30,8 +30,8 @@
  <license>PHP</license>\r
  <release>\r
   <state>stable</state>\r
-  <version>1.0</version>\r
-  <date>2005-11-26</date>\r
+  <version>1.0.1</version>\r
+  <date>2005-11-28</date>\r
 \r
   <notes>\r
 Now features native prepared statements and numerous other improvements.\r
@@ -42,6 +42,8 @@ intend to build and/or use it.
 \r
 If you are running on windows, you can download the binary from here:\r
 http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll\r
+\r
+Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink().\r
   </notes>\r
 \r
   <filelist>\r
@@ -57,7 +59,7 @@ http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll
   </filelist>\r
   <deps>\r
    <dep type="php" rel="ge" version="5.0.3"/>\r
-   <dep type="ext" rel="ge" name="pdo" version="1.0"/>\r
+   <dep type="ext" rel="ge" name="pdo" version="1.0.2"/>\r
   </deps>\r
  </release>\r
 </package>\r
index d812cb1d8a87bc718f15ad2f61cff07edda7d6ec..6a5bae36671a8444afc1d2c0605047ea217b8020 100644 (file)
@@ -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.1",
        STANDARD_MODULE_PROPERTIES
 };
 /* }}} */
index 96d2202536aa10f1736a1976fb2b65df6dc7b270..7345745b23f764a25adb6b13c8e0542b3bc7370b 100644 (file)
@@ -12,7 +12,9 @@
   | 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>                                   |
   +----------------------------------------------------------------------+
 */
 
@@ -108,6 +110,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_DC);
+       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;
@@ -397,6 +474,124 @@ static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
        return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC);
 }
 
+/* {{{ string pgSQL::pgsqlLOBCreate()
+   Creates a new large object, returning its identifier.  Must be called inside a transaction. */
+static PHP_METHOD(pgSQL, 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", lfd);
+               RETURN_STRING(buf, 0);
+       }
+       
+       pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ resource pgSQL::pgsqlLOBOpen(string oid [, string mode = 'rb'])
+   Opens an existing large object stream.  Must be called inside a transaction. */
+static PHP_METHOD(pgSQL, 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;
+}
+/* }}} */
+
+/* {{{ bool pgSQL::pgsqlLOBUnlink(int oid)
+   Deletes the large object identified by oid.  Must be called inside a transaction. */
+static PHP_METHOD(pgSQL, pgsqlLOBUnlink)
+{
+       pdo_dbh_t *dbh;
+       pdo_pgsql_db_handle *H;
+       long lfd;
+
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
+                               &lfd)) {
+               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, lfd)) {
+               RETURN_TRUE;
+       }
+       pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
+       RETURN_FALSE;
+}
+
+
+
+static function_entry dbh_methods[] = {
+       PHP_ME(pgSQL, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
+       PHP_ME(pgSQL, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
+       PHP_ME(pgSQL, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
+       {NULL, NULL, NULL}
+};
+
+static 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 +605,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 +657,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;
index fed9741513db130b3f4a2230c208d394cbc38729..088694b1057c73142d2975a4bd6fb11bba537eb9 100644 (file)
@@ -12,7 +12,9 @@
   | 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>                                   |
   +----------------------------------------------------------------------+
 */
 
@@ -39,7 +41,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;
@@ -184,6 +185,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 +231,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, &param->parameter);
                                                if (stm) {
-                                                       SEPARATE_ZVAL_IF_NOT_REF(&param->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(&param->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 +331,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 +348,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**)&param) ||
+                                       SUCCESS == zend_hash_find(stmt->bound_columns,
+                                               cols[colno].name, cols[colno].namelen,
+                                               (void**)&param))) {
+                               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 +526,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:
index 1b48f63ee1cb30d9ad6962ce3545f60882fea4b2..5f799161cd62cdade44af2958fbfb969b9dcbbe7 100644 (file)
@@ -12,7 +12,9 @@
   | 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>                                   |
   +----------------------------------------------------------------------+
 */
 
@@ -22,6 +24,7 @@
 #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"
@@ -66,10 +69,7 @@ typedef struct {
 } 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 +90,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 */
 
 /*
index 1184e7627e67812c3e0a9ccc1280c8912630aee6..725d44db9d848dbee2255f7c7b5d18b3b9b26677 100644 (file)
@@ -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();
 ?>
index 383700904c54de8611990c849f09443dbb42d747..2ecc2025f04fd1d8150e161336b197ec929ee1b2 100644 (file)
@@ -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 (file)
index 0000000..6d616cd
--- /dev/null
@@ -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 (file)
index 0000000..f6ee9e2
--- /dev/null
@@ -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!