Refactor setpub-commands, Allow multiple channels
[ric-plt/dbaas.git] / redismodule / src / exstrings.c
1 /*
2  * Copyright (c) 2018-2019 Nokia.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16
17 #include "redismodule.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <stdbool.h>
23 #include "../../redismodule/include/redismodule.h"
24
25 #ifdef __UT__
26 #include "exstringsStub.h"
27 #endif
28
29 /* make sure the response is not NULL or an error.
30 sends the error to the client and exit the current function if its */
31 #define  ASSERT_NOERROR(r) \
32     if (r == NULL) { \
33         return RedisModule_ReplyWithError(ctx,"ERR reply is NULL"); \
34     } else if (RedisModule_CallReplyType(r) == REDISMODULE_REPLY_ERROR) { \
35         RedisModule_ReplyWithCallReply(ctx,r); \
36         RedisModule_FreeCallReply(r); \
37         return REDISMODULE_ERR; \
38     }
39
40 #define OBJ_OP_NO 0
41 #define OBJ_OP_XX (1<<1)     /* OP if key exist */
42 #define OBJ_OP_NX (1<<2)     /* OP if key not exist */
43 #define OBJ_OP_IE (1<<4)     /* OP if equal old value */
44 #define OBJ_OP_NE (1<<5)     /* OP if not equal old value */
45
46 int getKeyType(RedisModuleCtx *ctx, RedisModuleString *key_str)
47 {
48     RedisModuleKey *key = RedisModule_OpenKey(ctx, key_str, REDISMODULE_READ);
49     int type = RedisModule_KeyType(key);
50     RedisModule_CloseKey(key);
51     return type;
52 }
53
54 bool replyContentsEqualString(RedisModuleCallReply *reply, RedisModuleString *expected_value)
55 {
56     size_t replylen = 0, expectedlen = 0;
57     const char *expectedval = RedisModule_StringPtrLen(expected_value, &expectedlen);
58     const char *replyval = RedisModule_CallReplyStringPtr(reply, &replylen);
59     return replyval &&
60            expectedlen == replylen &&
61            !strncmp(expectedval, replyval, replylen);
62 }
63
64 typedef struct _SetParams {
65     RedisModuleString **key_val_pairs;
66     size_t length;
67 } SetParams;
68
69 typedef struct _PubParams {
70     RedisModuleString **channel_msg_pairs;
71     size_t length;
72 } PubParams;
73
74 void multiPubCommand(RedisModuleCtx *ctx, PubParams* pubParams)
75 {
76     RedisModuleCallReply *reply = NULL;
77     for (unsigned int i = 0 ; i < pubParams->length ; i += 2) {
78         reply = RedisModule_Call(ctx, "PUBLISH", "v", pubParams->channel_msg_pairs + i, 2);
79         RedisModule_FreeCallReply(reply);
80     }
81 }
82
83 int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
84                                        int argc, const int flag)
85 {
86     RedisModuleString *oldvalstr = NULL;
87     RedisModuleCallReply *reply = NULL;
88
89     if (argc < 4)
90         return RedisModule_WrongArity(ctx);
91     else
92         oldvalstr = argv[3];
93
94     /*Check if key type is string*/
95     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
96         REDISMODULE_READ);
97     int type = RedisModule_KeyType(key);
98     RedisModule_CloseKey(key);
99
100     if (type == REDISMODULE_KEYTYPE_EMPTY) {
101         if (flag == OBJ_OP_IE){
102             RedisModule_ReplyWithNull(ctx);
103             return REDISMODULE_OK;
104         }
105     } else if (type != REDISMODULE_KEYTYPE_STRING) {
106         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
107     }
108
109     /*Get the value*/
110     reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
111     ASSERT_NOERROR(reply)
112     size_t curlen=0, oldvallen=0;
113     const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
114     const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
115     if (((flag == OBJ_OP_IE) &&
116         (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
117         ||
118         ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
119           !strncmp(oldval, curval, curlen))) {
120         RedisModule_FreeCallReply(reply);
121         return RedisModule_ReplyWithNull(ctx);
122     }
123     RedisModule_FreeCallReply(reply);
124
125     /* Prepare the arguments for the command. */
126     int i, j=0, cmdargc=argc-2;
127     RedisModuleString *cmdargv[cmdargc];
128     for (i = 1; i < argc; i++) {
129         if (i == 3)
130             continue;
131         cmdargv[j++] = argv[i];
132     }
133
134     /* Call the command and pass back the reply. */
135     reply = RedisModule_Call(ctx, "SET", "v!", cmdargv, cmdargc);
136     ASSERT_NOERROR(reply)
137     RedisModule_ReplyWithCallReply(ctx, reply);
138
139     RedisModule_FreeCallReply(reply);
140     return REDISMODULE_OK;
141 }
142
143 int SetIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
144 {
145     return setStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
146 }
147
148 int SetNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
149 {
150     return setStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
151 }
152
153 int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
154                                        int argc, const int flag)
155 {
156     RedisModuleString *oldvalstr = NULL;
157     RedisModuleCallReply *reply = NULL;
158
159     if (argc == 3)
160         oldvalstr = argv[2];
161     else
162         return RedisModule_WrongArity(ctx);
163
164     /*Check if key type is string*/
165     RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
166         REDISMODULE_READ);
167     int type = RedisModule_KeyType(key);
168     RedisModule_CloseKey(key);
169
170     if (type == REDISMODULE_KEYTYPE_EMPTY) {
171         return RedisModule_ReplyWithLongLong(ctx, 0);
172     } else if (type != REDISMODULE_KEYTYPE_STRING) {
173         return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
174     }
175
176     /*Get the value*/
177     reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
178     ASSERT_NOERROR(reply)
179     size_t curlen = 0, oldvallen = 0;
180     const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
181     const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
182     if (((flag == OBJ_OP_IE) &&
183         (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
184         ||
185         ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
186           !strncmp(oldval, curval, curlen))) {
187         RedisModule_FreeCallReply(reply);
188         return RedisModule_ReplyWithLongLong(ctx, 0);
189     }
190     RedisModule_FreeCallReply(reply);
191
192     /* Prepare the arguments for the command. */
193     int cmdargc=1;
194     RedisModuleString *cmdargv[1];
195     cmdargv[0] = argv[1];
196
197     /* Call the command and pass back the reply. */
198     reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, cmdargc);
199     ASSERT_NOERROR(reply)
200     RedisModule_ReplyWithCallReply(ctx, reply);
201
202     RedisModule_FreeCallReply(reply);
203     return REDISMODULE_OK;
204 }
205
206 int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
207 {
208     return delStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
209 }
210
211 int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
212 {
213     return delStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
214 }
215
216 int NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
217 {
218     RedisModuleCallReply *reply = NULL;
219
220     if (argc != 2)
221         return RedisModule_WrongArity(ctx);
222
223     /* Call the command to get keys with pattern. */
224     reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
225     ASSERT_NOERROR(reply)
226
227     /* Prepare the arguments for the command. */
228     size_t items = RedisModule_CallReplyLength(reply);
229     if (items == 0) {
230         //RedisModule_ReplyWithArray(ctx, items);
231         RedisModule_ReplyWithCallReply(ctx, reply);
232         RedisModule_FreeCallReply(reply);
233     }
234     else {
235         RedisModuleString *cmdargv[items];
236         size_t i=0, j;
237         for (j = 0; j < items; j++) {
238            RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
239            cmdargv[i++] = rms;
240
241            /*Assume all keys via SDL is string type for sake of saving time*/
242 #if 0
243            /*Check if key type is string*/
244            RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
245
246            if (key) {
247                int type = RedisModule_KeyType(key);
248                RedisModule_CloseKey(key);
249                if (type == REDISMODULE_KEYTYPE_STRING) {
250                    cmdargv[i++] = rms;
251                }
252            } else {
253                RedisModule_CloseKey(key);
254            }
255 #endif
256         }
257         RedisModule_FreeCallReply(reply);
258
259         reply = RedisModule_Call(ctx, "MGET", "v", cmdargv, i);
260         ASSERT_NOERROR(reply)
261         items = RedisModule_CallReplyLength(reply);
262         RedisModule_ReplyWithArray(ctx, i*2);
263         for (j = 0; (j<items && j<i); j++) {
264            RedisModule_ReplyWithString(ctx, cmdargv[j]);
265            RedisModule_ReplyWithString(ctx, RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j)));
266         }
267
268         RedisModule_FreeCallReply(reply);
269     }
270
271     return REDISMODULE_OK;
272 }
273
274 int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
275 {
276     RedisModuleCallReply *reply = NULL;
277
278     if (argc != 2)
279         return RedisModule_WrongArity(ctx);
280
281     /* Call the command to get keys with pattern. */
282     reply = RedisModule_Call(ctx, "KEYS", "s", argv[1]);
283     ASSERT_NOERROR(reply)
284
285     /* Prepare the arguments for the command. */
286     size_t items = RedisModule_CallReplyLength(reply);
287     if (items == 0) {
288         RedisModule_ReplyWithLongLong(ctx, 0);
289         RedisModule_FreeCallReply(reply);
290     }
291     else {
292         RedisModuleString *cmdargv[items];
293         size_t i=0, j;
294         for (j = 0; j < items; j++) {
295            RedisModuleString *rms = RedisModule_CreateStringFromCallReply(RedisModule_CallReplyArrayElement(reply, j));
296            cmdargv[i++] = rms;
297
298            /*Assume all keys via SDL is string type for sake of saving time*/
299 #if 0
300            //Check if key type is string
301            RedisModuleKey *key = RedisModule_OpenKey(ctx, rms ,REDISMODULE_READ);
302
303            if (key) {
304                int type = RedisModule_KeyType(key);
305                RedisModule_CloseKey(key);
306                if (type == REDISMODULE_KEYTYPE_STRING) {
307                    cmdargv[i++] = rms;
308                }
309            } else {
310                RedisModule_CloseKey(key);
311            }
312 #endif
313         }
314         RedisModule_FreeCallReply(reply);
315
316         reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, i);
317         ASSERT_NOERROR(reply)
318         RedisModule_ReplyWithCallReply(ctx, reply);
319         RedisModule_FreeCallReply(reply);
320
321     }
322
323     return REDISMODULE_OK;
324 }
325
326 int setPubStringCommon(RedisModuleCtx *ctx, SetParams* setParamsPtr, PubParams* pubParamsPtr)
327 {
328     RedisModuleCallReply *setReply;
329     setReply = RedisModule_Call(ctx, "MSET", "v!", setParamsPtr->key_val_pairs, setParamsPtr->length);
330     ASSERT_NOERROR(setReply)
331     int replytype = RedisModule_CallReplyType(setReply);
332     if (replytype == REDISMODULE_REPLY_NULL) {
333         RedisModule_ReplyWithNull(ctx);
334     } else {
335         multiPubCommand(ctx, pubParamsPtr);
336         RedisModule_ReplyWithCallReply(ctx, setReply);
337     }
338     RedisModule_FreeCallReply(setReply);
339     return REDISMODULE_OK;
340 }
341
342 int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
343 {
344     if (argc < 5 || (argc % 2) == 0)
345         return RedisModule_WrongArity(ctx);
346
347     SetParams setParams = {
348                            .key_val_pairs = argv + 1,
349                            .length = argc - 3
350                           };
351     PubParams pubParams = {
352                            .channel_msg_pairs = argv + argc - 2,
353                            .length = 2
354                           };
355
356     return setPubStringCommon(ctx, &setParams, &pubParams);
357 }
358
359 int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
360 {
361     if (argc < 6 || (argc % 2) != 0)
362         return RedisModule_WrongArity(ctx);
363
364     SetParams setParams = {
365                            .key_val_pairs = argv + 1,
366                            .length = 2
367                           };
368     PubParams pubParams = {
369                            .channel_msg_pairs = argv + 4,
370                            .length = argc - 4
371                           };
372     RedisModuleString *key = setParams.key_val_pairs[0];
373     RedisModuleString *oldvalstr = argv[3];
374
375     int type = getKeyType(ctx, key);
376     if (flag == OBJ_OP_IE && type == REDISMODULE_KEYTYPE_EMPTY) {
377         return RedisModule_ReplyWithNull(ctx);
378     } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
379         return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
380     }
381
382     RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
383     ASSERT_NOERROR(reply)
384     bool is_equal = replyContentsEqualString(reply, oldvalstr);
385     RedisModule_FreeCallReply(reply);
386     if ((flag == OBJ_OP_IE && !is_equal) ||
387         (flag == OBJ_OP_NE && is_equal)) {
388         return RedisModule_ReplyWithNull(ctx);
389     }
390
391     return setPubStringCommon(ctx, &setParams, &pubParams);
392 }
393
394 int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
395 {
396     return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
397 }
398
399 int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
400 {
401     return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
402 }
403
404 int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
405 {
406     if (argc < 5 || (argc % 2) == 0)
407         return RedisModule_WrongArity(ctx);
408
409     SetParams setParams = {
410                            .key_val_pairs = argv + 1,
411                            .length = 2
412                           };
413     PubParams pubParams = {
414                            .channel_msg_pairs = argv + 3,
415                            .length = argc - 3
416                           };
417     RedisModuleString *key = setParams.key_val_pairs[0];
418
419     int type = getKeyType(ctx, key);
420     if ((flag == OBJ_OP_XX && type == REDISMODULE_KEYTYPE_EMPTY) ||
421         (flag == OBJ_OP_NX && type == REDISMODULE_KEYTYPE_STRING)) {
422         return RedisModule_ReplyWithNull(ctx);
423     } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
424         RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
425         return REDISMODULE_OK;
426     }
427
428     return setPubStringCommon(ctx, &setParams, &pubParams);
429 }
430
431 int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
432 {
433     return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
434 }
435
436 int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
437 {
438     return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_XX);
439 }
440
441 int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
442                                        int argc, const int flag)
443 {
444     RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
445     RedisModuleCallReply *reply = NULL;
446
447     if (flag == OBJ_OP_NO) {
448         if (argc < 4)
449             return RedisModule_WrongArity(ctx);
450         else {
451             channel = argv[argc-2];
452             message = argv[argc-1];
453         }
454     } else {
455         if (argc != 5)
456             return RedisModule_WrongArity(ctx);
457         else {
458             oldvalstr = argv[2];
459             channel = argv[3];
460             message = argv[4];
461         }
462     }
463
464     if (flag != OBJ_OP_NO) {
465         /*Check if key type is string*/
466         RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
467             REDISMODULE_READ);
468         int type = RedisModule_KeyType(key);
469         RedisModule_CloseKey(key);
470
471         if (type == REDISMODULE_KEYTYPE_EMPTY) {
472             return RedisModule_ReplyWithLongLong(ctx, 0);
473         } else if (type != REDISMODULE_KEYTYPE_STRING) {
474             return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
475         }
476     }
477
478     if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
479         /*Get the value*/
480         reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
481         ASSERT_NOERROR(reply)
482         size_t curlen = 0, oldvallen = 0;
483         const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
484         const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
485         if (((flag == OBJ_OP_IE) &&
486             (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
487             ||
488             ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
489               !strncmp(oldval, curval, curlen))) {
490             RedisModule_FreeCallReply(reply);
491             return RedisModule_ReplyWithLongLong(ctx, 0);
492         }
493         RedisModule_FreeCallReply(reply);
494     }
495
496
497     /* Prepare the arguments for the command. */
498     int i, j=0, cmdargc=argc-3;
499     RedisModuleString *cmdargv[cmdargc];
500     for (i = 1; i < argc-2; i++) {
501         if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 2))
502             continue;
503         cmdargv[j++] = argv[i];
504     }
505
506     /* Call the command and pass back the reply. */
507     reply = RedisModule_Call(ctx, "UNLINK", "v!", cmdargv, j);
508     ASSERT_NOERROR(reply)
509     int replytype = RedisModule_CallReplyType(reply);
510     if (replytype == REDISMODULE_REPLY_NULL) {
511         RedisModule_ReplyWithNull(ctx);
512     }
513     else if (RedisModule_CallReplyInteger(reply) == 0) {
514         RedisModule_ReplyWithCallReply(ctx, reply);
515     } else {
516         cmdargc = 2;
517         cmdargv[0] = channel;
518         cmdargv[1] = message;
519         RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
520         RedisModule_FreeCallReply(pubreply);
521         RedisModule_ReplyWithCallReply(ctx, reply);
522     }
523
524     RedisModule_FreeCallReply(reply);
525     return REDISMODULE_OK;
526 }
527
528 int DelPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
529 {
530    return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
531 }
532
533 int DelIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
534 {
535    return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
536 }
537
538 int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
539 {
540    return delPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
541 }
542
543 /* This function must be present on each Redis module. It is used in order to
544  * register the commands into the Redis server. */
545 int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
546     REDISMODULE_NOT_USED(argv);
547     REDISMODULE_NOT_USED(argc);
548
549     if (RedisModule_Init(ctx,"exstrings",1,REDISMODULE_APIVER_1)
550         == REDISMODULE_ERR) return REDISMODULE_ERR;
551
552     if (RedisModule_CreateCommand(ctx,"setie",
553         SetIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
554         return REDISMODULE_ERR;
555
556     if (RedisModule_CreateCommand(ctx,"setne",
557         SetNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
558         return REDISMODULE_ERR;
559
560     if (RedisModule_CreateCommand(ctx,"delie",
561         DelIE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
562         return REDISMODULE_ERR;
563
564     if (RedisModule_CreateCommand(ctx,"delne",
565         DelNE_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
566         return REDISMODULE_ERR;
567
568     if (RedisModule_CreateCommand(ctx,"nget",
569         NGet_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
570         return REDISMODULE_ERR;
571
572     if (RedisModule_CreateCommand(ctx,"ndel",
573         NDel_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
574         return REDISMODULE_ERR;
575
576     if (RedisModule_CreateCommand(ctx,"msetpub",
577         SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
578         return REDISMODULE_ERR;
579
580     if (RedisModule_CreateCommand(ctx,"setiepub",
581         SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
582         return REDISMODULE_ERR;
583
584     if (RedisModule_CreateCommand(ctx,"setnepub",
585         SetNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
586         return REDISMODULE_ERR;
587
588     if (RedisModule_CreateCommand(ctx,"setxxpub",
589         SetXXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
590         return REDISMODULE_ERR;
591
592     if (RedisModule_CreateCommand(ctx,"setnxpub",
593         SetNXPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
594         return REDISMODULE_ERR;
595
596     if (RedisModule_CreateCommand(ctx,"delpub",
597         DelPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
598         return REDISMODULE_ERR;
599
600     if (RedisModule_CreateCommand(ctx,"deliepub",
601         DelIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
602         return REDISMODULE_ERR;
603
604     if (RedisModule_CreateCommand(ctx,"delnepub",
605         DelNEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
606         return REDISMODULE_ERR;
607
608     return REDISMODULE_OK;
609 }