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
->zo
.handle
, obj
, obj
->intern
->txn
->zo
.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 php_pq_object_dtor(o
);
53 php_pqlob_object_t
*php_pqlob_create_object_ex(zend_class_entry
*ce
, php_pqlob_t
*intern
)
55 return php_pq_object_create(ce
, intern
, sizeof(php_pqlob_object_t
),
56 &php_pqlob_object_handlers
, &php_pqlob_object_prophandlers
);
59 static zend_object
*php_pqlob_create_object(zend_class_entry
*class_type
)
61 return &php_pqlob_create_object_ex(class_type
, NULL
)->zo
;
64 static void php_pqlob_object_read_transaction(void *o
, zval
*return_value
)
66 php_pqlob_object_t
*obj
= o
;
68 php_pq_object_to_zval(obj
->intern
->txn
, return_value
);
71 static void php_pqlob_object_gc_transaction(void *o
, zval
*return_value
)
73 php_pqlob_object_t
*obj
= o
;
76 php_pq_object_to_zval_no_addref(obj
->intern
->txn
, &ztxn
);
77 add_next_index_zval(return_value
, &ztxn
);
80 static void php_pqlob_object_read_oid(void *o
, zval
*return_value
)
82 php_pqlob_object_t
*obj
= o
;
84 RETVAL_LONG(obj
->intern
->loid
);
87 static void php_pqlob_object_update_stream(php_pqlob_object_t
*obj
, zval
*zstream
);
89 static void php_pqlob_object_read_stream(void *o
, zval
*return_value
)
91 php_pqlob_object_t
*obj
= o
;
94 if (!obj
->intern
->stream
) {
95 php_pqlob_object_update_stream(obj
, &zstream
);
97 php_stream_to_zval(obj
->intern
->stream
, &zstream
);
100 RETVAL_ZVAL(&zstream
, 1, 0);
103 static ssize_t
php_pqlob_stream_write(php_stream
*stream
, const char *buffer
, size_t length
)
105 php_pqlob_object_t
*obj
= stream
->abstract
;
109 written
= lo_write(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, buffer
, length
);
112 php_error_docref(NULL
, E_WARNING
, "Failed to write to LOB with oid=%u (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
115 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
121 static ssize_t
php_pqlob_stream_read(php_stream
*stream
, char *buffer
, size_t length
)
123 php_pqlob_object_t
*obj
= stream
->abstract
;
128 if (!buffer
&& !length
) {
129 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
)) {
133 read
= lo_read(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, buffer
, length
);
136 php_error_docref(NULL
, E_WARNING
, "Failed to read from LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
140 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
146 static ZEND_RESULT_CODE
php_pqlob_stream_close(php_stream
*stream
, int close_handle
)
151 static int php_pqlob_stream_flush(php_stream
*stream
)
156 static ZEND_RESULT_CODE
php_pqlob_stream_seek(php_stream
*stream
, off_t offset
, int whence
, off_t
*newoffset
)
158 ZEND_RESULT_CODE rv
= FAILURE
;
159 php_pqlob_object_t
*obj
= stream
->abstract
;
162 int position
= lo_lseek(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, offset
, whence
);
165 php_error_docref(NULL
, E_WARNING
, "Failed to seek offset in LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
168 *newoffset
= position
;
172 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
178 static php_stream_ops php_pqlob_stream_ops
= {
179 /* stdio like functions - these are mandatory! */
180 php_pqlob_stream_write
,
181 php_pqlob_stream_read
,
182 php_pqlob_stream_close
,
183 php_pqlob_stream_flush
,
187 /* these are optional */
188 php_pqlob_stream_seek
,
191 NULL
, /* set_option */
194 static void php_pqlob_object_update_stream(php_pqlob_object_t
*obj
, zval
*zstream
)
198 ZVAL_STRINGL(&zmember
, "stream", sizeof("stream")-1);
200 obj
->intern
->stream
= php_stream_alloc(&php_pqlob_stream_ops
, obj
, NULL
, "r+b");
201 obj
->intern
->stream
->flags
|= PHP_STREAM_FLAG_NO_FCLOSE
;
202 php_stream_to_zval(obj
->intern
->stream
, zstream
);
204 #if PHP_VERSION_ID >= 80000
205 zend_std_write_property(&obj
->zo
, Z_STR(zmember
), zstream
, NULL
);
207 ZVAL_OBJ(&zobj
, &obj
->zo
);
208 zend_std_write_property(&zobj
, &zmember
, zstream
, NULL
);
210 zval_ptr_dtor(&zmember
);
213 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct
, 0, 0, 1)
214 ZEND_ARG_OBJ_INFO(0, transaction
, pq
\\Transaction
, 0)
215 ZEND_ARG_INFO(0, oid
)
216 ZEND_ARG_INFO(0, mode
)
218 static PHP_METHOD(pqlob
, __construct
) {
219 zend_error_handling zeh
;
221 zend_long mode
= INV_WRITE
|INV_READ
, loid
= InvalidOid
;
224 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
225 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &ztxn
, php_pqtxn_class_entry
, &loid
, &mode
);
226 zend_restore_error_handling(&zeh
);
229 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
230 php_pqtxn_object_t
*txn_obj
= PHP_PQ_OBJ(ztxn
, NULL
);
233 throw_exce(EX_BAD_METHODCALL
, "pq\\LOB already initialized");
234 } else if (!txn_obj
->intern
) {
235 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
236 } else if (!txn_obj
->intern
->open
) {
237 throw_exce(EX_RUNTIME
, "pq\\Transation already closed");
239 if (loid
== InvalidOid
) {
240 loid
= lo_creat(txn_obj
->intern
->conn
->intern
->conn
, mode
);
243 if (loid
== InvalidOid
) {
244 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
));
246 int lofd
= lo_open(txn_obj
->intern
->conn
->intern
->conn
, loid
, mode
);
249 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
));
251 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
252 obj
->intern
->lofd
= lofd
;
253 obj
->intern
->loid
= loid
;
254 php_pq_object_addref(txn_obj
);
255 obj
->intern
->txn
= txn_obj
;
259 php_pqconn_notify_listeners(txn_obj
->intern
->conn
);
264 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write
, 0, 0, 1)
265 ZEND_ARG_INFO(0, data
)
267 static PHP_METHOD(pqlob
, write
) {
268 zend_error_handling zeh
;
273 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
274 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str
, &data_len
);
275 zend_restore_error_handling(&zeh
);
278 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
281 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
283 int written
= lo_write(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, data_str
, data_len
);
286 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
));
288 RETVAL_LONG(written
);
291 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
296 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read
, 0, 0, 0)
297 ZEND_ARG_INFO(0, length
)
298 ZEND_ARG_INFO(1, read
)
300 static PHP_METHOD(pqlob
, read
) {
301 zend_error_handling zeh
;
302 zend_long length
= 0x1000;
306 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
307 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|lz!", &length
, &zread
);
308 zend_restore_error_handling(&zeh
);
311 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
314 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
316 zend_string
*buffer
= zend_string_alloc(length
, 0);
317 int read
= lo_read(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, &buffer
->val
[0], length
);
320 zend_string_release(buffer
);
321 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
));
326 ZVAL_LONG(zread
, read
);
328 buffer
->val
[buffer
->len
= read
] = '\0';
332 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
337 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek
, 0, 0, 1)
338 ZEND_ARG_INFO(0, offset
)
339 ZEND_ARG_INFO(0, whence
)
341 static PHP_METHOD(pqlob
, seek
) {
342 zend_error_handling zeh
;
343 zend_long offset
, whence
= SEEK_SET
;
346 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
347 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &offset
, &whence
);
348 zend_restore_error_handling(&zeh
);
351 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
354 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
356 int position
= lo_lseek(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, offset
, whence
);
359 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
));
361 RETVAL_LONG(position
);
364 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
369 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell
, 0, 0, 0)
371 static PHP_METHOD(pqlob
, tell
) {
372 zend_error_handling zeh
;
375 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
376 rv
= zend_parse_parameters_none();
377 zend_restore_error_handling(&zeh
);
380 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
383 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
385 int position
= lo_tell(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
);
388 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
));
390 RETVAL_LONG(position
);
393 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
398 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate
, 0, 0, 0)
399 ZEND_ARG_INFO(0, length
)
401 static PHP_METHOD(pqlob
, truncate
) {
402 zend_error_handling zeh
;
403 zend_long length
= 0;
406 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
407 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &length
);
408 zend_restore_error_handling(&zeh
);
411 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
414 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
416 int rc
= lo_truncate(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, length
);
419 throw_exce(EX_RUNTIME
, "Failed to truncate LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
422 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
427 static zend_function_entry php_pqlob_methods
[] = {
428 PHP_ME(pqlob
, __construct
, ai_pqlob_construct
, ZEND_ACC_PUBLIC
)
429 PHP_ME(pqlob
, write
, ai_pqlob_write
, ZEND_ACC_PUBLIC
)
430 PHP_ME(pqlob
, read
, ai_pqlob_read
, ZEND_ACC_PUBLIC
)
431 PHP_ME(pqlob
, seek
, ai_pqlob_seek
, ZEND_ACC_PUBLIC
)
432 PHP_ME(pqlob
, tell
, ai_pqlob_tell
, ZEND_ACC_PUBLIC
)
433 PHP_ME(pqlob
, truncate
, ai_pqlob_truncate
, ZEND_ACC_PUBLIC
)
437 PHP_MSHUTDOWN_FUNCTION(pqlob
)
439 zend_hash_destroy(&php_pqlob_object_prophandlers
);
443 PHP_MINIT_FUNCTION(pqlob
)
445 zend_class_entry ce
= {0};
446 php_pq_object_prophandler_t ph
= {0};
448 INIT_NS_CLASS_ENTRY(ce
, "pq", "LOB", php_pqlob_methods
);
449 php_pqlob_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
450 php_pqlob_class_entry
->create_object
= php_pqlob_create_object
;
452 memcpy(&php_pqlob_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
453 php_pqlob_object_handlers
.offset
= XtOffsetOf(php_pqlob_object_t
, zo
);
454 php_pqlob_object_handlers
.free_obj
= php_pqlob_object_free
;
455 php_pqlob_object_handlers
.read_property
= php_pq_object_read_prop
;
456 php_pqlob_object_handlers
.write_property
= php_pq_object_write_prop
;
457 php_pqlob_object_handlers
.clone_obj
= NULL
;
458 php_pqlob_object_handlers
.get_property_ptr_ptr
= php_pq_object_get_prop_ptr_null
;
459 php_pqlob_object_handlers
.get_gc
= php_pq_object_get_gc
;
460 php_pqlob_object_handlers
.get_properties
= php_pq_object_properties
;
461 php_pqlob_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
463 zend_hash_init(&php_pqlob_object_prophandlers
, 3, NULL
, php_pq_object_prophandler_dtor
, 1);
465 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC
);
466 ph
.read
= php_pqlob_object_read_transaction
;
467 ph
.gc
= php_pqlob_object_gc_transaction
;
468 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "transaction", sizeof("transaction")-1, (void *) &ph
, sizeof(ph
));
471 zend_declare_property_long(php_pqlob_class_entry
, ZEND_STRL("oid"), InvalidOid
, ZEND_ACC_PUBLIC
);
472 ph
.read
= php_pqlob_object_read_oid
;
473 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "oid", sizeof("oid")-1, (void *) &ph
, sizeof(ph
));
475 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("stream"), ZEND_ACC_PUBLIC
);
476 ph
.read
= php_pqlob_object_read_stream
;
477 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "stream", sizeof("stream")-1, (void *) &ph
, sizeof(ph
));
479 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("INVALID_OID"), InvalidOid
);
480 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("R"), INV_READ
);
481 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("W"), INV_WRITE
);
482 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("RW"), INV_READ
|INV_WRITE
);
492 * vim600: noet sw=4 ts=4 fdm=marker
493 * vim<600: noet sw=4 ts=4