Pretty ropey initial support for a '^' BQL operator that behaves like LIKE.
This commit is contained in:
@@ -423,6 +423,7 @@ QueryBuilderCreateSQL(QueryBuilder *builder, char **output)
|
||||
BongoStringBuilderAppend(&b, ";");
|
||||
|
||||
*output = MemStrdup(b.value);
|
||||
printf("SQL: '%s'\n", b.value);
|
||||
|
||||
BongoStringBuilderDestroy(&b);
|
||||
|
||||
@@ -476,7 +477,7 @@ AddExpValueByProperty(QueryBuilder *b, BongoStringBuilder *sb, void *exp, int co
|
||||
static int
|
||||
QueryExpressionToSQL(QueryBuilder *builder, struct expression *exp, BongoStringBuilder *sb)
|
||||
{
|
||||
const char basic_ops[] = "&|<>=!~";
|
||||
const char basic_ops[] = "&|<>=!~^";
|
||||
int retcode = 0;
|
||||
|
||||
for (unsigned int i=0; i < sizeof(basic_ops); i++) {
|
||||
@@ -504,12 +505,31 @@ QueryExpressionToSQL(QueryBuilder *builder, struct expression *exp, BongoStringB
|
||||
case '!':
|
||||
BongoStringBuilderAppend(sb, " != ");
|
||||
break;
|
||||
case '^':
|
||||
BongoStringBuilderAppend(sb, " LIKE ");
|
||||
break;
|
||||
default:
|
||||
// return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
retcode = AddExpValueByProperty(builder, sb, exp->exp2, exp->exp2_const);
|
||||
char *val = exp->exp2;
|
||||
if (exp->op[0] == '^') {
|
||||
// special case for LIKE: we need to stick % on the param
|
||||
int len = strlen(exp->exp2);
|
||||
val = malloc(len + 4);
|
||||
val[0] = '\''; val[1] = '%';
|
||||
char *expression = (char*)exp->exp2;
|
||||
for(int i=1; i < len; i++) val[i+1] = expression[i];
|
||||
val[len] = '%';
|
||||
val[len+1] = '\'';
|
||||
val[len+2] = '\0';
|
||||
}
|
||||
|
||||
retcode = AddExpValueByProperty(builder, sb, val, exp->exp2_const);
|
||||
|
||||
if (val != exp->exp2) free(val);
|
||||
|
||||
if (retcode) return retcode;
|
||||
|
||||
BongoStringBuilderAppend(sb, ")");
|
||||
|
||||
@@ -76,7 +76,7 @@ pull_token(char **query, char **out_token)
|
||||
int
|
||||
QueryParser_IsOp (const char *token)
|
||||
{
|
||||
const char *ops = "&|<>=!{l~";
|
||||
const char *ops = "&|<>=!{l~^";
|
||||
|
||||
// operations must be single characters
|
||||
if (token[1] != '\0') return -1;
|
||||
@@ -88,6 +88,16 @@ QueryParser_IsOp (const char *token)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
QueryParser_CanSubExp (const char *token)
|
||||
{
|
||||
// this is true for any operator that can take sub-expressions.
|
||||
// basically just the boolean operators.
|
||||
if (token[0] == '&') return 0;
|
||||
if (token[0] == '|') return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define CHAR_IS_LC_ALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
|
||||
#define CHAR_IS_NUMBER(x) (((x) >= '0') && ((x) <= '9'))
|
||||
#define CHAR_IS_PERIOD(x) ((x) == '.')
|
||||
@@ -194,6 +204,13 @@ QueryParserRun(struct parser_state *state, BOOL strict_quotes)
|
||||
}
|
||||
if (QueryParser_IsOp(token) == 0) {
|
||||
if (current_expression->op != NULL) {
|
||||
// check this operator will allow sub-expressions
|
||||
// TODO - this isn't quite right yet.
|
||||
//if (QueryParser_CanSubExp(current_expression->op) == 0) {
|
||||
// DEBUG_MESSAGE("ERR: Cannot accept subexpression at this point\n");
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
// need to find a free expr slot
|
||||
struct expression *next_expression = ++(state->last);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ int QueryParserRun(struct parser_state *state, BOOL strict_quotes);
|
||||
void QueryParserFinish(struct parser_state *state);
|
||||
|
||||
int QueryParser_IsOp (const char *token);
|
||||
int QueryParser_CanSubExp (const char *token);
|
||||
int QueryParser_IsProperty (const char *token);
|
||||
int QueryParser_IsNumber (const char *token);
|
||||
int QueryParser_IsString (const char *token);
|
||||
|
||||
Reference in New Issue
Block a user