/* Retrieve value from hash by the field name. This operation
* already increases the refcount of the returned object. */
initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(struct sdshdr)));
- o = hashTypeGet(o, &fieldobj);
+ o = hashTypeGetObject(o, &fieldobj);
} else {
if (o->type != REDIS_STRING) return NULL;
list *operations;
unsigned int outputlen = 0;
int desc = 0, alpha = 0;
- int limit_start = 0, limit_count = -1, start, end;
+ long limit_start = 0, limit_count = -1, start, end;
int j, dontsort = 0, vectorlen;
int getop = 0; /* GET operation counter */
robj *sortval, *sortby = NULL, *storekey = NULL;
/* Lookup the key to sort. It must be of the right types */
sortval = lookupKeyRead(c->db,c->argv[1]);
- if (sortval == NULL) {
- addReply(c,shared.emptymultibulk);
- return;
- }
- if (sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
+ if (sortval && sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
sortval->type != REDIS_ZSET)
{
addReply(c,shared.wrongtypeerr);
/* Now we need to protect sortval incrementing its count, in the future
* SORT may have options able to overwrite/delete keys during the sorting
* and the sorted key itself may get destroied */
- incrRefCount(sortval);
+ if (sortval)
+ incrRefCount(sortval);
+ else
+ sortval = createListObject();
/* The SORT command has an SQL-alike syntax, parse it */
while(j < c->argc) {
} else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
alpha = 1;
} else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
- limit_start = atoi(c->argv[j+1]->ptr);
- limit_count = atoi(c->argv[j+2]->ptr);
+ if ((getLongFromObjectOrReply(c, c->argv[j+1], &limit_start, NULL) != REDIS_OK) ||
+ (getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL) != REDIS_OK)) return;
j+=2;
} else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
storekey = c->argv[j+1];
j++;
}
+ /* Destructively convert encoded sorted sets for SORT. */
+ if (sortval->type == REDIS_ZSET)
+ zsetConvert(sortval, REDIS_ENCODING_SKIPLIST);
+
/* Load the sorting vector with all the objects to sort */
switch(sortval->type) {
case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
} else if (sortval->type == REDIS_SET) {
setTypeIterator *si = setTypeInitIterator(sortval);
robj *ele;
- while((ele = setTypeNext(si)) != NULL) {
+ while((ele = setTypeNextObject(si)) != NULL) {
vector[j].obj = ele;
vector[j].u.score = 0;
vector[j].u.cmpobj = NULL;
dictEntry *setele;
di = dictGetIterator(set);
while((setele = dictNext(di)) != NULL) {
- vector[j].obj = dictGetEntryKey(setele);
+ vector[j].obj = dictGetKey(setele);
vector[j].u.score = 0;
vector[j].u.cmpobj = NULL;
j++;
} else {
redisPanic("Unknown type");
}
- redisAssert(j == vectorlen);
+ redisAssertWithInfo(c,sortval,j == vectorlen);
/* Now it's time to load the right scores in the sorting vector */
if (dontsort == 0) {
* far. We can just cast it */
vector[j].u.score = (long)byval->ptr;
} else {
- redisAssert(1 != 1);
+ redisAssertWithInfo(c,sortval,1 != 1);
}
}
outputlen = getop ? getop*(end-start+1) : end-start+1;
if (storekey == NULL) {
/* STORE option not specified, sent the sorting result to client */
- addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",outputlen));
+ addReplyMultiBulkLen(c,outputlen);
for (j = start; j <= end; j++) {
listNode *ln;
listIter li;
decrRefCount(val);
}
} else {
- redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
+ /* Always fails */
+ redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET);
}
}
}
listTypePush(sobj,val,REDIS_TAIL);
decrRefCount(val);
} else {
- /* always fails */
- redisAssert(sop->type == REDIS_SORT_GET);
+ /* Always fails */
+ redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET);
}
}
}
}
- dbReplace(c->db,storekey,sobj);
- /* Note: we add 1 because the DB is dirty anyway since even if the
- * SORT result is empty a new key is set and maybe the old content
- * replaced. */
- server.dirty += 1+outputlen;
- touchWatchedKey(c->db,storekey);
- addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",outputlen));
+ if (outputlen) setKey(c->db,storekey,sobj);
+ decrRefCount(sobj);
+ server.dirty += outputlen;
+ addReplyLongLong(c,outputlen);
}
/* Cleanup */