diff options
author | michael-grunder <michael-grunder@github.com> | 2012-05-04 23:12:03 +0400 |
---|---|---|
committer | michael-grunder <michael-grunder@github.com> | 2012-05-04 23:12:03 +0400 |
commit | d59b53b6b5779113ef8bf4d6f951bddd75e7f99d (patch) | |
tree | 9a8e68ef3c88dc4ad03e31389311db70b46b95a8 | |
parent | 3160a64a17fc8824fcdbbcc5d17b8c18bc77ff52 (diff) |
Implemented INCRBYFLOAT and HINCRBYFLOAT
-rw-r--r-- | library.c | 2 | ||||
-rwxr-xr-x | php_redis.h | 2 | ||||
-rwxr-xr-x | redis.c | 89 | ||||
-rw-r--r-- | tests/TestRedis.php | 47 |
4 files changed, 130 insertions, 10 deletions
@@ -566,6 +566,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 82ed17f5..6392c375 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); @@ -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) @@ -189,6 +190,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 +1050,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) @@ -4506,6 +4540,59 @@ 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, val_len, key_free; + double val; + int i, dcount; + + // 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; + } + + // Start at the begining unless the first character is '-' + /*i = val_len && val[0] == '-' ? 1 : 0; + + // Initially we have no '.' characters + dcount = 0; + + // Iterate our string + for(; i<val_len; ++i) { + // Increment our decimal count and skip this iteration if we're on one + if(val[i] == '.') { + ++dcount; + continue; + } + + // We're invalid if this character isn't numeric, or if we have too many decimals + if((val[i] < '0' || val[i] > '9') || dcount > 1) { + 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 +4622,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 80810ddf..5a19e31d 100644 --- a/tests/TestRedis.php +++ b/tests/TestRedis.php @@ -354,7 +354,7 @@ class Redis_Test extends TestSuite $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 @@ class Redis_Test extends TestSuite $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 @@ class Redis_Test extends TestSuite // 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], '<?php +// fwrite($pipes[0], '<?php // sleep(2); // $r = new Redis; // $r->connect("'.self::HOST.'", '.self::PORT.'); @@ -645,11 +667,11 @@ class Redis_Test extends TestSuite // } // $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 @@ class Redis_Test extends TestSuite } //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); @@ -1909,6 +1931,15 @@ class Redis_Test extends TestSuite $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'))); |