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 switch (ZEND_NUM_ARGS()) {
236 isolation
= conn_obj
->intern
->default_txn_isolation
;
239 readonly
= conn_obj
->intern
->default_txn_readonly
;
242 deferrable
= conn_obj
->intern
->default_txn_deferrable
;
247 rv
= php_pqconn_start_transaction_async(zconn
, conn_obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
249 rv
= php_pqconn_start_transaction(zconn
, conn_obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
253 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
255 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
257 php_pq_object_addref(conn_obj TSRMLS_CC
);
258 obj
->intern
->conn
= conn_obj
;
259 obj
->intern
->open
= 1;
260 obj
->intern
->isolation
= isolation
;
261 obj
->intern
->readonly
= readonly
;
262 obj
->intern
->deferrable
= deferrable
;
268 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint
, 0, 0, 0)
270 static PHP_METHOD(pqtxn
, savepoint
) {
271 zend_error_handling zeh
;
274 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
275 rv
= zend_parse_parameters_none();
276 zend_restore_error_handling(&zeh TSRMLS_CC
);
279 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
282 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
283 } else if (!obj
->intern
->open
) {
284 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
289 smart_str_appends(&cmd
, "SAVEPOINT \"");
290 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
291 smart_str_appends(&cmd
, "\"");
294 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
297 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to create %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
299 php_pqres_success(res TSRMLS_CC
);
303 smart_str_free(&cmd
);
308 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async
, 0, 0, 0)
310 static PHP_METHOD(pqtxn
, savepointAsync
) {
311 zend_error_handling zeh
;
314 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
315 rv
= zend_parse_parameters_none();
316 zend_restore_error_handling(&zeh TSRMLS_CC
);
319 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
322 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
323 } else if (!obj
->intern
->open
) {
324 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
328 smart_str_appends(&cmd
, "SAVEPOINT \"");
329 smart_str_append_unsigned(&cmd
, ++obj
->intern
->savepoint
);
330 smart_str_appends(&cmd
, "\"");
333 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
)) {
334 throw_exce(EX_IO TSRMLS_CC
, "Failed to create %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
337 smart_str_free(&cmd
);
342 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit
, 0, 0, 0)
344 static PHP_METHOD(pqtxn
, commit
) {
345 zend_error_handling zeh
;
348 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
349 rv
= zend_parse_parameters_none();
350 zend_restore_error_handling(&zeh TSRMLS_CC
);
353 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
356 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transacation not initialized");
357 } else if (!obj
->intern
->open
) {
358 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
363 if (!obj
->intern
->savepoint
) {
364 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "COMMIT");
366 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
367 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
368 smart_str_appends(&cmd
, "\"");
371 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
375 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "commit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
377 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
379 obj
->intern
->open
= 0;
385 smart_str_free(&cmd
);
386 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
391 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async
, 0, 0, 0)
393 static PHP_METHOD(pqtxn
, commitAsync
) {
394 zend_error_handling zeh
;
397 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
398 rv
= zend_parse_parameters_none();
399 zend_restore_error_handling(&zeh TSRMLS_CC
);
402 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
405 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
406 } else if (!obj
->intern
->open
) {
407 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
412 if (!obj
->intern
->savepoint
) {
413 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "COMMIT");
415 smart_str_appends(&cmd
, "RELEASE SAVEPOINT \"");
416 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
417 smart_str_appends(&cmd
, "\"");
420 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
424 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "commmit transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
427 obj
->intern
->open
= 0;
429 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
430 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
433 smart_str_free(&cmd
);
438 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback
, 0, 0, 0)
440 static PHP_METHOD(pqtxn
, rollback
) {
441 zend_error_handling zeh
;
444 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
445 rv
= zend_parse_parameters_none();
446 zend_restore_error_handling(&zeh TSRMLS_CC
);
449 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
452 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
453 } else if (!obj
->intern
->open
) {
454 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
459 if (!obj
->intern
->savepoint
) {
460 res
= PQexec(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
462 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
463 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
464 smart_str_appends(&cmd
, "\"");
467 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
471 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
473 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
475 obj
->intern
->open
= 0;
481 smart_str_free(&cmd
);
482 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
487 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async
, 0, 0, 0)
489 static PHP_METHOD(pqtxn
, rollbackAsync
) {
490 zend_error_handling zeh
;
493 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
494 rv
= zend_parse_parameters_none();
495 zend_restore_error_handling(&zeh TSRMLS_CC
);
498 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
501 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
502 } else if (!obj
->intern
->open
) {
503 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction already closed");
508 if (!obj
->intern
->savepoint
) {
509 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, "ROLLBACK");
511 smart_str_appends(&cmd
, "ROLLBACK TO SAVEPOINT \"");
512 smart_str_append_unsigned(&cmd
, obj
->intern
->savepoint
--);
513 smart_str_appends(&cmd
, "\"");
516 rc
= PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
520 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
? cmd
.c
: "rollback transaction", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
523 obj
->intern
->open
= 0;
525 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
528 smart_str_free(&cmd
);
529 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
534 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot
, 0, 0, 0)
536 static PHP_METHOD(pqtxn
, exportSnapshot
) {
537 zend_error_handling zeh
;
540 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
541 rv
= zend_parse_parameters_none();
542 zend_restore_error_handling(&zeh TSRMLS_CC
);
545 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
548 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
550 PGresult
*res
= PQexec(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()");
553 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
555 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
556 RETVAL_STRING(PQgetvalue(res
, 0, 0), 1);
562 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
567 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async
, 0, 0, 0)
569 static PHP_METHOD(pqtxn
, exportSnapshotAsync
) {
570 zend_error_handling zeh
;
573 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
574 rv
= zend_parse_parameters_none();
575 zend_restore_error_handling(&zeh TSRMLS_CC
);
578 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
581 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
582 } else if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, "SELECT pg_export_snapshot()")) {
583 throw_exce(EX_IO TSRMLS_CC
, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
585 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
586 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
591 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot
, 0, 0, 1)
592 ZEND_ARG_INFO(0, snapshot_id
)
594 static PHP_METHOD(pqtxn
, importSnapshot
) {
595 zend_error_handling zeh
;
600 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
601 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &snapshot_str
, &snapshot_len
);
602 zend_restore_error_handling(&zeh TSRMLS_CC
);
605 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
608 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
609 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
610 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
612 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
615 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
620 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
621 smart_str_appends(&cmd
, sid
);
624 res
= PQexec(obj
->intern
->conn
->intern
->conn
, cmd
.c
);
627 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
629 php_pqres_success(res TSRMLS_CC
);
633 smart_str_free(&cmd
);
634 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
640 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async
, 0, 0, 1)
641 ZEND_ARG_INFO(0, snapshot_id
)
643 static PHP_METHOD(pqtxn
, importSnapshotAsync
) {
644 zend_error_handling zeh
;
649 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
650 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &snapshot_str
, &snapshot_len
);
651 zend_restore_error_handling(&zeh TSRMLS_CC
);
654 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
657 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
658 } else if (obj
->intern
->isolation
< PHP_PQTXN_REPEATABLE_READ
) {
659 throw_exce(EX_RUNTIME TSRMLS_CC
, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
661 char *sid
= PQescapeLiteral(obj
->intern
->conn
->intern
->conn
, snapshot_str
, snapshot_len
);
664 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
668 smart_str_appends(&cmd
, "SET TRANSACTION SNAPSHOT ");
669 smart_str_appends(&cmd
, sid
);
672 if (!PQsendQuery(obj
->intern
->conn
->intern
->conn
, cmd
.c
)) {
673 throw_exce(EX_IO TSRMLS_CC
, "Failed to %s (%s)", cmd
.c
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
675 obj
->intern
->conn
->intern
->poller
= PQconsumeInput
;
678 smart_str_free(&cmd
);
679 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
685 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob
, 0, 0, 1)
686 ZEND_ARG_INFO(0, oid
)
687 ZEND_ARG_INFO(0, mode
)
689 static PHP_METHOD(pqtxn
, openLOB
) {
690 zend_error_handling zeh
;
691 long mode
= INV_WRITE
|INV_READ
, loid
;
694 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
695 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l|l", &loid
, &mode
);
696 zend_restore_error_handling(&zeh TSRMLS_CC
);
699 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
702 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
704 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
707 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
));
709 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
713 php_pq_object_addref(obj TSRMLS_CC
);
716 return_value
->type
= IS_OBJECT
;
717 return_value
->value
.obj
= php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
, NULL TSRMLS_CC
);
720 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
725 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob
, 0, 0, 0)
726 ZEND_ARG_INFO(0, mode
)
728 static PHP_METHOD(pqtxn
, createLOB
) {
729 zend_error_handling zeh
;
730 long mode
= INV_WRITE
|INV_READ
;
733 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
734 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|l", &mode
);
735 zend_restore_error_handling(&zeh TSRMLS_CC
);
738 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
741 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
743 Oid loid
= lo_creat(obj
->intern
->conn
->intern
->conn
, mode
);
745 if (loid
== InvalidOid
) {
746 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to create large object with mode '%s' (%s)", strmode(mode
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
748 int lofd
= lo_open(obj
->intern
->conn
->intern
->conn
, loid
, mode
);
751 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
));
753 php_pqlob_t
*lob
= ecalloc(1, sizeof(*lob
));
757 php_pq_object_addref(obj TSRMLS_CC
);
760 return_value
->type
= IS_OBJECT
;
761 return_value
->value
.obj
= php_pqlob_create_object_ex(php_pqlob_class_entry
, lob
, NULL TSRMLS_CC
);
765 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
770 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob
, 0, 0, 1)
771 ZEND_ARG_INFO(0, oid
)
773 static PHP_METHOD(pqtxn
, unlinkLOB
) {
774 zend_error_handling zeh
;
778 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
779 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &loid
);
780 zend_restore_error_handling(&zeh TSRMLS_CC
);
783 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
786 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
788 int rc
= lo_unlink(obj
->intern
->conn
->intern
->conn
, loid
);
791 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to unlink LOB (oid=%u): %s", loid
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
794 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
799 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_lob
, 0, 0, 1)
800 ZEND_ARG_INFO(0, local_path
)
801 ZEND_ARG_INFO(0, oid
)
803 static PHP_METHOD(pqtxn
, importLOB
) {
804 zend_error_handling zeh
;
807 long oid
= InvalidOid
;
810 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
811 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "p|l", &path_str
, &path_len
, &oid
);
812 zend_restore_error_handling(&zeh TSRMLS_CC
);
815 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
818 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
820 if (oid
== InvalidOid
) {
821 oid
= lo_import(obj
->intern
->conn
->intern
->conn
, path_str
);
823 oid
= lo_import_with_oid(obj
->intern
->conn
->intern
->conn
, path_str
, oid
);
826 if (oid
== InvalidOid
) {
827 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to import LOB from '%s' (%s)", path_str
, PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
832 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
837 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_lob
, 0, 0, 2)
838 ZEND_ARG_INFO(0, oid
)
839 ZEND_ARG_INFO(0, local_path
)
841 static PHP_METHOD(pqtxn
, exportLOB
) {
842 zend_error_handling zeh
;
848 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
849 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "lp", &oid
, &path_str
, &path_len
);
850 zend_restore_error_handling(&zeh TSRMLS_CC
);
853 php_pqtxn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
856 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Transaction not initialized");
858 int rc
= lo_export(obj
->intern
->conn
->intern
->conn
, oid
, path_str
);
861 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
));
864 php_pqconn_notify_listeners(obj
->intern
->conn TSRMLS_CC
);
869 static zend_function_entry php_pqtxn_methods
[] = {
870 PHP_ME(pqtxn
, __construct
, ai_pqtxn_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
871 PHP_ME(pqtxn
, commit
, ai_pqtxn_commit
, ZEND_ACC_PUBLIC
)
872 PHP_ME(pqtxn
, rollback
, ai_pqtxn_rollback
, ZEND_ACC_PUBLIC
)
873 PHP_ME(pqtxn
, commitAsync
, ai_pqtxn_commit_async
, ZEND_ACC_PUBLIC
)
874 PHP_ME(pqtxn
, rollbackAsync
, ai_pqtxn_rollback_async
, ZEND_ACC_PUBLIC
)
875 PHP_ME(pqtxn
, savepoint
, ai_pqtxn_savepoint
, ZEND_ACC_PUBLIC
)
876 PHP_ME(pqtxn
, savepointAsync
, ai_pqtxn_savepoint_async
, ZEND_ACC_PUBLIC
)
877 PHP_ME(pqtxn
, exportSnapshot
, ai_pqtxn_export_snapshot
, ZEND_ACC_PUBLIC
)
878 PHP_ME(pqtxn
, exportSnapshotAsync
, ai_pqtxn_export_snapshot_async
, ZEND_ACC_PUBLIC
)
879 PHP_ME(pqtxn
, importSnapshot
, ai_pqtxn_import_snapshot
, ZEND_ACC_PUBLIC
)
880 PHP_ME(pqtxn
, importSnapshotAsync
, ai_pqtxn_import_snapshot_async
, ZEND_ACC_PUBLIC
)
881 PHP_ME(pqtxn
, openLOB
, ai_pqtxn_open_lob
, ZEND_ACC_PUBLIC
)
882 PHP_ME(pqtxn
, createLOB
, ai_pqtxn_create_lob
, ZEND_ACC_PUBLIC
)
883 PHP_ME(pqtxn
, unlinkLOB
, ai_pqtxn_unlink_lob
, ZEND_ACC_PUBLIC
)
884 PHP_ME(pqtxn
, importLOB
, ai_pqtxn_import_lob
, ZEND_ACC_PUBLIC
)
885 PHP_ME(pqtxn
, exportLOB
, ai_pqtxn_export_lob
, ZEND_ACC_PUBLIC
)
889 PHP_MSHUTDOWN_FUNCTION(pqtxn
)
891 zend_hash_destroy(&php_pqtxn_object_prophandlers
);
895 PHP_MINIT_FUNCTION(pqtxn
)
897 zend_class_entry ce
= {0};
898 php_pq_object_prophandler_t ph
= {0};
900 INIT_NS_CLASS_ENTRY(ce
, "pq", "Transaction", php_pqtxn_methods
);
901 php_pqtxn_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
902 php_pqtxn_class_entry
->create_object
= php_pqtxn_create_object
;
904 memcpy(&php_pqtxn_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
905 php_pqtxn_object_handlers
.read_property
= php_pq_object_read_prop
;
906 php_pqtxn_object_handlers
.write_property
= php_pq_object_write_prop
;
907 php_pqtxn_object_handlers
.clone_obj
= NULL
;
908 php_pqtxn_object_handlers
.get_property_ptr_ptr
= NULL
;
909 php_pqtxn_object_handlers
.get_gc
= NULL
;
910 php_pqtxn_object_handlers
.get_properties
= php_pq_object_properties
;
911 php_pqtxn_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
913 zend_hash_init(&php_pqtxn_object_prophandlers
, 4, NULL
, NULL
, 1);
915 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC
);
916 ph
.read
= php_pqtxn_object_read_connection
;
917 zend_hash_add(&php_pqtxn_object_prophandlers
, "connection", sizeof("connection"), (void *) &ph
, sizeof(ph
), NULL
);
919 zend_declare_property_null(php_pqtxn_class_entry
, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC TSRMLS_CC
);
920 ph
.read
= php_pqtxn_object_read_isolation
;
921 ph
.write
= php_pqtxn_object_write_isolation
;
922 zend_hash_add(&php_pqtxn_object_prophandlers
, "isolation", sizeof("isolation"), (void *) &ph
, sizeof(ph
), NULL
);
924 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
925 ph
.read
= php_pqtxn_object_read_readonly
;
926 ph
.write
= php_pqtxn_object_write_readonly
;
927 zend_hash_add(&php_pqtxn_object_prophandlers
, "readonly", sizeof("readonly"), (void *) &ph
, sizeof(ph
), NULL
);
929 zend_declare_property_bool(php_pqtxn_class_entry
, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
930 ph
.read
= php_pqtxn_object_read_deferrable
;
931 ph
.write
= php_pqtxn_object_write_deferrable
;
932 zend_hash_add(&php_pqtxn_object_prophandlers
, "deferrable", sizeof("deferrable"), (void *) &ph
, sizeof(ph
), NULL
);
935 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED TSRMLS_CC
);
936 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC
);
937 zend_declare_class_constant_long(php_pqtxn_class_entry
, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE TSRMLS_CC
);
947 * vim600: noet sw=4 ts=4 fdm=marker
948 * vim<600: noet sw=4 ts=4