+static int apply_to_oid(void *p, void *arg TSRMLS_DC)
+{
+ Oid **types = arg;
+ zval **ztype = p;
+
+ if (Z_TYPE_PP(ztype) != IS_LONG) {
+ convert_to_long_ex(ztype);
+ }
+
+ **types = Z_LVAL_PP(ztype);
+ ++*types;
+
+ if (*ztype != *(zval **)p) {
+ zval_ptr_dtor(ztype);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ char ***params;
+ HashTable *zdtor;
+ zval **zparam = p;
+
+ params = (char ***) va_arg(argv, char ***);
+ zdtor = (HashTable *) va_arg(argv, HashTable *);
+
+ if (Z_TYPE_PP(zparam) == IS_NULL) {
+ **params = NULL;
+ ++*params;
+ } else {
+ if (Z_TYPE_PP(zparam) != IS_STRING) {
+ convert_to_string_ex(zparam);
+ }
+
+ **params = Z_STRVAL_PP(zparam);
+ ++*params;
+
+ if (*zparam != *(zval **)p) {
+ zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
+ }
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
+ ZEND_ARG_INFO(0, query)
+ ZEND_ARG_ARRAY_INFO(0, params, 0)
+ ZEND_ARG_ARRAY_INFO(0, types, 1)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, execParams) {
+ zend_error_handling zeh;
+ char *query_str;
+ int query_len;
+ zval *zparams;
+ zval *ztypes = NULL;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ PGresult *res;
+ int count = 0;
+ Oid *types = NULL;
+ char **params = NULL;
+ HashTable zdtor;
+
+ ZEND_INIT_SYMTABLE(&zdtor);
+
+ if (ztypes && zend_hash_num_elements(Z_ARRVAL_P(ztypes))) {
+ Oid *tmp;
+
+ tmp = types = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(ztypes)), sizeof(Oid));
+ zend_hash_apply_with_argument(Z_ARRVAL_P(ztypes), apply_to_oid, &tmp TSRMLS_CC);
+ }
+ if ((count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
+ char **tmp;
+
+ tmp = params = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zparams)), sizeof(char *));
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
+ }
+
+ res = PQexecParams(obj->conn, query_str, count, types, params, NULL, NULL, 0);
+
+ zend_hash_destroy(&zdtor);
+ if (types) {
+ efree(types);
+ }
+ if (params) {
+ efree(params);
+ }
+
+ if (res) {
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+static STATUS php_pqconn_prepare(PGconn *conn, const char *name, const char *query, HashTable *typest TSRMLS_DC)
+{
+ Oid *types = NULL;
+ int count = 0;
+ PGresult *res;
+
+ if (typest && (count = zend_hash_num_elements(typest))) {
+ Oid *tmp;
+
+ tmp = types = ecalloc(count, sizeof(Oid));
+ zend_hash_apply_with_argument(typest, apply_to_oid, &tmp TSRMLS_CC);
+ }
+
+ res = PQprepare(conn, name, query, count, types);
+
+ if (types) {
+ efree(types);
+ }
+
+ if (res) {
+ if (PGRES_COMMAND_OK == PQresultStatus(res)) {
+ return SUCCESS;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQresultErrorMessage(res));
+ }
+ PQclear(res);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(conn));
+ }
+ return FAILURE;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
+ ZEND_ARG_INFO(0, "name")
+ ZEND_ARG_INFO(0, "query")
+ ZEND_ARG_ARRAY_INFO(0, "types", 1)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, prepare) {
+ zend_error_handling zeh;
+ zval *ztypes = NULL;
+ char *name_str, *query_str;
+ int name_len, *query_len;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn) {
+ if (SUCCESS == php_pqconn_prepare(obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, getThis(), name_str, NULL TSRMLS_CC);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
+ }
+ }
+}
+
+static zend_function_entry php_pqconn_methods[] = {