Merge pull request #6116 from AngusP/scan-types
SCAN: New Feature `SCAN cursor [TYPE type]` modifier suggested in issue #6107
This commit is contained in:
commit
722446510f
29
src/db.c
29
src/db.c
@ -614,7 +614,7 @@ int parseScanCursorOrReply(client *c, robj *o, unsigned long *cursor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This command implements SCAN, HSCAN and SSCAN commands.
|
/* This command implements SCAN, HSCAN and SSCAN commands.
|
||||||
* If object 'o' is passed, then it must be a Hash or Set object, otherwise
|
* If object 'o' is passed, then it must be a Hash, Set or Zset object, otherwise
|
||||||
* if 'o' is NULL the command will operate on the dictionary associated with
|
* if 'o' is NULL the command will operate on the dictionary associated with
|
||||||
* the current database.
|
* the current database.
|
||||||
*
|
*
|
||||||
@ -630,6 +630,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
|||||||
listNode *node, *nextnode;
|
listNode *node, *nextnode;
|
||||||
long count = 10;
|
long count = 10;
|
||||||
sds pat = NULL;
|
sds pat = NULL;
|
||||||
|
sds typename = NULL;
|
||||||
int patlen = 0, use_pattern = 0;
|
int patlen = 0, use_pattern = 0;
|
||||||
dict *ht;
|
dict *ht;
|
||||||
|
|
||||||
@ -666,6 +667,10 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
|||||||
use_pattern = !(pat[0] == '*' && patlen == 1);
|
use_pattern = !(pat[0] == '*' && patlen == 1);
|
||||||
|
|
||||||
i += 2;
|
i += 2;
|
||||||
|
} else if (!strcasecmp(c->argv[i]->ptr, "type") && o == NULL && j >= 2) {
|
||||||
|
/* SCAN for a particular type only applies to the db dict */
|
||||||
|
typename = c->argv[i+1]->ptr;
|
||||||
|
i+= 2;
|
||||||
} else {
|
} else {
|
||||||
addReply(c,shared.syntaxerr);
|
addReply(c,shared.syntaxerr);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -760,6 +765,13 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter an element if it isn't the type we want. */
|
||||||
|
if (!filter && o == NULL && typename){
|
||||||
|
robj* typecheck = lookupKeyReadWithFlags(c->db, kobj, LOOKUP_NOTOUCH);
|
||||||
|
char* type = getObjectTypeName(typecheck);
|
||||||
|
if (strcasecmp((char*) typename, type)) filter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Filter element if it is an expired key. */
|
/* Filter element if it is an expired key. */
|
||||||
if (!filter && o == NULL && expireIfNeeded(c->db, kobj)) filter = 1;
|
if (!filter && o == NULL && expireIfNeeded(c->db, kobj)) filter = 1;
|
||||||
|
|
||||||
@ -816,11 +828,8 @@ void lastsaveCommand(client *c) {
|
|||||||
addReplyLongLong(c,server.lastsave);
|
addReplyLongLong(c,server.lastsave);
|
||||||
}
|
}
|
||||||
|
|
||||||
void typeCommand(client *c) {
|
char* getObjectTypeName(robj *o) {
|
||||||
robj *o;
|
char* type;
|
||||||
char *type;
|
|
||||||
|
|
||||||
o = lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH);
|
|
||||||
if (o == NULL) {
|
if (o == NULL) {
|
||||||
type = "none";
|
type = "none";
|
||||||
} else {
|
} else {
|
||||||
@ -838,7 +847,13 @@ void typeCommand(client *c) {
|
|||||||
default: type = "unknown"; break;
|
default: type = "unknown"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addReplyStatus(c,type);
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void typeCommand(client *c) {
|
||||||
|
robj *o;
|
||||||
|
o = lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH);
|
||||||
|
addReplyStatus(c, getObjectTypeName(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdownCommand(client *c) {
|
void shutdownCommand(client *c) {
|
||||||
|
@ -652,6 +652,11 @@ typedef struct redisObject {
|
|||||||
void *ptr;
|
void *ptr;
|
||||||
} robj;
|
} robj;
|
||||||
|
|
||||||
|
/* The a string name for an object's type as listed above
|
||||||
|
* Native types are checked against the OBJ_STRING, OBJ_LIST, OBJ_* defines,
|
||||||
|
* and Module types have their registered name returned. */
|
||||||
|
char *getObjectTypeName(robj*);
|
||||||
|
|
||||||
/* Macro used to initialize a Redis object allocated on the stack.
|
/* Macro used to initialize a Redis object allocated on the stack.
|
||||||
* Note that this macro is taken near the structure definition to make sure
|
* Note that this macro is taken near the structure definition to make sure
|
||||||
* we'll update it when the structure is changed, to avoid bugs like
|
* we'll update it when the structure is changed, to avoid bugs like
|
||||||
|
@ -53,6 +53,51 @@ start_server {tags {"scan"}} {
|
|||||||
assert_equal 100 [llength $keys]
|
assert_equal 100 [llength $keys]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "SCAN TYPE" {
|
||||||
|
r flushdb
|
||||||
|
# populate only creates strings
|
||||||
|
r debug populate 1000
|
||||||
|
|
||||||
|
# Check non-strings are excluded
|
||||||
|
set cur 0
|
||||||
|
set keys {}
|
||||||
|
while 1 {
|
||||||
|
set res [r scan $cur type "list"]
|
||||||
|
set cur [lindex $res 0]
|
||||||
|
set k [lindex $res 1]
|
||||||
|
lappend keys {*}$k
|
||||||
|
if {$cur == 0} break
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 0 [llength $keys]
|
||||||
|
|
||||||
|
# Check strings are included
|
||||||
|
set cur 0
|
||||||
|
set keys {}
|
||||||
|
while 1 {
|
||||||
|
set res [r scan $cur type "string"]
|
||||||
|
set cur [lindex $res 0]
|
||||||
|
set k [lindex $res 1]
|
||||||
|
lappend keys {*}$k
|
||||||
|
if {$cur == 0} break
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 1000 [llength $keys]
|
||||||
|
|
||||||
|
# Check all three args work together
|
||||||
|
set cur 0
|
||||||
|
set keys {}
|
||||||
|
while 1 {
|
||||||
|
set res [r scan $cur type "string" match "key:*" count 10]
|
||||||
|
set cur [lindex $res 0]
|
||||||
|
set k [lindex $res 1]
|
||||||
|
lappend keys {*}$k
|
||||||
|
if {$cur == 0} break
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 1000 [llength $keys]
|
||||||
|
}
|
||||||
|
|
||||||
foreach enc {intset hashtable} {
|
foreach enc {intset hashtable} {
|
||||||
test "SSCAN with encoding $enc" {
|
test "SSCAN with encoding $enc" {
|
||||||
# Create the Set
|
# Create the Set
|
||||||
|
Loading…
x
Reference in New Issue
Block a user