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