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(zval
*object
, 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(zval
*object
, 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(zval
*object
, 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(zval
*this_ptr
, php_pqlob_object_t
*obj
, zval
*zstream
);
89 static void php_pqlob_object_read_stream(zval
*object
, void *o
, zval
*return_value
)
91 php_pqlob_object_t
*obj
= o
;
94 if (!obj
->intern
->stream
) {
95 php_pqlob_object_update_stream(object
, obj
, &zstream
);
97 php_stream_to_zval(obj
->intern
->stream
, &zstream
);
100 RETVAL_ZVAL(&zstream
, 1, 0);
103 static size_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 size_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(zval
*zpqlob
, php_pqlob_object_t
*obj
, zval
*zstream
)
198 ZVAL_STRINGL(&zmember
, "stream", sizeof("stream")-1);
201 obj
= PHP_PQ_OBJ(zpqlob
, NULL
);
203 obj
->intern
->stream
= php_stream_alloc(&php_pqlob_stream_ops
, obj
, NULL
, "r+b");
204 obj
->intern
->stream
->flags
|= PHP_STREAM_FLAG_NO_FCLOSE
;
205 php_stream_to_zval(obj
->intern
->stream
, zstream
);
207 zend_get_std_object_handlers()->write_property(zpqlob
, &zmember
, zstream
, NULL
);
208 zval_ptr_dtor(&zmember
);
211 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct
, 0, 0, 1)
212 ZEND_ARG_OBJ_INFO(0, transaction
, pq
\\Transaction
, 0)
213 ZEND_ARG_INFO(0, oid
)
214 ZEND_ARG_INFO(0, mode
)
216 static PHP_METHOD(pqlob
, __construct
) {
217 zend_error_handling zeh
;
219 zend_long mode
= INV_WRITE
|INV_READ
, loid
= InvalidOid
;
222 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
223 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &ztxn
, php_pqtxn_class_entry
, &loid
, &mode
);
224 zend_restore_error_handling(&zeh
);
227 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
228 php_pqtxn_object_t
*txn_obj
= PHP_PQ_OBJ(ztxn
, NULL
);
231 throw_exce(EX_BAD_METHODCALL
, "pq\\LOB already initialized");
232 } else if (!txn_obj
->intern
) {
233 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
234 } else if (!txn_obj
->intern
->open
) {
235 throw_exce(EX_RUNTIME
, "pq\\Transation already closed");
237 if (loid
== InvalidOid
) {
238 loid
= lo_creat(txn_obj
->intern
->conn
->intern
->conn
, mode
);
241 if (loid
== InvalidOid
) {
242 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
));
244 int lofd
= lo_open(txn_obj
->intern
->conn
->intern
->conn
, loid
, mode
);
247 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
));
249 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
250 obj
->intern
->lofd
= lofd
;
251 obj
->intern
->loid
= loid
;
252 php_pq_object_addref(txn_obj
);
253 obj
->intern
->txn
= txn_obj
;
257 php_pqconn_notify_listeners(txn_obj
->intern
->conn
);
262 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write
, 0, 0, 1)
263 ZEND_ARG_INFO(0, data
)
265 static PHP_METHOD(pqlob
, write
) {
266 zend_error_handling zeh
;
271 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
272 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str
, &data_len
);
273 zend_restore_error_handling(&zeh
);
276 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
279 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
281 int written
= lo_write(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, data_str
, data_len
);
284 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
));
286 RETVAL_LONG(written
);
289 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
294 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read
, 0, 0, 0)
295 ZEND_ARG_INFO(0, length
)
296 ZEND_ARG_INFO(1, read
)
298 static PHP_METHOD(pqlob
, read
) {
299 zend_error_handling zeh
;
300 zend_long length
= 0x1000;
304 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
305 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|lz!", &length
, &zread
);
306 zend_restore_error_handling(&zeh
);
309 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
312 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
314 zend_string
*buffer
= zend_string_alloc(length
, 0);
315 int read
= lo_read(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, &buffer
->val
[0], length
);
318 zend_string_release(buffer
);
319 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
));
324 ZVAL_LONG(zread
, read
);
326 buffer
->val
[buffer
->len
= read
] = '\0';
330 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
335 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek
, 0, 0, 1)
336 ZEND_ARG_INFO(0, offset
)
337 ZEND_ARG_INFO(0, whence
)
339 static PHP_METHOD(pqlob
, seek
) {
340 zend_error_handling zeh
;
341 zend_long offset
, whence
= SEEK_SET
;
344 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
345 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &offset
, &whence
);
346 zend_restore_error_handling(&zeh
);
349 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
352 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
354 int position
= lo_lseek(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, offset
, whence
);
357 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
));
359 RETVAL_LONG(position
);
362 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
367 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell
, 0, 0, 0)
369 static PHP_METHOD(pqlob
, tell
) {
370 zend_error_handling zeh
;
373 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
374 rv
= zend_parse_parameters_none();
375 zend_restore_error_handling(&zeh
);
378 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
381 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
383 int position
= lo_tell(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
);
386 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
));
388 RETVAL_LONG(position
);
391 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
396 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate
, 0, 0, 0)
397 ZEND_ARG_INFO(0, length
)
399 static PHP_METHOD(pqlob
, truncate
) {
400 zend_error_handling zeh
;
401 zend_long length
= 0;
404 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
405 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &length
);
406 zend_restore_error_handling(&zeh
);
409 php_pqlob_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
412 throw_exce(EX_UNINITIALIZED
, "pq\\LOB not initialized");
414 int rc
= lo_truncate(obj
->intern
->txn
->intern
->conn
->intern
->conn
, obj
->intern
->lofd
, length
);
417 throw_exce(EX_RUNTIME
, "Failed to truncate LOB with oid=%d (%s)", obj
->intern
->loid
, PHP_PQerrorMessage(obj
->intern
->txn
->intern
->conn
->intern
->conn
));
420 php_pqconn_notify_listeners(obj
->intern
->txn
->intern
->conn
);
425 static zend_function_entry php_pqlob_methods
[] = {
426 PHP_ME(pqlob
, __construct
, ai_pqlob_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
427 PHP_ME(pqlob
, write
, ai_pqlob_write
, ZEND_ACC_PUBLIC
)
428 PHP_ME(pqlob
, read
, ai_pqlob_read
, ZEND_ACC_PUBLIC
)
429 PHP_ME(pqlob
, seek
, ai_pqlob_seek
, ZEND_ACC_PUBLIC
)
430 PHP_ME(pqlob
, tell
, ai_pqlob_tell
, ZEND_ACC_PUBLIC
)
431 PHP_ME(pqlob
, truncate
, ai_pqlob_truncate
, ZEND_ACC_PUBLIC
)
435 PHP_MSHUTDOWN_FUNCTION(pqlob
)
437 zend_hash_destroy(&php_pqlob_object_prophandlers
);
441 PHP_MINIT_FUNCTION(pqlob
)
443 zend_class_entry ce
= {0};
444 php_pq_object_prophandler_t ph
= {0};
446 INIT_NS_CLASS_ENTRY(ce
, "pq", "LOB", php_pqlob_methods
);
447 php_pqlob_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
448 php_pqlob_class_entry
->create_object
= php_pqlob_create_object
;
450 memcpy(&php_pqlob_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
451 php_pqlob_object_handlers
.offset
= XtOffsetOf(php_pqlob_object_t
, zo
);
452 php_pqlob_object_handlers
.free_obj
= php_pqlob_object_free
;
453 php_pqlob_object_handlers
.read_property
= php_pq_object_read_prop
;
454 php_pqlob_object_handlers
.write_property
= php_pq_object_write_prop
;
455 php_pqlob_object_handlers
.clone_obj
= NULL
;
456 php_pqlob_object_handlers
.get_property_ptr_ptr
= NULL
;
457 php_pqlob_object_handlers
.get_gc
= php_pq_object_get_gc
;
458 php_pqlob_object_handlers
.get_properties
= php_pq_object_properties
;
459 php_pqlob_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
461 zend_hash_init(&php_pqlob_object_prophandlers
, 3, NULL
, php_pq_object_prophandler_dtor
, 1);
463 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC
);
464 ph
.read
= php_pqlob_object_read_transaction
;
465 ph
.gc
= php_pqlob_object_gc_transaction
;
466 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "transaction", sizeof("transaction")-1, (void *) &ph
, sizeof(ph
));
469 zend_declare_property_long(php_pqlob_class_entry
, ZEND_STRL("oid"), InvalidOid
, ZEND_ACC_PUBLIC
);
470 ph
.read
= php_pqlob_object_read_oid
;
471 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "oid", sizeof("oid")-1, (void *) &ph
, sizeof(ph
));
473 zend_declare_property_null(php_pqlob_class_entry
, ZEND_STRL("stream"), ZEND_ACC_PUBLIC
);
474 ph
.read
= php_pqlob_object_read_stream
;
475 zend_hash_str_add_mem(&php_pqlob_object_prophandlers
, "stream", sizeof("stream")-1, (void *) &ph
, sizeof(ph
));
477 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("INVALID_OID"), InvalidOid
);
478 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("R"), INV_READ
);
479 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("W"), INV_WRITE
);
480 zend_declare_class_constant_long(php_pqlob_class_entry
, ZEND_STRL("RW"), INV_READ
|INV_WRITE
);
490 * vim600: noet sw=4 ts=4 fdm=marker
491 * vim<600: noet sw=4 ts=4