Return the value associated to the key with a name obtained using * the following rules: * * 1) The first occurrence of '*' in 'pattern' is substituted with 'subst'. * * 2) If 'pattern' matches the "->" string, everything on the left of * the arrow is treated as the name of a hash field, and the part on the * left as the key name containing a hash. The value of the specified * fie
| 59 | * The returned object will always have its refcount increased by 1 |
| 60 | * when it is non-NULL. */ |
| 61 | robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst, int writeflag) { |
| 62 | char *p, *f, *k; |
| 63 | sds spat, ssub; |
| 64 | robj *keyobj, *fieldobj = NULL; |
| 65 | robj_roptr o; |
| 66 | int prefixlen, sublen, postfixlen, fieldlen; |
| 67 | |
| 68 | /* If the pattern is "#" return the substitution object itself in order |
| 69 | * to implement the "SORT ... GET #" feature. */ |
| 70 | spat = szFromObj(pattern); |
| 71 | if (spat[0] == '#' && spat[1] == '\0') { |
| 72 | incrRefCount(subst); |
| 73 | return subst; |
| 74 | } |
| 75 | |
| 76 | /* The substitution object may be specially encoded. If so we create |
| 77 | * a decoded object on the fly. Otherwise getDecodedObject will just |
| 78 | * increment the ref count, that we'll decrement later. */ |
| 79 | subst = getDecodedObject(subst); |
| 80 | ssub = szFromObj(subst); |
| 81 | |
| 82 | /* If we can't find '*' in the pattern we return NULL as to GET a |
| 83 | * fixed key does not make sense. */ |
| 84 | p = strchr(spat,'*'); |
| 85 | if (!p) { |
| 86 | decrRefCount(subst); |
| 87 | return NULL; |
| 88 | } |
| 89 | |
| 90 | /* Find out if we're dealing with a hash dereference. */ |
| 91 | if ((f = strstr(p+1, "->")) != NULL && *(f+2) != '\0') { |
| 92 | fieldlen = sdslen(spat)-(f-spat)-2; |
| 93 | fieldobj = createStringObject(f+2,fieldlen); |
| 94 | } else { |
| 95 | fieldlen = 0; |
| 96 | } |
| 97 | |
| 98 | /* Perform the '*' substitution. */ |
| 99 | prefixlen = p-spat; |
| 100 | sublen = sdslen(ssub); |
| 101 | postfixlen = sdslen(spat)-(prefixlen+1)-(fieldlen ? fieldlen+2 : 0); |
| 102 | keyobj = createStringObject(NULL,prefixlen+sublen+postfixlen); |
| 103 | k = szFromObj(keyobj); |
| 104 | memcpy(k,spat,prefixlen); |
| 105 | memcpy(k+prefixlen,ssub,sublen); |
| 106 | memcpy(k+prefixlen+sublen,p+1,postfixlen); |
| 107 | decrRefCount(subst); /* Incremented by decodeObject() */ |
| 108 | |
| 109 | /* Lookup substituted key */ |
| 110 | if (!writeflag) |
| 111 | o = lookupKeyRead(db,keyobj); |
| 112 | else |
| 113 | o = lookupKeyWrite(db,keyobj); |
| 114 | if (o == nullptr) goto noobj; |
| 115 | |
| 116 | if (fieldobj) { |
| 117 | if (o->type != OBJ_HASH) goto noobj; |
| 118 |
no test coverage detected