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