]>
git.saurik.com Git - redis.git/blob - src/t_string.c
3 /*-----------------------------------------------------------------------------
5 *----------------------------------------------------------------------------*/
7 void setGenericCommand(redisClient
*c
, int nx
, robj
*key
, robj
*val
, robj
*expire
) {
9 long seconds
= 0; /* initialized to avoid an harmness warning */
12 if (getLongFromObjectOrReply(c
, expire
, &seconds
, NULL
) != REDIS_OK
)
15 addReplyError(c
,"invalid expire time in SETEX");
20 retval
= dbAdd(c
->db
,key
,val
);
21 if (retval
== REDIS_ERR
) {
23 dbReplace(c
->db
,key
,val
);
26 addReply(c
,shared
.czero
);
32 touchWatchedKey(c
->db
,key
);
34 removeExpire(c
->db
,key
);
35 if (expire
) setExpire(c
->db
,key
,time(NULL
)+seconds
);
36 addReply(c
, nx
? shared
.cone
: shared
.ok
);
39 void setCommand(redisClient
*c
) {
40 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
41 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
);
44 void setnxCommand(redisClient
*c
) {
45 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
46 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
);
49 void setexCommand(redisClient
*c
) {
50 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
51 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2]);
54 int getGenericCommand(redisClient
*c
) {
57 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
60 if (o
->type
!= REDIS_STRING
) {
61 addReply(c
,shared
.wrongtypeerr
);
69 void getCommand(redisClient
*c
) {
73 void getsetCommand(redisClient
*c
) {
74 if (getGenericCommand(c
) == REDIS_ERR
) return;
75 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
76 dbReplace(c
->db
,c
->argv
[1],c
->argv
[2]);
77 incrRefCount(c
->argv
[2]);
78 touchWatchedKey(c
->db
,c
->argv
[1]);
80 removeExpire(c
->db
,c
->argv
[1]);
83 void mgetCommand(redisClient
*c
) {
86 addReplyMultiBulkLen(c
,c
->argc
-1);
87 for (j
= 1; j
< c
->argc
; j
++) {
88 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
90 addReply(c
,shared
.nullbulk
);
92 if (o
->type
!= REDIS_STRING
) {
93 addReply(c
,shared
.nullbulk
);
101 void msetGenericCommand(redisClient
*c
, int nx
) {
104 if ((c
->argc
% 2) == 0) {
105 addReplyError(c
,"wrong number of arguments for MSET");
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. */
111 for (j
= 1; j
< c
->argc
; j
+= 2) {
112 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
118 addReply(c
, shared
.czero
);
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
]);
127 touchWatchedKey(c
->db
,c
->argv
[j
]);
129 server
.dirty
+= (c
->argc
-1)/2;
130 addReply(c
, nx
? shared
.cone
: shared
.ok
);
133 void msetCommand(redisClient
*c
) {
134 msetGenericCommand(c
,0);
137 void msetnxCommand(redisClient
*c
) {
138 msetGenericCommand(c
,1);
141 void incrDecrCommand(redisClient
*c
, long long incr
) {
145 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
146 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
148 /* Fast path if the object is integer encoded and is not shared. */
149 if (o
&& o
->refcount
== 1 && o
->encoding
== REDIS_ENCODING_INT
) {
150 long long newval
= ((long)o
->ptr
) + incr
;
152 if (newval
< 0 && newval
>= REDIS_SHARED_INTEGERS
&&
153 newval
>= LONG_MIN
&& newval
<= LONG_MAX
) {
154 o
->ptr
= (void*) (long) newval
;
155 touchWatchedKey(c
->db
,c
->argv
[1]);
157 addReplyLongLong(c
,newval
);
160 /* ... else take the usual safe path */
163 /* Otherwise we create a new object and replace the old one. */
164 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
166 o
= createStringObjectFromLongLong(value
);
167 dbReplace(c
->db
,c
->argv
[1],o
);
168 touchWatchedKey(c
->db
,c
->argv
[1]);
170 addReply(c
,shared
.colon
);
172 addReply(c
,shared
.crlf
);
175 void incrCommand(redisClient
*c
) {
176 incrDecrCommand(c
,1);
179 void decrCommand(redisClient
*c
) {
180 incrDecrCommand(c
,-1);
183 void incrbyCommand(redisClient
*c
) {
186 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
187 incrDecrCommand(c
,incr
);
190 void decrbyCommand(redisClient
*c
) {
193 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
194 incrDecrCommand(c
,-incr
);
197 void appendCommand(redisClient
*c
) {
202 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
203 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
206 retval
= dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
207 incrRefCount(c
->argv
[2]);
208 totlen
= stringObjectLen(c
->argv
[2]);
210 if (o
->type
!= REDIS_STRING
) {
211 addReply(c
,shared
.wrongtypeerr
);
214 /* If the object is specially encoded or shared we have to make
216 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
217 robj
*decoded
= getDecodedObject(o
);
219 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
220 decrRefCount(decoded
);
221 dbReplace(c
->db
,c
->argv
[1],o
);
224 if (c
->argv
[2]->encoding
== REDIS_ENCODING_RAW
) {
225 o
->ptr
= sdscatlen(o
->ptr
,
226 c
->argv
[2]->ptr
, sdslen(c
->argv
[2]->ptr
));
228 o
->ptr
= sdscatprintf(o
->ptr
, "%ld",
229 (unsigned long) c
->argv
[2]->ptr
);
231 totlen
= sdslen(o
->ptr
);
233 touchWatchedKey(c
->db
,c
->argv
[1]);
235 addReplyLongLong(c
,totlen
);
238 void substrCommand(redisClient
*c
) {
240 long start
= atoi(c
->argv
[2]->ptr
);
241 long end
= atoi(c
->argv
[3]->ptr
);
242 size_t rangelen
, strlen
;
245 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
246 checkType(c
,o
,REDIS_STRING
)) return;
248 o
= getDecodedObject(o
);
249 strlen
= sdslen(o
->ptr
);
251 /* convert negative indexes */
252 if (start
< 0) start
= strlen
+start
;
253 if (end
< 0) end
= strlen
+end
;
254 if (start
< 0) start
= 0;
255 if (end
< 0) end
= 0;
257 /* indexes sanity checks */
258 if (start
> end
|| (size_t)start
>= strlen
) {
259 /* Out of range start or start > end result in null reply */
260 addReply(c
,shared
.nullbulk
);
264 if ((size_t)end
>= strlen
) end
= strlen
-1;
265 rangelen
= (end
-start
)+1;
267 /* Return the result */
268 addReplySds(c
,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen
));
269 range
= sdsnewlen((char*)o
->ptr
+start
,rangelen
);
270 addReplySds(c
,range
);
271 addReply(c
,shared
.crlf
);
275 void strlenCommand(redisClient
*c
) {
278 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
279 checkType(c
,o
,REDIS_STRING
)) return;
281 o
= getDecodedObject(o
);
282 addReplyLongLong(c
,sdslen(o
->ptr
));