allow multiple where condition joining by "and"

This commit is contained in:
Kenneth Cheng 2020-05-01 12:33:19 +08:00
parent ff90e37965
commit 3056d81fcc
2 changed files with 85 additions and 68 deletions

View File

@ -120,17 +120,20 @@ The above is nearly like REDIS keys command
Each record is exactly a hash, you could use raw REDIS commands ``hget, hmget or hgetall`` to retrieve the same content Each record is exactly a hash, you could use raw REDIS commands ``hget, hmget or hgetall`` to retrieve the same content
#### Where in Select Statement #### Where Clause in Select Statement
This module supports =, >, <, >=, <=, <>, != and like conditions. Only single condition is allowed. Your could specify =, >, <, >=, <=, <>, != or like conditions in where clause. Now the module only support "and" to join multiple conditions.
```bash ```bash
127.0.0.1:6379> dbx.select tel from phonebook where name like Son 127.0.0.1:6379> dbx.select tel from phonebook where name like Son
1) 1) tel 1) 1) tel
2) "1-888-3333-1412" 2) "1-888-3333-1412"
2) 1) tel 2) 1) tel
2) "1-456-1246-3421" 2) "1-456-1246-3421"
127.0.0.1:6379> dbx.select tel from phonebook where name like Son and pos = 4
1) 1) tel
2) "1-888-3333-1412"
``` ```
#### Order in Select Statement #### Order Clause in Select Statement
Ordering can be ascending or descending. All sortings are alpha-sort. Ordering can be ascending or descending. All sortings are alpha-sort.
```bash ```bash
127.0.0.1:6379> dbx.select * from phonebook order by pos asc 127.0.0.1:6379> dbx.select * from phonebook order by pos asc
@ -140,7 +143,7 @@ Ordering can be ascending or descending. All sortings are alpha-sort.
``` ```
#### Delete Statement #### Delete Statement
You may also use Insert and Delete statement to operate the hash You may also use Insert and Delete statement to operate the hash. If you does not provide the where clause, it will delete all the records of the specified key prefix. (i.e. phonebook)
```bash ```bash
127.0.0.1:6379> dbx.delete from phonebook where gender = F 127.0.0.1:6379> dbx.delete from phonebook where gender = F
(integer) 2 (integer) 2
@ -149,6 +152,7 @@ You may also use Insert and Delete statement to operate the hash
``` ```
#### Insert Statement #### Insert Statement
The module provide simple Insert statement which same as the function of the REDIS command hmset. It will append a random string to your provided key (i.e. phonebook). If operation is successful, it will return the key name.
```bash ```bash
127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson' ,1-456-1246-3421, 2019-10-01, 3, M) 127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson' ,1-456-1246-3421, 2019-10-01, 3, M)
"phonebook:1588298418-551514504" "phonebook:1588298418-551514504"
@ -159,7 +163,7 @@ You may also use Insert and Delete statement to operate the hash
127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Mattias Swensson' ,1-888-3333-1412, 2017-06-30, 4, M) 127.0.0.1:6379> dbx.insert into phonebook (name,tel,birth,pos,gender) values ('Mattias Swensson' ,1-888-3333-1412, 2017-06-30, 4, M)
"phonebook:1588299202-1052597574" "phonebook:1588299202-1052597574"
``` ```
Please be noted that Redis requires at least one space after the single and double quoted arguments. Note that Redis requires at least one space after the single and double quoted arguments.
Or you may quote the whole SQL statement as below: Or you may quote the whole SQL statement as below:
```bash ```bash
127.0.0.1:6379> dbx.insert "into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson','1-456-1246-3421','2019-10-01',3, 'M')" 127.0.0.1:6379> dbx.insert "into phonebook (name,tel,birth,pos,gender) values ('Peter Nelson','1-456-1246-3421','2019-10-01',3, 'M')"
@ -204,4 +208,4 @@ REDIS v4.0
MIT MIT
## Status ## Status
Now the Select statement only supports single where condition and single order sequence. I will add more useful features in the future. Simple Insert, Update and Delete statement will be included finally. This project is in an early stage of development. Any contribution is welcome :D This project is in an early stage of development. Any contribution is welcome :D

137
src/dbx.c
View File

