Parsing complex arithmetic operations.
parent
10f571263c
commit
51893ebd37
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
yacc -t -d query.yacc && lex -i query.lex
|
||||
export PATH=/usr/local/Cellar/bison/3.0/bin:/usr/local/Cellar/flex/2.5.37/bin:$PATH
|
||||
|
||||
bison -t -d query.yacc -o y.tab.c --defines=y.tab.h && flex -o lex.yy.c -i query.lex
|
||||
|
|
|
@ -32,8 +32,12 @@ free_value(value *value)
|
|||
void
|
||||
free_expression(expression *expr)
|
||||
{
|
||||
free_value(expr->left);
|
||||
if (expr->right) free_value(expr->right);
|
||||
if (expr->op == 0) {
|
||||
free_value((value*)expr->left);
|
||||
} else {
|
||||
free_expression((expression*) expr->left);
|
||||
free_expression(expr->right);
|
||||
}
|
||||
free(expr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#line 2 "lex.yy.c"
|
||||
|
||||
#line 3 "lex.yy.c"
|
||||
#line 4 "lex.yy.c"
|
||||
|
||||
#define YY_INT_ALIGNED short int
|
||||
|
||||
|
@ -8,7 +9,7 @@
|
|||
#define FLEX_SCANNER
|
||||
#define YY_FLEX_MAJOR_VERSION 2
|
||||
#define YY_FLEX_MINOR_VERSION 5
|
||||
#define YY_FLEX_SUBMINOR_VERSION 35
|
||||
#define YY_FLEX_SUBMINOR_VERSION 37
|
||||
#if YY_FLEX_SUBMINOR_VERSION > 0
|
||||
#define FLEX_BETA
|
||||
#endif
|
||||
|
@ -158,15 +159,7 @@ typedef void* yyscan_t;
|
|||
|
||||
/* Size of default input buffer. */
|
||||
#ifndef YY_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k.
|
||||
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
|
||||
* Ditto for the __ia64__ case accordingly.
|
||||
*/
|
||||
#define YY_BUF_SIZE 32768
|
||||
#else
|
||||
#define YY_BUF_SIZE 16384
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
/* The state buf must be large enough to hold one state per character in the main buffer.
|
||||
|
@ -178,6 +171,11 @@ typedef void* yyscan_t;
|
|||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SIZE_T
|
||||
#define YY_TYPEDEF_YY_SIZE_T
|
||||
typedef size_t yy_size_t;
|
||||
#endif
|
||||
|
||||
#define EOB_ACT_CONTINUE_SCAN 0
|
||||
#define EOB_ACT_END_OF_FILE 1
|
||||
#define EOB_ACT_LAST_MATCH 2
|
||||
|
@ -200,11 +198,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
|||
|
||||
#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SIZE_T
|
||||
#define YY_TYPEDEF_YY_SIZE_T
|
||||
typedef size_t yy_size_t;
|
||||
#endif
|
||||
|
||||
#ifndef YY_STRUCT_YY_BUFFER_STATE
|
||||
#define YY_STRUCT_YY_BUFFER_STATE
|
||||
struct yy_buffer_state
|
||||
|
@ -222,7 +215,7 @@ struct yy_buffer_state
|
|||
/* Number of characters read into yy_ch_buf, not including EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_n_chars;
|
||||
yy_size_t yy_n_chars;
|
||||
|
||||
/* Whether we "own" the buffer - i.e., we know we created it,
|
||||
* and can realloc() it to grow it, and should free() it to
|
||||
|
@ -301,7 +294,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
|
|||
|
||||
YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
|
||||
|
||||
void *yyalloc (yy_size_t ,yyscan_t yyscanner );
|
||||
void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
|
||||
|
@ -331,7 +324,7 @@ void yyfree (void * ,yyscan_t yyscanner );
|
|||
|
||||
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
|
||||
|
||||
#define yywrap(n) 1
|
||||
#define yywrap(yyscanner) 1
|
||||
#define YY_SKIP_YYWRAP
|
||||
|
||||
typedef unsigned char YY_CHAR;
|
||||
|
@ -570,7 +563,7 @@ static yyconst flex_int16_t yy_chk[458] =
|
|||
yylloc_param->last_column = yycolumn+yyleng-1; \
|
||||
yycolumn += yyleng; \
|
||||
} while(0);
|
||||
#line 574 "lex.yy.c"
|
||||
#line 567 "lex.yy.c"
|
||||
|
||||
#define INITIAL 0
|
||||
|
||||
|
@ -599,8 +592,8 @@ struct yyguts_t
|
|||
size_t yy_buffer_stack_max; /**< capacity of stack. */
|
||||
YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
|
||||
char yy_hold_char;
|
||||
int yy_n_chars;
|
||||
int yyleng_r;
|
||||
yy_size_t yy_n_chars;
|
||||
yy_size_t yyleng_r;
|
||||
char *yy_c_buf_p;
|
||||
int yy_init;
|
||||
int yy_start;
|
||||
|
@ -657,7 +650,7 @@ FILE *yyget_out (yyscan_t yyscanner );
|
|||
|
||||
void yyset_out (FILE * out_str ,yyscan_t yyscanner );
|
||||
|
||||
int yyget_leng (yyscan_t yyscanner );
|
||||
yy_size_t yyget_leng (yyscan_t yyscanner );
|
||||
|
||||
char *yyget_text (yyscan_t yyscanner );
|
||||
|
||||
|
@ -665,6 +658,10 @@ int yyget_lineno (yyscan_t yyscanner );
|
|||
|
||||
void yyset_lineno (int line_number ,yyscan_t yyscanner );
|
||||
|
||||
int yyget_column (yyscan_t yyscanner );
|
||||
|
||||
void yyset_column (int column_no ,yyscan_t yyscanner );
|
||||
|
||||
YYSTYPE * yyget_lval (yyscan_t yyscanner );
|
||||
|
||||
void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
|
||||
|
@ -707,12 +704,7 @@ static int input (yyscan_t yyscanner );
|
|||
|
||||
/* Amount of stuff to slurp up with each read. */
|
||||
#ifndef YY_READ_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k */
|
||||
#define YY_READ_BUF_SIZE 16384
|
||||
#else
|
||||
#define YY_READ_BUF_SIZE 8192
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
/* Copy whatever the last rule matched to the standard output. */
|
||||
|
@ -819,7 +811,7 @@ YY_DECL
|
|||
#line 21 "query.lex"
|
||||
|
||||
|
||||
#line 823 "lex.yy.c"
|
||||
#line 815 "lex.yy.c"
|
||||
|
||||
yylval = yylval_param;
|
||||
|
||||
|
@ -1059,7 +1051,7 @@ YY_RULE_SETUP
|
|||
#line 61 "query.lex"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 1063 "lex.yy.c"
|
||||
#line 1055 "lex.yy.c"
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
yyterminate();
|
||||
|
||||
|
@ -1246,21 +1238,21 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
|||
|
||||
else
|
||||
{
|
||||
int num_to_read =
|
||||
yy_size_t num_to_read =
|
||||
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
|
||||
|
||||
while ( num_to_read <= 0 )
|
||||
{ /* Not enough room in the buffer - grow it. */
|
||||
|
||||
/* just a shorter name for the current buffer */
|
||||
YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
|
||||
YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
|
||||
|
||||
int yy_c_buf_p_offset =
|
||||
(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
|
||||
|
||||
if ( b->yy_is_our_buffer )
|
||||
{
|
||||
int new_size = b->yy_buf_size * 2;
|
||||
yy_size_t new_size = b->yy_buf_size * 2;
|
||||
|
||||
if ( new_size <= 0 )
|
||||
b->yy_buf_size += b->yy_buf_size / 8;
|
||||
|
@ -1291,7 +1283,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
|||
|
||||
/* Read in more data. */
|
||||
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
|
||||
yyg->yy_n_chars, (size_t) num_to_read );
|
||||
yyg->yy_n_chars, num_to_read );
|
||||
|
||||
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
|
||||
}
|
||||
|
@ -1388,6 +1380,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
|||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
yy_is_jam = (yy_current_state == 72);
|
||||
|
||||
(void)yyg;
|
||||
return yy_is_jam ? 0 : yy_current_state;
|
||||
}
|
||||
|
||||
|
@ -1404,7 +1397,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
|||
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
|
||||
{ /* need to shift things up to make room */
|
||||
/* +2 for EOB chars. */
|
||||
register int number_to_move = yyg->yy_n_chars + 2;
|
||||
register yy_size_t number_to_move = yyg->yy_n_chars + 2;
|
||||
register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
|
||||
YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
|
||||
register char *source =
|
||||
|
@ -1454,7 +1447,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
|||
|
||||
else
|
||||
{ /* need more input */
|
||||
int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
|
||||
yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
|
||||
++yyg->yy_c_buf_p;
|
||||
|
||||
switch ( yy_get_next_buffer( yyscanner ) )
|
||||
|
@ -1618,10 +1611,6 @@ static void yy_load_buffer_state (yyscan_t yyscanner)
|
|||
yyfree((void *) b ,yyscanner );
|
||||
}
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern int isatty (int );
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Initializes or reinitializes a buffer.
|
||||
* This function is sometimes called more than once on the same buffer,
|
||||
* such as during a yyrestart() or at EOF.
|
||||
|
@ -1738,7 +1727,7 @@ void yypop_buffer_state (yyscan_t yyscanner)
|
|||
*/
|
||||
static void yyensure_buffer_stack (yyscan_t yyscanner)
|
||||
{
|
||||
int num_to_alloc;
|
||||
yy_size_t num_to_alloc;
|
||||
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
|
||||
|
||||
if (!yyg->yy_buffer_stack) {
|
||||
|
@ -1836,7 +1825,7 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
|
|||
* @param yyscanner The scanner object.
|
||||
* @return the newly allocated buffer state object.
|
||||
*/
|
||||
YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
|
||||
YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
|
||||
{
|
||||
YY_BUFFER_STATE b;
|
||||
char *buf;
|
||||
|
@ -1951,7 +1940,7 @@ FILE *yyget_out (yyscan_t yyscanner)
|
|||
/** Get the length of the current token.
|
||||
* @param yyscanner The scanner object.
|
||||
*/
|
||||
int yyget_leng (yyscan_t yyscanner)
|
||||
yy_size_t yyget_leng (yyscan_t yyscanner)
|
||||
{
|
||||
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
|
||||
return yyleng;
|
||||
|
@ -1987,7 +1976,7 @@ void yyset_lineno (int line_number , yyscan_t yyscanner)
|
|||
|
||||
/* lineno is only valid if an input buffer exists. */
|
||||
if (! YY_CURRENT_BUFFER )
|
||||
yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner);
|
||||
YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
|
||||
|
||||
yylineno = line_number;
|
||||
}
|
||||
|
@ -2002,7 +1991,7 @@ void yyset_column (int column_no , yyscan_t yyscanner)
|
|||
|
||||
/* column is only valid if an input buffer exists. */
|
||||
if (! YY_CURRENT_BUFFER )
|
||||
yy_fatal_error( "yyset_column called with no buffer" , yyscanner);
|
||||
YY_FATAL_ERROR( "yyset_column called with no buffer" );
|
||||
|
||||
yycolumn = column_no;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ func (self *Value) IsFunctionCall() bool {
|
|||
}
|
||||
|
||||
type Expression struct {
|
||||
Left *Value
|
||||
Left interface{}
|
||||
Operation byte
|
||||
Right *Value
|
||||
Right *Expression
|
||||
}
|
||||
|
||||
type BoolExpression struct {
|
||||
|
@ -45,6 +45,20 @@ type WhereCondition struct {
|
|||
Right *WhereCondition
|
||||
}
|
||||
|
||||
func (self *WhereCondition) GetBoolExpression() (*BoolExpression, bool) {
|
||||
if self.isBooleanExpression {
|
||||
return self.Left.(*BoolExpression), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (self *WhereCondition) GetLeftWhereCondition() (*WhereCondition, bool) {
|
||||
if !self.isBooleanExpression {
|
||||
return self.Left.(*WhereCondition), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
q C.query
|
||||
closed bool
|
||||
|
@ -53,12 +67,6 @@ type Query struct {
|
|||
groupByClause GroupByClause
|
||||
Limit int
|
||||
}
|
||||
func (self *WhereCondition) GetBoolExpression() (*BoolExpression, bool) {
|
||||
if self.isBooleanExpression {
|
||||
return self.Left.(*BoolExpression), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (self *Query) GetColumnNames() []*Value {
|
||||
if self.ColumnNames != nil {
|
||||
|
@ -73,9 +81,16 @@ func (self *Query) GetFromClause() *Value {
|
|||
return GetValue(self.q.f)
|
||||
}
|
||||
|
||||
func (self *Expression) GetSimpleValue() (*Value, bool) {
|
||||
if self.Operation == '\000' {
|
||||
return self.Left, true
|
||||
func (self *Expression) GetLeftValue() (*Value, bool) {
|
||||
if self.Operation == 0 {
|
||||
return self.Left.(*Value), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (self *Expression) GetLeftExpression() (*Expression, bool) {
|
||||
if self.Operation != 0 {
|
||||
return self.Left.(*Expression), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
@ -128,10 +143,14 @@ func GetValue(value *C.value) *Value {
|
|||
|
||||
func GetExpression(expr *C.expression) *Expression {
|
||||
expression := &Expression{}
|
||||
expression.Left = GetValue(expr.left)
|
||||
if expr.op != '\000' {
|
||||
if expr.op == 0 {
|
||||
expression.Left = GetValue((*C.value)(expr.left))
|
||||
expression.Operation = byte(expr.op)
|
||||
expression.Right = GetValue(expr.right)
|
||||
expression.Right = nil
|
||||
} else {
|
||||
expression.Left = GetExpression((*C.expression)(expr.left))
|
||||
expression.Operation = byte(expr.op)
|
||||
expression.Right = GetExpression((*C.expression)(unsafe.Pointer(expr.right)))
|
||||
}
|
||||
|
||||
return expression
|
||||
|
|
|
@ -3,6 +3,7 @@ package query
|
|||
import (
|
||||
. "launchpad.net/gocheck"
|
||||
"testing"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Hook up gocheck into the gotest runner.
|
||||
|
@ -21,296 +22,363 @@ func ToValueArray(strings ...string) (values []*Value) {
|
|||
return
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseBasicSelectQuery(c *C) {
|
||||
q, err := ParseQuery("select value from t where c == '5';")
|
||||
// func (self *QueryParserSuite) TestParseBasicSelectQuery(c *C) {
|
||||
// q, err := ParseQuery("select value from t where c == '5';")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.Limit, Equals, 0)
|
||||
|
||||
// c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value"))
|
||||
// w := q.GetWhereCondition()
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
// boolExpression, ok := w.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// leftExpression := boolExpression.Left
|
||||
// rightExpression := boolExpression.Right
|
||||
|
||||
// leftValue, ok := leftExpression.GetLeftValue() // simple value is an expression with one value, e.g. it doesn't combine value using arithmetic operations
|
||||
// rightValue, ok := rightExpression.GetLeftValue()
|
||||
|
||||
// c.Assert(leftValue.Name, Equals, "c")
|
||||
// c.Assert(boolExpression.Operation, Equals, "==")
|
||||
// c.Assert(rightValue.Name, Equals, "5")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithoutWhereClause(c *C) {
|
||||
// q, err := ParseQuery("select value, time from t;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value", "time"))
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
// c.Assert(q.GetWhereCondition(), IsNil)
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithUpperCase(c *C) {
|
||||
// q, err := ParseQuery("SELECT VALUE, TIME FROM t WHERE C == '5';")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("VALUE", "TIME"))
|
||||
// w := q.GetWhereCondition()
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
// boolExpression, ok := w.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// leftExpression := boolExpression.Left
|
||||
// rightExpression := boolExpression.Right
|
||||
|
||||
// leftValue, ok := leftExpression.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// rightValue, ok := rightExpression.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// c.Assert(leftValue.Name, Equals, "C")
|
||||
// c.Assert(rightValue.Name, Equals, "5")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithMultipleColumns(c *C) {
|
||||
// q, err := ParseQuery("select value, time from t;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithInequality(c *C) {
|
||||
// q, err := ParseQuery("select value, time from t where c < 5;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// w := q.GetWhereCondition()
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
// boolExpression, ok := w.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// leftExpression := boolExpression.Left
|
||||
// rightExpression := boolExpression.Right
|
||||
// leftValue, ok := leftExpression.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// rightValue, ok := rightExpression.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// c.Assert(leftValue.Name, Equals, "c")
|
||||
// c.Assert(boolExpression.Operation, Equals, "<")
|
||||
// c.Assert(rightValue.Name, Equals, "5")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithTimeCondition(c *C) {
|
||||
// q, err := ParseQuery("select value, time from t where time > now() - 1d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// w := q.GetWhereCondition()
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
// boolExpression, ok := w.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// leftExpression := boolExpression.Left
|
||||
// leftValue, ok := leftExpression.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(leftValue.Name, Equals, "time")
|
||||
|
||||
// rightExpression := boolExpression.Right
|
||||
// funCallExpr, ok := rightExpression.GetLeftExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// funCall, ok := funCallExpr.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// oneDay, ok := rightExpression.Right.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// c.Assert(funCall.IsFunctionCall(), Equals, true)
|
||||
// c.Assert(funCall.Name, Equals, "now")
|
||||
// c.Assert(oneDay.IsFunctionCall(), Equals, false)
|
||||
// c.Assert(oneDay.Name, Equals, "1d")
|
||||
// c.Assert(rightExpression.Operation, Equals, byte('-'))
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithAnd(c *C) {
|
||||
// q, err := ParseQuery("select value from cpu.idle where time>now()-7d and time<now()-6d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
// w := q.GetWhereCondition()
|
||||
// c.Assert(w.Operation, Equals, "AND")
|
||||
|
||||
// // leftBoolExpression = 'time > now() - 7d'
|
||||
// leftWhereCondition, ok := w.GetLeftWhereCondition()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// leftBoolExpression, ok := leftWhereCondition.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// // rightBoolExpression = 'time < now() - 6d'
|
||||
// rightBoolExpression, ok := w.Right.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
|
||||
// c.Assert(leftBoolExpression.Left.Left, DeepEquals, &Value{"time", nil})
|
||||
// expr, ok := leftBoolExpression.Right.GetLeftExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// value, ok := expr.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"now", []*Value{}})
|
||||
// value, ok = leftBoolExpression.Right.Right.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"7d", nil})
|
||||
// c.Assert(leftBoolExpression.Operation, Equals, ">")
|
||||
|
||||
// c.Assert(rightBoolExpression.Left.Left, DeepEquals, &Value{"time", nil})
|
||||
// expr, ok = rightBoolExpression.Right.GetLeftExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// value, ok = expr.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"now", []*Value{}})
|
||||
// value, ok = rightBoolExpression.Right.Right.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"6d", nil})
|
||||
// c.Assert(rightBoolExpression.Operation, Equals, "<")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithGroupBy(c *C) {
|
||||
// q, err := ParseQuery("select count(*) from users.events group_by user_email,time(1h) where time>now()-1d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "users.events")
|
||||
// c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
|
||||
// column := q.GetColumnNames()[0]
|
||||
// c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
// c.Assert(column.Name, Equals, "count")
|
||||
// c.Assert(column.Elems, HasLen, 1)
|
||||
// c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
||||
// c.Assert(column.Elems[0].Name, Equals, "*")
|
||||
|
||||
// groupBy := q.GetGroupByClause()
|
||||
// c.Assert(groupBy, HasLen, 2)
|
||||
// c.Assert(groupBy[0].IsFunctionCall(), Equals, false)
|
||||
// c.Assert(groupBy[0].Name, Equals, "user_email")
|
||||
// c.Assert(groupBy[1].IsFunctionCall(), Equals, true)
|
||||
// c.Assert(groupBy[1].Name, Equals, "time")
|
||||
// c.Assert(groupBy[1].Elems, HasLen, 1)
|
||||
// c.Assert(groupBy[1].Elems[0].Name, Equals, "1h")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseFromWithNestedFunctions(c *C) {
|
||||
// q, err := ParseQuery("select top(10, count(*)) from users.events;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
// column := q.GetColumnNames()[0]
|
||||
// c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
// c.Assert(column.Name, Equals, "top")
|
||||
// c.Assert(column.Elems, HasLen, 2)
|
||||
// c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
||||
// c.Assert(column.Elems[0].Name, Equals, "10")
|
||||
// c.Assert(column.Elems[1].IsFunctionCall(), Equals, true)
|
||||
// c.Assert(column.Elems[1].Name, Equals, "count")
|
||||
// c.Assert(column.Elems[1].Elems, HasLen, 1)
|
||||
// c.Assert(column.Elems[1].Elems[0].IsFunctionCall(), Equals, false)
|
||||
// c.Assert(column.Elems[1].Elems[0].Name, Equals, "*")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseWhereClausePrecedence(c *C) {
|
||||
// q, err := ParseQuery("select value from cpu.idle where value > 90 and time > now() - 1d or value > 80 and time > now() - 1w;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
// whereCondition := q.GetWhereCondition()
|
||||
|
||||
// c.Assert(whereCondition.Operation, Equals, "OR")
|
||||
// leftCondition, ok := whereCondition.Left.(*WhereCondition)
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(leftCondition.Operation, Equals, "AND")
|
||||
|
||||
// condition, ok := leftCondition.GetLeftWhereCondition()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// leftExpression, ok := condition.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(leftExpression.Operation, Equals, ">")
|
||||
// c.Assert(leftExpression.Left.Left, DeepEquals, &Value{"value", nil})
|
||||
// c.Assert(leftExpression.Right.Left, DeepEquals, &Value{"90", nil})
|
||||
|
||||
// rightExpression, ok := leftCondition.Right.GetBoolExpression()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(rightExpression.Operation, Equals, ">")
|
||||
// c.Assert(rightExpression.Left.Left, DeepEquals, &Value{"time", nil})
|
||||
// expr, ok := rightExpression.Right.GetLeftExpression()
|
||||
// value, ok := expr.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"now", []*Value{}})
|
||||
// value, ok = rightExpression.Right.Right.GetLeftValue()
|
||||
// c.Assert(ok, Equals, true)
|
||||
// c.Assert(value, DeepEquals, &Value{"1d", nil})
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseWhereClauseParantheses(c *C) {
|
||||
// q, err := ParseQuery("select value from cpu.idle where value > 90 and (time > now() - 1d or value > 80) and time < now() - 1w;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
// whereCondition := q.GetWhereCondition()
|
||||
|
||||
// first := whereCondition.Left.(*WhereCondition).Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
// second := whereCondition.Left.(*WhereCondition).Right
|
||||
// third := whereCondition.Right.Left.(*BoolExpression)
|
||||
|
||||
// c.Assert(first.Operation, Equals, ">")
|
||||
// c.Assert(second.Operation, Equals, "OR")
|
||||
// c.Assert(third.Operation, Equals, "<")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithLast(c *C) {
|
||||
// q, err := ParseQuery("select value from t last 10;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.Limit, Equals, -10)
|
||||
|
||||
// q, err = ParseQuery("select value from t first 10;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.Limit, Equals, 10)
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseFromWithNestedFunctions2(c *C) {
|
||||
// q, err := ParseQuery("select count(distinct(email)) from user.events where time>now()-1d group_by time(15m);")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
// column := q.GetColumnNames()[0]
|
||||
// c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
// c.Assert(column.Name, Equals, "count")
|
||||
// c.Assert(column.Elems, HasLen, 1)
|
||||
// c.Assert(column.Elems[0].IsFunctionCall(), Equals, true)
|
||||
// c.Assert(column.Elems[0].Name, Equals, "distinct")
|
||||
// c.Assert(column.Elems[0].Elems, HasLen, 1)
|
||||
// c.Assert(column.Elems[0].Elems[0].Name, Equals, "email")
|
||||
|
||||
// c.Assert(q.GetGroupByClause(), HasLen, 1)
|
||||
// c.Assert(q.GetGroupByClause()[0], DeepEquals, &Value{
|
||||
// Name: "time",
|
||||
// Elems: []*Value{&Value{"15m", nil}},
|
||||
// })
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseFromWithMergedTable(c *C) {
|
||||
// q, err := ParseQuery("select count(*) from merge(newsletter.signups,user.signups) where time>now()-1d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetFromClause().IsFunctionCall(), Equals, true)
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "merge")
|
||||
// c.Assert(q.GetFromClause().Elems, HasLen, 2)
|
||||
// c.Assert(q.GetFromClause().Elems[0].Name, Equals, "newsletter.signups")
|
||||
// c.Assert(q.GetFromClause().Elems[1].Name, Equals, "user.signups")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseFromWithJoinedTable(c *C) {
|
||||
// q, err := ParseQuery("select max(t1.value, t2.value) from inner_join(newsletter.signups, t1, user.signups, t2) where time>now()-1d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// c.Assert(q.GetFromClause().IsFunctionCall(), Equals, true)
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "inner_join")
|
||||
// c.Assert(q.GetFromClause().Elems, HasLen, 4)
|
||||
// c.Assert(q.GetFromClause().Elems[0].Name, Equals, "newsletter.signups")
|
||||
// c.Assert(q.GetFromClause().Elems[1].Name, Equals, "t1")
|
||||
// c.Assert(q.GetFromClause().Elems[2].Name, Equals, "user.signups")
|
||||
// c.Assert(q.GetFromClause().Elems[3].Name, Equals, "t2")
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithRegexCondition(c *C) {
|
||||
// q, err := ParseQuery("select email from users.events where email ~= /gmail\\.com/i and time>now()-2d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
// w := q.GetWhereCondition()
|
||||
|
||||
// regexExpression := w.Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
// c.Assert(regexExpression.Left.Left, DeepEquals, &Value{"email", nil})
|
||||
// c.Assert(regexExpression.Operation, Equals, "~=")
|
||||
// c.Assert(regexExpression.Right.Left, DeepEquals, &Value{"/gmail\\.com/i", nil})
|
||||
// }
|
||||
|
||||
// func (self *QueryParserSuite) TestParseSelectWithRegexTables(c *C) {
|
||||
// q, err := ParseQuery("select email from users.* where time>now()-2d;")
|
||||
// defer q.Close()
|
||||
// c.Assert(err, IsNil)
|
||||
|
||||
// c.Assert(q.GetFromClause().Name, Equals, "users.*")
|
||||
// }
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithComplexArithmeticOperations(c *C) {
|
||||
q, err := ParseQuery("select value from cpu.idle where 30 < value * 1 / 3 ;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Assert(q.Limit, Equals, 0)
|
||||
c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value"))
|
||||
w := q.GetWhereCondition()
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
boolExpression, ok := w.GetBoolExpression()
|
||||
boolExpression, ok := q.GetWhereCondition().GetBoolExpression()
|
||||
c.Assert(ok, Equals, true)
|
||||
|
||||
leftExpression := boolExpression.Left
|
||||
rightExpression := boolExpression.Right
|
||||
c.Assert(boolExpression.Left.Left, DeepEquals, &Value{"30", nil})
|
||||
|
||||
leftValue, ok := leftExpression.GetSimpleValue() // simple value is an expression with one value, e.g. it doesn't combine value using arithmetic operations
|
||||
rightValue, ok := rightExpression.GetSimpleValue()
|
||||
|
||||
c.Assert(leftValue.Name, Equals, "c")
|
||||
c.Assert(boolExpression.Operation, Equals, "==")
|
||||
c.Assert(rightValue.Name, Equals, "5")
|
||||
}
|
||||
// value * 1 / 3
|
||||
rightExpression := boolExpression.Right.Right
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithoutWhereClause(c *C) {
|
||||
q, err := ParseQuery("select value, time from t;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value", "time"))
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
c.Assert(q.GetWhereCondition(), IsNil)
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithUpperCase(c *C) {
|
||||
q, err := ParseQuery("SELECT VALUE, TIME FROM t WHERE C == '5';")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("VALUE", "TIME"))
|
||||
w := q.GetWhereCondition()
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
boolExpression := w.Left.(*BoolExpression)
|
||||
leftExpression := boolExpression.Left
|
||||
rightExpression := boolExpression.Right
|
||||
leftValue := leftExpression.Left.Name
|
||||
rightValue := rightExpression.Left.Name
|
||||
|
||||
c.Assert(leftValue, Equals, "C")
|
||||
c.Assert(rightValue, Equals, "5")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithMultipleColumns(c *C) {
|
||||
q, err := ParseQuery("select value, time from t;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithInequality(c *C) {
|
||||
q, err := ParseQuery("select value, time from t where c < 5;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
w := q.GetWhereCondition()
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
|
||||
boolExpression := w.Left.(*BoolExpression)
|
||||
leftExpression := boolExpression.Left
|
||||
rightExpression := boolExpression.Right
|
||||
leftValue := leftExpression.Left.Name
|
||||
rightValue := rightExpression.Left.Name
|
||||
|
||||
c.Assert(leftValue, Equals, "c")
|
||||
c.Assert(boolExpression.Operation, Equals, "<")
|
||||
c.Assert(rightValue, Equals, "5")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithTimeCondition(c *C) {
|
||||
q, err := ParseQuery("select value, time from t where time > now() - 1d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
w := q.GetWhereCondition()
|
||||
|
||||
boolExpression := w.Left.(*BoolExpression)
|
||||
leftExpression := boolExpression.Left
|
||||
rightExpression := boolExpression.Right
|
||||
leftValue := leftExpression.Left.Name
|
||||
|
||||
funCall := rightExpression.Left
|
||||
oneDay := rightExpression.Right
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "t")
|
||||
c.Assert(leftValue, Equals, "time")
|
||||
c.Assert(funCall.IsFunctionCall(), Equals, true)
|
||||
c.Assert(funCall.Name, Equals, "now")
|
||||
c.Assert(oneDay.IsFunctionCall(), Equals, false)
|
||||
c.Assert(oneDay.Name, Equals, "1d")
|
||||
c.Assert(rightExpression.Operation, Equals, byte('-'))
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithAnd(c *C) {
|
||||
q, err := ParseQuery("select value from cpu.idle where time>now()-7d and time<now()-6d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
w := q.GetWhereCondition()
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
leftBoolExpression := w.Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
c.Assert(w.Operation, Equals, "AND")
|
||||
rightBoolExpression := w.Right.Left.(*BoolExpression)
|
||||
|
||||
c.Assert(leftBoolExpression.Left.Left.Name, Equals, "time")
|
||||
c.Assert(leftBoolExpression.Left.Left.IsFunctionCall(), Equals, false)
|
||||
c.Assert(leftBoolExpression.Right.Left.Name, Equals, "now")
|
||||
c.Assert(leftBoolExpression.Right.Left.IsFunctionCall(), Equals, true)
|
||||
c.Assert(leftBoolExpression.Right.Right.Name, Equals, "7d")
|
||||
c.Assert(leftBoolExpression.Right.Right.IsFunctionCall(), Equals, false)
|
||||
c.Assert(leftBoolExpression.Operation, Equals, ">")
|
||||
|
||||
c.Assert(rightBoolExpression.Left.Left.Name, Equals, "time")
|
||||
c.Assert(rightBoolExpression.Left.Left.IsFunctionCall(), Equals, false)
|
||||
c.Assert(rightBoolExpression.Right.Left.Name, Equals, "now")
|
||||
c.Assert(rightBoolExpression.Right.Left.IsFunctionCall(), Equals, true)
|
||||
c.Assert(rightBoolExpression.Right.Right.Name, Equals, "6d")
|
||||
c.Assert(rightBoolExpression.Right.Right.IsFunctionCall(), Equals, false)
|
||||
c.Assert(rightBoolExpression.Operation, Equals, "<")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithGroupBy(c *C) {
|
||||
q, err := ParseQuery("select count(*) from users.events group_by user_email,time(1h) where time>now()-1d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
column := q.GetColumnNames()[0]
|
||||
c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
c.Assert(column.Name, Equals, "count")
|
||||
c.Assert(column.Elems, HasLen, 1)
|
||||
c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
||||
c.Assert(column.Elems[0].Name, Equals, "*")
|
||||
|
||||
groupBy := q.GetGroupByClause()
|
||||
c.Assert(groupBy, HasLen, 2)
|
||||
c.Assert(groupBy[0].IsFunctionCall(), Equals, false)
|
||||
c.Assert(groupBy[0].Name, Equals, "user_email")
|
||||
c.Assert(groupBy[1].IsFunctionCall(), Equals, true)
|
||||
c.Assert(groupBy[1].Name, Equals, "time")
|
||||
c.Assert(groupBy[1].Elems, HasLen, 1)
|
||||
c.Assert(groupBy[1].Elems[0].Name, Equals, "1h")
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "users.events")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseFromWithNestedFunctions(c *C) {
|
||||
q, err := ParseQuery("select top(10, count(*)) from users.events;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
column := q.GetColumnNames()[0]
|
||||
c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
c.Assert(column.Name, Equals, "top")
|
||||
c.Assert(column.Elems, HasLen, 2)
|
||||
c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
||||
c.Assert(column.Elems[0].Name, Equals, "10")
|
||||
c.Assert(column.Elems[1].IsFunctionCall(), Equals, true)
|
||||
c.Assert(column.Elems[1].Name, Equals, "count")
|
||||
c.Assert(column.Elems[1].Elems, HasLen, 1)
|
||||
c.Assert(column.Elems[1].Elems[0].IsFunctionCall(), Equals, false)
|
||||
c.Assert(column.Elems[1].Elems[0].Name, Equals, "*")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseWhereClausePrecedence(c *C) {
|
||||
q, err := ParseQuery("select value from cpu.idle where value > 90 and time > now() - 1d or value > 80 and time > now() - 1w;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
whereCondition := q.GetWhereCondition()
|
||||
|
||||
c.Assert(whereCondition.Operation, Equals, "OR")
|
||||
leftCondition, ok := whereCondition.Left.(*WhereCondition)
|
||||
// value * 1
|
||||
left, ok := rightExpression.GetLeftExpression()
|
||||
c.Assert(ok, Equals, true)
|
||||
c.Assert(leftCondition.Operation, Equals, "AND")
|
||||
|
||||
leftExpression := leftCondition.Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
c.Assert(leftExpression.Operation, Equals, ">")
|
||||
c.Assert(leftExpression.Left.Left.Name, Equals, "value")
|
||||
c.Assert(leftExpression.Right.Left.Name, Equals, "90")
|
||||
|
||||
rightExpression := leftCondition.Right.Left.(*BoolExpression)
|
||||
c.Assert(rightExpression.Operation, Equals, ">")
|
||||
c.Assert(rightExpression.Left.Left.Name, Equals, "time")
|
||||
c.Assert(rightExpression.Right.Left.Name, Equals, "now")
|
||||
c.Assert(rightExpression.Right.Right.Name, Equals, "1d")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseWhereClauseParantheses(c *C) {
|
||||
q, err := ParseQuery("select value from cpu.idle where value > 90 and (time > now() - 1d or value > 80) and time < now() - 1w;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "cpu.idle")
|
||||
|
||||
whereCondition := q.GetWhereCondition()
|
||||
|
||||
first := whereCondition.Left.(*WhereCondition).Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
second := whereCondition.Left.(*WhereCondition).Right
|
||||
third := whereCondition.Right.Left.(*BoolExpression)
|
||||
|
||||
c.Assert(first.Operation, Equals, ">")
|
||||
c.Assert(second.Operation, Equals, "OR")
|
||||
c.Assert(third.Operation, Equals, "<")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithLast(c *C) {
|
||||
q, err := ParseQuery("select value from t last 10;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.Limit, Equals, -10)
|
||||
|
||||
q, err = ParseQuery("select value from t first 10;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.Limit, Equals, 10)
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseFromWithNestedFunctions2(c *C) {
|
||||
q, err := ParseQuery("select count(distinct(email)) from user.events where time>now()-1d group_by time(15m);")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetColumnNames(), HasLen, 1)
|
||||
column := q.GetColumnNames()[0]
|
||||
c.Assert(column.IsFunctionCall(), Equals, true)
|
||||
c.Assert(column.Name, Equals, "count")
|
||||
c.Assert(column.Elems, HasLen, 1)
|
||||
c.Assert(column.Elems[0].IsFunctionCall(), Equals, true)
|
||||
c.Assert(column.Elems[0].Name, Equals, "distinct")
|
||||
c.Assert(column.Elems[0].Elems, HasLen, 1)
|
||||
c.Assert(column.Elems[0].Elems[0].Name, Equals, "email")
|
||||
|
||||
c.Assert(q.GetGroupByClause(), HasLen, 1)
|
||||
c.Assert(q.GetGroupByClause()[0], DeepEquals, &Value{
|
||||
Name: "time",
|
||||
Elems: []*Value{&Value{"15m", nil}},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseFromWithMergedTable(c *C) {
|
||||
q, err := ParseQuery("select count(*) from merge(newsletter.signups,user.signups) where time>now()-1d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetFromClause().IsFunctionCall(), Equals, true)
|
||||
c.Assert(q.GetFromClause().Name, Equals, "merge")
|
||||
c.Assert(q.GetFromClause().Elems, HasLen, 2)
|
||||
c.Assert(q.GetFromClause().Elems[0].Name, Equals, "newsletter.signups")
|
||||
c.Assert(q.GetFromClause().Elems[1].Name, Equals, "user.signups")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseFromWithJoinedTable(c *C) {
|
||||
q, err := ParseQuery("select max(t1.value, t2.value) from inner_join(newsletter.signups, t1, user.signups, t2) where time>now()-1d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(q.GetFromClause().IsFunctionCall(), Equals, true)
|
||||
c.Assert(q.GetFromClause().Name, Equals, "inner_join")
|
||||
c.Assert(q.GetFromClause().Elems, HasLen, 4)
|
||||
c.Assert(q.GetFromClause().Elems[0].Name, Equals, "newsletter.signups")
|
||||
c.Assert(q.GetFromClause().Elems[1].Name, Equals, "t1")
|
||||
c.Assert(q.GetFromClause().Elems[2].Name, Equals, "user.signups")
|
||||
c.Assert(q.GetFromClause().Elems[3].Name, Equals, "t2")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithRegexCondition(c *C) {
|
||||
q, err := ParseQuery("select email from users.events where email ~= /gmail\\.com/i and time>now()-2d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
w := q.GetWhereCondition()
|
||||
|
||||
regexExpression := w.Left.(*WhereCondition).Left.(*BoolExpression)
|
||||
c.Assert(regexExpression.Left.Left.Name, Equals, "email")
|
||||
c.Assert(regexExpression.Operation, Equals, "~=")
|
||||
c.Assert(regexExpression.Right.Left.Name, Equals, "/gmail\\.com/i")
|
||||
}
|
||||
|
||||
func (self *QueryParserSuite) TestParseSelectWithRegexTables(c *C) {
|
||||
q, err := ParseQuery("select email from users.* where time>now()-2d;")
|
||||
defer q.Close()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Assert(q.GetFromClause().Name, Equals, "users.*")
|
||||
fmt.Printf("left: %#v\n", left.Left)
|
||||
c.Assert(left.Operation, Equals, "*")
|
||||
_value, _ := left.GetLeftExpression()
|
||||
value, _ := _value.GetLeftValue()
|
||||
c.Assert(value.Name, Equals, "value")
|
||||
one, _ := left.Right.GetLeftValue()
|
||||
c.Assert(one.Name, Equals, "1")
|
||||
// right = '3'
|
||||
}
|
||||
|
||||
// TODO:
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
%union {
|
||||
char character;
|
||||
char* string;
|
||||
array* arr;
|
||||
int integer;
|
||||
condition* condition;
|
||||
bool_expression* bool_expression;
|
||||
|
@ -65,7 +64,6 @@
|
|||
// destructors are used to free up memory in case of an error
|
||||
%destructor { free_value($$); } <v>
|
||||
%destructor { if ($$) free_condition($$); } <condition>
|
||||
%destructor { free_array($$); } <arr>
|
||||
%destructor { free($$); } <string>
|
||||
%destructor { free_expression($$); } <expression>
|
||||
%destructor { if ($$) free_value_array($$); } <value_array>
|
||||
|
@ -210,9 +208,15 @@ EXPRESSION:
|
|||
$$->right = NULL;
|
||||
}
|
||||
|
|
||||
VALUE ARITHMETIC_OPERATION VALUE
|
||||
'(' EXPRESSION ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
|
|
||||
EXPRESSION ARITHMETIC_OPERATION EXPRESSION
|
||||
{
|
||||
$$ = malloc(sizeof(expression));
|
||||
printf("operation: %c\n", $2);
|
||||
$$->left = $1;
|
||||
$$->op = $2;
|
||||
$$->right = $3;
|
||||
|
@ -313,7 +317,7 @@ parse_query(char *const query_s)
|
|||
{
|
||||
query q;
|
||||
q.error = NULL;
|
||||
/* yydebug = 1; */
|
||||
yydebug = 1;
|
||||
void *scanner;
|
||||
yylex_init(&scanner);
|
||||
void *buffer = yy_scan_string(query_s, scanner);
|
||||
|
|
|
@ -20,10 +20,10 @@ typedef struct value_t {
|
|||
value_array *args;
|
||||
} value;
|
||||
|
||||
typedef struct {
|
||||
value *left;
|
||||
typedef struct expression_t {
|
||||
void *left; /* this can be a *value or *expression */
|
||||
char op; /* +, -, *, / or \0 if there's no right operand */
|
||||
value *right;
|
||||
struct expression_t *right;
|
||||
} expression;
|
||||
|
||||
typedef struct {
|
||||
|
|
1291
src/query/y.tab.c
1291
src/query/y.tab.c
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
|||
/* A Bison parser, made by GNU Bison 2.5. */
|
||||
/* A Bison parser, made by GNU Bison 3.0. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -30,13 +30,21 @@
|
|||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
#ifndef YY_YY_Y_TAB_H_INCLUDED
|
||||
# define YY_YY_Y_TAB_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 1
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Tokens. */
|
||||
/* Token type. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
enum yytokentype
|
||||
{
|
||||
SELECT = 258,
|
||||
FROM = 259,
|
||||
WHERE = 260,
|
||||
|
@ -51,49 +59,24 @@
|
|||
REGEX_STRING = 269,
|
||||
OR = 270,
|
||||
AND = 271,
|
||||
OPERATION_GE = 272,
|
||||
OPERATION_LE = 273,
|
||||
OPERATION_LT = 274,
|
||||
OPERATION_GT = 275,
|
||||
OPERATION_NE = 276,
|
||||
OPERATION_EQUAL = 277
|
||||
OPERATION_EQUAL = 272,
|
||||
OPERATION_NE = 273,
|
||||
OPERATION_GT = 274,
|
||||
OPERATION_LT = 275,
|
||||
OPERATION_LE = 276,
|
||||
OPERATION_GE = 277
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
#define SELECT 258
|
||||
#define FROM 259
|
||||
#define WHERE 260
|
||||
#define EQUAL 261
|
||||
#define GROUP_BY 262
|
||||
#define FIRST 263
|
||||
#define LAST 264
|
||||
#define STRING_VALUE 265
|
||||
#define INT_VALUE 266
|
||||
#define NAME 267
|
||||
#define REGEX_OP 268
|
||||
#define REGEX_STRING 269
|
||||
#define OR 270
|
||||
#define AND 271
|
||||
#define OPERATION_GE 272
|
||||
#define OPERATION_LE 273
|
||||
#define OPERATION_LT 274
|
||||
#define OPERATION_GT 275
|
||||
#define OPERATION_NE 276
|
||||
#define OPERATION_EQUAL 277
|
||||
|
||||
|
||||
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 11 "query.yacc"
|
||||
#line 11 "query.yacc" /* yacc.c:1915 */
|
||||
|
||||
char character;
|
||||
char* string;
|
||||
array* arr;
|
||||
int integer;
|
||||
condition* condition;
|
||||
bool_expression* bool_expression;
|
||||
|
@ -101,30 +84,28 @@ typedef union YYSTYPE
|
|||
value_array* value_array;
|
||||
value* v;
|
||||
|
||||
|
||||
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 108 "y.tab.h"
|
||||
} YYSTYPE;
|
||||
#line 88 "y.tab.h" /* yacc.c:1915 */
|
||||
};
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Location type. */
|
||||
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
|
||||
typedef struct YYLTYPE
|
||||
typedef struct YYLTYPE YYLTYPE;
|
||||
struct YYLTYPE
|
||||
{
|
||||
int first_line;
|
||||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
} YYLTYPE;
|
||||
# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
|
||||
};
|
||||
# define YYLTYPE_IS_DECLARED 1
|
||||
# define YYLTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int yyparse (query *q, void *scanner);
|
||||
|
||||
#endif /* !YY_YY_Y_TAB_H_INCLUDED */
|
||||
|
|
Loading…
Reference in New Issue