Parsing complex arithmetic operations.

pull/17/head
Todd Persen 2013-10-08 15:50:59 -04:00
parent 10f571263c
commit 51893ebd37
10 changed files with 1225 additions and 1387 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,19 @@
/* 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@ -26,74 +26,57 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
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 {
SELECT = 258,
FROM = 259,
WHERE = 260,
EQUAL = 261,
GROUP_BY = 262,
FIRST = 263,
LAST = 264,
STRING_VALUE = 265,
INT_VALUE = 266,
NAME = 267,
REGEX_OP = 268,
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
};
enum yytokentype
{
SELECT = 258,
FROM = 259,
WHERE = 260,
EQUAL = 261,
GROUP_BY = 262,
FIRST = 263,
LAST = 264,
STRING_VALUE = 265,
INT_VALUE = 266,
NAME = 267,
REGEX_OP = 268,
REGEX_STRING = 269,
OR = 270,
AND = 271,
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 */

10
test.sh
View File

@ -5,15 +5,15 @@ set -e
cd `dirname $0`
. exports.sh
pushd src/query
./build_parser.sh
if [ "x`uname`" == "xLinux" ]; then
pushd src/query
./build_parser.sh
if ! ./test_memory_leaks.sh; then
echo "ERROR: memory leak detected"
exit 1
echo "ERROR: memory leak detected"
exit 1
fi
popd
fi
popd
go get launchpad.net/gocheck