+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
+ ZEND_ARG_INFO(0, string)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, quote) {
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ char *quoted = PQescapeLiteral(obj->conn, str, len);
+
+ if (quoted) {
+ RETVAL_STRING(quoted, 1);
+ PQfreemem(quoted);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote string: %s", PQerrorMessage(obj->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
+ ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, quoteName) {
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ char *quoted = PQescapeIdentifier(obj->conn, str, len);
+
+ if (quoted) {
+ RETVAL_STRING(quoted, 1);
+ PQfreemem(quoted);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote name: %s", PQerrorMessage(obj->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
+ ZEND_ARG_INFO(0, bytea)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, escapeBytea) {
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ size_t escaped_len;
+ char *escaped_str = (char *) PQescapeByteaConn(obj->conn, (unsigned char *) str, len, &escaped_len);
+
+ if (escaped_str) {
+ RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
+ PQfreemem(escaped_str);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea: %s", PQerrorMessage(obj->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
+ ZEND_ARG_INFO(0, bytea)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, unescapeBytea) {
+ char *str;
+ int len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ size_t unescaped_len;
+ char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
+
+ if (unescaped_str) {
+ RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
+ PQfreemem(unescaped_str);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea: %s", PQerrorMessage(obj->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+static const char *isolation_level(long *isolation) {
+ switch (*isolation) {
+ case PHP_PQTXN_SERIALIZABLE:
+ return "SERIALIZABLE";
+ case PHP_PQTXN_REPEATABLE_READ:
+ return "REPEATABLE READ";
+ default:
+ *isolation = PHP_PQTXN_READ_COMMITTED;
+ /* no break */
+ case PHP_PQTXN_READ_COMMITTED:
+ return "READ COMMITTED";
+ }
+}
+
+static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
+{
+ if (!conn_obj) {
+ conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
+ }
+
+ if (conn_obj->conn) {
+ PGresult *res;
+ char *cmd;
+
+ spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
+ isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
+
+ res = PQexec(conn_obj->conn, cmd);
+
+ efree(cmd);
+
+ if (res) {
+ STATUS rv = php_pqres_success(res TSRMLS_CC);
+
+ PQclear(res);
+ return rv;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->conn));
+ return FAILURE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ return FAILURE;
+ }
+}
+
+static STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
+{
+ if (!conn_obj) {
+ conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
+ }
+
+ if (conn_obj->conn) {
+ char *cmd;
+
+ spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
+ isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
+
+ if (PQsendQuery(conn_obj->conn, cmd)) {
+ conn_obj->poller = PQconsumeInput;
+ efree(cmd);
+ return SUCCESS;
+ } else {
+ efree(cmd);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->conn));
+ return FAILURE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ return FAILURE;
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
+ ZEND_ARG_INFO(0, isolation)
+ ZEND_ARG_INFO(0, readonly)
+ ZEND_ARG_INFO(0, deferrable)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, startTransaction) {
+ zend_error_handling zeh;
+ long isolation = PHP_PQTXN_READ_COMMITTED;
+ zend_bool readonly = 0, deferrable = 0;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
+ STATUS rv;
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
+
+ txn->conn = getThis();
+ Z_ADDREF_P(txn->conn);
+ txn->isolation = isolation;
+ txn->readonly = readonly;
+ txn->deferrable = deferrable;
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
+ ZEND_ARG_INFO(0, isolation)
+ ZEND_ARG_INFO(0, readonly)
+ ZEND_ARG_INFO(0, deferrable)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, startTransactionAsync) {
+ zend_error_handling zeh;
+ long isolation = PHP_PQTXN_READ_COMMITTED;
+ zend_bool readonly = 0, deferrable = 0;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
+ STATUS rv;
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
+
+ txn->conn = getThis();
+ Z_ADDREF_P(txn->conn);
+ txn->isolation = isolation;
+ txn->readonly = readonly;
+ txn->deferrable = deferrable;
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+static zend_function_entry php_pqconn_methods[] = {
+ PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)