]> git.saurik.com Git - redis.git/commitdiff
Merge remote branch 'pietern/list-test'
authorantirez <antirez@gmail.com>
Sat, 31 Jul 2010 11:55:06 +0000 (13:55 +0200)
committerantirez <antirez@gmail.com>
Sat, 31 Jul 2010 11:55:06 +0000 (13:55 +0200)
src/object.c
src/t_zset.c
tests/unit/type/zset.tcl

index 51582619e12526ca6cec434cd50eee27055f8fe0..21268340c6d4e7e3b43766e5f405f51e5dfe8751 100644 (file)
@@ -1,5 +1,6 @@
 #include "redis.h"
 #include <pthread.h>
+#include <math.h>
 
 robj *createObject(int type, void *ptr) {
     robj *o;
@@ -319,7 +320,7 @@ int getDoubleFromObject(robj *o, double *target) {
         redisAssert(o->type == REDIS_STRING);
         if (o->encoding == REDIS_ENCODING_RAW) {
             value = strtod(o->ptr, &eptr);
-            if (eptr[0] != '\0') return REDIS_ERR;
+            if (eptr[0] != '\0' || isnan(value)) return REDIS_ERR;
         } else if (o->encoding == REDIS_ENCODING_INT) {
             value = (long)o->ptr;
         } else {
index 8efe3c2a4005057f7e3934232dc792b7c1a2df99..e93e5c406a5cb2088b134aeea7cbc249995ac83d 100644 (file)
@@ -327,11 +327,6 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
     zset *zs;
     double *score;
 
-    if (isnan(scoreval)) {
-        addReplySds(c,sdsnew("-ERR provide score is Not A Number (nan)\r\n"));
-        return;
-    }
-
     zsetobj = lookupKeyWrite(c->db,key);
     if (zsetobj == NULL) {
         zsetobj = createZsetObject();
@@ -361,7 +356,7 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
         }
         if (isnan(*score)) {
             addReplySds(c,
-                sdsnew("-ERR resulting score is Not A Number (nan)\r\n"));
+                sdsnew("-ERR resulting score is not a number (NaN)\r\n"));
             zfree(score);
             /* Note that we don't need to check if the zset may be empty and
              * should be removed here, as we can only obtain Nan as score if
@@ -417,15 +412,13 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
 
 void zaddCommand(redisClient *c) {
     double scoreval;
-
-    if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
+    if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
     zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,0);
 }
 
 void zincrbyCommand(redisClient *c) {
     double scoreval;
-
-    if (getDoubleFromObjectOrReply(c, c->argv[2], &scoreval, NULL) != REDIS_OK) return;
+    if (getDoubleFromObjectOrReply(c,c->argv[2],&scoreval,NULL) != REDIS_OK) return;
     zaddGenericCommand(c,c->argv[1],c->argv[3],scoreval,1);
 }
 
@@ -541,6 +534,10 @@ int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
 inline static void zunionInterAggregate(double *target, double val, int aggregate) {
     if (aggregate == REDIS_AGGR_SUM) {
         *target = *target + val;
+        /* The result of adding two doubles is NaN when one variable
+         * is +inf and the other is -inf. When these numbers are added,
+         * we maintain the convention of the result being 0.0. */
+        if (isnan(*target)) *target = 0.0;
     } else if (aggregate == REDIS_AGGR_MIN) {
         *target = val < *target ? val : *target;
     } else if (aggregate == REDIS_AGGR_MAX) {
@@ -604,8 +601,12 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
             if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
                 j++; remaining--;
                 for (i = 0; i < setnum; i++, j++, remaining--) {
-                    if (getDoubleFromObjectOrReply(c, c->argv[j], &src[i].weight, NULL) != REDIS_OK)
+                    if (getDoubleFromObjectOrReply(c,c->argv[j],&src[i].weight,
+                            "weight value is not a double") != REDIS_OK)
+                    {
+                        zfree(src);
                         return;
+                    }
                 }
             } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
                 j++; remaining--;
index da26484578a75c9bcedca818537d0143c3886b3b..642922e913be73637ac766681a7cc387b3b346a9 100644 (file)
@@ -433,6 +433,42 @@ start_server {tags {"zset"}} {
         list [r zinterstore zsetc 2 zseta zsetb aggregate max] [r zrange zsetc 0 -1 withscores]
     } {2 {b 2 c 3}}
     
+    foreach cmd {ZUNIONSTORE ZINTERSTORE} {
+        test "$cmd with +inf/-inf scores" {
+            r del zsetinf1 zsetinf2
+
+            r zadd zsetinf1 +inf key
+            r zadd zsetinf2 +inf key
+            r $cmd zsetinf3 2 zsetinf1 zsetinf2
+            assert_equal inf [r zscore zsetinf3 key]
+
+            r zadd zsetinf1 -inf key
+            r zadd zsetinf2 +inf key
+            r $cmd zsetinf3 2 zsetinf1 zsetinf2
+            assert_equal 0 [r zscore zsetinf3 key]
+
+            r zadd zsetinf1 +inf key
+            r zadd zsetinf2 -inf key
+            r $cmd zsetinf3 2 zsetinf1 zsetinf2
+            assert_equal 0 [r zscore zsetinf3 key]
+
+            r zadd zsetinf1 -inf key
+            r zadd zsetinf2 -inf key
+            r $cmd zsetinf3 2 zsetinf1 zsetinf2
+            assert_equal -inf [r zscore zsetinf3 key]
+        }
+
+        test "$cmd with NaN weights" {
+            r del zsetinf1 zsetinf2
+
+            r zadd zsetinf1 1.0 key
+            r zadd zsetinf2 1.0 key
+            assert_error "*weight value is not a double*" {
+                r $cmd zsetinf3 2 zsetinf1 zsetinf2 weights nan nan
+            }
+        }
+    }
+
     tags {"slow"} {
         test {ZSETs skiplist implementation backlink consistency test} {
             set diff 0
@@ -477,22 +513,16 @@ start_server {tags {"zset"}} {
         } {}
     }
 
-    test {ZSET element can't be set to nan with ZADD} {
-        set e {}
-        catch {r zadd myzset nan abc} e
-        set _ $e
-    } {*Not A Number*}
+    test {ZSET element can't be set to NaN with ZADD} {
+        assert_error "*not a double*" {r zadd myzset nan abc}
+    }
 
-    test {ZSET element can't be set to nan with ZINCRBY} {
-        set e {}
-        catch {r zincrby myzset nan abc} e
-        set _ $e
-    } {*Not A Number*}
+    test {ZSET element can't be set to NaN with ZINCRBY} {
+        assert_error "*not a double*" {r zadd myzset nan abc}
+    }
 
-    test {ZINCRBY calls leading to Nan are refused} {
-        set e {}
+    test {ZINCRBY calls leading to NaN result in error} {
         r zincrby myzset +inf abc
-        catch {r zincrby myzset -inf abc} e
-        set _ $e
-    } {*Not A Number*}
+        assert_error "*NaN*" {r zincrby myzset -inf abc}
+    }
 }