XRANGE/XREVRANGE actual implementation. * The 'start' and 'end' IDs are parsed as follows: * Incomplete 'start' has its sequence set to 0, and 'end' to UINT64_MAX. * "-" and "+"" mean the minimal and maximal ID values, respectively. * The "(" prefix means an open (exclusive) range, so XRANGE stream (1-0 (2-0 * will match anything from 1-1 and 1-UINT64_MAX. */
| 1874 | * will match anything from 1-1 and 1-UINT64_MAX. |
| 1875 | */ |
| 1876 | void xrangeGenericCommand(client *c, int rev) { |
| 1877 | robj_roptr o; |
| 1878 | stream *s; |
| 1879 | streamID startid, endid; |
| 1880 | long long count = -1; |
| 1881 | robj *startarg = rev ? c->argv[3] : c->argv[2]; |
| 1882 | robj *endarg = rev ? c->argv[2] : c->argv[3]; |
| 1883 | int startex = 0, endex = 0; |
| 1884 | |
| 1885 | /* Parse start and end IDs. */ |
| 1886 | if (streamParseIntervalIDOrReply(c,startarg,&startid,&startex,0) != C_OK) |
| 1887 | return; |
| 1888 | if (startex && streamIncrID(&startid) != C_OK) { |
| 1889 | addReplyError(c,"invalid start ID for the interval"); |
| 1890 | return; |
| 1891 | } |
| 1892 | if (streamParseIntervalIDOrReply(c,endarg,&endid,&endex,UINT64_MAX) != C_OK) |
| 1893 | return; |
| 1894 | if (endex && streamDecrID(&endid) != C_OK) { |
| 1895 | addReplyError(c,"invalid end ID for the interval"); |
| 1896 | return; |
| 1897 | } |
| 1898 | |
| 1899 | /* Parse the COUNT option if any. */ |
| 1900 | if (c->argc > 4) { |
| 1901 | for (int j = 4; j < c->argc; j++) { |
| 1902 | int additional = c->argc-j-1; |
| 1903 | if (strcasecmp(szFromObj(c->argv[j]),"COUNT") == 0 && additional >= 1) { |
| 1904 | if (getLongLongFromObjectOrReply(c,c->argv[j+1],&count,NULL) |
| 1905 | != C_OK) return; |
| 1906 | if (count < 0) count = 0; |
| 1907 | j++; /* Consume additional arg. */ |
| 1908 | } else { |
| 1909 | addReplyErrorObject(c,shared.syntaxerr); |
| 1910 | return; |
| 1911 | } |
| 1912 | } |
| 1913 | } |
| 1914 | |
| 1915 | /* Return the specified range to the user. */ |
| 1916 | if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptyarray)) == nullptr || |
| 1917 | checkType(c,o,OBJ_STREAM)) return; |
| 1918 | |
| 1919 | s = (stream*)ptrFromObj(o); |
| 1920 | |
| 1921 | if (count == 0) { |
| 1922 | addReplyNullArray(c); |
| 1923 | } else { |
| 1924 | if (count == -1) count = 0; |
| 1925 | streamReplyWithRange(c,s,&startid,&endid,count,rev,NULL,NULL,0,NULL); |
| 1926 | } |
| 1927 | } |
| 1928 | |
| 1929 | /* XRANGE key start end [COUNT <n>] */ |
| 1930 | void xrangeCommand(client *c) { |
no test coverage detected