+static size_t php_pqlob_stream_write(php_stream *stream, const char *buffer, size_t length TSRMLS_DC)
+{
+ php_pqlob_object_t *obj = stream->abstract;
+ int written = 0;
+
+ if (obj) {
+ written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length);
+
+ if (written < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ }
+
+ php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
+ }
+
+ return written;
+}
+
+static size_t php_pqlob_stream_read(php_stream *stream, char *buffer, size_t length TSRMLS_DC)
+{
+ php_pqlob_object_t *obj = stream->abstract;
+ int read = 0;
+
+ if (obj) {
+
+ if (!buffer && !length) {
+ if (lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd) == lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, 0, SEEK_CUR)) {
+ return EOF;
+ }
+ } else {
+ read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length);
+
+ if (read < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ }
+ }
+
+ php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
+ }
+
+ return read;
+}
+
+static STATUS php_pqlob_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ return SUCCESS;
+}
+
+static int php_pqlob_stream_flush(php_stream *stream TSRMLS_DC)
+{
+ return SUCCESS;
+}
+
+static STATUS php_pqlob_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
+{
+ STATUS rv = FAILURE;
+ php_pqlob_object_t *obj = stream->abstract;
+
+ if (obj) {
+ int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence);
+
+ if (position < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ rv = FAILURE;
+ } else {
+ *newoffset = position;
+ rv = SUCCESS;
+ }
+
+ php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
+ }
+
+ return rv;
+}
+
+static php_stream_ops php_pqlob_stream_ops = {
+ /* stdio like functions - these are mandatory! */
+ php_pqlob_stream_write,
+ php_pqlob_stream_read,
+ php_pqlob_stream_close,
+ php_pqlob_stream_flush,
+
+ "pq\\LOB stream",
+
+ /* these are optional */
+ php_pqlob_stream_seek,
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL, /* set_option */
+};
+
+static void php_pqlob_object_update_stream(zval *this_ptr, php_pqlob_object_t *obj, zval **zstream_ptr TSRMLS_DC)
+{
+ zval *zstream, zmember;
+ php_stream *stream;
+
+ INIT_PZVAL(&zmember);
+ ZVAL_STRINGL(&zmember, "stream", sizeof("stream")-1, 0);
+
+ MAKE_STD_ZVAL(zstream);
+ if (!obj) {
+ obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ }
+ stream = php_stream_alloc(&php_pqlob_stream_ops, obj, NULL, "r+b");
+ stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
+ zend_list_addref(obj->intern->stream = stream->rsrc_id);
+ php_stream_to_zval(stream, zstream);
+
+ zend_get_std_object_handlers()->write_property(getThis(), &zmember, zstream, NULL TSRMLS_CC);
+
+ if (zstream_ptr) {
+ *zstream_ptr = zstream;
+ } else {
+ zval_ptr_dtor(&zstream);
+ }
+}
+