+ return rv;
+}
+
+typedef struct php_pqres_col {
+ char *name;
+ int num;
+} php_pqres_col_t;
+
+static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col TSRMLS_DC)
+{
+ long index = -1;
+ char *name = NULL;
+
+ switch (Z_TYPE_P(zcol)) {
+ default:
+ convert_to_string(zcol);
+ /* no break */
+
+ case IS_STRING:
+ if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) {
+ name = Z_STRVAL_P(zcol);
+ }
+ break;
+
+ case IS_LONG:
+ index = Z_LVAL_P(zcol);
+ break;
+ }
+
+ if (name) {
+ col->name = name;
+ col->num = PQfnumber(obj->intern->res, name);
+ } else {
+ col->name = PQfname(obj->intern->res, index);
+ col->num = index;
+ }
+
+ if (!col->name) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column at index %ld", index);
+ return FAILURE;
+ }
+ if (col->num == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column with name '%s'", name);
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+static int compare_index(const void *lptr, const void *rptr TSRMLS_DC)
+{
+ const Bucket *l = *(const Bucket **) lptr;
+ const Bucket *r = *(const Bucket **) rptr;
+
+ if (l->h < r->h) {
+ return -1;
+ }
+ if (l->h > r->h) {
+ return 1;
+ }
+ return 0;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind, 0, 0, 2)
+ ZEND_ARG_INFO(0, col)
+ ZEND_ARG_INFO(1, ref)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqres, bind) {
+ zval *zcol, *zref;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z", &zcol, &zref)) {
+ php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ php_pqres_col_t col;
+
+ if (SUCCESS == column_nn(obj, zcol, &col TSRMLS_CC)) {
+ Z_ADDREF_P(zref);
+ if (SUCCESS == zend_hash_index_update(&obj->intern->bound, col.num, (void *) &zref, sizeof(zval *), NULL)) {
+ zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC);
+ RETVAL_TRUE;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to bind column %s@%d", col.name, col.num);
+ RETVAL_FALSE;
+ }
+ } else {
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+static int apply_bound(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
+{
+ zval **zvalue, **zbound = p;
+ zval **zrow = va_arg(argv, zval **);
+
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(zrow), key->h, (void *) &zvalue)) {
+ zval_dtor(*zbound);
+ ZVAL_COPY_VALUE(*zbound, *zvalue);
+ ZVAL_NULL(*zvalue);
+ zval_ptr_dtor(zvalue);
+ Z_ADDREF_P(*zbound);
+ *zvalue = *zbound;
+ return ZEND_HASH_APPLY_KEEP;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column ad index %lu", key->h);
+ return ZEND_HASH_APPLY_STOP;
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqres, fetchBound) {
+ zend_error_handling zeh;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ zval **row = NULL;
+
+ if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row TSRMLS_CC)) {
+ if (row) {
+ zend_hash_apply_with_arguments(&obj->intern->bound TSRMLS_CC, apply_bound, 1, row);
+ RETVAL_ZVAL(*row, 1, 0);
+ }
+ }
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);