typedef struct php_pqlob {
int lofd;
Oid loid;
+ int stream;
php_pqtxn_object_t *txn;
} php_pqlob_t;
}
}
- for (c = 0, cols = PQnfields(res); c < cols; ++c) {
- if (PQgetisnull(res, row, c)) {
- switch (fetch_type) {
- case PHP_PQRES_FETCH_OBJECT:
- add_property_null(data, PQfname(res, c));
- break;
+ if (PQntuples(res) > row) {
+ for (c = 0, cols = PQnfields(res); c < cols; ++c) {
+ if (PQgetisnull(res, row, c)) {
+ switch (fetch_type) {
+ case PHP_PQRES_FETCH_OBJECT:
+ add_property_null(data, PQfname(res, c));
+ break;
- case PHP_PQRES_FETCH_ASSOC:
- add_assoc_null(data, PQfname(res, c));
- break;
+ case PHP_PQRES_FETCH_ASSOC:
+ add_assoc_null(data, PQfname(res, c));
+ break;
- case PHP_PQRES_FETCH_ARRAY:
- add_index_null(data, c);
- break;
- }
- } else {
- char *val = PQgetvalue(res, row, c);
- int len = PQgetlength(res, row, c);
+ case PHP_PQRES_FETCH_ARRAY:
+ add_index_null(data, c);
+ break;
+ }
+ } else {
+ char *val = PQgetvalue(res, row, c);
+ int len = PQgetlength(res, row, c);
- switch (fetch_type) {
- case PHP_PQRES_FETCH_OBJECT:
- add_property_stringl(data, PQfname(res, c), val, len, 1);
- break;
+ switch (fetch_type) {
+ case PHP_PQRES_FETCH_OBJECT:
+ add_property_stringl(data, PQfname(res, c), val, len, 1);
+ break;
- case PHP_PQRES_FETCH_ASSOC:
- add_assoc_stringl(data, PQfname(res, c), val, len, 1);
- break;
+ case PHP_PQRES_FETCH_ASSOC:
+ add_assoc_stringl(data, PQfname(res, c), val, len, 1);
+ break;
- case PHP_PQRES_FETCH_ARRAY:
- add_index_stringl(data, c, val, len ,1);
- break;
+ case PHP_PQRES_FETCH_ARRAY:
+ add_index_stringl(data, c, val, len ,1);
+ break;
+ }
}
}
}
php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
- if (iter->current_val) {
- zval_ptr_dtor(&iter->current_val);
+ if (!iter->current_val) {
+ iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC);
}
- iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC);
*data_ptr = &iter->current_val;
}
return HASH_KEY_IS_LONG;
}
+static void php_pqres_iterator_invalidate(zend_object_iterator *i TSRMLS_DC)
+{
+ php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+
+ if (iter->current_val) {
+ zval_ptr_dtor(&iter->current_val);
+ iter->current_val = NULL;
+ }
+}
+
static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
{
php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+ php_pqres_iterator_invalidate(i TSRMLS_CC);
++iter->index;
}
{
php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+ php_pqres_iterator_invalidate(i TSRMLS_CC);
iter->index = 0;
}
/* rewind to start of data (optional, may be NULL) */
php_pqres_iterator_rewind,
/* invalidate current value/key (optional, may be NULL) */
- NULL
+ php_pqres_iterator_invalidate
};
static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC)
if (obj->intern->lofd) {
lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd);
}
+ /* invalidate the stream */
+ if (obj->intern->stream) {
+ zend_list_delete(obj->intern->stream);
+ obj->intern->stream = 0;
+ }
php_pq_object_delref(obj->intern->txn TSRMLS_CC);
efree(obj->intern);
obj->intern = NULL;
RETVAL_LONG(obj->intern->loid);
}
+static void php_pqlob_object_update_stream(zval *this_ptr, php_pqlob_object_t *obj, zval **zstream TSRMLS_DC);
+
+static void php_pqlob_object_read_stream(zval *object, void *o, zval *return_value TSRMLS_DC)
+{
+ php_pqlob_object_t *obj = o;
+
+ if (!obj->intern->stream) {
+ zval *zstream;
+
+ php_pqlob_object_update_stream(object, obj, &zstream TSRMLS_CC);
+ RETVAL_ZVAL(zstream, 1, 1);
+ } else {
+ RETVAL_RESOURCE(obj->intern->stream);
+ zend_list_addref(obj->intern->stream);
+ }
+}
+
static void php_pqcopy_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
{
php_pqcopy_object_t *obj = o;
php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
if (!obj->intern) {
- throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connectio not initialized");
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
} else {
PGresult *res = PQgetResult(obj->intern->conn);
obj = zend_object_store_get_object(getThis() TSRMLS_CC);
}
- if (!obj->intern->iter) {
+ if (obj->intern->iter) {
+ obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
+ } else {
obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
}
obj->intern->iter->fetch_type = fetch_type;
if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC))) {
obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, row TSRMLS_CC);
- obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
}
obj->intern->iter->fetch_type = orig_fetch;
int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode);
if (lofd < 0) {
- throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
} else {
php_pqlob_t *lob = ecalloc(1, sizeof(*lob));
int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode);
if (lofd < 0) {
- throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s': %s", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s': %s", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
} else {
php_pqlob_t *lob = ecalloc(1, sizeof(*lob));
int rc = lo_unlink(obj->intern->conn->intern->conn, loid);
if (rc != 1) {
- throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to unlink LOB (oid=%ld): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to unlink LOB (oid=%u): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ }
+
+ php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_lob, 0, 0, 1)
+ ZEND_ARG_INFO(0, local_path)
+ ZEND_ARG_INFO(0, oid)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqtxn, importLOB) {
+ zend_error_handling zeh;
+ char *path_str;
+ int path_len;
+ long oid = InvalidOid;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l", &path_str, &path_len, &oid);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (rv == SUCCESS) {
+ php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
+ } else {
+ if (oid == InvalidOid) {
+ oid = lo_import(obj->intern->conn->intern->conn, path_str);
+ } else {
+ oid = lo_import_with_oid(obj->intern->conn->intern->conn, path_str, oid);
+ }
+
+ if (oid == InvalidOid) {
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to import LOB from '%s' (%s)", path_str, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ } else {
+ RETVAL_LONG(oid);
+ }
+
+ php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_lob, 0, 0, 2)
+ ZEND_ARG_INFO(0, oid)
+ ZEND_ARG_INFO(0, local_path)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqtxn, exportLOB) {
+ zend_error_handling zeh;
+ char *path_str;
+ int path_len;
+ long oid;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lp", &oid, &path_str, &path_len);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (rv == SUCCESS) {
+ php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
+ } else {
+ int rc = lo_export(obj->intern->conn->intern->conn, oid, path_str);
+
+ if (rc == -1) {
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to export LOB (oid=%u) to '%s' (%s)", oid, path_str, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
}
php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
PHP_ME(pqtxn, openLOB, ai_pqtxn_open_lob, ZEND_ACC_PUBLIC)
PHP_ME(pqtxn, createLOB, ai_pqtxn_create_lob, ZEND_ACC_PUBLIC)
PHP_ME(pqtxn, unlinkLOB, ai_pqtxn_unlink_lob, ZEND_ACC_PUBLIC)
+ PHP_ME(pqtxn, importLOB, ai_pqtxn_import_lob, ZEND_ACC_PUBLIC)
+ PHP_ME(pqtxn, exportLOB, ai_pqtxn_export_lob, ZEND_ACC_PUBLIC)
{0}
};
{0}
};
+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);
+ }
+}
+
ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, transaction, pq\\Transaction, 0)
ZEND_ARG_INFO(0, oid)
int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode);
if (lofd < 0) {
- throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn));
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn));
} else {
php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len);
if (written < 0) {
- throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to write to LOB with oid=%ld (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
} else {
RETVAL_LONG(written);
}
php_pqlob_object_handlers.get_property_ptr_ptr = NULL;
php_pqlob_object_handlers.get_debug_info = php_pq_object_debug_info;
- zend_hash_init(&php_pqlob_object_prophandlers, 2, NULL, NULL, 1);
+ zend_hash_init(&php_pqlob_object_prophandlers, 3, NULL, NULL, 1);
zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC TSRMLS_CC);
ph.read = php_pqlob_object_read_transaction;
ph.read = php_pqlob_object_read_oid;
zend_hash_add(&php_pqlob_object_prophandlers, "oid", sizeof("oid"), (void *) &ph, sizeof(ph), NULL);
+ zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("stream"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ ph.read = php_pqlob_object_read_stream;
+ zend_hash_add(&php_pqlob_object_prophandlers, "stream", sizeof("stream"), (void *) &ph, sizeof(ph), NULL);
+
zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("INVALID_OID"), InvalidOid TSRMLS_CC);
zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("R"), INV_READ TSRMLS_CC);
zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("W"), INV_WRITE TSRMLS_CC);