From 6ed1819bf4faaee1ef3650d59089c66181b1f8ba Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 10 Jun 2010 12:11:19 +0000 Subject: [PATCH] Added inTransaction() method to PDO, with specialized support for Postgres --- ext/pdo/pdo_dbh.c | 20 +++++++ ext/pdo/php_pdo_driver.h | 1 + ext/pdo_pgsql/pdo_pgsql.c | 6 ++ ext/pdo_pgsql/pgsql_driver.c | 13 ++++- ext/pdo_pgsql/php_pdo_pgsql_int.h | 7 +++ ext/pdo_pgsql/tests/is_in_transaction.phpt | 66 ++++++++++++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 ext/pdo_pgsql/tests/is_in_transaction.phpt diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 1573290420..f50df54d48 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -683,6 +683,25 @@ static PHP_METHOD(PDO, rollBack) } /* }}} */ +/* {{{ proto bool PDO::inTransaction() + determine if inside a transaction */ +static PHP_METHOD(PDO, inTransaction) +{ + pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + PDO_CONSTRUCT_CHECK; + + if (!dbh->methods->in_transaction) { + RETURN_BOOL(dbh->in_txn); + } + + RETURN_LONG(dbh->methods->in_transaction(dbh TSRMLS_CC)); +} +/* }}} */ + static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC) /* {{{ */ { @@ -1246,6 +1265,7 @@ const zend_function_entry pdo_dbh_functions[] = { PHP_ME(PDO, beginTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, commit, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, rollBack, arginfo_pdo__void, ZEND_ACC_PUBLIC) + PHP_ME(PDO, inTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) PHP_ME(PDO, setAttribute, arginfo_pdo_setattribute, ZEND_ACC_PUBLIC) PHP_ME(PDO, exec, arginfo_pdo_exec, ZEND_ACC_PUBLIC) PHP_ME(PDO, query, NULL, ZEND_ACC_PUBLIC) diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index a9396c5a26..92280063c3 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -310,6 +310,7 @@ struct pdo_dbh_methods { pdo_dbh_check_liveness_func check_liveness; pdo_dbh_get_driver_methods_func get_driver_methods; pdo_dbh_request_shutdown persistent_shutdown; + pdo_dbh_txn_func in_transaction; }; /* }}} */ diff --git a/ext/pdo_pgsql/pdo_pgsql.c b/ext/pdo_pgsql/pdo_pgsql.c index 12af758802..045964cefa 100644 --- a/ext/pdo_pgsql/pdo_pgsql.c +++ b/ext/pdo_pgsql/pdo_pgsql.c @@ -86,6 +86,12 @@ ZEND_GET_MODULE(pdo_pgsql) PHP_MINIT_FUNCTION(pdo_pgsql) { REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT", PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_IDLE", (long)PGSQL_TRANSACTION_IDLE); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_ACTIVE", (long)PGSQL_TRANSACTION_ACTIVE); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INTRANS", (long)PGSQL_TRANSACTION_INTRANS); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INERROR", (long)PGSQL_TRANSACTION_INERROR); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_UNKNOWN", (long)PGSQL_TRANSACTION_UNKNOWN); + php_pdo_register_driver(&pdo_pgsql_driver); return SUCCESS; } diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index a9ce7e6032..bdb6fb9d18 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -497,6 +497,15 @@ static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC); } +static int pgsql_handle_in_transaction(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_pgsql_db_handle *H; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + return PQtransactionStatus(H->server); +} + /* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields]) Returns true if the copy worked fine or false if error */ static PHP_METHOD(PDO, pgsqlCopyFromArray) @@ -1020,7 +1029,9 @@ static struct pdo_dbh_methods pgsql_methods = { pdo_pgsql_fetch_error_func, pdo_pgsql_get_attribute, pdo_pgsql_check_liveness, /* check_liveness */ - pdo_pgsql_get_driver_methods /* get_driver_methods */ + pdo_pgsql_get_driver_methods, /* get_driver_methods */ + NULL, + pgsql_handle_in_transaction, }; static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index 7ebc457ee4..efe3a182f3 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -102,6 +102,13 @@ struct pdo_pgsql_lob_self { Oid oid; }; +enum pdo_pgsql_specific_constants { + PGSQL_TRANSACTION_IDLE = PQTRANS_IDLE, + PGSQL_TRANSACTION_ACTIVE = PQTRANS_ACTIVE, + PGSQL_TRANSACTION_INTRANS = PQTRANS_INTRANS, + PGSQL_TRANSACTION_INERROR = PQTRANS_INERROR, + PGSQL_TRANSACTION_UNKNOWN = PQTRANS_UNKNOWN +}; php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *stmt, int lfd, Oid oid TSRMLS_DC); extern php_stream_ops pdo_pgsql_lob_stream_ops; diff --git a/ext/pdo_pgsql/tests/is_in_transaction.phpt b/ext/pdo_pgsql/tests/is_in_transaction.phpt new file mode 100644 index 0000000000..99ff56162d --- /dev/null +++ b/ext/pdo_pgsql/tests/is_in_transaction.phpt @@ -0,0 +1,66 @@ +--TEST-- +PDO PgSQL isInTransaction +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); + +$db->exec('CREATE TABLE test (a integer not null primary key, b text)'); + +$db->beginTransaction(); +try { +echo "Test PDO::PGSQL_TRANSACTION_INTRANS\n"; +var_dump($db->inTransaction()); + +$stmt = $db->prepare("INSERT INTO test (a, b) values (?, ?)"); +$stmt->bindValue(1, 1); +$stmt->bindValue(2, "test insert"); +$stmt->execute(); + +$db->commit(); + +echo "Test PDO::PGSQL_TRANSACTION_IDLE\n"; +var_dump($db->inTransaction()); + +$db->beginTransaction(); + +try { +$stmt = $db->prepare("INSERT INTO test (a, b) values (?, ?)"); +$stmt->bindValue(1, "error"); +$stmt->bindValue(2, "test insert"); +$stmt->execute(); +} catch (Exception $e) { + /* We catch the exception because the execute will give error and we must test the PDO::PGSQL_TRANSACTION_ERROR */ + echo "Test PDO::PGSQL_TRANSACTION_INERROR\n"; + var_dump($db->inTransaction()); + $db->rollBack(); +} + +echo "Test PDO::PGSQL_TRANSACTION_IDLE\n"; +var_dump($db->inTransaction()); + +} catch (Exception $e) { + /* catch exceptions so that we can show the relative error */ + echo "Exception! at line ", $e->getLine(), "\n"; + var_dump($e->getMessage()); +} + +?> +--EXPECT-- +Test PDO::PGSQL_TRANSACTION_INTRANS +int(2) +Test PDO::PGSQL_TRANSACTION_IDLE +int(0) +Test PDO::PGSQL_TRANSACTION_INERROR +int(3) +Test PDO::PGSQL_TRANSACTION_IDLE +int(0) -- 2.40.0