2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
17 #include <libpq-events.h>
18 #include <libpq/libpq-fs.h>
22 #include "php_pq_misc.h"
23 #include "php_pq_object.h"
24 #include "php_pqexc.h"
25 #include "php_pqlob.h"
27 zend_class_entry
*php_pqlob_class_entry
;
28 static zend_object_handlers php_pqlob_object_handlers
;
29 static HashTable php_pqlob_object_prophandlers
;
31 static void php_pqlob_object_free(zend_object
*o
)
33 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
35 fprintf(stderr
, "FREE lob(#%d) %p (txn(#%d): %p)\n", obj
->zv
.handle
, obj
, obj
->intern
->txn
->zv
.handle
, obj
->intern
->txn
);
38 if (obj
->intern
->lofd
) {
39 lo_close(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
);
41 /* invalidate the stream */
42 if (obj
->intern
->stream
) {
43 zend_list_delete(obj
->intern
->stream
->res
);
44 obj
->intern
->stream
= NULL
;
46 php_pq_object_delref(obj
->intern
->txn
);
50 zend_object_std_dtor(o
);
54 php_pqlob_object_t
*php_pqlob_create_object_ex(zend_class_entry
*ce
, php_pqlob_t
*intern
)
56 php_pqlob_object_t
*o
;
58 o
= ecalloc(1, sizeof(*o
) + zend_object_properties_size(ce
));
59 zend_object_std_init(&o
->zo
, ce
);
60 object_properties_init(&o
->zo
, ce
);
61 o
->prophandler
= &php_pqlob_object_prophandlers
;
67 o
->zo
.handlers
= &php_pqlob_object_handlers
;
72 static zend_object
*php_pqlob_create_object(zend_class_entry
*class_type
)
74 return &php_pqlob_create_object_ex(class_type
, NULL
)->zo
;
77 static void php_pqlob_object_read_transaction(zval
*object
, void *o
, zval
*return_value
)
79 php_pqlob_object_t
*obj
= o
;
81 php_pq_object_to_zval(obj
->intern
->txn
, return_value
);
84 static void php_pqlob_object_read_oid(zval
*object
, void *o
, zval
*return_value
)
86 php_pqlob_object_t
*obj
= o
;
88 RETVAL_LONG(obj
->intern
->loid
);
91 static void php_pqlob_object_update_stream(zval
*this_ptr
, php_pqlob_object_t
*obj
, zval
*zstream
);
93 static void php_pqlob_object_read_stream(zval
*object
, void *o
, zval
*return_value
)
95 php_pqlob_object_t
*obj
= o
;
98 if (!obj
->intern
->stream
) {
99 php_pqlob_object_update_stream(object
, obj
, &zstream
);
101 php_stream_to_zval(obj
->intern
->stream
, &zstream
);
104 RETVAL_ZVAL(&zstream
, 1, 1);
107 static size_t php_pqlob_stream_write(php_stream
*stream
, const char *buffer
, size_t length TSRMLS_DC
)
109 php_pqlob_object_t
*obj
= stream
->abstract
;
113 written
= lo_write(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, buffer
, length
);
116 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
));
119 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn TSRMLS_CC
);
125 static size_t php_pqlob_stream_read(php_stream
*stream
, char *buffer
, size_t length TSRMLS_DC
)
127 php_pqlob_object_t
*obj
= stream
->abstract
;
132 if (!buffer
&& !length
) {
133 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
)) {
137 read
= lo_read(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, buffer
, length
);
140 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
));
144 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn TSRMLS_CC
);
150 static ZEND_RESULT_CODE
php_pqlob_stream_close(php_stream
*stream
, int close_handle TSRMLS_DC
)
155 static int php_pqlob_stream_flush(php_stream
*stream TSRMLS_DC
)
160 static ZEND_RESULT_CODE
php_pqlob_stream_seek(php_stream
*stream
, off_t offset
, int whence
, off_t
*newoffset TSRMLS_DC
)
162 ZEND_RESULT_CODE rv
= FAILURE
;
163 php_pqlob_object_t
*obj
= stream
->abstract
;
166 int position
= lo_lseek(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, offset
, whence
);
169 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
));
172 *newoffset
= position
;
176 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn TSRMLS_CC
);
182 static php_stream_ops php_pqlob_stream_ops
= {
183 /* stdio like functions - these are mandatory! */
184 php_pqlob_stream_write
,
185 php_pqlob_stream_read
,
186 php_pqlob_stream_close
,
187 php_pqlob_stream_flush
,
191 /* these are optional */
192 php_pqlob_stream_seek
,
195 NULL
, /* set_option */
198 static void php_pqlob_object_update_stream(zval
*zpqlob
, php_pqlob_object_t
*obj
, zval
*zstream
)
202 ZVAL_STRINGL(&zmember
, "stream", sizeof("stream")-1);
205 obj
= PHP_PQ_OBJ(zpqlob
, NULL
);
207 obj
->intern
->stream
= php_stream_alloc(&php_pqlob_stream_ops
, obj
, NULL
, "r+b");
208 obj
->intern
->stream
->flags
|= PHP_STREAM_FLAG_NO_FCLOSE
;
209 php_stream_to_zval(obj
->intern
->stream
, zstream
);
211 zend_get_std_object_handlers()->write_property(zpqlob
, &zmember
, zstream
, NULL
);
214 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct
, 0, 0, 1)
215 ZEND_ARG_OBJ_INFO(0, transaction
, pq
\\Transaction
, 0)
216 ZEND_ARG_INFO(0, oid
)
217 ZEND_ARG_INFO(0, mode
)
219 static PHP_METHOD(pqlob
, __construct
) {
220 zend_error_handling zeh
;
222 zend_long mode
= INV_WRITE
|INV_READ
, loid
= InvalidOid
;
225 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
226 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &ztxn
, php_pqtxn_class_entry
, &loid
, &mode
);
227 zend_restore_error_handling(&zeh
);
230 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
231 php_pqtxn_object_t
*txn_obj
= PHP_PQ_OBJ(ztxn
, NULL
);
234 throw_exce(EX_BAD_METHODCALL
, "pq\\LOB already initialized");
235 } else if (!txn_obj
->intern
) {
236 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
237 } else if (!txn_obj
->intern
->open
) {
238 throw_exce(EX_RUNTIME
, "pq\\Transation already closed");
240 if (loid
== InvalidOid
) {
241 loid
= lo_creat(txn_obj
->intern
->conn
->intern
->conn
, mode
);
244 if (loid
== InvalidOid
) {
245 throw_exce(EX_RUNTIME
, "Failed to create large object with mode '%s' (%s)", php_pq_strmode(mode
), PHP_PQerrorMessage(txn_obj
->intern
->conn
->intern
->conn
));
247 int lofd
= lo_open(txn_obj
->intern
->conn
->intern
->conn
, loid
, mode
);
250 throw_exce(EX_RUNTIME
, "Failed to open large object with oid=%u with mode '%s' (%s)", loid
, php_pq_strmode(mode
), PHP_PQerrorMessage(txn_obj
->intern
->conn
->intern
->conn
));
252 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
253 obj
->intern
->lofd
= lofd
;
254 obj
->intern
->loid
= loid
;
255 php_pq_object_addref(txn_obj
);
256 obj
->intern
->txn
= txn_obj
;
260 php_pqconn_notify_listeners(txn_obj
->intern
->conn
);
265 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write
, 0, 0, 1)
266 ZEND_ARG_INFO(0, data
)
268 static PHP_METHOD(pqlob
, write
) {
269 zend_error_handling zeh
;
274 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
275 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str
, &data_len
);
276 zend_restore_error_handling(&zeh
);
279 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
282 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
284 int written
= lo_write(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, data_str
, data_len
);
287 throw_exce(EX_RUNTIME
, "Failed to write to LOB with oid=%u (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
289 RETVAL_LONG(written
);
292 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
297 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read
, 0, 0, 0)
298 ZEND_ARG_INFO(0, length
)
299 ZEND_ARG_INFO(1, read
)
301 static PHP_METHOD(pqlob
, read
) {
302 zend_error_handling zeh
;
303 zend_long length
= 0x1000;
307 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
308 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|lz!", &length
, &zread
);
309 zend_restore_error_handling(&zeh
);
312 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
315 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
317 zend_string
*buffer
= zend_string_alloc(length
, 0);
318 int read
= lo_read(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, &buffer
->val
[0], length
);
321 zend_string_release(buffer
);
322 throw_exce(EX_RUNTIME
, "Failed to read from LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
327 ZVAL_LONG(zread
, read
);
329 buffer
->val
[buffer
->len
= read
] = '\0';
333 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
338 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek
, 0, 0, 1)
339 ZEND_ARG_INFO(0, offset
)
340 ZEND_ARG_INFO(0, whence
)
342 static PHP_METHOD(pqlob
, seek
) {
343 zend_error_handling zeh
;
344 zend_long offset
, whence
= SEEK_SET
;
347 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
348 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &offset
, &whence
);
349 zend_restore_error_handling(&zeh
);
352 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
355 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
357 int position
= lo_lseek(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, offset
, whence
);
360 throw_exce(EX_RUNTIME
, "Failed to seek offset in LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
362 RETVAL_LONG(position
);
365 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
370 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell
, 0, 0, 0)
372 static PHP_METHOD(pqlob
, tell
) {
373 zend_error_handling zeh
;
376 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
377 rv
= zend_parse_parameters_none();
378 zend_restore_error_handling(&zeh
);
381 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
384 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
386 int position
= lo_tell(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
);
389 throw_exce(EX_RUNTIME
, "Failed to tell offset in LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
391 RETVAL_LONG(position
);
394 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
399 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate
, 0, 0, 0)
400 ZEND_ARG_INFO(0, length
)
402 static PHP_METHOD(pqlob
, truncate
) {
403 zend_error_handling zeh
;
404 zend_long length
= 0;
407 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
408 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &length
);
409 zend_restore_error_handling(&zeh
);
412 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
415 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
417 int rc
= lo_truncate(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, length
);
420 throw_exce(EX_RUNTIME
, "Failed to truncate LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
423 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
428 static zend_function_entry php_pqlob_methods
[] = {
429 PHP_ME(pqlob
, __construct
, ai_pqlob_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
430 PHP_ME(pqlob
, write
, ai_pqlob_write
, ZEND_ACC_PUBLIC
)
431 PHP_ME(pqlob
, read
, ai_pqlob_read
, ZEND_ACC_PUBLIC
)
432 PHP_ME(pqlob
, seek
, ai_pqlob_seek
, ZEND_ACC_PUBLIC
)
433 PHP_ME(pqlob
, tell
, ai_pqlob_tell
, ZEND_ACC_PUBLIC
)
434 PHP_ME(pqlob
, truncate
, ai_pqlob_truncate
, ZEND_ACC_PUBLIC
)
438 PHP_MSHUTDOWN_FUNCTION(pqlob
)
440 zend_hash_destroy(&php_pqlob_object_prophandlers
);
444 PHP_MINIT_FUNCTION(pqlob
)
446 zend_class_entry ce
= {0};
447 php_pq_object_prophandler_t ph
= {0};
449 INIT_NS_CLASS_ENTRY(ce
, "pq", "LOB", php_pqlob_methods
);
450 php_pqlob_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
451 php_pqlob_class_entry
->create_object
= php_pqlob_create_object
;
453 memcpy(&php_pqlob_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
454 php_pqlob_object_handlers
.offset
= XtOffsetOf(php_pqlob_object_t
, zo
);
455 php_pqlob_object_handlers
.free_obj
= php_pqlob_object_free
;
456 php_pqlob_object_handlers
.read_property
= php_pq_object_read_prop
;
457 php_pqlob_object_handlers
.write_property
= php_pq_object_write_prop
;
458 php_pqlob_object_handlers
.clone_obj
= NULL
;
459 php_pqlob_object_handlers
.get_property_ptr_ptr
= NULL
;
460 php_pqlob_object_handlers
.get_gc
= NULL
;
461 php_pqlob_object_handlers
.get_properties
= php_pq_object_properties
;
462 php_pqlob_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
464 zend_hash_init(&php_pqlob_object_prophandlers
, 3, NULL
, NULL
, 1);
466 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC
);
467 ph
.read
= php_pqlob_object_read_transaction
;
468 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "transaction", sizeof("transaction")-1, (void *) &ph
, sizeof(ph
));
470 zend_declare_property_long(php_pqlob_class_entry
, ZEND_STRL("oid"), InvalidOid
, ZEND_ACC_PUBLIC
);
471 ph
.read
= php_pqlob_object_read_oid
;
472 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "oid", sizeof("oid"), (void *) &ph
, sizeof(ph
));
474 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("stream"), ZEND_ACC_PUBLIC
);
475 ph
.read
= php_pqlob_object_read_stream
;
476 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "stream", sizeof("stream"), (void *) &ph
, sizeof(ph
));
478 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("INVALID_OID"), InvalidOid
);
479 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("R"), INV_READ
);
480 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("W"), INV_WRITE
);
481 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("RW"), INV_READ
|INV_WRITE
);
491 * vim600: noet sw=4 ts=4 fdm=marker
492 * vim<600: noet sw=4 ts=4