diff --git a/library.c b/library.c index faef6232ca..930244a98f 100644 --- a/library.c +++ b/library.c @@ -278,6 +278,16 @@ redis_cmd_format_static(char **ret, char *keyword, char *format, ...) { smart_str_appendl(&buf, tmp, tmp_len); } break; + case 'l': + case 'L': { + long l = va_arg(ap, long); + char tmp[32]; + int tmp_len = snprintf(tmp, sizeof(tmp), "%ld", l); + smart_str_append_long(&buf, tmp_len); + smart_str_appendl(&buf, _NL, sizeof(_NL) -1); + smart_str_appendl(&buf, tmp, tmp_len); + } + break; } p++; smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); @@ -566,6 +576,8 @@ PHPAPI void redis_long_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s } } + + PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, int flag) { /* diff --git a/php_redis.h b/php_redis.h index 82ed17f5a5..6392c375af 100755 --- a/php_redis.h +++ b/php_redis.h @@ -44,6 +44,7 @@ PHP_METHOD(Redis, exists); PHP_METHOD(Redis, delete); PHP_METHOD(Redis, incr); PHP_METHOD(Redis, incrBy); +PHP_METHOD(Redis, incrByFloat); PHP_METHOD(Redis, decr); PHP_METHOD(Redis, decrBy); PHP_METHOD(Redis, type); @@ -141,6 +142,7 @@ PHP_METHOD(Redis, hVals); PHP_METHOD(Redis, hGetAll); PHP_METHOD(Redis, hExists); PHP_METHOD(Redis, hIncrBy); +PHP_METHOD(Redis, hIncrByFloat); PHP_METHOD(Redis, hMset); PHP_METHOD(Redis, hMget); diff --git a/redis.c b/redis.c index d1f5e5d17c..9eb9eb98f9 100755 --- a/redis.c +++ b/redis.c @@ -91,6 +91,7 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, delete, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, incr, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, incrBy, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, incrByFloat, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, decr, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, decrBy, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, type, NULL, ZEND_ACC_PUBLIC) @@ -176,6 +177,7 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, zUnion, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, zIncrBy, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, expireAt, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, pexpire, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, pexpireAt, NULL, ZEND_ACC_PUBLIC) /* 1.2 */ @@ -189,6 +191,7 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, hGetAll, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, hExists, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, hIncrBy, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, hIncrByFloat, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, hMset, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, hMget, NULL, ZEND_ACC_PUBLIC) @@ -1048,6 +1051,38 @@ PHP_METHOD(Redis, incrBy){ } /* }}} */ +/* {{{ proto float Redis::incrByFloat(string key, float value) + */ +PHP_METHOD(Redis, incrByFloat) { + zval *object; + RedisSock *redis_sock; + char *key = NULL, *cmd; + int key_len, cmd_len, key_free; + double val; + + if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osd", + &object, redis_ce, &key, &key_len, &val) == FAILURE) { + RETURN_FALSE; + } + + if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + // Prefix our key, free it if we have + key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC); + if(key_free) efree(key); + + // Format our INCRBYFLOAT command + cmd_len = redis_cmd_format_static(&cmd, "INCRBYFLOAT", "sf", key, key_len, val); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_bulk_double_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_bulk_double_response); +} + /* {{{ proto boolean Redis::decr(string key [,int value]) */ PHP_METHOD(Redis, decr) @@ -2858,7 +2893,7 @@ PHPAPI void generic_expire_cmd(INTERNAL_FUNCTION_PARAMETERS, char *keyword, int } key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC); - cmd_len = redis_cmd_format_static(&cmd, keyword, "sd", key, key_len, t); + cmd_len = redis_cmd_format_static(&cmd, keyword, "sl", key, key_len, t); if(key_free) efree(key); REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); @@ -4506,6 +4541,37 @@ PHPAPI void array_zip_values_and_scores(RedisSock *redis_sock, zval *z_tab, int efree(z_ret); } +PHP_METHOD(Redis, hIncrByFloat) +{ + zval *object; + RedisSock *redis_sock; + char *key = NULL, *cmd, *member; + int key_len, member_len, cmd_len, key_free; + double val; + + // Validate we have the right number of arguments + if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ossd", + &object, redis_ce, + &key, &key_len, &member, &member_len, &val) == FAILURE) { + RETURN_FALSE; + } + + // Grab our socket + if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC); + cmd_len = redis_cmd_format_static(&cmd, "HINCRBYFLOAT", "ssf", key, key_len, member, member_len, val); + if(key_free) efree(key); + + REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); + IF_ATOMIC() { + redis_bulk_double_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL); + } + REDIS_PROCESS_RESPONSE(redis_bulk_double_response); +} + PHP_METHOD(Redis, hIncrBy) { zval *object; @@ -4535,8 +4601,6 @@ PHP_METHOD(Redis, hIncrBy) } } - - /* HINCRBY key member amount */ key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC); cmd_len = redis_cmd_format_static(&cmd, "HINCRBY", "sss", key, key_len, member, member_len, val, val_len); diff --git a/tests/TestRedis.php b/tests/TestRedis.php index 80810ddf09..f6970dba22 100644 --- a/tests/TestRedis.php +++ b/tests/TestRedis.php @@ -354,7 +354,7 @@ public function testIncr() $this->redis->incr('key'); $this->assertEquals(2, (int)$this->redis->get('key')); - $this->redis->incr('key', 3); + $this->redis->incr('key', 3); $this->assertEquals(5, (int)$this->redis->get('key')); $this->redis->incrBy('key', 3); @@ -376,6 +376,28 @@ public function testIncr() $this->redis->incr('key'); $this->assertTrue("abc" === $this->redis->get('key')); + // incrbyfloat + + $this->redis->delete('key'); + + $this->redis->set('key', 0); + + $this->redis->incrbyfloat('key', 1.5); + $this->assertEquals('1.5', $this->redis->get('key')); + + $this->redis->incrbyfloat('key', 2.25); + $this->assertEquals('3.75', $this->redis->get('key')); + + $this->redis->incrbyfloat('key', -2.25); + $this->assertEquals('1.5', $this->redis->get('key')); + + $this->redis->set('key', 'abc'); + + $this->redis->incrbyfloat('key', 1.5); + $this->assertTrue("abc" === $this->redis->get('key')); + + $this->redis->incrbyfloat('key', -1.5); + $this->assertTrue("abc" === $this->redis->get('key')); } public function testDecr() @@ -627,16 +649,16 @@ public function testblockingPop() { // TODO: fix this broken test. // $this->redis->delete('list'); // $params = array( -// 0 => array("pipe", "r"), +// 0 => array("pipe", "r"), // 1 => array("pipe", "w"), // 2 => array("file", "/dev/null", "w") // ); // if(function_exists('proc_open')) { // $env = array('PHPREDIS_key' =>'list', 'PHPREDIS_value' => 'value'); // $process = proc_open('php', $params, $pipes, '/tmp', $env); -// +// // if (is_resource($process)) { -// fwrite($pipes[0], 'connect("'.self::HOST.'", '.self::PORT.'); @@ -645,11 +667,11 @@ public function testblockingPop() { // } // $r->lPush($_ENV["PHPREDIS_key"], $_ENV["PHPREDIS_value"]); // ?' . '>'); -// +// // fclose($pipes[0]); // fclose($pipes[1]); // $re = proc_close($process); -// +// // $this->assertTrue($this->redis->blPop(array('list'), 5) === array("list", "value")); // } // } @@ -684,8 +706,8 @@ public function testlSize() } //lInsert, lPopx, rPopx - public function testlPopx() { - //test lPushx/rPushx + public function testlPopx() { + //test lPushx/rPushx $this->redis->delete('keyNotExists'); $this->assertTrue($this->redis->lPushx('keyNotExists', 'value') === 0); $this->assertTrue($this->redis->rPushx('keyNotExists', 'value') === 0); @@ -1831,7 +1853,7 @@ public function testZX() { $this->redis->delete('z'); $this->redis->zadd('z', 1, 'one'); $this->redis->zadd('z', 2, 'two'); - $this->redis->zadd('z', 5, 'five'); + $this->redis->zadd('z', 5, 'five'); $this->assertTrue(0 === $this->redis->zRank('z', 'one')); $this->assertTrue(1 === $this->redis->zRank('z', 'two')); @@ -1840,6 +1862,7 @@ public function testZX() { $this->assertTrue(2 === $this->redis->zRevRank('z', 'one')); $this->assertTrue(1 === $this->redis->zRevRank('z', 'two')); $this->assertTrue(0 === $this->redis->zRevRank('z', 'five')); + } public function testHashes() { @@ -1909,6 +1932,15 @@ public function testHashes() { $this->redis->hSet('h', 'y', 'not-a-number'); $this->assertTrue(FALSE === $this->redis->hIncrBy('h', 'y', 1)); + // hIncrByFloat + $this->redis->delete('h'); + $this->assertTrue(1.5 === $this->redis->hIncrByFloat('h','x', 1.5)); + $this->assertTrue(3.0 === $this->redis->hincrByFloat('h','x', 1.5)); + $this->assertTrue(1.5 === $this->redis->hincrByFloat('h','x', -1.5)); + + $this->redis->hset('h','y','not-a-number'); + $this->assertTrue(FALSE === $this->redis->hIncrByFloat('h', 'y', 1.5)); + // hmset $this->redis->delete('h'); $this->assertTrue(TRUE === $this->redis->hMset('h', array('x' => 123, 'y' => 456, 'z' => 'abc')));