+static zval **column_at(zval *row, int col TSRMLS_DC)
+{
+ zval **data = NULL;
+ HashTable *ht = HASH_OF(row);
+ int count = zend_hash_num_elements(ht);
+
+ if (col < count) {
+ zend_hash_internal_pointer_reset(ht);
+ while (col-- > 0) {
+ zend_hash_move_forward(ht);
+ }
+ zend_hash_get_current_data(ht, (void *) &data);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d does excess column count %d", col, count);
+ }
+ return data;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
+ ZEND_ARG_INFO(0, col_num)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqres, fetchCol) {
+ zend_error_handling zeh;
+ long fetch_col = 0;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
+ php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ zval **row = php_pqres_iteration(getThis(), obj, obj->iter ? obj->iter->fetch_type : 0 TSRMLS_CC);
+
+ if (row) {
+ zval **col = column_at(*row, fetch_col TSRMLS_CC);
+
+ if (col) {
+ RETVAL_ZVAL(*col, 1, 0);
+ } else {
+ RETVAL_FALSE;
+ }
+ } else {
+ RETVAL_FALSE;
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+}
+
+static zend_function_entry php_pqres_methods[] = {
+ PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
+ PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
+ {0}
+};
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
+ ZEND_ARG_OBJ_INFO(0, "Connection", "pq\\Connection", 0)
+ ZEND_ARG_INFO(0, "name")
+ ZEND_ARG_INFO(0, "query")
+ ZEND_ARG_ARRAY_INFO(0, "types", 1)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqstm, __construct) {
+ zend_error_handling zeh;
+ zval *zconn, *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, "Oss|a/!", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes)) {
+ php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ php_pqconn_object_t *conn_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (conn_obj->conn) {
+ if (SUCCESS == php_pqconn_prepare(conn_obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
+ Z_ADDREF_P(zconn);
+ obj->conn = zconn;
+ obj->name = estrdup(name_str);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
+ ZEND_ARG_ARRAY_INFO(0, "params", 1)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqstm, exec) {
+ zend_error_handling zeh;
+ zval *zparams = NULL;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
+ php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn && obj->name) {
+ php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
+
+ if (conn_obj->conn) {
+ int count = 0;
+ char **params = NULL;
+ HashTable zdtor;
+ PGresult *res;
+
+ ZEND_INIT_SYMTABLE(&zdtor);
+
+ if (zparams && (count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
+ char **tmp;
+
+ tmp = params = ecalloc(count, sizeof(char *));
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
+ }
+
+ res = PQexecPrepared(conn_obj->conn, obj->name, count, (const char *const*) params, NULL, NULL, 0);
+
+ if (params) {
+ efree(params);
+ }
+ zend_hash_destroy(&zdtor);
+
+ if (res) {
+ if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
+ 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 statement: %s", PQerrorMessage(conn_obj->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqstm, desc) {
+ zend_error_handling zeh;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->conn && obj->name) {
+ php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
+
+ if (conn_obj->conn) {
+ PGresult *res = PQdescribePrepared(conn_obj->conn, obj->name);
+
+ if (res) {
+ if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
+ int p, params;
+
+ array_init(return_value);
+ for (p = 0, params = PQnparams(res); p < params; ++p) {
+ add_next_index_long(return_value, PQparamtype(res, p));
+ }
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(conn_obj->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+static zend_function_entry php_pqstm_methods[] = {
+ PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
+ PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)