Skip to content

Commit 5903466

Browse files
DOC-4996 commands and replies
1 parent 3509109 commit 5903466

File tree

2 files changed

+255
-3
lines changed

2 files changed

+255
-3
lines changed

content/develop/clients/hiredis/_index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ int main() {
6666

6767
// Check and free the reply.
6868
if (reply != NULL) {
69-
printf("Reply: %s\n", reply->str);
69+
printf("Reply: %s\n", reply->str); // >>> Reply: OK
7070
freeReplyObject(reply);
7171
}
7272

@@ -75,7 +75,7 @@ int main() {
7575

7676
// Check and free the reply.
7777
if (reply != NULL) {
78-
printf("Reply: %s\n", reply->str);
78+
printf("Reply: %s\n", reply->str); // >>> Reply: bar
7979
freeReplyObject(reply);
8080
}
8181

content/develop/clients/hiredis/issue-commands.md

Lines changed: 253 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,43 @@ reply formats defined in the
115115
[RESP2 and RESP3]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}})
116116
protocols, so its content varies greatly between calls.
117117

118+
A simple example is the status response returned by the `SET`
119+
command. The code below shows how to get this from the `redisReply`
120+
object:
121+
122+
```c
123+
redisReply *reply = redisCommand(c, "SET greeting Hello");
124+
125+
// Check and free the reply.
126+
if (reply != NULL) {
127+
printf("Reply: %s\n", reply->str);
128+
freeReplyObject(reply);
129+
reply = NULL;
130+
}
131+
```
132+
133+
A null reply indicates an error, so you should always check for this.
134+
If an error does occur, then the `redisContext` object will have a
135+
non-zero error number in its integer `err` field and sometimes a textual
136+
description of the error in its `errstr` field.
137+
138+
For `SET`, a successful call will simply return an "OK" string that you
139+
can access with the `reply->str` field. The code in the example prints
140+
this to the console, but you should check for the specific value to ensure
141+
the command executed correctly.
142+
143+
The `redisCommand()` call allocates memory for the reply, so you should
144+
always free it using `freeReplyObject()` when you have finished using
145+
the reply. If you want to reuse the reply variable then it is wise to
146+
set it to `NULL` after you free it, so that you don't accidentally use
147+
the stale pointer later.
148+
149+
### Reply formats
150+
151+
The Redis
152+
[`RESP`]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}})
153+
protocols support several different types of reply format for commands.
154+
118155
You can find the reply format for a command at the end of its
119156
reference page in the RESP2/RESP3 Reply section (for example, the
120157
[`INCRBY`]({{< relref "/commands/incrby" >}}) page shows that the
@@ -132,7 +169,7 @@ use to access the reply value:
132169
| Constant | Type | Relevant fields of `redisReply` | RESP protocol |
133170
| :- | :- |:- | :- |
134171
| `REDIS_REPLY_STATUS` | [Simple string]({{< relref "/develop/reference/protocol-spec#simple-strings" >}}) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
135-
| `REDIS_REPLY_ERROR` | [Simple string]({{< relref "/develop/reference/protocol-spec#simple-strings" >}}) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
172+
| `REDIS_REPLY_ERROR` | [Simple error]({{< relref "/develop/reference/protocol-spec#simple-errors" >}}) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
136173
| `REDIS_REPLY_INTEGER` | [Integer]({{< relref "/develop/reference/protocol-spec#integers" >}}) | `reply->integer`: the integer value (`long long`)| 2, 3 |
137174
| `REDIS_REPLY_NIL` | [Null]({{< relref "/develop/reference/protocol-spec#nulls" >}}) | No data | 2, 3 |
138175
| `REDIS_REPLY_STRING` | [Bulk string]({{< relref "/develop/reference/protocol-spec#bulk-strings" >}}) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
@@ -144,3 +181,218 @@ use to access the reply value:
144181
| `REDIS_REPLY_PUSH` | [Push]({{< relref "/develop/reference/protocol-spec#pushes" >}}) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |
145182
| `REDIS_REPLY_BIGNUM` | [Big number]({{< relref "/develop/reference/protocol-spec#big-numbers" >}}) | `reply->str`: number value as string (`char*`)<br/> `reply->len`: the string length (`size_t`) | 3 |
146183
| `REDIS_REPLY_VERB` | [Verbatim string]({{< relref "/develop/reference/protocol-spec#verbatim-strings" >}}) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`)<br/> `reply->vtype`: content type (`char[3]`) | 3 |
184+
185+
### Reply format processing examples
186+
187+
#### Integers
188+
189+
The `REDIS_REPLY_INTEGER` and `REDIS_REPLY_BOOL` reply types both
190+
contain values in `reply->integer`. However, `REDIS_REPLY_BOOL` is
191+
rarely used. Even when the command essentially returns a boolean value,
192+
the reply is usually reported as an integer.
193+
194+
```c
195+
// Add some values to a set.
196+
redisReply *reply = redisCommand(c, "SADD items bread milk peas");
197+
198+
if (reply != NULL) {
199+
// This gives an integer reply.
200+
if (reply->type == REDIS_REPLY_INTEGER) {
201+
// Report status.
202+
printf("Integer reply\n");
203+
printf("Number added: %lld\n", reply->integer);
204+
// >>> Number added: 3
205+
}
206+
207+
freeReplyObject(reply);
208+
reply = NULL;
209+
}
210+
211+
reply = redisCommand(c, "SISMEMBER items bread");
212+
213+
if (reply != NULL) {
214+
// This also gives an integer reply but you should interpret
215+
// it as a boolean value.
216+
if (reply->type == REDIS_REPLY_INTEGER) {
217+
// Respond to boolean integer value.
218+
printf("Integer reply\n");
219+
220+
if (reply->integer == 0) {
221+
printf("Items set has no member 'bread'\n");
222+
} else {
223+
printf("'Bread' is a member of items set\n");
224+
}
225+
// >>> 'Bread' is a member of items set
226+
}
227+
228+
freeReplyObject(reply);
229+
reply = NULL;
230+
}
231+
```
232+
233+
#### Strings
234+
235+
The `REDIS_REPLY_STATUS`, `REDIS_REPLY_ERROR`, `REDIS_REPLY_STRING`,
236+
`REDIS_REPLY_DOUBLE`, `REDIS_REPLY_BIGNUM`, and `REDIS_REPLY_VERB`
237+
are all returned as strings, with the main difference lying in how
238+
you interpret them. For all these types, the string value is
239+
returned in `reply->str` and the length of the string is in
240+
`reply->len`. The example below shows some of the possibilities.
241+
242+
```c
243+
// Set a numeric value in a string.
244+
reply = redisCommand(c, "SET number 1.5");
245+
246+
if (reply != NULL) {
247+
// This gives a status reply.
248+
if (reply->type == REDIS_REPLY_STATUS) {
249+
// Report status.
250+
printf("Status reply\n");
251+
printf("Reply: %s\n", reply->str); // >>> Reply: OK
252+
}
253+
254+
freeReplyObject(reply);
255+
reply = NULL;
256+
}
257+
258+
// Attempt to interpret the key as a hash.
259+
reply = redisCommand(c, "HGET number field1");
260+
261+
if (reply != NULL) {
262+
// This gives an error reply.
263+
if (reply->type == REDIS_REPLY_ERROR) {
264+
// Report the error.
265+
printf("Error reply\n");
266+
printf("Reply: %s\n", reply->str);
267+
// >>> Reply: WRONGTYPE Operation against a key holding the wrong kind of value
268+
}
269+
270+
freeReplyObject(reply);
271+
reply = NULL;
272+
}
273+
274+
reply = redisCommand(c, "GET number");
275+
276+
if (reply != NULL) {
277+
// This gives a simple string reply.
278+
if (reply->type == REDIS_REPLY_STRING) {
279+
// Display the string.
280+
printf("Simple string reply\n");
281+
printf("Reply: %s\n", reply->str); // >>> Reply: 1.5
282+
}
283+
284+
freeReplyObject(reply);
285+
reply = NULL;
286+
}
287+
288+
reply = redisCommand(c, "ZADD prices 1.75 bread 5.99 beer");
289+
290+
if (reply != NULL) {
291+
// This gives an integer reply.
292+
if (reply->type == REDIS_REPLY_INTEGER) {
293+
// Display the integer.
294+
printf("Integer reply\n");
295+
printf("Number added: %lld\n", reply->integer);
296+
// >>> Number added: 2
297+
}
298+
299+
freeReplyObject(reply);
300+
reply = NULL;
301+
}
302+
303+
reply = redisCommand(c, "ZSCORE prices bread");
304+
305+
if (reply != NULL) {
306+
// This gives a string reply with RESP2 and a double reply
307+
// with RESP3, but you handle it the same way in either case.
308+
if (reply->type == REDIS_REPLY_STRING) {
309+
printf("String reply\n");
310+
311+
char *endptr; // Not used.
312+
double price = strtod(reply->str, &endptr);
313+
double discounted = price * 0.75;
314+
printf("Discounted price: %.2f\n", discounted);
315+
// >>> Discounted price: 1.31
316+
}
317+
318+
freeReplyObject(reply);
319+
reply = NULL;
320+
}
321+
```
322+
323+
### Arrays and maps
324+
325+
Arrays (reply type `REDIS_REPLY_ARRAY`) and maps (reply type `REDIS_REPLY_MAP`)
326+
are returned by commands that retrieve several values at the
327+
same time. For both types, the number of elements in the reply is contained in
328+
`reply->elements` and the pointer to the array itself is is `reply->element`.
329+
Each item in the array is of type `redisReply`. The array elements
330+
are typically simple types rather than arrays or maps.
331+
332+
The example below shows how to get the items from a
333+
[list]({{< relref "/develop/data-types/lists" >}}):
334+
335+
```c
336+
reply = redisCommand(c, "RPUSH things thing0 thing1 thing2 thing3");
337+
338+
if (reply != NULL) {
339+
printf("Added %lld items\n", reply->integer);
340+
// >>> Added 4 items
341+
freeReplyObject(reply);
342+
reply = NULL;
343+
}
344+
345+
reply = redisCommand(c, "LRANGE things 0 -1");
346+
347+
if (reply != NULL) {
348+
for (int i = 0; i < reply->elements; ++i) {
349+
if (reply->element[i]->type == REDIS_REPLY_STRING) {
350+
printf("List item %d: %s\n", i, reply->element[i]->str);
351+
}
352+
}
353+
// >>> List item 0: thing0
354+
// >>> List item 1: thing1
355+
// >>> List item 2: thing2
356+
// >>> List item 3: thing3
357+
}
358+
```
359+
360+
A map is essentially the same as an array but it has the extra
361+
guarantee that the items will be listed in key-value pairs.
362+
The example below shows how to get all the fields from a
363+
[hash]({{< relref "/develop/data-types/hashes" >}}) using
364+
[`HGETALL`]({{< relref "/commands/hgetall" >}}):
365+
366+
```c
367+
const char *hashCommand[] = {
368+
"HSET", "details",
369+
"name", "Mr Benn",
370+
"address", "52 Festive Road",
371+
"hobbies", "Cosplay"
372+
};
373+
374+
reply = redisCommandArgv(c, 8, hashCommand, NULL);
375+
376+
if (reply != NULL) {
377+
printf("Added %lld fields\n", reply->integer);
378+
// >>> Added 3 fields
379+
380+
freeReplyObject(reply);
381+
reply = NULL;
382+
}
383+
384+
reply = redisCommand(c, "HGETALL details");
385+
386+
// This gives an array reply with RESP2 and a map reply with
387+
// RESP3, but you handle it the same way in either case.
388+
if (reply->type == REDIS_REPLY_ARRAY) {
389+
for (int i = 0; i < reply->elements; i += 2) {
390+
char *key = reply->element[i]->str;
391+
char *value = reply->element[i + 1]->str;
392+
printf("Key: %s, value: %s\n", key, value);
393+
}
394+
// >>> Key: name, value: Mr Benn
395+
// >>> Key: address, value: 52 Festive Road
396+
// >>> Key: hobbies, value: Cosplay
397+
}
398+
```

0 commit comments

Comments
 (0)