📄 swq.c
字号:
/* swq_identify_field() */
/************************************************************************/
static int swq_identify_field( const char *token, swq_field_list *field_list,
swq_field_type *this_type, int *table_id )
{
int i;
char table_name[128];
const char *field_token = token;
int tables_enabled;
if( field_list->table_count > 0 && field_list->table_ids != NULL )
tables_enabled = TRUE;
else
tables_enabled = FALSE;
/* -------------------------------------------------------------------- */
/* Parse out table name if present, and table support enabled. */
/* -------------------------------------------------------------------- */
table_name[0] = '\0';
if( tables_enabled && strchr(token, '.') != NULL )
{
int dot_offset = (int)(strchr(token,'.') - token);
if( dot_offset < sizeof(table_name) )
{
strncpy( table_name, token, dot_offset );
table_name[dot_offset] = '\0';
field_token = token + dot_offset + 1;
}
}
/* -------------------------------------------------------------------- */
/* Search for matching field. */
/* -------------------------------------------------------------------- */
for( i = 0; i < field_list->count; i++ )
{
int t_id = 0;
if( strcasecmp( field_list->names[i], field_token ) != 0 )
continue;
/* Do the table specifications match? */
if( tables_enabled )
{
t_id = field_list->table_ids[i];
if( table_name[0] != '\0'
&& strcasecmp(table_name,
field_list->table_defs[t_id].table_alias) != 0 )
continue;
#ifdef notdef
if( t_id != 0 && table_name[0] == '\0' )
continue;
#endif
}
/* We have a match, return various information */
if( this_type != NULL )
{
if( field_list->types != NULL )
*this_type = field_list->types[i];
else
*this_type = SWQ_OTHER;
}
if( table_id != NULL )
*table_id = t_id;
if( field_list->ids == NULL )
return i;
else
return field_list->ids[i];
}
/* -------------------------------------------------------------------- */
/* No match, return failure. */
/* -------------------------------------------------------------------- */
if( this_type != NULL )
*this_type = SWQ_OTHER;
if( table_id != NULL )
*table_id = 0;
return -1;
}
/************************************************************************/
/* swq_parse_in_list() */
/* */
/* Parse the argument list to the IN predicate. Might be used */
/* something like: */
/* */
/* WHERE color IN ('Red', 'Green', 'Blue') */
/************************************************************************/
static char *swq_parse_in_list( char **tokens, int *tokens_consumed )
{
int i, text_off = 2;
char *result;
if( tokens[*tokens_consumed] == NULL
|| strcasecmp(tokens[*tokens_consumed],"(") != 0 )
{
sprintf( swq_error, "IN argument doesn't start with '('." );
return NULL;
}
*tokens_consumed += 1;
/* Establish length of all tokens plus separators. */
for( i = *tokens_consumed;
tokens[i] != NULL && strcasecmp(tokens[i],")") != 0;
i++ )
{
text_off += strlen(tokens[i]) + 1;
}
result = (char *) SWQ_MALLOC(text_off);
/* Actually capture all the arguments. */
text_off = 0;
while( tokens[*tokens_consumed] != NULL
&& strcasecmp(tokens[*tokens_consumed],")") != 0 )
{
strcpy( result + text_off, tokens[*tokens_consumed] );
text_off += strlen(tokens[*tokens_consumed]) + 1;
*tokens_consumed += 1;
if( strcasecmp(tokens[*tokens_consumed],",") != 0
&& strcasecmp(tokens[*tokens_consumed],")") != 0 )
{
sprintf( swq_error,
"Contents of IN predicate missing comma or closing bracket." );
SWQ_FREE( result );
return NULL;
}
else if( strcasecmp(tokens[*tokens_consumed],",") == 0 )
*tokens_consumed += 1;
}
/* add final extra terminating zero char */
result[text_off] = '\0';
if( tokens[*tokens_consumed] == NULL )
{
sprintf( swq_error,
"Contents of IN predicate missing closing bracket." );
SWQ_FREE( result );
return NULL;
}
*tokens_consumed += 1;
return result;
}
/************************************************************************/
/* swq_subexpr_compile() */
/************************************************************************/
static const char *
swq_subexpr_compile( char **tokens, swq_field_list *field_list,
swq_expr **expr_out, int *tokens_consumed )
{
swq_expr *op;
const char *error;
int op_code = 0;
*tokens_consumed = 0;
*expr_out = NULL;
if( tokens[0] == NULL || tokens[1] == NULL )
{
sprintf( swq_error, "Not enough tokens to complete expression." );
return swq_error;
}
op = (swq_field_op *) SWQ_MALLOC(sizeof(swq_field_op));
memset( op, 0, sizeof(swq_field_op) );
op->field_index = -1;
if( strcmp(tokens[0],"(") == 0 )
{
int sub_consumed = 0;
error = swq_subexpr_compile( tokens + 1, field_list,
(swq_expr **) &(op->first_sub_expr),
&sub_consumed );
if( error != NULL )
{
swq_expr_free( op );
return error;
}
if( strcmp(tokens[sub_consumed+1],")") != 0 )
{
swq_expr_free( op );
sprintf(swq_error,"Unclosed brackets, or incomplete expression.");
return swq_error;
}
*tokens_consumed += sub_consumed + 2;
/* If we are at the end of the tokens, we should return our subnode */
if( tokens[*tokens_consumed] == NULL
|| strcmp(tokens[*tokens_consumed],")") == 0 )
{
*expr_out = (swq_expr *) op->first_sub_expr;
op->first_sub_expr = NULL;
swq_expr_free( op );
return NULL;
}
}
else if( strcasecmp(tokens[0],"NOT") == 0 )
{
/* do nothing, the NOT will be collected as the operation */
}
else
{
op->field_index =
swq_identify_field( tokens[*tokens_consumed], field_list,
&(op->field_type),
&(op->table_index) );
if( op->field_index < 0 )
{
swq_expr_free( op );
sprintf( swq_error, "Failed to identify field:" );
strncat( swq_error, tokens[*tokens_consumed],
sizeof(swq_error) - strlen(swq_error) - 1 );
return swq_error;
}
(*tokens_consumed)++;
}
/*
** Identify the operation.
*/
if( tokens[*tokens_consumed] == NULL || tokens[*tokens_consumed+1] == NULL)
{
sprintf( swq_error, "Not enough tokens to complete expression." );
return swq_error;
}
op->operation = swq_identify_op( tokens, tokens_consumed );
if( op->operation == SWQ_UNKNOWN )
{
swq_expr_free( op );
sprintf( swq_error, "Failed to identify operation:" );
strncat( swq_error, tokens[*tokens_consumed],
sizeof(swq_error) - strlen(swq_error) - 1 );
return swq_error;
}
if( SWQ_OP_IS_LOGICAL( op->operation )
&& op->first_sub_expr == NULL
&& op->operation != SWQ_NOT )
{
swq_expr_free( op );
strcpy( swq_error, "Used logical operation with non-logical operand.");
return swq_error;
}
if( op->field_index != -1 && op->field_type == SWQ_STRING
&& (op->operation != SWQ_EQ && op->operation != SWQ_NE
&& op->operation != SWQ_GT && op->operation != SWQ_LT
&& op->operation != SWQ_GE && op->operation != SWQ_LE
&& op->operation != SWQ_LIKE && op->operation != SWQ_NOTLIKE
&& op->operation != SWQ_IN && op->operation != SWQ_NOTIN
&& op->operation != SWQ_ISNULL && op->operation != SWQ_ISNOTNULL ))
{
/* NOTE: the use of names[] here is wrong. We should be looking
up the field that matches op->field_index and op->table_index */
sprintf( swq_error,
"Attempt to use STRING field `%s' with numeric comparison `%s'.",
field_list->names[op->field_index], tokens[*tokens_consumed] );
swq_expr_free( op );
return swq_error;
}
(*tokens_consumed)++;
/*
** Collect the second operand as a subexpression.
*/
if( SWQ_OP_IS_POSTUNARY(op->operation) )
{
/* we don't need another argument. */
}
else if( tokens[*tokens_consumed] == NULL )
{
sprintf( swq_error, "Not enough tokens to complete expression." );
return swq_error;
}
else if( SWQ_OP_IS_LOGICAL( op->operation ) )
{
int sub_consumed = 0;
error = swq_subexpr_compile( tokens + *tokens_consumed, field_list,
(swq_expr **) &(op->second_sub_expr),
&sub_consumed );
if( error != NULL )
{
swq_expr_free( op );
return error;
}
*tokens_consumed += sub_consumed;
}
/* The IN predicate has a complex argument syntax. */
else if( op->operation == SWQ_IN || op->operation == SWQ_NOTIN )
{
op->string_value = swq_parse_in_list( tokens, tokens_consumed );
if( op->string_value == NULL )
{
swq_expr_free( op );
return swq_error;
}
}
/*
** Otherwise collect it as a literal value.
*/
else
{
op->string_value = swq_strdup(tokens[*tokens_consumed]);
op->int_value = atoi(op->string_value);
op->float_value = atof(op->string_value);
if( op->field_index != -1
&& (op->field_type == SWQ_INTEGER || op->field_type == SWQ_FLOAT)
&& op->string_value[0] != '-'
&& op->string_value[0] != '+'
&& op->string_value[0] != '.'
&& (op->string_value[0] < '0' || op->string_value[0] > '9') )
{
/* NOTE: the use of names[] here is wrong. We should be looking
up the field that matches op->field_index and op->table_index */
sprintf( swq_error,
"Attempt to compare numeric field `%s' to non-numeric"
" value `%s' is illegal.",
field_list->names[op->field_index], op->string_value );
swq_expr_free( op );
return swq_error;
}
(*tokens_consumed)++;
}
*expr_out = op;
/* Transform stuff like A NOT LIKE X into NOT (A LIKE X) */
if( op->operation == SWQ_NOTLIKE
|| op->operation == SWQ_ISNOTNULL
|| op->operation == SWQ_NOTIN )
{
if( op->operation == SWQ_NOTLIKE )
op->operation = SWQ_LIKE;
else if( op->operation == SWQ_NOTIN )
op->operation = SWQ_IN;
else if( op->operation == SWQ_ISNOTNULL )
op->operation = SWQ_ISNULL;
op = (swq_field_op *) SWQ_MALLOC(sizeof(swq_field_op));
memset( op, 0, sizeof(swq_field_op) );
op->field_index = -1;
op->second_sub_expr = (struct swq_node_s *) *expr_out;
op->operation = SWQ_NOT;
*expr_out = op;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -