| 422 | } |
| 423 | |
| 424 | void setrangeCommand(client *c) { |
| 425 | robj *o; |
| 426 | long offset; |
| 427 | sds value = c->argv[3]->ptr; |
| 428 | |
| 429 | if (getLongFromObjectOrReply(c,c->argv[2],&offset,NULL) != C_OK) |
| 430 | return; |
| 431 | |
| 432 | if (offset < 0) { |
| 433 | addReplyError(c,"offset is out of range"); |
| 434 | return; |
| 435 | } |
| 436 | |
| 437 | o = lookupKeyWrite(c->db,c->argv[1]); |
| 438 | if (o == NULL) { |
| 439 | /* Return 0 when setting nothing on a non-existing string */ |
| 440 | if (sdslen(value) == 0) { |
| 441 | addReply(c,shared.czero); |
| 442 | return; |
| 443 | } |
| 444 | |
| 445 | /* Return when the resulting string exceeds allowed size */ |
| 446 | if (checkStringLength(c,offset+sdslen(value)) != C_OK) |
| 447 | return; |
| 448 | |
| 449 | o = createObject(OBJ_STRING,sdsnewlen(NULL, offset+sdslen(value))); |
| 450 | dbAdd(c->db,c->argv[1],o); |
| 451 | } else { |
| 452 | size_t olen; |
| 453 | |
| 454 | /* Key exists, check type */ |
| 455 | if (checkType(c,o,OBJ_STRING)) |
| 456 | return; |
| 457 | |
| 458 | /* Return existing string length when setting nothing */ |
| 459 | olen = stringObjectLen(o); |
| 460 | if (sdslen(value) == 0) { |
| 461 | addReplyLongLong(c,olen); |
| 462 | return; |
| 463 | } |
| 464 | |
| 465 | /* Return when the resulting string exceeds allowed size */ |
| 466 | if (checkStringLength(c,offset+sdslen(value)) != C_OK) |
| 467 | return; |
| 468 | |
| 469 | /* Create a copy when the object is shared or encoded. */ |
| 470 | o = dbUnshareStringValue(c->db,c->argv[1],o); |
| 471 | } |
| 472 | |
| 473 | if (sdslen(value) > 0) { |
| 474 | o->ptr = sdsgrowzero(o->ptr,offset+sdslen(value)); |
| 475 | memcpy((char*)o->ptr+offset,value,sdslen(value)); |
| 476 | signalModifiedKey(c,c->db,c->argv[1]); |
| 477 | notifyKeyspaceEvent(NOTIFY_STRING, |
| 478 | "setrange",c->argv[1],c->db->id); |
| 479 | server.dirty++; |
| 480 | } |
| 481 | addReplyLongLong(c,sdslen(o->ptr)); |
nothing calls this directly
no test coverage detected