diff --git a/src/module.c b/src/module.c index 5c8af588..c866dd77 100644 --- a/src/module.c +++ b/src/module.c @@ -1612,8 +1612,58 @@ int RM_HashSet(RedisModuleKey *key, int flags, ...) { * * The function returns REDISMODULE_OK on success and REDISMODULE_ERR if * the key is not an hash value. + * + * Memory management: + * + * The returned RedisModuleString objects should be released with + * RedisModule_FreeString(), or by enabling automatic memory management. */ int RM_HashGet(RedisModuleKey *key, int flags, ...) { + va_list ap; + if (key->value && key->value->type != OBJ_HASH) return REDISMODULE_ERR; + + va_start(ap, flags); + while(1) { + RedisModuleString *field, **valueptr; + int *existsptr; + /* Get the field object and the value pointer to pointer. */ + if (flags & REDISMODULE_HGET_CFIELDS) { + char *cfield = va_arg(ap,char*); + if (cfield == NULL) break; + field = createRawStringObject(cfield,strlen(cfield)); + } else { + field = va_arg(ap,RedisModuleString*); + if (field == NULL) break; + } + + /* Query the hash for existence or value object. */ + if (flags & REDISMODULE_HGET_EXISTS) { + existsptr = va_arg(ap,int*); + if (key->value) + *existsptr = hashTypeExists(key->value,field->ptr); + else + *existsptr = 0; + } else { + valueptr = va_arg(ap,RedisModuleString**); + if (key->value) { + *valueptr = hashTypeGetValueObject(key->value,field->ptr); + if (*valueptr) { + robj *decoded = getDecodedObject(*valueptr); + decrRefCount(*valueptr); + *valueptr = decoded; + } + if (*valueptr) + autoMemoryAdd(key->ctx,REDISMODULE_AM_STRING,*valueptr); + } else { + *valueptr = NULL; + } + } + + /* Cleanup */ + if (flags & REDISMODULE_HSET_CFIELDS) decrRefCount(field); + } + va_end(ap); + return REDISMODULE_ERR; } /* -------------------------------------------------------------------------- @@ -2078,6 +2128,7 @@ void moduleRegisterCoreAPI(void) { REGISTER_API(ZsetRangePrev); REGISTER_API(ZsetRangeEndReached); REGISTER_API(HashSet); + REGISTER_API(HashGet); } /* Global initialization at Redis startup. */ diff --git a/src/modules/helloworld.c b/src/modules/helloworld.c index e635d0df..2caac16d 100644 --- a/src/modules/helloworld.c +++ b/src/modules/helloworld.c @@ -438,10 +438,13 @@ int HelloHCopy_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE); } - /* XXX modify me. */ - RedisModule_HashSet(key,REDISMODULE_HSET_NONE,argv[2],argv[3],NULL); - RedisModule_HashSet(key,REDISMODULE_HSET_CFIELDS,"foo",argv[3],NULL); - RedisModule_ReplyWithLongLong(ctx,0); + /* Get the old field value. */ + RedisModuleString *oldval; + RedisModule_HashGet(key,REDISMODULE_HGET_NONE,argv[2],&oldval,NULL); + if (oldval) { + RedisModule_HashSet(key,REDISMODULE_HSET_NONE,argv[3],oldval,NULL); + } + RedisModule_ReplyWithLongLong(ctx,oldval != NULL); return REDISMODULE_OK; } diff --git a/src/redismodule.h b/src/redismodule.h index f911298e..d96e9645 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -150,6 +150,7 @@ int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key); int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key); int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key); int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...); +int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...); /* This is included inline inside each Redis module. */ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) { @@ -215,6 +216,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ZsetRangePrev); REDISMODULE_GET_API(ZsetRangeEndReached); REDISMODULE_GET_API(HashSet); + REDISMODULE_GET_API(HashGet); RedisModule_SetModuleAttribs(ctx,name,ver,apiver); return REDISMODULE_OK;