@ -41,50 +41,52 @@ int whereRecord(RedisModuleCtx *ctx, RedisModuleString *key, Vector *vWhere) {
int match = 1; int match = 1;
// If where statement is defined, get the specified hash content and do comparison // If where statement is defined, get the specified hash content and do comparison
if (Vector_Size(vWhere) == 3) { size_t n = Vector_Size(vWhere);
Vector_Get(vWhere, 0, &field); if (n == 0) return 1;
Vector_Get(vWhere, 1, &condition); if (n % 3 != 0) return 0;
Vector_Get(vWhere, 2, &w); for (size_t i = 0; i < n; i += 3) {
Vector_Get(vWhere, i, &field);
Vector_Get(vWhere, i+1, &condition);
Vector_Get(vWhere, i+2, &w);
if (condition == 7) if (condition == 7)
toLower(w); toLower(w);
if (strlen(w) == 0) if (strlen(w) == 0) return 0;
match = 0;
else { RedisModuleCallReply *tags = RedisModule_Call(ctx, "HGET", "sc", key, field);
RedisModuleCallReply *tags = RedisModule_Call(ctx, "HGET", "sc", key, field); if (RedisModule_CallReplyLength(tags) == 0) {
if (RedisModule_CallReplyLength(tags) > 0) { RedisModule_FreeCallReply(tags);
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(tags); return 0;
size_t l;
const char *s = RedisModule_StringPtrLen(rms, &l);
switch(condition) {
case 0:
match = strcmp(s, w) >= 0? 1: 0;
break;
case 1:
match = strcmp(s, w) <= 0? 1: 0;
break;
case 2:
case 3:
match = strcmp(s, w) != 0? 1: 0;
break;
case 4:
match = strcmp(s, w) > 0? 1: 0;
break;
case 5:
match = strcmp(s, w) < 0? 1: 0;
break;
case 6:
match = strcmp(s, w) == 0? 1: 0;
break;
case 7:
match = strstr(toLower((char*)s), w)? 1: 0;
break;
}
RedisModule_FreeString(ctx, rms);
RedisModule_FreeCallReply(tags);
}
else
match = 0;
} }
RedisModuleString *rms = RedisModule_CreateStringFromCallReply(tags);
size_t l;
const char *s = RedisModule_StringPtrLen(rms, &l);
switch(condition) {
case 0:
match = strcmp(s, w) >= 0? 1: 0;
break;
case 1:
match = strcmp(s, w) <= 0? 1: 0;
break;
case 2:
case 3:
match = strcmp(s, w) != 0? 1: 0;
break;
case 4:
match = strcmp(s, w) > 0? 1: 0;
break;
case 5:
match = strcmp(s, w) < 0? 1: 0;
break;
case 6:
match = strcmp(s, w) == 0? 1: 0;
break;
case 7:
match = strstr(toLower((char*)s), w)? 1: 0;
break;
}
RedisModule_FreeString(ctx, rms);
RedisModule_FreeCallReply(tags);
if (match == 0) return 0;
} }
return match; return match;
} }
@ -154,20 +156,24 @@ Vector* splitStringByChar(char *s, char* d) {
Vector* splitWhereString(char *s) { Vector* splitWhereString(char *s) {
Vector *v = NewVector(void *, 16); Vector *v = NewVector(void *, 16);
static char chk[8][3] = {">=", "<=", "!=", "<>", ">", "<", "=", "~"}; char *token = strtok(s, "&&");
char *p = s; while (token != NULL) {
while(*p++) { static char chk[8][3] = {">=", "<=", "!=", "<>", ">", "<", "=", "~"};
for(int i=0; i<8; i++) { char *p = token;
char *c = chk[i]; while(*p++) {
if (strncmp(c, p, strlen(c)) == 0) { for(int i=0; i<8; i++) {
*p = 0; char *c = chk[i];
p += strlen(c); if (strncmp(c, p, strlen(c)) == 0) {
Vector_Push(v, s); *p = 0;
Vector_Push(v, i); p += strlen(c);
Vector_Push(v, p); Vector_Push(v, token);
break; Vector_Push(v, i);
Vector_Push(v, p);
break;
}
} }
} }
token = strtok(NULL, "&&");
} }
return v; return v;
} }
@ -283,7 +289,7 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
} }
break; break;
case -1: case -1:
// parse from statement // parse from clause
fromKeys = RMUtil_CreateFormattedString(ctx, token); fromKeys = RMUtil_CreateFormattedString(ctx, token);
step = 2; step = 2;
break; break;
@ -299,9 +305,11 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
break; break;
case -3: case -3:
case 4: case 4:
// parse where statement // parse where clause
if (strcmp("order", token) == 0) if (strcmp("order", token) == 0)
step = -5; step = -5;
else if (strcmp("and", token) == 0)
strcat(stmWhere, "&&");
else { else {
if (strlen(stmWhere) + strlen(token) > 512) { if (strlen(stmWhere) + strlen(token) > 512) {
RedisModule_ReplyWithError(ctx, "where arguments are too long"); RedisModule_ReplyWithError(ctx, "where arguments are too long");
@ -323,7 +331,7 @@ int SelectCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
break; break;
case -6: case -6:
case 7: case 7:
// parse order statement // parse order clause
if (strlen(stmOrder) + strlen(token) > 512) { if (strlen(stmOrder) + strlen(token) > 512) {
RedisModule_ReplyWithError(ctx, "order arguments are too long"); RedisModule_ReplyWithError(ctx, "order arguments are too long");
return REDISMODULE_ERR; return REDISMODULE_ERR;
@ -471,7 +479,7 @@ int InsertCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
} }
break; break;
case -1: case -1:
// parse into key, assume time+rand always is new key // parse into clause, assume time+rand always is new key
intoKey = RMUtil_CreateFormattedString(ctx, "%s:%u-%i", token, (unsigned)time(NULL), rand()); intoKey = RMUtil_CreateFormattedString(ctx, "%s:%u-%i", token, (unsigned)time(NULL), rand());
step = -2; step = -2;
break; break;
@ -615,7 +623,7 @@ int DeleteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
} }
break; break;
case -1: case -1:
// parse from statement // parse from clause
fromKeys = RMUtil_CreateFormattedString(ctx, token); fromKeys = RMUtil_CreateFormattedString(ctx, token);
step = 2; step = 2;
break; break;
@ -629,14 +637,19 @@ int DeleteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
break; break;
case -3: case -3:
case 4: case 4:
// parse where clause
if (strlen(stmWhere) + strlen(token) > 512) { if (strlen(stmWhere) + strlen(token) > 512) {
RedisModule_ReplyWithError(ctx, "where arguments are too long"); RedisModule_ReplyWithError(ctx, "where arguments are too long");
return REDISMODULE_ERR; return REDISMODULE_ERR;
} }
char *p = token; if (strcmp("and", token) == 0)
while (*p++) *p = *p == 7? 32: *p; strcat(stmWhere, "&&");
strcat(stmWhere, token); else {
step = 4; char *p = token;
while (*p++) *p = *p == 7? 32: *p;
strcat(stmWhere, token);
step = 4;
}
break; break;
} }
token = strtok(NULL, " "); token = strtok(NULL, " ");