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