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);
}