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 +--------------------------------------------------------------------+
18 #include <Zend/zend_smart_str.h>
20 #include <libpq-events.h>
21 #include <libpq/libpq-fs.h>
24 #include "php_pq_misc.h"
25 #include "php_pq_object.h"
26 #include "php_pqexc.h"
27 #include "php_pqres.h"
28 #include "php_pqlob.h"
29 #include "php_pqtxn.h"
31 zend_class_entry
*php_pqtxn_class_entry
;
32 static zend_object_handlers php_pqtxn_object_handlers
;
33 static HashTable php_pqtxn_object_prophandlers
;
35 const char *php_pq_isolation_level(long *isolation
)
38 case PHP_PQTXN_SERIALIZABLE
:
39 return "SERIALIZABLE";
40 case PHP_PQTXN_REPEATABLE_READ
:
41 return "REPEATABLE READ";
43 *isolation
= PHP_PQTXN_READ_COMMITTED
;
45 case PHP_PQTXN_READ_COMMITTED
:
46 return "READ COMMITTED";
50 static void php_pqtxn_object_free(zend_object
*o
)
52 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
54 fprintf(stderr
, "FREE txn(#%d) %p (conn(#%d): %p)\n", obj
->zo
.handle
, obj
, obj
->intern
->conn
->zo
.handle
, obj
->intern
->conn
);
57 if (obj
->intern
->open
&& obj
->intern
->conn
->intern
) {
58 PGresult
*res
= PQexec(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
64 php_pq_object_delref(obj
->intern
->conn
);
68 php_pq_object_dtor(o
);
71 php_pqtxn_object_t
*php_pqtxn_create_object_ex(zend_class_entry
*ce
, php_pqtxn_t
*intern
)
73 return php_pq_object_create(ce
, intern
, sizeof(php_pqtxn_object_t
),
74 &php_pqtxn_object_handlers
, &php_pqtxn_object_prophandlers
);
77 static zend_object
*php_pqtxn_create_object(zend_class_entry
*class_type
)
79 return &php_pqtxn_create_object_ex(class_type
, NULL
)->zo
;
82 static void php_pqtxn_object_read_connection(zval
*object
, void *o
, zval
*return_value
)
84 php_pqtxn_object_t
*obj
= o
;
86 php_pq_object_to_zval(obj
->intern
->conn
, return_value
);
89 static void php_pqtxn_object_gc_connection(zval
*object
, void *o
, zval
*return_value
)
91 php_pqtxn_object_t
*obj
= o
;
94 php_pq_object_to_zval_no_addref(obj
->intern
->conn
, &zconn
);
95 add_next_index_zval(return_value
, &zconn
);
98 static void php_pqtxn_object_read_isolation(zval
*object
, void *o
, zval
*return_value
)
100 php_pqtxn_object_t
*obj
= o
;
102 RETVAL_LONG(obj
->intern
->isolation
);
105 static void php_pqtxn_object_read_readonly(zval
*object
, void *o
, zval
*return_value
)
107 php_pqtxn_object_t
*obj
= o
;
109 RETVAL_BOOL(obj
->intern
->readonly
);
112 static void php_pqtxn_object_read_deferrable(zval
*object
, void *o
, zval
*return_value
)
114 php_pqtxn_object_t
*obj
= o
;
116 RETVAL_BOOL(obj
->intern
->deferrable
);
119 static void php_pqtxn_object_write_isolation(zval
*object
, void *o
, zval
*value
)
121 php_pqtxn_object_t
*obj
= o
;
122 php_pqtxn_isolation_t orig
= obj
->intern
->isolation
;
125 switch ((obj
->intern
->isolation
= zval_get_long(value
))) {
126 case PHP_PQTXN_READ_COMMITTED
:
127 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL READ COMMITED");
129 case PHP_PQTXN_REPEATABLE_READ
:
130 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
132 case PHP_PQTXN_SERIALIZABLE
:
133 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
136 obj
->intern
->isolation
= orig
;
142 php_pqres_success(res
);
147 static void php_pqtxn_object_write_readonly(zval
*object
, void *o
, zval
*value
)
149 php_pqtxn_object_t
*obj
= o
;
152 if ((obj
->intern
->readonly
= z_is_true(value
))) {
153 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION READ ONLY");
155 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION READ WRITE");
159 php_pqres_success(res
);
164 static void php_pqtxn_object_write_deferrable(zval
*object
, void *o
, zval
*value
)
166 php_pqtxn_object_t
*obj
= o
;
169 if ((obj
->intern
->deferrable
= z_is_true(value
))) {
170 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION DEFERRABLE");
172 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION NOT DEFERRABLE");
176 php_pqres_success(res
);
182 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct
, 0, 0, 1)
183 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
184 ZEND_ARG_INFO(0, async
)
185 ZEND_ARG_INFO(0, isolation
)
186 ZEND_ARG_INFO(0, readonly
)
187 ZEND_ARG_INFO(0, deferrable
)
189 static PHP_METHOD(pqtxn
, __construct
) {
190 zend_error_handling zeh
;
192 zend_long isolation
= PHP_PQTXN_READ_COMMITTED
;
193 zend_bool async
= 0, readonly
= 0, deferrable
= 0;
196 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
197 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "O|blbb", &zconn
, php_pqconn_class_entry
, &async
, &isolation
, &readonly
, &deferrable
);
198 zend_restore_error_handling(&zeh
);
201 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
203 if (!conn_obj
->intern
) {
204 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
207 switch (ZEND_NUM_ARGS()) {
210 isolation
= conn_obj
->intern
->default_txn_isolation
;
213 readonly
= conn_obj
->intern
->default_txn_readonly
;
216 deferrable
= conn_obj
->intern
->default_txn_deferrable
;
221 rv
= php_pqconn_start_transaction_async(zconn
, conn_obj
, isolation
, readonly
, deferrable
);
223 rv
= php_pqconn_start_transaction(zconn
, conn_obj
, isolation
, readonly
, deferrable
);
227 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
229 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
231 php_pq_object_addref(conn_obj
);
232 obj
->intern
->conn
= conn_obj
;
233 obj
->intern
->open
= 1;
234 obj
->intern
->isolation
= isolation
;
235 obj
->intern
->readonly
= readonly
;
236 obj
->intern
->deferrable
= deferrable
;
242 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint
, 0, 0, 0)
244 static PHP_METHOD(pqtxn
, savepoint
) {
245 zend_error_handling zeh
;
248 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
249 rv
= zend_parse_parameters_none();
250 zend_restore_error_handling(&zeh
);
253 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
256 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
257 } else if (!obj
->intern
->open
) {
258 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
263 smart_str_appends(&cmd
, "SAVEPOINT \"");
264 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
265 smart_str_appends(&cmd
, "\"");
268 res
= PQexec(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
271 throw_exce(EX_RUNTIME
, "Failed to create %s (%s)", smart_str_v(&cmd
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
273 php_pqres_success(res
);
277 smart_str_free(&cmd
);
282 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async
, 0, 0, 0)
284 static PHP_METHOD(pqtxn
, savepointAsync
) {
285 zend_error_handling zeh
;
288 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
289 rv
= zend_parse_parameters_none();
290 zend_restore_error_handling(&zeh
);
293 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
296 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
297 } else if (!obj
->intern
->open
) {
298 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
302 smart_str_appends(&cmd
, "SAVEPOINT \"");
303 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
304 smart_str_appends(&cmd
, "\"");
307 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
))) {
308 throw_exce(EX_IO
, "Failed to create %s (%s)", smart_str_v(&cmd
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
311 smart_str_free(&cmd
);
316 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit
, 0, 0, 0)
318 static PHP_METHOD(pqtxn
, commit
) {
319 zend_error_handling zeh
;
322 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
323 rv
= zend_parse_parameters_none();
324 zend_restore_error_handling(&zeh
);
327 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
330 throw_exce(EX_UNINITIALIZED
, "pq\\Transacation not initialized");
331 } else if (!obj
->intern
->open
) {
332 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
336 zend_bool just_release_sp
= !!obj
->intern
->savepoint
;
338 if (!just_release_sp
) {
339 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "COMMIT");
341 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
342 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
343 smart_str_appends(&cmd
, "\"");
346 res
= PQexec(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
350 throw_exce(EX_RUNTIME
, "Failed to %s (%s)", smart_str_l(&cmd
) ? smart_str_v(&cmd
) : "commit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
352 if (SUCCESS
== php_pqres_success(res
)) {
353 if (!just_release_sp
) {
354 obj
->intern
->open
= 0;
360 smart_str_free(&cmd
);
361 php_pqconn_notify_listeners(obj
->intern
->conn
);
366 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async
, 0, 0, 0)
368 static PHP_METHOD(pqtxn
, commitAsync
) {
369 zend_error_handling zeh
;
372 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
373 rv
= zend_parse_parameters_none();
374 zend_restore_error_handling(&zeh
);
377 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
380 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
381 } else if (!obj
->intern
->open
) {
382 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
386 zend_bool just_release_sp
= !!obj
->intern
->savepoint
;
388 if (!just_release_sp
) {
389 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "COMMIT");
391 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
392 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
393 smart_str_appends(&cmd
, "\"");
396 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
400 throw_exce(EX_IO
, "Failed to %s (%s)", smart_str_l(&cmd
) ? smart_str_v(&cmd
) : "commmit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
402 if (!just_release_sp
) {
403 obj
->intern
->open
= 0;
405 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
406 php_pqconn_notify_listeners(obj
->intern
->conn
);
409 smart_str_free(&cmd
);
414 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback
, 0, 0, 0)
416 static PHP_METHOD(pqtxn
, rollback
) {
417 zend_error_handling zeh
;
420 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
421 rv
= zend_parse_parameters_none();
422 zend_restore_error_handling(&zeh
);
425 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
428 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
429 } else if (!obj
->intern
->open
) {
430 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
434 zend_bool just_release_sp
= !!obj
->intern
->savepoint
;
436 if (!just_release_sp
) {
437 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
439 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
440 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
441 smart_str_appends(&cmd
, "\"");
444 res
= PQexec(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
448 throw_exce(EX_RUNTIME
, "Failed to %s (%s)", smart_str_l(&cmd
) ? smart_str_v(&cmd
) : "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
450 if (SUCCESS
== php_pqres_success(res
)) {
451 if (!just_release_sp
) {
452 obj
->intern
->open
= 0;
458 smart_str_free(&cmd
);
459 php_pqconn_notify_listeners(obj
->intern
->conn
);
464 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async
, 0, 0, 0)
466 static PHP_METHOD(pqtxn
, rollbackAsync
) {
467 zend_error_handling zeh
;
470 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
471 rv
= zend_parse_parameters_none();
472 zend_restore_error_handling(&zeh
);
475 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
478 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
479 } else if (!obj
->intern
->open
) {
480 throw_exce(EX_RUNTIME
, "pq\\Transaction already closed");
484 zend_bool just_release_sp
= !!obj
->intern
->savepoint
;
486 if (!just_release_sp
) {
487 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
489 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
490 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
491 smart_str_appends(&cmd
, "\"");
494 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
498 throw_exce(EX_IO
, "Failed to %s (%s)", smart_str_l(&cmd
) ? smart_str_v(&cmd
) : "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
500 if (!just_release_sp
) {
501 obj
->intern
->open
= 0;
503 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
506 smart_str_free(&cmd
);
507 php_pqconn_notify_listeners(obj
->intern
->conn
);
512 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot
, 0, 0, 0)
514 static PHP_METHOD(pqtxn
, exportSnapshot
) {
515 zend_error_handling zeh
;
518 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
519 rv
= zend_parse_parameters_none();
520 zend_restore_error_handling(&zeh
);
523 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
526 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
528 PGresult
*res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()");
531 throw_exce(EX_RUNTIME
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
533 if (SUCCESS
== php_pqres_success(res
)) {
534 RETVAL_STRING(PQgetvalue(res
, 0, 0));
540 php_pqconn_notify_listeners(obj
->intern
->conn
);
545 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async
, 0, 0, 0)
547 static PHP_METHOD(pqtxn
, exportSnapshotAsync
) {
548 zend_error_handling zeh
;
551 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
552 rv
= zend_parse_parameters_none();
553 zend_restore_error_handling(&zeh
);
556 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
559 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
560 } else if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()")) {
561 throw_exce(EX_IO
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
563 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
564 php_pqconn_notify_listeners(obj
->intern
->conn
);
569 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot
, 0, 0, 1)
570 ZEND_ARG_INFO(0, snapshot_id
)
572 static PHP_METHOD(pqtxn
, importSnapshot
) {
573 zend_error_handling zeh
;
578 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
579 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &snapshot_str
, &snapshot_len
);
580 zend_restore_error_handling(&zeh
);
583 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
586 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
587 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
588 throw_exce(EX_RUNTIME
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
590 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
593 throw_exce(EX_ESCAPE
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
598 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
599 smart_str_appends(&cmd
, sid
);
602 res
= PQexec(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
));
605 throw_exce(EX_RUNTIME
, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
607 php_pqres_success(res
);
611 smart_str_free(&cmd
);
612 php_pqconn_notify_listeners(obj
->intern
->conn
);
618 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async
, 0, 0, 1)
619 ZEND_ARG_INFO(0, snapshot_id
)
621 static PHP_METHOD(pqtxn
, importSnapshotAsync
) {
622 zend_error_handling zeh
;
627 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
628 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &snapshot_str
, &snapshot_len
);
629 zend_restore_error_handling(&zeh
);
632 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
635 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
636 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
637 throw_exce(EX_RUNTIME
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
639 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
642 throw_exce(EX_ESCAPE
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
646 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
647 smart_str_appends(&cmd
, sid
);
650 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, smart_str_v(&cmd
))) {
651 throw_exce(EX_IO
, "Failed to %s (%s)", smart_str_v(&cmd
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
653 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
656 smart_str_free(&cmd
);
657 php_pqconn_notify_listeners(obj
->intern
->conn
);
663 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob
, 0, 0, 1)
664 ZEND_ARG_INFO(0, oid
)
665 ZEND_ARG_INFO(0, mode
)
667 static PHP_METHOD(pqtxn
, openLOB
) {
668 zend_error_handling zeh
;
669 zend_long mode
= INV_WRITE
|INV_READ
, loid
;
672 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
673 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &loid
, &mode
);
674 zend_restore_error_handling(&zeh
);
677 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
680 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
682 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
685 throw_exce(EX_RUNTIME
, "Failed to open large object with oid=%lu with mode '%s' (%s)", loid
, php_pq_strmode(mode
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
687 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
691 php_pq_object_addref(obj
);
694 RETVAL_OBJ(&php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
)->zo
);
697 php_pqconn_notify_listeners(obj
->intern
->conn
);
702 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob
, 0, 0, 0)
703 ZEND_ARG_INFO(0, mode
)
705 static PHP_METHOD(pqtxn
, createLOB
) {
706 zend_error_handling zeh
;
707 zend_long mode
= INV_WRITE
|INV_READ
;
710 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
711 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &mode
);
712 zend_restore_error_handling(&zeh
);
715 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
718 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
720 Oid loid
= lo_creat(obj
->intern
->conn
->intern
->conn
, mode
);
722 if (loid
== InvalidOid
) {
723 throw_exce(EX_RUNTIME
, "Failed to create large object with mode '%s' (%s)", php_pq_strmode(mode
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
725 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
728 throw_exce(EX_RUNTIME
, "Failed to open large object with oid=%lu with mode '%s': %s", loid
, php_pq_strmode(mode
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
730 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
734 php_pq_object_addref(obj TSRMLS_CC
);
737 RETVAL_OBJ(&php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
)->zo
);
741 php_pqconn_notify_listeners(obj
->intern
->conn
);
746 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob
, 0, 0, 1)
747 ZEND_ARG_INFO(0, oid
)
749 static PHP_METHOD(pqtxn
, unlinkLOB
) {
750 zend_error_handling zeh
;
754 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
755 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "l", &loid
);
756 zend_restore_error_handling(&zeh
);
759 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
762 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
764 int rc
= lo_unlink(obj
->intern
->conn
->intern
->conn
, loid
);
767 throw_exce(EX_RUNTIME
, "Failed to unlink LOB (oid=%lu): %s", loid
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
770 php_pqconn_notify_listeners(obj
->intern
->conn
);
775 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_lob
, 0, 0, 1)
776 ZEND_ARG_INFO(0, local_path
)
777 ZEND_ARG_INFO(0, oid
)
779 static PHP_METHOD(pqtxn
, importLOB
) {
780 zend_error_handling zeh
;
783 zend_long oid
= InvalidOid
;
786 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
787 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &path_str
, &path_len
, &oid
);
788 zend_restore_error_handling(&zeh
);
791 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
794 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
796 if (oid
== InvalidOid
) {
797 oid
= lo_import(obj
->intern
->conn
->intern
->conn
, path_str
);
799 oid
= lo_import_with_oid(obj
->intern
->conn
->intern
->conn
, path_str
, oid
);
802 if (oid
== InvalidOid
) {
803 throw_exce(EX_RUNTIME
, "Failed to import LOB from '%s' (%s)", path_str
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
808 php_pqconn_notify_listeners(obj
->intern
->conn
);
813 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_lob
, 0, 0, 2)
814 ZEND_ARG_INFO(0, oid
)
815 ZEND_ARG_INFO(0, local_path
)
817 static PHP_METHOD(pqtxn
, exportLOB
) {
818 zend_error_handling zeh
;
824 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
825 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "lp", &oid
, &path_str
, &path_len
);
826 zend_restore_error_handling(&zeh
);
829 php_pqtxn_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
832 throw_exce(EX_UNINITIALIZED
, "pq\\Transaction not initialized");
834 int rc
= lo_export(obj
->intern
->conn
->intern
->conn
, oid
, path_str
);
837 throw_exce(EX_RUNTIME
, "Failed to export LOB (oid=%lu) to '%s' (%s)", oid
, path_str
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
840 php_pqconn_notify_listeners(obj
->intern
->conn
);
845 static zend_function_entry php_pqtxn_methods
[] = {
846 PHP_ME(pqtxn
, __construct
, ai_pqtxn_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
847 PHP_ME(pqtxn
, commit
, ai_pqtxn_commit
, ZEND_ACC_PUBLIC
)
848 PHP_ME(pqtxn
, rollback
, ai_pqtxn_rollback
, ZEND_ACC_PUBLIC
)
849 PHP_ME(pqtxn
, commitAsync
, ai_pqtxn_commit_async
, ZEND_ACC_PUBLIC
)
850 PHP_ME(pqtxn
, rollbackAsync
, ai_pqtxn_rollback_async
, ZEND_ACC_PUBLIC
)
851 PHP_ME(pqtxn
, savepoint
, ai_pqtxn_savepoint
, ZEND_ACC_PUBLIC
)
852 PHP_ME(pqtxn
, savepointAsync
, ai_pqtxn_savepoint_async
, ZEND_ACC_PUBLIC
)
853 PHP_ME(pqtxn
, exportSnapshot
, ai_pqtxn_export_snapshot
, ZEND_ACC_PUBLIC
)
854 PHP_ME(pqtxn
, exportSnapshotAsync
, ai_pqtxn_export_snapshot_async
, ZEND_ACC_PUBLIC
)
855 PHP_ME(pqtxn
, importSnapshot
, ai_pqtxn_import_snapshot
, ZEND_ACC_PUBLIC
)
856 PHP_ME(pqtxn
, importSnapshotAsync
, ai_pqtxn_import_snapshot_async
, ZEND_ACC_PUBLIC
)
857 PHP_ME(pqtxn
, openLOB
, ai_pqtxn_open_lob
, ZEND_ACC_PUBLIC
)
858 PHP_ME(pqtxn
, createLOB
, ai_pqtxn_create_lob
, ZEND_ACC_PUBLIC
)
859 PHP_ME(pqtxn
, unlinkLOB
, ai_pqtxn_unlink_lob
, ZEND_ACC_PUBLIC
)
860 PHP_ME(pqtxn
, importLOB
, ai_pqtxn_import_lob
, ZEND_ACC_PUBLIC
)
861 PHP_ME(pqtxn
, exportLOB
, ai_pqtxn_export_lob
, ZEND_ACC_PUBLIC
)
865 PHP_MSHUTDOWN_FUNCTION(pqtxn
)
867 zend_hash_destroy(&php_pqtxn_object_prophandlers
);
871 PHP_MINIT_FUNCTION(pqtxn
)
873 zend_class_entry ce
= {0};
874 php_pq_object_prophandler_t ph
= {0};
876 INIT_NS_CLASS_ENTRY(ce
, "pq", "Transaction", php_pqtxn_methods
);
877 php_pqtxn_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
878 php_pqtxn_class_entry
->create_object
= php_pqtxn_create_object
;
880 memcpy(&php_pqtxn_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
881 php_pqtxn_object_handlers
.offset
= XtOffsetOf(php_pqtxn_object_t
, zo
);
882 php_pqtxn_object_handlers
.free_obj
= php_pqtxn_object_free
;
883 php_pqtxn_object_handlers
.read_property
= php_pq_object_read_prop
;
884 php_pqtxn_object_handlers
.write_property
= php_pq_object_write_prop
;
885 php_pqtxn_object_handlers
.clone_obj
= NULL
;
886 php_pqtxn_object_handlers
.get_property_ptr_ptr
= NULL
;
887 php_pqtxn_object_handlers
.get_gc
= php_pq_object_get_gc
;
888 php_pqtxn_object_handlers
.get_properties
= php_pq_object_properties
;
889 php_pqtxn_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
891 zend_hash_init(&php_pqtxn_object_prophandlers
, 4, NULL
, php_pq_object_prophandler_dtor
, 1);
893 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
894 ph
.read
= php_pqtxn_object_read_connection
;
895 ph
.gc
= php_pqtxn_object_gc_connection
;
896 zend_hash_str_add_mem(&php_pqtxn_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
899 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC
);
900 ph
.read
= php_pqtxn_object_read_isolation
;
901 ph
.write
= php_pqtxn_object_write_isolation
;
902 zend_hash_str_add_mem(&php_pqtxn_object_prophandlers
, "isolation", sizeof("isolation")-1, (void *) &ph
, sizeof(ph
));
904 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC
);
905 ph
.read
= php_pqtxn_object_read_readonly
;
906 ph
.write
= php_pqtxn_object_write_readonly
;
907 zend_hash_str_add_mem(&php_pqtxn_object_prophandlers
, "readonly", sizeof("readonly")-1, (void *) &ph
, sizeof(ph
));
909 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC
);
910 ph
.read
= php_pqtxn_object_read_deferrable
;
911 ph
.write
= php_pqtxn_object_write_deferrable
;
912 zend_hash_str_add_mem(&php_pqtxn_object_prophandlers
, "deferrable", sizeof("deferrable")-1, (void *) &ph
, sizeof(ph
));
915 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED
);
916 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ
);
917 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE
);
927 * vim600: noet sw=4 ts=4 fdm=marker
928 * vim<600: noet sw=4 ts=4