static void php_memc_incdec_impl()

in php_memcached.c [2283:2380]


static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr)
{
	zend_string *key, *server_key = NULL;
	zend_long offset = 1;
	zend_long expiry = 0;
	zend_long initial = 0;
	uint64_t value = UINT64_MAX;
	memcached_return status;
	int n_args = ZEND_NUM_ARGS();

	MEMC_METHOD_INIT_VARS;

	if (!by_key) {
		/* "S|lll" */
		ZEND_PARSE_PARAMETERS_START(1, 4)
			Z_PARAM_STR(key)
			Z_PARAM_OPTIONAL
			Z_PARAM_LONG(offset)
			Z_PARAM_LONG(initial)
			Z_PARAM_LONG(expiry)
		ZEND_PARSE_PARAMETERS_END();
	} else {
		/* "SS|lll" */
		ZEND_PARSE_PARAMETERS_START(2, 5)
			Z_PARAM_STR(server_key)
			Z_PARAM_STR(key)
			Z_PARAM_OPTIONAL
			Z_PARAM_LONG(offset)
			Z_PARAM_LONG(initial)
			Z_PARAM_LONG(expiry)
		ZEND_PARSE_PARAMETERS_END();
	}

	MEMC_METHOD_FETCH_OBJECT;
	s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
	MEMC_CHECK_KEY(intern, key);

	if (offset < 0) {
		php_error_docref(NULL, E_WARNING, "offset cannot be a negative value");
		RETURN_FALSE;
	}

	if ((!by_key && n_args < 3) || (by_key && n_args < 4)) {
		if (by_key) {
			if (incr) {
				status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
			} else {
				status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
			}
		} else {
			/* The libmemcached API has a quirk that memcached_increment() takes only a 32-bit
			 * offset, but memcached_increment_by_key() and all other increment and decrement
			 * functions take a 64-bit offset. The memcached protocol allows increment/decrement
			 * greater than UINT_MAX, so we just work around memcached_increment() here.
			 */
			if (incr) {
				status = memcached_increment_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
			} else {
				status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value);
			}
		}

	} else {
		zend_long retries = memc_user_data->store_retry_count;

retry_inc_dec:
		if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
			php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol");
			RETURN_FALSE;
		}
		if (by_key) {
			if (incr) {
				status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value);
			} else {
				status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value);
			}
		} else {
			if (incr) {
				status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value);
			} else {
				status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value);
			}
		}
		if (s_should_retry_write(intern, status) && retries-- > 0) {
			goto retry_inc_dec;
		}
	}

	if (s_memc_status_handle_result_code(intern, status) == FAILURE) {
		RETURN_FALSE;
	}

	if (value == UINT64_MAX) {
		RETURN_FALSE;
	}

	RETURN_LONG((long)value);
}