This generic command implements both ZADD and ZINCRBY. */
| 1717 | |
| 1718 | /* This generic command implements both ZADD and ZINCRBY. */ |
| 1719 | void zaddGenericCommand(client *c, int flags) { |
| 1720 | static const char *nanerr = "resulting score is not a number (NaN)"; |
| 1721 | robj *key = c->argv[1]; |
| 1722 | robj *zobj; |
| 1723 | sds ele; |
| 1724 | double score = 0, *scores = NULL; |
| 1725 | int j, elements, ch = 0; |
| 1726 | int scoreidx = 0; |
| 1727 | /* The following vars are used in order to track what the command actually |
| 1728 | * did during the execution, to reply to the client and to trigger the |
| 1729 | * notification of keyspace change. */ |
| 1730 | int added = 0; /* Number of new elements added. */ |
| 1731 | int updated = 0; /* Number of elements with updated score. */ |
| 1732 | int processed = 0; /* Number of elements processed, may remain zero with |
| 1733 | options like XX. */ |
| 1734 | |
| 1735 | /* Parse options. At the end 'scoreidx' is set to the argument position |
| 1736 | * of the score of the first score-element pair. */ |
| 1737 | scoreidx = 2; |
| 1738 | while(scoreidx < c->argc) { |
| 1739 | char *opt = szFromObj(c->argv[scoreidx]); |
| 1740 | if (!strcasecmp(opt,"nx")) flags |= ZADD_IN_NX; |
| 1741 | else if (!strcasecmp(opt,"xx")) flags |= ZADD_IN_XX; |
| 1742 | else if (!strcasecmp(opt,"ch")) ch = 1; /* Return num of elements added or updated. */ |
| 1743 | else if (!strcasecmp(opt,"incr")) flags |= ZADD_IN_INCR; |
| 1744 | else if (!strcasecmp(opt,"gt")) flags |= ZADD_IN_GT; |
| 1745 | else if (!strcasecmp(opt,"lt")) flags |= ZADD_IN_LT; |
| 1746 | else break; |
| 1747 | scoreidx++; |
| 1748 | } |
| 1749 | |
| 1750 | /* Turn options into simple to check vars. */ |
| 1751 | int incr = (flags & ZADD_IN_INCR) != 0; |
| 1752 | int nx = (flags & ZADD_IN_NX) != 0; |
| 1753 | int xx = (flags & ZADD_IN_XX) != 0; |
| 1754 | int gt = (flags & ZADD_IN_GT) != 0; |
| 1755 | int lt = (flags & ZADD_IN_LT) != 0; |
| 1756 | |
| 1757 | /* After the options, we expect to have an even number of args, since |
| 1758 | * we expect any number of score-element pairs. */ |
| 1759 | elements = c->argc-scoreidx; |
| 1760 | if (elements % 2 || !elements) { |
| 1761 | addReplyErrorObject(c,shared.syntaxerr); |
| 1762 | return; |
| 1763 | } |
| 1764 | elements /= 2; /* Now this holds the number of score-element pairs. */ |
| 1765 | |
| 1766 | /* Check for incompatible options. */ |
| 1767 | if (nx && xx) { |
| 1768 | addReplyError(c, |
| 1769 | "XX and NX options at the same time are not compatible"); |
| 1770 | return; |
| 1771 | } |
| 1772 | |
| 1773 | if ((gt && nx) || (lt && nx) || (gt && lt)) { |
| 1774 | addReplyError(c, |
| 1775 | "GT, LT, and/or NX options at the same time are not compatible"); |
| 1776 | return; |
no test coverage detected