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