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 <ext/standard/php_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 *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(void *o TSRMLS_DC
)
52 php_pqtxn_object_t
*obj
= o
;
54 fprintf(stderr
, "FREE txn(#%d) %p (conn(#%d): %p)\n", obj
->zv
.handle
, obj
, obj
->intern
->conn
->zv
.handle
, obj
->intern
->conn
);
57 if (obj
->intern
->open
) {
58 PGresult
*res
= PQexec(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
64 php_pq_object_delref(obj
->intern
->conn TSRMLS_CC
);
68 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
72 zend_object_value
php_pqtxn_create_object_ex(zend_class_entry
*ce
, php_pqtxn_t
*intern
, php_pqtxn_object_t
**ptr TSRMLS_DC
)
74 php_pqtxn_object_t
*o
;
76 o
= ecalloc(1, sizeof(*o
));
77 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
78 object_properties_init((zend_object
*) o
, ce
);
79 o
->prophandler
= &php_pqtxn_object_prophandlers
;
89 o
->zv
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_pqtxn_object_free
, NULL TSRMLS_CC
);
90 o
->zv
.handlers
= &php_pqtxn_object_handlers
;
95 static zend_object_value
php_pqtxn_create_object(zend_class_entry
*class_type TSRMLS_DC
)
97 return php_pqtxn_create_object_ex(class_type
, NULL
, NULL TSRMLS_CC
);
100 static void php_pqtxn_object_read_connection(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
102 php_pqtxn_object_t
*obj
= o
;
104 php_pq_object_to_zval(obj
->intern
->conn
, &return_value TSRMLS_CC
);
107 static void php_pqtxn_object_read_isolation(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
109 php_pqtxn_object_t
*obj
= o
;
111 RETVAL_LONG(obj
->intern
->isolation
);
114 static void php_pqtxn_object_read_readonly(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
116 php_pqtxn_object_t
*obj
= o
;
118 RETVAL_BOOL(obj
->intern
->readonly
);
121 static void php_pqtxn_object_read_deferrable(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
123 php_pqtxn_object_t
*obj
= o
;
125 RETVAL_BOOL(obj
->intern
->deferrable
);
128 static void php_pqtxn_object_write_isolation(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
130 php_pqtxn_object_t
*obj
= o
;
131 php_pqtxn_isolation_t orig
= obj
->intern
->isolation
;
132 zval
*zisolation
= value
;
135 if (Z_TYPE_P(zisolation
) != IS_LONG
) {
136 if (Z_REFCOUNT_P(value
) > 1) {
139 ZVAL_ZVAL(tmp
, zisolation
, 1, 0);
140 convert_to_long(tmp
);
143 convert_to_long_ex(&zisolation
);
147 switch ((obj
->intern
->isolation
= Z_LVAL_P(zisolation
))) {
148 case PHP_PQTXN_READ_COMMITTED
:
149 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL READ COMMITED");
151 case PHP_PQTXN_REPEATABLE_READ
:
152 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
154 case PHP_PQTXN_SERIALIZABLE
:
155 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
158 obj
->intern
->isolation
= orig
;
163 if (zisolation
!= value
) {
164 zval_ptr_dtor(&zisolation
);
168 php_pqres_success(res TSRMLS_CC
);
173 static void php_pqtxn_object_write_readonly(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
175 php_pqtxn_object_t
*obj
= o
;
178 if ((obj
->intern
->readonly
= z_is_true(value
))) {
179 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION READ ONLY");
181 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION READ WRITE");
185 php_pqres_success(res TSRMLS_CC
);
190 static void php_pqtxn_object_write_deferrable(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
192 php_pqtxn_object_t
*obj
= o
;
195 if ((obj
->intern
->deferrable
= z_is_true(value
))) {
196 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION DEFERRABLE");
198 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SET TRANSACTION NOT DEFERRABLE");
202 php_pqres_success(res TSRMLS_CC
);
208 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct
, 0, 0, 1)
209 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
210 ZEND_ARG_INFO(0, async
)
211 ZEND_ARG_INFO(0, isolation
)
212 ZEND_ARG_INFO(0, readonly
)
213 ZEND_ARG_INFO(0, deferrable
)
215 static PHP_METHOD(pqtxn
, __construct
) {
216 zend_error_handling zeh
;
218 long isolation
= PHP_PQTXN_READ_COMMITTED
;
219 zend_bool async
= 0, readonly
= 0, deferrable
= 0;
222 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
223 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|blbb", &zconn
, php_pqconn_class_entry
, &async
, &isolation
, &readonly
, &deferrable
);
224 zend_restore_error_handling(&zeh TSRMLS_CC
);
227 php_pqconn_object_t
*conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
229 if (!conn_obj
->intern
) {
230 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
233 rv
= php_pqconn_start_transaction_async(zconn
, conn_obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
235 rv
= php_pqconn_start_transaction(zconn
, conn_obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
239 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
241 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
243 php_pq_object_addref(conn_obj TSRMLS_CC
);
244 obj
->intern
->conn
= conn_obj
;
245 obj
->intern
->open
= 1;
246 obj
->intern
->isolation
= isolation
;
247 obj
->intern
->readonly
= readonly
;
248 obj
->intern
->deferrable
= deferrable
;
254 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint
, 0, 0, 0)
256 static PHP_METHOD(pqtxn
, savepoint
) {
257 zend_error_handling zeh
;
260 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
261 rv
= zend_parse_parameters_none();
262 zend_restore_error_handling(&zeh TSRMLS_CC
);
265 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
268 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
269 } else if (!obj
->intern
->open
) {
270 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
275 smart_str_appends(&cmd
, "SAVEPOINT \"");
276 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
277 smart_str_appends(&cmd
, "\"");
280 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
283 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to create %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
285 php_pqres_success(res TSRMLS_CC
);
289 smart_str_free(&cmd
);
294 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async
, 0, 0, 0)
296 static PHP_METHOD(pqtxn
, savepointAsync
) {
297 zend_error_handling zeh
;
300 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
301 rv
= zend_parse_parameters_none();
302 zend_restore_error_handling(&zeh TSRMLS_CC
);
305 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
308 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
309 } else if (!obj
->intern
->open
) {
310 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
314 smart_str_appends(&cmd
, "SAVEPOINT \"");
315 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
316 smart_str_appends(&cmd
, "\"");
319 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
)) {
320 throw_exce(EX_IO TSRMLS_CC
, "Failed to create %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
323 smart_str_free(&cmd
);
328 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit
, 0, 0, 0)
330 static PHP_METHOD(pqtxn
, commit
) {
331 zend_error_handling zeh
;
334 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
335 rv
= zend_parse_parameters_none();
336 zend_restore_error_handling(&zeh TSRMLS_CC
);
339 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
342 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transacation not initialized");
343 } else if (!obj
->intern
->open
) {
344 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transacation already closed");
349 if (!obj
->intern
->savepoint
) {
350 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "COMMIT");
352 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
353 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
354 smart_str_appends(&cmd
, "\"");
357 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
361 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "commit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
363 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
365 obj
->intern
->open
= 0;
371 smart_str_free(&cmd
);
372 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
377 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async
, 0, 0, 0)
379 static PHP_METHOD(pqtxn
, commitAsync
) {
380 zend_error_handling zeh
;
383 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
384 rv
= zend_parse_parameters_none();
385 zend_restore_error_handling(&zeh TSRMLS_CC
);
388 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
391 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
392 } else if (!obj
->intern
->open
) {
393 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
398 if (!obj
->intern
->savepoint
) {
399 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "COMMIT");
401 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
402 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
403 smart_str_appends(&cmd
, "\"");
406 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
410 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "commmit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
413 obj
->intern
->open
= 0;
415 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
416 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
419 smart_str_free(&cmd
);
424 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback
, 0, 0, 0)
426 static PHP_METHOD(pqtxn
, rollback
) {
427 zend_error_handling zeh
;
430 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
431 rv
= zend_parse_parameters_none();
432 zend_restore_error_handling(&zeh TSRMLS_CC
);
435 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
438 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
439 } else if (!obj
->intern
->open
) {
440 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
445 if (!obj
->intern
->savepoint
) {
446 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
448 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
449 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
450 smart_str_appends(&cmd
, "\"");
453 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
457 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
459 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
461 obj
->intern
->open
= 0;
467 smart_str_free(&cmd
);
468 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
473 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async
, 0, 0, 0)
475 static PHP_METHOD(pqtxn
, rollbackAsync
) {
476 zend_error_handling zeh
;
479 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
480 rv
= zend_parse_parameters_none();
481 zend_restore_error_handling(&zeh TSRMLS_CC
);
484 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
487 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
488 } else if (!obj
->intern
->open
) {
489 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
494 if (!obj
->intern
->savepoint
) {
495 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
497 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
498 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
499 smart_str_appends(&cmd
, "\"");
502 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
506 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
509 obj
->intern
->open
= 0;
511 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
514 smart_str_free(&cmd
);
515 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
520 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot
, 0, 0, 0)
522 static PHP_METHOD(pqtxn
, exportSnapshot
) {
523 zend_error_handling zeh
;
526 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
527 rv
= zend_parse_parameters_none();
528 zend_restore_error_handling(&zeh TSRMLS_CC
);
531 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
534 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
536 PGresult
*res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()");
539 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
541 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
542 RETVAL_STRING(PQgetvalue(res
, 0, 0), 1);
548 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
553 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async
, 0, 0, 0)
555 static PHP_METHOD(pqtxn
, exportSnapshotAsync
) {
556 zend_error_handling zeh
;
559 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
560 rv
= zend_parse_parameters_none();
561 zend_restore_error_handling(&zeh TSRMLS_CC
);
564 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
567 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
568 } else if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()")) {
569 throw_exce(EX_IO TSRMLS_CC
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
571 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
572 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
577 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot
, 0, 0, 1)
578 ZEND_ARG_INFO(0, snapshot_id
)
580 static PHP_METHOD(pqtxn
, importSnapshot
) {
581 zend_error_handling zeh
;
586 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
587 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &snapshot_str
, &snapshot_len
);
588 zend_restore_error_handling(&zeh TSRMLS_CC
);
591 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
594 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
595 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
596 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
598 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
601 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
606 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
607 smart_str_appends(&cmd
, sid
);
610 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
613 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
615 php_pqres_success(res TSRMLS_CC
);
619 smart_str_free(&cmd
);
620 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
626 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async
, 0, 0, 1)
627 ZEND_ARG_INFO(0, snapshot_id
)
629 static PHP_METHOD(pqtxn
, importSnapshotAsync
) {
630 zend_error_handling zeh
;
635 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
636 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &snapshot_str
, &snapshot_len
);
637 zend_restore_error_handling(&zeh TSRMLS_CC
);
640 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
643 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
644 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
645 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
647 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
650 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
654 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
655 smart_str_appends(&cmd
, sid
);
658 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
)) {
659 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
661 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
664 smart_str_free(&cmd
);
665 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
671 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob
, 0, 0, 1)
672 ZEND_ARG_INFO(0, oid
)
673 ZEND_ARG_INFO(0, mode
)
675 static PHP_METHOD(pqtxn
, openLOB
) {
676 zend_error_handling zeh
;
677 long mode
= INV_WRITE
|INV_READ
, loid
;
680 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
681 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|l", &loid
, &mode
);
682 zend_restore_error_handling(&zeh TSRMLS_CC
);
685 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
688 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
690 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
693 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
));
695 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
699 php_pq_object_addref(obj TSRMLS_CC
);
702 return_value
->type
= IS_OBJECT
;
703 return_value
->value
.obj
= php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
, NULL TSRMLS_CC
);
706 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
711 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob
, 0, 0, 0)
712 ZEND_ARG_INFO(0, mode
)
714 static PHP_METHOD(pqtxn
, createLOB
) {
715 zend_error_handling zeh
;
716 long mode
= INV_WRITE
|INV_READ
;
719 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
720 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &mode
);
721 zend_restore_error_handling(&zeh TSRMLS_CC
);
724 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
727 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
729 Oid loid
= lo_creat(obj
->intern
->conn
->intern
->conn
, mode
);
731 if (loid
== InvalidOid
) {
732 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to create large object with mode '%s' (%s)", strmode(mode
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
734 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
737 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
));
739 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
743 php_pq_object_addref(obj TSRMLS_CC
);
746 return_value
->type
= IS_OBJECT
;
747 return_value
->value
.obj
= php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
, NULL TSRMLS_CC
);
751 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
756 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob
, 0, 0, 1)
757 ZEND_ARG_INFO(0, oid
)
759 static PHP_METHOD(pqtxn
, unlinkLOB
) {
760 zend_error_handling zeh
;
764 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
765 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &loid
);
766 zend_restore_error_handling(&zeh TSRMLS_CC
);
769 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
772 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
774 int rc
= lo_unlink(obj
->intern
->conn
->intern
->conn
, loid
);
777 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to unlink LOB (oid=%u): %s", loid
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
780 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
785 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_lob
, 0, 0, 1)
786 ZEND_ARG_INFO(0, local_path
)
787 ZEND_ARG_INFO(0, oid
)
789 static PHP_METHOD(pqtxn
, importLOB
) {
790 zend_error_handling zeh
;
793 long oid
= InvalidOid
;
796 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
797 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "p|l", &path_str
, &path_len
, &oid
);
798 zend_restore_error_handling(&zeh TSRMLS_CC
);
801 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
804 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
806 if (oid
== InvalidOid
) {
807 oid
= lo_import(obj
->intern
->conn
->intern
->conn
, path_str
);
809 oid
= lo_import_with_oid(obj
->intern
->conn
->intern
->conn
, path_str
, oid
);
812 if (oid
== InvalidOid
) {
813 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to import LOB from '%s' (%s)", path_str
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
818 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
823 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_lob
, 0, 0, 2)
824 ZEND_ARG_INFO(0, oid
)
825 ZEND_ARG_INFO(0, local_path
)
827 static PHP_METHOD(pqtxn
, exportLOB
) {
828 zend_error_handling zeh
;
834 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
835 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "lp", &oid
, &path_str
, &path_len
);
836 zend_restore_error_handling(&zeh TSRMLS_CC
);
839 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
842 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
844 int rc
= lo_export(obj
->intern
->conn
->intern
->conn
, oid
, path_str
);
847 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
));
850 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
855 static zend_function_entry php_pqtxn_methods
[] = {
856 PHP_ME(pqtxn
, __construct
, ai_pqtxn_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
857 PHP_ME(pqtxn
, commit
, ai_pqtxn_commit
, ZEND_ACC_PUBLIC
)
858 PHP_ME(pqtxn
, rollback
, ai_pqtxn_rollback
, ZEND_ACC_PUBLIC
)
859 PHP_ME(pqtxn
, commitAsync
, ai_pqtxn_commit_async
, ZEND_ACC_PUBLIC
)
860 PHP_ME(pqtxn
, rollbackAsync
, ai_pqtxn_rollback_async
, ZEND_ACC_PUBLIC
)
861 PHP_ME(pqtxn
, savepoint
, ai_pqtxn_savepoint
, ZEND_ACC_PUBLIC
)
862 PHP_ME(pqtxn
, savepointAsync
, ai_pqtxn_savepoint_async
, ZEND_ACC_PUBLIC
)
863 PHP_ME(pqtxn
, exportSnapshot
, ai_pqtxn_export_snapshot
, ZEND_ACC_PUBLIC
)
864 PHP_ME(pqtxn
, exportSnapshotAsync
, ai_pqtxn_export_snapshot_async
, ZEND_ACC_PUBLIC
)
865 PHP_ME(pqtxn
, importSnapshot
, ai_pqtxn_import_snapshot
, ZEND_ACC_PUBLIC
)
866 PHP_ME(pqtxn
, importSnapshotAsync
, ai_pqtxn_import_snapshot_async
, ZEND_ACC_PUBLIC
)
867 PHP_ME(pqtxn
, openLOB
, ai_pqtxn_open_lob
, ZEND_ACC_PUBLIC
)
868 PHP_ME(pqtxn
, createLOB
, ai_pqtxn_create_lob
, ZEND_ACC_PUBLIC
)
869 PHP_ME(pqtxn
, unlinkLOB
, ai_pqtxn_unlink_lob
, ZEND_ACC_PUBLIC
)
870 PHP_ME(pqtxn
, importLOB
, ai_pqtxn_import_lob
, ZEND_ACC_PUBLIC
)
871 PHP_ME(pqtxn
, exportLOB
, ai_pqtxn_export_lob
, ZEND_ACC_PUBLIC
)
875 PHP_MSHUTDOWN_FUNCTION(pqtxn
)
877 zend_hash_destroy(&php_pqtxn_object_prophandlers
);
881 PHP_MINIT_FUNCTION(pqtxn
)
883 zend_class_entry ce
= {0};
884 php_pq_object_prophandler_t ph
= {0};
886 INIT_NS_CLASS_ENTRY(ce
, "pq", "Transaction", php_pqtxn_methods
);
887 php_pqtxn_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
888 php_pqtxn_class_entry
->create_object
= php_pqtxn_create_object
;
890 memcpy(&php_pqtxn_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
891 php_pqtxn_object_handlers
.read_property
= php_pq_object_read_prop
;
892 php_pqtxn_object_handlers
.write_property
= php_pq_object_write_prop
;
893 php_pqtxn_object_handlers
.clone_obj
= NULL
;
894 php_pqtxn_object_handlers
.get_property_ptr_ptr
= NULL
;
895 php_pqtxn_object_handlers
.get_gc
= NULL
;
896 php_pqtxn_object_handlers
.get_properties
= php_pq_object_properties
;
897 php_pqtxn_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
899 zend_hash_init(&php_pqtxn_object_prophandlers
, 4, NULL
, NULL
, 1);
901 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC
);
902 ph
.read
= php_pqtxn_object_read_connection
;
903 zend_hash_add(&php_pqtxn_object_prophandlers
, "connection", sizeof("connection"), (void *) &ph
, sizeof(ph
), NULL
);
905 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC TSRMLS_CC
);
906 ph
.read
= php_pqtxn_object_read_isolation
;
907 ph
.write
= php_pqtxn_object_write_isolation
;
908 zend_hash_add(&php_pqtxn_object_prophandlers
, "isolation", sizeof("isolation"), (void *) &ph
, sizeof(ph
), NULL
);
910 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
911 ph
.read
= php_pqtxn_object_read_readonly
;
912 ph
.write
= php_pqtxn_object_write_readonly
;
913 zend_hash_add(&php_pqtxn_object_prophandlers
, "readonly", sizeof("readonly"), (void *) &ph
, sizeof(ph
), NULL
);
915 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
916 ph
.read
= php_pqtxn_object_read_deferrable
;
917 ph
.write
= php_pqtxn_object_write_deferrable
;
918 zend_hash_add(&php_pqtxn_object_prophandlers
, "deferrable", sizeof("deferrable"), (void *) &ph
, sizeof(ph
), NULL
);
921 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED TSRMLS_CC
);
922 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC
);
923 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE TSRMLS_CC
);
933 * vim600: noet sw=4 ts=4 fdm=marker
934 * vim<600: noet sw=4 ts=4