]> git.saurik.com Git - redis.git/blame - src/t_string.c
command line option in test suite to activate valgrind mode
[redis.git] / src / t_string.c
CommitLineData
e2641e09 1#include "redis.h"
2
3/*-----------------------------------------------------------------------------
4 * String Commands
5 *----------------------------------------------------------------------------*/
6
7void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
8 int retval;
9 long seconds = 0; /* initialized to avoid an harmness warning */
10
11 if (expire) {
12 if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
13 return;
14 if (seconds <= 0) {
3ab20376 15 addReplyError(c,"invalid expire time in SETEX");
e2641e09 16 return;
17 }
18 }
19
e2641e09 20 retval = dbAdd(c->db,key,val);
21 if (retval == REDIS_ERR) {
22 if (!nx) {
23 dbReplace(c->db,key,val);
24 incrRefCount(val);
25 } else {
26 addReply(c,shared.czero);
27 return;
28 }
29 } else {
30 incrRefCount(val);
31 }
5b4bff9c 32 touchWatchedKey(c->db,key);
e2641e09 33 server.dirty++;
34 removeExpire(c->db,key);
35 if (expire) setExpire(c->db,key,time(NULL)+seconds);
36 addReply(c, nx ? shared.cone : shared.ok);
37}
38
39void setCommand(redisClient *c) {
75b41de8 40 c->argv[2] = tryObjectEncoding(c->argv[2]);
e2641e09 41 setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
42}
43
44void setnxCommand(redisClient *c) {
75b41de8 45 c->argv[2] = tryObjectEncoding(c->argv[2]);
e2641e09 46 setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
47}
48
49void setexCommand(redisClient *c) {
75b41de8 50 c->argv[3] = tryObjectEncoding(c->argv[3]);
e2641e09 51 setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
52}
53
54int getGenericCommand(redisClient *c) {
55 robj *o;
56
57 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
58 return REDIS_OK;
59
60 if (o->type != REDIS_STRING) {
61 addReply(c,shared.wrongtypeerr);
62 return REDIS_ERR;
63 } else {
64 addReplyBulk(c,o);
65 return REDIS_OK;
66 }
67}
68
69void getCommand(redisClient *c) {
70 getGenericCommand(c);
71}
72
73void getsetCommand(redisClient *c) {
74 if (getGenericCommand(c) == REDIS_ERR) return;
75b41de8 75 c->argv[2] = tryObjectEncoding(c->argv[2]);
e2641e09 76 dbReplace(c->db,c->argv[1],c->argv[2]);
77 incrRefCount(c->argv[2]);
5b4bff9c 78 touchWatchedKey(c->db,c->argv[1]);
e2641e09 79 server.dirty++;
80 removeExpire(c->db,c->argv[1]);
81}
82
83void mgetCommand(redisClient *c) {
84 int j;
85
0537e7bf 86 addReplyMultiBulkLen(c,c->argc-1);
e2641e09 87 for (j = 1; j < c->argc; j++) {
88 robj *o = lookupKeyRead(c->db,c->argv[j]);
89 if (o == NULL) {
90 addReply(c,shared.nullbulk);
91 } else {
92 if (o->type != REDIS_STRING) {
93 addReply(c,shared.nullbulk);
94 } else {
95 addReplyBulk(c,o);
96 }
97 }
98 }
99}
100
101void msetGenericCommand(redisClient *c, int nx) {
102 int j, busykeys = 0;
103
104 if ((c->argc % 2) == 0) {
3ab20376 105 addReplyError(c,"wrong number of arguments for MSET");
e2641e09 106 return;
107 }
108 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
109 * set nothing at all if at least one already key exists. */
110 if (nx) {
111 for (j = 1; j < c->argc; j += 2) {
112 if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
113 busykeys++;
114 }
115 }
116 }
117 if (busykeys) {
118 addReply(c, shared.czero);
119 return;
120 }
121
122 for (j = 1; j < c->argc; j += 2) {
123 c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
124 dbReplace(c->db,c->argv[j],c->argv[j+1]);
125 incrRefCount(c->argv[j+1]);
126 removeExpire(c->db,c->argv[j]);
5b4bff9c 127 touchWatchedKey(c->db,c->argv[j]);
e2641e09 128 }
129 server.dirty += (c->argc-1)/2;
130 addReply(c, nx ? shared.cone : shared.ok);
131}
132
133void msetCommand(redisClient *c) {
134 msetGenericCommand(c,0);
135}
136
137void msetnxCommand(redisClient *c) {
138 msetGenericCommand(c,1);
139}
140
141void incrDecrCommand(redisClient *c, long long incr) {
142 long long value;
143 robj *o;
144
145 o = lookupKeyWrite(c->db,c->argv[1]);
146 if (o != NULL && checkType(c,o,REDIS_STRING)) return;
147 if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
148
149 value += incr;
150 o = createStringObjectFromLongLong(value);
151 dbReplace(c->db,c->argv[1],o);
5b4bff9c 152 touchWatchedKey(c->db,c->argv[1]);
e2641e09 153 server.dirty++;
154 addReply(c,shared.colon);
155 addReply(c,o);
156 addReply(c,shared.crlf);
157}
158
159void incrCommand(redisClient *c) {
160 incrDecrCommand(c,1);
161}
162
163void decrCommand(redisClient *c) {
164 incrDecrCommand(c,-1);
165}
166
167void incrbyCommand(redisClient *c) {
168 long long incr;
169
170 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
171 incrDecrCommand(c,incr);
172}
173
174void decrbyCommand(redisClient *c) {
175 long long incr;
176
177 if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != REDIS_OK) return;
178 incrDecrCommand(c,-incr);
179}
180
181void appendCommand(redisClient *c) {
182 int retval;
183 size_t totlen;
184 robj *o;
185
186 o = lookupKeyWrite(c->db,c->argv[1]);
75b41de8 187 c->argv[2] = tryObjectEncoding(c->argv[2]);
e2641e09 188 if (o == NULL) {
189 /* Create the key */
190 retval = dbAdd(c->db,c->argv[1],c->argv[2]);
191 incrRefCount(c->argv[2]);
192 totlen = stringObjectLen(c->argv[2]);
193 } else {
194 if (o->type != REDIS_STRING) {
195 addReply(c,shared.wrongtypeerr);
196 return;
197 }
198 /* If the object is specially encoded or shared we have to make
199 * a copy */
200 if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
201 robj *decoded = getDecodedObject(o);
202
203 o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
204 decrRefCount(decoded);
205 dbReplace(c->db,c->argv[1],o);
206 }
207 /* APPEND! */
208 if (c->argv[2]->encoding == REDIS_ENCODING_RAW) {
209 o->ptr = sdscatlen(o->ptr,
210 c->argv[2]->ptr, sdslen(c->argv[2]->ptr));
211 } else {
212 o->ptr = sdscatprintf(o->ptr, "%ld",
213 (unsigned long) c->argv[2]->ptr);
214 }
215 totlen = sdslen(o->ptr);
216 }
5b4bff9c 217 touchWatchedKey(c->db,c->argv[1]);
e2641e09 218 server.dirty++;
b70d3555 219 addReplyLongLong(c,totlen);
e2641e09 220}
221
222void substrCommand(redisClient *c) {
223 robj *o;
224 long start = atoi(c->argv[2]->ptr);
225 long end = atoi(c->argv[3]->ptr);
226 size_t rangelen, strlen;
227 sds range;
228
229 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
230 checkType(c,o,REDIS_STRING)) return;
231
232 o = getDecodedObject(o);
233 strlen = sdslen(o->ptr);
234
235 /* convert negative indexes */
236 if (start < 0) start = strlen+start;
237 if (end < 0) end = strlen+end;
238 if (start < 0) start = 0;
239 if (end < 0) end = 0;
240
241 /* indexes sanity checks */
242 if (start > end || (size_t)start >= strlen) {
243 /* Out of range start or start > end result in null reply */
244 addReply(c,shared.nullbulk);
245 decrRefCount(o);
246 return;
247 }
248 if ((size_t)end >= strlen) end = strlen-1;
249 rangelen = (end-start)+1;
250
251 /* Return the result */
252 addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
253 range = sdsnewlen((char*)o->ptr+start,rangelen);
254 addReplySds(c,range);
255 addReply(c,shared.crlf);
256 decrRefCount(o);
257}
258
80091bba 259void strlenCommand(redisClient *c) {
260 robj *o;
261
262 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
263 checkType(c,o,REDIS_STRING)) return;
e2641e09 264
80091bba 265 o = getDecodedObject(o);
266 addReplyLongLong(c,sdslen(o->ptr));
267 decrRefCount(o);
268}